Fixes most issues with the SoyC reports.
Applied an unsubmitted patch (http://gwt-code-reviews.appspot.com/1726803/)
by Alan and added a few fixes. Will show incorrect inforamtion on atoms pulled to leftover by the
latest safety check. A full refactor is needed and will be done when the new Fragment Merging
strategy is implemented.
Change-Id: I950ebd7b367671446e3d919a00be24d4cbf3fa88
Review-Link: https://gwt-review.googlesource.com/#/c/1610/
diff --git a/dev/core/src/com/google/gwt/dev/jjs/impl/CodeSplitter2.java b/dev/core/src/com/google/gwt/dev/jjs/impl/CodeSplitter2.java
index 897464d..4b6543a 100644
--- a/dev/core/src/com/google/gwt/dev/jjs/impl/CodeSplitter2.java
+++ b/dev/core/src/com/google/gwt/dev/jjs/impl/CodeSplitter2.java
@@ -90,7 +90,6 @@
* TODO(acleung): Figure out how to integrate with SOYC and dependency tracker.
* TODO(acleung): Insert SpeedTracer calls at performance sensitive places.
* TODO(acleung): Insert logger calls to generate meaningful logs.
- * TODO(acleung): May be add back the old heuristics if needed.
*/
public class CodeSplitter2 {
@@ -109,9 +108,6 @@
private FragmentPartitioningResult(int[] splitPointToFragmentMap, int numFragments) {
this.splitPointToFragmentMap = splitPointToFragmentMap;
fragmentToSplitPoint = new int[numFragments];
- for (int i = 0, len = splitPointToFragmentMap.length - 1; i < len; i++) {
- System.out.println("splitPointToFragmentMap[" + i + "] = " + splitPointToFragmentMap[i]);
- }
for (int i = 1, len = splitPointToFragmentMap.length - 1; i < len; i++) {
if (fragmentToSplitPoint[splitPointToFragmentMap[i]] == 0) {
fragmentToSplitPoint[splitPointToFragmentMap[i]] = i;
@@ -310,6 +306,7 @@
return;
}
Event codeSplitterEvent = SpeedTracerLogger.start(CompilerEventType.CODE_SPLITTER);
+ dependencyRecorder.open();
new CodeSplitter2(
logger, jprogram, jsprogram, map, fragmentsToMerge,
dependencyRecorder, leftOverMergeLimit).execImpl();
@@ -608,8 +605,8 @@
* @param liveFromSplitPoint everything live from the split point, including leftovers
* @param <T> the type of node (field, method, etc) in the map
*/
- private static <T> void updateReverseMap(int splitPoint, Map<T, Integer> map, Set<?> liveWithoutEntry,
- Iterable<T> all, Set<?> liveFromSplitPoint) {
+ private static <T> void updateReverseMap(int splitPoint, Map<T, Integer> map,
+ Set<?> liveWithoutEntry, Iterable<T> all, Set<?> liveFromSplitPoint) {
for (T each : all) {
if (!liveWithoutEntry.contains(each)) {
/*
@@ -629,7 +626,9 @@
}
ExclusivityMap fragmentMap = new ExclusivityMap();
-
+
+ private MultipleDependencyGraphRecorder dependencyRecorder;
+
private final Map<JField, JClassLiteral> fieldToLiteralOfClass;
private FragmentExtractor fragmentExtractor;
@@ -683,6 +682,7 @@
this.jsprogram = jsprogram;
this.splitPointsMerge = splitPointsMerge;
this.leftOverMergeLimit = leftOverMergeLimit;
+ this.dependencyRecorder = dependencyRecorder;
this.fragmentExtractor = new FragmentExtractor(jprogram, jsprogram, map);
this.initialLoadSequence = new LinkedHashSet<Integer>(jprogram.getSplitPointInitialSequence());
@@ -819,10 +819,12 @@
private static class MergeLimitExceededException extends RuntimeException {
}
- private ControlFlowAnalyzer computeAllButNCfas(
- ControlFlowAnalyzer liveAfterInitialSequence, List<Integer> sp) {
+ private ControlFlowAnalyzer computeAllButNCfas(ControlFlowAnalyzer liveAfterInitialSequence,
+ List<Integer> sp, ControlFlowAnalyzer.DependencyRecorder dependencyRecorder) {
List<ControlFlowAnalyzer> allButOnes = new ArrayList<ControlFlowAnalyzer>();
ControlFlowAnalyzer cfa = new ControlFlowAnalyzer(liveAfterInitialSequence);
+ cfa.setDependencyRecorder(dependencyRecorder);
+
for (JRunAsync otherRunAsync : jprogram.getRunAsyncs()) {
if (isInitial(otherRunAsync.getSplitPoint())) {
continue;
@@ -832,6 +834,7 @@
}
cfa.traverseFromRunAsync(otherRunAsync);
}
+
return cfa;
}
@@ -843,25 +846,29 @@
*/
private ControlFlowAnalyzer computeAllLiveFromSplitPoints(
ControlFlowAnalyzer liveAfterInitialSequence, List<Integer> splitPoints) {
- ControlFlowAnalyzer cfa = new ControlFlowAnalyzer(liveAfterInitialSequence);
- for (JRunAsync otherRunAsync : jprogram.getRunAsyncs()) {
- if (isInitial(otherRunAsync.getSplitPoint())) {
- continue;
- }
- if (!splitPoints.contains(otherRunAsync.getSplitPoint())) {
- continue;
- }
- cfa.traverseFromRunAsync(otherRunAsync);
- }
- return cfa;
- }
+ ControlFlowAnalyzer cfa = new ControlFlowAnalyzer(liveAfterInitialSequence);
+
+ for (JRunAsync otherRunAsync : jprogram.getRunAsyncs()) {
+ if (isInitial(otherRunAsync.getSplitPoint())) {
+ continue;
+ }
+ if (!splitPoints.contains(otherRunAsync.getSplitPoint())) {
+ continue;
+ }
+ cfa.traverseFromRunAsync(otherRunAsync);
+ }
+ return cfa;
+ }
/**
* Compute a CFA that covers the entire live code of the program.
*/
private ControlFlowAnalyzer computeCompleteCfa() {
+ dependencyRecorder.startDependencyGraph("total", null);
ControlFlowAnalyzer everything = new ControlFlowAnalyzer(jprogram);
+ everything.setDependencyRecorder(dependencyRecorder);
everything.traverseEverything();
+ dependencyRecorder.endDependencyGraph();
return everything;
}
@@ -909,7 +916,7 @@
partitionFragments();
// Step #6: Extract fragments using the partition algorithm.
- extractStatements(computeInitiallyLive(jprogram, CodeSplitter.NULL_RECORDER));
+ extractStatements(computeInitiallyLive(jprogram, dependencyRecorder));
// Step #7: Replaces the splitpoint number with the new fragment number.
replaceFragmentId();
@@ -941,16 +948,27 @@
}
ControlFlowAnalyzer liveAfterInitialSequence = new ControlFlowAnalyzer(initiallyLive);
+ String extendsCfa = "initial";
int cacheIndex = 1;
// Initial Split Point.
{
for (final int sp : initialLoadSequence) {
- splitPointToCodeIndexMap[sp] = cacheIndex;
+ splitPointToCodeIndexMap[sp] = cacheIndex;
+ String depGraphName = "sp" + cacheIndex;
+
+ // Records dependency Graph.
+ dependencyRecorder.startDependencyGraph(depGraphName, extendsCfa);
+ extendsCfa = depGraphName;
+
LivenessPredicate alreadyLoaded = new CfaLivenessPredicate(liveAfterInitialSequence);
ControlFlowAnalyzer liveAfterSp = new ControlFlowAnalyzer(liveAfterInitialSequence);
JRunAsync runAsync = jprogram.getRunAsyncs().get(sp - 1);
+
+ liveAfterSp.setDependencyRecorder(dependencyRecorder);
liveAfterSp.traverseFromRunAsync(runAsync);
+ dependencyRecorder.endDependencyGraph();
+
LivenessPredicate liveNow = new CfaLivenessPredicate(liveAfterSp);
List<JsStatement> statsToAppend = fragmentExtractor.createOnLoadedCall(cacheIndex);
addFragment(sp, alreadyLoaded, liveNow, statsToAppend, fragmentStats);
@@ -1003,8 +1021,15 @@
}
}
- ControlFlowAnalyzer allButOne = computeAllButNCfas(liveAfterInitialSequence, splitPoints);
- ControlFlowAnalyzer allFromSplitPoints = computeAllLiveFromSplitPoints(liveAfterInitialSequence, splitPoints);
+ dependencyRecorder.startDependencyGraph("sp" + cacheIndex, extendsCfa);
+ ControlFlowAnalyzer allButOne =
+ computeAllButNCfas(liveAfterInitialSequence, splitPoints, dependencyRecorder);
+ dependencyRecorder.endDependencyGraph();
+
+ // TODO(rluble): the dependency recorder wont capture atoms that are not in the current
+ // fragment due to the fact that they are not live here.
+ ControlFlowAnalyzer allFromSplitPoints = computeAllLiveFromSplitPoints(
+ liveAfterInitialSequence, splitPoints);
Set<JNode> allLiveNodes =
union(allButOne.getLiveFieldsAndMethods(), allButOne.getFieldsWritten());
@@ -1083,7 +1108,8 @@
fixUpLoadOrderDependenciesForFieldsInitializedToStrings(fragmentMap, splitPoint);
}
- private void fixUpLoadOrderDependenciesForClassLiterals(LiveSplitPointMap fragmentMap, int splitPoint) {
+ private void fixUpLoadOrderDependenciesForClassLiterals(LiveSplitPointMap fragmentMap,
+ int splitPoint) {
int numClassLitStrings = 0;
int numFixups = 0;
for (JField field : fragmentMap.fields.keySet()) {
@@ -1107,7 +1133,8 @@
}
}
- private void fixUpLoadOrderDependenciesForFieldsInitializedToStrings(LiveSplitPointMap fragmentMap, int splitPoint) {
+ private void fixUpLoadOrderDependenciesForFieldsInitializedToStrings(
+ LiveSplitPointMap fragmentMap, int splitPoint) {
int numFixups = 0;
int numFieldStrings = 0;
@@ -1125,6 +1152,7 @@
}
}
}
+
private void fixUpLoadOrderDependenciesForMethods(LiveSplitPointMap fragmentMap, int splitPoint) {
int numFixups = 0;
diff --git a/dev/core/test/com/google/gwt/dev/jjs/impl/CodeSplitter2Test.java b/dev/core/test/com/google/gwt/dev/jjs/impl/CodeSplitter2Test.java
index 9d64fa5..70eaa5e 100644
--- a/dev/core/test/com/google/gwt/dev/jjs/impl/CodeSplitter2Test.java
+++ b/dev/core/test/com/google/gwt/dev/jjs/impl/CodeSplitter2Test.java
@@ -28,7 +28,9 @@
import com.google.gwt.dev.javac.testing.impl.MockJavaResource;
import com.google.gwt.dev.jjs.JavaAstConstructor;
import com.google.gwt.dev.jjs.JsOutputOption;
+import com.google.gwt.dev.jjs.ast.JMethod;
import com.google.gwt.dev.jjs.ast.JProgram;
+import com.google.gwt.dev.jjs.impl.CodeSplitter.MultipleDependencyGraphRecorder;
import com.google.gwt.dev.js.ast.JsBlock;
import com.google.gwt.dev.js.ast.JsContext;
import com.google.gwt.dev.js.ast.JsFunction;
@@ -36,6 +38,7 @@
import com.google.gwt.dev.js.ast.JsProgram;
import com.google.gwt.dev.js.ast.JsVisitor;
+import java.util.ArrayList;
import java.util.Map;
import java.util.TreeMap;
@@ -43,6 +46,28 @@
* Unit test for {@link CodeSplitter2}.
*/
public class CodeSplitter2Test extends JJSTestBase {
+
+ /**
+ * A {@link MultipleDependencyGraphRecorder} that does nothing.
+ */
+ private static final MultipleDependencyGraphRecorder NULL_RECORDER =
+ new MultipleDependencyGraphRecorder() {
+ public void close() {
+ }
+
+ public void endDependencyGraph() {
+ }
+
+ public void methodIsLiveBecause(JMethod liveMethod, ArrayList<JMethod> dependencyChain) {
+ }
+
+ public void open() {
+ }
+
+ public void startDependencyGraph(String name, String extnds) {
+ }
+ };
+
// These will be the functions that are shared between fragments. This unit test will
// be based for finding these function in the proper fragments.
private final String functionA = "public static void functionA() {}";
@@ -50,7 +75,6 @@
private final String functionC = "public static void functionC() {}";
private final String functionD = "public static void functionD() {}";
-
// Compilation Configuration Properties.
private BindingProperty stackMode = new BindingProperty("compiler.stackMode");
private BindingProperty[] orderedProps = {stackMode};
@@ -273,7 +297,7 @@
JavaToJavaScriptMap map = GenerateJavaScriptAST.exec(
jProgram, jsProgram, JsOutputOption.PRETTY, symbolTable, new PropertyOracle[]{
new StaticPropertyOracle(orderedProps, orderedPropValues, configProps)}).getLeft();
- CodeSplitter2.exec(logger, jProgram, jsProgram, map, 4, null, 0);
+ CodeSplitter2.exec(logger, jProgram, jsProgram, map, 4, NULL_RECORDER, 0);
}
/**
@@ -304,7 +328,7 @@
JavaToJavaScriptMap map = GenerateJavaScriptAST.exec(
jProgram, jsProgram, JsOutputOption.PRETTY, symbolTable, new PropertyOracle[]{
new StaticPropertyOracle(orderedProps, orderedPropValues, configProps)}).getLeft();
- CodeSplitter2.exec(logger, jProgram, jsProgram, map, 4, null,
+ CodeSplitter2.exec(logger, jProgram, jsProgram, map, 4, NULL_RECORDER,
mergeLimit);
}