Revision: 10191
Author:   gwt.mirror...@gmail.com
Date:     Tue May 17 07:35:44 2011
Log: In PRETTY and DETAILED, generate symbolic type queries for readability.

This makes the output much nicer to read, you can actually tell what type checks mean instead of looking at useless numbers. Also, this patch greatly reduces compiled output "jitter" when you're trying to diff slightly different versions of compiler output to track down a bug.

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

http://code.google.com/p/google-web-toolkit/source/detail?r=10191

Added:
 /trunk/dev/core/src/com/google/gwt/dev/jjs/ast/js/JsCastMap.java
Modified:
 /trunk/dev/core/src/com/google/gwt/dev/jjs/ast/JProgram.java
 /trunk/dev/core/src/com/google/gwt/dev/jjs/ast/JVisitor.java
 /trunk/dev/core/src/com/google/gwt/dev/jjs/ast/js/JsonArray.java
 /trunk/dev/core/src/com/google/gwt/dev/jjs/impl/ArrayNormalizer.java
 /trunk/dev/core/src/com/google/gwt/dev/jjs/impl/CastNormalizer.java
 /trunk/dev/core/src/com/google/gwt/dev/jjs/impl/GenerateJavaScriptAST.java
/trunk/dev/core/src/com/google/gwt/dev/jjs/impl/ToStringGenerationVisitor.java

=======================================
--- /dev/null
+++ /trunk/dev/core/src/com/google/gwt/dev/jjs/ast/js/JsCastMap.java Tue May 17 07:35:44 2011
@@ -0,0 +1,69 @@
+/*
+ * 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.ast.js;
+
+import com.google.gwt.dev.jjs.SourceInfo;
+import com.google.gwt.dev.jjs.ast.Context;
+import com.google.gwt.dev.jjs.ast.JClassType;
+import com.google.gwt.dev.jjs.ast.JIntLiteral;
+import com.google.gwt.dev.jjs.ast.JType;
+import com.google.gwt.dev.jjs.ast.JVisitor;
+
+import java.util.List;
+
+/**
+ * A low-level node representing a castable type map.
+ */
+public class JsCastMap extends JsonArray {
+
+  /**
+   * A low-level node representing a query type for cast/instanceof.
+   */
+  public static class JsQueryType extends JIntLiteral {
+    private final JType queryType;
+
+ public JsQueryType(SourceInfo sourceInfo, JType queryType, int queryId) {
+      super(sourceInfo, queryId);
+      this.queryType = queryType;
+    }
+
+    public int getQueryId() {
+      return getValue();
+    }
+
+    public JType getQueryType() {
+      return queryType;
+    }
+
+    public void traverse(JVisitor visitor, Context ctx) {
+      if (visitor.visit(this, ctx)) {
+      }
+      visitor.endVisit(this, ctx);
+    }
+  }
+
+ public JsCastMap(SourceInfo sourceInfo, List<JsQueryType> queryTypes, JClassType jsoType) {
+    super(sourceInfo, jsoType);
+    getExprs().addAll(queryTypes);
+  }
+
+  public void traverse(JVisitor visitor, Context ctx) {
+    if (visitor.visit(this, ctx)) {
+      visitor.accept(getExprs());
+    }
+    visitor.endVisit(this, ctx);
+  }
+}
=======================================
--- /trunk/dev/core/src/com/google/gwt/dev/jjs/ast/JProgram.java Fri May 13 08:44:36 2011 +++ /trunk/dev/core/src/com/google/gwt/dev/jjs/ast/JProgram.java Tue May 17 07:35:44 2011
@@ -22,8 +22,8 @@
 import com.google.gwt.dev.jjs.SourceInfo;
 import com.google.gwt.dev.jjs.SourceOrigin;
 import com.google.gwt.dev.jjs.ast.JField.Disposition;
+import com.google.gwt.dev.jjs.ast.js.JsCastMap;
 import com.google.gwt.dev.jjs.ast.js.JsniMethodBody;
-import com.google.gwt.dev.jjs.ast.js.JsonObject;
 import com.google.gwt.dev.jjs.impl.CodeSplitter;
 import com.google.gwt.dev.jjs.impl.ReplaceRunAsyncs.RunAsyncReplacement;
 import com.google.gwt.dev.util.collect.Lists;
@@ -320,7 +320,7 @@

private final HashMap<JType, JArrayType> arrayTypes = new HashMap<JType, JArrayType>();

