Reduce the number of classes in the preamble.
1) Limit the preamble to the reachable control flow from
Class.createForClass.
2) Do not artificially consider all JSOs, JsTypes live when
computing the preamble classes.
Change-Id: I856f4070246ebd685464fee81f76f0be56d209dc
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 5ea9fdd..fb1c9e2 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
@@ -742,6 +742,10 @@
return Collections.unmodifiableCollection(indexedMethods.values());
}
+ public JMethod getIndexedMethodOrNull(String string) {
+ return indexedMethods.get(string);
+ }
+
public JDeclaredType getIndexedType(String string) {
JDeclaredType type = indexedTypes.get(string);
if (type == null) {
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 2d363c3..ca82868 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
@@ -92,19 +92,6 @@
private class RescueVisitor extends JVisitor {
private final List<JMethod> curMethodStack = Lists.newArrayList();
- private RescueVisitor() {
- /*
- * Rescue any types that would have been rescued by JCastOperation/JInstanceOf
- * after normalization.
- */
- if (rescuedViaCast != null) {
- for (JReferenceType type : rescuedViaCast) {
- rescue(type, true, true);
- }
- rescuedViaCast.clear();
- }
- }
-
@Override
public boolean visit(JArrayType type, Context ctx) {
assert (referencedTypes.contains(type));
@@ -955,7 +942,6 @@
private final JProgram program;
private Set<JReferenceType> referencedTypes = Sets.newHashSet();
private final RescueVisitor rescuer;
- private final Set<JReferenceType> rescuedViaCast = Sets.newHashSet();
private final JMethod runAsyncOnsuccess;
private JMethod stringValueOfChar = null;
@@ -987,7 +973,6 @@
runAsyncOnsuccess = program.getIndexedMethod("RunAsyncCallback.onSuccess");
getClassField = program.getIndexedField("Object.___clazz");
getClassMethod = program.getIndexedMethod("Object.getClass");
- rescuedViaCast.addAll(program.typeOracle.getInstantiatedJsoTypesViaCast());
buildMethodsOverriding();
rescuer = new RescueVisitor();
}
@@ -1026,6 +1011,20 @@
}
/**
+ * Forcibly rescue {@code typesToRescue}.
+ * <p>
+ * NOTE: this is used to rescue types that are made live by operations (e.g. casts) that
+ * have been eliminated by a normalization pass.
+ */
+ public void rescue(Iterable<JReferenceType> typesToRescue) {
+ // TODO(rluble): this functionality should go away, the AST should contain all the information
+ // needed to determine whether a type is live or not.
+ for (JReferenceType type : typesToRescue) {
+ rescuer.rescue(type, true, true);
+ }
+ }
+
+ /**
* Specify the {@link DependencyRecorder} to be used for future traversals.
* Specifying <code>null</code> means to stop recording dependencies.
*/
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 5248548..8dc98f8 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
@@ -1901,18 +1901,17 @@
if (program.isReferenceOnly(program.getIndexedType("Class"))) {
return Collections.emptyList();
}
- // Include in the preamble all classes that are reachable for Class.createForClass and
- // Class.createForEnum that are not JSOs nor interfaces.
+ // Include in the preamble all classes that are reachable for Class.createForClass,
+ // Class.createForInterface
SortedSet<JDeclaredType> reachableClasses =
- computeReachableTypes(program.getTypeClassLiteralHolder().getClinitMethod());
+ computeReachableTypes(METHODS_PROVIDED_BY_PREAMBLE);
assert !modularCompile || checkCoreModulePreambleComplete(program,
program.getTypeClassLiteralHolder().getClinitMethod());
- // TODO(stalcup): modify CFA to not artificially add all JSOs.
Set<JDeclaredType> orderedPreambleClasses = Sets.newLinkedHashSet();
for (JDeclaredType type : reachableClasses) {
- if (typeOracle.isJavaScriptObject(type) || alreadyProcessedTypes.contains(type)) {
+ if (alreadyProcessedTypes.contains(type)) {
continue;
}
insertInTopologicalOrder(type, orderedPreambleClasses);
@@ -1941,9 +1940,7 @@
}
}.accept(classLiteralInitMethod);
- for (String createForMethodName : ImmutableList.of(
- "Class.createForClass", "Class.createForPrimitive", "Class.createForInterface",
- "Class.createForEnum")) {
+ for (String createForMethodName : METHODS_PROVIDED_BY_PREAMBLE) {
if (!calledMethods.contains(program.getIndexedMethod(createForMethodName))) {
return false;
}
@@ -1952,14 +1949,21 @@
}
/**
- * Computes the set of types whose methods or fields are reachable from {@code method}.
+ * Computes the set of types whose methods or fields are reachable from {@code methods}.
*/
- private SortedSet<JDeclaredType> computeReachableTypes(JMethod method) {
+ private SortedSet<JDeclaredType> computeReachableTypes(Iterable<String> methodNames) {
ControlFlowAnalyzer cfa = new ControlFlowAnalyzer(program);
- cfa.traverseFrom(method);
+ for (String methodName : methodNames) {
+ JMethod method = program.getIndexedMethodOrNull(methodName);
+ // Only traverse it if it has not been pruned.
+ if (method != null) {
+ cfa.traverseFrom(method);
+ }
+ }
// Get the list of enclosing classes that were not excluded.
- SortedSet<JDeclaredType> reachableTypes = ImmutableSortedSet.copyOf(HasName.BY_NAME_COMPARATOR,
+ SortedSet<JDeclaredType> reachableTypes =
+ ImmutableSortedSet.copyOf(HasName.BY_NAME_COMPARATOR,
Iterables.filter(
Iterables.transform(cfa.getLiveFieldsAndMethods(),
new Function<JNode, JDeclaredType>() {
@@ -3264,6 +3268,10 @@
}
}
+ private static final ImmutableList<String> METHODS_PROVIDED_BY_PREAMBLE = ImmutableList.of(
+ "Class.createForClass", "Class.createForPrimitive", "Class.createForInterface",
+ "Class.createForEnum");
+
private final Map<JBlock, JsCatch> catchMap = Maps.newIdentityHashMap();
private final Set<JsName> catchParamIdentifiers = Sets.newHashSet();
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 038dd65..89bbd58 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
@@ -611,6 +611,11 @@
OptimizerStats stats = new OptimizerStats(NAME);
ControlFlowAnalyzer livenessAnalyzer = new ControlFlowAnalyzer(program);
+ // Don't prune JSOs, JsTypes that were considered instantiated before removing
+ // casts at {@link ImplementCastsAndTypeChecks}.
+ // TODO(rluble): the AST should have been left in a state that whatever method, attribute, etc
+ // from a JSO, JsType needs to be live, should have been already reachable from the AST.
+ livenessAnalyzer.rescue(program.typeOracle.getInstantiatedJsoTypesViaCast());
livenessAnalyzer.setForPruning();
// SPECIAL: Immortal codegen types are never pruned