Program: 53592
Project: 53592
Buggy source:
/** 
 * Given the set of code initially live, and a set of splitpoints grouped into fragments: The core algorithm to compute exclusive merged fragments is as follows: For each fragment (grouping of merged splitpoint numbers) 1) compute the set of live statements of every splitpoint EXCEPT those in the fragment 2) compute the set of live statements reachable from those in the fragment 3) calculate a set difference of everything live minus the results of step 1 4) filter results by checking for membership in the results of step 2 5) assign resulting live code to this fragment (recorded in a map) The results of these steps are then used to extract individual JavaScript chunks into blocks corresponding to fragments which are ultimately written to disk.
 * @param initiallyLive the CFA of code live from the entry point (initial fragments)
 */
private void extractStatements(ControlFlowAnalyzer initiallyLive){
  Map<Integer,List<JsStatement>> fragmentStats=new LinkedHashMap<Integer,List<JsStatement>>();
{
    LivenessPredicate alreadyLoaded=new NothingAlivePredicate();
    LivenessPredicate liveNow=new CfaLivenessPredicate(initiallyLive);
    List<JsStatement> noStats=new ArrayList<JsStatement>();
    addFragment(0,alreadyLoaded,liveNow,noStats,fragmentStats);
  }
  ControlFlowAnalyzer liveAfterInitialSequence=new ControlFlowAnalyzer(initiallyLive);
  int cacheIndex=1;
{
    for (    final int sp : initialLoadSequence) {
      splitPointToCodeIndexMap[sp]=cacheIndex;
      LivenessPredicate alreadyLoaded=new CfaLivenessPredicate(liveAfterInitialSequence);
      ControlFlowAnalyzer liveAfterSp=new ControlFlowAnalyzer(liveAfterInitialSequence);
      JRunAsync runAsync=jprogram.getRunAsyncs().get(sp - 1);
      liveAfterSp.traverseFromRunAsync(runAsync);
      LivenessPredicate liveNow=new CfaLivenessPredicate(liveAfterSp);
      List<JsStatement> statsToAppend=fragmentExtractor.createOnLoadedCall(cacheIndex);
      addFragment(sp,alreadyLoaded,liveNow,statsToAppend,fragmentStats);
      liveAfterInitialSequence=liveAfterSp;
      cacheIndex++;
    }
  }
  ControlFlowAnalyzer everything=computeCompleteCfa();
  Set<JField> allFields=new HashSet<JField>();
  Set<JMethod> allMethods=new HashSet<JMethod>();
  for (  JNode node : everything.getLiveFieldsAndMethods()) {
    if (node instanceof JField) {
      allFields.add((JField)node);
    }
    if (node instanceof JMethod) {
      allMethods.add((JMethod)node);
    }
  }
  allFields.addAll(everything.getFieldsWritten());
  ArrayList<JsStatement> leftOverMergeStats=new ArrayList<JsStatement>();
  for (int i=1; i < splitPointToFragmentMap.length; i++) {
    ArrayList<Integer> splitPoints=new ArrayList<Integer>();
    if (splitPointToFragmentMap[i] != i) {
      continue;
    }
    if (initialLoadSequence.contains(i)) {
      continue;
    }
    splitPoints.add(i);
    splitPointToCodeIndexMap[i]=cacheIndex;
    for (int j=i + 1; j < splitPointToFragmentMap.length; j++) {
      if (initialLoadSequence.contains(j)) {
        continue;
      }
      if (splitPointToFragmentMap[j] == i) {
        splitPointToCodeIndexMap[j]=cacheIndex;
        splitPoints.add(j);
      }
    }
    ControlFlowAnalyzer allButOne=computeAllButNCfas(liveAfterInitialSequence,splitPoints);
    ControlFlowAnalyzer allFromSplitPoints=computeAllLiveFromSplitPoints(liveAfterInitialSequence,splitPoints);
    Set<JNode> allLiveNodes=union(allButOne.getLiveFieldsAndMethods(),allButOne.getFieldsWritten());
    Set<JNode> allLiveFromSplitPoints=union(allFromSplitPoints.getLiveFieldsAndMethods(),allFromSplitPoints.getFieldsWritten());
    updateReverseMap(i,fragmentMap.fields,allLiveNodes,allFields,allLiveFromSplitPoints);
    updateReverseMap(i,fragmentMap.methods,allButOne.getLiveFieldsAndMethods(),allMethods,allFromSplitPoints.getLiveFieldsAndMethods());
    updateReverseMap(i,fragmentMap.strings,allButOne.getLiveStrings(),everything.getLiveStrings(),allFromSplitPoints.getLiveStrings());
    updateReverseMap(i,fragmentMap.types,declaredTypesIn(allButOne.getInstantiatedTypes()),declaredTypesIn(everything.getInstantiatedTypes()),declaredTypesIn(allFromSplitPoints.getInstantiatedTypes()));
    if (splitPointToFragmentMap[i] != i) {
      continue;
    }
    if (initialLoadSequence.contains(i)) {
      continue;
    }
    LivenessPredicate alreadyLoaded=new ExclusivityMapLivenessPredicate(fragmentMap,0);
    LivenessPredicate liveNow=new ExclusivityMapLivenessPredicate(fragmentMap,i);
    List<JsStatement> exclusiveStats=fragmentExtractor.extractStatements(liveNow,alreadyLoaded);
    if (fragmentSizeBelowMergeLimit(exclusiveStats,leftOverMergeLimit)) {
      leftOverMergeStats.addAll(exclusiveStats);
      splitPointToFragmentMap[i]=-1;
      continue;
    }
 else {
      List<JsStatement> statsToAppend=fragmentExtractor.createOnLoadedCall(cacheIndex);
      addFragment(i,alreadyLoaded,liveNow,statsToAppend,fragmentStats);
    }
    cacheIndex++;
  }
  for (int i=0; i < splitPointToFragmentMap.length; i++) {
    if (splitPointToFragmentMap[i] == -1) {
      splitPointToFragmentMap[i]=splitPointToFragmentMap.length;
    }
  }
{
    LivenessPredicate alreadyLoaded=new CfaLivenessPredicate(liveAfterInitialSequence);
    LivenessPredicate liveNow=new ExclusivityMapLivenessPredicate(fragmentMap,0);
    List<JsStatement> statsToAppend=fragmentExtractor.createOnLoadedCall(cacheIndex);
    leftOverMergeStats.addAll(statsToAppend);
    addFragment(splitPointToFragmentMap.length,alreadyLoaded,liveNow,leftOverMergeStats,fragmentStats);
  }
  jsprogram.setFragmentCount(fragmentStats.size());
  int count=0;
  for (  int i : fragmentStats.keySet()) {
    JsBlock fragBlock=jsprogram.getFragmentBlock(count++);
    fragBlock.getStatements().clear();
    fragBlock.getStatements().addAll(fragmentStats.get(i));
  }
  jprogram.setFragmentPartitioningResult(new FragmentPartitioningResult(splitPointToCodeIndexMap,fragmentStats.size()));
}

