- Fixes a bug in GenerateJavaAST where the Iterator variable of a foreach was assigned the wrong type, causing all kinds of madness.
- Fixes a latent problem where referencing a generic field fails to generate an appropriate cast operation.
- Adds gwt.jjs.traceMethods to the compiler for easy method change tracking
Found by: jaimeyap
Review by: spoon (pair prog)
git-svn-id: https://google-web-toolkit.googlecode.com/svn/trunk@2171 8db76d5a-ed1c-0410-87a9-c151d255dfc7
diff --git a/dev/core/src/com/google/gwt/dev/jjs/ast/JMethod.java b/dev/core/src/com/google/gwt/dev/jjs/ast/JMethod.java
index e2976b3..e008c91 100644
--- a/dev/core/src/com/google/gwt/dev/jjs/ast/JMethod.java
+++ b/dev/core/src/com/google/gwt/dev/jjs/ast/JMethod.java
@@ -20,13 +20,20 @@
import java.util.ArrayList;
import java.util.List;
+import java.util.Set;
/**
* A Java method implementation.
*/
public final class JMethod extends JNode implements HasEnclosingType, HasName,
- HasSettableType, CanBeAbstract, CanBeSetFinal, CanBeNative,
- CanBeStatic {
+ HasSettableType, CanBeAbstract, CanBeSetFinal, CanBeNative, CanBeStatic {
+
+ private static void trace(String title, String code) {
+ System.out.println("---------------------------");
+ System.out.println(title + ":");
+ System.out.println("---------------------------");
+ System.out.println(code);
+ }
/**
* References to any methods which this method overrides. This should be an
@@ -46,6 +53,8 @@
private final String name;
private ArrayList<JType> originalParamTypes;
private JType returnType;
+ private boolean trace = false;
+ private boolean traceFirst = true;
/**
* These are only supposed to be constructed by JProgram.
@@ -72,6 +81,22 @@
JParameter param = params.get(i);
originalParamTypes.add(param.getType());
}
+
+ // Determine if we should trace this method.
+ if (enclosingType != null) {
+ String jsniSig = JProgram.getJsniSig(this);
+ Set<String> set = JProgram.traceMethods.get(enclosingType.getName());
+ if (set != null && (set.contains(name) || set.contains(jsniSig))) {
+ trace = true;
+ }
+ // Try the short name.
+ if (!trace && enclosingType != null) {
+ set = JProgram.traceMethods.get(enclosingType.getShortName());
+ if (set != null && (set.contains(name) || set.contains(jsniSig))) {
+ trace = true;
+ }
+ }
+ }
}
public JAbstractMethodBody getBody() {
@@ -138,6 +163,14 @@
}
public void traverse(JVisitor visitor, Context ctx) {
+ String before = null;
+ if (trace && visitor instanceof JModVisitor) {
+ before = this.toSource();
+ if (traceFirst) {
+ traceFirst = false;
+ trace("Initial", before);
+ }
+ }
if (visitor.visit(this, ctx)) {
visitor.accept(params);
if (body != null) {
@@ -145,6 +178,16 @@
}
}
visitor.endVisit(this, ctx);
+ if (trace && visitor instanceof JModVisitor) {
+ String after = this.toSource();
+ if (!after.equals(before)) {
+ String title = visitor.getClass().getSimpleName();
+ trace(title, after);
+ }
+ }
}
+ void copyTraceStatusFrom(JMethod x) {
+ this.trace = x.trace;
+ }
}
diff --git a/dev/core/src/com/google/gwt/dev/jjs/ast/JProgram.java b/dev/core/src/com/google/gwt/dev/jjs/ast/JProgram.java
index 9bc354a..9cbbc04 100644
--- a/dev/core/src/com/google/gwt/dev/jjs/ast/JProgram.java
+++ b/dev/core/src/com/google/gwt/dev/jjs/ast/JProgram.java
@@ -50,6 +50,8 @@
"com.google.gwt.lang.Exceptions", "com.google.gwt.lang.LongLib",
"com.google.gwt.lang.Stats",}));
+ static final Map<String, Set<String>> traceMethods = new HashMap<String, Set<String>>();
+
private static final Set<String> INDEX_TYPES_SET = new HashSet<String>(
Arrays.asList(new String[] {
"java.lang.Object", "java.lang.String", "java.lang.Class",
@@ -67,6 +69,43 @@
static {
INDEX_TYPES_SET.addAll(CODEGEN_TYPES_SET);
+
+ /*
+ * The format to trace methods is a colon-separated list of
+ * "className.methodName", such as "Hello.onModuleLoad:Foo.bar". You can
+ * fully-qualify a class to disambiguate classes, and you can also append
+ * the JSNI signature of the method to disambiguate overloads, ala
+ * "Foo.bar(IZ)".
+ */
+ String toTrace = System.getProperty("gwt.jjs.traceMethods");
+ if (toTrace != null) {
+ String[] split = toTrace.split(":");
+ for (String str : split) {
+ int pos = str.lastIndexOf('.');
+ if (pos > 0) {
+ String className = str.substring(0, pos);
+ String methodName = str.substring(pos + 1);
+ Set<String> set = traceMethods.get(className);
+ if (set == null) {
+ set = new HashSet<String>();
+ traceMethods.put(className, set);
+ }
+ set.add(methodName);
+ }
+ }
+ }
+ }
+
+ public static String getJsniSig(JMethod method) {
+ StringBuffer sb = new StringBuffer();
+ sb.append(method.getName());
+ sb.append("(");
+ for (int i = 0; i < method.getOriginalParamTypes().size(); ++i) {
+ JType type = method.getOriginalParamTypes().get(i);
+ sb.append(type.getJsniSignatureName());
+ }
+ sb.append(")");
+ return sb.toString();
}
public static boolean methodsDoMatch(JMethod method1, JMethod method2) {
@@ -701,6 +740,7 @@
public void putStaticImpl(JMethod method, JMethod staticImpl) {
instanceToStaticMap.put(method, staticImpl);
staticToInstanceMap.put(staticImpl, method);
+ staticImpl.copyTraceStatusFrom(method);
}
public JClassType rebind(JType type) {
diff --git a/dev/core/src/com/google/gwt/dev/jjs/impl/GenerateJavaAST.java b/dev/core/src/com/google/gwt/dev/jjs/impl/GenerateJavaAST.java
index fd392c4..b51c265 100644
--- a/dev/core/src/com/google/gwt/dev/jjs/impl/GenerateJavaAST.java
+++ b/dev/core/src/com/google/gwt/dev/jjs/impl/GenerateJavaAST.java
@@ -278,7 +278,7 @@
for (int i = 0; i < type.methods.size(); ++i) {
JMethod method = type.methods.get(i);
if (method.getName().equals(methodName)) {
- String jsniSig = getJsniSig(method);
+ String jsniSig = JProgram.getJsniSig(method);
if (jsniSig.equals(rhs)) {
return method;
} else if (almostMatches == null) {
@@ -387,18 +387,6 @@
}
}
- private static String getJsniSig(JMethod method) {
- StringBuffer sb = new StringBuffer();
- sb.append(method.getName());
- sb.append("(");
- for (int i = 0; i < method.getOriginalParamTypes().size(); ++i) {
- JType type = method.getOriginalParamTypes().get(i);
- sb.append(type.getJsniSignatureName());
- }
- sb.append(")");
- return sb.toString();
- }
-
private static InternalCompilerException translateException(JNode node,
Throwable e) {
InternalCompilerException ice;
@@ -1190,6 +1178,7 @@
JExpression processExpression(FieldReference x) {
SourceInfo info = makeSourceInfo(x);
FieldBinding fieldBinding = x.binding;
+ JType type = (JType) typeMap.get(x.resolvedType);
JField field;
if (fieldBinding.declaringClass == null) {
// probably array.length
@@ -1203,7 +1192,14 @@
JExpression instance = dispProcessExpression(x.receiver);
JExpression fieldRef = new JFieldRef(program, info, instance, field,
currentClass);
- return fieldRef;
+
+ if (type != field.getType()) {
+ // Must be a generic; insert a cast operation.
+ JReferenceType toType = (JReferenceType) type;
+ return new JCastOperation(program, info, toType, fieldRef);
+ } else {
+ return fieldRef;
+ }
}
JExpression processExpression(InstanceOfExpression x) {
@@ -1753,7 +1749,7 @@
* </pre>
*/
JLocal iteratorVar = createSyntheticLocal(info, elementVarName
- + "$iterator", (JType) typeMap.get(x.collection.resolvedType));
+ + "$iterator", program.getIndexedType("Iterator"));
List<JStatement> initializers = new ArrayList<JStatement>(1);
// Iterator<T> i$iterator = collection.iterator()
@@ -1766,10 +1762,20 @@
createVariableRef(info, iteratorVar),
program.getIndexedMethod("Iterator.hasNext"));
- // T elementVar = i$array[i$index];
- elementDecl.initializer = new JMethodCall(program, info,
+ // T elementVar = (T) i$iterator.next();
+ JMethodCall nextCall = new JMethodCall(program, info,
createVariableRef(info, iteratorVar),
program.getIndexedMethod("Iterator.next"));
+
+ JType elementType = elementDecl.getVariableRef().getType();
+ if (elementType != nextCall.getType()) {
+ // Must be a generic; insert a cast operation.
+ elementDecl.initializer = new JCastOperation(program, info,
+ elementType, nextCall);
+ } else {
+ elementDecl.initializer = nextCall;
+ }
+
body.statements.add(0, elementDecl);
result = new JForStatement(program, info, initializers, condition,