Temporarily rolling back r10435 due to issue with uninstantiable type associated with a class literal getting pruned. git-svn-id: https://google-web-toolkit.googlecode.com/svn/trunk@10436 8db76d5a-ed1c-0410-87a9-c151d255dfc7
diff --git a/dev/core/src/com/google/gwt/core/ext/linker/SymbolData.java b/dev/core/src/com/google/gwt/core/ext/linker/SymbolData.java index 97cd1d7..368acec 100644 --- a/dev/core/src/com/google/gwt/core/ext/linker/SymbolData.java +++ b/dev/core/src/com/google/gwt/core/ext/linker/SymbolData.java
@@ -108,11 +108,6 @@ int getQueryId(); /** - * Returns the seedId for types. - */ - int getSeedId(); - - /** * Returns the line number on which the symbol was originally declared or * <code>-1</code> if the line number is unknown. */
diff --git a/dev/core/src/com/google/gwt/core/ext/linker/impl/StandardSymbolData.java b/dev/core/src/com/google/gwt/core/ext/linker/impl/StandardSymbolData.java index 78cfb0c..fc57185 100644 --- a/dev/core/src/com/google/gwt/core/ext/linker/impl/StandardSymbolData.java +++ b/dev/core/src/com/google/gwt/core/ext/linker/impl/StandardSymbolData.java
@@ -32,15 +32,15 @@ public class StandardSymbolData implements SymbolData { public static StandardSymbolData forClass(String className, String uriString, - int lineNumber, int queryId, CastableTypeMap castableTypeMap, int seedId) { + int lineNumber, int queryId, CastableTypeMap castableTypeMap) { return new StandardSymbolData(className, null, null, uriString, lineNumber, - queryId, castableTypeMap, seedId); + queryId, castableTypeMap); } public static StandardSymbolData forMember(String className, String memberName, String methodSig, String uriString, int lineNumber) { return new StandardSymbolData(className, memberName, methodSig, uriString, - lineNumber, 0, null, -1); + lineNumber, 0, null); } public static String toUriString(String fileName) { @@ -63,12 +63,11 @@ private String sourceUri; private String symbolName; private int queryId; - private int seedId; private CastableTypeMap castableTypeMap; private StandardSymbolData(String className, String memberName, String methodSig, String sourceUri, int sourceLine, int queryId, - CastableTypeMap castableTypeMap, int seedId) { + CastableTypeMap castableTypeMap) { assert className != null && className.length() > 0 : "className"; assert memberName != null || methodSig == null : "methodSig without memberName"; assert sourceLine >= -1 : "sourceLine: " + sourceLine; @@ -80,7 +79,6 @@ this.sourceLine = sourceLine; this.queryId = queryId; this.castableTypeMap = castableTypeMap; - this.seedId = seedId; } public CastableTypeMap getCastableTypeMap() { @@ -109,10 +107,6 @@ return queryId; } - public int getSeedId() { - return seedId; - } - public int getSourceLine() { return sourceLine; } @@ -167,7 +161,6 @@ symbolName = in.readUTF(); queryId = in.readInt(); castableTypeMap = (CastableTypeMap) in.readObject(); - seedId = in.readInt(); } /** @@ -196,6 +189,5 @@ out.writeUTF(symbolName); out.writeInt(queryId); out.writeObject(castableTypeMap); - out.writeInt(seedId); } }
diff --git a/dev/core/src/com/google/gwt/dev/cfg/StaticPropertyOracle.java b/dev/core/src/com/google/gwt/dev/cfg/StaticPropertyOracle.java index a32d252..47906e4 100644 --- a/dev/core/src/com/google/gwt/dev/cfg/StaticPropertyOracle.java +++ b/dev/core/src/com/google/gwt/dev/cfg/StaticPropertyOracle.java
@@ -22,6 +22,9 @@ import com.google.gwt.core.ext.TreeLogger; import java.io.Serializable; +import java.util.List; +import java.util.Map; +import java.util.Set; import java.util.TreeSet; /** @@ -152,7 +155,7 @@ possibleValues.add(v); } return new DefaultSelectionProperty(value, prop.getFallback(), name, - possibleValues, prop.getFallbackValuesMap()); + possibleValues, (Map<String, List<Set<String>>>) prop.getFallbackValuesMap()); } }
diff --git a/dev/core/src/com/google/gwt/dev/javac/testing/impl/JavaResourceBase.java b/dev/core/src/com/google/gwt/dev/javac/testing/impl/JavaResourceBase.java index ea413fb..ee1c256 100644 --- a/dev/core/src/com/google/gwt/dev/javac/testing/impl/JavaResourceBase.java +++ b/dev/core/src/com/google/gwt/dev/javac/testing/impl/JavaResourceBase.java
@@ -302,12 +302,11 @@ StringBuilder code = new StringBuilder(); code.append("package java.lang;\n"); code.append("public class Object {\n"); - code.append(" private Class<?> ___clazz;"); code.append(" public boolean equals(Object that){return this == that;}"); code.append(" public int hashCode() { return 0; }\n"); code.append(" public String toString() { return \"Object\"; }\n"); code.append(" public Object clone() { return this; } "); - code.append(" public Class<?> getClass() { return ___clazz; } "); + code.append(" public Class<?> getClass() { return Object.class; } "); code.append("}\n"); return code; }
diff --git a/dev/core/src/com/google/gwt/dev/jjs/JavaToJavaScriptCompiler.java b/dev/core/src/com/google/gwt/dev/jjs/JavaToJavaScriptCompiler.java index 67d86c7..bac3201 100644 --- a/dev/core/src/com/google/gwt/dev/jjs/JavaToJavaScriptCompiler.java +++ b/dev/core/src/com/google/gwt/dev/jjs/JavaToJavaScriptCompiler.java
@@ -99,7 +99,6 @@ import com.google.gwt.dev.jjs.impl.Pruner; import com.google.gwt.dev.jjs.impl.RecordRebinds; import com.google.gwt.dev.jjs.impl.RemoveEmptySuperCalls; -import com.google.gwt.dev.jjs.impl.ReplaceGetClassOverrides; import com.google.gwt.dev.jjs.impl.ReplaceRebinds; import com.google.gwt.dev.jjs.impl.ReplaceRunAsyncs; import com.google.gwt.dev.jjs.impl.ResolveRebinds; @@ -308,8 +307,6 @@ // (6) Perform further post-normalization optimizations // Prune everything Pruner.exec(jprogram, false); - // prune all Object.getClass() overrides and replace with inline field ref - ReplaceGetClassOverrides.exec(jprogram); // (7) Generate a JavaScript code DOM from the Java type declarations jprogram.typeOracle.recomputeAfterOptimizations(); @@ -338,7 +335,7 @@ /* * Creates new variables, must run before code splitter and namer. */ - JsStackEmulator.exec(jprogram, jsProgram, propertyOracles, jjsmap); + JsStackEmulator.exec(jsProgram, propertyOracles); /* * Work around Safari 5 bug by rewriting a >> b as ~~a >> b.
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 eb6b85e..1363eb8 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
@@ -64,21 +64,6 @@ "com.google.gwt.lang.CollapsedPropertyHolder", "com.google.gwt.lang.Exceptions", "com.google.gwt.lang.LongLib", "com.google.gwt.lang.Stats", "com.google.gwt.lang.Util")); - /* - * Types which are not referenced by any Java code, but are required to exist - * after Java optimizations have run in order to be used by backend - * code-generation. These classes and their members, are considered live - * by ControlFlowAnalysis, at all times. Immortal types always live in the - * initial fragment and their definitions are hoisted to appear before all - * other types. Only static methods and fields are allowed, and no clinits - * are run. Field initializers must be primitives, literals, or one of - * JSO.createObject() or JSO.createArray(). - * - * Classes are inserted into the JsAST in the order they appear in the Set. - */ - public static final Set<String> IMMORTAL_CODEGEN_TYPES_SET = new LinkedHashSet<String>(Arrays.asList( - "com.google.gwt.lang.SeedUtil")); - public static final Set<String> INDEX_TYPES_SET = new LinkedHashSet<String>(Arrays.asList( "java.io.Serializable", "java.lang.Object", "java.lang.String", "java.lang.Class", "java.lang.CharSequence", "java.lang.Cloneable", "java.lang.Comparable", "java.lang.Enum", @@ -113,7 +98,6 @@ new HashMap<String, JPrimitiveType>(); static { - CODEGEN_TYPES_SET.addAll(IMMORTAL_CODEGEN_TYPES_SET); INDEX_TYPES_SET.addAll(CODEGEN_TYPES_SET); /* @@ -318,7 +302,6 @@ } public final List<JClassType> codeGenTypes = new ArrayList<JClassType>(); - public final List<JClassType> immortalCodeGenTypes = new ArrayList<JClassType>(); public final JTypeOracle typeOracle = new JTypeOracle(this); @@ -331,8 +314,6 @@ private IdentityHashMap<JReferenceType, JsCastMap> castMaps; - private Map<JType, JField> classLiteralFields; - /** * A factory to create correlations. */ @@ -410,11 +391,6 @@ if (CODEGEN_TYPES_SET.contains(name)) { codeGenTypes.add((JClassType) type); } - - if (IMMORTAL_CODEGEN_TYPES_SET.contains(name)) { - immortalCodeGenTypes.add((JClassType) type); - } - if (INDEX_TYPES_SET.contains(name)) { indexedTypes.put(type.getShortName(), type); for (JMethod method : type.getMethods()) { @@ -754,10 +730,6 @@ return castMaps.get(referenceType); } - public JField getClassLiteralField(JType type) { - return classLiteralFields.get(isJavaScriptObject(type) ? getJavaScriptObject() : type); - } - public String getClassLiteralName(JType type) { return type.getJavahSignatureName() + "_classLit"; } @@ -1039,10 +1011,6 @@ } } - public void recordClassLiteralFields(Map<JType, JField> classLiteralFields) { - this.classLiteralFields = classLiteralFields; - } - public void recordQueryIds(Map<JReferenceType, Integer> queryIdsByType, List<JReferenceType> typesByQueryId) { this.queryIdsByType = queryIdsByType;
diff --git a/dev/core/src/com/google/gwt/dev/jjs/ast/JSeedIdOf.java b/dev/core/src/com/google/gwt/dev/jjs/ast/JSeedIdOf.java deleted file mode 100644 index ab1ca95..0000000 --- a/dev/core/src/com/google/gwt/dev/jjs/ast/JSeedIdOf.java +++ /dev/null
@@ -1,36 +0,0 @@ -/* - * 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; - -import com.google.gwt.dev.jjs.SourceInfo; - -/** - * An AST node whose evaluation results in the seedId of its node. - */ -public class JSeedIdOf extends JNameOf { - - public JSeedIdOf(SourceInfo info, JClassType stringType, HasName node) { - super(info, stringType, node); - } - - 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/JTypeOracle.java b/dev/core/src/com/google/gwt/dev/jjs/ast/JTypeOracle.java index 8850cb6..b9095eb 100644 --- a/dev/core/src/com/google/gwt/dev/jjs/ast/JTypeOracle.java +++ b/dev/core/src/com/google/gwt/dev/jjs/ast/JTypeOracle.java
@@ -565,10 +565,6 @@ return results; } - public Set<JReferenceType> getInstantiatedTypes() { - return instantiatedTypes; - } - public JMethod getPolyMethod(JClassType type, String signature) { return getOrCreatePolyMap(type).get(signature); }
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 8e17e97..885d8e7 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
@@ -417,10 +417,6 @@ endVisit((JExpression) x, ctx); } - public void endVisit(JSeedIdOf x, Context ctx) { - endVisit((JNameOf) x, ctx); - } - public void endVisit(JsCastMap x, Context ctx) { endVisit((JsonArray) x, ctx); } @@ -745,10 +741,6 @@ return visit((JExpression) x, ctx); } - public boolean visit(JSeedIdOf x, Context ctx) { - return visit((JNameOf) x, ctx); - } - public boolean visit(JsCastMap x, Context ctx) { return visit((JsonArray) x, ctx); }
diff --git a/dev/core/src/com/google/gwt/dev/jjs/impl/CodeSplitter.java b/dev/core/src/com/google/gwt/dev/jjs/impl/CodeSplitter.java index 4c85a0a..7730084 100644 --- a/dev/core/src/com/google/gwt/dev/jjs/impl/CodeSplitter.java +++ b/dev/core/src/com/google/gwt/dev/jjs/impl/CodeSplitter.java
@@ -24,7 +24,6 @@ import com.google.gwt.dev.jjs.ast.Context; import com.google.gwt.dev.jjs.ast.JArrayType; import com.google.gwt.dev.jjs.ast.JClassLiteral; -import com.google.gwt.dev.jjs.ast.JClassType; import com.google.gwt.dev.jjs.ast.JDeclaredType; import com.google.gwt.dev.jjs.ast.JExpression; import com.google.gwt.dev.jjs.ast.JField; @@ -455,7 +454,7 @@ cfa.setDependencyRecorder(dependencyRecorder); cfa.traverseEntryMethods(); traverseClassArray(jprogram, cfa); - traverseImmortalTypes(jprogram, cfa); + dependencyRecorder.endDependencyGraph(); return cfa; } @@ -581,21 +580,6 @@ } } - /** - * Any immortal codegen types must be part of the initial download. - */ - private static void traverseImmortalTypes(JProgram jprogram, - ControlFlowAnalyzer cfa) { - for (JClassType type : jprogram.immortalCodeGenTypes) { - cfa.traverseFromInstantiationOf(type); - for (JMethod method : type.getMethods()) { - if (!method.needsVtable()) { - cfa.traverseFrom(method); - } - } - } - } - private static <T> Set<T> union(Set<? extends T> set1, Set<? extends T> set2) { Set<T> union = new HashSet<T>(); union.addAll(set1);
diff --git a/dev/core/src/com/google/gwt/dev/jjs/impl/ControlFlowAnalyzer.java b/dev/core/src/com/google/gwt/dev/jjs/impl/ControlFlowAnalyzer.java index f9b3aaa..36c534f 100644 --- a/dev/core/src/com/google/gwt/dev/jjs/impl/ControlFlowAnalyzer.java +++ b/dev/core/src/com/google/gwt/dev/jjs/impl/ControlFlowAnalyzer.java
@@ -518,16 +518,6 @@ return false; } - private void maybeRescueClassLiteral(JReferenceType type) { - if (liveFieldsAndMethods.contains(getClassMethod) || liveFieldsAndMethods.contains(getClassField)) { - // getClass() already live so rescue class literal immediately - rescue(program.getClassLiteralField(type)); - } else { - // getClass() not live yet, so mark for later rescue - classLiteralsToBeRescuedIfGetClassIsLive.add(type); - } - } - /** * Subclasses of JavaScriptObject are never instantiated directly. They are * implicitly created when a JSNI method passes a reference to an existing @@ -584,9 +574,6 @@ maybeRescueJavaScriptObjectPassingIntoJava(method.getType()); } rescueOverridingMethods(method); - if (method == getClassMethod) { - rescueClassLiteralsIfGetClassIsLive(); - } return true; } } @@ -607,8 +594,6 @@ boolean doVisit = false; if (isInstantiated && !instantiatedTypes.contains(type)) { instantiatedTypes.add(type); - maybeRescueClassLiteral(type); - doVisit = true; } @@ -638,10 +623,6 @@ if (var != null) { if (liveFieldsAndMethods.add(var)) { membersToRescueIfTypeIsInstantiated.remove(var); - if (var == getClassField) { - rescueClassLiteralsIfGetClassIsLive(); - } - if (isStaticFieldInitializedToLiteral(var)) { /* * Rescue literal initializers when the field is rescued, not when @@ -765,18 +746,6 @@ } } - private void rescueClassLiteralsIfGetClassIsLive() { - if (classLiteralsToBeRescuedIfGetClassIsLive != null) { - // guard against re-entrant calls. This only needs to run once. - Set<JReferenceType> toRescue = classLiteralsToBeRescuedIfGetClassIsLive; - classLiteralsToBeRescuedIfGetClassIsLive = null; - - for (JReferenceType classLit : toRescue) { - maybeRescueClassLiteral(classLit); - } - } - } - /** * If the type is instantiable, rescue any of its virtual methods that a * previously seen method call could call. @@ -838,13 +807,6 @@ private final JMethod asyncFragmentOnLoad; private final JDeclaredType baseArrayType; - - /** - * Schrodinger set of classLiterals to be rescued if type is instantiated AND getClass() - * is live. - */ - private Set<JReferenceType> classLiteralsToBeRescuedIfGetClassIsLive = new HashSet<JReferenceType>(); - private DependencyRecorder dependencyRecorder; private Set<JField> fieldsWritten = new HashSet<JField>(); private Set<JReferenceType> instantiatedTypes = new HashSet<JReferenceType>(); @@ -865,8 +827,6 @@ */ private Map<JMethod, List<JMethod>> methodsThatOverrideMe; - private final JField getClassField; - private final JMethod getClassMethod; private final JProgram program; private Set<JReferenceType> referencedTypes = new HashSet<JReferenceType>(); private final RescueVisitor rescuer = new RescueVisitor(); @@ -891,8 +851,6 @@ new HashMap<JParameter, List<JExpression>>(cfa.argsToRescueIfParameterRead); } methodsThatOverrideMe = cfa.methodsThatOverrideMe; - getClassField = program.getIndexedField("Object.___clazz"); - getClassMethod = program.getIndexedMethod("Object.getClass"); } public ControlFlowAnalyzer(JProgram program) { @@ -900,8 +858,6 @@ asyncFragmentOnLoad = program.getIndexedMethod("AsyncFragmentLoader.onLoad"); runAsyncOnsuccess = program.getIndexedMethod("RunAsyncCallback.onSuccess"); baseArrayType = program.getIndexedType("Array"); - getClassField = program.getIndexedField("Object.___clazz"); - getClassMethod = program.getIndexedMethod("Object.getClass"); buildMethodsOverriding(); } @@ -1008,15 +964,6 @@ runAsync.traverseOnSuccess(rescuer); } - /** - * Traverse the fragments for all runAsyncs. - */ - public void traverseFromRunAsyncs() { - for (JRunAsync runAsync : program.getRunAsyncs()) { - traverseFromRunAsync(runAsync); - } - } - private void buildMethodsOverriding() { methodsThatOverrideMe = new HashMap<JMethod, List<JMethod>>(); for (JDeclaredType type : program.getDeclaredTypes()) { @@ -1032,4 +979,13 @@ } } } + + /** + * Traverse the fragments for all runAsyncs. + */ + private void traverseFromRunAsyncs() { + for (JRunAsync runAsync : program.getRunAsyncs()) { + traverseFromRunAsync(runAsync); + } + } }
diff --git a/dev/core/src/com/google/gwt/dev/jjs/impl/FragmentExtractor.java b/dev/core/src/com/google/gwt/dev/jjs/impl/FragmentExtractor.java index 8d75fc9..a522b6e 100644 --- a/dev/core/src/com/google/gwt/dev/jjs/impl/FragmentExtractor.java +++ b/dev/core/src/com/google/gwt/dev/jjs/impl/FragmentExtractor.java
@@ -31,15 +31,15 @@ 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.JsModVisitor; import com.google.gwt.dev.js.ast.JsName; import com.google.gwt.dev.js.ast.JsNameRef; +import com.google.gwt.dev.js.ast.JsNew; import com.google.gwt.dev.js.ast.JsNumberLiteral; +import com.google.gwt.dev.js.ast.JsObjectLiteral; import com.google.gwt.dev.js.ast.JsProgram; import com.google.gwt.dev.js.ast.JsStatement; import com.google.gwt.dev.js.ast.JsVars; import com.google.gwt.dev.js.ast.JsVars.JsVar; -import com.google.gwt.dev.js.ast.JsVisitable; import java.util.ArrayList; import java.util.Collections; @@ -238,31 +238,21 @@ * The type whose vtables can currently be installed. */ JClassType currentVtableType = null; - JClassType pendingVtableType = null; - JsExprStmt pendingDefineSeed = null; - - // Since we haven't run yet. + // Since we haven't run yet. assert jsprogram.getFragmentCount() == 1; - List<JsStatement> stats = jsprogram.getGlobalBlock().getStatements(); for (JsStatement stat : stats) { - boolean keepIt; JClassType vtableTypeAssigned = vtableTypeAssigned(stat); - if (vtableTypeAssigned != null - && livenessPredicate.isLive(vtableTypeAssigned)) { - boolean[] anyCtorsSetup = new boolean[1]; - JsExprStmt result = maybeRemoveCtorsFromDefineSeedStmt(livenessPredicate, - alreadyLoadedPredicate, stat, anyCtorsSetup); - boolean anyWorkDone = anyCtorsSetup[0] - || !alreadyLoadedPredicate.isLive(vtableTypeAssigned); - if (anyWorkDone) { + if (vtableTypeAssigned != null && livenessPredicate.isLive(vtableTypeAssigned)) { + JsExprStmt result = + extractPrototypeSetup(livenessPredicate, alreadyLoadedPredicate, stat, + vtableTypeAssigned); + if (result != null) { stat = result; keepIt = true; } else { - pendingDefineSeed = result; - pendingVtableType = vtableTypeAssigned; keepIt = false; } } else if (containsRemovableVars(stat)) { @@ -280,11 +270,8 @@ } JClassType vtableType = vtableTypeNeeded(stat); if (vtableType != null && vtableType != currentVtableType) { - assert pendingVtableType == vtableType; - extractedStats.add(pendingDefineSeed); - currentVtableType = pendingVtableType; - pendingDefineSeed = null; - pendingVtableType = null; + extractedStats.add(vtableStatFor(vtableType)); + currentVtableType = vtableType; } extractedStats.add(stat); } @@ -336,6 +323,57 @@ return false; } + /** + * Weird case: the seed function's liveness is associated with the type + * itself. However, individual constructors can have a liveness that is a + * subset of the type's liveness. We essentially have to break up the + * prototype chain according to exactly what's newly live. + */ + private JsExprStmt extractPrototypeSetup(final LivenessPredicate livenessPredicate, + final LivenessPredicate alreadyLoadedPredicate, JsStatement stat, + final JClassType vtableTypeAssigned) { + final boolean[] anyLiveCode = new boolean[1]; + Cloner c = new Cloner() { + @Override + public void endVisit(JsBinaryOperation x, JsContext ctx) { + JsExpression rhs = stack.pop(); + JsNameRef lhs = (JsNameRef) stack.pop(); + if (rhs instanceof JsNew || rhs instanceof JsObjectLiteral) { + // The super op is being assigned to the seed prototype. + if (alreadyLoadedPredicate.isLive(vtableTypeAssigned)) { + stack.push(lhs); + return; + } else { + anyLiveCode[0] = true; + } + } else if (lhs.getQualifier() == null) { + // The underscore is being assigned to. + assert "_".equals(lhs.getIdent()); + } else { + // A constructor function is being assigned to. + assert "prototype".equals(lhs.getIdent()); + JsNameRef ctorRef = (JsNameRef) lhs.getQualifier(); + JConstructor ctor = (JConstructor) map.nameToMethod(ctorRef.getName()); + assert ctor != null; + if (livenessPredicate.isLive(ctor) && !alreadyLoadedPredicate.isLive(ctor)) { + anyLiveCode[0] = true; + } else { + stack.push(rhs); + return; + } + } + + JsBinaryOperation toReturn = new JsBinaryOperation(x.getSourceInfo(), x.getOperator()); + toReturn.setArg2(rhs); + toReturn.setArg1(lhs); + stack.push(toReturn); + } + }; + c.accept(((JsExprStmt) stat).getExpression()); + JsExprStmt result = anyLiveCode[0] ? c.getExpression().makeStmt() : null; + return result; + } + private boolean isLive(JsStatement stat, LivenessPredicate livenessPredicate) { JClassType type = map.typeForStatement(stat); if (type != null) { @@ -382,42 +420,6 @@ } /** - * Weird case: the seed function's liveness is associated with the type - * itself. However, individual constructors can have a liveness that is a - * subset of the type's liveness. - */ - private JsExprStmt maybeRemoveCtorsFromDefineSeedStmt( - final LivenessPredicate livenessPredicate, - final LivenessPredicate alreadyLoadedPredicate, JsStatement stat, - final boolean[] anyCtorsSetup) { - Cloner c = new Cloner(); - c.accept(((JsExprStmt) stat).getExpression()); - JsExprStmt result = c.getExpression().makeStmt(); - new JsModVisitor() { - public void endVisit(JsNameRef x, JsContext ctx) { - JMethod maybeCtor = map.nameToMethod(x.getName()); - if (maybeCtor instanceof JConstructor) { - JConstructor ctor = (JConstructor) maybeCtor; - if (!livenessPredicate.isLive(ctor) - || alreadyLoadedPredicate.isLive(ctor)) { - ctx.removeMe(); - } else { - anyCtorsSetup[0] = true; - } - } - }; - - /** - * Overridden to allow insert/remove on the varargs portion. - */ - protected <T extends JsVisitable> void doAcceptList(List<T> collection) { - doAcceptWithInsertRemove(collection); - }; - }.accept(result); - return result; - } - - /** * Return the Java method corresponding to <code>stat</code>, or * <code>null</code> if there isn't one. It recognizes JavaScript of the form * <code>function foo(...) { ...}</code>, where <code>foo</code> is the name @@ -463,30 +465,40 @@ } /** - * If <code>state</code> is of the form <code>_ = String.prototype</code>, - * then return <code>String</code>. If the form is - * <code>defineSeed(id, superId, cTM, ctor1, ctor2, ...)</code> return the type - * corresponding to that id. Otherwise return <code>null</code>. + * Compute a statement that can be used to set up for installing instance + * methods into a vtable. It will be of the form + * <code>_ = foo.prototype</code>, where <code>foo</code> is the constructor + * function for <code>vtableType</code>. + */ + private JsStatement vtableStatFor(JClassType vtableType) { + JsNameRef prototypeField = + new JsNameRef(jsprogram.createSourceInfoSynthetic(FragmentExtractor.class), "prototype"); + JsExpression constructorRef; + SourceInfo sourceInfoVtableSetup = jsprogram.createSourceInfoSynthetic(FragmentExtractor.class); + if (vtableType == jprogram.getTypeJavaLangString()) { + // The methods of java.lang.String are put onto JavaScript's String + // prototype + SourceInfo sourceInfoConstructorRef = + jsprogram.createSourceInfoSynthetic(FragmentExtractor.class); + constructorRef = new JsNameRef(sourceInfoConstructorRef, "String"); + } else { + constructorRef = map.nameForType(vtableType).makeRef(sourceInfoVtableSetup); + } + prototypeField.setQualifier(constructorRef); + SourceInfo underlineSourceInfo = jsprogram.createSourceInfoSynthetic(FragmentExtractor.class); + return (new JsBinaryOperation(sourceInfoVtableSetup, JsBinaryOperator.ASG, jsprogram.getScope() + .declareName("_").makeRef(underlineSourceInfo), prototypeField)).makeStmt(); + } + + /** + * If <code>state</code> is of the form <code>_ = Foo.prototype = exp</code>, + * then return <code>Foo</code>. Otherwise return <code>null</code>. */ private JClassType vtableTypeAssigned(JsStatement stat) { if (!(stat instanceof JsExprStmt)) { return null; } JsExprStmt expr = (JsExprStmt) stat; - if (expr.getExpression() instanceof JsInvocation) { - // Handle a defineSeed call. - JsInvocation call = (JsInvocation) expr.getExpression(); - if (!(call.getQualifier() instanceof JsNameRef)) { - return null; - } - JsNameRef func = (JsNameRef) call.getQualifier(); - if (func.getName() != jsprogram.getIndexedFunction("SeedUtil.defineSeed").getName()) { - return null; - } - return map.typeForStatement(stat); - } - - // Handle String. if (!(expr.getExpression() instanceof JsBinaryOperation)) { return null; } @@ -498,26 +510,30 @@ return null; } JsNameRef lhs = (JsNameRef) binExpr.getArg1(); - JsName underBar = jsprogram.getScope().findExistingName("_"); - assert underBar != null; - if (lhs.getName() != underBar) { + if (lhs.getQualifier() != null) { return null; } - if (!(binExpr.getArg2() instanceof JsNameRef)) { + if (lhs.getName() == null) { + return null; + } + if (!lhs.getName().getShortIdent().equals("_")) { + return null; + } + if (!(binExpr.getArg2() instanceof JsBinaryOperation)) { + return null; + } + JsBinaryOperation binExprRhs = (JsBinaryOperation) binExpr.getArg2(); + if (binExprRhs.getOperator() != JsBinaryOperator.ASG) { + return null; + } + if (!(binExprRhs.getArg1() instanceof JsNameRef)) { + return null; + } + JsNameRef middleNameRef = (JsNameRef) binExprRhs.getArg1(); + if (!middleNameRef.getName().getShortIdent().equals("prototype")) { return null; } - JsNameRef rhsRef = (JsNameRef) binExpr.getArg2(); - if (!(rhsRef.getQualifier() instanceof JsNameRef)) { - return null; - } - if (!((JsNameRef) rhsRef.getQualifier()).getShortIdent().equals("String")) { - return null; - } - - if (!rhsRef.getName().getShortIdent().equals("prototype")) { - return null; - } return map.typeForStatement(stat); }
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 3c4883f..87a6aa7 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
@@ -514,17 +514,14 @@ // Just use JavaScriptObject's implementation for all subclasses. currentClass.getMethods().remove(2); } else { - if (currentClass == program.getIndexedType("Array")) { - /* - * Don't implement, fall through to Object.getClass(). Array emulation code - * in com.google.gwt.lang.Array invokes Array.getClass() and expects to get the - * class literal for the actual runtime type of the array (e.g. Foo[].class) and - * not Array.class. - */ - currentClass.getMethods().remove(2); + tryFindUpRefs(method); + SourceInfo info = method.getSourceInfo(); + if (isScript(program) && currentClass == program.getIndexedType("Array")) { + // Special implementation: return this.arrayClass + implementMethod(method, new JFieldRef(info, new JThisRef(info, + (JClassType) currentClass), program.getIndexedField("Array.arrayClass"), + currentClass)); } else { - tryFindUpRefs(method); - SourceInfo info = method.getSourceInfo(); implementMethod(method, new JClassLiteral(info.makeChild(), currentClass)); } }
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 708261b..287f1c1 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
@@ -76,7 +76,6 @@ import com.google.gwt.dev.jjs.ast.JReboundEntryPoint; import com.google.gwt.dev.jjs.ast.JReferenceType; import com.google.gwt.dev.jjs.ast.JReturnStatement; -import com.google.gwt.dev.jjs.ast.JSeedIdOf; import com.google.gwt.dev.jjs.ast.JStatement; import com.google.gwt.dev.jjs.ast.JSwitchStatement; import com.google.gwt.dev.jjs.ast.JThisRef; @@ -139,7 +138,6 @@ import com.google.gwt.dev.js.ast.JsReturn; import com.google.gwt.dev.js.ast.JsRootScope; import com.google.gwt.dev.js.ast.JsScope; -import com.google.gwt.dev.js.ast.JsSeedIdOf; import com.google.gwt.dev.js.ast.JsStatement; import com.google.gwt.dev.js.ast.JsSwitch; import com.google.gwt.dev.js.ast.JsSwitchMember; @@ -389,7 +387,7 @@ * as var foo = function blah() {} and introduce a separate scope for * the function's name according to EcmaScript-262, but this would mess * up stack traces by allowing two inner scope function names to - * obfuscate to the same identifier, making function names no longer a + * onfuscate to the same identifier, making function names no longer a * 1:1 mapping to obfuscated symbols. Leaving them in global scope * causes no harm. */ @@ -406,7 +404,6 @@ Maps.put(indexedFunctions, x.getEnclosingType().getShortName() + "." + x.getName(), jsFunction); } - return true; } @@ -501,8 +498,7 @@ StandardSymbolData symbolData = StandardSymbolData.forClass(x.getName(), x.getSourceInfo().getFileName(), x - .getSourceInfo().getStartLine(), program.getQueryId(x), castableTypeMap, - x instanceof JClassType ? getSeedId((JClassType) x) : -1); + .getSourceInfo().getStartLine(), program.getQueryId(x), castableTypeMap); assert !symbolTable.containsKey(symbolData); symbolTable.put(symbolData, jsName); } @@ -571,7 +567,6 @@ JsName name = topScope.declareName("Q$" + longName, "Q$" + shortName); namesByQueryId.add(name); } - // TODO(cromwellian): see about moving this into an immortal type StringBuilder sb = new StringBuilder(); sb.append("function makeCastMap(a) {"); sb.append(" var result = {};"); @@ -611,16 +606,12 @@ private final JsName prototype = objectScope.declareName("prototype"); - { globalTemp.setObfuscatable(false); prototype.setObfuscatable(false); arrayLength.setObfuscatable(false); } - public GenerateJavaScriptVisitor() { - } - @Override public void endVisit(JAbsentArrayDimension x, Context ctx) { throw new InternalCompilerException("Should not get here."); @@ -727,11 +718,6 @@ return; } - if (program.immortalCodeGenTypes.contains(x)) { - // Handled in generateImmortalTypes - return; - } - alreadyRan.add(x); List<JsFunction> jsFuncs = popList(x.getMethods().size()); // methods @@ -751,7 +737,6 @@ // declare all methods into the global scope for (int i = 0; i < jsFuncs.size(); ++i) { JsFunction func = jsFuncs.get(i); - // don't add polymorphic JsFuncs, inline decl into vtable assignment if (func != null && !polymorphicJsFunctions.contains(func)) { globalStmts.add(func.makeStmt()); @@ -1271,7 +1256,7 @@ // Long lits must go at the top, they can be constant field initializers. generateLongLiterals(vars); - generateImmortalTypes(vars); + generateQueryIdConstants(vars); // Class objects, but only if there are any. @@ -1309,13 +1294,6 @@ } @Override - public void endVisit(JSeedIdOf x, Context ctx) { - JsName name = names.get(x.getNode()); - assert name != null : "Missing JsName for " + x.getNode().getName(); - push(new JsSeedIdOf(x.getSourceInfo(), name)); - } - - @Override public void endVisit(JsCastMap x, Context ctx) { super.endVisit(x, ctx); JsArrayLiteral arrayLit = (JsArrayLiteral) pop(); @@ -1436,11 +1414,6 @@ return false; } - if (program.immortalCodeGenTypes.contains(x)) { - // Handled in generateImmortalTypes - return false; - } - // force super type to generate code first, this is required for prototype // chaining to work properly if (x.getSuperClass() != null && !alreadyRan.contains(x)) { @@ -1471,7 +1444,6 @@ for (int i = 0; i < entryMethods.size(); i++) { entryMethodToIndex.put(entryMethods.get(i), i); } - return true; } @@ -1651,20 +1623,27 @@ return new JsBinaryOperation(lhs.getSourceInfo(), JsBinaryOperator.COMMA, lhs, rhs); } - private JsExpression generateCastableTypeMap(JClassType x) { + private void generateCastableTypeMap(JClassType x, List<JsStatement> globalStmts) { 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 new JsObjectLiteral(SourceOrigin.UNKNOWN); + return; } + // Generate castableTypeMap for each type prototype + // _.castableTypeMap$ = ... + SourceInfo sourceInfo = jsProgram.createSourceInfoSynthetic(GenerateJavaScriptAST.class); + JsNameRef fieldRef = castableTypeMapName.makeRef(sourceInfo); + fieldRef.setQualifier(globalTemp.makeRef(sourceInfo)); accept(castMap); - return (JsExpression) pop(); + JsExpression asg = createAssignment(fieldRef, (JsExpression) pop()); + JsExprStmt asgStmt = asg.makeStmt(); + globalStmts.add(asgStmt); + typeForStatMap.put(asgStmt, x); } - return new JsObjectLiteral(SourceOrigin.UNKNOWN); } private void generateClassLiteral(JDeclarationStatement decl, JsVars vars) { @@ -1701,6 +1680,8 @@ // special: setup the identifying typeMarker field generateTypeMarker(globalStmts); } + + generateCastableTypeMap(x, globalStmts); } private void generateGwtOnLoad(List<JsFunction> entryFuncs, List<JsStatement> globalStmts) { @@ -1801,78 +1782,6 @@ errCall.getArguments().add(modName.makeRef(sourceInfo)); } - private void generateImmortalTypes(JsVars globals) { - List<JsStatement> globalStmts = jsProgram.getGlobalBlock().getStatements(); - List<JClassType> immortalTypes = new ArrayList<JClassType>( - program.immortalCodeGenTypes); - // visit in reverse order since insertions start at head - Collections.reverse(immortalTypes); - JMethod createObjMethod = program.getIndexedMethod("JavaScriptObject.createObject"); - JMethod createArrMethod = program.getIndexedMethod("JavaScriptObject.createArray"); - - for (JClassType x : immortalTypes) { - // should not be pruned - assert x.getMethods().size() > 0; - // insert all static methods - for (JMethod method : x.getMethods()) { - /* - * Skip virtual methods and constructors. Even in cases where there is no constructor - * defined, the compiler will synthesize a default constructor which invokes - * a synthensized $init() method. We must skip both of these inserted methods. - */ - if (method.needsVtable() || method instanceof JConstructor) { - continue; - } - if (JProgram.isClinit(method)) { - /** - * Emit empty clinits that will be pruned. If a type B extends A, then even if - * B and A have no fields to initialize, there will be a call inserted in B's clinit - * to invoke A's clinit. Likewise, if you have a static field initialized to - * JavaScriptObject.createObject(), the clinit() will include this initializer code, - * which we don't want. - */ - JsFunction func = new JsFunction(x.getSourceInfo(), topScope, - topScope.declareName(mangleNameForGlobal(method)), true); - func.setBody(new JsBlock(method.getBody().getSourceInfo())); - push(func); - } else { - accept(method); - } - // add after var declaration, but before everything else - JsFunction func = (JsFunction) pop(); - assert func.getName() != null; - globalStmts.add(1, func.makeStmt()); - } - - // insert fields into global var declaration - for (JField field : x.getFields()) { - assert field.isStatic() : "All fields on immortal types must be static."; - accept(field); - JsNode node = pop(); - assert node instanceof JsVar; - JsVar fieldVar = (JsVar) node; - JExpression init = field.getInitializer(); - if (init != null - && field.getLiteralInitializer() == null) { - // no literal, but it could be a JavaScriptObject - if (init.getType() == program.getJavaScriptObject()) { - assert init instanceof JMethodCall; - JMethod meth = ((JMethodCall) init).getTarget(); - // immortal types can only have non-primitive literal initializers of createArray,createObject - if (meth == createObjMethod) { - fieldVar.setInitExpr(new JsObjectLiteral(init.getSourceInfo())); - } else if (meth == createArrMethod) { - fieldVar.setInitExpr(new JsArrayLiteral(init.getSourceInfo())); - } else { - assert false : "Illegal initializer expression for immortal field " + field; - } - } - } - globals.add(fieldVar); - } - } - } - private void generateLongLiterals(JsVars vars) { for (Entry<Long, JsName> entry : longLits.entrySet()) { JsName jsName = entry.getValue(); @@ -1898,31 +1807,44 @@ private void generateSeedFuncAndPrototype(JClassType x, List<JsStatement> globalStmts) { SourceInfo sourceInfo = x.getSourceInfo(); if (x != program.getTypeJavaLangString()) { - JsInvocation defineSeed = new JsInvocation(x.getSourceInfo()); - JsName seedNameRef = indexedFunctions.get( - "SeedUtil.defineSeed").getName(); - defineSeed.setQualifier(seedNameRef.makeRef(x.getSourceInfo())); - int newSeed = getSeedId(x); - assert newSeed > 0; - JClassType superClass = x.getSuperClass(); - int superSeed = (superClass == null) ? -1 : getSeedId(x.getSuperClass()); - // SeedUtil.defineSeed(queryId, superId, castableMap, constructors) - defineSeed.getArguments().add(new JsNumberLiteral(x.getSourceInfo(), - newSeed)); - defineSeed.getArguments().add(new JsNumberLiteral(x.getSourceInfo(), - superSeed)); - JsExpression castMap = generateCastableTypeMap(x); - defineSeed.getArguments().add(castMap); - + JsName seedFuncName = names.get(x); + + // seed function + // function com_example_foo_Foo() { } + JsFunction seedFunc = new JsFunction(sourceInfo, topScope, seedFuncName, true); + seedFuncName.setStaticRef(seedFunc); + JsBlock body = new JsBlock(sourceInfo); + seedFunc.setBody(body); + JsExprStmt seedFuncStmt = seedFunc.makeStmt(); + globalStmts.add(seedFuncStmt); + typeForStatMap.put(seedFuncStmt, x); + + // Setup prototype chain. + // _ = Foo__V.prototype = FooSeed.prototype = new FooSuper(); + JsNameRef seedProtoRef = prototype.makeRef(sourceInfo); + seedProtoRef.setQualifier(seedFuncName.makeRef(sourceInfo)); + JsExpression protoObj; + if (x.getSuperClass() != null) { + JsNameRef superPrototypeRef = names.get(x.getSuperClass()).makeRef(sourceInfo); + JsNew newExpr = new JsNew(sourceInfo, superPrototypeRef); + protoObj = newExpr; + } else { + protoObj = new JsObjectLiteral(sourceInfo); + } + JsExpression protoAsg = createAssignment(seedProtoRef, protoObj); + // Chain assign the same prototype to every live constructor. for (JMethod method : x.getMethods()) { if (liveCtors.contains(method)) { - defineSeed.getArguments().add(names.get(method).makeRef( - sourceInfo)); + JsNameRef protoRef = prototype.makeRef(sourceInfo); + protoRef.setQualifier(names.get(method).makeRef(sourceInfo)); + protoAsg = createAssignment(protoRef, protoAsg); } } - JsStatement tmpAsgStmt = defineSeed.makeStmt(); + // Finally, assign to the temp var for setup code. + JsExpression tmpAsg = createAssignment(globalTemp.makeRef(sourceInfo), protoAsg); + JsExprStmt tmpAsgStmt = tmpAsg.makeStmt(); globalStmts.add(tmpAsgStmt); typeForStatMap.put(tmpAsgStmt, x); } else { @@ -1937,16 +1859,6 @@ JsExprStmt tmpAsgStmt = tmpAsg.makeStmt(); globalStmts.add(tmpAsgStmt); typeForStatMap.put(tmpAsgStmt, x); - JField castableTypeMapField = program.getIndexedField("Object.castableTypeMap"); - JsName castableTypeMapName = names.get(castableTypeMapField); - JsNameRef ctmRef = castableTypeMapName.makeRef(sourceInfo); - ctmRef.setQualifier(globalTemp.makeRef(sourceInfo)); - JsExpression castMapLit = generateCastableTypeMap(x); - JsExpression ctmAsg = createAssignment(ctmRef, - castMapLit); - JsExprStmt ctmAsgStmt = ctmAsg.makeStmt(); - globalStmts.add(ctmAsgStmt); - typeForStatMap.put(ctmAsgStmt, x); } } @@ -2249,7 +2161,6 @@ private final Map<JAbstractMethodBody, JsFunction> methodBodyMap = new IdentityHashMap<JAbstractMethodBody, JsFunction>(); private final Map<HasName, JsName> names = new IdentityHashMap<HasName, JsName>(); - private int nextSeedId = 1; private List<JsName> namesByQueryId; private JsFunction nullFunc; @@ -2264,11 +2175,6 @@ private final JProgram program; /** - * Map of class type to allocated seed id. - */ - private final Map<JClassType, Integer> seedIdMap = new HashMap<JClassType, Integer>(); - - /** * All of the fields in String and Array need special handling for interop. */ private final Map<JField, String> specialObfuscatedFields = new HashMap<JField, String>(); @@ -2350,8 +2256,8 @@ namesToIdents.put("expando", "eX"); namesToIdents.put("typeMarker", "tM"); namesToIdents.put("castableTypeMap", "cM"); - namesToIdents.put("___clazz", "cZ"); // Array magic field + namesToIdents.put("arrayClass", "aC"); namesToIdents.put("queryId", "qI"); List<JField> fields = new ArrayList<JField>(program.getTypeJavaLangObject().getFields()); @@ -2363,11 +2269,6 @@ specialObfuscatedFields.put(field, ident); } } - - // force java.lang.Object,java.lang.String - // to have seed ids 1,2 - getSeedId(program.getTypeJavaLangObject()); - getSeedId(program.getTypeJavaLangString()); } String getNameString(HasName hasName) { @@ -2375,20 +2276,6 @@ return s; } - /** - * Looks up or assigns a seed id for a type.. - */ - int getSeedId(JClassType type) { - Integer val = seedIdMap.get(type); - int seedId = val == null ? 0 : val; - - if (seedId == 0) { - seedId = nextSeedId++; - seedIdMap.put(type, seedId); - } - return seedId; - } - String mangleName(JField x) { String s = getNameString(x.getEnclosingType()) + '_' + getNameString(x); return s; @@ -2522,11 +2409,6 @@ return constructorNameToTypeMap.get(name); } - public int seedIdForType(JClassType type) { - Integer seedId = seedIdMap.get(type); - return seedId != null ? seedId : -1; - } - public JClassType typeForStatement(JsStatement stat) { return typeForStatMap.get(stat); }
diff --git a/dev/core/src/com/google/gwt/dev/jjs/impl/GwtAstBuilder.java b/dev/core/src/com/google/gwt/dev/jjs/impl/GwtAstBuilder.java index 831aa25..ae2e645 100644 --- a/dev/core/src/com/google/gwt/dev/jjs/impl/GwtAstBuilder.java +++ b/dev/core/src/com/google/gwt/dev/jjs/impl/GwtAstBuilder.java
@@ -2158,13 +2158,15 @@ assert ("getClass".equals(method.getName())); SourceInfo info = method.getSourceInfo(); if ("com.google.gwt.lang.Array".equals(type.getName())) { - /* - * Don't implement, fall through to Object.getClass(). Array emulation code - * in com.google.gwt.lang.Array invokes Array.getClass() and expects to get the - * class literal for the actual runtime type of the array (e.g. Foo[].class) and - * not Array.class. - */ - type.getMethods().remove(2); + // Special implementation: return this.arrayClass + JField arrayClassField = null; + for (JField field : type.getFields()) { + if ("arrayClass".equals(field.getName())) { + arrayClassField = field; + } + } + assert arrayClassField != null; + implementMethod(method, new JFieldRef(info, makeThisRef(info), arrayClassField, type)); } else { implementMethod(method, new JClassLiteral(info, type)); } @@ -2765,7 +2767,8 @@ * * TODO(zundel): something much more awesome? */ - private static final long AST_VERSION = 3; + private static final long AST_VERSION = 2; + private static final char[] _STRING = "_String".toCharArray(); private static final String ARRAY_LENGTH_FIELD = "length";
diff --git a/dev/core/src/com/google/gwt/dev/jjs/impl/ImplementClassLiteralsAsFields.java b/dev/core/src/com/google/gwt/dev/jjs/impl/ImplementClassLiteralsAsFields.java index 7d31cae..f525c3a 100644 --- a/dev/core/src/com/google/gwt/dev/jjs/impl/ImplementClassLiteralsAsFields.java +++ b/dev/core/src/com/google/gwt/dev/jjs/impl/ImplementClassLiteralsAsFields.java
@@ -34,10 +34,10 @@ import com.google.gwt.dev.jjs.ast.JMethodBody; import com.google.gwt.dev.jjs.ast.JMethodCall; import com.google.gwt.dev.jjs.ast.JModVisitor; +import com.google.gwt.dev.jjs.ast.JNameOf; import com.google.gwt.dev.jjs.ast.JNullLiteral; import com.google.gwt.dev.jjs.ast.JPrimitiveType; import com.google.gwt.dev.jjs.ast.JProgram; -import com.google.gwt.dev.jjs.ast.JSeedIdOf; import com.google.gwt.dev.jjs.ast.JStringLiteral; import com.google.gwt.dev.jjs.ast.JType; import com.google.gwt.dev.jjs.ast.js.JsniMethodRef; @@ -58,20 +58,15 @@ * Ordinarily, accessing one of these fields would trigger a clinit to run, but * we've special-cased class literal fields to evaluate as top-level code before * the application starts running to avoid the clinit. - * - * Class literal factory methods are responsible for installing references - * to themselves on the Object.clazz field of their JS runtime prototype - * since getClass() is no longer an overridden method. Prototypes can be - * looked up via 'seedId' from the global seedTable object, and so each - * class literal factory method is passed the seedId of its type. * <p> + * TODO(cromwellian): consider lazy-initialization to improve startup time. */ public class ImplementClassLiteralsAsFields { private class NormalizeVisitor extends JModVisitor { @Override public void endVisit(JClassLiteral x, Context ctx) { - JField field = resolveClassLiteralField(x.getRefType()); + JField field = resolveClassLiteralField(x); x.setField(field); } } @@ -125,8 +120,8 @@ * Class: * * <pre> - * Class.createForClass("java.lang.", "Object", /JSeedIdOf/"java.lang.Object", null) - * Class.createForClass("java.lang.", "Exception", /JSeedIdOf/"java.lang.Exception", Throwable.class) + * Class.createForClass("java.lang.", "Object", /JNameOf/"java.lang.Object", null) + * Class.createForClass("java.lang.", "Exception", /JNameOf/"java.lang.Exception", Throwable.class) * </pre> * * Interface: @@ -144,21 +139,21 @@ * Array: * * <pre> - * Class.createForArray("", "[I", /JSeedIdOf/"com.google.gwt.lang.Array", int.class) - * Class.createForArray("[Lcom.example.", "Foo;", /JSeedIdOf/"com.google.gwt.lang.Array", Foo.class) + * Class.createForArray("", "[I", /JNameOf/"com.google.gwt.lang.Array", int.class) + * Class.createForArray("[Lcom.example.", "Foo;", /JNameOf/"com.google.gwt.lang.Array", Foo.class) * </pre> * * Enum: * * <pre> - * Class.createForEnum("com.example.", "MyEnum", /JSeedIdOf/"com.example.MyEnum", Enum.class, + * Class.createForEnum("com.example.", "MyEnum", /JNameOf/"com.example.MyEnum", Enum.class, * public static MyEnum[] values(), public static MyEnum valueOf(String name)) * </pre> * * Enum subclass: * * <pre> - * Class.createForEnum("com.example.", "MyEnum$1", /JSeedIdOf/"com.example.MyEnum$1", MyEnum.class, + * Class.createForEnum("com.example.", "MyEnum$1", /JNameOf/"com.example.MyEnum$1", MyEnum.class, * null, null)) * </pre> */ @@ -190,10 +185,12 @@ if (type instanceof JArrayType) { // There's only one seed function for all arrays JDeclaredType arrayType = program.getIndexedType("Array"); - call.addArg(new JSeedIdOf(info, program.getTypeJavaLangString(), arrayType)); + call.addArg(new JNameOf(info, program.getTypeJavaLangString(), arrayType)); + } else if (type instanceof JClassType) { // Add the name of the seed function for concrete types - call.addArg(new JSeedIdOf(info, program.getTypeJavaLangString(), type)); + call.addArg(new JNameOf(info, program.getTypeJavaLangString(), type)); + } else if (type instanceof JPrimitiveType) { // And give primitive types an illegal, though meaningful, value call.addArg(program.getLiteralString(info, " " + type.getJavahSignatureName())); @@ -259,7 +256,7 @@ private JClassLiteral createDependentClassLiteral(SourceInfo info, JType type) { JClassLiteral classLiteral = new JClassLiteral(info.makeChild(), type); - JField field = resolveClassLiteralField(classLiteral.getRefType()); + JField field = resolveClassLiteralField(classLiteral); classLiteral.setField(field); return classLiteral; } @@ -267,7 +264,6 @@ private void execImpl() { NormalizeVisitor visitor = new NormalizeVisitor(); visitor.accept(program); - program.recordClassLiteralFields(classLiteralFields); } private String getTypeName(JType type) { @@ -313,7 +309,8 @@ * } * </pre> */ - private JField resolveClassLiteralField(JType type) { + private JField resolveClassLiteralField(JClassLiteral classLiteral) { + JType type = classLiteral.getRefType(); type = normalizeJsoType(type); JField field = classLiteralFields.get(type); if (field == null) {
diff --git a/dev/core/src/com/google/gwt/dev/jjs/impl/JavaToJavaScriptMap.java b/dev/core/src/com/google/gwt/dev/jjs/impl/JavaToJavaScriptMap.java index de9e7fa..89aace3 100644 --- a/dev/core/src/com/google/gwt/dev/jjs/impl/JavaToJavaScriptMap.java +++ b/dev/core/src/com/google/gwt/dev/jjs/impl/JavaToJavaScriptMap.java
@@ -55,11 +55,6 @@ JClassType nameToType(JsName name); /** - * Return the seed id corresponding to the Java type. - */ - int seedIdForType(JClassType type); - - /** * If <code>stat</code> is used to set up the definition of some class, return * that class. Otherwise, return null. */
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 12b72c2..4375220 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
@@ -599,17 +599,13 @@ ControlFlowAnalyzer livenessAnalyzer = new ControlFlowAnalyzer(program); livenessAnalyzer.setForPruning(); - - // SPECIAL: Immortal codegen types are never pruned - traverseTypes(livenessAnalyzer, program.immortalCodeGenTypes); - if (saveCodeGenTypes) { /* * SPECIAL: Some classes contain methods used by code generation later. * Unless those transforms have already been performed, we must rescue all * contained methods for later user. */ - traverseTypes(livenessAnalyzer, program.codeGenTypes); + traverseFromCodeGenTypes(livenessAnalyzer); } livenessAnalyzer.traverseEverything(); @@ -631,11 +627,11 @@ } /** - * Traverse from all methods starting from a set of types. + * Traverse from all methods in the program's code-gen types. See + * {@link JProgram#CODEGEN_TYPES_SET}. */ - private void traverseTypes(ControlFlowAnalyzer livenessAnalyzer, - List<JClassType> types) { - for (JClassType type : types) { + private void traverseFromCodeGenTypes(ControlFlowAnalyzer livenessAnalyzer) { + for (JClassType type : program.codeGenTypes) { livenessAnalyzer.traverseFromReferenceTo(type); for (JMethod method : type.getMethods()) { if (method instanceof JConstructor) {
diff --git a/dev/core/src/com/google/gwt/dev/jjs/impl/ReplaceGetClassOverrides.java b/dev/core/src/com/google/gwt/dev/jjs/impl/ReplaceGetClassOverrides.java deleted file mode 100644 index 18152d0..0000000 --- a/dev/core/src/com/google/gwt/dev/jjs/impl/ReplaceGetClassOverrides.java +++ /dev/null
@@ -1,71 +0,0 @@ -/* - * Copyright 2011 Google Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); you may not - * use this file except in compliance with the License. You may obtain a copy of - * the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT - * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the - * License for the specific language governing permissions and limitations under - * the License. - */ -package com.google.gwt.dev.jjs.impl; - -import com.google.gwt.dev.jjs.ast.Context; -import com.google.gwt.dev.jjs.ast.JField; -import com.google.gwt.dev.jjs.ast.JFieldRef; -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.JProgram; - -/** - * Prune all overrides of Object.getClass() except when the enclosing class is JavaScriptObject - * (to permit getClass() devirtualization in JsoDevirtualizer to continue to work). - * Also Inline all method calls to Object.getClass() as Object.clazz. - */ -public class ReplaceGetClassOverrides { - public static void exec(JProgram program) { - new GetClassInlinerRemover(program).accept(program); - } - - private static class GetClassInlinerRemover extends JModVisitor { - - private JProgram program; - private JMethod getClassMethod; - private JField clazzField; - - public GetClassInlinerRemover(JProgram program) { - this.program = program; - getClassMethod = program.getIndexedMethod("Object.getClass"); - clazzField = program.getIndexedField("Object.___clazz"); - } - - public void endVisit(JMethod x, Context ctx) { - // don't prune JSO.getClass() - if (x.getEnclosingType() == program.getJavaScriptObject()) { - return; - } - if (x.getOverrides().contains(getClassMethod)) { - ctx.removeMe(); - } - } - - public void endVisit(JMethodCall x, Context ctx) { - // don't inline JSO.getClass() - if (x.getTarget().getEnclosingType() == program.getJavaScriptObject()) { - return; - } - // replace overridden getClass() with reference to Object.clazz field - if (x.getTarget() == getClassMethod || - x.getTarget().getOverrides().contains(getClassMethod)) { - ctx.replaceMe(new JFieldRef(x.getSourceInfo(), x.getInstance(), - clazzField, clazzField.getEnclosingType())); - } - } - } -}
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 691752a..829886f 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
@@ -76,7 +76,6 @@ import com.google.gwt.dev.jjs.ast.JReboundEntryPoint; import com.google.gwt.dev.jjs.ast.JReferenceType; import com.google.gwt.dev.jjs.ast.JReturnStatement; -import com.google.gwt.dev.jjs.ast.JSeedIdOf; import com.google.gwt.dev.jjs.ast.JStatement; import com.google.gwt.dev.jjs.ast.JStringLiteral; import com.google.gwt.dev.jjs.ast.JSwitchStatement; @@ -136,7 +135,6 @@ protected static final char[] CHARS_PROTECTED = "protected ".toCharArray(); protected static final char[] CHARS_PUBLIC = "public ".toCharArray(); protected static final char[] CHARS_RETURN = "return".toCharArray(); - protected static final char[] CHARS_SEEDIDOF = " JSeedIdOf ".toCharArray(); protected static final char[] CHARS_SLASHSTAR = "/*".toCharArray(); protected static final char[] CHARS_STARSLASH = "*/".toCharArray(); protected static final char[] CHARS_STATIC = "static ".toCharArray(); @@ -679,7 +677,7 @@ @Override public boolean visit(JNameOf x, Context ctx) { print(CHARS_SLASHSTAR); - print(x instanceof JSeedIdOf ? CHARS_SEEDIDOF : CHARS_NAMEOF); + print(CHARS_NAMEOF); print(CHARS_STARSLASH); printStringLiteral(x.getNode().getName()); return false;
diff --git a/dev/core/src/com/google/gwt/dev/js/JsSourceGenerationVisitorWithSizeBreakdown.java b/dev/core/src/com/google/gwt/dev/js/JsSourceGenerationVisitorWithSizeBreakdown.java index 834bce7..2a430a5 100644 --- a/dev/core/src/com/google/gwt/dev/js/JsSourceGenerationVisitorWithSizeBreakdown.java +++ b/dev/core/src/com/google/gwt/dev/js/JsSourceGenerationVisitorWithSizeBreakdown.java
@@ -26,7 +26,6 @@ import com.google.gwt.dev.js.ast.JsName; import com.google.gwt.dev.js.ast.JsProgram; import com.google.gwt.dev.js.ast.JsProgramFragment; -import com.google.gwt.dev.js.ast.JsSeedIdOf; import com.google.gwt.dev.js.ast.JsStatement; import com.google.gwt.dev.js.ast.JsVisitable; import com.google.gwt.dev.js.ast.JsVars.JsVar; @@ -83,17 +82,6 @@ } @Override - public boolean visit(JsSeedIdOf x, JsContext ctx) { - Integer seedId = map.seedIdForType(map.nameToType(x.getName())); - if (seedId == null) { - seedId = -1; - } - out.print(Integer.toString(seedId)); - - return false; - } - - @Override protected <T extends JsVisitable> T doAccept(T node) { JsName newName = nameToBillTo(node); if (newName == null) {
diff --git a/dev/core/src/com/google/gwt/dev/js/JsStackEmulator.java b/dev/core/src/com/google/gwt/dev/js/JsStackEmulator.java index 5df8898..82a6379 100644 --- a/dev/core/src/com/google/gwt/dev/js/JsStackEmulator.java +++ b/dev/core/src/com/google/gwt/dev/js/JsStackEmulator.java
@@ -22,9 +22,6 @@ import com.google.gwt.dev.jjs.HasSourceInfo; import com.google.gwt.dev.jjs.InternalCompilerException; import com.google.gwt.dev.jjs.SourceInfo; -import com.google.gwt.dev.jjs.ast.JMethod; -import com.google.gwt.dev.jjs.ast.JProgram; -import com.google.gwt.dev.jjs.impl.JavaToJavaScriptMap; import com.google.gwt.dev.js.ast.JsArrayAccess; import com.google.gwt.dev.js.ast.JsArrayLiteral; import com.google.gwt.dev.js.ast.JsBinaryOperation; @@ -562,22 +559,12 @@ } /** - * Creates a visitor to instrument each JsFunction in the jsProgram. + * Creates a visitor to instrument each JsFunction in the program. */ private class InstrumentAllFunctions extends JsVisitor { - @Override public void endVisit(JsFunction x, JsContext ctx) { if (!x.getBody().getStatements().isEmpty()) { - JsName fnName = x.getName(); - JMethod method = jjsmap.nameToMethod(fnName); - /** - * Do not instrumental immortal types because they are potentially - * evaluated before anything else has been defined. - */ - if (method != null && jprogram.immortalCodeGenTypes.contains(method.getEnclosingType())) { - return; - } if (recordLineNumbers) { (new LocationVisitor(x)).accept(x.getBody()); } else { @@ -815,11 +802,9 @@ STRIP, NATIVE, EMULATED; } - public static void exec(JProgram jprogram, JsProgram jsProgram, - PropertyOracle[] propertyOracles, - JavaToJavaScriptMap jjsmap) { + public static void exec(JsProgram program, PropertyOracle[] propertyOracles) { if (getStackMode(propertyOracles) == StackMode.EMULATED) { - (new JsStackEmulator(jprogram, jsProgram, propertyOracles, jjsmap)).execImpl(); + (new JsStackEmulator(program, propertyOracles)).execImpl(); } } @@ -854,20 +839,14 @@ private JsFunction caughtFunction; private JsName lineNumbers; - private JProgram jprogram; - private final JsProgram jsProgram; - private JavaToJavaScriptMap jjsmap; + private final JsProgram program; private boolean recordFileNames; private boolean recordLineNumbers; private JsName stack; private JsName stackDepth; - private JsStackEmulator(JProgram jprogram, JsProgram jsProgram, - PropertyOracle[] propertyOracles, - JavaToJavaScriptMap jjsmap) { - this.jprogram = jprogram; - this.jsProgram = jsProgram; - this.jjsmap = jjsmap; + private JsStackEmulator(JsProgram program, PropertyOracle[] propertyOracles) { + this.program = program; assert propertyOracles.length > 0; PropertyOracle oracle = propertyOracles[0]; @@ -886,27 +865,27 @@ } private void execImpl() { - caughtFunction = jsProgram.getIndexedFunction("Exceptions.caught"); + caughtFunction = program.getIndexedFunction("Exceptions.caught"); if (caughtFunction == null) { // No exceptions caught? Weird, but possible. return; } initNames(); makeVars(); - (new ReplaceUnobfuscatableNames()).accept(jsProgram); - (new InstrumentAllFunctions()).accept(jsProgram); + (new ReplaceUnobfuscatableNames()).accept(program); + (new InstrumentAllFunctions()).accept(program); } private void initNames() { - stack = jsProgram.getScope().declareName("$JsStackEmulator_stack", "$stack"); - stackDepth = jsProgram.getScope().declareName("$JsStackEmulator_stackDepth", + stack = program.getScope().declareName("$JsStackEmulator_stack", "$stack"); + stackDepth = program.getScope().declareName("$JsStackEmulator_stackDepth", "$stackDepth"); - lineNumbers = jsProgram.getScope().declareName("$JsStackEmulator_location", + lineNumbers = program.getScope().declareName("$JsStackEmulator_location", "$location"); } private void makeVars() { - SourceInfo info = jsProgram.createSourceInfoSynthetic(getClass()); + SourceInfo info = program.createSourceInfoSynthetic(getClass()); JsVar stackVar = new JsVar(info, stack); stackVar.setInitExpr(new JsArrayLiteral(info)); JsVar stackDepthVar = new JsVar(info, stackDepth); @@ -915,12 +894,12 @@ lineNumbersVar.setInitExpr(new JsArrayLiteral(info)); JsVars vars; - JsStatement first = jsProgram.getGlobalBlock().getStatements().get(0); + JsStatement first = program.getGlobalBlock().getStatements().get(0); if (first instanceof JsVars) { vars = (JsVars) first; } else { vars = new JsVars(info); - jsProgram.getGlobalBlock().getStatements().add(0, vars); + program.getGlobalBlock().getStatements().add(0, vars); } vars.add(stackVar); vars.add(stackDepthVar);
diff --git a/dev/core/src/com/google/gwt/dev/js/ast/JsSeedIdOf.java b/dev/core/src/com/google/gwt/dev/js/ast/JsSeedIdOf.java deleted file mode 100644 index 51d0ed5..0000000 --- a/dev/core/src/com/google/gwt/dev/js/ast/JsSeedIdOf.java +++ /dev/null
@@ -1,34 +0,0 @@ -/* - * 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.js.ast; - -import com.google.gwt.dev.jjs.SourceInfo; - -/** - * An AST node whose evaluation results in the numeric seed id of its type. - */ -public class JsSeedIdOf extends JsNameOf { - - public JsSeedIdOf(SourceInfo info, JsName name) { - super(info, name); - } - - public void traverse(JsVisitor visitor, JsContext 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 142e462..e64799f 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
@@ -219,10 +219,6 @@ public void endVisit(JsReturn x, JsContext ctx) { } - public void endVisit(JsSeedIdOf x, JsContext ctx) { - endVisit((JsNameOf) x, ctx); - } - public void endVisit(JsStringLiteral x, JsContext ctx) { } @@ -387,10 +383,6 @@ return true; } - public boolean visit(JsSeedIdOf x, JsContext ctx) { - return visit((JsNameOf) x, ctx); - } - public boolean visit(JsStringLiteral x, JsContext ctx) { return true; }
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 3c36c55..60c809f 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
@@ -173,7 +173,7 @@ public static Array initValues(Class<?> arrayClass, JavaScriptObject castableTypeMap, int queryId, Array array) { ExpandoWrapper.wrapArray(array); - setClass(array, arrayClass); + array.arrayClass = arrayClass; Util.setCastableTypeMap(array, castableTypeMap); array.queryId = queryId; return array; @@ -302,15 +302,17 @@ return array[index] = value; }-*/; - // violator pattern so that the field remains private - private static native void setClass(Object o, Class<?> clazz) /*-{ - o.@java.lang.Object::___clazz = clazz; - }-*/; - /* * Explicitly initialize all fields to JS false values; see comment in * ExpandoWrapper.initExpandos(). */ + + /** + * 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; /** * A representation of the necessary cast target for objects stored into this
diff --git a/dev/core/super/com/google/gwt/dev/jjs/intrinsic/com/google/gwt/lang/SeedUtil.java b/dev/core/super/com/google/gwt/dev/jjs/intrinsic/com/google/gwt/lang/SeedUtil.java deleted file mode 100644 index bd80104..0000000 --- a/dev/core/super/com/google/gwt/dev/jjs/intrinsic/com/google/gwt/lang/SeedUtil.java +++ /dev/null
@@ -1,70 +0,0 @@ -/* - * 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.lang; - -import com.google.gwt.core.client.JavaScriptObject; - -/** - * Utility class for fetching prototype-seed functions for injection into JsAST. - */ -public class SeedUtil { - - /* - * Holds a map of seedId to anonymous Javascript functions (prototypes for class vtables). - */ - private static JavaScriptObject seedTable = JavaScriptObject.createObject(); - - /** - * If not already created, generates an anonymous function and assigns it a slot in the global - * seedTable. If superSeed is > -1, it creates an instance of the superSeed by invoking - * newSeed() and then assigns it as the prototype of the seed being defined. It also sets up the - * castableTypeMap, as well as any ctors which are passed in via Javascript varargs. Finally, if - * the class literal for this seed id was setup first, which can happen if they are in separate - * code-split fragments, the Class.createFor* methods will have created a placeholder seedTable - * entry containing the Class literal, and this will be copied from the placeholder location - * onto the current prototype. - */ - public static native JavaScriptObject defineSeed(int id, int superSeed, - JavaScriptObject castableTypeMap) /*-{ - var seed = @com.google.gwt.lang.SeedUtil::seedTable[id]; - if (seed && !seed.@java.lang.Object::___clazz) { - // not a placeholder entry setup by Class.setClassLiteral - _ = seed.prototype; - } else { - if (!seed) { - seed = @com.google.gwt.lang.SeedUtil::seedTable[id] = function() { - }; - } - _ = seed.prototype = (superSeed < 0) ? {} - : @com.google.gwt.lang.SeedUtil::newSeed(I)(superSeed); - _.@java.lang.Object::castableTypeMap = castableTypeMap; - } - for (var i = 3; i < arguments.length; ++i) { - arguments[i].prototype = _; - } - if (seed.@java.lang.Object::___clazz) { - _.@java.lang.Object::___clazz = seed.@java.lang.Object::___clazz; - seed.@java.lang.Object::___clazz = null; - } - }-*/; - - /** - * Lookup seed function by id and instantiate an object with it. - */ - public static native JavaScriptObject newSeed(int id) /*-{ - return new (@com.google.gwt.lang.SeedUtil::seedTable[id]); - }-*/; -}
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 d9cdc10..187b660 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
@@ -31,5 +31,7 @@ ControlFlowAnalyzer cfa = CodeSplitter.computeInitiallyLive(program); assertTrue(cfa.getInstantiatedTypes().contains(findType(program, "com.google.gwt.lang.Array"))); + assertTrue(cfa.getLiveFieldsAndMethods().contains( + findMethod(findType(program, "com.google.gwt.lang.Array"), "getClass"))); } }
diff --git a/user/src/com/google/gwt/rpc/linker/ClientOracleLinker.java b/user/src/com/google/gwt/rpc/linker/ClientOracleLinker.java index 9bd5e36..eb3c555 100644 --- a/user/src/com/google/gwt/rpc/linker/ClientOracleLinker.java +++ b/user/src/com/google/gwt/rpc/linker/ClientOracleLinker.java
@@ -77,8 +77,7 @@ builder.add(symbolData.getSymbolName(), symbolData.getJsniIdent(), symbolData.getClassName(), symbolData.getMemberName(), symbolData.getQueryId(), - new CastableTypeDataImpl(castableTypeMapString), - symbolData.getSeedId()); + new CastableTypeDataImpl(castableTypeMapString)); } ByteArrayOutputStream out = new ByteArrayOutputStream();
diff --git a/user/src/com/google/gwt/rpc/server/WebModeClientOracle.java b/user/src/com/google/gwt/rpc/server/WebModeClientOracle.java index 602fabb..d91c0e3 100644 --- a/user/src/com/google/gwt/rpc/server/WebModeClientOracle.java +++ b/user/src/com/google/gwt/rpc/server/WebModeClientOracle.java
@@ -52,8 +52,7 @@ private WebModeClientOracle oracle = new WebModeClientOracle(); public void add(String jsIdent, String jsniIdent, String className, - String memberName, int queryId, CastableTypeData castableTypeData, - int seedId) { + String memberName, int queryId, CastableTypeData castableTypeData) { oracle.idents.add(jsIdent); ClassData data = oracle.getClassData(className); @@ -74,8 +73,6 @@ data.typeName = className; data.seedName = jsIdent; oracle.seedNamesToClassData.put(jsIdent, data); - oracle.seedIdsToClassData.put(seedId, data); - data.seedId = seedId; } else { if (jsniIdent.contains("(")) { jsniIdent = jsniIdent.substring(jsniIdent.indexOf("::") + 2, @@ -134,7 +131,6 @@ public String seedName; public List<String> serializableFields = Collections.emptyList(); public String typeName; - public int seedId; } /** @@ -143,7 +139,7 @@ * TODO: Use something other than Java serialization to store this type's * data. */ - private static final long serialVersionUID = 2L; + private static final long serialVersionUID = 1L; /** * Recreate a WebModeClientOracle based on the contents previously emitted by @@ -226,7 +222,6 @@ private final Set<String> idents = new HashSet<String>(); private final Map<String, ClassData> seedNamesToClassData = new HashMap<String, ClassData>(); - private final Map<Integer, ClassData> seedIdsToClassData = new HashMap<Integer, ClassData>(); private transient Map<Class<?>, Field[]> operableFieldMap = new IdentityHashMap<Class<?>, Field[]>(); @@ -386,15 +381,6 @@ seedName = seedName.substring(6); } ClassData data = seedNamesToClassData.get(seedName); - if (data == null) { - int seedId = 0; - try { - seedId = Integer.parseInt(seedName); - } catch (NumberFormatException e) { - return null; - } - data = seedIdsToClassData.get(seedId); - } return data == null ? null : data.typeName; }
diff --git a/user/src/com/google/gwt/rpc/server/WebModePayloadSink.java b/user/src/com/google/gwt/rpc/server/WebModePayloadSink.java index 7e9f431..b5716fd 100644 --- a/user/src/com/google/gwt/rpc/server/WebModePayloadSink.java +++ b/user/src/com/google/gwt/rpc/server/WebModePayloadSink.java
@@ -257,14 +257,12 @@ byte[] currentBackRef = begin(x); byte[] constructorFunction = constructorFunction(x); + String seedName = clientOracle.getSeedName(x.getTargetClass()); - String getSeedFunc = clientOracle.getMethodId("java.lang.Class", - "getSeedFunction", "Ljava/lang/Class;"); - String classLitId = clientOracle.getFieldId( - "com.google.gwt.lang.ClassLiteralHolder", - getJavahSignatureName(x.getTargetClass()) + "_classLit"); - assert classLitId != null : "No class literal for " - + x.getTargetClass().getName(); + if (seedName == null) { + throw new IncompatibleRemoteServiceException( + "The client cannot create type " + x.getTargetClass()); + } /* * If we need to maintain a backreference to the object, it's established @@ -272,7 +270,7 @@ * constructorFunction. This is done in case one of the fields should * require a reference to the object that is currently being constructed. */ - // constructorFunctionFoo(x = new (classLit.getSeedFunction()), field1, field2) + // constructorFunctionFoo(x = new Foo, field1, field2) push(constructorFunction); lparen(); if (hasBackRef) { @@ -280,12 +278,7 @@ eq(); } _new(); - lparen(); - push(getSeedFunc); - lparen(); - push(classLitId); - rparen(); - rparen(); + push(seedName); for (SetCommand setter : x.getSetters()) { comma(); accept(setter.getValue()); @@ -569,7 +562,7 @@ byte[] ident = getBytes("_0"); - // function foo(_0) {return initValues(classLit, castableTypeData, queryId, _0)} + // function foo(_0) {return initValues(classLid, castableTypeData, queryId, _0)} function(); push(functionName); lparen();
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 c41f7d3..d000d2d 100644 --- a/user/super/com/google/gwt/emul/java/lang/Class.java +++ b/user/super/com/google/gwt/emul/java/lang/Class.java
@@ -30,20 +30,16 @@ private static final int ARRAY = 0x00000004; private static final int ENUM = 0x00000008; - static native String asString(int number) /*-{ - return number; - }-*/; - /** * Create a Class object for an array. * * @skip */ static <T> Class<T> createForArray(String packageName, String className, - int seedId, Class<?> componentType) { + String seedName, Class<?> componentType) { // Initialize here to avoid method inliner Class<T> clazz = new Class<T>(); - setName(clazz, packageName, className, -1); + setName(clazz, packageName, className, seedName); clazz.modifiers = ARRAY; clazz.superclass = Object.class; clazz.componentType = componentType; @@ -56,10 +52,10 @@ * @skip */ static <T> Class<T> createForClass(String packageName, String className, - int seedId, Class<? super T> superclass) { + String seedName, Class<? super T> superclass) { // Initialize here to avoid method inliner Class<T> clazz = new Class<T>(); - setName(clazz, packageName, className, seedId); + setName(clazz, packageName, className, seedName); clazz.superclass = superclass; return clazz; } @@ -70,11 +66,11 @@ * @skip */ static <T> Class<T> createForEnum(String packageName, String className, - int seedId, Class<? super T> superclass, + String seedName, Class<? super T> superclass, JavaScriptObject enumConstantsFunc, JavaScriptObject enumValueOfFunc) { // Initialize here to avoid method inliner Class<T> clazz = new Class<T>(); - setName(clazz, packageName, className, seedId); + setName(clazz, packageName, className, seedName); clazz.modifiers = (enumConstantsFunc != null) ? ENUM : 0; clazz.superclass = clazz.enumSuperclass = superclass; clazz.enumConstantsFunc = enumConstantsFunc; @@ -90,7 +86,7 @@ static <T> Class<T> createForInterface(String packageName, String className) { // Initialize here to avoid method inliner Class<T> clazz = new Class<T>(); - setName(clazz, packageName, className, -1); + setName(clazz, packageName, className, null); clazz.modifiers = INTERFACE; return clazz; } @@ -101,73 +97,21 @@ * @skip */ static Class<?> createForPrimitive(String packageName, String className, - int seedId) { + String seedName) { // Initialize here to avoid method inliner Class<?> clazz = new Class<Object>(); - setName(clazz, packageName, className, seedId); + setName(clazz, packageName, className, seedName); clazz.modifiers = PRIMITIVE; return clazz; } - /** - * Used by {@link WebModePayloadSink} to create uninitialized instances. - */ - static native JavaScriptObject getSeedFunction(Class<?> clazz) /*-{ - var func = @com.google.gwt.lang.SeedUtil::seedTable[clazz.@java.lang.Class::seedId]; - clazz = null; // HACK: prevent pruning via inlining by using param as lvalue - return func; - }-*/; - static boolean isClassMetadataEnabled() { // This body may be replaced by the compiler return true; } - /** - * null or -1 implies lack of seed function / non-instantiable type - */ - static native boolean isInstantiable(int seedId) /*-{ - return seedId != null && seedId > -1; - }-*/; - - /** - * Install class literal into seed.prototype.clazz field such that - * Object.getClass() returning this.clazz returns the literal. Also stores - * seedId on class literal for looking up prototypes given a literal. This - * is used for deRPC at the moment, but may be used to implement - * Class.newInstance() in the future. - */ - static native void setClassLiteral(int seedId, Class<?> clazz) /*-{ - var proto; - clazz.@java.lang.Class::seedId = seedId; - // String is the exception to the usual vtable setup logic - if (seedId == 2) { - proto = String.prototype - } else { - if (seedId > -1) { - // Guarantees virtual method won't be pruned by using a JSNI ref - // This is required because deRPC needs to call it. - var seed = @java.lang.Class::getSeedFunction(Ljava/lang/Class;)(clazz); - // A class literal may be referenced prior to an async-loaded vtable setup - // For example, class literal lives in inital fragment, - // but type is instantiated in another fragment - if (seed) { - proto = seed.prototype; - } else { - // Leave a place holder for now to be filled in by __defineSeed__ later - seed = @com.google.gwt.lang.SeedUtil::seedTable[seedId] = function(){}; - seed.@java.lang.Object::___clazz = clazz; - return; - } - } else { - return; - } - } - proto.@java.lang.Object::___clazz = clazz; - }-*/; - static void setName(Class<?> clazz, String packageName, String className, - int seedId) { + String seedName) { if (clazz.isClassMetadataEnabled()) { clazz.typeName = packageName + className; } else { @@ -177,10 +121,7 @@ * during application start up, before class Integer has been initialized. */ clazz.typeName = "Class$" - + (seedId != -1 ? asString(seedId) : "" + clazz.hashCode()); - } - if (isInstantiable(seedId)) { - setClassLiteral(seedId, clazz); + + (seedName != null ? seedName : "" + clazz.hashCode()); } } @@ -199,8 +140,6 @@ private String typeName; - private int seedId; - /** * Not publicly instantiable. *
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 63717d2..3b8efff 100644 --- a/user/super/com/google/gwt/emul/java/lang/Object.java +++ b/user/super/com/google/gwt/emul/java/lang/Object.java
@@ -26,14 +26,6 @@ public class Object { /** - * Holds class literal for subtypes of Object. - */ - // BUG: If this field name conflicts with a method param name, JDT will complain - // CHECKSTYLE_OFF - private transient Class<?> ___clazz; - // CHECKSTYLE_ON - - /** * Used by {@link com.google.gwt.core.client.impl.WeakMapping} in web mode * to store an expando containing a String -> Object mapping. * @@ -68,11 +60,14 @@ } /* - * magic; Actual assignment to this field is done by Class.createFor() methods by injecting it - * into the prototype. + * Note: Unlike the real JRE, we don't spec this method as final because the + * compiler generates a polymorphic override on every other class which will + * return the correct class object. + * + * TODO(scottb, compiler magician): declare this final, but have the compiler fix it up. */ public Class<? extends Object> getClass() { - return ___clazz; + return Object.class; } public int hashCode() {
diff --git a/user/test/com/google/gwt/emultest/java/util/ArraysTest.java b/user/test/com/google/gwt/emultest/java/util/ArraysTest.java index 8bc3344..6b17574 100644 --- a/user/test/com/google/gwt/emultest/java/util/ArraysTest.java +++ b/user/test/com/google/gwt/emultest/java/util/ArraysTest.java
@@ -402,7 +402,7 @@ /** * Test Arrays.binarySearch(Object[], Object, Comparator). * - * <pre> -draftCompile + * <pre> * Verify the following cases: * empty array * odd numbers of elements