Fixed version (ground truth):
/** 
 * Given the set of code initially live, and a set of splitpoints grouped into fragments: The core algorithm to compute exclusive merged fragments is as follows: For each fragment (grouping of merged splitpoint numbers) 1) compute the set of live statements of every splitpoint EXCEPT those in the fragment 2) compute the set of live statements reachable from those in the fragment 3) calculate a set difference of everything live minus the results of step 1 4) filter results by checking for membership in the results of step 2 5) assign resulting live code to this fragment (recorded in a map) The results of these steps are then used to extract individual JavaScript chunks into blocks corresponding to fragments which are ultimately written to disk.
 * @param initiallyLive the CFA of code live from the entry point (initial fragments)
 */
private void extractStatements(ControlFlowAnalyzer initiallyLive){
  Map<Integer,List<JsStatement>> fragmentStats=new LinkedHashMap<Integer,List<JsStatement>>();
{
    LivenessPredicate alreadyLoaded=new NothingAlivePredicate();
    LivenessPredicate liveNow=new CfaLivenessPredicate(initiallyLive);
    List<JsStatement> noStats=new ArrayList<JsStatement>();
    addFragment(0,alreadyLoaded,liveNow,noStats,fragmentStats);
  }
  ControlFlowAnalyzer liveAfterInitialSequence=new ControlFlowAnalyzer(initiallyLive);
  String extendsCfa="String_Node_Str";
  int cacheIndex=1;
{
    for (    final int sp : initialLoadSequence) {
      splitPointToCodeIndexMap[sp]=cacheIndex;
      String depGraphName="String_Node_Str" + cacheIndex;
      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);
      liveAfterInitialSequence=liveAfterSp;
      cacheIndex++;
    }
  }
  ControlFlowAnalyzer everything=computeCompleteCfa();
  Set<JField> allFields=new HashSet<JField>();
  Set<JMethod> allMethods=new HashSet<JMethod>();
  for (  JNode node : everything.getLiveFieldsAndMethods()) {
    if (node instanceof JField) {
      allFields.add((JField)node);
    }
    if (node instanceof JMethod) {
      allMethods.add((JMethod)node);
    }
  }
  allFields.addAll(everything.getFieldsWritten());
  ArrayList<JsStatement> leftOverMergeStats=new ArrayList<JsStatement>();
  for (int i=1; i < splitPointToFragmentMap.length; i++) {
    ArrayList<Integer> splitPoints=new ArrayList<Integer>();
    if (splitPointToFragmentMap[i] != i) {
      continue;
    }
    if (initialLoadSequence.contains(i)) {
      continue;
    }
    splitPoints.add(i);
    splitPointToCodeIndexMap[i]=cacheIndex;
    for (int j=i + 1; j < splitPointToFragmentMap.length; j++) {
      if (initialLoadSequence.contains(j)) {
        continue;
      }
      if (splitPointToFragmentMap[j] == i) {
        splitPointToCodeIndexMap[j]=cacheIndex;
        splitPoints.add(j);
      }
    }
    dependencyRecorder.startDependencyGraph("String_Node_Str" + cacheIndex,extendsCfa);
    ControlFlowAnalyzer allButOne=computeAllButNCfas(liveAfterInitialSequence,splitPoints,dependencyRecorder);
    dependencyRecorder.endDependencyGraph();
    ControlFlowAnalyzer allFromSplitPoints=computeAllLiveFromSplitPoints(liveAfterInitialSequence,splitPoints);
    Set<JNode> allLiveNodes=union(allButOne.getLiveFieldsAndMethods(),allButOne.getFieldsWritten());
    Set<JNode> allLiveFromSplitPoints=union(allFromSplitPoints.getLiveFieldsAndMethods(),allFromSplitPoints.getFieldsWritten());
    updateReverseMap(i,fragmentMap.fields,allLiveNodes,allFields,allLiveFromSplitPoints);
    updateReverseMap(i,fragmentMap.methods,allButOne.getLiveFieldsAndMethods(),allMethods,allFromSplitPoints.getLiveFieldsAndMethods());
    updateReverseMap(i,fragmentMap.strings,allButOne.getLiveStrings(),everything.getLiveStrings(),allFromSplitPoints.getLiveStrings());
    updateReverseMap(i,fragmentMap.types,declaredTypesIn(allButOne.getInstantiatedTypes()),declaredTypesIn(everything.getInstantiatedTypes()),declaredTypesIn(allFromSplitPoints.getInstantiatedTypes()));
    if (splitPointToFragmentMap[i] != i) {
      continue;
    }
    if (initialLoadSequence.contains(i)) {
      continue;
    }
    LivenessPredicate alreadyLoaded=new ExclusivityMapLivenessPredicate(fragmentMap,0);
    LivenessPredicate liveNow=new ExclusivityMapLivenessPredicate(fragmentMap,i);
    List<JsStatement> exclusiveStats=fragmentExtractor.extractStatements(liveNow,alreadyLoaded);
    if (fragmentSizeBelowMergeLimit(exclusiveStats,leftOverMergeLimit)) {
      leftOverMergeStats.addAll(exclusiveStats);
      splitPointToFragmentMap[i]=-1;
      continue;
    }
 else {
      List<JsStatement> statsToAppend=fragmentExtractor.createOnLoadedCall(cacheIndex);
      addFragment(i,alreadyLoaded,liveNow,statsToAppend,fragmentStats);
    }
    cacheIndex++;
  }
  for (int i=0; i < splitPointToFragmentMap.length; i++) {
    if (splitPointToFragmentMap[i] == -1) {
      splitPointToFragmentMap[i]=splitPointToFragmentMap.length;
    }
  }
{
    LivenessPredicate alreadyLoaded=new CfaLivenessPredicate(liveAfterInitialSequence);
    LivenessPredicate liveNow=new ExclusivityMapLivenessPredicate(fragmentMap,0);
    List<JsStatement> statsToAppend=fragmentExtractor.createOnLoadedCall(cacheIndex);
    leftOverMergeStats.addAll(statsToAppend);
    addFragment(splitPointToFragmentMap.length,alreadyLoaded,liveNow,leftOverMergeStats,fragmentStats);
  }
  jsprogram.setFragmentCount(fragmentStats.size());
  int count=0;
  for (  int i : fragmentStats.keySet()) {
    JsBlock fragBlock=jsprogram.getFragmentBlock(count++);
    fragBlock.getStatements().clear();
    fragBlock.getStatements().addAll(fragmentStats.get(i));
  }
  jprogram.setFragmentPartitioningResult(new FragmentPartitioningResult(splitPointToCodeIndexMap,fragmentStats.size()));
}