couple fixes to make sure out-of-context nodes get all the states they need, and...
[IRC.git] / Robust / src / Analysis / Disjoint / DisjointAnalysis.java
index 94224b130a710172ff1230401d090295f028c4d2..2dbe1862a744fff0ba4fe446a1a1c2c9f97fff58 100644 (file)
@@ -11,6 +11,290 @@ import java.io.*;
 
 
 public class DisjointAnalysis {
+       
+         ///////////////////////////////////////////
+         //
+         //  Public interface to discover possible
+         //  aliases in the program under analysis
+         //
+         ///////////////////////////////////////////
+       
+         public HashSet<AllocSite>
+         getFlaggedAllocationSitesReachableFromTask(TaskDescriptor td) {
+           checkAnalysisComplete();
+           return getFlaggedAllocationSitesReachableFromTaskPRIVATE(td);
+         }
+         
+         public AllocSite getAllocationSiteFromFlatNew(FlatNew fn) {
+                   checkAnalysisComplete();
+                   return getAllocSiteFromFlatNewPRIVATE(fn);
+          }      
+         
+         public AllocSite getAllocationSiteFromHeapRegionNodeID(Integer id) {
+                   checkAnalysisComplete();
+                   return mapHrnIdToAllocSite.get(id);
+         }
+         
+         public Set<HeapRegionNode> createsPotentialAliases(Descriptor taskOrMethod,
+              int paramIndex1,
+              int paramIndex2) {
+                 checkAnalysisComplete();
+                 ReachGraph rg=mapDescriptorToCompleteReachGraph.get(taskOrMethod);
+                 FlatMethod fm=state.getMethodFlat(taskOrMethod);
+                 assert(rg != null);
+                 return rg.mayReachSharedObjects(fm, paramIndex1, paramIndex2);
+         }
+         
+       public Set<HeapRegionNode> createsPotentialAliases(Descriptor taskOrMethod,
+                       int paramIndex, AllocSite alloc) {
+               checkAnalysisComplete();
+               ReachGraph rg = mapDescriptorToCompleteReachGraph.get(taskOrMethod);
+           FlatMethod fm=state.getMethodFlat(taskOrMethod);
+               assert (rg != null);
+               return rg.mayReachSharedObjects(fm, paramIndex, alloc);
+       }
+
+       public Set<HeapRegionNode> createsPotentialAliases(Descriptor taskOrMethod,
+                       AllocSite alloc, int paramIndex) {
+               checkAnalysisComplete();
+               ReachGraph rg  = mapDescriptorToCompleteReachGraph.get(taskOrMethod);
+               FlatMethod fm=state.getMethodFlat(taskOrMethod);
+               assert (rg != null);
+               return rg.mayReachSharedObjects(fm, paramIndex, alloc);
+       }
+
+       public Set<HeapRegionNode> createsPotentialAliases(Descriptor taskOrMethod,
+                       AllocSite alloc1, AllocSite alloc2) {
+               checkAnalysisComplete();
+               ReachGraph rg  = mapDescriptorToCompleteReachGraph.get(taskOrMethod);
+               assert (rg != null);
+               return rg.mayReachSharedObjects(alloc1, alloc2);
+       }
+       
+       public String prettyPrintNodeSet(Set<HeapRegionNode> s) {
+               checkAnalysisComplete();
+
+               String out = "{\n";
+
+               Iterator<HeapRegionNode> i = s.iterator();
+               while (i.hasNext()) {
+                       HeapRegionNode n = i.next();
+
+                       AllocSite as = n.getAllocSite();
+                       if (as == null) {
+                               out += "  " + n.toString() + ",\n";
+                       } else {
+                               out += "  " + n.toString() + ": " + as.toStringVerbose()
+                                               + ",\n";
+                       }
+               }
+
+               out += "}\n";
+               return out;
+       }
+       
+       // use the methods given above to check every possible alias
+         // between task parameters and flagged allocation sites reachable
+         // from the task
+         public void writeAllAliases(String outputFile, 
+                                     String timeReport,
+                                     String justTime,
+                                     boolean tabularOutput,
+                                     int numLines
+)
+                       throws java.io.IOException {
+               checkAnalysisComplete();
+
+               BufferedWriter bw = new BufferedWriter(new FileWriter(outputFile));
+
+               if (!tabularOutput) {
+                       bw.write("Conducting ownership analysis with allocation depth = "
+                                       + allocationDepth + "\n");
+                       bw.write(timeReport + "\n");
+               }
+
+               int numAlias = 0;
+
+               // look through every task for potential aliases
+               Iterator taskItr = state.getTaskSymbolTable().getDescriptorsIterator();
+               while (taskItr.hasNext()) {
+                       TaskDescriptor td = (TaskDescriptor) taskItr.next();
+
+                       if (!tabularOutput) {
+                               bw.write("\n---------" + td + "--------\n");
+                       }
+
+                       HashSet<AllocSite> allocSites = getFlaggedAllocationSitesReachableFromTask(td);
+
+                       Set<HeapRegionNode> common;
+
+                       // for each task parameter, check for aliases with
+                       // other task parameters and every allocation site
+                       // reachable from this task
+                       boolean foundSomeAlias = false;
+
+                       FlatMethod fm = state.getMethodFlat(td);
+                       for (int i = 0; i < fm.numParameters(); ++i) {
+
+                               // for the ith parameter check for aliases to all
+                               // higher numbered parameters
+                               for (int j = i + 1; j < fm.numParameters(); ++j) {
+                                       common = createsPotentialAliases(td, i, j);
+                                       if (!common.isEmpty()) {
+                                               foundSomeAlias = true;
+                                               if (!tabularOutput) {
+                                                       bw.write("Potential alias between parameters " + i
+                                                                       + " and " + j + ".\n");
+                                                       bw.write(prettyPrintNodeSet(common) + "\n");
+                                               } else {
+                                                       ++numAlias;
+                                               }
+                                       }
+                               }
+
+                               // for the ith parameter, check for aliases against
+                               // the set of allocation sites reachable from this
+                               // task context
+                               Iterator allocItr = allocSites.iterator();
+                               while (allocItr.hasNext()) {
+                                       AllocSite as = (AllocSite) allocItr.next();
+                                       common = createsPotentialAliases(td, i, as);
+                                       if (!common.isEmpty()) {
+                                               foundSomeAlias = true;
+                                               if (!tabularOutput) {
+                                                       bw.write("Potential alias between parameter " + i
+                                                                       + " and " + as.getFlatNew() + ".\n");
+                                                       bw.write(prettyPrintNodeSet(common) + "\n");
+                                               } else {
+                                                       ++numAlias;
+                                               }
+                                       }
+                               }
+                       }
+
+                       // for each allocation site check for aliases with
+                       // other allocation sites in the context of execution
+                       // of this task
+                       HashSet<AllocSite> outerChecked = new HashSet<AllocSite>();
+                       Iterator allocItr1 = allocSites.iterator();
+                       while (allocItr1.hasNext()) {
+                               AllocSite as1 = (AllocSite) allocItr1.next();
+
+                               Iterator allocItr2 = allocSites.iterator();
+                               while (allocItr2.hasNext()) {
+                                       AllocSite as2 = (AllocSite) allocItr2.next();
+
+                                       if (!outerChecked.contains(as2)) {
+                                               common = createsPotentialAliases(td, as1, as2);
+
+                                               if (!common.isEmpty()) {
+                                                       foundSomeAlias = true;
+                                                       if (!tabularOutput) {
+                                                               bw.write("Potential alias between "
+                                                                               + as1.getFlatNew() + " and "
+                                                                               + as2.getFlatNew() + ".\n");
+                                                               bw.write(prettyPrintNodeSet(common) + "\n");
+                                                       } else {
+                                                               ++numAlias;
+                                                       }
+                                               }
+                                       }
+                               }
+
+                               outerChecked.add(as1);
+                       }
+
+                       if (!foundSomeAlias) {
+                               if (!tabularOutput) {
+                                       bw.write("No aliases between flagged objects in Task " + td
+                                                       + ".\n");
+                               }
+                       }
+               }
+
+               /*
+               if (!tabularOutput) {
+                       bw.write("\n" + computeAliasContextHistogram());
+               } else {
+                       bw.write(" & " + numAlias + " & " + justTime + " & " + numLines
+                                       + " & " + numMethodsAnalyzed() + " \\\\\n");
+               }
+               */
+
+               bw.close();
+       }
+       
+       // this version of writeAllAliases is for Java programs that have no tasks
+         public void writeAllAliasesJava(String outputFile, 
+                                         String timeReport,
+                                         String justTime,
+                                         boolean tabularOutput,
+                                         int numLines
+)
+                       throws java.io.IOException {
+               checkAnalysisComplete();
+
+               assert !state.TASK;
+
+               BufferedWriter bw = new BufferedWriter(new FileWriter(outputFile));
+
+               bw.write("Conducting ownership analysis with allocation depth = "
+                               + allocationDepth + "\n");
+               bw.write(timeReport + "\n\n");
+
+               boolean foundSomeAlias = false;
+
+               Descriptor d = typeUtil.getMain();
+               HashSet<AllocSite> allocSites = getFlaggedAllocationSites(d);
+
+               // for each allocation site check for aliases with
+               // other allocation sites in the context of execution
+               // of this task
+               HashSet<AllocSite> outerChecked = new HashSet<AllocSite>();
+               Iterator allocItr1 = allocSites.iterator();
+               while (allocItr1.hasNext()) {
+                       AllocSite as1 = (AllocSite) allocItr1.next();
+
+                       Iterator allocItr2 = allocSites.iterator();
+                       while (allocItr2.hasNext()) {
+                               AllocSite as2 = (AllocSite) allocItr2.next();
+
+                               if (!outerChecked.contains(as2)) {
+                                       Set<HeapRegionNode> common = createsPotentialAliases(d,
+                                                       as1, as2);
+
+                                       if (!common.isEmpty()) {
+                                               foundSomeAlias = true;
+                                               bw.write("Potential alias between "
+                                                               + as1.getDisjointAnalysisId() + " and "
+                                                               + as2.getDisjointAnalysisId() + ".\n");
+                                               bw.write(prettyPrintNodeSet(common) + "\n");
+                                       }
+                               }
+                       }
+
+                       outerChecked.add(as1);
+               }
+
+               if (!foundSomeAlias) {
+                       bw.write("No aliases between flagged objects found.\n");
+               }
+
+//             bw.write("\n" + computeAliasContextHistogram());
+               bw.close();
+       }
+         
+         ///////////////////////////////////////////
+         //
+         // end public interface
+         //
+         ///////////////////////////////////////////
+
+         protected void checkAnalysisComplete() {
+                   if( !analysisComplete ) {
+                     throw new Error("Warning: public interface method called while analysis is running.");
+                   }
+         } 
 
 
   // data from the compiler
@@ -20,6 +304,14 @@ public class DisjointAnalysis {
   public ArrayReferencees arrayReferencees;
   public TypeUtil         typeUtil;
   public int              allocationDepth;
+  
+  // data structure for public interface
+  private Hashtable<Descriptor,    HashSet<AllocSite> > mapDescriptorToAllocSiteSet;
+
+  
+  // for public interface methods to warn that they
+  // are grabbing results during analysis
+  private boolean analysisComplete;
 
 
   // used to identify HeapRegionNode objects
@@ -47,7 +339,26 @@ public class DisjointAnalysis {
 
   // the set of task and/or method descriptors
   // reachable in call graph
-  protected Set<Descriptor> descriptorsToAnalyze;
+  protected Set<Descriptor> 
+    descriptorsToAnalyze;
+
+  // current descriptors to visit in fixed-point
+  // interprocedural analysis, prioritized by
+  // dependency in the call graph
+  protected PriorityQueue<DescriptorQWrapper> 
+    descriptorsToVisitQ;
+  
+  // a duplication of the above structure, but
+  // for efficient testing of inclusion
+  protected HashSet<Descriptor> 
+    descriptorsToVisitSet;
+
+  // storage for priorities (doesn't make sense)
+  // to add it to the Descriptor class, just in
+  // this analysis
+  protected Hashtable<Descriptor, Integer> 
+    mapDescriptorToPriority;
+
 
   // maps a descriptor to its current partial result
   // from the intraprocedural fixed-point analysis--
@@ -74,6 +385,14 @@ public class DisjointAnalysis {
   protected Hashtable<Integer, AllocSite>
     mapHrnIdToAllocSite;
 
+  // maps a method to its initial heap model (IHM) that
+  // is the set of reachability graphs from every caller
+  // site, all merged together.  The reason that we keep
+  // them separate is that any one call site's contribution
+  // to the IHM may changed along the path to the fixed point
+  protected Hashtable< Descriptor, Hashtable< FlatCall, ReachGraph > >
+    mapDescriptorToIHMcontributions;
+
   // TODO -- CHANGE EDGE/TYPE/FIELD storage!
   public static final String arrayElementFieldName = "___element_";
   static protected Hashtable<TypeDescriptor, FieldDescriptor>
@@ -88,6 +407,10 @@ public class DisjointAnalysis {
   // unique filenames
   protected Hashtable<Descriptor, Integer>
     mapDescriptorToNumUpdates;
+  
+  //map task descriptor to initial task parameter 
+  protected Hashtable<Descriptor, ReachGraph>
+  mapDescriptorToReachGraph;
 
 
   // allocate various structures that are not local
@@ -107,32 +430,52 @@ public class DisjointAnalysis {
     mapFlatNewToAllocSite = 
       new Hashtable<FlatNew, AllocSite>();
 
+    mapDescriptorToIHMcontributions =
+      new Hashtable< Descriptor, Hashtable< FlatCall, ReachGraph > >();
+
     mapHrnIdToAllocSite =
       new Hashtable<Integer, AllocSite>();
 
     mapTypeToArrayField = 
       new Hashtable <TypeDescriptor, FieldDescriptor>();
+
+    descriptorsToVisitQ =
+      new PriorityQueue<DescriptorQWrapper>();
+
+    descriptorsToVisitSet =
+      new HashSet<Descriptor>();
+
+    mapDescriptorToPriority =
+      new Hashtable<Descriptor, Integer>();
+    
+    mapDescriptorToAllocSiteSet =
+       new Hashtable<Descriptor,    HashSet<AllocSite> >();
+    
+    mapDescriptorToReachGraph = 
+       new Hashtable<Descriptor, ReachGraph>();
   }
 
 
 
   // this analysis generates a disjoint reachability
   // graph for every reachable method in the program
-  public DisjointAnalysis( State s,
-                          TypeUtil tu,
-                          CallGraph cg,
-                          Liveness l,
+  public DisjointAnalysis( State            s,
+                          TypeUtil         tu,
+                          CallGraph        cg,
+                          Liveness         l,
                           ArrayReferencees ar
                            ) throws java.io.IOException {
     init( s, tu, cg, l, ar );
   }
   
-  protected void init( State state,
-                       TypeUtil typeUtil,
-                       CallGraph callGraph,
-                       Liveness liveness,
+  protected void init( State            state,
+                       TypeUtil         typeUtil,
+                       CallGraph        callGraph,
+                       Liveness         liveness,
                        ArrayReferencees arrayReferencees
                        ) throws java.io.IOException {
+         
+       analysisComplete = false;
     
     this.state                   = state;
     this.typeUtil                = typeUtil;
@@ -153,6 +496,7 @@ public class DisjointAnalysis {
 
     // start interprocedural fixed-point computation
     analyzeMethods();
+    analysisComplete=true;
 
     double timeEndAnalysis = (double) System.nanoTime();
     double dt = (timeEndAnalysis - timeStartAnalysis)/(Math.pow( 10.0, 9.0 ) );
@@ -161,12 +505,17 @@ public class DisjointAnalysis {
     System.out.println( treport );
 
     if( writeFinalDOTs && !writeAllIncrementalDOTs ) {
-      //writeFinalContextGraphs();      
-    }  
+      writeFinalGraphs();      
+    }
+
+    if( state.DISJOINTWRITEIHMS ) {
+      writeFinalIHMs();
+    }
 
     if( state.DISJOINTALIASFILE != null ) {
       if( state.TASK ) {
         // not supporting tasks yet...
+         writeAllAliases(state.OWNERSHIPALIASFILE, treport, justtime, state.OWNERSHIPALIASTAB, state.lines);
       } else {
         /*
         writeAllAliasesJava( aliasFile, 
@@ -190,8 +539,16 @@ public class DisjointAnalysis {
       // set of descriptors to analyze as the program-reachable
       // tasks and the methods callable by them.  For Java,
       // just methods reachable from the main method.
-      System.out.println( "No Bamboo support yet..." );
-      System.exit( -1 );
+      System.out.println( "Bamboo..." );
+      Iterator taskItr = state.getTaskSymbolTable().getDescriptorsIterator();
+      
+      while (taskItr.hasNext()) {
+         TaskDescriptor td = (TaskDescriptor) taskItr.next();
+         if (!descriptorsToAnalyze.contains(td)) {           
+             descriptorsToAnalyze.add(td);
+             descriptorsToAnalyze.addAll(callGraph.getAllMethods(td));
+         }       
+      }
 
     } else {
       // add all methods transitively reachable from the
@@ -217,15 +574,6 @@ public class DisjointAnalysis {
     // add sorted descriptors to priority queue, and duplicate
     // the queue as a set for efficiently testing whether some
     // method is marked for analysis
-    PriorityQueue<DescriptorQWrapper> descriptorsToVisitQ     
-      = new PriorityQueue<DescriptorQWrapper>();
-
-    HashSet<Descriptor> descriptorsToVisitSet
-      = new HashSet<Descriptor>();
-
-    Hashtable<Descriptor, Integer> mapDescriptorToPriority
-      = new Hashtable<Descriptor, Integer>();
-
     int p = 0;
     Iterator<Descriptor> dItr = sortedDescriptors.iterator();
     while( dItr.hasNext() ) {
@@ -254,29 +602,21 @@ public class DisjointAnalysis {
 
       ReachGraph rg     = analyzeMethod( d );
       ReachGraph rgPrev = getPartial( d );
-
+      
       if( !rg.equals( rgPrev ) ) {
         setPartial( d, rg );
 
-        // results for d changed, so queue dependents
+        // results for d changed, so enqueue dependents
         // of d for further analysis
        Iterator<Descriptor> depsItr = getDependents( d ).iterator();
        while( depsItr.hasNext() ) {
          Descriptor dNext = depsItr.next();
-
-         if( !descriptorsToVisitSet.contains( dNext ) ) {
-            Integer priority = mapDescriptorToPriority.get( dNext );
-           descriptorsToVisitQ.add( new DescriptorQWrapper( priority , 
-                                                             dNext ) 
-                                     );
-           descriptorsToVisitSet.add( dNext );
-         }
+          enqueue( dNext );
        }
       }      
     }
   }
 
-
   protected ReachGraph analyzeMethod( Descriptor d ) 
     throws java.io.IOException {
 
@@ -311,25 +651,47 @@ public class DisjointAnalysis {
       // to see if anything was updated.
 
       ReachGraph rg = new ReachGraph();
+      TaskDescriptor taskDesc;
+      if(fn instanceof FlatMethod && (taskDesc=((FlatMethod)fn).getTask())!=null){
+         if(mapDescriptorToReachGraph.containsKey(taskDesc)){
+                 // retrieve existing reach graph if it is not first time
+                 rg=mapDescriptorToReachGraph.get(taskDesc);
+         }else{
+                 // create initial reach graph for a task
+                 rg=createInitialTaskReachGraph((FlatMethod)fn);
+                 rg.globalSweep();
+                 mapDescriptorToReachGraph.put(taskDesc, rg);
+         }
+      }
 
       // start by merging all node's parents' graphs
       for( int i = 0; i < fn.numPrev(); ++i ) {
        FlatNode pn = fn.getPrev( i );
        if( mapFlatNodeToReachGraph.containsKey( pn ) ) {
          ReachGraph rgParent = mapFlatNodeToReachGraph.get( pn );
+//       System.out.println("parent="+pn+"->"+rgParent);
          rg.merge( rgParent );
        }
       }
 
+
+      if( takeDebugSnapshots && 
+         d.getSymbol().equals( descSymbolDebug ) 
+          ) {
+       debugSnapshot( rg, fn, true );
+      }
+
       // modify rg with appropriate transfer function
-      analyzeFlatNode( d, fm, fn, setReturns, rg );
-          
-      /*
+      rg = analyzeFlatNode( d, fm, fn, setReturns, rg );
+
+
       if( takeDebugSnapshots && 
-         d.getSymbol().equals( descSymbolDebug ) ) {
-       debugSnapshot(og,fn);
+         d.getSymbol().equals( descSymbolDebug ) 
+          ) {
+       debugSnapshot( rg, fn, false );
       }
-      */
+          
 
       // if the results of the new graph are different from
       // the current graph at this node, replace the graph
@@ -350,46 +712,68 @@ public class DisjointAnalysis {
     // states after the flat method returns
     ReachGraph completeGraph = new ReachGraph();
 
+    assert !setReturns.isEmpty();
     Iterator retItr = setReturns.iterator();
     while( retItr.hasNext() ) {
       FlatReturnNode frn = (FlatReturnNode) retItr.next();
+
       assert mapFlatNodeToReachGraph.containsKey( frn );
       ReachGraph rgRet = mapFlatNodeToReachGraph.get( frn );
+
       completeGraph.merge( rgRet );
     }
-    
     return completeGraph;
   }
 
   
-  protected void
-    analyzeFlatNode( Descriptor d,
-                     FlatMethod fmContaining,
-                     FlatNode fn,
+  protected ReachGraph
+    analyzeFlatNode( Descriptor              d,
+                     FlatMethod              fmContaining,
+                     FlatNode                fn,
                      HashSet<FlatReturnNode> setRetNodes,
-                     ReachGraph rg
+                     ReachGraph              rg
                      ) throws java.io.IOException {
 
     
     // any variables that are no longer live should be
     // nullified in the graph to reduce edges
-    // NOTE: it is not clear we need this.  It costs a
-    // liveness calculation for every method, so only
-    // turn it on if we find we actually need it.
-    // rg.nullifyDeadVars( liveness.getLiveInTemps( fmContaining, fn ) );
+    //rg.nullifyDeadVars( liveness.getLiveInTemps( fmContaining, fn ) );
 
          
-    TempDescriptor lhs;
-    TempDescriptor rhs;
+    TempDescriptor  lhs;
+    TempDescriptor  rhs;
     FieldDescriptor fld;
 
     // use node type to decide what transfer function
     // to apply to the reachability graph
     switch( fn.kind() ) {
 
-    case FKind.FlatMethod:
-      FlatMethod fm = (FlatMethod) fn;
-      break;
+    case FKind.FlatMethod: {
+      // construct this method's initial heap model (IHM)
+      // since we're working on the FlatMethod, we know
+      // the incoming ReachGraph 'rg' is empty
+
+      Hashtable<FlatCall, ReachGraph> heapsFromCallers = 
+        getIHMcontributions( d );
+
+      Set entrySet = heapsFromCallers.entrySet();
+      Iterator itr = entrySet.iterator();
+      while( itr.hasNext() ) {
+        Map.Entry  me        = (Map.Entry)  itr.next();
+        FlatCall   fc        = (FlatCall)   me.getKey();
+        ReachGraph rgContrib = (ReachGraph) me.getValue();
+
+        assert fc.getMethod().equals( d );
+
+        // some call sites are in same method context though,
+        // and all of them should be merged together first,
+        // then heaps from different contexts should be merged
+        // THIS ASSUMES DIFFERENT CONTEXTS NEED SPECIAL CONSIDERATION!
+        // such as, do allocation sites need to be aged?
+
+        rg.merge_diffMethodContext( rgContrib );
+      }      
+    } break;
       
     case FKind.FlatOpNode:
       FlatOpNode fon = (FlatOpNode) fn;
@@ -478,102 +862,109 @@ public class DisjointAnalysis {
       }
       break;
 
-    case FKind.FlatCall:
-      /*
-      FlatCall fc = (FlatCall) fn;
-      MethodDescriptor md = fc.getMethod();
-      FlatMethod flatm = state.getMethodFlat(md);
-      ReachGraph ogMergeOfAllPossibleCalleeResults = new ReachGraph();
-
-      if( md.isStatic() ) {
-       // a static method is simply always the same, makes life easy
-       ogMergeOfAllPossibleCalleeResults = og;
-
-       Set<Integer> aliasedParamIndices = 
-         ogMergeOfAllPossibleCalleeResults.calculateAliasedParamSet(fc, md.isStatic(), flatm);
-
-       Descriptor mcNew = new Descriptor( md, aliasedParamIndices );
-       Set contexts = mapDescriptorToAllDescriptors.get( md );
-       assert contexts != null;
-       contexts.add( mcNew );
-
-       addDependent( mc, mcNew );
-
-       ReachGraph onlyPossibleCallee = mapDescriptorToCompleteReachabilityGraph.get( mcNew );
-
-       if( onlyPossibleCallee == null ) {
-         // if this method context has never been analyzed just schedule it for analysis
-         // and skip over this call site for now
-         if( !methodContextsToVisitSet.contains( mcNew ) ) {
-           methodContextsToVisitQ.add( new DescriptorQWrapper( mapDescriptorToPriority.get( md ), 
-                                                                  mcNew ) );
-           methodContextsToVisitSet.add( mcNew );
-         }
-         
-       } else {
-         ogMergeOfAllPossibleCalleeResults.resolveMethodCall(fc, md.isStatic(), flatm, onlyPossibleCallee, mc, null);
-       }
-       
-       meAnalysis.createNewMapping(mcNew);
-       meAnalysis.analyzeFlatCall(ogMergeOfAllPossibleCalleeResults, mcNew, mc, fc);
-       
-
-      } else {
-       // if the method descriptor is virtual, then there could be a
-       // set of possible methods that will actually be invoked, so
-       // find all of them and merge all of their results together
-       TypeDescriptor typeDesc = fc.getThis().getType();
-       Set possibleCallees = callGraph.getMethods(md, typeDesc);
+    case FKind.FlatCall: {
+      //TODO: temporal fix for task descriptor case
+      //MethodDescriptor mdCaller = fmContaining.getMethod();
+      Descriptor mdCaller;
+      if(fmContaining.getMethod()!=null){
+         mdCaller  = fmContaining.getMethod();
+      }else{
+         mdCaller = fmContaining.getTask();
+      }      
+      FlatCall         fc       = (FlatCall) fn;
+      MethodDescriptor mdCallee = fc.getMethod();
+      FlatMethod       fmCallee = state.getMethodFlat( mdCallee );
+
+      boolean writeDebugDOTs = 
+        mdCaller.getSymbol().equals( state.DISJOINTDEBUGCALLER ) &&
+        mdCallee.getSymbol().equals( state.DISJOINTDEBUGCALLEE );      
+
+
+      // calculate the heap this call site can reach--note this is
+      // not used for the current call site transform, we are
+      // grabbing this heap model for future analysis of the callees,
+      // so if different results emerge we will return to this site
+      ReachGraph heapForThisCall_old = 
+        getIHMcontribution( mdCallee, fc );
+
+      // the computation of the callee-reachable heap
+      // is useful for making the callee starting point
+      // and for applying the call site transfer function
+      Set<Integer> callerNodeIDsCopiedToCallee = 
+        new HashSet<Integer>();
+
+      ReachGraph heapForThisCall_cur = 
+        rg.makeCalleeView( fc, 
+                           fmCallee,
+                           callerNodeIDsCopiedToCallee,
+                           writeDebugDOTs
+                           );
+
+      if( !heapForThisCall_cur.equals( heapForThisCall_old ) ) {        
+        // if heap at call site changed, update the contribution,
+        // and reschedule the callee for analysis
+        addIHMcontribution( mdCallee, fc, heapForThisCall_cur );        
+        enqueue( mdCallee );
+      }
 
-       Iterator i = possibleCallees.iterator();
-       while( i.hasNext() ) {
-         MethodDescriptor possibleMd = (MethodDescriptor) i.next();
-         FlatMethod pflatm = state.getMethodFlat(possibleMd);
 
-         // don't alter the working graph (og) until we compute a result for every
-         // possible callee, merge them all together, then set og to that
-         ReachGraph ogCopy = new ReachGraph();
-         ogCopy.merge(og);
 
-         Set<Integer> aliasedParamIndices = 
-           ogCopy.calculateAliasedParamSet(fc, possibleMd.isStatic(), pflatm);
 
-         Descriptor mcNew = new Descriptor( possibleMd, aliasedParamIndices );
-         Set contexts = mapDescriptorToAllDescriptors.get( md );
-         assert contexts != null;
-         contexts.add( mcNew );
-         
-               
-       meAnalysis.createNewMapping(mcNew);
-               
-         
-         addDependent( mc, mcNew );
+      // the transformation for a call site should update the
+      // current heap abstraction with any effects from the callee,
+      // or if the method is virtual, the effects from any possible
+      // callees, so find the set of callees...
+      Set<MethodDescriptor> setPossibleCallees =
+        new HashSet<MethodDescriptor>();
 
-         ReachGraph ogPotentialCallee = mapDescriptorToCompleteReachabilityGraph.get( mcNew );
+      if( mdCallee.isStatic() ) {        
+        setPossibleCallees.add( mdCallee );
+      } else {
+       TypeDescriptor typeDesc = fc.getThis().getType();
+       setPossibleCallees.addAll( callGraph.getMethods( mdCallee, 
+                                                         typeDesc )
+                                   );
+      }
 
-         if( ogPotentialCallee == null ) {
-           // if this method context has never been analyzed just schedule it for analysis
-           // and skip over this call site for now
-           if( !methodContextsToVisitSet.contains( mcNew ) ) {
-             methodContextsToVisitQ.add( new DescriptorQWrapper( mapDescriptorToPriority.get( md ), 
-                                                                    mcNew ) );
-             methodContextsToVisitSet.add( mcNew );
-           }
-           
-         } else {
-           ogCopy.resolveMethodCall(fc, possibleMd.isStatic(), pflatm, ogPotentialCallee, mc, null);
-         }
-               
-         ogMergeOfAllPossibleCalleeResults.merge(ogCopy);
-         
-         meAnalysis.analyzeFlatCall(ogMergeOfAllPossibleCalleeResults, mcNew, mc, fc);
-       }
-       
+      ReachGraph rgMergeOfEffects = new ReachGraph();
+
+      Iterator<MethodDescriptor> mdItr = setPossibleCallees.iterator();
+      while( mdItr.hasNext() ) {
+        MethodDescriptor mdPossible = mdItr.next();
+        FlatMethod       fmPossible = state.getMethodFlat( mdPossible );
+
+        addDependent( mdPossible, // callee
+                      d );        // caller
+
+        // don't alter the working graph (rg) until we compute a 
+        // result for every possible callee, merge them all together,
+        // then set rg to that
+        ReachGraph rgCopy = new ReachGraph();
+        rgCopy.merge( rg );            
+                
+        ReachGraph rgEffect = getPartial( mdPossible );
+
+        if( rgEffect == null ) {
+          // if this method has never been analyzed just schedule it 
+          // for analysis and skip over this call site for now
+          enqueue( mdPossible );
+        } else {
+          rgCopy.resolveMethodCall( fc, 
+                                    fmPossible, 
+                                    rgEffect,
+                                    callerNodeIDsCopiedToCallee,
+                                    writeDebugDOTs
+                                    );
+        }
+        
+        rgMergeOfEffects.merge( rgCopy );
       }
 
-      og = ogMergeOfAllPossibleCalleeResults;
-      */
-      break;
+
+      // now that we've taken care of building heap models for
+      // callee analysis, finish this transformation
+      rg = rgMergeOfEffects;
+    } break;
       
 
     case FKind.FlatReturnNode:
@@ -586,10 +977,20 @@ public class DisjointAnalysis {
       break;
 
     } // end switch
+
     
+    // dead variables were removed before the above transfer function
+    // was applied, so eliminate heap regions and edges that are no
+    // longer part of the abstractly-live heap graph, and sweep up
+    // and reachability effects that are altered by the reduction
+    //rg.abstractGarbageCollect();
+    //rg.globalSweep();
+
+
     // at this point rg should be the correct update
     // by an above transfer function, or untouched if
     // the flat node type doesn't affect the heap
+    return rg;
   }
 
   
@@ -617,36 +1018,64 @@ public class DisjointAnalysis {
   }
 
   
-  /*
-  private void writeFinalContextGraphs() {
-    Set entrySet = mapDescriptorToCompleteReachabilityGraph.entrySet();
+  
+  private void writeFinalGraphs() {
+    Set entrySet = mapDescriptorToCompleteReachGraph.entrySet();
     Iterator itr = entrySet.iterator();
     while( itr.hasNext() ) {
-      Map.Entry      me = (Map.Entry)      itr.next();
-      Descriptor  mc = (Descriptor)  me.getKey();
-      ReachabilityGraph og = (ReachabilityGraph) me.getValue();
-
-      try {
-       og.writeGraph(mc+"COMPLETE",
-                     true,  // write labels (variables)
-                     true,  // selectively hide intermediate temp vars
-                     true,  // prune unreachable heap regions
-                     false, // show back edges to confirm graph validity
-                     false, // show parameter indices (unmaintained!)
-                     true,  // hide subset reachability states
-                     true); // hide edge taints
+      Map.Entry  me = (Map.Entry)  itr.next();
+      Descriptor  d = (Descriptor) me.getKey();
+      ReachGraph rg = (ReachGraph) me.getValue();
+
+      try {        
+       rg.writeGraph( "COMPLETE"+d,
+                       true,   // write labels (variables)                
+                       true,   // selectively hide intermediate temp vars 
+                       true,   // prune unreachable heap regions          
+                       false,  // hide subset reachability states         
+                       true ); // hide edge taints                        
       } catch( IOException e ) {}    
     }
   }
-  
-  */
+
+  private void writeFinalIHMs() {
+    Iterator d2IHMsItr = mapDescriptorToIHMcontributions.entrySet().iterator();
+    while( d2IHMsItr.hasNext() ) {
+      Map.Entry                        me1 = (Map.Entry)                       d2IHMsItr.next();
+      Descriptor                         d = (Descriptor)                      me1.getKey();
+      Hashtable<FlatCall, ReachGraph> IHMs = (Hashtable<FlatCall, ReachGraph>) me1.getValue();
+
+      Iterator fc2rgItr = IHMs.entrySet().iterator();
+      while( fc2rgItr.hasNext() ) {
+        Map.Entry  me2 = (Map.Entry)  fc2rgItr.next();
+        FlatCall   fc  = (FlatCall)   me2.getKey();
+        ReachGraph rg  = (ReachGraph) me2.getValue();
+                
+        try {        
+          rg.writeGraph( "IHMPARTFOR"+d+"FROM"+fc,
+                         true,   // write labels (variables)
+                         false,  // selectively hide intermediate temp vars
+                         false,  // prune unreachable heap regions
+                         false,  // hide subset reachability states
+                         true ); // hide edge taints
+        } catch( IOException e ) {}    
+      }
+    }
+  }
+   
+
+
 
   // return just the allocation site associated with one FlatNew node
   protected AllocSite getAllocSiteFromFlatNewPRIVATE( FlatNew fnew ) {
 
     if( !mapFlatNewToAllocSite.containsKey( fnew ) ) {
       AllocSite as = 
-        new AllocSite( allocationDepth, fnew, fnew.getDisjointId() );
+        (AllocSite) Canonical.makeCanonical( new AllocSite( allocationDepth, 
+                                                            fnew, 
+                                                            fnew.getDisjointId() 
+                                                            )
+                                             );
 
       // the newest nodes are single objects
       for( int i = 0; i < allocationDepth; ++i ) {
@@ -656,8 +1085,7 @@ public class DisjointAnalysis {
       }
 
       // the oldest node is a summary node
-      Integer idSummary = generateUniqueHeapRegionNodeID();
-      as.setSummary( idSummary );
+      as.setSummary( generateUniqueHeapRegionNodeID() );
 
       mapFlatNewToAllocSite.put( fnew, as );
     }
@@ -845,72 +1273,7 @@ public class DisjointAnalysis {
   }
   */
 
-
-  /*
-  // insert a call to debugSnapshot() somewhere in the analysis 
-  // to get successive captures of the analysis state
-  boolean takeDebugSnapshots = false;
-  String mcDescSymbolDebug = "setRoute";
-  boolean stopAfterCapture = true;
-
-  // increments every visit to debugSnapshot, don't fiddle with it
-  // IMPORTANT NOTE FOR SETTING THE FOLLOWING VALUES: this
-  // counter increments just after every node is analyzed
-  // from the body of the method whose symbol is specified
-  // above.
-  int debugCounter = 0;
-
-  // the value of debugCounter to start reporting the debugCounter
-  // to the screen to let user know what debug iteration we're at
-  int numStartCountReport = 0;
-
-  // the frequency of debugCounter values to print out, 0 no report
-  int freqCountReport = 0;
-
-  // the debugCounter value at which to start taking snapshots
-  int iterStartCapture = 0;
-
-  // the number of snapshots to take
-  int numIterToCapture = 300;
-
-  void debugSnapshot(ReachabilityGraph og, FlatNode fn) {
-    if( debugCounter > iterStartCapture + numIterToCapture ) {
-      return;
-    }
-
-    ++debugCounter;
-    if( debugCounter > numStartCountReport &&
-       freqCountReport > 0 &&
-        debugCounter % freqCountReport == 0 ) {
-      System.out.println("    @@@ debug counter = "+debugCounter);
-    }
-    if( debugCounter > iterStartCapture ) {
-      System.out.println("    @@@ capturing debug "+(debugCounter-iterStartCapture)+" @@@");
-      String graphName = String.format("snap%04d",debugCounter-iterStartCapture);
-      if( fn != null ) {
-       graphName = graphName+fn;
-      }
-      try {
-       og.writeGraph(graphName,
-                     true,  // write labels (variables)
-                     true,  // selectively hide intermediate temp vars
-                     true,  // prune unreachable heap regions
-                     false, // show back edges to confirm graph validity
-                     false, // show parameter indices (unmaintained!)
-                     true,  // hide subset reachability states
-                     true); // hide edge taints
-      } catch( Exception e ) {
-       System.out.println("Error writing debug capture.");
-       System.exit(0);
-      }
-    }
-
-    if( debugCounter == iterStartCapture + numIterToCapture && stopAfterCapture ) {
-      System.out.println("Stopping analysis after debug captures.");
-      System.exit(0);
-    }
-  }
-  */
+  
   
   
   // Take in source entry which is the program's compiled entry and
@@ -933,29 +1296,40 @@ public class DisjointAnalysis {
                             "analysisEntryMethod"
                             );
 
-    TempDescriptor cmdLineArgs = new TempDescriptor( "args" );
-    
-    FlatNew fn = new FlatNew( mdSourceEntry.getParamType( 0 ),
-                              cmdLineArgs,
-                              false // is global 
-                              );
+    TempDescriptor cmdLineArgs = 
+      new TempDescriptor( "args",
+                          mdSourceEntry.getParamType( 0 )
+                          );
+
+    FlatNew fn = 
+      new FlatNew( mdSourceEntry.getParamType( 0 ),
+                   cmdLineArgs,
+                   false // is global 
+                   );
     
     TempDescriptor[] sourceEntryArgs = new TempDescriptor[1];
     sourceEntryArgs[0] = cmdLineArgs;
     
-    FlatCall fc = new FlatCall( mdSourceEntry,
-                                null, // dst temp
-                                null, // this temp
-                                sourceEntryArgs
-                                );
+    FlatCall fc = 
+      new FlatCall( mdSourceEntry,
+                    null, // dst temp
+                    null, // this temp
+                    sourceEntryArgs
+                    );
+
+    FlatReturnNode frn = new FlatReturnNode( null );
 
     FlatExit fe = new FlatExit();
 
-    this.fmAnalysisEntry = new FlatMethod( mdAnalysisEntry, fe );
+    this.fmAnalysisEntry = 
+      new FlatMethod( mdAnalysisEntry, 
+                      fe
+                      );
 
     this.fmAnalysisEntry.addNext( fn );
     fn.addNext( fc );
-    fc.addNext( fe );
+    fc.addNext( frn );
+    frn.addNext( fe );
   }
 
 
@@ -1029,6 +1403,17 @@ public class DisjointAnalysis {
   }
 
 
+  protected void enqueue( Descriptor d ) {
+    if( !descriptorsToVisitSet.contains( d ) ) {
+      Integer priority = mapDescriptorToPriority.get( d );
+      descriptorsToVisitQ.add( new DescriptorQWrapper( priority, 
+                                                       d ) 
+                               );
+      descriptorsToVisitSet.add( d );
+    }
+  }
+
+
   protected ReachGraph getPartial( Descriptor d ) {
     return mapDescriptorToCompleteReachGraph.get( d );
   }
@@ -1084,5 +1469,417 @@ public class DisjointAnalysis {
     return deps;
   }
 
+  
+  public Hashtable<FlatCall, ReachGraph> getIHMcontributions( Descriptor d ) {
+
+    Hashtable<FlatCall, ReachGraph> heapsFromCallers = 
+      mapDescriptorToIHMcontributions.get( d );
+    
+    if( heapsFromCallers == null ) {
+      heapsFromCallers = new Hashtable<FlatCall, ReachGraph>();
+      mapDescriptorToIHMcontributions.put( d, heapsFromCallers );
+    }
+    
+    return heapsFromCallers;
+  }
+
+  public ReachGraph getIHMcontribution( Descriptor d, 
+                                        FlatCall   fc
+                                        ) {
+    Hashtable<FlatCall, ReachGraph> heapsFromCallers = 
+      getIHMcontributions( d );
+
+    if( !heapsFromCallers.containsKey( fc ) ) {
+      heapsFromCallers.put( fc, new ReachGraph() );
+    }
+
+    return heapsFromCallers.get( fc );
+  }
+
+  public void addIHMcontribution( Descriptor d,
+                                  FlatCall   fc,
+                                  ReachGraph rg
+                                  ) {
+    Hashtable<FlatCall, ReachGraph> heapsFromCallers = 
+      getIHMcontributions( d );
+
+    heapsFromCallers.put( fc, rg );
+  }
+
+private AllocSite createParameterAllocSite(ReachGraph rg, TempDescriptor tempDesc) {
+    
+    // create temp descriptor for each parameter variable
+    FlatNew flatNew = new FlatNew(tempDesc.getType(), tempDesc, false);
+    // create allocation site
+    AllocSite as = (AllocSite) Canonical.makeCanonical(new AllocSite( allocationDepth, flatNew, flatNew.getDisjointId()));
+    for (int i = 0; i < allocationDepth; ++i) {
+       Integer id = generateUniqueHeapRegionNodeID();
+       as.setIthOldest(i, id);
+       mapHrnIdToAllocSite.put(id, as);
+    }
+    // the oldest node is a summary node
+    as.setSummary( generateUniqueHeapRegionNodeID() );
+    
+    rg.age(as);
+    
+    return as;
+    
+}
+    
+private ReachGraph createInitialTaskReachGraph(FlatMethod fm) {
+    ReachGraph rg = new ReachGraph();
+    TaskDescriptor taskDesc = fm.getTask();
+    
+    for (int idx = 0; idx < taskDesc.numParameters(); idx++) {
+       Descriptor paramDesc = taskDesc.getParameter(idx);
+       TypeDescriptor paramTypeDesc = taskDesc.getParamType(idx);
+       
+       // setup data structure
+       Set<HashMap<HeapRegionNode, FieldDescriptor>> workSet = 
+           new HashSet<HashMap<HeapRegionNode, FieldDescriptor>>();
+       Hashtable<TypeDescriptor, HeapRegionNode> mapTypeToExistingSummaryNode = 
+           new Hashtable<TypeDescriptor, HeapRegionNode>();
+       Set<String> doneSet = new HashSet<String>();
+       
+       TempDescriptor tempDesc = fm.getParameter(idx);
+       
+       AllocSite as = createParameterAllocSite(rg, tempDesc);
+       VariableNode lnX = rg.getVariableNodeFromTemp(tempDesc);
+       Integer idNewest = as.getIthOldest(0);
+       HeapRegionNode hrnNewest = rg.id2hrn.get(idNewest);
+       // make a new reference to allocated node
+       RefEdge edgeNew = new RefEdge(lnX, // source
+                                     hrnNewest, // dest
+                                     taskDesc.getParamType(idx), // type
+                                     null, // field name
+                                     hrnNewest.getAlpha(), // beta
+                                     ExistPredSet.factory(rg.predTrue) // predicates
+                                     );
+       rg.addRefEdge(lnX, hrnNewest, edgeNew);
+       
+       // set-up a work set for class field
+       ClassDescriptor classDesc = paramTypeDesc.getClassDesc();
+       for (Iterator it = classDesc.getFields(); it.hasNext();) {
+           FieldDescriptor fd = (FieldDescriptor) it.next();
+           TypeDescriptor fieldType = fd.getType();
+           if (!fieldType.isImmutable() || fieldType.isArray()) {
+               HashMap<HeapRegionNode, FieldDescriptor> newMap = new HashMap<HeapRegionNode, FieldDescriptor>();
+               newMap.put(hrnNewest, fd);
+               workSet.add(newMap);
+           }
+       }
+       
+       int uniqueIdentifier = 0;
+       while (!workSet.isEmpty()) {
+           HashMap<HeapRegionNode, FieldDescriptor> map = workSet
+               .iterator().next();
+           workSet.remove(map);
+           
+           Set<HeapRegionNode> key = map.keySet();
+           HeapRegionNode srcHRN = key.iterator().next();
+           FieldDescriptor fd = map.get(srcHRN);
+           TypeDescriptor type = fd.getType();
+           String doneSetIdentifier = srcHRN.getIDString() + "_" + fd;
+           
+           if (!doneSet.contains(doneSetIdentifier)) {
+               doneSet.add(doneSetIdentifier);
+               if (!mapTypeToExistingSummaryNode.containsKey(type)) {
+                   // create new summary Node
+                   TempDescriptor td = new TempDescriptor("temp"
+                                                          + uniqueIdentifier, type);
+                   
+                   AllocSite allocSite;
+                   if(type.equals(paramTypeDesc)){
+                   //corresponding allocsite has already been created for a parameter variable.
+                       allocSite=as;
+                   }else{
+                       allocSite = createParameterAllocSite(rg, td);
+                   }
+                   String strDesc = allocSite.toStringForDOT()
+                       + "\\nsummary";
+                   HeapRegionNode hrnSummary = 
+                       rg.createNewHeapRegionNode(allocSite.getSummary(), // id or null to generate a new one
+                                                  false, // single object?
+                                                  true, // summary?
+                                                  false, // flagged?
+                                                  false, // out-of-context?
+                                                  allocSite.getType(), // type
+                                                  allocSite, // allocation site
+                                                  null, // inherent reach
+                                                  srcHRN.getAlpha(), // current reach
+                                                  ExistPredSet.factory(), // predicates
+                                                  strDesc // description
+                                                  );
+                   rg.id2hrn.put(allocSite.getSummary(),hrnSummary);
+                   
+                   // make a new reference to summary node
+                   RefEdge edgeToSummary = new RefEdge(srcHRN, // source
+                                                       hrnSummary, // dest
+                                                       fd.getType(), // type
+                                                       fd.getSymbol(), // field name
+                                                       srcHRN.getAlpha(), // beta
+                                                       ExistPredSet.factory(rg.predTrue) // predicates
+                                                       );
+                   
+                   rg.addRefEdge(srcHRN, hrnSummary, edgeToSummary);
+                   
+                   uniqueIdentifier++;
+                   
+                   mapTypeToExistingSummaryNode.put(type, hrnSummary);
+                   
+                   // set-up a work set for  fields of the class
+                   if(!type.isImmutable()){
+                   classDesc = type.getClassDesc();                
+                   for (Iterator it = classDesc.getFields(); it.hasNext();) {
+                       FieldDescriptor typeFieldDesc = (FieldDescriptor) it.next();
+                       TypeDescriptor fieldType = typeFieldDesc.getType();
+                       if (!fieldType.isImmutable()) {
+                           doneSetIdentifier = hrnSummary.getIDString() + "_" + typeFieldDesc;                                                          
+                           if(!doneSet.contains(doneSetIdentifier)){
+                               // add new work item
+                               HashMap<HeapRegionNode, FieldDescriptor> newMap = 
+                                   new HashMap<HeapRegionNode, FieldDescriptor>();
+                               newMap.put(hrnSummary, typeFieldDesc);
+                               workSet.add(newMap);
+                           }
+                       }
+                   }
+                   }
+                   
+               }else{
+                   // if there exists corresponding summary node
+                   HeapRegionNode hrnDst=mapTypeToExistingSummaryNode.get(type);
+                   
+                   RefEdge edgeToSummary = new RefEdge(srcHRN, // source
+                                                       hrnDst, // dest
+                                                       fd.getType(), // type
+                                                       fd.getSymbol(), // field name
+                                                       srcHRN.getAlpha(), // beta
+                                                       ExistPredSet.factory(rg.predTrue) // predicates
+                                                       );
+                   rg.addRefEdge(srcHRN, hrnDst, edgeToSummary);
+                   
+               }               
+           }       
+       }           
+    }  
+//    debugSnapshot(rg, fm, true);
+    return rg;
+}
+
+// return all allocation sites in the method (there is one allocation
+// site per FlatNew node in a method)
+private HashSet<AllocSite> getAllocationSiteSet(Descriptor d) {
+  if( !mapDescriptorToAllocSiteSet.containsKey(d) ) {
+    buildAllocationSiteSet(d);
+  }
+
+  return mapDescriptorToAllocSiteSet.get(d);
+
+}
+
+private void buildAllocationSiteSet(Descriptor d) {
+    HashSet<AllocSite> s = new HashSet<AllocSite>();
+
+    FlatMethod fm;
+    if( d instanceof MethodDescriptor ) {
+      fm = state.getMethodFlat( (MethodDescriptor) d);
+    } else {
+      assert d instanceof TaskDescriptor;
+      fm = state.getMethodFlat( (TaskDescriptor) d);
+    }
+
+    // visit every node in this FlatMethod's IR graph
+    // and make a set of the allocation sites from the
+    // FlatNew node's visited
+    HashSet<FlatNode> visited = new HashSet<FlatNode>();
+    HashSet<FlatNode> toVisit = new HashSet<FlatNode>();
+    toVisit.add(fm);
+
+    while( !toVisit.isEmpty() ) {
+      FlatNode n = toVisit.iterator().next();
+
+      if( n instanceof FlatNew ) {
+       s.add(getAllocSiteFromFlatNewPRIVATE( (FlatNew) n) );
+      }
+
+      toVisit.remove(n);
+      visited.add(n);
+
+      for( int i = 0; i < n.numNext(); ++i ) {
+       FlatNode child = n.getNext(i);
+       if( !visited.contains(child) ) {
+         toVisit.add(child);
+       }
+      }
+    }
+
+    mapDescriptorToAllocSiteSet.put(d, s);
+  }
+
+       private HashSet<AllocSite> getFlaggedAllocationSites(Descriptor dIn) {
+
+               HashSet<AllocSite> out = new HashSet<AllocSite>();
+               HashSet<Descriptor> toVisit = new HashSet<Descriptor>();
+               HashSet<Descriptor> visited = new HashSet<Descriptor>();
+
+               toVisit.add(dIn);
+
+               while (!toVisit.isEmpty()) {
+                       Descriptor d = toVisit.iterator().next();
+                       toVisit.remove(d);
+                       visited.add(d);
+
+                       HashSet<AllocSite> asSet = getAllocationSiteSet(d);
+                       Iterator asItr = asSet.iterator();
+                       while (asItr.hasNext()) {
+                               AllocSite as = (AllocSite) asItr.next();
+                               if (as.getDisjointAnalysisId() != null) {
+                                       out.add(as);
+                               }
+                       }
+
+                       // enqueue callees of this method to be searched for
+                       // allocation sites also
+                       Set callees = callGraph.getCalleeSet(d);
+                       if (callees != null) {
+                               Iterator methItr = callees.iterator();
+                               while (methItr.hasNext()) {
+                                       MethodDescriptor md = (MethodDescriptor) methItr.next();
+
+                                       if (!visited.contains(md)) {
+                                               toVisit.add(md);
+                                       }
+                               }
+                       }
+               }
+
+               return out;
+       }
+    
+private HashSet<AllocSite>
+getFlaggedAllocationSitesReachableFromTaskPRIVATE(TaskDescriptor td) {
+
+  HashSet<AllocSite> asSetTotal = new HashSet<AllocSite>();
+  HashSet<Descriptor>     toVisit    = new HashSet<Descriptor>();
+  HashSet<Descriptor>     visited    = new HashSet<Descriptor>();
+
+  toVisit.add(td);
+
+  // traverse this task and all methods reachable from this task
+  while( !toVisit.isEmpty() ) {
+    Descriptor d = toVisit.iterator().next();
+    toVisit.remove(d);
+    visited.add(d);
+
+    HashSet<AllocSite> asSet = getAllocationSiteSet(d);
+    Iterator asItr = asSet.iterator();
+    while( asItr.hasNext() ) {
+       AllocSite as = (AllocSite) asItr.next();
+       TypeDescriptor typed = as.getType();
+       if( typed != null ) {
+         ClassDescriptor cd = typed.getClassDesc();
+         if( cd != null && cd.hasFlags() ) {
+           asSetTotal.add(as);
+         }
+       }
+    }
+
+    // enqueue callees of this method to be searched for
+    // allocation sites also
+    Set callees = callGraph.getCalleeSet(d);
+    if( callees != null ) {
+       Iterator methItr = callees.iterator();
+       while( methItr.hasNext() ) {
+         MethodDescriptor md = (MethodDescriptor) methItr.next();
+
+         if( !visited.contains(md) ) {
+           toVisit.add(md);
+         }
+       }
+    }
+  }
+
+  return asSetTotal;
+}
+
+
+  
+  
+  // get successive captures of the analysis state
+  boolean takeDebugSnapshots = false;
+  String descSymbolDebug = "addSomething";
+  boolean stopAfterCapture = true;
+
+  // increments every visit to debugSnapshot, don't fiddle with it
+  int debugCounter = 0;
+
+  // the value of debugCounter to start reporting the debugCounter
+  // to the screen to let user know what debug iteration we're at
+  int numStartCountReport = 0;
+
+  // the frequency of debugCounter values to print out, 0 no report
+  int freqCountReport = 0;
+
+  // the debugCounter value at which to start taking snapshots
+  int iterStartCapture = 25;
+
+  // the number of snapshots to take
+  int numIterToCapture = 300;
+
+
+  void debugSnapshot( ReachGraph rg, FlatNode fn, boolean in ) {
+    if( debugCounter > iterStartCapture + numIterToCapture ) {
+      return;
+    }
+
+    if( in ) {
+      ++debugCounter;
+    }
+
+    if( debugCounter    > numStartCountReport &&
+       freqCountReport > 0                   &&
+        debugCounter % freqCountReport == 0 
+        ) {
+      System.out.println( "    @@@ debug counter = "+
+                          debugCounter );
+    }
+
+    if( debugCounter > iterStartCapture ) {
+      System.out.println( "    @@@ capturing debug "+
+                          (debugCounter - iterStartCapture)+
+                          " @@@" );
+      String graphName;
+      if( in ) {
+        graphName = String.format( "snap%04din",
+                                   debugCounter - iterStartCapture );
+      } else {
+        graphName = String.format( "snap%04dout",
+                                   debugCounter - iterStartCapture );
+      }
+      if( fn != null ) {
+       graphName = graphName + fn;
+      }
+      try {
+       rg.writeGraph( graphName,
+                       true,  // write labels (variables)
+                       true,  // selectively hide intermediate temp vars
+                       true,  // prune unreachable heap regions
+                       false, // hide subset reachability states
+                       true );// hide edge taints
+      } catch( Exception e ) {
+       System.out.println( "Error writing debug capture." );
+       System.exit( 0 );
+      }
+    }
+
+    if( debugCounter == iterStartCapture + numIterToCapture && 
+        stopAfterCapture 
+        ) {
+      System.out.println( "Stopping analysis after debug captures." );
+      System.exit( 0 );
+    }
+  }
 
 }