Normalize Array.getClass()

It's kind of weird to have the magic Array class implement getClass() directly, which is normally final on Object.  Since we had to special-case it in the compiler anyway, it seems better to just move the implementation there.

http://gwt-code-reviews.appspot.com/658802/show
Review by: tobyr


git-svn-id: https://google-web-toolkit.googlecode.com/svn/trunk@8314 8db76d5a-ed1c-0410-87a9-c151d255dfc7
diff --git a/dev/core/src/com/google/gwt/dev/jjs/impl/BuildTypeMap.java b/dev/core/src/com/google/gwt/dev/jjs/impl/BuildTypeMap.java
index 06f21db..44414f4 100644
--- a/dev/core/src/com/google/gwt/dev/jjs/impl/BuildTypeMap.java
+++ b/dev/core/src/com/google/gwt/dev/jjs/impl/BuildTypeMap.java
@@ -564,8 +564,7 @@
       try {
         // Create an override for getClass().
         if (type instanceof JClassType
-            && type != program.getTypeJavaLangObject()
-            && type != program.getIndexedType("Array")) {
+            && type != program.getTypeJavaLangObject()) {
           JMethod getClassMethod = program.createMethod(
               type.getSourceInfo().makeChild(BuildDeclMapVisitor.class,
                   "Synthetic getClass()"), "getClass", type,
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 658c1cb..f5b512d 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
@@ -81,6 +81,7 @@
 import com.google.gwt.dev.jjs.ast.JStatement;
 import com.google.gwt.dev.jjs.ast.JStringLiteral;
 import com.google.gwt.dev.jjs.ast.JSwitchStatement;
+import com.google.gwt.dev.jjs.ast.JThisRef;
 import com.google.gwt.dev.jjs.ast.JThrowStatement;
 import com.google.gwt.dev.jjs.ast.JTryStatement;
 import com.google.gwt.dev.jjs.ast.JType;
@@ -450,8 +451,7 @@
 
         // Write the body of the getClass() override.
         if (currentClass instanceof JClassType
-            && currentClass != program.getTypeJavaLangObject()
-            && currentClass != program.getIndexedType("Array")) {
+            && currentClass != program.getTypeJavaLangObject()) {
           JMethod method = currentClass.getMethods().get(2);
           assert ("getClass".equals(method.getName()));
 
@@ -461,7 +461,15 @@
             currentClass.getMethods().remove(2);
           } else {
             tryFindUpRefs(method);
-            implementMethod(method, program.getLiteralClass(currentClass));
+            if (currentClass == program.getIndexedType("Array")) {
+              // Special implementation: return this.arrayClass
+              SourceInfo info = method.getSourceInfo();
+              implementMethod(method, new JFieldRef(info, new JThisRef(info,
+                  program.getNonNullType(currentClass)),
+                  program.getIndexedField("Array.arrayClass"), currentClass));
+            } else {
+              implementMethod(method, program.getLiteralClass(currentClass));
+            }
           }
         }
 
diff --git a/dev/core/super/com/google/gwt/dev/jjs/intrinsic/com/google/gwt/lang/Array.java b/dev/core/super/com/google/gwt/dev/jjs/intrinsic/com/google/gwt/lang/Array.java
index 02ddedd..1d09a04 100644
--- a/dev/core/super/com/google/gwt/dev/jjs/intrinsic/com/google/gwt/lang/Array.java
+++ b/dev/core/super/com/google/gwt/dev/jjs/intrinsic/com/google/gwt/lang/Array.java
@@ -130,7 +130,7 @@
    * @param seedType the primitive type of the array; 0: null; 1: zero; 2: false
    * @return the new array
    */
-  public static Array initDim(Class arrayClass, int typeId, int queryId,
+  public static Array initDim(Class<?> arrayClass, int typeId, int queryId,
       int length, int seedType) {
     Array result = createFromSeed(seedType, length);
     initValues(arrayClass, typeId, queryId, result);
@@ -148,7 +148,7 @@
    * @param seedType the primitive type of the array; 0: null; 1: zero; 2: false
    * @return the new array
    */
-  public static Array initDims(Class arrayClasses[], int[] typeIdExprs,
+  public static Array initDims(Class<?> arrayClasses[], int[] typeIdExprs,
       int[] queryIdExprs, int[] dimExprs, int count, int seedType) {
     return initDims(arrayClasses, typeIdExprs, queryIdExprs, dimExprs, 0,
         count, seedType);
@@ -164,7 +164,7 @@
    * @param array the JSON array that will be transformed into a GWT array
    * @return values; having wrapped it for GWT
    */
-  public static Array initValues(Class arrayClass, int typeId, int queryId,
+  public static Array initValues(Class<?> arrayClass, int typeId, int queryId,
       Array array) {
     ExpandoWrapper.wrapArray(array);
     array.arrayClass = arrayClass;
@@ -235,7 +235,7 @@
     return array;
   }-*/;
 
-  private static Array initDims(Class arrayClasses[], int[] typeIdExprs,
+  private static Array initDims(Class<?> arrayClasses[], int[] typeIdExprs,
       int[] queryIdExprs, int[] dimExprs, int index, int count, int seedType) {
     int length = dimExprs[index];
     boolean isLastDim = (index == (count - 1));
@@ -265,12 +265,24 @@
    * Explicitly initialize all fields to JS false values; see comment in
    * ExpandoWrapper.initExpandos().
    */
+  
+  /**
+   * Represents the array length. References to this field are magically
+   * translated.
+   */
   public volatile int length = 0;
-  protected Class arrayClass = null;
-  protected int queryId = 0;
 
-  @Override
-  public Class getClass() {
-    return arrayClass;
-  }
+  /**
+   * Holds the real type-specific Class object for a given array instance. The
+   * compiler produces a magic implementation of getClass() which returns this
+   * field directly.
+   */
+  protected Class<?> arrayClass = null;
+
+  /**
+   * The necessary cast target for objects stored into this array. Attempting to
+   * store an object that cannot satisfy the query id throws and
+   * {@link ArrayStoreException}.
+   */
+  protected int queryId = 0;
 }
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 544dc2d..a5b5e96 100644
--- a/dev/core/test/com/google/gwt/dev/jjs/JavaAstConstructor.java
+++ b/dev/core/test/com/google/gwt/dev/jjs/JavaAstConstructor.java
@@ -57,7 +57,8 @@
       StringBuffer code = new StringBuffer();
       code.append("package com.google.gwt.lang;\n");
       code.append("public final class Array {\n");
-      code.append("  public int length;\n");
+      code.append("  public int length = 0;\n");
+      code.append("  protected Class<?> arrayClass = null;\n");
       code.append("}\n");
       return code;
     }
diff --git a/dev/core/test/com/google/gwt/dev/jjs/impl/CodeSplitterTest.java b/dev/core/test/com/google/gwt/dev/jjs/impl/CodeSplitterTest.java
index fe8ead0..1a4d726 100644
--- a/dev/core/test/com/google/gwt/dev/jjs/impl/CodeSplitterTest.java
+++ b/dev/core/test/com/google/gwt/dev/jjs/impl/CodeSplitterTest.java
@@ -16,7 +16,6 @@
 package com.google.gwt.dev.jjs.impl;
 
 import com.google.gwt.core.ext.UnableToCompleteException;
-import com.google.gwt.dev.javac.impl.MockJavaResource;
 import com.google.gwt.dev.jjs.ast.JProgram;
 
 /**
@@ -28,19 +27,6 @@
    * live.
    */
   public void testArrayIsInitial() throws UnableToCompleteException {
-    sourceOracle.addOrReplace(new MockJavaResource("com.google.gwt.lang.Array") {
-      @Override
-      protected CharSequence getContent() {
-        StringBuffer code = new StringBuffer();
-        code.append("package com.google.gwt.lang;\n");
-        code.append("public class Array {\n");
-        code.append("  private Class type;\n");
-        code.append("  public Class getClass() { return type; }\n");
-        code.append("}\n");
-        return code;
-      }
-    });
-
     JProgram program = compileSnippet("void", "");
     ControlFlowAnalyzer cfa = CodeSplitter.computeInitiallyLive(program);
 
diff --git a/user/super/com/google/gwt/emul/java/lang/Object.java b/user/super/com/google/gwt/emul/java/lang/Object.java
index c93e2ae..4979a83 100644
--- a/user/super/com/google/gwt/emul/java/lang/Object.java
+++ b/user/super/com/google/gwt/emul/java/lang/Object.java
@@ -58,6 +58,8 @@
    * Magic; unlike the real JRE, we don't spec this method as final. The
    * compiler will generate a polymorphic override on every other class which
    * will return the correct class object.
+   * 
+   * TODO(scottb): declare this final, but have the compiler fix it up.
    */
   public Class<? extends Object> getClass() {
     return Object.class;