Simplify RuntypeTypeId generation.

Change-Id: I4a5ad99b849e7c2b04ab56b6320f5c83b2ab2a88
diff --git a/dev/core/src/com/google/gwt/dev/jjs/JavaToJavaScriptCompiler.java b/dev/core/src/com/google/gwt/dev/jjs/JavaToJavaScriptCompiler.java
index 133ac68..1546051 100644
--- a/dev/core/src/com/google/gwt/dev/jjs/JavaToJavaScriptCompiler.java
+++ b/dev/core/src/com/google/gwt/dev/jjs/JavaToJavaScriptCompiler.java
@@ -1492,7 +1492,7 @@
     }
 
     if (this.options.useDetailedTypeIds()) {
-      return new StringTypeMapper();
+      return new StringTypeMapper(jprogram);
     }
     return this.options.isIncrementalCompileEnabled() ?
         compilerContext.getMinimalRebuildCache().getTypeMapper() :
diff --git a/dev/core/src/com/google/gwt/dev/jjs/impl/GenerateJavaScriptAST.java b/dev/core/src/com/google/gwt/dev/jjs/impl/GenerateJavaScriptAST.java
index af64f2f..0e8a567 100644
--- a/dev/core/src/com/google/gwt/dev/jjs/impl/GenerateJavaScriptAST.java
+++ b/dev/core/src/com/google/gwt/dev/jjs/impl/GenerateJavaScriptAST.java
@@ -947,7 +947,7 @@
         // then we could do Type.prototype.polyname.call(this, ...). Currently prototypes do not
         // have global names instead they are stuck into the prototypesByTypeId array.
         return constructInvocation(sourceInfo, "JavaClassHierarchySetupUtil.getClassPrototype",
-            convertJavaLiteral(typeMapper.get(type)));
+            (JsExpression) transform(getRuntimeTypeReference(type)));
       }
     }
 
