Decentralize JClassLiterals.

This change allows JClassLiterals to be created apart from a JProgram.  A new normalization pass runs before optimizations and creates all the ClassLiteralHolder implementation fields.

http://gwt-code-reviews.appspot.com/1375801/


git-svn-id: https://google-web-toolkit.googlecode.com/svn/trunk@9808 8db76d5a-ed1c-0410-87a9-c151d255dfc7
diff --git a/dev/core/src/com/google/gwt/dev/jjs/ArtificialRescueRecorder.java b/dev/core/src/com/google/gwt/dev/jjs/ArtificialRescueRecorder.java
index fa14b5e..f256ff9 100644
--- a/dev/core/src/com/google/gwt/dev/jjs/ArtificialRescueRecorder.java
+++ b/dev/core/src/com/google/gwt/dev/jjs/ArtificialRescueRecorder.java
@@ -18,7 +18,6 @@
 import com.google.gwt.core.client.impl.ArtificialRescue;
 import com.google.gwt.core.client.impl.ArtificialRescue.Rescue;
 import com.google.gwt.dev.jjs.ast.Context;
-import com.google.gwt.dev.jjs.ast.HasEnclosingType;
 import com.google.gwt.dev.jjs.ast.JAnnotation;
 import com.google.gwt.dev.jjs.ast.JDeclaredType;
 import com.google.gwt.dev.jjs.ast.JField;
@@ -26,6 +25,7 @@
 import com.google.gwt.dev.jjs.ast.JNode;
 import com.google.gwt.dev.jjs.ast.JProgram;
 import com.google.gwt.dev.jjs.ast.JReferenceType;
+import com.google.gwt.dev.jjs.ast.JType;
 import com.google.gwt.dev.jjs.ast.JVisitor;
 import com.google.gwt.dev.jjs.impl.JsniRefLookup;
 import com.google.gwt.dev.util.JsniRef;