-  private IdentityHashMap<JReferenceType, JsonObject> castableTypeMaps;
+  private IdentityHashMap<JReferenceType, JsCastMap> castMaps;

   /**
    * A factory to create correlations.
@@ -335,7 +335,7 @@

private final Map<JMethod, JMethod> instanceToStaticMap = new IdentityHashMap<JMethod, JMethod>();

-  private Map<JReferenceType, Integer> queryIds;
+  private Map<JReferenceType, Integer> queryIdsByType;

   /**
    * Filled in by ReplaceRunAsync, once the numbers are known.
@@ -358,6 +358,8 @@

private final Map<String, JDeclaredType> typeNameMap = new HashMap<String, JDeclaredType>();

+  private List<JReferenceType> typesByQueryId;
+
   private JClassType typeSpecialClassLiteralHolder;

   private JClassType typeSpecialJavaScriptObject;
@@ -740,19 +742,13 @@
     return allEntryMethods;
   }

-  public JsonObject getCastableTypeMap(JReferenceType referenceType) {
+  public JsCastMap getCastMap(JReferenceType referenceType) {
     // ensure jsonCastableTypeMaps has been initialized
     // it might not have been if the CastNormalizer has not been run
-    if (castableTypeMaps == null) {
+    if (castMaps == null) {
       initTypeInfo(null);
     }
-    JsonObject returnMap = castableTypeMaps.get(referenceType);
-    if (returnMap == null) {
-      // add a new empty map
- returnMap = new JsonObject(createSourceInfoSynthetic(JProgram.class), getJavaScriptObject());
-      castableTypeMaps.put(referenceType, returnMap);
-    }
-    return returnMap;
+    return castMaps.get(referenceType);
   }

   public String getClassLiteralName(JType type) {
@@ -860,7 +856,7 @@

   public int getQueryId(JReferenceType elementType) {
     assert (elementType == elementType.getUnderlyingType());
-    Integer integer = queryIds.get(elementType);
+    Integer integer = queryIdsByType.get(elementType);
     if (integer == null) {
       return 0;
     }
@@ -980,16 +976,19 @@
   public JPrimitiveType getTypePrimitiveShort() {
     return JPrimitiveType.SHORT;
   }
+
+  public List<JReferenceType> getTypesByQueryId() {
+    return typesByQueryId;
+  }

   public JPrimitiveType getTypeVoid() {
     return JPrimitiveType.VOID;
   }

-  public void initTypeInfo(
- IdentityHashMap<JReferenceType, JsonObject> instantiatedTypeCastableTypeMaps) {
-    castableTypeMaps = instantiatedTypeCastableTypeMaps;
-    if (castableTypeMaps == null || castableTypeMaps.size() == 0) {
-      castableTypeMaps = new IdentityHashMap<JReferenceType, JsonObject>();
+ public void initTypeInfo(IdentityHashMap<JReferenceType, JsCastMap> instantiatedCastableTypesMap) {
+    castMaps = instantiatedCastableTypesMap;
+    if (castMaps == null) {
+      castMaps = new IdentityHashMap<JReferenceType, JsCastMap>();
     }
   }

@@ -1032,8 +1031,10 @@
     }
   }

-  public void recordQueryIds(Map<JReferenceType, Integer> queryIds) {
-    this.queryIds = queryIds;
+  public void recordQueryIds(Map<JReferenceType, Integer> queryIdsByType,
+      List<JReferenceType> typesByQueryId) {
+    this.queryIdsByType = queryIdsByType;
+    this.typesByQueryId = typesByQueryId;
   }

public void setRunAsyncReplacements(Map<Integer, RunAsyncReplacement> map) {
=======================================
--- /trunk/dev/core/src/com/google/gwt/dev/jjs/ast/JVisitor.java Tue Apr 19 10:10:18 2011 +++ /trunk/dev/core/src/com/google/gwt/dev/jjs/ast/JVisitor.java Tue May 17 07:35:44 2011
@@ -17,6 +17,8 @@

 import com.google.gwt.dev.jjs.InternalCompilerException;
 import com.google.gwt.dev.jjs.ast.js.JMultiExpression;
+import com.google.gwt.dev.jjs.ast.js.JsCastMap;
+import com.google.gwt.dev.jjs.ast.js.JsCastMap.JsQueryType;
 import com.google.gwt.dev.jjs.ast.js.JsniFieldRef;
 import com.google.gwt.dev.jjs.ast.js.JsniMethodBody;
 import com.google.gwt.dev.jjs.ast.js.JsniMethodRef;
@@ -410,6 +412,10 @@
   public void endVisit(JReturnStatement x, Context ctx) {
     endVisit((JStatement) x, ctx);
   }
+
+  public void endVisit(JsCastMap x, Context ctx) {
+    endVisit((JsonArray) x, ctx);
+  }

   public void endVisit(JsniFieldRef x, Context ctx) {
     /* NOTE: Skip JFieldRef */
@@ -436,6 +442,10 @@
   public void endVisit(JsonPropInit x, Context ctx) {
     endVisit((JNode) x, ctx);
   }
