Re-rolling r8522: For synthetic this refs, use params rather than fields while in constructors
http://gwt-code-reviews.appspot.com/752801
Review by: tobyr
git-svn-id: https://google-web-toolkit.googlecode.com/svn/trunk@8547 8db76d5a-ed1c-0410-87a9-c151d255dfc7
diff --git a/dev/core/src/com/google/gwt/dev/jjs/ast/JField.java b/dev/core/src/com/google/gwt/dev/jjs/ast/JField.java
index b785f08..279a12a 100644
--- a/dev/core/src/com/google/gwt/dev/jjs/ast/JField.java
+++ b/dev/core/src/com/google/gwt/dev/jjs/ast/JField.java
@@ -25,10 +25,14 @@
* Determines whether the variable is final, volatile, or neither.
*/
public static enum Disposition {
- COMPILE_TIME_CONSTANT, FINAL, NONE, VOLATILE;
+ COMPILE_TIME_CONSTANT, FINAL, NONE, THIS_REF, VOLATILE;
public boolean isFinal() {
- return this == COMPILE_TIME_CONSTANT || this == FINAL;
+ return this == COMPILE_TIME_CONSTANT || this == FINAL || this == THIS_REF;
+ }
+
+ public boolean isThisRef() {
+ return this == THIS_REF;
}
private boolean isCompileTimeConstant() {
@@ -43,6 +47,7 @@
private final JDeclaredType enclosingType;
private final boolean isCompileTimeConstant;
private final boolean isStatic;
+ private boolean isThisRef;
private boolean isVolatile;
JField(SourceInfo info, String name, JDeclaredType enclosingType, JType type,
@@ -52,6 +57,7 @@
this.isStatic = isStatic;
this.isCompileTimeConstant = disposition.isCompileTimeConstant();
this.isVolatile = disposition.isVolatile();
+ this.isThisRef = disposition.isThisRef();
// Disposition is not cached because we can be set final later.
}
@@ -75,6 +81,10 @@
return isStatic;
}
+ public boolean isThisRef() {
+ return isThisRef;
+ }
+
public boolean isVolatile() {
return isVolatile;
}
diff --git a/dev/core/src/com/google/gwt/dev/jjs/impl/BuildTypeMap.java b/dev/core/src/com/google/gwt/dev/jjs/impl/BuildTypeMap.java
index 449fa77..9ecbe30 100644
--- a/dev/core/src/com/google/gwt/dev/jjs/impl/BuildTypeMap.java
+++ b/dev/core/src/com/google/gwt/dev/jjs/impl/BuildTypeMap.java
@@ -613,12 +613,12 @@
}
private JField createField(SyntheticArgumentBinding binding,
- JDeclaredType enclosingType) {
+ JDeclaredType enclosingType, Disposition disposition) {
JType type = getType(binding.type);
SourceInfo info = enclosingType.getSourceInfo().makeChild(
BuildDeclMapVisitor.class, "Field " + String.valueOf(binding.name));
JField field = program.createField(info, String.valueOf(binding.name),
- enclosingType, type, false, Disposition.FINAL);
+ enclosingType, type, false, disposition);
info.addCorrelation(program.getCorrelator().by(field));
if (binding.matchingField != null) {
typeMap.put(binding.matchingField, field);
@@ -834,7 +834,7 @@
for (int i = 0; i < nestedBinding.enclosingInstances.length; ++i) {
SyntheticArgumentBinding arg = nestedBinding.enclosingInstances[i];
if (arg.matchingField != null) {
- createField(arg, type);
+ createField(arg, type, Disposition.THIS_REF);
}
}
}
@@ -842,7 +842,19 @@
if (nestedBinding.outerLocalVariables != null) {
for (int i = 0; i < nestedBinding.outerLocalVariables.length; ++i) {
SyntheticArgumentBinding arg = nestedBinding.outerLocalVariables[i];
- createField(arg, type);
+ // See InnerClassTest.testOuterThisFromSuperCall().
+ boolean isReallyThisRef = false;
+ if (arg.actualOuterLocalVariable instanceof SyntheticArgumentBinding) {
+ SyntheticArgumentBinding outer = (SyntheticArgumentBinding) arg.actualOuterLocalVariable;
+ if (outer.matchingField != null) {
+ JField field = (JField) typeMap.get(outer.matchingField);
+ if (field.isThisRef()) {
+ isReallyThisRef = true;
+ }
+ }
+ }
+ createField(arg, type, isReallyThisRef ? Disposition.THIS_REF
+ : Disposition.FINAL);
}
}
}
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 31c48de..7849d45 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
@@ -103,6 +103,7 @@
import com.google.gwt.dev.js.ast.JsProgram;
import com.google.gwt.dev.util.JsniRef;
import com.google.gwt.dev.util.collect.Lists;
+import com.google.gwt.dev.util.collect.Maps;
import com.google.gwt.dev.util.log.speedtracer.CompilerEventType;
import com.google.gwt.dev.util.log.speedtracer.SpeedTracerLogger;
import com.google.gwt.dev.util.log.speedtracer.SpeedTracerLogger.Event;
@@ -272,6 +273,8 @@
private MethodScope currentMethodScope;
+ private Map<JField, JParameter> currentOuterThisRefParams;
+
private int[] currentSeparatorPositions;
private final boolean disableClassMetadata;
@@ -672,13 +675,6 @@
currentMethodBody = ctor.getBody();
currentMethodScope = x.scope;
- JMethodCall superOrThisCall = null;
- ExplicitConstructorCall ctorCall = x.constructorCall;
- if (ctorCall != null) {
- superOrThisCall = (JMethodCall) dispatch("processExpression",
- ctorCall);
- }
-
/*
* Determine if we have an explicit this call. The presence of an
* explicit this call indicates we can skip certain initialization steps
@@ -686,11 +682,12 @@
* steps are 1) assigning synthetic args to fields and 2) running
* initializers.
*/
- boolean hasExplicitThis = (ctorCall != null)
- && !ctorCall.isSuperAccess();
+ boolean hasExplicitThis = (x.constructorCall != null)
+ && !x.constructorCall.isSuperAccess();
JClassType enclosingType = ctor.getEnclosingType();
JBlock block = currentMethodBody.getBlock();
+ currentOuterThisRefParams = Maps.create();
/*
* All synthetic fields must be assigned, unless we have an explicit
@@ -710,6 +707,8 @@
block.addStmt(JProgram.createAssignmentStmt(info,
createVariableRef(info, field), createVariableRef(info,
param)));
+ currentOuterThisRefParams = Maps.put(
+ currentOuterThisRefParams, field, param);
}
}
}
@@ -727,19 +726,20 @@
}
}
- // Enums: wire up synthetic name/ordinal params to the super method.
- if (enclosingType.isEnumOrSubclass() != null) {
- assert (superOrThisCall != null);
- JVariableRef enumNameRef = createVariableRef(
- superOrThisCall.getSourceInfo(), ctor.getParams().get(0));
- superOrThisCall.addArg(0, enumNameRef);
- JVariableRef enumOrdinalRef = createVariableRef(
- superOrThisCall.getSourceInfo(), ctor.getParams().get(1));
- superOrThisCall.addArg(1, enumOrdinalRef);
- }
-
// optional this or super constructor call
- if (superOrThisCall != null) {
+ if (x.constructorCall != null) {
+ JMethodCall superOrThisCall = (JMethodCall) dispatch(
+ "processExpression", x.constructorCall);
+ // Enums: wire up synthetic name/ordinal params to the super method.
+ if (enclosingType.isEnumOrSubclass() != null) {
+ JVariableRef enumNameRef = createVariableRef(
+ superOrThisCall.getSourceInfo(), ctor.getParams().get(0));
+ superOrThisCall.addArg(0, enumNameRef);
+ JVariableRef enumOrdinalRef = createVariableRef(
+ superOrThisCall.getSourceInfo(), ctor.getParams().get(1));
+ superOrThisCall.addArg(1, enumOrdinalRef);
+ }
+
superOrThisCall.setStaticDispatchOnly();
block.addStmt(superOrThisCall.makeStatement());
}
@@ -760,6 +760,7 @@
// user code (finally!)
block.addStmts(processStatements(x.statements));
+ currentOuterThisRefParams = null;
currentMethodScope = null;
currentMethod = null;
} catch (Throwable e) {
@@ -1969,18 +1970,21 @@
return call;
}
- private void addAllOuterThisRefs(List<? super JFieldRef> list,
+ private void addAllOuterThisRefs(List<? super JVariableRef> list,
JExpression expr, JClassType classType) {
- if (classType.getFields().size() > 0) {
- JField field = classType.getFields().get(0);
- /*
- * In some circumstances, the outer this ref can be captured as a local
- * value (val$this), in other cases, as a this ref (this$).
- *
- * TODO: investigate using more JDT node information as an alternative
- */
- if (field.getName().startsWith("this$")
- || field.getName().startsWith("val$this$")) {
+ for (JField field : classType.getFields()) {
+ // This fields are always first.
+ if (!field.isThisRef()) {
+ break;
+ }
+ // In a constructor, use the local param instead of the field.
+ JParameter param = null;
+ if (currentOuterThisRefParams != null && expr instanceof JThisRef) {
+ param = currentOuterThisRefParams.get(field);
+ }
+ if (param != null) {
+ list.add(new JParameterRef(expr.getSourceInfo(), param));
+ } else {
list.add(new JFieldRef(expr.getSourceInfo(), expr, field,
currentClass));
}
@@ -1988,7 +1992,8 @@
}
private void addAllOuterThisRefsPlusSuperChain(
- List<? super JFieldRef> workList, JExpression expr, JClassType classType) {
+ List<? super JVariableRef> workList, JExpression expr,
+ JClassType classType) {
for (; classType != null; classType = classType.getSuperClass()) {
addAllOuterThisRefs(workList, expr, classType);
}
diff --git a/user/test/com/google/gwt/dev/jjs/test/InnerClassTest.java b/user/test/com/google/gwt/dev/jjs/test/InnerClassTest.java
index 918b2c2..e38a869 100644
--- a/user/test/com/google/gwt/dev/jjs/test/InnerClassTest.java
+++ b/user/test/com/google/gwt/dev/jjs/test/InnerClassTest.java
@@ -45,6 +45,24 @@
}
}
+ class OuterRefFromSuperCtorBase {
+ OuterRefFromSuperCtorBase(Object o) {
+ o.toString();
+ }
+ }
+
+ class OuterRefFromSuperCtorCall extends OuterRefFromSuperCtorBase {
+ OuterRefFromSuperCtorCall() {
+ super(new Object() {
+ @Override
+ public String toString() {
+ testAppend.append("OuterRefFromSuperCtorCall");
+ return "";
+ }
+ });
+ }
+ }
+
static class P1<T1> {
class P2<T2> extends P1<T1> {
class P3<T3> extends P2<T2> {
@@ -77,7 +95,7 @@
}
}
- private StringBuffer testAppend;
+ private StringBuffer testAppend = new StringBuffer();
public String getModuleName() {
return "com.google.gwt.dev.jjs.CompilerSuite";
@@ -95,7 +113,6 @@
}
public void testInnerClassInitialization() {
- testAppend = new StringBuffer();
new InnerClass();
assertEquals("ab", testAppend.toString());
}
@@ -116,6 +133,7 @@
AppendToStringBuffer ap = new AppendToStringBuffer(i) {
public void act() {
b.append(num);
+ testAppend.append(num);
}
};
results.add(ap);
@@ -124,6 +142,12 @@
theAp.act();
}
assertEquals("0123456789", b.toString());
+ assertEquals("0123456789", testAppend.toString());
+ }
+
+ public void testOuterThisFromSuperCall() {
+ new OuterRefFromSuperCtorCall();
+ assertEquals("OuterRefFromSuperCtorCall", testAppend.toString());
}
}