Make Class.getName() behave in a useful manner when class metadata is disabled.
The return value from getName() will be of the format "Class$abc" for instantiable types, where "abc" can be deobfuscated using the symbol map file.
For all other types, the return value will be "Class$123", where the numeric value will vary between runs.

Patch by: bobv
Review by: scottb

git-svn-id: https://google-web-toolkit.googlecode.com/svn/trunk@5479 8db76d5a-ed1c-0410-87a9-c151d255dfc7
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 83ff78b..aab937b 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
@@ -56,7 +56,27 @@
     call.addArgs(program.getLiteralString(info, getPackageName(typeName)),
         program.getLiteralString(info, getClassName(typeName)));
 
+    if (type instanceof JArrayType) {
+      // There's only one seed function for all arrays
+      JDeclaredType arrayType = program.getIndexedType("Array");
+      call.addArg(new JNameOf(info, program, arrayType));
+
+    } else if (type instanceof JDeclaredType) {
+      // Add the name of the seed function for non-array reference types
+      call.addArg(new JNameOf(info, program, 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;
diff --git a/dev/core/src/com/google/gwt/dev/jjs/ast/JNameOf.java b/dev/core/src/com/google/gwt/dev/jjs/ast/JNameOf.java
new file mode 100644
index 0000000..5679812
--- /dev/null
+++ b/dev/core/src/com/google/gwt/dev/jjs/ast/JNameOf.java
@@ -0,0 +1,54 @@
+/*
+ * Copyright 2009 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.ast;
+
+import com.google.gwt.dev.jjs.SourceInfo;
+
+/**
+ * An AST node whose evaluation results in the string name of its node.
+ */
+public class JNameOf extends JExpression {
+
+  private final HasName node;
+  private final JType stringType;
+
+  public JNameOf(SourceInfo info, JProgram program, HasName node) {
+    super(info);
+    this.node = node;
+    stringType = program.getTypeJavaLangString();
+  }
+
+  public HasName getNode() {
+    return node;
+  }
+
+  public JType getType() {
+    return stringType;
+  }
+
+  @Override
+  public boolean hasSideEffects() {
+    return false;
+  }
+
+  public void traverse(JVisitor visitor, Context ctx) {
+    if (visitor.visit(this, ctx)) {
+      // Intentionally not visiting referenced node
+    }
+    visitor.endVisit(this, ctx);
+  }
+
+}
diff --git a/dev/core/src/com/google/gwt/dev/jjs/ast/JVisitor.java b/dev/core/src/com/google/gwt/dev/jjs/ast/JVisitor.java
index b552eb8..cf8dc20 100644
--- a/dev/core/src/com/google/gwt/dev/jjs/ast/JVisitor.java
+++ b/dev/core/src/com/google/gwt/dev/jjs/ast/JVisitor.java
@@ -237,6 +237,9 @@
   public void endVisit(JMultiExpression x, Context ctx) {
   }
 
+  public void endVisit(JNameOf x, Context ctx) {
+  }
+
   public void endVisit(JNewArray x, Context ctx) {
   }
 
@@ -461,6 +464,10 @@
     return true;
   }
 
+  public boolean visit(JNameOf x, Context ctx) {
+    return true;
+  }
+
   public boolean visit(JNewArray x, Context ctx) {
     return true;
   }
diff --git a/dev/core/src/com/google/gwt/dev/jjs/impl/CloneExpressionVisitor.java b/dev/core/src/com/google/gwt/dev/jjs/impl/CloneExpressionVisitor.java
index 6d858bf..f4c5a2d 100644
--- a/dev/core/src/com/google/gwt/dev/jjs/impl/CloneExpressionVisitor.java
+++ b/dev/core/src/com/google/gwt/dev/jjs/impl/CloneExpressionVisitor.java
@@ -35,6 +35,7 @@
 import com.google.gwt.dev.jjs.ast.JLocalRef;
 import com.google.gwt.dev.jjs.ast.JLongLiteral;
 import com.google.gwt.dev.jjs.ast.JMethodCall;
+import com.google.gwt.dev.jjs.ast.JNameOf;
 import com.google.gwt.dev.jjs.ast.JNewArray;
 import com.google.gwt.dev.jjs.ast.JNewInstance;
 import com.google.gwt.dev.jjs.ast.JNullLiteral;
@@ -110,8 +111,8 @@
 
   @Override
   public boolean visit(JBinaryOperation x, Context ctx) {
-    expression = new JBinaryOperation(x.getSourceInfo(), x.getType(), x.getOp(),
-        cloneExpression(x.getLhs()), cloneExpression(x.getRhs()));
+    expression = new JBinaryOperation(x.getSourceInfo(), x.getType(),
+        x.getOp(), cloneExpression(x.getLhs()), cloneExpression(x.getRhs()));
     return false;
   }
 
@@ -149,8 +150,9 @@
 
   @Override
   public boolean visit(JConditional x, Context ctx) {
-    expression = new JConditional(x.getSourceInfo(), x.getType(), cloneExpression(x.getIfTest()),
-        cloneExpression(x.getThenExpr()), cloneExpression(x.getElseExpr()));
+    expression = new JConditional(x.getSourceInfo(), x.getType(),
+        cloneExpression(x.getIfTest()), cloneExpression(x.getThenExpr()),
+        cloneExpression(x.getElseExpr()));
     return false;
   }
 
@@ -162,8 +164,8 @@
 
   @Override
   public boolean visit(JFieldRef x, Context ctx) {
-    expression = new JFieldRef(x.getSourceInfo(), cloneExpression(x.getInstance()),
-        x.getField(), x.getEnclosingType());
+    expression = new JFieldRef(x.getSourceInfo(),
+        cloneExpression(x.getInstance()), x.getField(), x.getEnclosingType());
     return false;
   }
 
@@ -183,7 +185,8 @@
 
     // Use the clone constructor.
     JGwtCreate gwtCreate = new JGwtCreate(x.getSourceInfo(), x.getSourceType(),
-        x.getResultTypes(), x.getType(), cloneExpressions(x.getInstantiationExpressions()));
+        x.getResultTypes(), x.getType(),
+        cloneExpressions(x.getInstantiationExpressions()));
 
     expression = gwtCreate;
     return false;
@@ -237,9 +240,16 @@
   }
 
   @Override