+
+  public void endVisit(JsQueryType x, Context ctx) {
+    endVisit((JIntLiteral) x, ctx);
+  }

   public void endVisit(JStatement x, Context ctx) {
     endVisit((JNode) x, ctx);
@@ -722,6 +732,10 @@
   public boolean visit(JReturnStatement x, Context ctx) {
     return visit((JStatement) x, ctx);
   }
+
+  public boolean visit(JsCastMap x, Context ctx) {
+    return visit((JsonArray) x, ctx);
+  }

   public boolean visit(JsniFieldRef x, Context ctx) {
     /* NOTE: Skip JFieldRef */
@@ -748,6 +762,10 @@
   public boolean visit(JsonPropInit x, Context ctx) {
     return visit((JNode) x, ctx);
   }
+
+  public boolean visit(JsQueryType x, Context ctx) {
+    return visit((JIntLiteral) x, ctx);
+  }

   public boolean visit(JStatement x, Context ctx) {
     return visit((JNode) x, ctx);
=======================================
--- /trunk/dev/core/src/com/google/gwt/dev/jjs/ast/js/JsonArray.java Tue Mar 9 10:54:56 2010 +++ /trunk/dev/core/src/com/google/gwt/dev/jjs/ast/js/JsonArray.java Tue May 17 07:35:44 2011
@@ -19,7 +19,6 @@
 import com.google.gwt.dev.jjs.ast.Context;
 import com.google.gwt.dev.jjs.ast.JClassType;
 import com.google.gwt.dev.jjs.ast.JExpression;
-import com.google.gwt.dev.jjs.ast.JType;
 import com.google.gwt.dev.jjs.ast.JVisitor;

 import java.util.ArrayList;
@@ -30,7 +29,7 @@
  */
 public class JsonArray extends JExpression {

-  public List<JExpression> exprs = new ArrayList<JExpression>();
+  private final List<JExpression> exprs = new ArrayList<JExpression>();

   private final JClassType jsoType;

@@ -39,13 +38,17 @@
     this.jsoType = jsoType;
   }

-  public JType getType() {
+  public List<JExpression> getExprs() {
+    return exprs;
+  }
+
+  public JClassType getType() {
     return jsoType;
   }

   @Override
   public boolean hasSideEffects() {
-    for (int i = 0, c = exprs.size(); i < c; ++i) {
+    for (int i = 0, c = getExprs().size(); i < c; ++i) {
       if (exprs.get(i).hasSideEffects()) {
         return true;
       }
=======================================
--- /trunk/dev/core/src/com/google/gwt/dev/jjs/impl/ArrayNormalizer.java Tue Apr 19 10:10:18 2011 +++ /trunk/dev/core/src/com/google/gwt/dev/jjs/impl/ArrayNormalizer.java Tue May 17 07:35:44 2011
@@ -34,6 +34,8 @@
 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.js.JsCastMap;
+import com.google.gwt.dev.jjs.ast.js.JsCastMap.JsQueryType;
 import com.google.gwt.dev.jjs.ast.js.JsonArray;
 import com.google.gwt.dev.jjs.ast.js.JsonObject;

@@ -95,6 +97,25 @@
         }
       }
     }
+
+ private JsQueryType getElementQueryType(SourceInfo sourceInfo, JArrayType arrayType) {
+      JType elementType = arrayType.getElementType();
+      int elementQueryId = -1;
+      if (elementType instanceof JReferenceType) {
+        JReferenceType elementRefType = (JReferenceType) elementType;
+        elementType = elementRefType.getUnderlyingType();
+        elementQueryId = program.getQueryId(elementRefType);
+      }
+      return new JsQueryType(sourceInfo, elementType, elementQueryId);
+    }
+
+ private JExpression getOrCreateCastMap(SourceInfo sourceInfo, JArrayType arrayType) {
+      JsCastMap castableTypeMap = program.getCastMap(arrayType);
+ if (castableTypeMap == null || castableTypeMap.getExprs().size() == 0) {
+        return new JsonObject(sourceInfo, program.getJavaScriptObject());
+      }
+      return castableTypeMap;
+    }

     /**
      * @see com.google.gwt.lang.Array regarding seed types
@@ -118,10 +139,11 @@

private void processDim(JNewArray x, Context ctx, JArrayType arrayType) {
       // override the type of the called method with the array's type
- JMethodCall call = new JMethodCall(x.getSourceInfo(), null, initDim, arrayType);
+      SourceInfo sourceInfo = x.getSourceInfo();
+ JMethodCall call = new JMethodCall(sourceInfo, null, initDim, arrayType);
       JLiteral classLit = x.getClassLiteral();
-      JsonObject castableTypeMap = program.getCastableTypeMap(arrayType);
- JLiteral queryIdLit = program.getLiteralInt(tryGetQueryId(arrayType)); + JExpression castableTypeMap = getOrCreateCastMap(sourceInfo, arrayType);
+      JLiteral queryIdLit = getElementQueryType(sourceInfo, arrayType);
       JExpression dim = x.dims.get(0);
       JType elementType = arrayType.getElementType();
call.addArgs(classLit, castableTypeMap, queryIdLit, dim, getSeedTypeLiteralFor(elementType));
@@ -142,15 +164,15 @@
         JArrayType curArrayType = (JArrayType) cur;

         JLiteral classLit = x.getClassLiterals().get(i);
-        classLitList.exprs.add(classLit);
-
- JsonObject castableTypeMap = program.getCastableTypeMap(curArrayType);
-        castableTypeMapList.exprs.add(castableTypeMap);
-
- JLiteral queryIdLit = program.getLiteralInt(tryGetQueryId(curArrayType));
-        queryIdList.exprs.add(queryIdLit);
-
-        dimList.exprs.add(x.dims.get(i));
+        classLitList.getExprs().add(classLit);
+
+ JExpression castableTypeMap = getOrCreateCastMap(sourceInfo, curArrayType);
+        castableTypeMapList.getExprs().add(castableTypeMap);
+
+ JLiteral queryIdLit = getElementQueryType(sourceInfo, curArrayType);
+        queryIdList.getExprs().add(queryIdLit);
+
+        dimList.getExprs().add(x.dims.get(i));
         cur = curArrayType.getElementType();
       }
call.addArgs(classLitList, castableTypeMapList, queryIdList, dimList, program
@@ -163,24 +185,15 @@
       SourceInfo sourceInfo = x.getSourceInfo();
JMethodCall call = new JMethodCall(sourceInfo, null, initValues, arrayType);
       JLiteral classLit = x.getClassLiteral();
-      JsonObject castableTypeMap = program.getCastableTypeMap(arrayType);
- JLiteral queryIdLit = program.getLiteralInt(tryGetQueryId(arrayType)); + JExpression castableTypeMap = getOrCreateCastMap(sourceInfo, arrayType);
+      JLiteral queryIdLit = getElementQueryType(sourceInfo, arrayType);
JsonArray initList = new JsonArray(sourceInfo, program.getJavaScriptObject());
       for (int i = 0; i < x.initializers.size(); ++i) {
-        initList.exprs.add(x.initializers.get(i));
+        initList.getExprs().add(x.initializers.get(i));
       }
       call.addArgs(classLit, castableTypeMap, queryIdLit, initList);
       ctx.replaceMe(call);
     }
-
-    private int tryGetQueryId(JArrayType type) {
-      JType elementType = type.getElementType();
-      int leafQueryId = -1;
-      if (elementType instanceof JReferenceType) {
- leafQueryId = program.getQueryId(((JReferenceType) elementType).getUnderlyingType());
-      }
-      return leafQueryId;
-    }
   }

   public static void exec(JProgram program) {
=======================================
--- /trunk/dev/core/src/com/google/gwt/dev/jjs/impl/CastNormalizer.java Thu Apr 28 15:00:16 2011 +++ /trunk/dev/core/src/com/google/gwt/dev/jjs/impl/CastNormalizer.java Tue May 17 07:35:44 2011
@@ -16,6 +16,7 @@
 package com.google.gwt.dev.jjs.impl;

 import com.google.gwt.dev.jjs.SourceInfo;
+import com.google.gwt.dev.jjs.SourceOrigin;
 import com.google.gwt.dev.jjs.ast.Context;
 import com.google.gwt.dev.jjs.ast.JArrayRef;
 import com.google.gwt.dev.jjs.ast.JArrayType;
@@ -26,7 +27,6 @@
 import com.google.gwt.dev.jjs.ast.JClassType;
 import com.google.gwt.dev.jjs.ast.JExpression;
 import com.google.gwt.dev.jjs.ast.JInstanceOf;
-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;
@@ -38,15 +38,20 @@
 import com.google.gwt.dev.jjs.ast.JType;
 import com.google.gwt.dev.jjs.ast.JTypeOracle;
 import com.google.gwt.dev.jjs.ast.JVisitor;
-import com.google.gwt.dev.jjs.ast.js.JsonObject;
-import com.google.gwt.dev.jjs.ast.js.JsonObject.JsonPropInit;
+import com.google.gwt.dev.jjs.ast.js.JsCastMap;
+import com.google.gwt.dev.jjs.ast.js.JsCastMap.JsQueryType;
+import com.google.gwt.dev.util.collect.Lists;

 import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Comparator;
 import java.util.HashSet;
 import java.util.IdentityHashMap;
+import java.util.LinkedHashSet;
 import java.util.List;
 import java.util.Map;
 import java.util.Set;
+import java.util.TreeSet;

 /**
* Replace cast and instanceof operations with calls to the Cast class. Depends
@@ -68,11 +73,10 @@
 public class CastNormalizer {
   private class AssignTypeCastabilityVisitor extends JVisitor {

-    Set<JReferenceType> alreadyRan = new HashSet<JReferenceType>();
- private final IdentityHashMap<JReferenceType, JsonObject> castableTypeMaps =
-        new IdentityHashMap<JReferenceType, JsonObject>();
+ private final Set<JReferenceType> alreadyRan = new HashSet<JReferenceType>(); + private final IdentityHashMap<JReferenceType, JsCastMap> castableTypesMap =
+        new IdentityHashMap<JReferenceType, JsCastMap>();
private final List<JArrayType> instantiatedArrayTypes = new ArrayList<JArrayType>();
-    private int nextQueryId = 0;
     private final Map<JReferenceType, Set<JReferenceType>> queriedTypes =
         new IdentityHashMap<JReferenceType, Set<JReferenceType>>();

@@ -84,20 +88,18 @@
         }
       }

- // Reserve query id 0 for java.lang.Object (for array stores on JSOs).
+      // Force entries for Object and String.
recordCastInternal(program.getTypeJavaLangObject(), program.getTypeJavaLangObject());
-
- // Reserve query id 1 for java.lang.String to facilitate the mashup case. - // Also, facilitates detecting an object as a Java String (see Cast.java) - // Multiple GWT modules need to modify String's prototype the same way. recordCastInternal(program.getTypeJavaLangString(), program.getTypeJavaLangObject());
     }

     public void computeTypeCastabilityMaps() {
+      List<JReferenceType> sortedQueryTypes = sortQueryTypes();
+      queryIdsByType = assignQueryIds(sortedQueryTypes);

       // do String first (which will pull in Object also, it's superclass).
       computeSourceType(program.getTypeJavaLangString());
-      assert (castableTypeMaps.size() == 2);
+      assert (castableTypesMap.size() == 2);

       /*
        * Compute the list of classes than can successfully satisfy cast
@@ -115,14 +117,9 @@
       }

       // pass our info to JProgram
-      program.initTypeInfo(castableTypeMaps);
-
-      // JSO's marker queryId is -1 (used for array stores).
-      JClassType jsoType = program.getJavaScriptObject();
-      if (jsoType != null) {
-        queryIds.put(jsoType, -1);
-      }
-      program.recordQueryIds(queryIds);
+      program.initTypeInfo(castableTypesMap);
+
+      program.recordQueryIds(queryIdsByType, sortedQueryTypes);
     }

     /*
@@ -188,6 +185,20 @@
       assert (x.getTestType() != program.getTypeNull());
       recordCast(x.getTestType(), x.getExpr());
     }
+
+ private Map<JReferenceType, Integer> assignQueryIds(List<JReferenceType> sortedQueryTypes) { + Map<JReferenceType, Integer> result = new IdentityHashMap<JReferenceType, Integer>();
+      int queryId = 0;
+      for (JReferenceType queryType : sortedQueryTypes) {
+        result.put(queryType, queryId++);
+      }
+      // JSO's marker queryId is -1 (used for array stores).
+      JClassType jsoType = program.getJavaScriptObject();
+      if (jsoType != null) {
+        result.put(jsoType, -1);
+      }
+      return result;
+    }

private boolean canTriviallyCastJsoSemantics(JReferenceType type, JReferenceType qType) {
       type = type.getUnderlyingType();
@@ -227,10 +238,12 @@
       }

       // Find all possible query types which I can satisfy
-      Set<JReferenceType> yesSet = null;
-
- // NOTE: non-deterministic iteration over HashSet and HashMap. This is
-      // okay here because we're just adding things to another HashSet.
+ Set<JsQueryType> castableTypes = new TreeSet<JsQueryType>(JSQUERY_COMPARATOR);
+
+      /*
+       * NOTE: non-deterministic iteration over HashSet and HashMap. Okay
+       * because we're sorting the results.
+       */
       for (JReferenceType qType : queriedTypes.keySet()) {

         Set<JReferenceType> querySet = queriedTypes.get(qType);
@@ -239,51 +252,31 @@
          * with JSO cross-casts anymore.
          */
         if (canTriviallyCastJsoSemantics(type, qType)) {
-
           for (JReferenceType argType : querySet) {
-
if (canTriviallyCastJsoSemantics(type, argType) || program.isJavaScriptObject(qType)) {
-              if (yesSet == null) {
-                yesSet = new HashSet<JReferenceType>();
-              }
-              yesSet.add(qType);
+              int queryId = queryIdsByType.get(qType);
+              // Ignore Object (id 0) which is always true.
+              if (queryId > 0) {
+ castableTypes.add(new JsQueryType(SourceOrigin.UNKNOWN, qType, queryId));
+              }
               break;
             }
           }
         }
       }
-
-      // Use a sparse array to sort my yes set.
-      JReferenceType[] yesArray = new JReferenceType[nextQueryId];
-      if (yesSet != null) {
-        for (JReferenceType yesType : yesSet) {
-          yesArray[queryIds.get(yesType)] = yesType;
-        }
-      }
-
-      // Create a sparse lookup object.
- SourceInfo sourceInfo = program.createSourceInfoSynthetic(AssignTypeCastabilityVisitor.class); - JsonObject jsonObject = new JsonObject(sourceInfo, program.getJavaScriptObject());
-      // Start at 1; 0 is Object and always true.
-      for (int i = 1; i < nextQueryId; ++i) {
-        if (yesArray[i] != null) {
-          JIntLiteral labelExpr = program.getLiteralInt(i);
-          JIntLiteral valueExpr = program.getLiteralInt(1);
- jsonObject.propInits.add(new JsonPropInit(sourceInfo, labelExpr, valueExpr));
-        }
-      }

       /*
* Don't add an entry for empty answer sets, except for Object and String
        * which require entries.
        */
- if (jsonObject.propInits.isEmpty() && type != program.getTypeJavaLangObject() + if (castableTypes.isEmpty() && type != program.getTypeJavaLangObject()
           && type != program.getTypeJavaLangString()) {
         return;
       }

       // add an entry for me
-      castableTypeMaps.put(type, jsonObject);
+ castableTypesMap.put(type, new JsCastMap(SourceOrigin.UNKNOWN, Lists.create(castableTypes),
+          program.getJavaScriptObject()));
     }

     private void recordCast(JType targetType, JExpression rhs) {
@@ -310,12 +303,35 @@
       rhsType = rhsType.getUnderlyingType();
       Set<JReferenceType> querySet = queriedTypes.get(toType);
       if (querySet == null) {
-        queryIds.put(toType, nextQueryId++);
         querySet = new HashSet<JReferenceType>();
         queriedTypes.put(toType, querySet);
       }
       querySet.add(rhsType);
     }
+
+    /**
+ * Sort into alphabetical, except Object and String which must come first.
+     */
+    private List<JReferenceType> sortQueryTypes() {
+      // Initial name-only sort.
+ List<JReferenceType> sortedQueryTypes = new ArrayList<JReferenceType>(queriedTypes.keySet());
+      Collections.sort(sortedQueryTypes, new HasNameSort());
+
+      // Used LinkedHashSet to move Object and String to the front.
+ LinkedHashSet<JReferenceType> tempSortedQueryTypes = new LinkedHashSet<JReferenceType>(); + // Reserve query id 0 for java.lang.Object (for array stores on JSOs).
+      tempSortedQueryTypes.add(program.getTypeJavaLangObject());
+      /*
+ * Reserve query id 1 for java.lang.String to facilitate the mashup case. + * Also, facilitates detecting an object as a Java String (see Cast.java) + * Multiple GWT modules need to modify String's prototype the same way.
+       */
+      tempSortedQueryTypes.add(program.getTypeJavaLangString());
+      // Add the rest.
+      tempSortedQueryTypes.addAll(sortedQueryTypes);
+ sortedQueryTypes = new ArrayList<JReferenceType>(tempSortedQueryTypes);
+      return sortedQueryTypes;
+    }
   }

   /**
@@ -413,6 +429,7 @@
         // Just leave the cast in, GenerateJavaScriptAST will ignore it.
         return;
       }
+      SourceInfo info = x.getSourceInfo();
       if (toType instanceof JNullType) {
         /*
* Magic: a null type cast means the user tried a cast that couldn't
@@ -425,7 +442,7 @@
         /*
          * Override the type of the magic method with the null type.
          */
- JMethodCall call = new JMethodCall(x.getSourceInfo(), null, method, toType);
+        JMethodCall call = new JMethodCall(info, null, method, toType);
         call.addArg(expr);
         replaceExpr = call;
       } else if (toType instanceof JReferenceType) {
@@ -438,7 +455,6 @@
           // just remove the cast
           replaceExpr = curExpr;
         } else {
-
           JMethod method;
boolean isJsoCast = program.typeOracle.isEffectivelyJavaScriptObject(refType);
           if (isJsoCast) {
@@ -452,11 +468,10 @@
             method = program.getIndexedMethod("Cast.dynamicCast");
           }
// override the type of the called method with the target cast type - JMethodCall call = new JMethodCall(x.getSourceInfo(), null, method, toType);
+          JMethodCall call = new JMethodCall(info, null, method, toType);
           call.addArg(curExpr);
           if (!isJsoCast) {
-            JIntLiteral qId = program.getLiteralInt(queryIds.get(refType));
-            call.addArg(qId);
+ call.addArg(new JsQueryType(info, refType, queryIdsByType.get(refType)));
           }
           replaceExpr = call;
         }
@@ -485,7 +500,7 @@
              * do the narrowing conversion.
              */
             JMethod castMethod = program.getIndexedMethod("LongLib.toInt");
- JMethodCall call = new JMethodCall(x.getSourceInfo(), null, castMethod);
+            JMethodCall call = new JMethodCall(info, null, castMethod);
             call.addArg(expr);
             expr = call;
             fromType = tInt;
@@ -527,7 +542,7 @@

         if (methodName != null) {
           JMethod castMethod = program.getIndexedMethod(methodName);
- JMethodCall call = new JMethodCall(x.getSourceInfo(), null, castMethod, toType); + JMethodCall call = new JMethodCall(info, null, castMethod, toType);
           call.addArg(expr);
           replaceExpr = call;
         } else {
@@ -568,14 +583,20 @@
JMethodCall call = new JMethodCall(x.getSourceInfo(), null, method);
         call.addArg(x.getExpr());
         if (!isJsoCast) {
-          JIntLiteral qId = program.getLiteralInt(queryIds.get(toType));
-          call.addArg(qId);
+ call.addArg(new JsQueryType(x.getSourceInfo(), toType, queryIdsByType.get(toType)));
         }
         ctx.replaceMe(call);
       }
     }
   }

