Fix EnumOridnalizer codesize regression. Change-Id: I0277c343f129d8456f388bf361e5167fb56afecc
diff --git a/dev/core/src/com/google/gwt/dev/jjs/impl/EnumOrdinalizer.java b/dev/core/src/com/google/gwt/dev/jjs/impl/EnumOrdinalizer.java index 3ab88c8..4bcc5f1 100644 --- a/dev/core/src/com/google/gwt/dev/jjs/impl/EnumOrdinalizer.java +++ b/dev/core/src/com/google/gwt/dev/jjs/impl/EnumOrdinalizer.java
@@ -22,6 +22,7 @@ import com.google.gwt.dev.jjs.ast.JCastOperation; import com.google.gwt.dev.jjs.ast.JClassLiteral; import com.google.gwt.dev.jjs.ast.JClassType; +import com.google.gwt.dev.jjs.ast.JDeclarationStatement; import com.google.gwt.dev.jjs.ast.JEnumField; import com.google.gwt.dev.jjs.ast.JEnumType; import com.google.gwt.dev.jjs.ast.JExpression; @@ -147,6 +148,10 @@ return info.getFileName() + ": Line " + info.getStartLine(); } + public Set<String> getOrdinalizedNames() { + return allEnumsOrdinalized; + } + public int getNumOrdinalized() { return allEnumsOrdinalized.size(); } @@ -658,6 +663,26 @@ } } + @Override + public void endVisit(JDeclarationStatement x, Context ctx) { + super.endVisit(x, ctx); + if (!(x.getVariableRef().getTarget() instanceof JEnumField)) { + return; + } + + JEnumField enumField = (JEnumField) x.getVariableRef().getTarget(); + if (!(canBeOrdinal(enumField.getEnclosingType()))) { + return; + } + + // Also replace the declaration statement so that the enum instances are not constructed; + // eventually the field will be pruned but the declaration statement will only completely + // disappear if there are no side effects (constructing a new instance counts as side + // effects). + ctx.replaceMe(new JDeclarationStatement(x.getSourceInfo(), x.getVariableRef(), + program.getLiteralInt(enumField.ordinal()))); + } + /** * Remap enum types with JPrimitiveType.INT. Also handle case for arrays, * replace enum leaftype with JPrimitive.INT. This is an override
diff --git a/dev/core/src/com/google/gwt/dev/jjs/impl/GwtAstBuilder.java b/dev/core/src/com/google/gwt/dev/jjs/impl/GwtAstBuilder.java index e3d849e..94451a1 100644 --- a/dev/core/src/com/google/gwt/dev/jjs/impl/GwtAstBuilder.java +++ b/dev/core/src/com/google/gwt/dev/jjs/impl/GwtAstBuilder.java
@@ -2198,6 +2198,10 @@ initializers.add(fieldRef); } JNewArray valuesArrayCopy = JNewArray.createInitializers(info, enumArrayType, initializers); + if (type.getEnumList().size() > MAX_INLINEABLE_ENUM_SIZE) { + // Only inline values() if it is small. + method.setInliningAllowed(false); + } implementMethod(method, valuesArrayCopy); } @@ -2921,6 +2925,7 @@ private static final char[] _STRING = "_String".toCharArray(); private static final String ARRAY_LENGTH_FIELD = "length"; + private static final int MAX_INLINEABLE_ENUM_SIZE = 10; /** * Reflective access to {@link ForeachStatement#collectionElementType}. */
diff --git a/dev/core/test/com/google/gwt/dev/jjs/impl/EnumOrdinalizerTest.java b/dev/core/test/com/google/gwt/dev/jjs/impl/EnumOrdinalizerTest.java index ff0ee68..19e3895 100644 --- a/dev/core/test/com/google/gwt/dev/jjs/impl/EnumOrdinalizerTest.java +++ b/dev/core/test/com/google/gwt/dev/jjs/impl/EnumOrdinalizerTest.java
@@ -16,8 +16,14 @@ package com.google.gwt.dev.jjs.impl; import com.google.gwt.core.ext.UnableToCompleteException; +import com.google.gwt.dev.jjs.ast.Context; +import com.google.gwt.dev.jjs.ast.JDeclarationStatement; +import com.google.gwt.dev.jjs.ast.JFieldRef; import com.google.gwt.dev.jjs.ast.JMethod; import com.google.gwt.dev.jjs.ast.JProgram; +import com.google.gwt.dev.jjs.ast.JValueLiteral; +import com.google.gwt.dev.jjs.ast.JVisitor; +import com.google.gwt.dev.jjs.impl.EnumOrdinalizer.Tracker; /** * A set of tests for the conditions under which ordinalization is and is not allowed. The @@ -74,36 +80,41 @@ public void testOrdinalizeBasicAssignment() throws UnableToCompleteException { setupFruitEnum(); - optimize("void", "Fruit apple = Fruit.APPLE;", + Result result = optimize("void", "Fruit apple = Fruit.APPLE;", "Fruit orange = Fruit.ORANGE;"); EnumOrdinalizer.Tracker tracker = EnumOrdinalizer.getTracker(); assertTrue(tracker.isOrdinalized("test.EntryPoint$Fruit")); + assertAllEnumOrdinalizedReferencesReplaced(result.getOptimizedProgram(), tracker); } public void testOrdinalizeNewArrayAndAssignmentLocalRef() throws UnableToCompleteException { setupFruitEnum(); - optimize("void", "Fruit[] fruits = new Fruit[] {Fruit.APPLE, Fruit.ORANGE, Fruit.APPLE};", - "if (fruits[0] == Fruit.APPLE) {", - " fruits[0] = Fruit.ORANGE;", - "}"); + Result result = + optimize("void", "Fruit[] fruits = new Fruit[] {Fruit.APPLE, Fruit.ORANGE, Fruit.APPLE};", + "if (fruits[0] == Fruit.APPLE) {", + " fruits[0] = Fruit.ORANGE;", + "}"); EnumOrdinalizer.Tracker tracker = EnumOrdinalizer.getTracker(); assertTrue(tracker.isOrdinalized("test.EntryPoint$Fruit")); + assertAllEnumOrdinalizedReferencesReplaced(result.getOptimizedProgram(), tracker); } public void testOrdinalizeNewArrayOfArrayAndAssignmentLocalRef() throws UnableToCompleteException { setupFruitEnum(); - optimize("void", "Fruit[][] fruits = new Fruit[][] ", - " {{Fruit.APPLE, Fruit.ORANGE},{Fruit.APPLE, Fruit.ORANGE}};", - "if (fruits[0][1] == Fruit.APPLE) {", - " fruits[0][1] = Fruit.ORANGE;", - "}"); + Result result = + optimize("void", "Fruit[][] fruits = new Fruit[][] ", + " {{Fruit.APPLE, Fruit.ORANGE},{Fruit.APPLE, Fruit.ORANGE}};", + "if (fruits[0][1] == Fruit.APPLE) {", + " fruits[0][1] = Fruit.ORANGE;", + "}"); EnumOrdinalizer.Tracker tracker = EnumOrdinalizer.getTracker(); assertTrue(tracker.isOrdinalized("test.EntryPoint$Fruit")); + assertAllEnumOrdinalizedReferencesReplaced(result.getOptimizedProgram(), tracker); } public void testOrdinalizeNewArrayAndAssignmentFieldRef() @@ -111,10 +122,11 @@ setupFruitEnum(); addSnippetClassDecl("private final Fruit[] fruits = new Fruit[] ", " {Fruit.APPLE, Fruit.ORANGE, Fruit.APPLE};"); - optimize("void", "EntryPoint ep = new EntryPoint();"); + Result result = optimize("void", "EntryPoint ep = new EntryPoint();"); EnumOrdinalizer.Tracker tracker = EnumOrdinalizer.getTracker(); assertTrue(tracker.isOrdinalized("test.EntryPoint$Fruit")); + assertAllEnumOrdinalizedReferencesReplaced(result.getOptimizedProgram(), tracker); } public void testOrdinalizableFinalFieldUninitializedByDefault() @@ -124,22 +136,24 @@ "public EntryPoint() {", " uninitializedFinalFruit = Fruit.ORANGE;", "}"); - optimize("void", "EntryPoint ep = new EntryPoint();"); + Result result = optimize("void", "EntryPoint ep = new EntryPoint();"); EnumOrdinalizer.Tracker tracker = EnumOrdinalizer.getTracker(); assertTrue(tracker.isVisited("test.EntryPoint$Fruit")); assertTrue(tracker.isOrdinalized("test.EntryPoint$Fruit")); + assertAllEnumOrdinalizedReferencesReplaced(result.getOptimizedProgram(), tracker); } public void testOrdinalizeSwitchStatement() throws UnableToCompleteException { setupFruitEnum(); setupFruitSwitchMethod(); - optimize("void", "String apple = fruitSwitch(Fruit.APPLE);", + Result result = optimize("void", "String apple = fruitSwitch(Fruit.APPLE);", "String orange = fruitSwitch(Fruit.ORANGE);"); EnumOrdinalizer.Tracker tracker = EnumOrdinalizer.getTracker(); assertTrue(tracker.isOrdinalized("test.EntryPoint$Fruit")); + assertAllEnumOrdinalizedReferencesReplaced(result.getOptimizedProgram(), tracker); } public void testOrdinalizeIfStatement() @@ -155,59 +169,69 @@ " return \"Unknown\";", " }", "}"); - optimize("void", "String apple = fruitIf(Fruit.APPLE);", + Result result = optimize("void", "String apple = fruitIf(Fruit.APPLE);", "String orange = fruitIf(Fruit.ORANGE);"); EnumOrdinalizer.Tracker tracker = EnumOrdinalizer.getTracker(); assertTrue(tracker.isOrdinalized("test.EntryPoint$Fruit")); + assertAllEnumOrdinalizedReferencesReplaced(result.getOptimizedProgram(), tracker); } public void testOrdinalizeConditional() throws UnableToCompleteException { setupFruitEnum(); - optimize("void", "Fruit fruit = (true) ? Fruit.APPLE : Fruit.ORANGE;"); + Result result = optimize("void", "Fruit fruit = (true) ? Fruit.APPLE : Fruit.ORANGE;"); EnumOrdinalizer.Tracker tracker = EnumOrdinalizer.getTracker(); assertTrue(tracker.isOrdinalized("test.EntryPoint$Fruit")); + assertAllEnumOrdinalizedReferencesReplaced(result.getOptimizedProgram(), tracker); } public void testOrdinalizeFieldRefOrdinalMethodCall() throws UnableToCompleteException { setupFruitEnum(); - optimize("void", "int i = Fruit.APPLE.ordinal();"); + Result result = optimize("void", "int i = Fruit.APPLE.ordinal();"); EnumOrdinalizer.Tracker tracker = EnumOrdinalizer.getTracker(); assertTrue(tracker.isOrdinalized("test.EntryPoint$Fruit")); + assertAllEnumOrdinalizedReferencesReplaced(result.getOptimizedProgram(), tracker); } public void testOrdinalizeVariableRefOrdinalMethodCall() throws UnableToCompleteException { setupFruitEnum(); - optimize("void", "Fruit fruit = Fruit.APPLE;", + Result result = optimize("void", "Fruit fruit = Fruit.APPLE;", "int i = fruit.ordinal();"); EnumOrdinalizer.Tracker tracker = EnumOrdinalizer.getTracker(); assertTrue(tracker.isOrdinalized("test.EntryPoint$Fruit")); + assertAllEnumOrdinalizedReferencesReplaced(result.getOptimizedProgram(), tracker); } public void testOrdinalizeUnusedEmptyEnum() throws UnableToCompleteException { setupEmptyEnum(); - optimize("void", "EmptyEnum myEnum;"); + Result result = optimize("void", "EmptyEnum myEnum;"); EnumOrdinalizer.Tracker tracker = EnumOrdinalizer.getTracker(); assertTrue(tracker.isOrdinalized("test.EntryPoint$EmptyEnum") || !tracker.isVisited("test.EntryPoint$EmptyEnum")); + assertAllEnumOrdinalizedReferencesReplaced(result.getOptimizedProgram(), tracker); } public void testOrdinalizeUnusedEnum() throws UnableToCompleteException { setupFruitEnum(); - optimize("void", "Fruit myEnum;"); + Result result = optimize("void", "Fruit myEnum;"); EnumOrdinalizer.Tracker tracker = EnumOrdinalizer.getTracker(); assertTrue(tracker.isOrdinalized("test.EntryPoint$Fruit") || !tracker.isVisited("test.EntryPoint$Fruit")); + + // This enum is not referenced and it has gone away before ordinalizing, however make + // sure there are no references anyway. + tracker.addOrdinalized("test.EntryPoint$Fruit"); + assertAllEnumOrdinalizedReferencesReplaced(result.getOptimizedProgram(), tracker); } public void testOrdinalizeMethodCallExpressionOrdinalFieldRef() @@ -228,43 +252,47 @@ " }", " return retVal;", "}"); - optimize("void", "int i = switchMethodCall(Fruit.APPLE);", + Result result = optimize("void", "int i = switchMethodCall(Fruit.APPLE);", "Fruit fruit = Fruit.ORANGE;", "int j = switchMethodCall(fruit);"); EnumOrdinalizer.Tracker tracker = EnumOrdinalizer.getTracker(); assertTrue(tracker.isOrdinalized("test.EntryPoint$Fruit")); + assertAllEnumOrdinalizedReferencesReplaced(result.getOptimizedProgram(), tracker); } public void testOrdinalizableStaticFieldRef() throws UnableToCompleteException { // this will cause a static field ref in the enum clinit setupFruitEnumWithStaticField(); - optimize("void", "String y = Fruit.staticField + Fruit.APPLE.ordinal();"); + Result result = optimize("void", "String y = Fruit.staticField + Fruit.APPLE.ordinal();"); EnumOrdinalizer.Tracker tracker = EnumOrdinalizer.getTracker(); assertTrue(tracker.isOrdinalized("test.EntryPoint$Fruit")); + assertAllEnumOrdinalizedReferencesReplaced(result.getOptimizedProgram(), tracker); } public void testOrdinalizableStaticMethod() throws UnableToCompleteException { // this will cause a static method enum class setupFruitEnumWithStaticMethod(); - optimize("void", "int y = Fruit.staticMethod() + Fruit.APPLE.ordinal();"); + Result result = optimize("void", "int y = Fruit.staticMethod() + Fruit.APPLE.ordinal();"); EnumOrdinalizer.Tracker tracker = EnumOrdinalizer.getTracker(); assertTrue(tracker.isOrdinalized("test.EntryPoint$Fruit")); + assertAllEnumOrdinalizedReferencesReplaced(result.getOptimizedProgram(), tracker); } public void testOrdinalizableCallingValues() throws UnableToCompleteException { setupFruitEnum(); - optimize("void", "int l = Fruit.values().length;", + Result result = optimize("void", "int l = Fruit.values().length;", "int ord = Fruit.APPLE.ordinal();"); EnumOrdinalizer.Tracker tracker = EnumOrdinalizer.getTracker(); assertTrue(tracker.isVisited("test.EntryPoint$Fruit")); assertTrue(tracker.isOrdinalized("test.EntryPoint$Fruit")); + assertAllEnumOrdinalizedReferencesReplaced(result.getOptimizedProgram(), tracker); } public void testOrdinalizableStaticFieldRefToVALUES() @@ -272,181 +300,196 @@ // this ends up inlining the values() method call, and thus $VALUES is referenced external // to the Fruit enum class. setupFruitEnum(); - optimize("void", "Fruit[] fruits = Fruit.values();", + Result result = optimize("void", "Fruit[] fruits = Fruit.values();", "int ord = Fruit.APPLE.ordinal();"); EnumOrdinalizer.Tracker tracker = EnumOrdinalizer.getTracker(); assertTrue(tracker.isVisited("test.EntryPoint$Fruit")); assertTrue(tracker.isOrdinalized("test.EntryPoint$Fruit")); + assertAllEnumOrdinalizedReferencesReplaced(result.getOptimizedProgram(), tracker); } public void testOrdinalizableStaticMethodThatRefsValuesLength() throws UnableToCompleteException { // this will cause a static method that references values().length setupFruitEnumWithStaticMethodThatRefsValuesLength(); - optimize("void", "Fruit y = Fruit.forInteger(0);", + Result result = optimize("void", "Fruit y = Fruit.forInteger(0);", "int ord = Fruit.APPLE.ordinal();"); EnumOrdinalizer.Tracker tracker = EnumOrdinalizer.getTracker(); assertTrue(tracker.isVisited("test.EntryPoint$Fruit")); assertTrue(tracker.isOrdinalized("test.EntryPoint$Fruit")); + assertAllEnumOrdinalizedReferencesReplaced(result.getOptimizedProgram(), tracker); } public void testNotOrdinalizableInstanceStaticFieldRef() throws UnableToCompleteException { // this will cause a static field ref in the enum clinit setupFruitEnumWithStaticField(); - optimize("void", "Fruit fruit = Fruit.APPLE;", + Result result = optimize("void", "Fruit fruit = Fruit.APPLE;", "String y = fruit.staticField;"); EnumOrdinalizer.Tracker tracker = EnumOrdinalizer.getTracker(); assertTrue(tracker.isVisited("test.EntryPoint$Fruit")); assertFalse(tracker.isOrdinalized("test.EntryPoint$Fruit")); + assertAllEnumOrdinalizedReferencesReplaced(result.getOptimizedProgram(), tracker); } public void testNotOrdinalizableInstanceStaticMethod() throws UnableToCompleteException { // this will cause a static method enum class setupFruitEnumWithStaticMethod(); - optimize("void", "Fruit fruit = Fruit.APPLE;", + Result result = optimize("void", "Fruit fruit = Fruit.APPLE;", "int y = fruit.staticMethod();"); EnumOrdinalizer.Tracker tracker = EnumOrdinalizer.getTracker(); assertTrue(tracker.isVisited("test.EntryPoint$Fruit")); assertFalse(tracker.isOrdinalized("test.EntryPoint$Fruit")); + assertAllEnumOrdinalizedReferencesReplaced(result.getOptimizedProgram(), tracker); } public void testNotOrdinalizableClassLiteralReference() throws UnableToCompleteException { setupFruitEnum(); - optimize("void", "Class clazz = Fruit.class;", + Result result = optimize("void", "Class clazz = Fruit.class;", "String clazzStr = clazz.toString() + Fruit.APPLE.ordinal();"); EnumOrdinalizer.Tracker tracker = EnumOrdinalizer.getTracker(); assertTrue(tracker.isVisited("test.EntryPoint$Fruit")); assertFalse(tracker.isOrdinalized("test.EntryPoint$Fruit")); + assertAllEnumOrdinalizedReferencesReplaced(result.getOptimizedProgram(), tracker); } public void testNotOrdinalizableEnumValueOfWithClassLiteralArg() throws UnableToCompleteException { setupFruitEnum(); - optimize("void", "Object Carrot = Enum.valueOf(Fruit.class, \"APPLE\");", + Result result = optimize("void", "Object Carrot = Enum.valueOf(Fruit.class, \"APPLE\");", "String carrot = Carrot.toString() + Fruit.APPLE.ordinal();"); EnumOrdinalizer.Tracker tracker = EnumOrdinalizer.getTracker(); assertTrue(tracker.isVisited("test.EntryPoint$Fruit")); assertFalse(tracker.isOrdinalized("test.EntryPoint$Fruit")); + assertAllEnumOrdinalizedReferencesReplaced(result.getOptimizedProgram(), tracker); } public void testNotOrdinalizableGetClassMethodCall() throws UnableToCompleteException { setupFruitEnum(); - optimize("void", "Class clazz = Fruit.APPLE.getClass();", + Result result = optimize("void", "Class clazz = Fruit.APPLE.getClass();", "String clazzStr = clazz.toString() + Fruit.APPLE.ordinal();"); EnumOrdinalizer.Tracker tracker = EnumOrdinalizer.getTracker(); assertTrue(tracker.isVisited("test.EntryPoint$Fruit")); assertFalse(tracker.isOrdinalized("test.EntryPoint$Fruit")); + assertAllEnumOrdinalizedReferencesReplaced(result.getOptimizedProgram(), tracker); } public void testNotOrdinalizableExplicitCastToEnumClass() throws UnableToCompleteException { setupFruitEnum(); - optimize("void", "Object obj = new Object();", + Result result = optimize("void", "Object obj = new Object();", "Fruit fruit = (Fruit) obj;", "int ord = Fruit.APPLE.ordinal();"); EnumOrdinalizer.Tracker tracker = EnumOrdinalizer.getTracker(); assertTrue(tracker.isVisited("test.EntryPoint$Fruit")); assertFalse(tracker.isOrdinalized("test.EntryPoint$Fruit")); + assertAllEnumOrdinalizedReferencesReplaced(result.getOptimizedProgram(), tracker); } public void testNotOrdinalizableExplicitCastToArrayOfEnumClass() throws UnableToCompleteException { setupFruitEnum(); - optimize("void", "Enum[] enumArray = new Enum[10];", + Result result = optimize("void", "Enum[] enumArray = new Enum[10];", "Fruit[] fruitArray = (Fruit[]) enumArray;", "int ord = Fruit.APPLE.ordinal();"); EnumOrdinalizer.Tracker tracker = EnumOrdinalizer.getTracker(); assertTrue(tracker.isVisited("test.EntryPoint$Fruit")); assertFalse(tracker.isOrdinalized("test.EntryPoint$Fruit")); + assertAllEnumOrdinalizedReferencesReplaced(result.getOptimizedProgram(), tracker); } public void testNotOrdinalizableExplicitCastFromArrayOfEnumClass() throws UnableToCompleteException { setupFruitEnum(); - optimize("void", "Fruit[] fruitArray = new Fruit[10];", + Result result = optimize("void", "Fruit[] fruitArray = new Fruit[10];", "Enum[] enumArray = (Enum[]) fruitArray;", "int ord = Fruit.APPLE.ordinal();"); EnumOrdinalizer.Tracker tracker = EnumOrdinalizer.getTracker(); assertTrue(tracker.isVisited("test.EntryPoint$Fruit")); assertFalse(tracker.isOrdinalized("test.EntryPoint$Fruit")); + assertAllEnumOrdinalizedReferencesReplaced(result.getOptimizedProgram(), tracker); } public void testNotOrdinalizableExplicitCastToArrayOfArrayOfEnumClass() throws UnableToCompleteException { setupFruitEnum(); - optimize("void", "Enum[][] enumArray = new Enum[10][10];", + Result result = optimize("void", "Enum[][] enumArray = new Enum[10][10];", "Fruit[][] fruitArray = (Fruit[][]) enumArray;", "int ord = Fruit.APPLE.ordinal();"); EnumOrdinalizer.Tracker tracker = EnumOrdinalizer.getTracker(); assertTrue(tracker.isVisited("test.EntryPoint$Fruit")); assertFalse(tracker.isOrdinalized("test.EntryPoint$Fruit")); + assertAllEnumOrdinalizedReferencesReplaced(result.getOptimizedProgram(), tracker); } public void testNotOrdinalizableExplicitCastFromArrayOfArrayOfEnumClass() throws UnableToCompleteException { setupFruitEnum(); - optimize("void", "Fruit[][] fruitArray = new Fruit[10][10];", + Result result = optimize("void", "Fruit[][] fruitArray = new Fruit[10][10];", "Enum[][] enumArray = (Enum[][]) fruitArray;", "int ord = Fruit.APPLE.ordinal();"); EnumOrdinalizer.Tracker tracker = EnumOrdinalizer.getTracker(); assertTrue(tracker.isVisited("test.EntryPoint$Fruit")); assertFalse(tracker.isOrdinalized("test.EntryPoint$Fruit")); + assertAllEnumOrdinalizedReferencesReplaced(result.getOptimizedProgram(), tracker); } public void testNotOrdinalizableExplicitCastFromEnumClass() throws UnableToCompleteException { setupFruitEnum(); - optimize("void", "Enum Carrot = (Enum) Fruit.APPLE;", + Result result = optimize("void", "Enum Carrot = (Enum) Fruit.APPLE;", "String carrot = Carrot.toString();"); EnumOrdinalizer.Tracker tracker = EnumOrdinalizer.getTracker(); assertTrue(tracker.isVisited("test.EntryPoint$Fruit")); assertFalse(tracker.isOrdinalized("test.EntryPoint$Fruit")); + assertAllEnumOrdinalizedReferencesReplaced(result.getOptimizedProgram(), tracker); } public void testNotOrdinalizableOrdinalMethodRefFromExplicitCastWithBlackListableSubExpression() throws UnableToCompleteException { setupFruitEnum(); - optimize("void", "int ord = " + + Result result = optimize("void", "int ord = " + "((Fruit) Enum.valueOf(Fruit.class,\"APPLE\")).ordinal();", "int ord2 = Fruit.APPLE.ordinal();"); EnumOrdinalizer.Tracker tracker = EnumOrdinalizer.getTracker(); assertTrue(tracker.isVisited("test.EntryPoint$Fruit")); assertFalse(tracker.isOrdinalized("test.EntryPoint$Fruit")); + assertAllEnumOrdinalizedReferencesReplaced(result.getOptimizedProgram(), tracker); } public void testNotOrdinalizableInstanceFieldRef() throws UnableToCompleteException { // this will cause an instance field ref in the enum constructor setupFruitEnumWithInstanceField(); - optimize("void", "String instanceField = Fruit.APPLE.instanceField;"); + Result result = optimize("void", "String instanceField = Fruit.APPLE.instanceField;"); EnumOrdinalizer.Tracker tracker = EnumOrdinalizer.getTracker(); assertTrue(tracker.isVisited("test.EntryPoint$Fruit")); assertFalse(tracker.isOrdinalized("test.EntryPoint$Fruit")); + assertAllEnumOrdinalizedReferencesReplaced(result.getOptimizedProgram(), tracker); } public void testNotOrdinalizableInstanceOfEnumExpression() throws UnableToCompleteException { setupFruitEnum(); - optimize("void", "Fruit fruit = Fruit.APPLE;", + Result result = optimize("void", "Fruit fruit = Fruit.APPLE;", "if (fruit instanceof Enum) {", " fruit = Fruit.ORANGE;", "}"); @@ -454,12 +497,13 @@ EnumOrdinalizer.Tracker tracker = EnumOrdinalizer.getTracker(); assertTrue(tracker.isVisited("test.EntryPoint$Fruit")); assertFalse(tracker.isOrdinalized("test.EntryPoint$Fruit")); + assertAllEnumOrdinalizedReferencesReplaced(result.getOptimizedProgram(), tracker); } public void testNotOrdinalizableInstanceOfEnumTestType() throws UnableToCompleteException { setupFruitEnum(); - optimize("void", "Object fruitObj = new Object();", + Result result = optimize("void", "Object fruitObj = new Object();", "if (fruitObj instanceof Fruit) {", " fruitObj = null;", "}", @@ -468,6 +512,7 @@ EnumOrdinalizer.Tracker tracker = EnumOrdinalizer.getTracker(); assertTrue(tracker.isVisited("test.EntryPoint$Fruit")); assertFalse(tracker.isOrdinalized("test.EntryPoint$Fruit")); + assertAllEnumOrdinalizedReferencesReplaced(result.getOptimizedProgram(), tracker); } public void testNotOrdinalizableStaticMethodCallValues() @@ -476,12 +521,13 @@ runMethodInliner = false; setupFruitEnum(); - optimize("void", "Fruit[] fruits = Fruit.values();", + Result result = optimize("void", "Fruit[] fruits = Fruit.values();", "int ord = Fruit.APPLE.ordinal();"); EnumOrdinalizer.Tracker tracker = EnumOrdinalizer.getTracker(); assertTrue(tracker.isVisited("test.EntryPoint$Fruit")); assertFalse(tracker.isOrdinalized("test.EntryPoint$Fruit")); + assertAllEnumOrdinalizedReferencesReplaced(result.getOptimizedProgram(), tracker); } public void testNotOrdinalizableJsniFieldRef() @@ -491,13 +537,14 @@ addSnippetClassDecl("public static native void jsniMethod() /*-{", " var x = @test.EntryPoint::instanceFruit", "}-*/"); - optimize("void", "instanceFruit = Fruit.APPLE;", + Result result = optimize("void", "instanceFruit = Fruit.APPLE;", "jsniMethod();", "int ord = Fruit.APPLE.ordinal();"); EnumOrdinalizer.Tracker tracker = EnumOrdinalizer.getTracker(); assertTrue(tracker.isVisited("test.EntryPoint$Fruit")); assertFalse(tracker.isOrdinalized("test.EntryPoint$Fruit")); + assertAllEnumOrdinalizedReferencesReplaced(result.getOptimizedProgram(), tracker); } public void testNotOrdinalizableJsniFieldRefStatic() @@ -506,12 +553,13 @@ addSnippetClassDecl("public static native void jsniMethod() /*-{", " var x = @test.EntryPoint.Fruit::APPLE", "}-*/"); - optimize("void", "jsniMethod();", + Result result = optimize("void", "jsniMethod();", "int ord = Fruit.APPLE.ordinal();"); EnumOrdinalizer.Tracker tracker = EnumOrdinalizer.getTracker(); assertTrue(tracker.isVisited("test.EntryPoint$Fruit")); assertFalse(tracker.isOrdinalized("test.EntryPoint$Fruit")); + assertAllEnumOrdinalizedReferencesReplaced(result.getOptimizedProgram(), tracker); } public void testNotOrdinalizableJsniFieldRefClassLiteral() @@ -520,18 +568,19 @@ addSnippetClassDecl("public static native void jsniMethod() /*-{", " var x = @test.EntryPoint.Fruit::class", "}-*/"); - optimize("void", "jsniMethod();", + Result result = optimize("void", "jsniMethod();", "int ord = Fruit.APPLE.ordinal();"); EnumOrdinalizer.Tracker tracker = EnumOrdinalizer.getTracker(); assertTrue(tracker.isVisited("test.EntryPoint$Fruit")); assertFalse(tracker.isOrdinalized("test.EntryPoint$Fruit")); + assertAllEnumOrdinalizedReferencesReplaced(result.getOptimizedProgram(), tracker); } public void testNotOrdinalizableImplicitUpcastBinaryOpAssignment() throws UnableToCompleteException { setupFruitEnum(); - optimize("void", + Result result = optimize("void", "Enum tomato;", "tomato = Fruit.APPLE;", "int ord = tomato.ordinal();"); @@ -539,13 +588,14 @@ EnumOrdinalizer.Tracker tracker = EnumOrdinalizer.getTracker(); assertTrue(tracker.isVisited("test.EntryPoint$Fruit")); assertFalse(tracker.isOrdinalized("test.EntryPoint$Fruit")); + assertAllEnumOrdinalizedReferencesReplaced(result.getOptimizedProgram(), tracker); } public void testNotOrdinalizableImplicitUpcastFieldInitializedWithNullByDefault() throws UnableToCompleteException { setupFruitEnum(); addSnippetClassDecl("static private Fruit uninitializedFruitAsNull;"); - optimize("void", "if (uninitializedFruitAsNull != Fruit.APPLE) {", + Result result = optimize("void", "if (uninitializedFruitAsNull != Fruit.APPLE) {", " uninitializedFruitAsNull = Fruit.ORANGE;", "}", "int ord = Fruit.APPLE.ordinal();"); @@ -553,13 +603,14 @@ EnumOrdinalizer.Tracker tracker = EnumOrdinalizer.getTracker(); assertTrue(tracker.isVisited("test.EntryPoint$Fruit")); assertFalse(tracker.isOrdinalized("test.EntryPoint$Fruit")); + assertAllEnumOrdinalizedReferencesReplaced(result.getOptimizedProgram(), tracker); } public void testNotOrdinalizableImplicitUpcastBinaryOpEquals() throws UnableToCompleteException { setupFruitEnum(); setupVegetableEnum(); - optimize("void", "Fruit fruit = Fruit.APPLE;", + Result result = optimize("void", "Fruit fruit = Fruit.APPLE;", "Enum carrot = (Enum) Vegetable.CARROT;", "boolean test = (fruit == carrot);"); @@ -568,13 +619,14 @@ assertFalse(tracker.isOrdinalized("test.EntryPoint$Fruit")); assertTrue(tracker.isVisited("test.EntryPoint$Vegetable")); assertFalse(tracker.isOrdinalized("test.EntryPoint$Vegetable")); + assertAllEnumOrdinalizedReferencesReplaced(result.getOptimizedProgram(), tracker); } public void testNotOrdinalizableImplicitUpcastBinaryOpNotEquals() throws UnableToCompleteException { setupFruitEnum(); setupVegetableEnum(); - optimize("void", "Fruit fruit = Fruit.APPLE;", + Result result = optimize("void", "Fruit fruit = Fruit.APPLE;", "Enum carrot = (Enum) Vegetable.CARROT;", // do in opposite order from OpEquals test "boolean test = (carrot != fruit);"); @@ -584,6 +636,7 @@ assertFalse(tracker.isOrdinalized("test.EntryPoint$Fruit")); assertTrue(tracker.isVisited("test.EntryPoint$Vegetable")); assertFalse(tracker.isOrdinalized("test.EntryPoint$Vegetable")); + assertAllEnumOrdinalizedReferencesReplaced(result.getOptimizedProgram(), tracker); } public void testNotOrdinalizableImplicitUpcastBinaryOpEqualsNull() @@ -592,16 +645,17 @@ addSnippetClassDecl("public static boolean testIsNull(Fruit fruit) {", " if (fruit == null) {", " return true;", - " } else {", + " } else {", " return false;", - " }", + " }", "}"); - optimize("void", "Fruit fruit = Fruit.APPLE;", + Result result = optimize("void", "Fruit fruit = Fruit.APPLE;", "boolean isNull = testIsNull(fruit) || testIsNull(Fruit.ORANGE);"); EnumOrdinalizer.Tracker tracker = EnumOrdinalizer.getTracker(); assertTrue(tracker.isVisited("test.EntryPoint$Fruit")); assertFalse(tracker.isOrdinalized("test.EntryPoint$Fruit")); + assertAllEnumOrdinalizedReferencesReplaced(result.getOptimizedProgram(), tracker); } public void testNotOrdinalizableImplicitUpcastBinaryOpNotEqualsNull() @@ -614,87 +668,94 @@ " return false;", " }", "}"); - optimize("void", "Fruit fruit = Fruit.APPLE;", + Result result = optimize("void", "Fruit fruit = Fruit.APPLE;", "boolean isNull = testIsNull(fruit) || testIsNull(Fruit.ORANGE);"); EnumOrdinalizer.Tracker tracker = EnumOrdinalizer.getTracker(); assertTrue(tracker.isVisited("test.EntryPoint$Fruit")); assertFalse(tracker.isOrdinalized("test.EntryPoint$Fruit")); + assertAllEnumOrdinalizedReferencesReplaced(result.getOptimizedProgram(), tracker); } public void testNotOrdinalizableImplicitUpcastBinaryOpStringConcat() throws UnableToCompleteException { setupFruitEnum(); - optimize("void", "Fruit fruit = Fruit.APPLE;", + Result result = optimize("void", "Fruit fruit = Fruit.APPLE;", "String str = \"A string followed by \" + fruit;"); EnumOrdinalizer.Tracker tracker = EnumOrdinalizer.getTracker(); assertTrue(tracker.isVisited("test.EntryPoint$Fruit")); assertFalse(tracker.isOrdinalized("test.EntryPoint$Fruit")); + assertAllEnumOrdinalizedReferencesReplaced(result.getOptimizedProgram(), tracker); } public void testNotOrdinalizableImplicitUpcastBinaryOpStringConcat2() throws UnableToCompleteException { setupFruitEnum(); - optimize("void", "Fruit fruit = Fruit.APPLE;", + Result result = optimize("void", "Fruit fruit = Fruit.APPLE;", "String str = fruit + \" followed by a string\";"); EnumOrdinalizer.Tracker tracker = EnumOrdinalizer.getTracker(); assertTrue(tracker.isVisited("test.EntryPoint$Fruit")); assertFalse(tracker.isOrdinalized("test.EntryPoint$Fruit")); + assertAllEnumOrdinalizedReferencesReplaced(result.getOptimizedProgram(), tracker); } public void testNotOrdinalizableImplicitUpcastBinaryOpStringConcatAssignment() throws UnableToCompleteException { setupFruitEnum(); - optimize("void", "Fruit fruit = Fruit.APPLE;", + Result result = optimize("void", "Fruit fruit = Fruit.APPLE;", "String str = \"A string concatenated with: \";", "str += fruit;"); EnumOrdinalizer.Tracker tracker = EnumOrdinalizer.getTracker(); assertTrue(tracker.isVisited("test.EntryPoint$Fruit")); assertFalse(tracker.isOrdinalized("test.EntryPoint$Fruit")); + assertAllEnumOrdinalizedReferencesReplaced(result.getOptimizedProgram(), tracker); } public void testNotOrdinalizableImplicitUpcastDeclarationToNull() throws UnableToCompleteException { setupFruitEnum(); - optimize("void", "Fruit fruit = null;", + Result result = optimize("void", "Fruit fruit = null;", "int ord = fruit == null ? Fruit.APPLE.ordinal() : fruit.ordinal();"); EnumOrdinalizer.Tracker tracker = EnumOrdinalizer.getTracker(); assertTrue(tracker.isVisited("test.EntryPoint$Fruit")); assertFalse(tracker.isOrdinalized("test.EntryPoint$Fruit")); + assertAllEnumOrdinalizedReferencesReplaced(result.getOptimizedProgram(), tracker); } public void testNotOrdinalizableImplicitUpcastAssignmentToNull() throws UnableToCompleteException { setupFruitEnum(); - optimize("void", "Fruit fruit;", + Result result = optimize("void", "Fruit fruit;", "fruit = null;", "int ord = fruit == null ? Fruit.APPLE.ordinal() : fruit.ordinal();"); EnumOrdinalizer.Tracker tracker = EnumOrdinalizer.getTracker(); assertTrue(tracker.isVisited("test.EntryPoint$Fruit")); assertFalse(tracker.isOrdinalized("test.EntryPoint$Fruit")); + assertAllEnumOrdinalizedReferencesReplaced(result.getOptimizedProgram(), tracker); } public void testNotOrdinalizableImplicitUpcastDeclaration() throws UnableToCompleteException { setupFruitEnum(); - optimize("void", "Enum tomato = Fruit.APPLE;", + Result result = optimize("void", "Enum tomato = Fruit.APPLE;", "int ord = Fruit.APPLE.ordinal() + tomato.ordinal();"); EnumOrdinalizer.Tracker tracker = EnumOrdinalizer.getTracker(); assertTrue(tracker.isVisited("test.EntryPoint$Fruit")); assertFalse(tracker.isOrdinalized("test.EntryPoint$Fruit")); + assertAllEnumOrdinalizedReferencesReplaced(result.getOptimizedProgram(), tracker); } public void testNotOrdinalizableImplicitUpcastConditional() throws UnableToCompleteException { setupFruitEnum(); setupVegetableEnum(); - optimize("void", "Enum tomato = null;", + Result result = optimize("void", "Enum tomato = null;", "tomato = (true) ? Fruit.APPLE : Vegetable.CARROT;", "int ord = Fruit.APPLE.ordinal() + Vegetable.CARROT.ordinal() + tomato.ordinal();"); @@ -703,6 +764,7 @@ assertFalse(tracker.isOrdinalized("test.EntryPoint$Fruit")); assertTrue(tracker.isVisited("test.EntryPoint$Vegetable")); assertTrue(tracker.isOrdinalized("test.EntryPoint$Vegetable")); + assertAllEnumOrdinalizedReferencesReplaced(result.getOptimizedProgram(), tracker); } public void testNotOrdinalizableImplicitUpcastOverriddenMethodReturnType() @@ -738,7 +800,7 @@ addSnippetClassDecl("public static void testEnumClass(AbstractClass abstractClass) {", " EnumInterface enumClass = abstractClass.getEnumClass();", "}"); - optimize("void", "EntryPoint ep = new EntryPoint();", + Result result = optimize("void", "EntryPoint ep = new EntryPoint();", "AbstractClass abstractClass1 = ep.new CustomClass1();", "AbstractClass abstractClass2 = ep.new CustomClass2();", "testEnumClass(abstractClass1);", @@ -749,6 +811,7 @@ assertFalse(tracker.isOrdinalized("test.EntryPoint$EnumClass1")); assertTrue(tracker.isVisited("test.EntryPoint$EnumClass2")); assertFalse(tracker.isOrdinalized("test.EntryPoint$EnumClass2")); + assertAllEnumOrdinalizedReferencesReplaced(result.getOptimizedProgram(), tracker); } public void testNotOrdinalizableImplicitUpcastMethodCallArgs() @@ -764,11 +827,12 @@ " retString += myEnum.name();", " return retString;", "}"); - optimize("void", "String stringApple = getEnumString(Fruit.APPLE);"); + Result result = optimize("void", "String stringApple = getEnumString(Fruit.APPLE);"); EnumOrdinalizer.Tracker tracker = EnumOrdinalizer.getTracker(); assertTrue(tracker.isVisited("test.EntryPoint$Fruit")); assertFalse(tracker.isOrdinalized("test.EntryPoint$Fruit")); + assertAllEnumOrdinalizedReferencesReplaced(result.getOptimizedProgram(), tracker); } public void testNotOrdinalizableImplicitUpcastMethodCallArgsNewArray() @@ -781,12 +845,13 @@ " }", " return retString;", "}"); - optimize("void", + Result result = optimize("void", "String stringFruits = getEnumString(new Enum[] {Fruit.APPLE, Fruit.ORANGE});"); EnumOrdinalizer.Tracker tracker = EnumOrdinalizer.getTracker(); assertTrue(tracker.isVisited("test.EntryPoint$Fruit")); assertFalse(tracker.isOrdinalized("test.EntryPoint$Fruit")); + assertAllEnumOrdinalizedReferencesReplaced(result.getOptimizedProgram(), tracker); } public void testNotOrdinalizableImplicitUpcastMethodCallVarArgs() @@ -799,32 +864,36 @@ " }", " return retString;", "}"); - optimize("void", "String stringFruits = getEnumString(Fruit.APPLE, Fruit.ORANGE);"); + Result result = optimize("void", + "String stringFruits = getEnumString(Fruit.APPLE, Fruit.ORANGE);"); EnumOrdinalizer.Tracker tracker = EnumOrdinalizer.getTracker(); assertTrue(tracker.isVisited("test.EntryPoint$Fruit")); assertFalse(tracker.isOrdinalized("test.EntryPoint$Fruit")); + assertAllEnumOrdinalizedReferencesReplaced(result.getOptimizedProgram(), tracker); } public void testNotOrdinalizableImplicitUpcastNewArrayElements() throws UnableToCompleteException { setupFruitEnum(); - optimize("void", "Enum[] enums = new Enum[] {Fruit.APPLE, Fruit.ORANGE};"); + Result result = optimize("void", "Enum[] enums = new Enum[] {Fruit.APPLE, Fruit.ORANGE};"); EnumOrdinalizer.Tracker tracker = EnumOrdinalizer.getTracker(); assertTrue(tracker.isVisited("test.EntryPoint$Fruit")); assertFalse(tracker.isOrdinalized("test.EntryPoint$Fruit")); + assertAllEnumOrdinalizedReferencesReplaced(result.getOptimizedProgram(), tracker); } public void testNotOrdinalizableImplicitUpcastNewArrayArrayElements() throws UnableToCompleteException { setupFruitEnum(); - optimize("void", + Result result = optimize("void", "Enum[][] enums = new Enum[][] {{Fruit.APPLE, Fruit.ORANGE},{Fruit.ORANGE, Fruit.APPLE}};"); EnumOrdinalizer.Tracker tracker = EnumOrdinalizer.getTracker(); assertTrue(tracker.isVisited("test.EntryPoint$Fruit")); assertFalse(tracker.isOrdinalized("test.EntryPoint$Fruit")); + assertAllEnumOrdinalizedReferencesReplaced(result.getOptimizedProgram(), tracker); } public void testNotOrdinalizableJsniMethodBodyParams() @@ -832,11 +901,12 @@ setupFruitEnum(); addSnippetClassDecl("public static native void passEnumToJsniMethod(Enum myEnum) /*-{", " myEnum == null; }-*/"); - optimize("void", "passEnumToJsniMethod(Fruit.APPLE);"); + Result result = optimize("void", "passEnumToJsniMethod(Fruit.APPLE);"); EnumOrdinalizer.Tracker tracker = EnumOrdinalizer.getTracker(); assertTrue(tracker.isVisited("test.EntryPoint$Fruit")); assertFalse(tracker.isOrdinalized("test.EntryPoint$Fruit")); + assertAllEnumOrdinalizedReferencesReplaced(result.getOptimizedProgram(), tracker); } public void testNotOrdinalizableImplicitUpcastJsniMethodBodyParams() @@ -844,11 +914,12 @@ setupFruitEnum(); addSnippetClassDecl("public static native void passEnumToJsniMethod(Fruit myEnum) /*-{", " myEnum == null; }-*/;"); - optimize("void", "passEnumToJsniMethod(Fruit.APPLE);"); + Result result = optimize("void", "passEnumToJsniMethod(Fruit.APPLE);"); EnumOrdinalizer.Tracker tracker = EnumOrdinalizer.getTracker(); assertTrue(tracker.isVisited("test.EntryPoint$Fruit")); assertFalse(tracker.isOrdinalized("test.EntryPoint$Fruit")); + assertAllEnumOrdinalizedReferencesReplaced(result.getOptimizedProgram(), tracker); } public void testNotOrdinalizableJsniMethodBodyCall() @@ -860,12 +931,13 @@ "public static Fruit calledFromJsni() {", " return Fruit.APPLE;", "}"); - optimize("void", "consumeFruitViaJsni();", + Result result = optimize("void", "consumeFruitViaJsni();", "int ord = Fruit.APPLE.ordinal();"); EnumOrdinalizer.Tracker tracker = EnumOrdinalizer.getTracker(); assertTrue(tracker.isVisited("test.EntryPoint$Fruit")); assertFalse(tracker.isOrdinalized("test.EntryPoint$Fruit")); + assertAllEnumOrdinalizedReferencesReplaced(result.getOptimizedProgram(), tracker); } public void testNotOrdinalizableImplicitUpcastJsniMethodRefParams() @@ -876,12 +948,13 @@ " var myJso;", " var result = @test.EntryPoint::fruitSwitch(Ltest/EntryPoint$Fruit;)(myJso);", "}-*/"); - optimize("void", "fruitSwitchViaJsni();", + Result result = optimize("void", "fruitSwitchViaJsni();", "int ord = Fruit.APPLE.ordinal();"); EnumOrdinalizer.Tracker tracker = EnumOrdinalizer.getTracker(); assertTrue(tracker.isVisited("test.EntryPoint$Fruit")); assertFalse(tracker.isOrdinalized("test.EntryPoint$Fruit")); + assertAllEnumOrdinalizedReferencesReplaced(result.getOptimizedProgram(), tracker); } public void testNotOrdinalizableImplicitUpcastJsniMethodRefReturnType() @@ -893,12 +966,13 @@ addSnippetClassDecl("public static native void jsniMethodRefWithEnumReturn() /*-{", " var result = @test.EntryPoint::returnSomeFruit()();", "}-*/"); - optimize("void", "jsniMethodRefWithEnumReturn();", + Result result = optimize("void", "jsniMethodRefWithEnumReturn();", "int ord = Fruit.APPLE.ordinal();"); EnumOrdinalizer.Tracker tracker = EnumOrdinalizer.getTracker(); assertTrue(tracker.isVisited("test.EntryPoint$Fruit")); assertFalse(tracker.isOrdinalized("test.EntryPoint$Fruit")); + assertAllEnumOrdinalizedReferencesReplaced(result.getOptimizedProgram(), tracker); } public void testNotOrdinalizableImplicitUpcastReturnStatement() @@ -912,7 +986,7 @@ " return Vegetable.CARROT;", " }", "}"); - optimize("void", "Enum myEnum = returnAsEnum(0);", + Result result = optimize("void", "Enum myEnum = returnAsEnum(0);", // do a second one, to prevent inlining "Enum myOtherEnum = returnAsEnum(1);", "int ord = Fruit.APPLE.ordinal() + Vegetable.CARROT.ordinal();"); @@ -922,6 +996,7 @@ assertFalse(tracker.isOrdinalized("test.EntryPoint$Fruit")); assertTrue(tracker.isVisited("test.EntryPoint$Vegetable")); assertFalse(tracker.isOrdinalized("test.EntryPoint$Vegetable")); + assertAllEnumOrdinalizedReferencesReplaced(result.getOptimizedProgram(), tracker); } private void setupEmptyEnum() { @@ -1043,4 +1118,23 @@ return didChange; } + + private void assertAllEnumOrdinalizedReferencesReplaced(JProgram program, final Tracker tracker) { + new JVisitor() { + @Override + public void endVisit(JFieldRef x, Context ctx) { + assertTrue(x.getField() + " was not replaced everywhere", + ctx.isLvalue() || !tracker.isOrdinalized(x.getEnclosingType().getName())); + } + + @Override + public void endVisit(JDeclarationStatement x, Context ctx) { + assertTrue(x.getVariableRef().getTarget() + " was not replaced everywhere", + x.getInitializer() instanceof JValueLiteral || + !(x.getVariableRef() instanceof JFieldRef) || + !tracker.isOrdinalized( + ((JFieldRef) x.getVariableRef()).getField().getEnclosingType().getName())); + } + }.accept(program); + } }
diff --git a/dev/core/test/com/google/gwt/dev/jjs/impl/OptimizerTestBase.java b/dev/core/test/com/google/gwt/dev/jjs/impl/OptimizerTestBase.java index 8829e50..7945681 100644 --- a/dev/core/test/com/google/gwt/dev/jjs/impl/OptimizerTestBase.java +++ b/dev/core/test/com/google/gwt/dev/jjs/impl/OptimizerTestBase.java
@@ -133,6 +133,10 @@ public JDeclaredType findClass(String className) { return OptimizerTestBase.findDeclaredType(optimizedProgram, className); } + + public JProgram getOptimizedProgram() { + return optimizedProgram; + } } /**