+  public boolean visit(JNameOf x, Context ctx) {
+    expression = new JNameOf(x.getSourceInfo(), program, x.getNode());
+    return false;
+  }
+
+  @Override
   public boolean visit(JNewArray x, Context ctx) {
-    expression = new JNewArray(x.getSourceInfo(), x.getArrayType(), cloneExpressions(x.dims),
-        cloneExpressions(x.initializers), x.getClassLiterals());
+    expression = new JNewArray(x.getSourceInfo(), x.getArrayType(),
+        cloneExpressions(x.dims), cloneExpressions(x.initializers),
+        x.getClassLiterals());
     return false;
   }
 
@@ -263,13 +273,15 @@
 
   @Override
   public boolean visit(JPostfixOperation x, Context ctx) {
-    expression = new JPostfixOperation(x.getSourceInfo(), x.getOp(), cloneExpression(x.getArg()));
+    expression = new JPostfixOperation(x.getSourceInfo(), x.getOp(),
+        cloneExpression(x.getArg()));
     return false;
   }
 
   @Override
   public boolean visit(JPrefixOperation x, Context ctx) {
-    expression = new JPrefixOperation(x.getSourceInfo(), x.getOp(), cloneExpression(x.getArg()));
+    expression = new JPrefixOperation(x.getSourceInfo(), x.getOp(),
+        cloneExpression(x.getArg()));
     return false;
   }
 
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 570103c..21dd71f 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
@@ -464,26 +464,9 @@
           implementMethod(method, program.getLiteralBoolean(enableAsserts));
 
           if (disableClassMetadata) {
-            SourceInfo info = currentClass.getSourceInfo().makeChild(
-                JavaASTGenerationVisitor.class, "Disabled class metadata");
-
-            JMethod nameMethod = program.getIndexedMethod("Class.getName");
-
-            // this.hashCode()
-            JMethodCall hashCall = new JMethodCall(info,
-                program.getExprThisRef(info, (JClassType) currentClass),
-                program.getIndexedMethod("Object.hashCode"));
-
-            // "Class$" + hashCode()
-            JBinaryOperation op = new JBinaryOperation(info,
-                program.getTypeJavaLangString(), JBinaryOperator.ADD,
-                program.getLiteralString(info, "Class$"), hashCall);
-
-            implementMethod(nameMethod, op);
-
-            // Forget the superclass
-            JMethod superclassMethod = program.getIndexedMethod("Class.getSuperclass");
-            implementMethod(superclassMethod, program.getLiteralNull());
+            JMethod isMetadataEnabledMethod = program.getIndexedMethod("Class.isClassMetadataEnabled");
+            implementMethod(isMetadataEnabledMethod,
+                program.getLiteralBoolean(false));
           }
         }
 
