Decentralize JNonNullType from JProgram.

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

Review by: cromwellian@google.com

git-svn-id: https://google-web-toolkit.googlecode.com/svn/trunk@9593 8db76d5a-ed1c-0410-87a9-c151d255dfc7
diff --git a/dev/core/src/com/google/gwt/dev/jjs/EnumNameObfuscator.java b/dev/core/src/com/google/gwt/dev/jjs/EnumNameObfuscator.java
index 8cb26c2..147d5d8 100644
--- a/dev/core/src/com/google/gwt/dev/jjs/EnumNameObfuscator.java
+++ b/dev/core/src/com/google/gwt/dev/jjs/EnumNameObfuscator.java
@@ -22,7 +22,6 @@
 import com.google.gwt.dev.jjs.ast.JMethod;
 import com.google.gwt.dev.jjs.ast.JMethodCall;
 import com.google.gwt.dev.jjs.ast.JModVisitor;
-import com.google.gwt.dev.jjs.ast.JNonNullType;
 import com.google.gwt.dev.jjs.ast.JParameter;
 import com.google.gwt.dev.jjs.ast.JProgram;
 import com.google.gwt.dev.jjs.ast.JReturnStatement;
@@ -135,12 +134,12 @@
     private final TreeLogger logger;
     private final JProgram jprogram;
     private final JMethod enumObfuscatedName;
-    private final JNonNullType enumType;
+    private final JClassType enumType;
 
     public EnumNameReplacer(JProgram jprogram, TreeLogger logger) {
       this.logger = logger;
       this.jprogram = jprogram;
-      this.enumType = jprogram.getNonNullType(jprogram.getIndexedType("Enum"));
+      this.enumType = (JClassType) jprogram.getIndexedType("Enum");
       this.enumObfuscatedName = jprogram.getIndexedMethod("Enum.obfuscatedName");
     }
 
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 5df5e87..3a206fb 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
@@ -45,7 +45,7 @@
       classLiterals.add(classLit);
       cur = ((JArrayType) cur).getElementType();
     }
-    return new JNewArray(info, program.getNonNullType(arrayType), dims, null,
+    return new JNewArray(info, arrayType.getNonNull(), dims, null,
         classLiterals);
   }
 
@@ -53,8 +53,8 @@
       JArrayType arrayType, List<JExpression> initializers) {
     List<JClassLiteral> classLiterals = new ArrayList<JClassLiteral>();
     classLiterals.add(program.getLiteralClass(arrayType));
-    return new JNewArray(info, program.getNonNullType(arrayType), null,
-        initializers, classLiterals);
+    return new JNewArray(info, arrayType.getNonNull(), null, initializers,
+        classLiterals);
   }
 
   public final List<JExpression> dims;
diff --git a/dev/core/src/com/google/gwt/dev/jjs/ast/JNonNullType.java b/dev/core/src/com/google/gwt/dev/jjs/ast/JNonNullType.java
index 05edfed..5357e41 100644
--- a/dev/core/src/com/google/gwt/dev/jjs/ast/JNonNullType.java
+++ b/dev/core/src/com/google/gwt/dev/jjs/ast/JNonNullType.java
@@ -40,6 +40,11 @@
   }
 
   @Override
+  public JNonNullType getNonNull() {
+    return this;
+  }
+
+  @Override
   public JClassType getSuperClass() {
     return ref.getSuperClass();
   }
@@ -60,4 +65,8 @@
   public void traverse(JVisitor visitor, Context ctx) {
     visitor.accept(ref);
   }
+
+  private Object readResolve() {
+    return ref.getNonNull();
+  }
 }
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 9c0f5b5..a04ed86 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
@@ -321,8 +321,6 @@
 
   private IdentityHashMap<JReferenceType, JsonObject> castableTypeMaps;
 
-  private Map<JReferenceType, JNonNullType> nonNullTypes = new IdentityHashMap<JReferenceType, JNonNullType>();
-
   private JField nullField;
 
   private JMethod nullMethod;
