Fixes CodeSplitter to address a third load-order
dependency: instance methods cannot be loaded
before their enclosing type is loaded.
Review by: bobv (TBR)
git-svn-id: https://google-web-toolkit.googlecode.com/svn/trunk@3983 8db76d5a-ed1c-0410-87a9-c151d255dfc7
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 63cd8ea..d0e5e1f 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
@@ -91,9 +91,8 @@
JsFunction func = (JsFunction) expr;
if (func.getName() != null) {
JMethod method = map.nameToMethod(func.getName());
- if (method != null && method.getEnclosingType() != null) {
- System.out.println(method.getEnclosingType().getName() + "."
- + JProgram.getJsniSig(method));
+ if (method != null) {
+ System.out.println(fullNameString(method));
}
}
}
@@ -212,6 +211,11 @@
new CodeSplitter(logger, jprogram, jsprogram, map).execImpl();
}
+ private static String fullNameString(JMethod method) {
+ return method.getEnclosingType().getName() + "."
+ + JProgram.getJsniSig(method);
+ }
+
private static <T> int getOrZero(Map<T, Integer> map, T key) {
Integer value = map.get(key);
return (value == null) ? 0 : value;
@@ -245,6 +249,7 @@
private final TreeLogger logger;
private final boolean logging;
private JavaToJavaScriptMap map;
+ private final Set<JMethod> methodsInJavaScript;
private final int numEntries;
private CodeSplitter(TreeLogger logger, JProgram jprogram,
@@ -263,6 +268,8 @@
initiallyLive = new ControlFlowAnalyzer(jprogram);
traverseEntry(initiallyLive, 0);
initiallyLive.finishTraversal();
+
+ methodsInJavaScript = fragmentExtractor.findAllMethodsInJavaScript();
}
/**
@@ -318,6 +325,7 @@
for (int entry = 0; entry < numEntries; entry++) {
traverseEntry(everything, entry);
}
+ everything.traverseFromLeftoversFragmentHasLoaded();
everything.finishTraversal();
return everything;
}
@@ -399,6 +407,7 @@
* dependencies to fragment 0, so they are sure to be available.
*/
private void fixUpLoadOrderDependencies(FragmentMap fragmentMap) {
+ fixUpLoadOrderDependenciesForMethods(fragmentMap);
fixUpLoadOrderDependenciesForTypes(fragmentMap);
fixUpLoadOrderDependenciesForClassLiterals(fragmentMap);
}
@@ -433,14 +442,48 @@
}
/**
- * The setup code for a class cannot be loaded before the setup code for its
- * superclass.
+ * Fixes up the load-order dependencies from instance methods to their
+ * enclosing types.
+ */
+ private void fixUpLoadOrderDependenciesForMethods(FragmentMap fragmentMap) {
+ int numFixups = 0;
+
+ for (JReferenceType type : jprogram.getDeclaredTypes()) {
+ int typeFrag = getOrZero(fragmentMap.types, type);
+
+ if (typeFrag != 0) {
+ /*
+ * If the type is in an exclusive fragment, all its instance methods
+ * must be in the same one.
+ */
+ for (JMethod method : type.methods) {
+ if (!method.isStatic() && methodsInJavaScript.contains(method)) {
+ int methodFrag = getOrZero(fragmentMap.methods, method);
+ if (methodFrag != typeFrag) {
+ fragmentMap.types.put(type, 0);
+ numFixups++;
+ break;
+ }
+ }
+ }
+ }
+ }
+
+ logger.log(TreeLogger.DEBUG,
+ "Fixed up load-order dependencies for instance methods by moving "
+ + numFixups + " types to fragment 0, out of "
+ + jprogram.getDeclaredTypes().size());
+ }
+
+ /**
+ * Fixes up load order dependencies from types to their supertypes.
*/
private void fixUpLoadOrderDependenciesForTypes(FragmentMap fragmentMap) {
int numFixups = 0;
Queue<JReferenceType> typesToCheck = new ArrayBlockingQueue<JReferenceType>(
jprogram.getDeclaredTypes().size());
typesToCheck.addAll(jprogram.getDeclaredTypes());
+
while (!typesToCheck.isEmpty()) {
JReferenceType type = typesToCheck.remove();
if (type.extnds != null) {
@@ -453,9 +496,11 @@
}
}
}
- logger.log(TreeLogger.DEBUG, "Fixed up load-order dependencies by moving "
- + numFixups + " types to fragment 0, out of "
- + jprogram.getDeclaredTypes().size());
+
+ logger.log(TreeLogger.DEBUG,
+ "Fixed up load-order dependencies on supertypes by moving " + numFixups
+ + " types to fragment 0, out of "
+ + jprogram.getDeclaredTypes().size());
}
/**
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 3f9df05..a3a75eb 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
@@ -270,6 +270,24 @@
return extractedStats;
}
+ /**
+ * Find all Java methods that still exist in the resulting JavaScript, even
+ * after JavaScript inlining and pruning.
+ */
+ public Set<JMethod> findAllMethodsInJavaScript() {
+ Set<JMethod> methodsInJs = new HashSet<JMethod>();
+ for (int frag = 0; frag < jsprogram.getFragmentCount(); frag++) {
+ List<JsStatement> stats = jsprogram.getFragmentBlock(frag).getStatements();
+ for (JsStatement stat : stats) {
+ JMethod method = methodFor(stat);
+ if (method != null) {
+ methodsInJs.add(method);
+ }
+ }
+ }
+ return methodsInJs;
+ }
+
public void setStatementLogger(StatementLogger logger) {
statementLogger = logger;
}
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 c06573a..a05cb76 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
@@ -301,12 +301,9 @@
// my global name
JsName globalName;
- if (x.getEnclosingType() == null) {
- globalName = topScope.declareName(name);
- } else {
- String mangleName = mangleNameForGlobal(x);
- globalName = topScope.declareName(mangleName, name);
- }
+ assert x.getEnclosingType() != null;
+ String mangleName = mangleNameForGlobal(x);
+ globalName = topScope.declareName(mangleName, name);
names.put(x, globalName);
JsFunction jsFunction;
@@ -1964,9 +1961,6 @@
GenerateJavaScriptVisitor generator = new GenerateJavaScriptVisitor();
generator.accept(program);
final Map<JsName, JMethod> nameToMethodMap = new HashMap<JsName, JMethod>();
- for (JAbstractMethodBody body : methodBodyMap.keySet()) {
- nameToMethodMap.put(methodBodyMap.get(body).getName(), body.getMethod());
- }
final HashMap<JsName, JField> nameToFieldMap = new HashMap<JsName, JField>();
final HashMap<JsName, JReferenceType> constructorNameToTypeMap = new HashMap<JsName, JReferenceType>();
for (JReferenceType type : program.getDeclaredTypes()) {
@@ -1982,6 +1976,12 @@
}
}
}
+ for (JMethod method : type.methods) {
+ JsName methodName = names.get(method);
+ if (methodName != null) {
+ nameToMethodMap.put(methodName, method);
+ }
+ }
}
// TODO(spoon): Instead of gathering the information here, get it via