@@ -2000,7 +2000,6 @@
 
     private void generateCallToDefineClass(JClassType x,
         List<JsNameRef> constructorArgs) {
-      JExpression typeId = getRuntimeTypeReference(x);
       JClassType superClass = x.getSuperClass();
       JExpression superTypeId = (superClass == null) ? JNullLiteral.INSTANCE :
           getRuntimeTypeReference(superClass);
@@ -2008,8 +2007,8 @@
 
       List<JsExpression> defineClassArguments = Lists.newArrayList();
 
-      defineClassArguments.add(convertJavaLiteral(typeId));
-      defineClassArguments.add(jsPrototype == null ? convertJavaLiteral(superTypeId) :
+      defineClassArguments.add(transform(getRuntimeTypeReference(x)));
+      defineClassArguments.add(jsPrototype == null ? transform(superTypeId) :
           createJsQualifier(jsPrototype, x.getSourceInfo()));
       defineClassArguments.add(generateCastableTypeMap(x));
       defineClassArguments.addAll(constructorArgs);
@@ -2361,13 +2360,9 @@
      * Returns either _ or ClassCtor.prototype depending on output mode.
      */
     private JsNameRef getPrototypeQualifierOf(JDeclaredType type, SourceInfo info) {
-      if (closureCompilerFormatEnabled) {
-        JsNameRef protoRef = prototype.makeRef(info);
-        protoRef.setQualifier(names.get(type).makeRef(info));
-        return protoRef;
-      } else {
-        return globalTemp.makeRef(info);
-      }
+      return closureCompilerFormatEnabled
+          ? prototype.makeQualifiedRef(info, names.get(type).makeRef(info))
+          : globalTemp.makeRef(info);
     }
 
     private void collectExports(JDeclaredType type) {
@@ -2503,14 +2498,6 @@
      * If a field is a literal, we can potentially treat it as immutable and assign it once on the
      * prototype, to be reused by all instances of the class, instead of re-assigning the same
      * literal in each constructor.
-     *
-     * Technically, to match JVM semantics, we should only do this for final or static fields. For
-     * non-final/non-static fields, a super class's cstr, when it calls a polymorphic method that is
-     * overridden in the subclass, should actually see default values (not the literal initializer)
-     * before the subclass's cstr runs.
-     *
-     * However, cstr's calling polymorphic methods is admittedly an uncommon case, so we apply some
-     * heuristics to see if we can initialize the field on the prototype anyway.
      */
     private boolean initializeAtTopScope(JField x) {
       if (x.getLiteralInitializer() == null) {
@@ -2936,14 +2923,7 @@
    * Retrieves the runtime typeId for {@code type}.
    */
   JExpression getRuntimeTypeReference(JReferenceType type) {
-    Object typeId = typeMapper.get(type);
-    if (typeId == null) {
-      return null;
-    }
-    if (typeId instanceof JMethodCall) {
-      return (JMethodCall) typeId;
-    }
-    return program.getLiteral(typeId);
+    return typeMapper.get(type);
   }
 
   private String mangleName(JField x) {
diff --git a/dev/core/src/com/google/gwt/dev/jjs/impl/ResolveRuntimeTypeReferences.java b/dev/core/src/com/google/gwt/dev/jjs/impl/ResolveRuntimeTypeReferences.java
index 1d89caf..8fa4da3 100644
--- a/dev/core/src/com/google/gwt/dev/jjs/impl/ResolveRuntimeTypeReferences.java
+++ b/dev/core/src/com/google/gwt/dev/jjs/impl/ResolveRuntimeTypeReferences.java
@@ -19,12 +19,14 @@
 import com.google.gwt.dev.jjs.ast.HasName;
 import com.google.gwt.dev.jjs.ast.JCastMap;
 import com.google.gwt.dev.jjs.ast.JExpression;
+import com.google.gwt.dev.jjs.ast.JIntLiteral;
 import com.google.gwt.dev.jjs.ast.JMethod;
 import com.google.gwt.dev.jjs.ast.JMethodCall;
 import com.google.gwt.dev.jjs.ast.JModVisitor;
 import com.google.gwt.dev.jjs.ast.JProgram;
 import com.google.gwt.dev.jjs.ast.JReferenceType;
 import com.google.gwt.dev.jjs.ast.JRuntimeTypeReference;
+import com.google.gwt.dev.jjs.ast.JStringLiteral;
 import com.google.gwt.dev.jjs.ast.JType;
 import com.google.gwt.dev.jjs.ast.JVisitor;
 import com.google.gwt.thirdparty.guava.common.annotations.VisibleForTesting;
@@ -56,7 +58,7 @@
   /**
    * Maps a type into a type id literal.
    */
-  public interface TypeMapper<T> {
+  public interface TypeMapper<T extends JExpression> {
     T getOrCreateTypeId(JType type);
 
     void copyFrom(TypeMapper<T> typeMapper);
@@ -67,14 +69,14 @@
   /**
    * Sequentially creates int type ids for types.
    */
-  public static class IntTypeMapper implements Serializable, TypeMapper<Integer> {
+  public static class IntTypeMapper implements Serializable, TypeMapper<JIntLiteral> {
 
     // NOTE: DO NOT STORE ANY AST REFERENCE. Objects of this type persist across compiles.
     private final Map<String, Integer> typeIdByTypeName = Maps.newHashMap();
     private int nextAvailableId =  0;
 
     @Override
-    public void copyFrom(TypeMapper<Integer> that) {
+    public void copyFrom(TypeMapper<JIntLiteral> that) {
       if (!(that instanceof  IntTypeMapper)) {
         throw new IllegalArgumentException("Can only copy from IntTypeMapper");
       }
@@ -92,43 +94,49 @@
     }
 
     @Override
-    public Integer get(JType type) {
-      return typeIdByTypeName.get(type.getName());
+    public JIntLiteral get(JType type) {
+      Integer typeId = typeIdByTypeName.get(type.getName());
+      return typeId == null ? null : new JIntLiteral(type.getSourceInfo(), typeId);
     }
 
     @Override
-    public Integer getOrCreateTypeId(JType type) {
+    public JIntLiteral getOrCreateTypeId(JType type) {
       String typeName = type.getName();
-      if (typeIdByTypeName.containsKey(typeName)) {
-        return typeIdByTypeName.get(typeName);
+      if (!typeIdByTypeName.containsKey(typeName)) {
+        int nextId = nextAvailableId++;
+        typeIdByTypeName.put(typeName, nextId);
       }
 
-      int nextId = nextAvailableId++;
-      typeIdByTypeName.put(typeName, nextId);
-      return nextId;
+      return get(type);
     }
   }
 
   /**
    * Predictably creates String type id literals for castable and instantiable types.
    */
-  public static class StringTypeMapper implements TypeMapper<String> {
+  public static class StringTypeMapper implements TypeMapper<JStringLiteral> {
+
+    private JProgram program;
+
+    public StringTypeMapper(JProgram program) {
+      this.program = program;
+    }
 
     @Override
-    public void copyFrom(TypeMapper<String> that) {
+    public void copyFrom(TypeMapper<JStringLiteral> that) {
       if (!(that instanceof  StringTypeMapper)) {
         throw new IllegalArgumentException("Can only copy from StringTypeMapper");
       }
     }
 
     @Override
-    public String getOrCreateTypeId(JType type) {
+    public JStringLiteral getOrCreateTypeId(JType type) {
       return get(type);
     }
 
     @Override
-    public String get(JType type) {
-      return type.getName();
+    public JStringLiteral get(JType type) {
+      return program.getStringLiteral(type.getSourceInfo(), type.getName());
     }
   }
 
@@ -202,7 +210,7 @@
   private class ReplaceRuntimeTypeReferencesVisitor extends JModVisitor {
     @Override
     public void endVisit(JRuntimeTypeReference x, Context ctx) {
-      ctx.replaceMe(getTypeIdLiteral(x.getReferredType()));
+      ctx.replaceMe(getTypeIdExpression(x.getReferredType()));
     }
   }
 
@@ -272,9 +280,8 @@
     }
   }
 
-  private JExpression getTypeIdLiteral(JType type) {
-    Object typeId = typeMapper.getOrCreateTypeId(type);
-    return typeId instanceof JMethodCall ? (JExpression) typeId : program.getLiteral(typeId);
+  private JExpression getTypeIdExpression(JType type) {
+    return  typeMapper.getOrCreateTypeId(type);
   }
 
   public static void exec(JProgram program, TypeMapper<?> typeMapper, TypeOrder typeOrder) {
diff --git a/dev/core/test/com/google/gwt/dev/jjs/impl/FullCompileTestBase.java b/dev/core/test/com/google/gwt/dev/jjs/impl/FullCompileTestBase.java
index 7d72375..e52b521 100644
--- a/dev/core/test/com/google/gwt/dev/jjs/impl/FullCompileTestBase.java
+++ b/dev/core/test/com/google/gwt/dev/jjs/impl/FullCompileTestBase.java
@@ -31,7 +31,6 @@
 import com.google.gwt.dev.jjs.JavaAstConstructor;
 import com.google.gwt.dev.jjs.ast.JProgram;
 import com.google.gwt.dev.jjs.impl.ResolveRuntimeTypeReferences.IntTypeMapper;
-import com.google.gwt.dev.jjs.impl.ResolveRuntimeTypeReferences.TypeMapper;
 import com.google.gwt.dev.jjs.impl.ResolveRuntimeTypeReferences.TypeOrder;
 import com.google.gwt.dev.js.ast.JsName;
 import com.google.gwt.dev.js.ast.JsNode;
@@ -101,7 +100,7 @@
     MethodCallTightener.exec(jProgram);
     NameClashesFixer.exec(jProgram);
 
-    TypeMapper<Integer> typeMapper = new IntTypeMapper();
+    IntTypeMapper typeMapper = new IntTypeMapper();
     ResolveRuntimeTypeReferences.exec(jProgram, typeMapper, TypeOrder.FREQUENCY);
 
     Map<StandardSymbolData, JsName> symbolTable =
diff --git a/dev/core/test/com/google/gwt/dev/js/JsStackEmulatorTest.java b/dev/core/test/com/google/gwt/dev/js/JsStackEmulatorTest.java
index 2bba3e7..5ee2152 100644
--- a/dev/core/test/com/google/gwt/dev/js/JsStackEmulatorTest.java
+++ b/dev/core/test/com/google/gwt/dev/js/JsStackEmulatorTest.java
@@ -46,7 +46,6 @@
 import com.google.gwt.dev.jjs.impl.MethodInliner;
 import com.google.gwt.dev.jjs.impl.ResolveRuntimeTypeReferences;
 import com.google.gwt.dev.jjs.impl.ResolveRuntimeTypeReferences.StringTypeMapper;
-import com.google.gwt.dev.jjs.impl.ResolveRuntimeTypeReferences.TypeMapper;
 import com.google.gwt.dev.jjs.impl.ResolveRuntimeTypeReferences.TypeOrder;
 import com.google.gwt.dev.js.ast.JsFunction;
 import com.google.gwt.dev.js.ast.JsName;
@@ -283,7 +282,7 @@
     ImplementCastsAndTypeChecks.exec(jProgram, false);
     ArrayNormalizer.exec(jProgram);
 
-    TypeMapper<String> typeMapper = new StringTypeMapper();
+    StringTypeMapper typeMapper = new StringTypeMapper(jProgram);
     ResolveRuntimeTypeReferences.exec(jProgram, typeMapper, TypeOrder.FREQUENCY);
     Map<StandardSymbolData, JsName> symbolTable =
         new TreeMap<StandardSymbolData, JsName>(new SymbolData.ClassIdentComparator());