@@ -430,7 +428,7 @@
         typeJavaLangObject = x;
       } else if (name.equals("java.lang.String")) {
         typeString = x;
-        typeNonNullString = getNonNullType(x);
+        typeNonNullString = x.getNonNull();
       } else if (name.equals("java.lang.Enum")) {
         typeJavaLangEnum = x;
       } else if (name.equals("java.lang.Class")) {
@@ -448,7 +446,7 @@
   public JConstructor createConstructor(SourceInfo info,
       JClassType enclosingType) {
     JConstructor x = new JConstructor(info, enclosingType,
-        getNonNullType(enclosingType));
+        enclosingType.getNonNull());
     x.setBody(new JMethodBody(info));
     if (indexedTypes.containsValue(enclosingType)) {
       indexedMethods.put(enclosingType.getShortName() + '.'
@@ -596,7 +594,7 @@
       // Neither can be null.
       type1 = type1.getUnderlyingType();
       type2 = type2.getUnderlyingType();
-      return getNonNullType(generalizeTypes(type1, type2));
+      return generalizeTypes(type1, type2).getNonNull();
     } else if (type1 instanceof JNonNullType) {
       // type2 can be null, so the result can be null
       type1 = type1.getUnderlyingType();
@@ -797,10 +795,6 @@
     return entryMethods.get(fragment).size();
   }
 
-  public JThisRef getExprThisRef(SourceInfo info, JClassType enclosingType) {
-    return new JThisRef(info, getNonNullType(enclosingType));
-  }
-
   public int getFragmentCount() {
     return entryMethods.size();
   }
@@ -949,18 +943,6 @@
     return toReturn;
   }
 
-  public JNonNullType getNonNullType(JReferenceType type) {
-    if (type instanceof JNonNullType) {
-      return (JNonNullType) type;
-    }
-    JNonNullType nonNullType = nonNullTypes.get(type);
-    if (nonNullType == null) {
-      nonNullType = new JNonNullType(type);
-      nonNullTypes.put(type, nonNullType);
-    }
-    return nonNullType;
-  }
-
   public JField getNullField() {
     if (nullField == null) {
       nullField = new JField(createSourceInfoSynthetic(JProgram.class,
@@ -1247,7 +1229,7 @@
 
     if (type1 instanceof JNonNullType != type2 instanceof JNonNullType) {
       // If either is non-nullable, the result should be non-nullable.
-      return strongerType(getNonNullType(type1), getNonNullType(type2));
+      return strongerType(type1.getNonNull(), type2.getNonNull());
     }
 
     if (typeOracle.canTriviallyCast(type1, type2)) {
diff --git a/dev/core/src/com/google/gwt/dev/jjs/ast/JReferenceType.java b/dev/core/src/com/google/gwt/dev/jjs/ast/JReferenceType.java
index 4fc8dea..d7954fa 100644
--- a/dev/core/src/com/google/gwt/dev/jjs/ast/JReferenceType.java
+++ b/dev/core/src/com/google/gwt/dev/jjs/ast/JReferenceType.java
@@ -22,6 +22,8 @@
  */
 public abstract class JReferenceType extends JType implements CanBeAbstract {
 
+  private transient JNonNullType nonNullType;
+
   public JReferenceType(SourceInfo info, String name) {
     super(info, name, JNullLiteral.INSTANCE);
   }
@@ -46,6 +48,13 @@
     return "L" + name.replace('.', '/') + ';';
   }
 
+  public JNonNullType getNonNull() {
+    if (nonNullType == null) {
+      nonNullType = new JNonNullType(this);
+    }
+    return nonNullType;
+  }
+
   public String getShortName() {
     int dotpos = name.lastIndexOf('.');
     return name.substring(dotpos + 1);
diff --git a/dev/core/src/com/google/gwt/dev/jjs/ast/JThisRef.java b/dev/core/src/com/google/gwt/dev/jjs/ast/JThisRef.java
index d1a5ca5..8fbd1a0 100644
--- a/dev/core/src/com/google/gwt/dev/jjs/ast/JThisRef.java
+++ b/dev/core/src/com/google/gwt/dev/jjs/ast/JThisRef.java
@@ -22,20 +22,19 @@
  */
 public class JThisRef extends JExpression {
 
-  private final JNonNullType type;
+  private final JClassType type;
 
-  public JThisRef(SourceInfo info, JNonNullType type) {
+  public JThisRef(SourceInfo info, JClassType type) {
     super(info);
-    assert type.getUnderlyingType() instanceof JClassType;
     this.type = type;
   }
 
   public JClassType getClassType() {
-    return (JClassType) type.getUnderlyingType();
+    return type;
   }
 
   public JNonNullType getType() {
-    return type;
+    return type.getNonNull();
   }
 
   @Override
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 09a790f..30eb6ee 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
@@ -299,7 +299,7 @@
 
   @Override
   public boolean visit(JThisRef x, Context ctx) {
-    expression = new JThisRef(x.getSourceInfo(), x.getType());
+    expression = new JThisRef(x.getSourceInfo(), x.getClassType());
     return false;
   }
 }
\ No newline at end of file
diff --git a/dev/core/src/com/google/gwt/dev/jjs/impl/EnumOrdinalizer.java b/dev/core/src/com/google/gwt/dev/jjs/impl/EnumOrdinalizer.java
index 715786e..28f8594 100644
--- a/dev/core/src/com/google/gwt/dev/jjs/impl/EnumOrdinalizer.java
+++ b/dev/core/src/com/google/gwt/dev/jjs/impl/EnumOrdinalizer.java
@@ -651,7 +651,7 @@
         if (canBeOrdinal(leafType)) {
           JArrayType newAType = program.getTypeArray(
                     JPrimitiveType.INT, aType.getDims());
-          return program.getNonNullType(newAType);
+          return newAType.getNonNull();
         }
       }
       
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 cbb5d55..cd1b578 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
@@ -534,9 +534,11 @@
             if (isScript(program) && 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));
+              implementMethod(
+                  method,
+                  new JFieldRef(info, new JThisRef(info,
+                      (JClassType) currentClass),
+                      program.getIndexedField("Array.arrayClass"), currentClass));
             } else {
               implementMethod(method, program.getLiteralClass(currentClass));
             }
@@ -1300,7 +1302,7 @@
        * because the explicit qualifier takes precedence.
        */
       if (!currentMethod.isStatic()) {
-        JExpression implicitOuter = program.getExprThisRef(info,
+        JExpression implicitOuter = new JThisRef(info,
             (JClassType) currentClass);
         qualList.add(implicitOuter);
       }
@@ -2132,8 +2134,8 @@
       bridgeMethod.freezeParamTypes();
 
       // create a call
-      JMethodCall call = new JMethodCall(info, program.getExprThisRef(info,
-          clazz), implmeth);
+      JMethodCall call = new JMethodCall(info, new JThisRef(info, clazz),
+          implmeth);
 
       for (int i = 0; i < bridgeMethod.getParams().size(); i++) {
         JParameter param = bridgeMethod.getParams().get(i);
@@ -2183,7 +2185,7 @@
     private JExpression createQualifiedThisRef(SourceInfo info,
         JClassType targetType) {
       assert (currentClass instanceof JClassType);
-      JExpression expr = program.getExprThisRef(info, (JClassType) currentClass);
+      JExpression expr = new JThisRef(info, ((JClassType) currentClass));
       List<JExpression> list = new ArrayList<JExpression>();
       addAllOuterThisRefsPlusSuperChain(list, expr, (JClassType) currentClass);
       return createThisRef(targetType, list);
@@ -2250,8 +2252,8 @@
      */
     private JExpression createThisRef(SourceInfo info, JReferenceType targetType) {
       assert (currentClass instanceof JClassType);
-      return createThisRef(targetType, program.getExprThisRef(info,
-          (JClassType) currentClass));
+      return createThisRef(targetType, new JThisRef(info,
+          ((JClassType) currentClass)));
     }
 
     /**
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 f640c4d..8f47803 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
@@ -267,7 +267,7 @@
           refType = program.getTypeArray(replacement, arrayType.getDims());
         }
       }
-      return canBeNull ? refType : program.getNonNullType(refType);
+      return canBeNull ? refType : refType.getNonNull();
     }
   }
 
diff --git a/dev/core/src/com/google/gwt/dev/jjs/impl/MakeCallsStatic.java b/dev/core/src/com/google/gwt/dev/jjs/impl/MakeCallsStatic.java
index 9233651..26cbffb 100644
--- a/dev/core/src/com/google/gwt/dev/jjs/impl/MakeCallsStatic.java
+++ b/dev/core/src/com/google/gwt/dev/jjs/impl/MakeCallsStatic.java
@@ -166,7 +166,7 @@
       // Setup parameters; map from the old params to the new params
       JParameter thisParam = JParameter.create(sourceInfo.makeChild(
           CreateStaticImplsVisitor.class, "Instance parameter"), "this$static",
-          program.getNonNullType(enclosingType), true, true, newMethod);
+          enclosingType.getNonNull(), true, true, newMethod);
       Map<JParameter, JParameter> varMap = new IdentityHashMap<JParameter, JParameter>();
       for (int i = 0; i < x.getParams().size(); ++i) {
         JParameter oldVar = x.getParams().get(i);
@@ -178,7 +178,7 @@
 
       // Set the new original param types based on the old original param types
       List<JType> originalParamTypes = new ArrayList<JType>();
-      originalParamTypes.add(program.getNonNullType(enclosingType));
+      originalParamTypes.add(enclosingType.getNonNull());
       originalParamTypes.addAll(x.getOriginalParamTypes());
       newMethod.setOriginalTypes(x.getOriginalReturnType(), originalParamTypes);
 
@@ -193,8 +193,7 @@
       x.setBody(newBody);
       JMethodCall newCall = new JMethodCall(delegateCallSourceInfo, null, 
           newMethod);
-      newCall.addArg(new JThisRef(delegateCallSourceInfo, 
-          program.getNonNullType(enclosingType)));
+      newCall.addArg(new JThisRef(delegateCallSourceInfo, enclosingType));
       for (int i = 0; i < x.getParams().size(); ++i) {
         JParameter param = x.getParams().get(i);
         newCall.addArg(new JParameterRef(delegateCallSourceInfo, param));
diff --git a/dev/core/src/com/google/gwt/dev/jjs/impl/ResolveRebinds.java b/dev/core/src/com/google/gwt/dev/jjs/impl/ResolveRebinds.java
index 8a93585..a0a1b6c 100644
--- a/dev/core/src/com/google/gwt/dev/jjs/impl/ResolveRebinds.java
+++ b/dev/core/src/com/google/gwt/dev/jjs/impl/ResolveRebinds.java
@@ -219,7 +219,7 @@
     // c_g_g_d_c_i_DOMImpl
     toReturn = program.createMethod(info, requestType.getName().replace("_",
         "_1").replace('.', '_'), holderType,
-        program.getNonNullType(program.getTypeJavaLangObject()), false, true,
+        program.getTypeJavaLangObject().getNonNull(), false, true,
         true, false, false);
     toReturn.freezeParamTypes();
     rebindMethods.put(requestType, toReturn);
diff --git a/dev/core/src/com/google/gwt/dev/jjs/impl/TypeTightener.java b/dev/core/src/com/google/gwt/dev/jjs/impl/TypeTightener.java
index 2c3e561..c1cff6b 100644
--- a/dev/core/src/com/google/gwt/dev/jjs/impl/TypeTightener.java
+++ b/dev/core/src/com/google/gwt/dev/jjs/impl/TypeTightener.java
@@ -681,7 +681,7 @@
             return null;
           }
           return refType.canBeNull() ? singleConcrete
-              : program.getNonNullType(singleConcrete);
+              : singleConcrete.getNonNull();
         }
       }
       return null;
diff --git a/dev/core/test/com/google/gwt/dev/jjs/JjsTypeTest.java b/dev/core/test/com/google/gwt/dev/jjs/JjsTypeTest.java
index 2640cfe..822697d 100644
--- a/dev/core/test/com/google/gwt/dev/jjs/JjsTypeTest.java
+++ b/dev/core/test/com/google/gwt/dev/jjs/JjsTypeTest.java
@@ -268,8 +268,8 @@
     // Save off some miscellaneous types to test against
     typeNull = program.getTypeNull();
 
-    classBnn = program.getNonNullType(classB);
-    classBaseNn = program.getNonNullType(classBase);
+    classBnn = classB.getNonNull();
+    classBaseNn = classBase.getNonNull();
 
     arrayOfA = program.getTypeArray(classA, 1);
     arrayOfB = program.getTypeArray(classB, 1);