+ private static final Comparator<JsQueryType> JSQUERY_COMPARATOR = new Comparator<JsQueryType>() {
+    @Override
+    public int compare(JsQueryType o1, JsQueryType o2) {
+      return o1.getQueryId() - o2.getQueryId();
+    }
+  };
+
   public static void exec(JProgram program, boolean disableCastChecking) {
     new CastNormalizer(program, disableCastChecking).execImpl();
   }
@@ -584,8 +605,7 @@

   private final JProgram program;

-  private final Map<JReferenceType, Integer> queryIds =
-      new IdentityHashMap<JReferenceType, Integer>();
+  private Map<JReferenceType, Integer> queryIdsByType;

   private CastNormalizer(JProgram program, boolean disableCastChecking) {
     this.program = program;
=======================================
--- /trunk/dev/core/src/com/google/gwt/dev/jjs/impl/GenerateJavaScriptAST.java Tue May 17 05:22:26 2011 +++ /trunk/dev/core/src/com/google/gwt/dev/jjs/impl/GenerateJavaScriptAST.java Tue May 17 07:35:44 2011
@@ -23,6 +23,7 @@
 import com.google.gwt.dev.jjs.InternalCompilerException;
 import com.google.gwt.dev.jjs.JsOutputOption;
 import com.google.gwt.dev.jjs.SourceInfo;
+import com.google.gwt.dev.jjs.SourceOrigin;
 import com.google.gwt.dev.jjs.ast.Context;
 import com.google.gwt.dev.jjs.ast.HasEnclosingType;
 import com.google.gwt.dev.jjs.ast.HasName;
@@ -46,6 +47,7 @@
 import com.google.gwt.dev.jjs.ast.JDeclarationStatement;
 import com.google.gwt.dev.jjs.ast.JDeclaredType;
 import com.google.gwt.dev.jjs.ast.JDoStatement;
+import com.google.gwt.dev.jjs.ast.JExpression;
 import com.google.gwt.dev.jjs.ast.JExpressionStatement;
 import com.google.gwt.dev.jjs.ast.JField;
 import com.google.gwt.dev.jjs.ast.JFieldRef;
@@ -86,6 +88,8 @@
 import com.google.gwt.dev.jjs.ast.JVisitor;
 import com.google.gwt.dev.jjs.ast.JWhileStatement;
 import com.google.gwt.dev.jjs.ast.js.JMultiExpression;
+import com.google.gwt.dev.jjs.ast.js.JsCastMap;
+import com.google.gwt.dev.jjs.ast.js.JsCastMap.JsQueryType;
 import com.google.gwt.dev.jjs.ast.js.JsniClassLiteral;
 import com.google.gwt.dev.jjs.ast.js.JsniFieldRef;
 import com.google.gwt.dev.jjs.ast.js.JsniMethodBody;
@@ -93,6 +97,7 @@
 import com.google.gwt.dev.jjs.ast.js.JsonArray;
 import com.google.gwt.dev.jjs.ast.js.JsonObject;
 import com.google.gwt.dev.jjs.ast.js.JsonObject.JsonPropInit;
+import com.google.gwt.dev.js.JsParser;
 import com.google.gwt.dev.js.JsStackEmulator;
 import com.google.gwt.dev.js.ast.JsArrayAccess;
 import com.google.gwt.dev.js.ast.JsArrayLiteral;
@@ -122,6 +127,7 @@
 import com.google.gwt.dev.js.ast.JsNew;
 import com.google.gwt.dev.js.ast.JsNode;
 import com.google.gwt.dev.js.ast.JsNormalScope;
+import com.google.gwt.dev.js.ast.JsNumberLiteral;
 import com.google.gwt.dev.js.ast.JsObjectLiteral;
 import com.google.gwt.dev.js.ast.JsParameter;
 import com.google.gwt.dev.js.ast.JsPostfixOperation;
@@ -146,6 +152,7 @@
 import com.google.gwt.dev.util.collect.IdentityHashSet;
 import com.google.gwt.dev.util.collect.Maps;

+import java.io.StringReader;
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Collections;
@@ -256,14 +263,19 @@
       /*
* put nullMethod in the global scope, too; it's the replacer for clinits
        */
-      nullMethodName = topScope.declareName(nullMethod.getName());
-      names.put(nullMethod, nullMethodName);
+ nullFunc = createGlobalFunction("function " + nullMethod.getName() + "(){}");
+      names.put(nullMethod, nullFunc.getName());

       /*
        * Make sure we record all of the program's array types since
        * JProgram.traverse() doesn't iterate over them.
        */
       accept(program.getAllArrayTypes());
+
+      // Generate symbolic names for all query type ids.
+      if (!output.shouldMinimize()) {
+        setupSymbolicCastMaps();
+      }
     }

     @Override