@@ -2347,8 +2330,8 @@
      * expression. Beware that when autoboxing, the type of the expression is
      * not necessarily the same as the type of the box to be created. The JDT
      * figures out what the necessary conversion is, depending on the context
-     * the expression appears in, and stores it in <code>x.implicitConversion</code>,
-     * so extract it from there.
+     * the expression appears in, and stores it in
+     * <code>x.implicitConversion</code>, so extract it from there.
      */
     private JPrimitiveType implicitConversionTargetType(Expression x)
         throws InternalCompilerException {
@@ -2560,7 +2543,8 @@
 
       // recurse super class
       if (searchThisType.getSuperClass() != null) {
-        tryFindUpRefsRecursive(method, searchThisType.getSuperClass(), overrides);
+        tryFindUpRefsRecursive(method, searchThisType.getSuperClass(),
+            overrides);
       }
 
       // recurse super interfaces
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 12c5154..45db80e 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
@@ -56,6 +56,7 @@
 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.JNameOf;
 import com.google.gwt.dev.jjs.ast.JNewArray;
 import com.google.gwt.dev.jjs.ast.JNewInstance;
 import com.google.gwt.dev.jjs.ast.JParameter;
@@ -106,6 +107,7 @@
 import com.google.gwt.dev.js.ast.JsLabel;
 import com.google.gwt.dev.js.ast.JsModVisitor;
 import com.google.gwt.dev.js.ast.JsName;
+import com.google.gwt.dev.js.ast.JsNameOf;
 import com.google.gwt.dev.js.ast.JsNameRef;
 import com.google.gwt.dev.js.ast.JsNew;
 import com.google.gwt.dev.js.ast.JsNode;
@@ -1036,6 +1038,13 @@
     }
 
     @Override
+    public void endVisit(JNameOf x, Context ctx) {
+      JsName name = names.get(x.getNode());
+      assert name != null : "Missing JsName for " + x.getNode().getName();
+      push(new JsNameOf(x.getSourceInfo(), name));
+    }
+
+    @Override
     public void endVisit(JNewArray x, Context ctx) {
       throw new InternalCompilerException("Should not get here.");
     }
diff --git a/dev/core/src/com/google/gwt/dev/jjs/impl/Pruner.java b/dev/core/src/com/google/gwt/dev/jjs/impl/Pruner.java
index 2caa635..5840554 100644
--- a/dev/core/src/com/google/gwt/dev/jjs/impl/Pruner.java
+++ b/dev/core/src/com/google/gwt/dev/jjs/impl/Pruner.java
@@ -19,6 +19,7 @@
 import com.google.gwt.dev.jjs.ast.CanBeStatic;
 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.JBinaryOperation;
 import com.google.gwt.dev.jjs.ast.JBinaryOperator;
 import com.google.gwt.dev.jjs.ast.JClassType;
