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);
   }