@@ -344,6 +356,10 @@
       assert x.getEnclosingType() != null;
       String mangleName = mangleNameForGlobal(x);

+      if (JProgram.isClinit(x)) {
+        name = name + "_" + x.getEnclosingType().getShortName();
+      }
+
       /*
* Only allocate a name for a function if it is native, not polymorphic,
        * or stack-stripping is disabled.
@@ -410,6 +426,20 @@
       }
       return false;
     }
+
+    private JsFunction createGlobalFunction(String code) {
+      try {
+        List<JsStatement> stmts =
+ JsParser.parse(SourceOrigin.UNKNOWN, topScope, new StringReader(code));
+        assert stmts.size() == 1;
+        JsExprStmt stmt = (JsExprStmt) stmts.get(0);
+ List<JsStatement> globalStmts = jsProgram.getGlobalBlock().getStatements();
+        globalStmts.add(0, stmt);
+        return (JsFunction) stmt.getExpression();
+      } catch (Exception e) {
+ throw new InternalCompilerException("Unexpected exception parsing '" + code + "'", e);
+      }
+    }

     /**
      * Generate a file name URI string for a source info, for symbol data
@@ -441,13 +471,28 @@
     }

     private void recordSymbol(JReferenceType x, JsName jsName) {
-      int queryId = program.getQueryId(x);
-      JsonObject castableTypeMapObj = program.getCastableTypeMap(x);
- CastableTypeMap castableTypeMap = new StandardCastableTypeMap(castableTypeMapObj.toString());
+      StringBuilder sb = new StringBuilder();
+      sb.append('{');
+      JsCastMap castMap = program.getCastMap(x);
+      if (castMap != null) {
+        boolean isFirst = true;
+        for (JExpression expr : castMap.getExprs()) {
+          JsQueryType queryType = (JsQueryType) expr;
+          if (isFirst) {
+            isFirst = false;
+          } else {
+            sb.append(',');
+          }
+          sb.append(queryType.getQueryId());
+          sb.append(":1");
+        }
+      }
+      sb.append('}');
+ CastableTypeMap castableTypeMap = new StandardCastableTypeMap(sb.toString());

       StandardSymbolData symbolData =
StandardSymbolData.forClass(x.getName(), x.getSourceInfo().getFileName(), x
-              .getSourceInfo().getStartLine(), queryId, castableTypeMap);
+ .getSourceInfo().getStartLine(), program.getQueryId(x), castableTypeMap);
       assert !symbolTable.containsKey(symbolData);
       symbolTable.put(symbolData, jsName);
     }
@@ -489,6 +534,43 @@
+ jsName.getIdent() + " for " + x.getName() + " and key " + symbolData.getJsniIdent();
       symbolTable.put(symbolData, jsName);
     }
+
+    /**
+ * Create more readable output by generating symbolic constants for query
+     * ids.
+     */
+    private void setupSymbolicCastMaps() {
+      namesByQueryId = new ArrayList<JsName>();
+      for (JReferenceType type : program.getTypesByQueryId()) {
+        String shortName;
+        String longName;
+        if (type instanceof JArrayType) {
+          JArrayType arrayType = (JArrayType) type;
+          JType leafType = arrayType.getLeafType();
+          if (leafType instanceof JReferenceType) {
+            shortName = ((JReferenceType) leafType).getShortName();
+          } else {
+            shortName = leafType.getName();
+          }
+          shortName += "_$" + arrayType.getDims();
+          longName = getNameString(leafType) + "_$" + arrayType.getDims();
+        } else {
+          shortName = type.getShortName();
+          longName = getNameString(type);
+        }
+ JsName name = topScope.declareName("Q$" + longName, "Q$" + shortName);
+        namesByQueryId.add(name);
+      }
+      StringBuilder sb = new StringBuilder();
+      sb.append("function makeCastMap(a) {");
+      sb.append("  var result = {};");
+      sb.append("  for (var i = 0, c = a.length; i < c; ++i) {");
+      sb.append("    result[a[i]] = 1;");
+      sb.append("  }");
+      sb.append("  return result;");
+      sb.append("}");
+      makeMapFunction = createGlobalFunction(sb.toString());
+    }
   }

