Fix compiler exception in SuperDevMode. Commit e261a009786 (Double and Booleans as native types) introduced an error that causes the compiler to abort during UnifyAST due to having only partially processed types like Double that require devirtualization. Change-Id: Id8bb52ae7566e8e11b4ec901b38443e3a8b9d6c3
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 304e50a..a437cda 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
@@ -29,8 +29,10 @@ import com.google.gwt.dev.util.log.speedtracer.SpeedTracerLogger; import com.google.gwt.dev.util.log.speedtracer.SpeedTracerLogger.Event; import com.google.gwt.thirdparty.guava.common.base.Function; +import com.google.gwt.thirdparty.guava.common.base.Predicates; import com.google.gwt.thirdparty.guava.common.collect.BiMap; import com.google.gwt.thirdparty.guava.common.collect.Collections2; +import com.google.gwt.thirdparty.guava.common.collect.FluentIterable; import com.google.gwt.thirdparty.guava.common.collect.HashBiMap; import com.google.gwt.thirdparty.guava.common.collect.ImmutableList; import com.google.gwt.thirdparty.guava.common.collect.ImmutableMap; @@ -65,9 +67,11 @@ public enum DispatchType { // These this list can be extended by creating the appropriate fields/methods on Cast, // as well as extending the TypeCategory enum and updating EqualityNormalizer. - STRING(true), - DOUBLE(true), + // The order in which these native types appear is the inverse as the way they are + // checked by devirtualized method. BOOLEAN(true), + DOUBLE(true), + STRING(true), // non-native represented type values. HAS_JAVA_VIRTUAL_DISPATCH(false), JAVA_ARRAY(false), JSO(false); @@ -76,6 +80,7 @@ private final String castMapField; private final TypeCategory typeCategory; private final String dynamicCastMethod; + private final String className; DispatchType(boolean nativeType) { if (nativeType) { @@ -90,11 +95,13 @@ this.castMapField = "Cast." + name().toLowerCase() + "CastMap"; this.dynamicCastMethod = "Cast.dynamicCastTo" + camelCase(name()); this.typeCategory = TypeCategory.valueOf("TYPE_JAVA_LANG_" + name()); + this.className = "java.lang." + camelCase(name()); } else { - instanceOfMethod = null; - castMapField = null; - typeCategory = null; - dynamicCastMethod = null; + this.instanceOfMethod = null; + this.castMapField = null; + this.typeCategory = null; + this.dynamicCastMethod = null; + this.className = null; } } @@ -117,6 +124,10 @@ public String getDynamicCastMethod() { return dynamicCastMethod; } + + public String getclassName() { + return className; + } } /** @@ -372,7 +383,7 @@ private FragmentPartitioningResult fragmentPartitioningResult; - private Map<JClassType, DispatchType> nativeType2DispatchType; + private Map<JClassType, DispatchType> dispatchTypeByNativeType; /** * Add a pinned method. @@ -455,6 +466,16 @@ } } + public static boolean isRepresentedAsNative(String className) { + return FluentIterable.from(Arrays.asList(DispatchType.values())).transform( + new Function<DispatchType, String>() { + @Override + public String apply(DispatchType dispatchType) { + return dispatchType.getclassName(); + } + }).filter(Predicates.notNull()).toSet().contains(className); + } + public boolean isRepresentedAsNativeJsPrimitive(JType type) { return getRepresentedAsNativeTypes().contains(type); } @@ -464,15 +485,19 @@ } public Map<JClassType, DispatchType> getRepresentedAsNativeTypesDispatchMap() { - if (nativeType2DispatchType == null) { - // these are returned in the reverse order in which they are checked - // because devirtualizer constructs the nested expressions from the inside out. - nativeType2DispatchType = ImmutableMap.of( - typeBoolean, DispatchType.BOOLEAN, - typeDouble, DispatchType.DOUBLE, - typeString, DispatchType.STRING); + if (dispatchTypeByNativeType == null) { + ImmutableMap.Builder builder = new ImmutableMap.Builder(); + for (DispatchType dispatchType : DispatchType.values()) { + if (dispatchType.getclassName() == null) { + continue; + } + JClassType classType = (JClassType) getFromTypeMap(dispatchType.getclassName()); + assert classType != null : "Class " + dispatchType.getclassName() + " has not been loaded"; + builder.put(classType, dispatchType); + } + dispatchTypeByNativeType = builder.build(); } - return nativeType2DispatchType; + return dispatchTypeByNativeType; } public EnumSet<DispatchType> getDispatchType(JReferenceType type) {
diff --git a/dev/core/src/com/google/gwt/dev/jjs/impl/UnifyAst.java b/dev/core/src/com/google/gwt/dev/jjs/impl/UnifyAst.java index 6b2bc0c..2bad71d 100644 --- a/dev/core/src/com/google/gwt/dev/jjs/impl/UnifyAst.java +++ b/dev/core/src/com/google/gwt/dev/jjs/impl/UnifyAst.java
@@ -1354,7 +1354,10 @@ private boolean requiresDevirtualization(JDeclaredType type) { // NOTE: these types are the ones {@link Devirtualizer} handles. - return isJso(type) || type == program.getTypeJavaLangString(); + return isJso(type) || + // Use the version that takes names instead of instances as some + // relevant instances might have not been leaded yet. + JProgram.isRepresentedAsNative(type.getName()); } private boolean isJso(JDeclaredType type) {
diff --git a/dev/core/test/com/google/gwt/dev/CompilerTest.java b/dev/core/test/com/google/gwt/dev/CompilerTest.java index ae49c8c..e61e312 100644 --- a/dev/core/test/com/google/gwt/dev/CompilerTest.java +++ b/dev/core/test/com/google/gwt/dev/CompilerTest.java
@@ -1262,6 +1262,14 @@ checkIncrementalRecompile_devirtualizeString(JsOutputOption.DETAILED); } + public void testIncrementalRecompile_devirtualizeComparable() + throws UnableToCompleteException, IOException, InterruptedException { + // Tests that Doublecalls through interfaces are correctly devirtualized when compiling per + // file and neither String nor CharSequence interface are stale. + checkIncrementalRecompile_devirtualizeComparable(JsOutputOption.OBFUSCATED); + checkIncrementalRecompile_devirtualizeComparable(JsOutputOption.DETAILED); + } + public void testIncrementalRecompile_multipleClassGenerator() throws UnableToCompleteException, IOException, InterruptedException { // Tests that a Generated type that is not directly referenced from the rebound GWT.create() @@ -1625,15 +1633,15 @@ MinimalRebuildCache relinkMinimalRebuildCache = new MinimalRebuildCache(); File relinkApplicationDir = Files.createTempDir(); - String originalJs = compileToJs(relinkApplicationDir, "com.foo.SimpleModule", Lists - .newArrayList(simpleModuleResource, simpleModelEntryPointResource, simpleModelResource, + String originalJs = compileToJs(relinkApplicationDir, "com.foo.SimpleModule", + Lists.newArrayList(simpleModuleResource, simpleModelEntryPointResource, simpleModelResource, constantsModelResource), relinkMinimalRebuildCache, emptySet, output); // Compile again with the same source but a new date stamp on SimpleModel and reusing the // minimalRebuildCache. String relinkedJs = compileToJs(relinkApplicationDir, "com.foo.SimpleModule", - Lists.<MockResource> newArrayList(simpleModelResource), relinkMinimalRebuildCache, + Lists.<MockResource>newArrayList(simpleModelResource), relinkMinimalRebuildCache, stringSet("com.foo.TestEntryPoint", "com.foo.SimpleModel"), output); assertTrue(originalJs.equals(relinkedJs)); @@ -1810,6 +1818,39 @@ output); } + private void checkIncrementalRecompile_devirtualizeComparable(JsOutputOption output) + throws UnableToCompleteException, IOException, InterruptedException { + + final MockResource devirtualizeComparableModuleResource = + JavaResourceBase.createMockResource("com/foo/DevirtualizeComparableModule.gwt.xml", + "<module>", + "<source path=''/>", + "<entry-point class='com.foo.DevirtualizeComparableEntryPoint'/>", + "</module>"); + + final MockJavaResource devirtualizeComparableEntryPointResource = + JavaResourceBase.createMockJavaResource("com.foo.DevirtualizeComparableEntryPoint", + "package com.foo;", + "import com.google.gwt.core.client.EntryPoint;", + "public class DevirtualizeComparableEntryPoint implements EntryPoint {", + " @Override", + " public void onModuleLoad() {", + " Comparable c = (Double) 0.1;", + " c.compareTo(c);", + " }", + "}"); + + CompilerOptions compilerOptions = new CompilerOptionsImpl(); + compilerOptions.setUseDetailedTypeIds(true); + + checkRecompiledModifiedApp(compilerOptions, "com.foo.DevirtualizeComparableModule", + Lists.newArrayList(devirtualizeComparableModuleResource), + devirtualizeComparableEntryPointResource, devirtualizeComparableEntryPointResource, + stringSet("com.foo.DevirtualizeComparableEntryPoint", + getEntryMethodHolderTypeName("com.foo.DevirtualizeComparableModule")), + output); + } + private void checkIncrementalRecompile_multipleClassGenerator(JsOutputOption output) throws UnableToCompleteException, IOException, InterruptedException { CompilerOptions compilerOptions = new CompilerOptionsImpl();