@@ -32,6 +33,7 @@
 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.JNode;
 import com.google.gwt.dev.jjs.ast.JParameter;
 import com.google.gwt.dev.jjs.ast.JPrimitiveType;
@@ -139,6 +141,19 @@
     }
 
     @Override
+    public void endVisit(JNameOf x, Context ctx) {
+      HasName node = x.getNode();
+      JReferenceType isType = node instanceof JReferenceType
+          ? (JReferenceType) node : null;
+      if (isType == null && !referencedNonTypes.contains(node)) {
+        ctx.replaceMe(program.getLiteralNull());
+      } else if (isType != null
+          && !program.typeOracle.isInstantiatedType(isType)) {
+        ctx.replaceMe(program.getLiteralNull());
+      }
+    }
+
+    @Override
     public void endVisit(JMethod x, Context ctx) {
       JType type = x.getType();
       if (type instanceof JReferenceType) {
diff --git a/dev/core/src/com/google/gwt/dev/jjs/impl/ToStringGenerationVisitor.java b/dev/core/src/com/google/gwt/dev/jjs/impl/ToStringGenerationVisitor.java
index c42a230..8dcd398 100644
--- a/dev/core/src/com/google/gwt/dev/jjs/impl/ToStringGenerationVisitor.java
+++ b/dev/core/src/com/google/gwt/dev/jjs/impl/ToStringGenerationVisitor.java
@@ -59,6 +59,7 @@
 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.JNameOf;
 import com.google.gwt.dev.jjs.ast.JNewArray;
 import com.google.gwt.dev.jjs.ast.JNewInstance;
 import com.google.gwt.dev.jjs.ast.JNode;
@@ -123,6 +124,7 @@
   protected static final char[] CHARS_IMPLEMENTS = "implements ".toCharArray();
   protected static final char[] CHARS_INSTANCEOF = " instanceof ".toCharArray();
   protected static final char[] CHARS_INTERFACE = "interface ".toCharArray();
+  protected static final char[] CHARS_NAMEOF = " JNameOf ".toCharArray();
   protected static final char[] CHARS_NATIVE = "native ".toCharArray();
   protected static final char[] CHARS_NEW = "new ".toCharArray();
   protected static final char[] CHARS_NULL = "null".toCharArray();
@@ -630,6 +632,15 @@
   }
 
   @Override
+  public boolean visit(JNameOf x, Context ctx) {
+    print(CHARS_SLASHSTAR);
+    print(CHARS_NAMEOF);
+    print(CHARS_STARSLASH);
+    printStringLiteral(x.getNode().getName());
+    return false;
+  }
+
+  @Override
   public boolean visit(JNewArray x, Context ctx) {
     print(CHARS_NEW);
     printTypeName(x.getArrayType());
diff --git a/dev/core/src/com/google/gwt/dev/js/JsHoister.java b/dev/core/src/com/google/gwt/dev/js/JsHoister.java
index e5f02ec..09d2934 100644
--- a/dev/core/src/com/google/gwt/dev/js/JsHoister.java
+++ b/dev/core/src/com/google/gwt/dev/js/JsHoister.java
@@ -22,13 +22,14 @@
 import com.google.gwt.dev.js.ast.JsBooleanLiteral;
 import com.google.gwt.dev.js.ast.JsConditional;
 import com.google.gwt.dev.js.ast.JsContext;
-import com.google.gwt.dev.js.ast.JsNumberLiteral;
 import com.google.gwt.dev.js.ast.JsExpression;
 import com.google.gwt.dev.js.ast.JsFunction;
 import com.google.gwt.dev.js.ast.JsInvocation;
+import com.google.gwt.dev.js.ast.JsNameOf;
 import com.google.gwt.dev.js.ast.JsNameRef;
 import com.google.gwt.dev.js.ast.JsNew;
 import com.google.gwt.dev.js.ast.JsNullLiteral;
+import com.google.gwt.dev.js.ast.JsNumberLiteral;
 import com.google.gwt.dev.js.ast.JsObjectLiteral;
 import com.google.gwt.dev.js.ast.JsPostfixOperation;
 import com.google.gwt.dev.js.ast.JsPrefixOperation;
@@ -78,7 +79,8 @@
 
     @Override
     public void endVisit(JsBinaryOperation x, JsContext<JsExpression> ctx) {
-      JsBinaryOperation toReturn = new JsBinaryOperation(x.getSourceInfo(), x.getOperator());
+      JsBinaryOperation toReturn = new JsBinaryOperation(x.getSourceInfo(),
+          x.getOperator());
       toReturn.setArg2(stack.pop());
       toReturn.setArg1(stack.pop());
       stack.push(toReturn);
@@ -125,6 +127,11 @@
       stack.push(toReturn);
     }
 
+    public void endVisit(JsNameOf x, JsContext<JsExpression> ctx) {
+      JsNameOf toReturn = new JsNameOf(x.getSourceInfo(), x.getName());
+      stack.push(toReturn);
+    }
+
     /**
      * Do a deep clone of a JsNameRef. Because JsNameRef chains are shared
      * throughout the AST, you can't just go and change their qualifiers when
@@ -174,7 +181,8 @@
          * rather than expecting it to be on the stack and having to perform
          * narrowing casts at all stack.pop() invocations.
          */
-        JsPropertyInitializer newInit = new JsPropertyInitializer(x.getSourceInfo());
+        JsPropertyInitializer newInit = new JsPropertyInitializer(
+            x.getSourceInfo());
         newInit.setValueExpr(stack.pop());
         newInit.setLabelExpr(stack.pop());
 
@@ -185,14 +193,16 @@
 
     @Override
     public void endVisit(JsPostfixOperation x, JsContext<JsExpression> ctx) {
-      JsPostfixOperation toReturn = new JsPostfixOperation(x.getSourceInfo(), x.getOperator());
+      JsPostfixOperation toReturn = new JsPostfixOperation(x.getSourceInfo(),
+          x.getOperator());
       toReturn.setArg(stack.pop());
       stack.push(toReturn);
     }
 
     @Override
     public void endVisit(JsPrefixOperation x, JsContext<JsExpression> ctx) {
-      JsPrefixOperation toReturn = new JsPrefixOperation(x.getSourceInfo(), x.getOperator());
+      JsPrefixOperation toReturn = new JsPrefixOperation(x.getSourceInfo(),
+          x.getOperator());
       toReturn.setArg(stack.pop());
       stack.push(toReturn);
     }
diff --git a/dev/core/src/com/google/gwt/dev/js/JsToStringGenerationVisitor.java b/dev/core/src/com/google/gwt/dev/js/JsToStringGenerationVisitor.java
index 0660d3e..3b43086 100644
--- a/dev/core/src/com/google/gwt/dev/js/JsToStringGenerationVisitor.java
+++ b/dev/core/src/com/google/gwt/dev/js/JsToStringGenerationVisitor.java
@@ -41,6 +41,7 @@
 import com.google.gwt.dev.js.ast.JsInvocation;
 import com.google.gwt.dev.js.ast.JsLabel;
 import com.google.gwt.dev.js.ast.JsName;
+import com.google.gwt.dev.js.ast.JsNameOf;
 import com.google.gwt.dev.js.ast.JsNameRef;
 import com.google.gwt.dev.js.ast.JsNew;
 import com.google.gwt.dev.js.ast.JsNullLiteral;
@@ -530,6 +531,12 @@
   }
 
   @Override
+  public boolean visit(JsNameOf x, JsContext<JsExpression> ctx) {
+    printStringLiteral(x.getName().getShortIdent());
+    return false;
+  }
+
+  @Override
   public boolean visit(JsNameRef x, JsContext<JsExpression> ctx) {
     JsExpression q = x.getQualifier();
     if (q != null) {
@@ -1103,9 +1110,8 @@
   }
 
   /**
-   * Decide whether, if <code>op</code> is printed followed by
-   * <code>arg</code>, there needs to be a space between the operator and
-   * expression.
+   * Decide whether, if <code>op</code> is printed followed by <code>arg</code>,
+   * there needs to be a space between the operator and expression.
    * 
    * @return <code>true</code> if a space needs to be printed
    */
@@ -1201,9 +1207,9 @@
 
   /**
    * Adapted from
-   * {@link com.google.gwt.dev.js.rhino.ScriptRuntime#escapeString(String)}.
-   * The difference is that we quote with either &quot; or &apos; depending on
-   * which one is used less inside the string.
+   * {@link com.google.gwt.dev.js.rhino.ScriptRuntime#escapeString(String)}. The
+   * difference is that we quote with either &quot; or &apos; depending on which
+   * one is used less inside the string.
    */
   private void printStringLiteral(String value) {
 
diff --git a/dev/core/src/com/google/gwt/dev/js/ast/JsNameOf.java b/dev/core/src/com/google/gwt/dev/js/ast/JsNameOf.java
new file mode 100644
index 0000000..7fc79a0
--- /dev/null
+++ b/dev/core/src/com/google/gwt/dev/js/ast/JsNameOf.java
@@ -0,0 +1,60 @@
+/*
+ * Copyright 2009 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.js.ast;
+
+import com.google.gwt.dev.jjs.SourceInfo;
+
+/**
+ * An AST node whose evaluation results in the string name of its node.
+ */
+public class JsNameOf extends JsExpression {
+  private final JsName name;
+
+  public JsNameOf(SourceInfo info, JsName name) {
+    super(info);
+    this.name = name;
+  }
+
+  public JsNameOf(SourceInfo info, HasName node) {
+    this(info, node.getName());
+  }
+
+  public JsName getName() {
+    return name;
+  }
+
+  @Override
+  public boolean hasSideEffects() {
+    return false;
+  }
+
+  @Override
+  public boolean isDefinitelyNotNull() {
+    // GenerateJsAST would have already replaced unnamed references with null
+    return true;
+  }
+
+  @Override
+  public boolean isDefinitelyNull() {
+    return false;
+  }
+
+  public void traverse(JsVisitor visitor, JsContext<JsExpression> ctx) {
+    if (visitor.visit(this, ctx)) {
+    }
+    visitor.endVisit(this, ctx);
+  }
+}
diff --git a/dev/core/src/com/google/gwt/dev/js/ast/JsVisitor.java b/dev/core/src/com/google/gwt/dev/js/ast/JsVisitor.java
index e3151f5..0769870 100644
--- a/dev/core/src/com/google/gwt/dev/js/ast/JsVisitor.java
+++ b/dev/core/src/com/google/gwt/dev/js/ast/JsVisitor.java
@@ -176,6 +176,9 @@
   public void endVisit(JsLabel x, JsContext<JsStatement> ctx) {
   }
 
+  public void endVisit(JsNameOf x, JsContext<JsExpression> ctx) {
+  }
+
   public void endVisit(JsNameRef x, JsContext<JsExpression> ctx) {
   }
 
@@ -324,6 +327,10 @@
     return true;
   }
 
+  public boolean visit(JsNameOf x, JsContext<JsExpression> ctx) {
+    return true;
+  }
+
   public boolean visit(JsNameRef x, JsContext<JsExpression> ctx) {
     return true;
   }
diff --git a/user/super/com/google/gwt/emul/java/lang/Class.java b/user/super/com/google/gwt/emul/java/lang/Class.java
index 515fecf..1285c8b 100644
--- a/user/super/com/google/gwt/emul/java/lang/Class.java
+++ b/user/super/com/google/gwt/emul/java/lang/Class.java
@@ -35,10 +35,11 @@
    * 
    * @skip
    */
-  static <T> Class<T> createForArray(String packageName, String className, Class<?> componentType) {
+  static <T> Class<T> createForArray(String packageName, String className,
+      String seedName, Class<?> componentType) {
     // Initialize here to avoid method inliner
     Class<T> clazz = new Class<T>();
-    clazz.typeName = packageName + className;
+    setName(clazz, packageName, className, seedName);
     clazz.modifiers = ARRAY;
     clazz.superclass = Object.class;
     clazz.componentType = componentType;
@@ -51,10 +52,10 @@
    * @skip
    */
   static <T> Class<T> createForClass(String packageName, String className,
-      Class<? super T> superclass) {
+      String seedName, Class<? super T> superclass) {
     // Initialize here to avoid method inliner
     Class<T> clazz = new Class<T>();
-    clazz.typeName = packageName + className;
+    setName(clazz, packageName, className, seedName);
     clazz.superclass = superclass;
     return clazz;
   }
@@ -65,10 +66,11 @@
    * @skip
    */
   static <T> Class<T> createForEnum(String packageName, String className,
-      Class<? super T> superclass, JavaScriptObject enumConstantsFunc) {
+      String seedName, Class<? super T> superclass,
+      JavaScriptObject enumConstantsFunc) {
     // Initialize here to avoid method inliner
     Class<T> clazz = new Class<T>();
-    clazz.typeName = packageName + className;
+    setName(clazz, packageName, className, seedName);
     clazz.modifiers = (enumConstantsFunc != null) ? ENUM : 0;
     clazz.superclass = clazz.enumSuperclass = superclass;
     clazz.enumConstantsFunc = enumConstantsFunc;
@@ -83,7 +85,7 @@
   static <T> Class<T> createForInterface(String packageName, String className) {
     // Initialize here to avoid method inliner
     Class<T> clazz = new Class<T>();
-    clazz.typeName = packageName + className;
+    setName(clazz, packageName, className, null);
     clazz.modifiers = INTERFACE;
     return clazz;
   }
@@ -93,21 +95,37 @@
    * 
    * @skip
    */
-  static Class<?> createForPrimitive(String packageName, String className) {
+  static Class<?> createForPrimitive(String packageName, String className,
+      String seedName) {
     // Initialize here to avoid method inliner
     Class<?> clazz = new Class<Object>();
-    clazz.typeName = packageName + className;
+    setName(clazz, packageName, className, seedName);
     clazz.modifiers = PRIMITIVE;
     return clazz;
   }
-  
+
+  static boolean isClassMetadataEnabled() {
+    // This body may be replaced by the compiler
+    return true;
+  }
+
+  static void setName(Class<?> clazz, String packageName, String className,
+      String seedName) {
+    if (clazz.isClassMetadataEnabled()) {
+      clazz.typeName = packageName + className;
+    } else {
+      clazz.typeName = "Class$"
+          + (seedName != null ? seedName : clazz.hashCode());
+    }
+  }
+
   int modifiers;
 
   private Class<?> componentType;
 
   @SuppressWarnings("unused")
   private JavaScriptObject enumConstantsFunc;
-  
+
   private Class<? super T> enumSuperclass;
 
   private String typeName;
@@ -123,8 +141,8 @@
   }
 
   public boolean desiredAssertionStatus() {
-    // This body is ignored by the JJS compiler and a new one is 
-    // synthesized at compile-time based on the actual compilation arguments.  
+    // This body is ignored by the JJS compiler and a new one is
+    // synthesized at compile-time based on the actual compilation arguments.
     return false;
   }
 
@@ -145,13 +163,15 @@
   }
 
   public String getName() {
-    // This body may be replaced by the compiler
     return typeName;
   }
 
   public Class<? super T> getSuperclass() {
-    // This body may be replaced by the compiler
-    return superclass;
+    if (isClassMetadataEnabled()) {
+      return superclass;
+    } else {
+      return null;
+    }
   }
 
   public boolean isArray() {