private class GenerateJavaScriptVisitor extends GenerateJavaScriptLiterals {
@@ -1133,7 +1215,6 @@

       // Generate entry methods
generateGwtOnLoad(Arrays.asList(entryFunctions).subList(0, x.getEntryCount(0)), globalStmts);
-      generateNullFunc(globalStmts);

       // Add a few things onto the beginning.

@@ -1145,6 +1226,8 @@
// Long lits must go at the top, they can be constant field initializers.
       generateLongLiterals(vars);

+      generateQueryIdConstants(vars);
+
       // Class objects, but only if there are any.
       if (x.getDeclaredTypes().contains(x.getTypeClassLiteralHolder())) {
         // TODO: perhaps they could be constant field initializers also?
@@ -1193,6 +1276,30 @@
         push(new JsReturn(x.getSourceInfo()));
       }
     }
+
+    @Override
+    public void endVisit(JsCastMap x, Context ctx) {
+      super.endVisit(x, ctx);
+      JsArrayLiteral arrayLit = (JsArrayLiteral) pop();
+      SourceInfo sourceInfo = x.getSourceInfo();
+      if (namesByQueryId == null || x.getExprs().size() == 0) {
+        // {2:1, 4:1, 12:1};
+        JsObjectLiteral objLit = new JsObjectLiteral(sourceInfo);
+ List<JsPropertyInitializer> props = objLit.getPropertyInitializers();
+        JsNumberLiteral one = new JsNumberLiteral(sourceInfo, 1);
+        for (JsExpression expr : arrayLit.getExpressions()) {
+ JsPropertyInitializer prop = new JsPropertyInitializer(sourceInfo, expr, one);
+          props.add(prop);
+        }
+        push(objLit);
+      } else {
+        // makeMap([Q_Object, Q_Foo, Q_Bar]);
+        JsInvocation inv = new JsInvocation(sourceInfo);
+        inv.setQualifier(makeMapFunction.getName().makeRef(sourceInfo));
+        inv.getArguments().add(arrayLit);
+        push(inv);
+      }
+    }

     @Override
     public void endVisit(JsniMethodRef x, Context ctx) {
@@ -1204,7 +1311,7 @@
     @Override
     public void endVisit(JsonArray x, Context ctx) {
JsArrayLiteral jsArrayLiteral = new JsArrayLiteral(x.getSourceInfo());
-      popList(jsArrayLiteral.getExpressions(), x.exprs.size());
+      popList(jsArrayLiteral.getExpressions(), x.getExprs().size());
       push(jsArrayLiteral);
     }

@@ -1221,6 +1328,16 @@
       JsExpression labelExpr = (JsExpression) pop();
push(new JsPropertyInitializer(init.getSourceInfo(), labelExpr, valueExpr));
     }