@@ -97,7 +97,7 @@
         for (String name : toRescue) {
           JsniRef ref = JsniRef.parse("@" + classType.getName() + "::" + name);
           final String[] errors = {null};
-          HasEnclosingType node = JsniRefLookup.findJsniRefTarget(ref, program,
+          JNode node = JsniRefLookup.findJsniRefTarget(ref, program,
               new JsniRefLookup.ErrorReporter() {
                 public void reportError(String error) {
                   errors[0] = error;
@@ -109,7 +109,11 @@
                 "Unable to artificially rescue " + name + ": " + errors[0]);
           }
 
-          currentClass.addArtificialRescue((JNode) node);
+          if (node instanceof JType) {
+            // Already added the type above.
+          } else {
+            currentClass.addArtificialRescue(node);
+          }
           if (node instanceof JField) {
             JField field = (JField) node;
             if (!field.isFinal()) {
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 1b58ac7..19bbba7 100644
--- a/dev/core/src/com/google/gwt/dev/jjs/JavaToJavaScriptCompiler.java
+++ b/dev/core/src/com/google/gwt/dev/jjs/JavaToJavaScriptCompiler.java
@@ -81,6 +81,7 @@
 import com.google.gwt.dev.jjs.impl.GenerateJavaAST;
 import com.google.gwt.dev.jjs.impl.GenerateJavaScriptAST;
 import com.google.gwt.dev.jjs.impl.HandleCrossFragmentReferences;
+import com.google.gwt.dev.jjs.impl.ImplementClassLiteralsAsFields;
 import com.google.gwt.dev.jjs.impl.JavaScriptObjectNormalizer;
 import com.google.gwt.dev.jjs.impl.JavaToJavaScriptMap;
 import com.google.gwt.dev.jjs.impl.JsFunctionClusterer;
@@ -622,6 +623,8 @@
       // Replace references to JSO subtypes with JSO itself.
       JavaScriptObjectNormalizer.exec(jprogram);
 
+      ImplementClassLiteralsAsFields.exec(jprogram);
+      
       /*
        * 4) Possibly optimize some.
        * 
@@ -675,12 +678,6 @@
    */
   protected static void draftOptimize(JProgram jprogram) {
     Event draftOptimizeEvent = SpeedTracerLogger.start(CompilerEventType.DRAFT_OPTIMIZE);
-    /*
-     * Record the beginning of optimizations; this turns on certain checks that
-     * guard against problematic late construction of things like class
-     * literals.
-     */
-    jprogram.beginOptimizations();
     Finalizer.exec(jprogram);
     MakeCallsStatic.exec(jprogram);
     jprogram.typeOracle.recomputeAfterOptimizations();
@@ -692,13 +689,6 @@
       throws InterruptedException {
     Event optimizeEvent = SpeedTracerLogger.start(CompilerEventType.OPTIMIZE);
 
-    /*
-     * Record the beginning of optimizations; this turns on certain checks that
-     * guard against problematic late construction of things like class
-     * literals.
-     */
-    jprogram.beginOptimizations();
-
     List<OptimizerStats> allOptimizerStats = new ArrayList<OptimizerStats>();
     int counter = 0;
     int optimizationLevel = options.getOptimizationLevel();
diff --git a/dev/core/src/com/google/gwt/dev/jjs/ast/JClassLiteral.java b/dev/core/src/com/google/gwt/dev/jjs/ast/JClassLiteral.java
index 5184def..2e33f6d 100644
--- a/dev/core/src/com/google/gwt/dev/jjs/ast/JClassLiteral.java
+++ b/dev/core/src/com/google/gwt/dev/jjs/ast/JClassLiteral.java
@@ -15,9 +15,8 @@
  */
 package com.google.gwt.dev.jjs.ast;
 
-import com.google.gwt.dev.jjs.InternalCompilerException;
+import com.google.gwt.dev.jjs.Correlation.Literal;
 import com.google.gwt.dev.jjs.SourceInfo;
-import com.google.gwt.dev.jjs.ast.js.JsniMethodRef;
 
 /**
  * Java class literal expression.
@@ -27,152 +26,19 @@
  * initializer.
  */
 public class JClassLiteral extends JLiteral implements JAnnotationArgument {
-  /**
-   * Create an expression that will evaluate, at run time, to the class literal.
-   * Cannot be called after optimizations begin.
-   */
-  static JMethodCall computeClassObjectAllocation(JProgram program,
-      SourceInfo info, JType type) {
-    String typeName = getTypeName(program, type);
 
-    JMethod method = program.getIndexedMethod(type.getClassLiteralFactoryMethod());
-
-    /*
-     * Use the classForEnum() constructor even for enum subtypes to aid in
-     * pruning supertype data.
-     */
-    boolean isEnumOrSubclass = false;
-    if (type instanceof JClassType) {
-      JEnumType maybeEnum = ((JClassType) type).isEnumOrSubclass();
-      if (maybeEnum != null) {
-        isEnumOrSubclass = true;
-        method = program.getIndexedMethod(maybeEnum.getClassLiteralFactoryMethod());
-      }
-    }
-
-    assert method != null;
-
-    JMethodCall call = new JMethodCall(info, null, method);
-    JStringLiteral packageName = program.getLiteralString(info,
-        getPackageName(typeName));
-    JStringLiteral className = program.getLiteralString(info,
-        getClassName(typeName));
-    call.addArgs(packageName, className);
-
-    if (type instanceof JArrayType) {
-      // There's only one seed function for all arrays
-      JDeclaredType arrayType = program.getIndexedType("Array");
-      call.addArg(new JNameOf(info, className.getType(), arrayType));
-
-    } else if (type instanceof JClassType) {
-      // Add the name of the seed function for concrete types
-      call.addArg(new JNameOf(info, className.getType(), type));
-
-    } else if (type instanceof JPrimitiveType) {
-      // And give primitive types an illegal, though meaningful, value
-      call.addArg(program.getLiteralString(info, " "
-          + type.getJavahSignatureName()));
-    }
-
-    if (type instanceof JClassType) {
-      /*
-       * For non-array classes and enums, determine the class literal of the
-       * supertype, if there is one. Arrays are excluded because they always
-       * have Object as their superclass.
-       */
-      JClassType classType = (JClassType) type;
-
-      JLiteral superclassLiteral;
-      if (classType.getSuperClass() != null) {
-        superclassLiteral = program.getLiteralClass(classType.getSuperClass());
-      } else {
-        superclassLiteral = program.getLiteralNull();
-      }
-
-      call.addArg(superclassLiteral);
-
-      if (classType instanceof JEnumType) {
-        JEnumType enumType = (JEnumType) classType;
-        JMethod valuesMethod = null;
-        JMethod valueOfMethod = null;
-        for (JMethod methodIt : enumType.getMethods()) {
-          if ("values".equals(methodIt.getName())) {
-            if (methodIt.getParams().size() != 0) {
-              continue;
-            }
-            valuesMethod = methodIt;
-          } else if ("valueOf".equals(methodIt.getName())) {
-            if (methodIt.getParams().size() != 1 ||
-                methodIt.getParams().get(0).getType() != program.getTypeJavaLangString()) {
-              continue;
-            }
-            valueOfMethod = methodIt;
-          }
-        }
-        if (valuesMethod == null) {
-          throw new InternalCompilerException(
-              "Could not find enum values() method");
-        }
-        if (valueOfMethod == null) {
-          throw new InternalCompilerException(
-              "Could not find enum valueOf() method");
-        }
-        call.addArg(new JsniMethodRef(info, null, valuesMethod,
-            program.getJavaScriptObject()));
-        call.addArg(new JsniMethodRef(info, null, valueOfMethod,
-            program.getJavaScriptObject()));
-      } else if (isEnumOrSubclass) {
-        // A subclass of an enum class
-        call.addArg(program.getLiteralNull());
-        call.addArg(program.getLiteralNull());
-      }
-    } else if (type instanceof JArrayType) {
-      JArrayType arrayType = (JArrayType) type;
-      JClassLiteral componentLiteral = program.getLiteralClass(arrayType.getElementType());
-      call.addArg(componentLiteral);
-    } else {
-      assert (type instanceof JInterfaceType || type instanceof JPrimitiveType);
-    }
-    assert call.getArgs().size() == method.getParams().size() : "Argument / param mismatch "
-        + call.toString() + " versus " + method.toString();
-    return call;
+  private static SourceInfo addCorrelation(SourceInfo info) {
+    info.addCorrelation(info.getCorrelator().by(Literal.CLASS));
+    return info;
   }
 
-  private static String getClassName(String fullName) {
-    int pos = fullName.lastIndexOf(".");
-    return fullName.substring(pos + 1);
-  }
+  private JField field;
 
-  private static String getPackageName(String fullName) {
-    int pos = fullName.lastIndexOf(".");
-    return fullName.substring(0, pos + 1);
-  }
-
-  private static String getTypeName(JProgram program, JType type) {
-    String typeName;
-    if (type instanceof JArrayType) {
-      typeName = type.getJsniSignatureName().replace('/', '.');
-      // Mangle the class name to match hosted mode.
-      if (program.isJavaScriptObject(((JArrayType) type).getLeafType())) {
-        typeName = typeName.replace(";", "$;");
-      }
-    } else {
-      typeName = type.getName();
-      // Mangle the class name to match hosted mode.
-      if (program.isJavaScriptObject(type)) {
-        typeName += '$';
-      }
-    }
-    return typeName;
-  }
-
-  private final JField field;
   private final JType refType;
 
-  public JClassLiteral(SourceInfo sourceInfo, JType type, JField field) {
-    super(sourceInfo);
+  public JClassLiteral(SourceInfo sourceInfo, JType type) {
+    super(addCorrelation(sourceInfo));
     refType = type;
-    this.field = field;
   }
 
   public JNode annotationNode() {
@@ -194,6 +60,14 @@
     return field.getType();
   }
 
+  /**
+   * @param field the field to set
+   */
+  public void setField(JField field) {
+    assert field != null;
+    this.field = field;
+  }
+
   public void traverse(JVisitor visitor, Context ctx) {
     if (visitor.visit(this, ctx)) {
     }
diff --git a/dev/core/src/com/google/gwt/dev/jjs/ast/JNewArray.java b/dev/core/src/com/google/gwt/dev/jjs/ast/JNewArray.java
index 3a206fb..1ce797a 100644
--- a/dev/core/src/com/google/gwt/dev/jjs/ast/JNewArray.java
+++ b/dev/core/src/com/google/gwt/dev/jjs/ast/JNewArray.java
@@ -25,8 +25,8 @@
  */
 public class JNewArray extends JExpression {
 
-  public static JNewArray createDims(JProgram program, SourceInfo info,
-      JArrayType arrayType, List<JExpression> dims) {
+  public static JNewArray createDims(SourceInfo info, JArrayType arrayType,
+      List<JExpression> dims) {
     List<JClassLiteral> classLiterals = new ArrayList<JClassLiteral>();
 
     // Produce all class literals that will eventually get generated.
@@ -41,7 +41,7 @@
     JType cur = arrayType;
     for (int i = 0; i < realDims; ++i) {
       // Walk down each type from most dims to least.
-      JClassLiteral classLit = program.getLiteralClass(cur);
+      JClassLiteral classLit = new JClassLiteral(info.makeChild(), cur);
       classLiterals.add(classLit);
       cur = ((JArrayType) cur).getElementType();
     }
@@ -49,10 +49,10 @@
         classLiterals);
   }
 
-  public static JNewArray createInitializers(JProgram program, SourceInfo info,
+  public static JNewArray createInitializers(SourceInfo info,
       JArrayType arrayType, List<JExpression> initializers) {
     List<JClassLiteral> classLiterals = new ArrayList<JClassLiteral>();
-    classLiterals.add(program.getLiteralClass(arrayType));
+    classLiterals.add(new JClassLiteral(info.makeChild(), arrayType));
     return new JNewArray(info, arrayType.getNonNull(), null, initializers,
         classLiterals);
   }
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 aa3977f..af5e68e 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
@@ -311,7 +311,7 @@
    */
   public final List<List<JMethod>> entryMethods = new ArrayList<List<JMethod>>();
 
-  public final Map<String, HasEnclosingType> jsniMap = new HashMap<String, HasEnclosingType>();
+  public final Map<String, JNode> jsniMap = new HashMap<String, JNode>();
 
   public final JTypeOracle typeOracle = new JTypeOracle(this);
 
@@ -322,8 +322,6 @@
 
   private final HashMap<JType, JArrayType> arrayTypes = new HashMap<JType, JArrayType>();
 
-  private final Map<JType, JClassLiteral> classLiterals = new IdentityHashMap<JType, JClassLiteral>();
-
   /**
    * A factory to create correlations.
    */
@@ -343,11 +341,6 @@
 
   private JMethod nullMethod;
 
-  /**
-   * Turned on once optimizations begin.
-   */
-  private boolean optimizationsStarted = false;
-
   private Map<JReferenceType, Integer> queryIds;
 
   /**
@@ -411,15 +404,6 @@
     }
   }
 
-  /**
-   * Record the start of optimizations, which disables certain problematic
-   * constructions. In particular, new class literals cannot be created once
-   * optimization starts.
-   */
-  public void beginOptimizations() {
-    optimizationsStarted = true;
-  }
-
   public JClassType createClass(SourceInfo info, String name,
       boolean isAbstract, boolean isFinal) {
     JClassType x = new JClassType(info, name, isAbstract, isFinal);
@@ -860,61 +844,6 @@
     return JCharLiteral.get(value);
   }
 
-  /**
-   * May not be called once optimizations begin; all possible class literals
-   * must be created up front.
-   */
-  public JClassLiteral getLiteralClass(JType type) {
-    JClassLiteral classLiteral = classLiterals.get(type);
-    if (classLiteral == null) {
-      if (optimizationsStarted) {
-        throw new InternalCompilerException(
-            "New class literals cannot be created once optimizations have started; type '"
-                + type + "'");
-      }
-
-      SourceInfo info = typeSpecialClassLiteralHolder.getSourceInfo();
-
-      // Create the allocation expression FIRST since this may be recursive on
-      // super type (this forces the super type classLit to be created first).
-      boolean isObjectExternal = getTypeJavaLangObject().isExternal();
-      JExpression alloc = isObjectExternal ? null :
-          JClassLiteral.computeClassObjectAllocation(this,info, type);
-
-      // Create a field in the class literal holder to hold the object.
-      JField field = new JField(info, getClassLiteralName(type),
-          typeSpecialClassLiteralHolder, getTypeJavaLangClass(),
-          true, Disposition.FINAL);
-      typeSpecialClassLiteralHolder.addField(field);
-
-      // Initialize the field.
-      if (alloc != null) {
-        JFieldRef fieldRef = new JFieldRef(info, null, field,
-            typeSpecialClassLiteralHolder);
-        JDeclarationStatement decl = new JDeclarationStatement(info, fieldRef,
-            alloc);
-        JMethodBody clinitBody = (JMethodBody)
-            typeSpecialClassLiteralHolder.getMethods().get(0).getBody();
-        clinitBody.getBlock().addStmt(decl);
-      }
-
-      SourceInfo literalInfo = createSourceInfoSynthetic(JProgram.class);
-      literalInfo.addCorrelation(correlator.by(Literal.CLASS));
-      classLiteral = new JClassLiteral(literalInfo, type, field);
-      classLiterals.put(type, classLiteral);
-    } else {
-      // Make sure the field hasn't been pruned.
-      JField field = classLiteral.getField();
-      if (optimizationsStarted
-          && !field.getEnclosingType().getFields().contains(field)) {
-        throw new InternalCompilerException(
-            "Getting a class literal whose field holder has already been pruned; type '"
-                + type + " '");
-      }
-    }
-    return classLiteral;
-  }
-
   public JDoubleLiteral getLiteralDouble(double d) {
     return JDoubleLiteral.get(d);
   }
diff --git a/dev/core/src/com/google/gwt/dev/jjs/ast/js/JsniMethodBody.java b/dev/core/src/com/google/gwt/dev/jjs/ast/js/JsniMethodBody.java
index c5d5f09..a64b394 100644
--- a/dev/core/src/com/google/gwt/dev/jjs/ast/js/JsniMethodBody.java
+++ b/dev/core/src/com/google/gwt/dev/jjs/ast/js/JsniMethodBody.java
@@ -18,6 +18,7 @@
 import com.google.gwt.dev.jjs.SourceInfo;
 import com.google.gwt.dev.jjs.ast.Context;
 import com.google.gwt.dev.jjs.ast.JAbstractMethodBody;
+import com.google.gwt.dev.jjs.ast.JClassLiteral;
 import com.google.gwt.dev.jjs.ast.JVisitor;
 import com.google.gwt.dev.js.ast.JsContext;
 import com.google.gwt.dev.js.ast.JsFunction;
@@ -36,6 +37,7 @@
  */
 public class JsniMethodBody extends JAbstractMethodBody {
 
+  private List<JClassLiteral> classRefs = Collections.emptyList();
   private JsFunction jsFunction = null;
   private List<JsniFieldRef> jsniFieldRefs = Collections.emptyList();
   private List<JsniMethodRef> jsniMethodRefs = Collections.emptyList();
@@ -47,6 +49,13 @@
   }
 
   /**
+   * Adds a reference from this method to a Java class literal.
+   */
+  public void addClassRef(JClassLiteral ref) {
+    classRefs = Lists.add(classRefs, ref);
+  }
+
+  /**
    * Adds a reference from this method to a Java field.
    */
   public void addJsniRef(JsniFieldRef ref) {
@@ -60,6 +69,13 @@
     jsniMethodRefs = Lists.add(jsniMethodRefs, ref);
   }
 
+  /**
+   * Return this method's references to Java class literals.
+   */
+  public List<JClassLiteral> getClassRefs() {
+    return classRefs;
+  }
+
   public JsFunction getFunc() {
     assert (this.jsFunction != null);
     return jsFunction;
@@ -104,6 +120,7 @@
 
   public void traverse(JVisitor visitor, Context ctx) {
     if (visitor.visit(this, ctx)) {
+      classRefs = visitor.acceptImmutable(classRefs);
       jsniFieldRefs = visitor.acceptImmutable(jsniFieldRefs);
       jsniMethodRefs = visitor.acceptImmutable(jsniMethodRefs);
     }
diff --git a/dev/core/src/com/google/gwt/dev/jjs/impl/CodeSplitter.java b/dev/core/src/com/google/gwt/dev/jjs/impl/CodeSplitter.java
index de107d4..54871d6 100644
--- a/dev/core/src/com/google/gwt/dev/jjs/impl/CodeSplitter.java
+++ b/dev/core/src/com/google/gwt/dev/jjs/impl/CodeSplitter.java
@@ -21,14 +21,12 @@
 import com.google.gwt.dev.cfg.Properties;
 import com.google.gwt.dev.cfg.Property;
 import com.google.gwt.dev.jjs.InternalCompilerException;
-import com.google.gwt.dev.jjs.SourceInfo;
 import com.google.gwt.dev.jjs.ast.Context;
-import com.google.gwt.dev.jjs.ast.HasEnclosingType;
-import com.google.gwt.dev.jjs.ast.JArrayType;
 import com.google.gwt.dev.jjs.ast.JClassLiteral;
 import com.google.gwt.dev.jjs.ast.JDeclaredType;
 import com.google.gwt.dev.jjs.ast.JExpression;
 import com.google.gwt.dev.jjs.ast.JField;
+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.JNewArray;
@@ -282,8 +280,8 @@
         throw new UnableToCompleteException();
       }
       final String lookupErrorHolder[] = new String[1];
-      HasEnclosingType referent = JsniRefLookup.findJsniRefTarget(jsniRef,
-          program, new JsniRefLookup.ErrorReporter() {
+      JNode referent = JsniRefLookup.findJsniRefTarget(jsniRef, program,
+          new JsniRefLookup.ErrorReporter() {
             public void reportError(String error) {
               lookupErrorHolder[0] = error;
             }
@@ -512,21 +510,15 @@
    */
   private static void installInitialLoadSequenceField(JProgram program,
       LinkedHashSet<Integer> initialLoadSequence) {
+     // Arg 1 is initialized in the source as  "new int[]{}".
     JMethodCall constructorCall = ReplaceRunAsyncs.getBrowserLoaderConstructor(program);
-    assert ((JReferenceType) constructorCall.getArgs().get(1).getType()).getUnderlyingType() instanceof JArrayType;
-    assert ((JArrayType) ((JReferenceType) constructorCall.getArgs().get(1).getType()).getUnderlyingType()).getElementType() == JPrimitiveType.INT;
+    JNewArray newArray = (JNewArray) constructorCall.getArgs().get(1);
+    assert newArray.getArrayType().getElementType() == JPrimitiveType.INT;
+    assert newArray.initializers.size() == 0;
 
-    SourceInfo info = program.createSourceInfoSynthetic(ReplaceRunAsyncs.class);
-    List<JExpression> intExprs = new ArrayList<JExpression>();
     for (int sp : initialLoadSequence) {
-      intExprs.add(program.getLiteralInt(sp));
+      newArray.initializers.add(JIntLiteral.get(sp));
     }
-    /*
-     * Note: the following field is known to have a manually installed
-     * initializer, of new int[0].
-     */
-    constructorCall.setArg(1, JNewArray.createInitializers(program, info,
-        program.getTypeArray(JPrimitiveType.INT), intExprs));
   }
 
   private static <T> T last(T[] array) {
diff --git a/dev/core/src/com/google/gwt/dev/jjs/impl/ControlFlowAnalyzer.java b/dev/core/src/com/google/gwt/dev/jjs/impl/ControlFlowAnalyzer.java
index 42e284c..1ebe42e 100644
--- a/dev/core/src/com/google/gwt/dev/jjs/impl/ControlFlowAnalyzer.java
+++ b/dev/core/src/com/google/gwt/dev/jjs/impl/ControlFlowAnalyzer.java
@@ -192,6 +192,7 @@
     @Override
     public boolean visit(JClassLiteral x, Context ctx) {
       JField field = x.getField();
+      assert field != null;
       rescue(field);
       return true;
     }
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 f727a48..b0f4fbb 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
@@ -23,7 +23,6 @@
 import com.google.gwt.dev.jjs.SourceOrigin;
 import com.google.gwt.dev.jjs.ast.Context;
 import com.google.gwt.dev.jjs.ast.HasAnnotations;
-import com.google.gwt.dev.jjs.ast.HasEnclosingType;
 import com.google.gwt.dev.jjs.ast.JAnnotation;
 import com.google.gwt.dev.jjs.ast.JAnnotation.Property;
 import com.google.gwt.dev.jjs.ast.JAnnotationArgument;
@@ -39,6 +38,7 @@
 import com.google.gwt.dev.jjs.ast.JCaseStatement;
 import com.google.gwt.dev.jjs.ast.JCastOperation;
 import com.google.gwt.dev.jjs.ast.JCharLiteral;
+import com.google.gwt.dev.jjs.ast.JClassLiteral;
 import com.google.gwt.dev.jjs.ast.JClassType;
 import com.google.gwt.dev.jjs.ast.JConditional;
 import com.google.gwt.dev.jjs.ast.JConstructor;
@@ -524,17 +524,18 @@
             currentClass.getMethods().remove(2);
           } else {
             tryFindUpRefs(method);
+            SourceInfo info = method.getSourceInfo();
             if (isScript(program)
                 && currentClass == program.getIndexedType("Array")) {
               // Special implementation: return this.arrayClass
-              SourceInfo info = method.getSourceInfo();
               implementMethod(
                   method,
                   new JFieldRef(info, new JThisRef(info,
                       (JClassType) currentClass),
                       program.getIndexedField("Array.arrayClass"), currentClass));
             } else {
-              implementMethod(method, program.getLiteralClass(currentClass));
+              implementMethod(method, new JClassLiteral(info.makeChild(),
+                  currentClass));
             }
           }
         }
@@ -919,7 +920,7 @@
             initializers.add(dispProcessExpression(expression));
           }
         }
-        return JNewArray.createInitializers(program, info, type, initializers);
+        return JNewArray.createInitializers(info, type, initializers);
       } else {
         List<JExpression> dims = new ArrayList<JExpression>();
         for (Expression dimension : x.dimensions) {
@@ -930,7 +931,7 @@
             dims.add(dispProcessExpression(dimension));
           }
         }
-        return JNewArray.createDims(program, info, type, dims);
+        return JNewArray.createDims(info, type, dims);
       }
     }
 
@@ -944,7 +945,7 @@
           initializers.add(dispProcessExpression(expression));
         }
       }
-      return JNewArray.createInitializers(program, info, type, initializers);
+      return JNewArray.createInitializers(info, type, initializers);
     }
 
     JExpression processExpression(ArrayReference x) {
@@ -1034,8 +1035,9 @@
     }
 
     JExpression processExpression(ClassLiteralAccess x) {
+      SourceInfo info = makeSourceInfo(x);
       JType type = (JType) typeMap.get(x.targetType);
-      return program.getLiteralClass(type);
+      return new JClassLiteral(info, type);
     }
 
     JExpression processExpression(CombinedBinaryExpression x) {
@@ -1699,7 +1701,7 @@
       } else {
         /**
          * <pre>
-         * for (Iterator<T> i$iterator = collection.iterator(); i$iterator.hasNext(); ) {
+         * for (Iterator<T> i$iterator = collection.iterator(); i$iterator.hasNext();) {
          *   T elementVar = i$iterator.next();
          *   // user action
          * }
@@ -2086,8 +2088,8 @@
         initializers.add(args[i]);
       }
       JArrayType lastParamType = (JArrayType) typeMap.get(params[varArg]);
-      JNewArray newArray = JNewArray.createInitializers(program,
-          SourceOrigin.UNKNOWN, lastParamType, initializers);
+      JNewArray newArray = JNewArray.createInitializers(SourceOrigin.UNKNOWN,
+          lastParamType, initializers);
       call.addArg(newArray);
     }
 
@@ -2571,7 +2573,8 @@
           type = getOrCreateExternalType(info,
               ((ReferenceBinding) value).compoundName);
         }
-        return Lists.<JAnnotationArgument> create(program.getLiteralClass(type));
+        return Lists.<JAnnotationArgument> create(new JClassLiteral(
+            info.makeChild(), type));
 
       } else if (value instanceof Constant) {
         return Lists.create((JAnnotationArgument) dispatch("processConstant",
@@ -2910,7 +2913,7 @@
           JFieldRef fieldRef = new JFieldRef(fieldInfo, null, field, type);
           initializers.add(fieldRef);
         }
-        JNewArray newExpr = JNewArray.createInitializers(program, fieldInfo,
+        JNewArray newExpr = JNewArray.createInitializers(fieldInfo,
             enumArrayType, initializers);
         JFieldRef valuesRef = new JFieldRef(fieldInfo, null, valuesField, type);
         JDeclarationStatement declStmt = new JDeclarationStatement(fieldInfo,
@@ -2962,8 +2965,7 @@
         }
       }
 
-      private HasEnclosingType findJsniRefTarget(final SourceInfo info,
-          String ident) {
+      private JNode findJsniRefTarget(final SourceInfo info, String ident) {
         JsniRef parsed = JsniRef.parse(ident);
         if (parsed == null) {
           JsniCollector.reportJsniError(info, methodDecl,
@@ -2981,6 +2983,11 @@
             });
       }
 
+      private void processClassLiteral(JClassLiteral classLiteral, JsContext ctx) {
+        assert !ctx.isLvalue();
+        nativeMethodBody.addClassRef(classLiteral);
+      }
+
       private void processField(JsNameRef nameRef, SourceInfo info,
           JField field, JsContext ctx) {
         /*
@@ -3020,12 +3027,15 @@
         // TODO: make this tighter when we have real source info
         // JSourceInfo info = translateInfo(nameRef.getInfo());
         String ident = nameRef.getIdent();
-        HasEnclosingType node = program.jsniMap.get(ident);
+        JNode node = program.jsniMap.get(ident);
         if (node == null) {
           node = findJsniRefTarget(info, ident);
           if (node == null) {
             return; // already reported error
           }
+          if (node instanceof JType) {
+            node = new JClassLiteral(info.makeChild(), (JType) node);
+          }
           program.jsniMap.put(ident, node);
         }
 
@@ -3033,9 +3043,11 @@
           processField(nameRef, info, (JField) node, ctx);
         } else if (node instanceof JMethod) {
           processMethod(nameRef, info, (JMethod) node, ctx);
+        } else if (node instanceof JClassLiteral) {
+          processClassLiteral((JClassLiteral) node, ctx);
         } else {
-          throw new InternalCompilerException((HasSourceInfo) node,
-              "JSNI reference to something other than a field or method?", null);
+          throw new InternalCompilerException(node,
+              "JSNI reference to something other than a class, field, or method?", null);
         }
       }
     }
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 82531e9..80517a8 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
@@ -1340,7 +1340,7 @@
             JsNameRef ref = (JsNameRef) x.getQualifier();
             String ident = ref.getIdent();
             if (isJsniIdent(ident)) {
-              HasEnclosingType node = program.jsniMap.get(ident);
+              JNode node = program.jsniMap.get(ident);
               assert node instanceof JConstructor;
               assert ref.getQualifier() == null;
               JsName jsName = names.get(node);
@@ -1357,8 +1357,12 @@
         public void endVisit(JsNameRef x, JsContext ctx) {
           String ident = x.getIdent();
           if (isJsniIdent(ident)) {
-            HasEnclosingType node = program.jsniMap.get(ident);
+            JNode node = program.jsniMap.get(ident);
             assert (node != null);
+            if (node instanceof JClassLiteral) {
+              node = ((JClassLiteral) node).getField();
+              assert node != null;
+            }
             if (node instanceof JField) {
               JField field = (JField) node;
               JsName jsName = names.get(field);
diff --git a/dev/core/src/com/google/gwt/dev/jjs/impl/ImplementClassLiteralsAsFields.java b/dev/core/src/com/google/gwt/dev/jjs/impl/ImplementClassLiteralsAsFields.java
new file mode 100644
index 0000000..017e69b
--- /dev/null
+++ b/dev/core/src/com/google/gwt/dev/jjs/impl/ImplementClassLiteralsAsFields.java
@@ -0,0 +1,309 @@
+/*
+ * Copyright 2011 Google Inc.
+ * 
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ * 
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package com.google.gwt.dev.jjs.impl;
+
+import com.google.gwt.dev.jjs.Correlation.Literal;
+import com.google.gwt.dev.jjs.InternalCompilerException;
+import com.google.gwt.dev.jjs.SourceInfo;
+import com.google.gwt.dev.jjs.ast.Context;
+import com.google.gwt.dev.jjs.ast.JArrayType;
+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.JDeclaredType;
+import com.google.gwt.dev.jjs.ast.JEnumType;
+import com.google.gwt.dev.jjs.ast.JField;
+import com.google.gwt.dev.jjs.ast.JFieldRef;
+import com.google.gwt.dev.jjs.ast.JInterfaceType;
+import com.google.gwt.dev.jjs.ast.JLiteral;
+import com.google.gwt.dev.jjs.ast.JMethod;
+import com.google.gwt.dev.jjs.ast.JMethodBody;
+import com.google.gwt.dev.jjs.ast.JMethodCall;
+import com.google.gwt.dev.jjs.ast.JModVisitor;
+import com.google.gwt.dev.jjs.ast.JNameOf;
+import com.google.gwt.dev.jjs.ast.JNullLiteral;
+import com.google.gwt.dev.jjs.ast.JPrimitiveType;
+import com.google.gwt.dev.jjs.ast.JProgram;
+import com.google.gwt.dev.jjs.ast.JStringLiteral;
+import com.google.gwt.dev.jjs.ast.JType;
+import com.google.gwt.dev.jjs.ast.JField.Disposition;
+import com.google.gwt.dev.jjs.ast.js.JsniMethodRef;
+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;
+
+import java.util.IdentityHashMap;
+import java.util.Map;
+
+/**
+ * Create fields to represent the mechanical implementation of class literals.
+ * Must be done after all class literals are created, but before optimizations
+ * begin. {@link ControlFlowAnalyzer} depends on this.
+ * <p>
+ * Class literals are implemented as static field references. The static fields
+ * are all put into the special com.google.gwt.lang.ClassLiteralHolder class.
+ * Ordinarily, accessing one of these fields would trigger a clinit to run, but
+ * we've special-cased class literal fields to evaluate as top-level code before
+ * the application starts running to avoid the clinit.
+ * <p>
+ * TODO(cromwellian): consider lazy-initialization to improve startup time.
+ */
+public class ImplementClassLiteralsAsFields {
+
+  private class NormalizeVisitor extends JModVisitor {
+    @Override
+    public void endVisit(JClassLiteral x, Context ctx) {
+      JField field = resolveClassLiteralField(x);
+      x.setField(field);
+    }
+  }
+
+  public static void exec(JProgram program) {
+    Event normalizerEvent = SpeedTracerLogger.start(CompilerEventType.NORMALIZER);
+    new ImplementClassLiteralsAsFields(program).execImpl();
+    normalizerEvent.end();
+  }
+
+  private static String getClassName(String fullName) {
+    int pos = fullName.lastIndexOf(".");
+    return fullName.substring(pos + 1);
+  }
+
+  private static String getPackageName(String fullName) {
+    int pos = fullName.lastIndexOf(".");
+    return fullName.substring(0, pos + 1);
+  }
+
+  private final Map<JType, JField> classLiteralFields = new IdentityHashMap<JType, JField>();
+  private final JMethodBody classLiteralHolderClinitBody;
+  private final JProgram program;
+  private final JClassType typeClassLiteralHolder;
+
+  private ImplementClassLiteralsAsFields(JProgram program) {
+    this.program = program;
+    this.typeClassLiteralHolder = program.getTypeClassLiteralHolder();
+    this.classLiteralHolderClinitBody =
+        (JMethodBody) typeClassLiteralHolder.getMethods().get(0).getBody();
+  }
+
+  /**
+   * Create an expression that will evaluate, at run time, to the class literal.
+   * Causes recursive literal create (super type, array element type). Examples:
+   * 
+   * Class:
+   * 
+   * <pre>
+   * Class.createForClass("java.lang.", "Object", /JNameOf/"java.lang.Object", null)
+   * Class.createForClass("java.lang.", "Exception", /JNameOf/"java.lang.Exception", Throwable.class)
+   * </pre>
+   * 
+   * Interface:
+   * 
+   * <pre>
+   * Class.createForInterface(&quot;java.lang.&quot;, &quot;Comparable&quot;)
+   * </pre>
+   * 
+   * Primitive:
+   * 
+   * <pre>
+   * Class.createForPrimitive(&quot;&quot;, &quot;int&quot;, &quot; I&quot;)
+   * </pre>
+   * 
+   * Array:
+   * 
+   * <pre>
+   * Class.createForArray("", "[I", /JNameOf/"com.google.gwt.lang.Array", int.class)
+   * Class.createForArray("[Lcom.example.", "Foo;", /JNameOf/"com.google.gwt.lang.Array", Foo.class)
+   * </pre>
+   * 
+   * Enum:
+   * 
+   * <pre>
+   * Class.createForEnum("com.example.", "MyEnum", /JNameOf/"com.example.MyEnum", Enum.class,
+   *     public static MyEnum[] values(), public static MyEnum valueOf(String name))
+   * </pre>
+   * 
+   * Enum subclass:
+   * 
+   * <pre>
+   * Class.createForEnum("com.example.", "MyEnum$1", /JNameOf/"com.example.MyEnum$1", MyEnum.class,
+   *     null, null))
+   * </pre>
+   */
+  private JMethodCall computeClassObjectAllocation(SourceInfo info, JType type) {
+    String typeName = getTypeName(type);
+
+    JMethod method = program.getIndexedMethod(type.getClassLiteralFactoryMethod());
+
+    /*
+     * Use the classForEnum() constructor even for enum subtypes to aid in
+     * pruning supertype data.
+     */
+    boolean isEnumOrSubclass = false;
+    if (type instanceof JClassType) {
+      JEnumType maybeEnum = ((JClassType) type).isEnumOrSubclass();
+      if (maybeEnum != null) {
+        isEnumOrSubclass = true;
+        method = program.getIndexedMethod(maybeEnum.getClassLiteralFactoryMethod());
+      }
+    }
+
+    assert method != null;
+
+    JMethodCall call = new JMethodCall(info, null, method);
+    JStringLiteral packageName = program.getLiteralString(info, getPackageName(typeName));
+    JStringLiteral className = program.getLiteralString(info, getClassName(typeName));
+    call.addArgs(packageName, className);
+
+    if (type instanceof JArrayType) {
+      // There's only one seed function for all arrays
+      JDeclaredType arrayType = program.getIndexedType("Array");
+      call.addArg(new JNameOf(info, className.getType(), arrayType));
+
+    } else if (type instanceof JClassType) {
+      // Add the name of the seed function for concrete types
+      call.addArg(new JNameOf(info, className.getType(), type));
+
+    } else if (type instanceof JPrimitiveType) {
+      // And give primitive types an illegal, though meaningful, value
+      call.addArg(program.getLiteralString(info, " " + type.getJavahSignatureName()));
+    }
+
+    if (type instanceof JClassType) {
+      /*
+       * For non-array classes and enums, determine the class literal of the
+       * supertype, if there is one. Arrays are excluded because they always
+       * have Object as their superclass.
+       */
+      JClassType classType = (JClassType) type;
+
+      JLiteral superclassLiteral;
+      if (classType.getSuperClass() != null) {
+        superclassLiteral = createDependentClassLiteral(info, classType.getSuperClass());
+      } else {
+        superclassLiteral = JNullLiteral.INSTANCE;
+      }
+
+      call.addArg(superclassLiteral);
+
+      if (classType instanceof JEnumType) {
+        JEnumType enumType = (JEnumType) classType;
+        JMethod valuesMethod = null;
+        JMethod valueOfMethod = null;
+        for (JMethod methodIt : enumType.getMethods()) {
+          if ("values".equals(methodIt.getName())) {
+            if (methodIt.getParams().size() != 0) {
+              continue;
+            }
+            valuesMethod = methodIt;
+          } else if ("valueOf".equals(methodIt.getName())) {
+            if (methodIt.getParams().size() != 1
+                || methodIt.getParams().get(0).getType() != program.getTypeJavaLangString()) {
+              continue;
+            }
+            valueOfMethod = methodIt;
+          }
+        }
+        if (valuesMethod == null) {
+          throw new InternalCompilerException("Could not find enum values() method");
+        }
+        if (valueOfMethod == null) {
+          throw new InternalCompilerException("Could not find enum valueOf() method");
+        }
+        call.addArg(new JsniMethodRef(info, null, valuesMethod, program.getJavaScriptObject()));
+        call.addArg(new JsniMethodRef(info, null, valueOfMethod, program.getJavaScriptObject()));
+      } else if (isEnumOrSubclass) {
+        // A subclass of an enum class
+        call.addArg(JNullLiteral.INSTANCE);
+        call.addArg(JNullLiteral.INSTANCE);
+      }
+    } else if (type instanceof JArrayType) {
+      JArrayType arrayType = (JArrayType) type;
+      JClassLiteral componentLiteral =
+          createDependentClassLiteral(info, arrayType.getElementType());
+      call.addArg(componentLiteral);
+    } else {
+      assert (type instanceof JInterfaceType || type instanceof JPrimitiveType);
+    }
+    assert call.getArgs().size() == method.getParams().size() : "Argument / param mismatch "
+        + call.toString() + " versus " + method.toString();
+    return call;
+  }
+
+  private JClassLiteral createDependentClassLiteral(SourceInfo info, JType type) {
+    JClassLiteral classLiteral = new JClassLiteral(info.makeChild(), type);
+    JField field = resolveClassLiteralField(classLiteral);
+    classLiteral.setField(field);
+    return classLiteral;
+  }
+
+  private void execImpl() {
+    NormalizeVisitor visitor = new NormalizeVisitor();
+    visitor.accept(program);
+  }
+
+  private String getTypeName(JType type) {
+    String typeName;
+    if (type instanceof JArrayType) {
+      typeName = type.getJsniSignatureName().replace('/', '.');
+      // Mangle the class name to match hosted mode.
+      if (program.isJavaScriptObject(((JArrayType) type).getLeafType())) {
+        typeName = typeName.replace(";", "$;");
+      }
+    } else {
+      typeName = type.getName();
+      // Mangle the class name to match hosted mode.
+      if (program.isJavaScriptObject(type)) {
+        typeName += '$';
+      }
+    }
+    return typeName;
+  }
+
+  /**
+   * Takes the form:
+   * 
+   * <pre>
+   * class ClassLiteralHolder {
+   *   Class Ljava_lang_Object_2_classLit =
+   *       Class.createForClass("java.lang.", "Object", /JNameOf/"java.lang.Object", null)
+   * }
+   * </pre>
+   */
+  private JField resolveClassLiteralField(JClassLiteral classLiteral) {
+    JType type = classLiteral.getRefType();
+    JField field = classLiteralFields.get(type);
+    if (field == null) {
+      // Create the allocation expression FIRST since this may be recursive on
+      // super type (this forces the super type classLit to be created first).
+      SourceInfo info = typeClassLiteralHolder.getSourceInfo().makeChild();
+      JMethodCall alloc = computeClassObjectAllocation(info, type);
+      // Create a field in the class literal holder to hold the object.
+      field =
+          new JField(info, program.getClassLiteralName(type), typeClassLiteralHolder, program
+              .getTypeJavaLangClass(), true, Disposition.FINAL);
+      typeClassLiteralHolder.addField(field);
+      info.addCorrelation(info.getCorrelator().by(Literal.CLASS));
+
+      // Initialize the field.
+      JFieldRef fieldRef = new JFieldRef(info, null, field, typeClassLiteralHolder);
+      JDeclarationStatement decl = new JDeclarationStatement(info, fieldRef, alloc);
+      classLiteralHolderClinitBody.getBlock().addStmt(decl);
+      classLiteralFields.put(type, field);
+    }
+    return field;
+  }
+}
diff --git a/dev/core/src/com/google/gwt/dev/jjs/impl/JavaScriptObjectNormalizer.java b/dev/core/src/com/google/gwt/dev/jjs/impl/JavaScriptObjectNormalizer.java
index a137b88..743b6b9 100644
--- a/dev/core/src/com/google/gwt/dev/jjs/impl/JavaScriptObjectNormalizer.java
+++ b/dev/core/src/com/google/gwt/dev/jjs/impl/JavaScriptObjectNormalizer.java
@@ -69,7 +69,7 @@
     public void endVisit(JClassLiteral x, Context ctx) {
       JType newType = translate(x.getRefType());
       if (newType != x.getRefType()) {
-        ctx.replaceMe(program.getLiteralClass(newType));
+        ctx.replaceMe(new JClassLiteral(x.getSourceInfo(), newType));
       }
     }
 
diff --git a/dev/core/src/com/google/gwt/dev/jjs/impl/JsniRefLookup.java b/dev/core/src/com/google/gwt/dev/jjs/impl/JsniRefLookup.java
index 7ea3d1d..b43a622 100644
--- a/dev/core/src/com/google/gwt/dev/jjs/impl/JsniRefLookup.java
+++ b/dev/core/src/com/google/gwt/dev/jjs/impl/JsniRefLookup.java
@@ -15,14 +15,13 @@
  */
 package com.google.gwt.dev.jjs.impl;
 
-import com.google.gwt.dev.jjs.ast.HasEnclosingType;
 import com.google.gwt.dev.jjs.ast.JArrayType;
-import com.google.gwt.dev.jjs.ast.JClassLiteral;
 import com.google.gwt.dev.jjs.ast.JClassType;
 import com.google.gwt.dev.jjs.ast.JConstructor;
 import com.google.gwt.dev.jjs.ast.JDeclaredType;
 import com.google.gwt.dev.jjs.ast.JField;
 import com.google.gwt.dev.jjs.ast.JMethod;
+import com.google.gwt.dev.jjs.ast.JNode;
 import com.google.gwt.dev.jjs.ast.JParameter;
 import com.google.gwt.dev.jjs.ast.JPrimitiveType;
 import com.google.gwt.dev.jjs.ast.JProgram;
@@ -56,8 +55,8 @@
    *         found. If the return value is <code>null</code>,
    *         <code>errorReporter</code> will have been invoked.
    */
-  public static HasEnclosingType findJsniRefTarget(JsniRef ref,
-      JProgram program, JsniRefLookup.ErrorReporter errorReporter) {
+  public static JNode findJsniRefTarget(JsniRef ref, JProgram program,
+      JsniRefLookup.ErrorReporter errorReporter) {
     String className = ref.className();
     JType type = null;
     if (!className.equals("null")) {
@@ -78,8 +77,7 @@
         }
 
       } else if (fieldName.equals(JsniRef.CLASS)) {
-        JClassLiteral lit = program.getLiteralClass(type);
-        return lit.getField();
+        return type;
 
       } else if (type instanceof JPrimitiveType) {
         errorReporter.reportError("May not refer to fields on primitive types");
diff --git a/dev/core/src/com/google/gwt/dev/jjs/impl/ReplaceRebinds.java b/dev/core/src/com/google/gwt/dev/jjs/impl/ReplaceRebinds.java
index 84302ec..19627d5 100644
--- a/dev/core/src/com/google/gwt/dev/jjs/impl/ReplaceRebinds.java
+++ b/dev/core/src/com/google/gwt/dev/jjs/impl/ReplaceRebinds.java
@@ -20,7 +20,6 @@
 import com.google.gwt.dev.jdt.RebindPermutationOracle;
 import com.google.gwt.dev.jjs.InternalCompilerException;
 import com.google.gwt.dev.jjs.ast.Context;
-import com.google.gwt.dev.jjs.ast.HasEnclosingType;
 import com.google.gwt.dev.jjs.ast.HasName;
 import com.google.gwt.dev.jjs.ast.JClassLiteral;
 import com.google.gwt.dev.jjs.ast.JClassType;
@@ -31,6 +30,7 @@
 import com.google.gwt.dev.jjs.ast.JMethodCall;
 import com.google.gwt.dev.jjs.ast.JModVisitor;
 import com.google.gwt.dev.jjs.ast.JNameOf;
+import com.google.gwt.dev.jjs.ast.JNode;
 import com.google.gwt.dev.jjs.ast.JNullLiteral;
 import com.google.gwt.dev.jjs.ast.JProgram;
 import com.google.gwt.dev.jjs.ast.JReferenceType;
@@ -106,7 +106,7 @@
 
       if (ref != null) {
         final List<String> errors = new ArrayList<String>();
-        HasEnclosingType node = JsniRefLookup.findJsniRefTarget(ref, program,
+        JNode node = JsniRefLookup.findJsniRefTarget(ref, program,
             new JsniRefLookup.ErrorReporter() {
               public void reportError(String error) {
                 errors.add(error);
diff --git a/dev/core/test/com/google/gwt/dev/jjs/JavaAstConstructor.java b/dev/core/test/com/google/gwt/dev/jjs/JavaAstConstructor.java
index ce8b05e..f96623d 100644
--- a/dev/core/test/com/google/gwt/dev/jjs/JavaAstConstructor.java
+++ b/dev/core/test/com/google/gwt/dev/jjs/JavaAstConstructor.java
@@ -29,6 +29,7 @@
 import com.google.gwt.dev.jjs.ast.JProgram;
 import com.google.gwt.dev.jjs.impl.AssertionNormalizer;
 import com.google.gwt.dev.jjs.impl.BuildTypeMap;
+import com.google.gwt.dev.jjs.impl.ImplementClassLiteralsAsFields;
 import com.google.gwt.dev.jjs.impl.TypeLinker;
 import com.google.gwt.dev.jjs.impl.FixAssignmentToUnbox;
 import com.google.gwt.dev.jjs.impl.GenerateJavaAST;
@@ -275,6 +276,8 @@
     // Replace references to JSO subtypes with JSO itself.
     JavaScriptObjectNormalizer.exec(jprogram);
 
+    ImplementClassLiteralsAsFields.exec(jprogram);
+
     // Tree is now ready to optimize.
     return jprogram;
   }
diff --git a/dev/core/test/com/google/gwt/dev/jjs/impl/JsniRefLookupTest.java b/dev/core/test/com/google/gwt/dev/jjs/impl/JsniRefLookupTest.java
index f6b24dc..f9a6557 100644
--- a/dev/core/test/com/google/gwt/dev/jjs/impl/JsniRefLookupTest.java
+++ b/dev/core/test/com/google/gwt/dev/jjs/impl/JsniRefLookupTest.java
@@ -17,9 +17,9 @@
 
 import com.google.gwt.core.ext.UnableToCompleteException;
 import com.google.gwt.dev.javac.impl.MockJavaResource;
-import com.google.gwt.dev.jjs.ast.HasEnclosingType;
 import com.google.gwt.dev.jjs.ast.JField;
 import com.google.gwt.dev.jjs.ast.JMethod;
+import com.google.gwt.dev.jjs.ast.JNode;
 import com.google.gwt.dev.jjs.ast.JPrimitiveType;
 import com.google.gwt.dev.jjs.ast.JProgram;
 import com.google.gwt.dev.jjs.impl.JsniRefLookup.ErrorReporter;
@@ -238,17 +238,17 @@
 
     {
       MockErrorReporter errors = new MockErrorReporter();
-      HasEnclosingType res = lookup("test.Foo::bogoField", errors);
+      lookup("test.Foo::bogoField", errors);
       errors.assertHasError();
     }
     {
       MockErrorReporter errors = new MockErrorReporter();
-      HasEnclosingType res = lookup("test.Foo::bogoMethod()", errors);
+      lookup("test.Foo::bogoMethod()", errors);
       errors.assertHasError();
     }
     {
       MockErrorReporter errors = new MockErrorReporter();
-      HasEnclosingType res = lookup("test.Foo::new(J)", errors);
+      lookup("test.Foo::new(J)", errors);
       errors.assertHasError();
     }
   }
@@ -367,7 +367,7 @@
     }
     {
       MockErrorReporter errors = new MockErrorReporter();
-      HasEnclosingType res = lookup("test.Bar::addTwoOverloaded(*)", errors);
+      lookup("test.Bar::addTwoOverloaded(*)", errors);
       errors.assertHasError();
     }
 
@@ -398,7 +398,7 @@
     }
     {
       MockErrorReporter errors = new MockErrorReporter();
-      HasEnclosingType res = lookup("test.Bar::foo(*)", errors);
+      lookup("test.Bar::foo(*)", errors);
       errors.assertHasError();
     }
 
@@ -463,7 +463,7 @@
     }
     {
       MockErrorReporter errors = new MockErrorReporter();
-      JMethod res = (JMethod) lookup("test.Intf::foo(*)", errors);
+      lookup("test.Intf::foo(*)", errors);
       errors.assertHasError();
     }
   }
@@ -488,12 +488,12 @@
     // test private entries in the superclass
     {
       MockErrorReporter errors = new MockErrorReporter();
-      JMethod res = (JMethod) lookup("test.PrivateSub::methodSup()", errors);
+      lookup("test.PrivateSub::methodSup()", errors);
       errors.assertHasError();
     }
     {
       MockErrorReporter errors = new MockErrorReporter();
-      JField res = (JField) lookup("test.PrivateSub::fieldSup", errors);
+      lookup("test.PrivateSub::fieldSup", errors);
       errors.assertHasError();
     }
   }
@@ -508,17 +508,17 @@
     }
     {
       MockErrorReporter errors = new MockErrorReporter();
-      HasEnclosingType res = lookup("test.Foo::addTwoOverloaded(*)", errors);
+      lookup("test.Foo::addTwoOverloaded(*)", errors);
       errors.assertHasError();
     }
     {
       MockErrorReporter errors = new MockErrorReporter();
-      HasEnclosingType res = lookup("test.Foo::bogoMethod(*)", errors);
+      lookup("test.Foo::bogoMethod(*)", errors);
       errors.assertHasError();
     }
   }
 
-  private HasEnclosingType lookup(String refString, MockErrorReporter errors) {
+  private JNode lookup(String refString, MockErrorReporter errors) {
     return JsniRefLookup.findJsniRefTarget(JsniRef.parse(refString), program,
         errors);
   }