Author: [EMAIL PROTECTED]
Date: Sat Oct 18 17:16:09 2008
New Revision: 3783
Modified:
changes/spoon/runAsync/dev/core/src/com/google/gwt/dev/jjs/impl/CodeSplitter.java
changes/spoon/runAsync/dev/core/src/com/google/gwt/dev/jjs/impl/ControlFlowAnalyzer.java
changes/spoon/runAsync/dev/core/src/com/google/gwt/dev/jjs/impl/FragmentExtractor.java
Log:
Updates CodeSplitter to more thoroughly address
load-order dependencies. For example, no type's
JS prototype is emitted except in a conext where
its superty's JS prototype is known to have already
been loaded.
Modified:
changes/spoon/runAsync/dev/core/src/com/google/gwt/dev/jjs/impl/CodeSplitter.java
==============================================================================
---
changes/spoon/runAsync/dev/core/src/com/google/gwt/dev/jjs/impl/CodeSplitter.java
(original)
+++
changes/spoon/runAsync/dev/core/src/com/google/gwt/dev/jjs/impl/CodeSplitter.java
Sat Oct 18 17:16:09 2008
@@ -15,11 +15,16 @@
*/
package com.google.gwt.dev.jjs.impl;
+import com.google.gwt.dev.jjs.ast.Context;
+import com.google.gwt.dev.jjs.ast.JClassLiteral;
+import com.google.gwt.dev.jjs.ast.JExpression;
import com.google.gwt.dev.jjs.ast.JField;
import com.google.gwt.dev.jjs.ast.JMethod;
import com.google.gwt.dev.jjs.ast.JNode;
import com.google.gwt.dev.jjs.ast.JProgram;
import com.google.gwt.dev.jjs.ast.JReferenceType;
+import com.google.gwt.dev.jjs.ast.JStringLiteral;
+import com.google.gwt.dev.jjs.ast.JVisitor;
import com.google.gwt.dev.jjs.impl.FragmentExtractor.LivenessPredicate;
import com.google.gwt.dev.jjs.impl.FragmentExtractor.NothingAlivePredicate;
import com.google.gwt.dev.jjs.impl.FragmentExtractor.StatementLogger;
@@ -36,7 +41,9 @@
import java.util.HashSet;
import java.util.List;
import java.util.Map;
+import java.util.Queue;
import java.util.Set;
+import java.util.concurrent.ArrayBlockingQueue;
/**
* Divides a [EMAIL PROTECTED] JsProgram} into separate fragments. All access
to code
in a
@@ -137,6 +144,11 @@
new CodeSplitter(jprogram, jsprogram, map).execImpl();
}
+ private static <T> int getOrZero(Map<T, Integer> map, T key) {
+ Integer value = map.get(key);
+ return (value == null) ? 0 : value;
+ }
+
private static <T> void updateMap(int entry, Map<T, Integer> map,
Set<?> liveWithoutEntry, Iterable<T> all) {
for (T each : all) {
@@ -153,6 +165,7 @@
}
}
+ private final Map<JField, JClassLiteral> fieldToLiteralOfClass;
private JProgram jprogram;
private JsProgram jsprogram;
private final boolean logging;
@@ -166,6 +179,7 @@
this.map = map;
numEntries = jprogram.entryMethods.size();
logging = Boolean.getBoolean(PROP_LOG_FRAGMENT_MAP);
+ fieldToLiteralOfClass =
FragmentExtractor.buildFieldToClassLiteralMap(jprogram);
}
/**
@@ -255,8 +269,49 @@
PerfLogger.end();
}
+ private void fixUpLoadOrderDependencies(FragmentMap fragmentMap) {
+ fixUpLoadOrderDependenciesForTypes(fragmentMap);
+ fixUpLoadOrderDependenciesForClassLiterals(fragmentMap);
+ }
+
+ private void fixUpLoadOrderDependenciesForClassLiterals(
+ FragmentMap fragmentMap) {
+ for (JField field : fragmentMap.fields.keySet()) {
+ JClassLiteral classLit = fieldToLiteralOfClass.get(field);
+ if (classLit != null) {
+ int classLitFrag = fragmentMap.fields.get(field);
+ if (classLitFrag != 0) {
+ for (String string : stringsIn(field.getInitializer())) {
+ int stringFrag = getOrZero(fragmentMap.strings, string);
+ if (stringFrag != classLitFrag && stringFrag != 0) {
+ fragmentMap.strings.put(string, 0);
+ }
+ }
+ }
+ }
+ }
+ }
+
+ private void fixUpLoadOrderDependenciesForTypes(FragmentMap fragmentMap)
{
+ Queue<JReferenceType> typesToCheck = new
ArrayBlockingQueue<JReferenceType>(
+ jprogram.getDeclaredTypes().size());
+ typesToCheck.addAll(jprogram.getDeclaredTypes());
+ while (!typesToCheck.isEmpty()) {
+ JReferenceType type = typesToCheck.remove();
+ if (type.extnds != null) {
+ int typeFrag = getOrZero(fragmentMap.types, type);
+ int supertypeFrag = getOrZero(fragmentMap.types, type.extnds);
+ if (typeFrag != supertypeFrag && supertypeFrag != 0) {
+ fragmentMap.types.put(type.extnds, 0);
+ typesToCheck.add(type.extnds);
+ }
+ }
+ }
+ }
+
private void mapExclusiveAtoms(FragmentMap fragmentMap) {
List<ControlFlowAnalyzer> allButOnes = computeAllButOneCfas();
+
ControlFlowAnalyzer everything = computeCompleteCfa();
Set<JField> allFields = new HashSet<JField>();
@@ -285,56 +340,6 @@
}
/**
- * Make sure that all field initializers can run in their specified
fragment.
- * To do this, trace the code needed by each initializer, and make sure
it is
- * either in 0 or in the same entry point as the field itself.
- */
- private void mapFieldInitializerCode(FragmentMap fragmentMap) {
- ControlFlowAnalyzer initiallyLive = new ControlFlowAnalyzer(jprogram);
- traverseEntry(initiallyLive, 0);
- initiallyLive.finishTraversal();
-
- // Note: do split point 0 last, to account for any fields moved to it
- for (int splitPoint = numEntries - 1; splitPoint >= 0; splitPoint--) {
- ControlFlowAnalyzer neededByFields = initiallyLive.clone();
- for (JField field : fragmentMap.fields.keySet()) {
- if (fragmentMap.fields.get(field) == splitPoint) {
- if (field.getInitializer() != null) {
- neededByFields.traverseFrom(field.getInitializer());
- }
- }
- }
- neededByFields.finishTraversal();
- for (JNode node : neededByFields.getLiveFieldsAndMethods()) {
- if (node instanceof JField) {
- if (!fragmentMap.fields.containsKey(node)
- || (fragmentMap.fields.get(node) != splitPoint)) {
- fragmentMap.fields.put((JField) node, 0);
- }
- }
- if (node instanceof JMethod) {
- if (!fragmentMap.methods.containsKey(node)
- || (fragmentMap.methods.get(node) != splitPoint)) {
- fragmentMap.methods.put((JMethod) node, 0);
- }
- }
- }
- for (String string : neededByFields.getLiveStrings()) {
- if (!fragmentMap.strings.containsKey(string)
- || (fragmentMap.strings.get(string) != splitPoint)) {
- fragmentMap.strings.put(string, 0);
- }
- }
- for (JReferenceType type : neededByFields.getInstantiatedTypes()) {
- if (!fragmentMap.types.containsKey(type)
- || (fragmentMap.types.get(type) != splitPoint)) {
- fragmentMap.types.put(type, 0);
- }
- }
- }
- }
-
- /**
* Map each program atom to a fragment. Atoms are mapped to a non-zero
* fragment whenever they are known not to be needed whenever that
fragment's
* split point has not been reached. Any atoms that cannot be so mapped
are
@@ -344,10 +349,23 @@
FragmentMap fragmentMap = new FragmentMap();
mapExclusiveAtoms(fragmentMap);
- mapFieldInitializerCode(fragmentMap);
+ fixUpLoadOrderDependencies(fragmentMap);
+
return fragmentMap;
}
+ private Set<String> stringsIn(JExpression exp) {
+ final Set<String> strings = new HashSet<String>();
+ class StringFinder extends JVisitor {
+ @Override
+ public void endVisit(JStringLiteral stringLiteral, Context ctx) {
+ strings.add(stringLiteral.getValue());
+ }
+ }
+ (new StringFinder()).accept(exp);
+ return strings;
+ }
+
/**
* Traverse all code in the program except for that reachable only via
* fragment <code>frag</code>. This does not call
@@ -369,6 +387,14 @@
private void traverseEntry(ControlFlowAnalyzer cfa, int entry) {
for (JMethod entryMethod : jprogram.entryMethods.get(entry)) {
cfa.traverseFrom(entryMethod);
+ }
+ if (entry == 0) {
+ /*
+ * Include class literal factories for simplicity. It is possible to
move
+ * them out, if they are only needed by one fragment, but they are
tiny,
+ * so it does not look like it is worth the complexity in the
compiler.
+ */
+ cfa.traverseFromClassLiteralFactories();
}
}
}
Modified:
changes/spoon/runAsync/dev/core/src/com/google/gwt/dev/jjs/impl/ControlFlowAnalyzer.java
==============================================================================
---
changes/spoon/runAsync/dev/core/src/com/google/gwt/dev/jjs/impl/ControlFlowAnalyzer.java
(original)
+++
changes/spoon/runAsync/dev/core/src/com/google/gwt/dev/jjs/impl/ControlFlowAnalyzer.java
Sat Oct 18 17:16:09 2008
@@ -32,6 +32,7 @@
import com.google.gwt.dev.jjs.ast.JLocalRef;
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.JNewArray;
import com.google.gwt.dev.jjs.ast.JNewInstance;
import com.google.gwt.dev.jjs.ast.JNode;
@@ -650,15 +651,32 @@
}
/**
- * Traverse from all class literals anywhere in the program.
+ * Trace all code needed by class literal constructor expressions except
for
+ * the string literals they include. At the time of writing, these would
+ * include the factory methods for class literals.
*/
- public void traverseFromClassLiterals() {
+ public void traverseFromClassLiteralFactories() {
+ class ReplaceStringLiterals extends JModVisitor {
+ @Override
+ public void endVisit(JStringLiteral stringLiteral, Context ctx) {
+ ctx.replaceMe(program.getLiteralString(
+ stringLiteral.getSourceInfo().makeChild("remove string
literals"),
+ ""));
+ }
+ }
+
+ final JModVisitor stringLiteralReplacer = new ReplaceStringLiterals();
+ final CloneExpressionVisitor cloner = new
CloneExpressionVisitor(program);
+
class ClassLitTraverser extends JVisitor {
@Override
public void endVisit(JClassLiteral classLiteral, Context ctx) {
- rescuer.accept(classLiteral);
+ JExpression initializer = classLiteral.getField().getInitializer();
+ JExpression initializerWithoutStrings =
stringLiteralReplacer.accept(cloner.cloneExpression(initializer));
+ rescuer.accept(initializerWithoutStrings);
}
}
+
(new ClassLitTraverser()).accept(program);
}
Modified:
changes/spoon/runAsync/dev/core/src/com/google/gwt/dev/jjs/impl/FragmentExtractor.java
==============================================================================
---
changes/spoon/runAsync/dev/core/src/com/google/gwt/dev/jjs/impl/FragmentExtractor.java
(original)
+++
changes/spoon/runAsync/dev/core/src/com/google/gwt/dev/jjs/impl/FragmentExtractor.java
Sat Oct 18 17:16:09 2008
@@ -22,7 +22,6 @@
import com.google.gwt.dev.jjs.ast.JMethod;
import com.google.gwt.dev.jjs.ast.JProgram;
import com.google.gwt.dev.jjs.ast.JReferenceType;
-import com.google.gwt.dev.jjs.ast.JType;
import com.google.gwt.dev.jjs.ast.JVisitor;
import com.google.gwt.dev.js.ast.JsBinaryOperation;
import com.google.gwt.dev.js.ast.JsBinaryOperator;
@@ -143,11 +142,22 @@
}
}
- private Set<JsName> entryMethodNames;
+ public static Map<JField, JClassLiteral> buildFieldToClassLiteralMap(
+ JProgram jprogram) {
+ final Map<JField, JClassLiteral> map = new HashMap<JField,
JClassLiteral>();
+ class BuildFieldToLiteralVisitor extends JVisitor {
+ @Override
+ public void endVisit(JClassLiteral lit, Context ctx) {
+ map.put(lit.getField(), lit);
+ }
+ }
+ (new BuildFieldToLiteralVisitor()).accept(jprogram);
+ return map;
+ }
- private Map<JField, JType> fieldToLiteralOfClass;
+ private Set<JsName> entryMethodNames;
- private StatementLogger statementLogger = new NullStatementLogger();
+ private Map<JField, JClassLiteral> fieldToLiteralOfClass;
private final JProgram jprogram;
@@ -155,6 +165,8 @@
private final JavaToJavaScriptMap map;
+ private StatementLogger statementLogger = new NullStatementLogger();
+
public FragmentExtractor(JavaAndJavaScript javaAndJavaScript) {
this(javaAndJavaScript.jprogram, javaAndJavaScript.jsprogram,
javaAndJavaScript.map);
@@ -166,13 +178,13 @@
this.jsprogram = jsprogram;
this.map = map;
- buildFieldToClassLiteralMap();
+ fieldToLiteralOfClass = buildFieldToClassLiteralMap(jprogram);
buildEntryMethodSet();
}
/**
- * Add direct calls to the entry methods of the specified entry number.
- */
+ * Add direct calls to the entry methods of the specified entry
number.
+ */
public void addCallsToEntryMethods(int entry, List<JsStatement> stats) {
for (JMethod entryMethod : jprogram.entryMethods.get(entry)) {
JsName name = map.nameForMethod(entryMethod);
@@ -250,17 +262,6 @@
assert name != null;
entryMethodNames.add(name);
}
- }
-
- private void buildFieldToClassLiteralMap() {
- fieldToLiteralOfClass = new HashMap<JField, JType>();
- class BuildFieldToLiteralVisitor extends JVisitor {
- @Override
- public void endVisit(JClassLiteral lit, Context ctx) {
- fieldToLiteralOfClass.put(lit.getField(), lit.getRefType());
- }
- }
- (new BuildFieldToLiteralVisitor()).accept(jprogram);
}
/**
--~--~---------~--~----~------------~-------~--~----~
http://groups.google.com/group/Google-Web-Toolkit-Contributors
-~----------~----~----~----~------~----~------~--~---