+
+    @Override
+    public void endVisit(JsQueryType x, Context ctx) {
+      if (namesByQueryId == null || x.getQueryId() < 0) {
+        super.endVisit(x, ctx);
+      } else {
+        JsName name = namesByQueryId.get(x.getQueryId());
+        push(name.makeRef(x.getSourceInfo()));
+      }
+    }

     @Override
     public void endVisit(JThisRef x, Context ctx) {
@@ -1413,7 +1530,7 @@
                 if (jsName == null) {
// this can occur when JSNI references an instance method on a
                   // type that was never actually instantiated.
-                  jsName = nullMethodName;
+                  jsName = nullFunc.getName();
                 }
                 x.resolve(jsName);
               }
@@ -1491,26 +1608,22 @@
     }

private void generateCastableTypeMap(JClassType x, List<JsStatement> globalStmts) {
-      JsonObject castableTypeMap = program.getCastableTypeMap(x);
-      if (castableTypeMap != null) {
+      JsCastMap castMap = program.getCastMap(x);
+      if (castMap != null) {
JField castableTypeMapField = program.getIndexedField("Object.castableTypeMap");
         JsName castableTypeMapName = names.get(castableTypeMapField);
         if (castableTypeMapName == null) {
           // Was pruned; this compilation must have no dynamic casts.
           return;
         }
-
- SourceInfo sourceInfo = jsProgram.createSourceInfoSynthetic(GenerateJavaScriptAST.class);
-
-        accept(castableTypeMap);
-        JsExpression objExpr = pop();

         // Generate castableTypeMap for each type prototype
-        // _.castableTypeMap$ = {2:1, 4:1, 12:1};
+        // _.castableTypeMap$ = ...
+ SourceInfo sourceInfo = jsProgram.createSourceInfoSynthetic(GenerateJavaScriptAST.class);
         JsNameRef fieldRef = castableTypeMapName.makeRef(sourceInfo);
         fieldRef.setQualifier(globalTemp.makeRef(sourceInfo));
-        JsExpression asg = createAssignment(fieldRef, objExpr);
-
+        accept(castMap);
+ JsExpression asg = createAssignment(fieldRef, (JsExpression) pop());
         JsExprStmt asgStmt = asg.makeStmt();
         globalStmts.add(asgStmt);
         typeForStatMap.put(asgStmt, x);
@@ -1662,13 +1775,16 @@
       }
     }

-    private void generateNullFunc(List<JsStatement> globalStatements) {
-      // handle null method
- SourceInfo sourceInfo = jsProgram.createSourceInfoSynthetic(GenerateJavaScriptAST.class); - JsFunction nullFunc = new JsFunction(sourceInfo, topScope, nullMethodName, true);
-      nullFunc.setBody(new JsBlock(sourceInfo));
-      // Add it first, so that script-tag chunking in IFrameLinker works
-      globalStatements.add(0, nullFunc.makeStmt());
+    private void generateQueryIdConstants(JsVars vars) {
+      if (namesByQueryId != null) {
+        SourceInfo info = vars.getSourceInfo();
+        int id = 0;
+        for (JsName jsName : namesByQueryId) {
+          JsVar var = new JsVar(info, jsName);
+          var.setInitExpr(new JsNumberLiteral(info, id++));
+          vars.add(var);
+        }
+      }
     }

private void generateSeedFuncAndPrototype(JClassType x, List<JsStatement> globalStmts) {
@@ -1770,7 +1886,7 @@
SourceInfo sourceInfo = jsProgram.createSourceInfoSynthetic(GenerateJavaScriptAST.class);
       JsNameRef fieldRef = typeMarkerName.makeRef(sourceInfo);
       fieldRef.setQualifier(globalTemp.makeRef(sourceInfo));
- JsExpression asg = createAssignment(fieldRef, nullMethodName.makeRef(sourceInfo)); + JsExpression asg = createAssignment(fieldRef, nullFunc.getName().makeRef(sourceInfo));
       JsExprStmt stmt = asg.makeStmt();
       globalStmts.add(stmt);
       typeForStatMap.put(stmt, program.getTypeJavaLangObject());
@@ -1802,8 +1918,8 @@
       SourceInfo sourceInfo = clinitFunc.getSourceInfo();
       // self-assign to the null method immediately (to prevent reentrancy)
       JsExpression asg =
- createAssignment(clinitFunc.getName().makeRef(sourceInfo), nullMethodName
-              .makeRef(sourceInfo));
+ createAssignment(clinitFunc.getName().makeRef(sourceInfo), nullFunc.getName().makeRef(
+              sourceInfo));
       statements.add(0, asg.makeStmt());
     }

@@ -2017,11 +2133,14 @@
    * Sorted to avoid nondeterministic iteration.
    */
   private final Map<Long, JsName> longLits = new TreeMap<Long, JsName>();
+
private final Map<JsName, JsExpression> longObjects = new IdentityHashMap<JsName, JsExpression>();
+  private JsFunction makeMapFunction;
   private final Map<JAbstractMethodBody, JsFunction> methodBodyMap =
       new IdentityHashMap<JAbstractMethodBody, JsFunction>();
private final Map<HasName, JsName> names = new IdentityHashMap<HasName, JsName>();
-  private JsName nullMethodName;
+  private List<JsName> namesByQueryId;
+  private JsFunction nullFunc;

   /**
* Contains JsNames for the Object instance methods, such as equals, hashCode,
=======================================
--- /trunk/dev/core/src/com/google/gwt/dev/jjs/impl/ToStringGenerationVisitor.java Wed Apr 27 14:46:52 2011 +++ /trunk/dev/core/src/com/google/gwt/dev/jjs/impl/ToStringGenerationVisitor.java Tue May 17 07:35:44 2011
@@ -90,6 +90,7 @@
 import com.google.gwt.dev.jjs.ast.js.JsniMethodRef;
 import com.google.gwt.dev.jjs.ast.js.JsonArray;
 import com.google.gwt.dev.jjs.ast.js.JsonObject;
+import com.google.gwt.dev.jjs.ast.js.JsCastMap.JsQueryType;
 import com.google.gwt.dev.jjs.ast.js.JsonObject.JsonPropInit;
 import com.google.gwt.dev.js.JsSourceGenerationVisitor;
 import com.google.gwt.dev.util.TextOutput;
@@ -574,7 +575,7 @@

   @Override
   public boolean visit(JIntLiteral x, Context ctx) {
-    print(Integer.toString(x.getValue()).toCharArray());
+    print(Integer.toString(x.getValue()));
     return false;
   }

@@ -681,6 +682,14 @@
     printStringLiteral(x.getNode().getName());
     return false;
   }
+
+  @Override
+  public boolean visit(JsQueryType x, Context ctx) {
+    print(CHARS_SLASHSTAR);
+    printTypeName(x.getQueryType());
+    print(CHARS_STARSLASH);
+    return super.visit(x, ctx);
+  }

   @Override
   public boolean visit(JNewArray x, Context ctx) {
@@ -816,7 +825,7 @@
   @Override
   public boolean visit(JsonArray x, Context ctx) {
     print('[');
-    visitCollectionWithCommas(x.exprs.iterator());
+    visitCollectionWithCommas(x.getExprs().iterator());
     print(']');
     return false;
   }

--
http://groups.google.com/group/Google-Web-Toolkit-Contributors

Reply via email to