e43a39304b1b5b2826002e3aa30cfd3aa491c4d6
[IRC.git] / Robust / src / Analysis / Disjoint / DisjointAnalysis.java
1 package Analysis.Disjoint;
2
3 import Analysis.CallGraph.*;
4 import Analysis.Liveness;
5 import Analysis.ArrayReferencees;
6 import Analysis.OoOJava.RBlockRelationAnalysis;
7 import Analysis.OoOJava.RBlockStatusAnalysis;
8 import IR.*;
9 import IR.Flat.*;
10 import IR.Tree.Modifiers;
11 import java.util.*;
12 import java.io.*;
13
14
15 public class DisjointAnalysis {
16         
17           ///////////////////////////////////////////
18           //
19           //  Public interface to discover possible
20           //  aliases in the program under analysis
21           //
22           ///////////////////////////////////////////
23         
24           public HashSet<AllocSite>
25           getFlaggedAllocationSitesReachableFromTask(TaskDescriptor td) {
26             checkAnalysisComplete();
27             return getFlaggedAllocationSitesReachableFromTaskPRIVATE(td);
28           }
29           
30           public AllocSite getAllocationSiteFromFlatNew(FlatNew fn) {
31                     checkAnalysisComplete();
32                     return getAllocSiteFromFlatNewPRIVATE(fn);
33            }      
34           
35           public AllocSite getAllocationSiteFromHeapRegionNodeID(Integer id) {
36                     checkAnalysisComplete();
37                     return mapHrnIdToAllocSite.get(id);
38           }
39           
40           public Set<HeapRegionNode> hasPotentialSharing(Descriptor taskOrMethod,
41               int paramIndex1,
42               int paramIndex2) {
43                   checkAnalysisComplete();
44                   ReachGraph rg=mapDescriptorToCompleteReachGraph.get(taskOrMethod);
45                   FlatMethod fm=state.getMethodFlat(taskOrMethod);
46                   assert(rg != null);
47                   return rg.mayReachSharedObjects(fm, paramIndex1, paramIndex2);
48           }
49           
50         public Set<HeapRegionNode> hasPotentialSharing(Descriptor taskOrMethod,
51                         int paramIndex, AllocSite alloc) {
52                 checkAnalysisComplete();
53                 ReachGraph rg = mapDescriptorToCompleteReachGraph.get(taskOrMethod);
54             FlatMethod fm=state.getMethodFlat(taskOrMethod);
55                 assert (rg != null);
56                 return rg.mayReachSharedObjects(fm, paramIndex, alloc);
57         }
58
59         public Set<HeapRegionNode> hasPotentialSharing(Descriptor taskOrMethod,
60                         AllocSite alloc, int paramIndex) {
61                 checkAnalysisComplete();
62                 ReachGraph rg  = mapDescriptorToCompleteReachGraph.get(taskOrMethod);
63                 FlatMethod fm=state.getMethodFlat(taskOrMethod);
64                 assert (rg != null);
65                 return rg.mayReachSharedObjects(fm, paramIndex, alloc);
66         }
67
68         public Set<HeapRegionNode> hasPotentialSharing(Descriptor taskOrMethod,
69                         AllocSite alloc1, AllocSite alloc2) {
70                 checkAnalysisComplete();
71                 ReachGraph rg  = mapDescriptorToCompleteReachGraph.get(taskOrMethod);
72                 assert (rg != null);
73                 return rg.mayReachSharedObjects(alloc1, alloc2);
74         }
75         
76         public String prettyPrintNodeSet(Set<HeapRegionNode> s) {
77                 checkAnalysisComplete();
78
79                 String out = "{\n";
80
81                 Iterator<HeapRegionNode> i = s.iterator();
82                 while (i.hasNext()) {
83                         HeapRegionNode n = i.next();
84
85                         AllocSite as = n.getAllocSite();
86                         if (as == null) {
87                                 out += "  " + n.toString() + ",\n";
88                         } else {
89                                 out += "  " + n.toString() + ": " + as.toStringVerbose()
90                                                 + ",\n";
91                         }
92                 }
93
94                 out += "}\n";
95                 return out;
96         }
97         
98   // use the methods given above to check every possible sharing class
99   // between task parameters and flagged allocation sites reachable
100   // from the task
101   public void writeAllSharing(String outputFile, 
102                               String timeReport,
103                               String justTime,
104                               boolean tabularOutput,
105                               int numLines
106                               )
107     throws java.io.IOException {
108     checkAnalysisComplete();
109
110     BufferedWriter bw = new BufferedWriter(new FileWriter(outputFile));
111
112     if (!tabularOutput) {
113       bw.write("Conducting ownership analysis with allocation depth = "
114                + allocationDepth + "\n");
115       bw.write(timeReport + "\n");
116     }
117
118     int numSharing = 0;
119
120     // look through every task for potential sharing
121     Iterator taskItr = state.getTaskSymbolTable().getDescriptorsIterator();
122     while (taskItr.hasNext()) {
123       TaskDescriptor td = (TaskDescriptor) taskItr.next();
124
125       if (!tabularOutput) {
126         bw.write("\n---------" + td + "--------\n");
127       }
128
129       HashSet<AllocSite> allocSites = getFlaggedAllocationSitesReachableFromTask(td);
130
131       Set<HeapRegionNode> common;
132
133       // for each task parameter, check for sharing classes with
134       // other task parameters and every allocation site
135       // reachable from this task
136       boolean foundSomeSharing = false;
137
138       FlatMethod fm = state.getMethodFlat(td);
139       for (int i = 0; i < fm.numParameters(); ++i) {
140
141         // skip parameters with types that cannot reference
142         // into the heap
143         if( !shouldAnalysisTrack( fm.getParameter( i ).getType() ) ) {
144           continue;
145         }
146                           
147         // for the ith parameter check for sharing classes to all
148         // higher numbered parameters
149         for (int j = i + 1; j < fm.numParameters(); ++j) {
150
151           // skip parameters with types that cannot reference
152           // into the heap
153           if( !shouldAnalysisTrack( fm.getParameter( j ).getType() ) ) {
154             continue;
155           }
156
157
158           common = hasPotentialSharing(td, i, j);
159           if (!common.isEmpty()) {
160             foundSomeSharing = true;
161             ++numSharing;
162             if (!tabularOutput) {
163               bw.write("Potential sharing between parameters " + i
164                        + " and " + j + ".\n");
165               bw.write(prettyPrintNodeSet(common) + "\n");
166             }
167           }
168         }
169
170         // for the ith parameter, check for sharing classes against
171         // the set of allocation sites reachable from this
172         // task context
173         Iterator allocItr = allocSites.iterator();
174         while (allocItr.hasNext()) {
175           AllocSite as = (AllocSite) allocItr.next();
176           common = hasPotentialSharing(td, i, as);
177           if (!common.isEmpty()) {
178             foundSomeSharing = true;
179             ++numSharing;
180             if (!tabularOutput) {
181               bw.write("Potential sharing between parameter " + i
182                        + " and " + as.getFlatNew() + ".\n");
183               bw.write(prettyPrintNodeSet(common) + "\n");
184             }
185           }
186         }
187       }
188
189       // for each allocation site check for sharing classes with
190       // other allocation sites in the context of execution
191       // of this task
192       HashSet<AllocSite> outerChecked = new HashSet<AllocSite>();
193       Iterator allocItr1 = allocSites.iterator();
194       while (allocItr1.hasNext()) {
195         AllocSite as1 = (AllocSite) allocItr1.next();
196
197         Iterator allocItr2 = allocSites.iterator();
198         while (allocItr2.hasNext()) {
199           AllocSite as2 = (AllocSite) allocItr2.next();
200
201           if (!outerChecked.contains(as2)) {
202             common = hasPotentialSharing(td, as1, as2);
203
204             if (!common.isEmpty()) {
205               foundSomeSharing = true;
206               ++numSharing;
207               if (!tabularOutput) {
208                 bw.write("Potential sharing between "
209                          + as1.getFlatNew() + " and "
210                          + as2.getFlatNew() + ".\n");
211                 bw.write(prettyPrintNodeSet(common) + "\n");
212               }
213             }
214           }
215         }
216
217         outerChecked.add(as1);
218       }
219
220       if (!foundSomeSharing) {
221         if (!tabularOutput) {
222           bw.write("No sharing between flagged objects in Task " + td
223                    + ".\n");
224         }
225       }
226     }
227
228                 
229     if (tabularOutput) {
230       bw.write(" & " + numSharing + " & " + justTime + " & " + numLines
231                + " & " + numMethodsAnalyzed() + " \\\\\n");
232     } else {
233       bw.write("\nNumber sharing classes: "+numSharing);
234     }
235
236     bw.close();
237   }
238         
239   // this version of writeAllSharing is for Java programs that have no tasks
240   public void writeAllSharingJava(String outputFile, 
241                                   String timeReport,
242                                   String justTime,
243                                   boolean tabularOutput,
244                                   int numLines
245                                   )
246     throws java.io.IOException {
247     checkAnalysisComplete();
248
249     assert !state.TASK;
250
251     int numSharing = 0;
252
253     BufferedWriter bw = new BufferedWriter(new FileWriter(outputFile));
254     
255     bw.write("Conducting disjoint reachability analysis with allocation depth = "
256              + allocationDepth + "\n");
257     bw.write(timeReport + "\n\n");
258
259     boolean foundSomeSharing = false;
260
261     Descriptor d = typeUtil.getMain();
262     HashSet<AllocSite> allocSites = getFlaggedAllocationSites(d);
263
264     // for each allocation site check for sharing classes with
265     // other allocation sites in the context of execution
266     // of this task
267     HashSet<AllocSite> outerChecked = new HashSet<AllocSite>();
268     Iterator allocItr1 = allocSites.iterator();
269     while (allocItr1.hasNext()) {
270       AllocSite as1 = (AllocSite) allocItr1.next();
271
272       Iterator allocItr2 = allocSites.iterator();
273       while (allocItr2.hasNext()) {
274         AllocSite as2 = (AllocSite) allocItr2.next();
275
276         if (!outerChecked.contains(as2)) {
277           Set<HeapRegionNode> common = hasPotentialSharing(d,
278                                                            as1, as2);
279
280           if (!common.isEmpty()) {
281             foundSomeSharing = true;
282             bw.write("Potential sharing between "
283                      + as1.getDisjointAnalysisId() + " and "
284                      + as2.getDisjointAnalysisId() + ".\n");
285             bw.write(prettyPrintNodeSet(common) + "\n");
286             ++numSharing;
287           }
288         }
289       }
290
291       outerChecked.add(as1);
292     }
293
294     if (!foundSomeSharing) {
295       bw.write("No sharing classes between flagged objects found.\n");
296     } else {
297       bw.write("\nNumber sharing classes: "+numSharing);
298     }
299
300     bw.write("Number of methods analyzed: "+numMethodsAnalyzed()+"\n");
301
302     bw.close();
303   }
304           
305   ///////////////////////////////////////////
306   //
307   // end public interface
308   //
309   ///////////////////////////////////////////
310
311   protected void checkAnalysisComplete() {
312     if( !analysisComplete ) {
313       throw new Error("Warning: public interface method called while analysis is running.");
314     }
315   } 
316
317
318   // run in faster mode, only when bugs wrung out!
319   public static boolean releaseMode;
320
321   // use command line option to set this, analysis
322   // should attempt to be deterministic
323   public static boolean determinismDesired;
324
325   // when we want to enforce determinism in the 
326   // analysis we need to sort descriptors rather
327   // than toss them in efficient sets, use this
328   public static DescriptorComparator dComp =
329     new DescriptorComparator();
330
331
332   // data from the compiler
333   public State            state;
334   public CallGraph        callGraph;
335   public Liveness         liveness;
336   public ArrayReferencees arrayReferencees;
337   public RBlockRelationAnalysis rblockRel;
338   public RBlockStatusAnalysis rblockStatus;
339   public TypeUtil         typeUtil;
340   public int              allocationDepth;
341
342   protected boolean doEffectsAnalysis = false;
343   protected EffectsAnalysis effectsAnalysis;
344   
345   // data structure for public interface
346   private Hashtable< Descriptor, HashSet<AllocSite> > 
347     mapDescriptorToAllocSiteSet;
348
349   
350   // for public interface methods to warn that they
351   // are grabbing results during analysis
352   private boolean analysisComplete;
353
354
355   // used to identify HeapRegionNode objects
356   // A unique ID equates an object in one
357   // ownership graph with an object in another
358   // graph that logically represents the same
359   // heap region
360   // start at 10 and increment to reserve some
361   // IDs for special purposes
362   static protected int uniqueIDcount = 10;
363
364
365   // An out-of-scope method created by the
366   // analysis that has no parameters, and
367   // appears to allocate the command line
368   // arguments, then invoke the source code's
369   // main method.  The purpose of this is to
370   // provide the analysis with an explicit
371   // top-level context with no parameters
372   protected MethodDescriptor mdAnalysisEntry;
373   protected FlatMethod       fmAnalysisEntry;
374
375   // main method defined by source program
376   protected MethodDescriptor mdSourceEntry;
377
378   // the set of task and/or method descriptors
379   // reachable in call graph
380   protected Set<Descriptor> 
381     descriptorsToAnalyze;
382
383   // current descriptors to visit in fixed-point
384   // interprocedural analysis, prioritized by
385   // dependency in the call graph
386   protected Stack<Descriptor>
387     descriptorsToVisitStack;
388   protected PriorityQueue<DescriptorQWrapper> 
389     descriptorsToVisitQ;
390   
391   // a duplication of the above structure, but
392   // for efficient testing of inclusion
393   protected HashSet<Descriptor> 
394     descriptorsToVisitSet;
395
396   // storage for priorities (doesn't make sense)
397   // to add it to the Descriptor class, just in
398   // this analysis
399   protected Hashtable<Descriptor, Integer> 
400     mapDescriptorToPriority;
401
402   // when analyzing a method and scheduling more:
403   // remember set of callee's enqueued for analysis
404   // so they can be put on top of the callers in
405   // the stack-visit mode
406   protected Set<Descriptor>
407     calleesToEnqueue;
408
409   // maps a descriptor to its current partial result
410   // from the intraprocedural fixed-point analysis--
411   // then the interprocedural analysis settles, this
412   // mapping will have the final results for each
413   // method descriptor
414   protected Hashtable<Descriptor, ReachGraph> 
415     mapDescriptorToCompleteReachGraph;
416
417   // maps a descriptor to its known dependents: namely
418   // methods or tasks that call the descriptor's method
419   // AND are part of this analysis (reachable from main)
420   protected Hashtable< Descriptor, Set<Descriptor> >
421     mapDescriptorToSetDependents;
422
423   // maps each flat new to one analysis abstraction
424   // allocate site object, these exist outside reach graphs
425   protected Hashtable<FlatNew, AllocSite>
426     mapFlatNewToAllocSite;
427
428   // maps intergraph heap region IDs to intergraph
429   // allocation sites that created them, a redundant
430   // structure for efficiency in some operations
431   protected Hashtable<Integer, AllocSite>
432     mapHrnIdToAllocSite;
433
434   // maps a method to its initial heap model (IHM) that
435   // is the set of reachability graphs from every caller
436   // site, all merged together.  The reason that we keep
437   // them separate is that any one call site's contribution
438   // to the IHM may changed along the path to the fixed point
439   protected Hashtable< Descriptor, Hashtable< FlatCall, ReachGraph > >
440     mapDescriptorToIHMcontributions;
441
442   // additionally, keep a mapping from descriptors to the
443   // merged in-coming initial context, because we want this
444   // initial context to be STRICTLY MONOTONIC
445   protected Hashtable<Descriptor, ReachGraph>
446     mapDescriptorToInitialContext;
447
448   // make the result for back edges analysis-wide STRICTLY
449   // MONOTONIC as well, but notice we use FlatNode as the
450   // key for this map: in case we want to consider other
451   // nodes as back edge's in future implementations
452   protected Hashtable<FlatNode, ReachGraph>
453     mapBackEdgeToMonotone;
454
455
456   public static final String arrayElementFieldName = "___element_";
457   static protected Hashtable<TypeDescriptor, FieldDescriptor>
458     mapTypeToArrayField;
459
460   // for controlling DOT file output
461   protected boolean writeFinalDOTs;
462   protected boolean writeAllIncrementalDOTs;
463
464   // supporting DOT output--when we want to write every
465   // partial method result, keep a tally for generating
466   // unique filenames
467   protected Hashtable<Descriptor, Integer>
468     mapDescriptorToNumUpdates;
469   
470   //map task descriptor to initial task parameter 
471   protected Hashtable<Descriptor, ReachGraph>
472     mapDescriptorToReachGraph;
473
474   protected PointerMethod pm;
475
476   static protected Hashtable<FlatNode, ReachGraph> fn2rg =
477     new Hashtable<FlatNode, ReachGraph>();
478
479   private Hashtable<FlatCall, Descriptor> fc2enclosing;  
480
481
482   // allocate various structures that are not local
483   // to a single class method--should be done once
484   protected void allocateStructures() {
485     
486     if( determinismDesired ) {
487       // use an ordered set
488       descriptorsToAnalyze = new TreeSet<Descriptor>( dComp );      
489     } else {
490       // otherwise use a speedy hashset
491       descriptorsToAnalyze = new HashSet<Descriptor>();
492     }
493
494     mapDescriptorToCompleteReachGraph =
495       new Hashtable<Descriptor, ReachGraph>();
496
497     mapDescriptorToNumUpdates =
498       new Hashtable<Descriptor, Integer>();
499
500     mapDescriptorToSetDependents =
501       new Hashtable< Descriptor, Set<Descriptor> >();
502
503     mapFlatNewToAllocSite = 
504       new Hashtable<FlatNew, AllocSite>();
505
506     mapDescriptorToIHMcontributions =
507       new Hashtable< Descriptor, Hashtable< FlatCall, ReachGraph > >();
508
509     mapDescriptorToInitialContext =
510       new Hashtable<Descriptor, ReachGraph>();    
511
512     mapBackEdgeToMonotone =
513       new Hashtable<FlatNode, ReachGraph>();
514     
515     mapHrnIdToAllocSite =
516       new Hashtable<Integer, AllocSite>();
517
518     mapTypeToArrayField = 
519       new Hashtable <TypeDescriptor, FieldDescriptor>();
520
521     if( state.DISJOINTDVISITSTACK ||
522         state.DISJOINTDVISITSTACKEESONTOP 
523         ) {
524       descriptorsToVisitStack =
525         new Stack<Descriptor>();
526     }
527
528     if( state.DISJOINTDVISITPQUE ) {
529       descriptorsToVisitQ =
530         new PriorityQueue<DescriptorQWrapper>();
531     }
532
533     descriptorsToVisitSet =
534       new HashSet<Descriptor>();
535
536     mapDescriptorToPriority =
537       new Hashtable<Descriptor, Integer>();
538     
539     calleesToEnqueue = 
540       new HashSet<Descriptor>();    
541
542     mapDescriptorToAllocSiteSet =
543         new Hashtable<Descriptor,    HashSet<AllocSite> >();
544     
545     mapDescriptorToReachGraph = 
546         new Hashtable<Descriptor, ReachGraph>();
547
548     pm = new PointerMethod();
549
550     fc2enclosing = new Hashtable<FlatCall, Descriptor>();
551   }
552
553
554
555   // this analysis generates a disjoint reachability
556   // graph for every reachable method in the program
557   public DisjointAnalysis( State            s,
558                            TypeUtil         tu,
559                            CallGraph        cg,
560                            Liveness         l,
561                            ArrayReferencees ar,
562                            RBlockRelationAnalysis rra,
563                            RBlockStatusAnalysis rsa
564                            ) {
565     init( s, tu, cg, l, ar, rra, rsa );
566   }
567   
568   protected void init( State            state,
569                        TypeUtil         typeUtil,
570                        CallGraph        callGraph,
571                        Liveness         liveness,
572                        ArrayReferencees arrayReferencees,
573                        RBlockRelationAnalysis rra,
574                        RBlockStatusAnalysis rsa
575                        ) {
576           
577     analysisComplete = false;
578     
579     this.state                   = state;
580     this.typeUtil                = typeUtil;
581     this.callGraph               = callGraph;
582     this.liveness                = liveness;
583     this.arrayReferencees        = arrayReferencees;
584     this.rblockRel               = rra;
585     this.rblockStatus         = rsa;
586
587     if( rblockRel != null ) {
588       doEffectsAnalysis = true;
589       effectsAnalysis   = new EffectsAnalysis();
590     }
591
592     this.allocationDepth         = state.DISJOINTALLOCDEPTH;
593     this.releaseMode             = state.DISJOINTRELEASEMODE;
594     this.determinismDesired      = state.DISJOINTDETERMINISM;
595
596     this.writeFinalDOTs          = state.DISJOINTWRITEDOTS && !state.DISJOINTWRITEALL;
597     this.writeAllIncrementalDOTs = state.DISJOINTWRITEDOTS &&  state.DISJOINTWRITEALL;
598
599     this.takeDebugSnapshots      = state.DISJOINTSNAPSYMBOL != null;
600     this.descSymbolDebug         = state.DISJOINTSNAPSYMBOL;
601     this.visitStartCapture       = state.DISJOINTSNAPVISITTOSTART;
602     this.numVisitsToCapture      = state.DISJOINTSNAPNUMVISITS;
603     this.stopAfterCapture        = state.DISJOINTSNAPSTOPAFTER;
604     this.snapVisitCounter        = 1; // count visits from 1 (user will write 1, means 1st visit)
605     this.snapNodeCounter         = 0; // count nodes from 0
606
607     assert
608       state.DISJOINTDVISITSTACK ||
609       state.DISJOINTDVISITPQUE  ||
610       state.DISJOINTDVISITSTACKEESONTOP;
611     assert !(state.DISJOINTDVISITSTACK && state.DISJOINTDVISITPQUE);
612     assert !(state.DISJOINTDVISITSTACK && state.DISJOINTDVISITSTACKEESONTOP);
613     assert !(state.DISJOINTDVISITPQUE  && state.DISJOINTDVISITSTACKEESONTOP);
614             
615     // set some static configuration for ReachGraphs
616     ReachGraph.allocationDepth = allocationDepth;
617     ReachGraph.typeUtil        = typeUtil;
618
619     ReachGraph.debugCallSiteVisitStartCapture
620       = state.DISJOINTDEBUGCALLVISITTOSTART;
621
622     ReachGraph.debugCallSiteNumVisitsToCapture
623       = state.DISJOINTDEBUGCALLNUMVISITS;
624
625     ReachGraph.debugCallSiteStopAfter
626       = state.DISJOINTDEBUGCALLSTOPAFTER;
627
628     ReachGraph.debugCallSiteVisitCounter 
629       = 0; // count visits from 1, is incremented before first visit
630     
631     
632
633     allocateStructures();
634
635     double timeStartAnalysis = (double) System.nanoTime();
636
637     // start interprocedural fixed-point computation
638     try {
639       analyzeMethods();
640     } catch( IOException e ) {
641       throw new Error( "IO Exception while writing disjointness analysis output." );
642     }
643
644     analysisComplete=true;
645
646     double timeEndAnalysis = (double) System.nanoTime();
647     double dt = (timeEndAnalysis - timeStartAnalysis)/(Math.pow( 10.0, 9.0 ) );
648     String treport = String.format( "The reachability analysis took %.3f sec.", dt );
649     String justtime = String.format( "%.2f", dt );
650     System.out.println( treport );
651
652     try {
653       if( writeFinalDOTs && !writeAllIncrementalDOTs ) {
654         writeFinalGraphs();      
655       }
656
657       if( state.DISJOINTWRITEIHMS ) {
658         writeFinalIHMs();
659       }
660
661       if( state.DISJOINTWRITEINITCONTEXTS ) {
662         writeInitialContexts();
663       }
664
665       if( state.DISJOINTALIASFILE != null ) {
666         if( state.TASK ) {
667           writeAllSharing(state.DISJOINTALIASFILE, treport, justtime, state.DISJOINTALIASTAB, state.lines);
668         } else {
669           writeAllSharingJava(state.DISJOINTALIASFILE, 
670                               treport, 
671                               justtime, 
672                               state.DISJOINTALIASTAB, 
673                               state.lines
674                               );
675         }
676       }
677     } catch( IOException e ) {
678       throw new Error( "IO Exception while writing disjointness analysis output." );
679     }
680
681     if( doEffectsAnalysis ) {
682       effectsAnalysis.writeEffects( "effects.txt" );
683     }
684   }
685
686
687   protected boolean moreDescriptorsToVisit() {
688     if( state.DISJOINTDVISITSTACK ||
689         state.DISJOINTDVISITSTACKEESONTOP
690         ) {
691       return !descriptorsToVisitStack.isEmpty();
692
693     } else if( state.DISJOINTDVISITPQUE ) {
694       return !descriptorsToVisitQ.isEmpty();
695     }
696
697     throw new Error( "Neither descriptor visiting mode set" );
698   }
699
700
701   // fixed-point computation over the call graph--when a
702   // method's callees are updated, it must be reanalyzed
703   protected void analyzeMethods() throws java.io.IOException {  
704
705     // task or non-task (java) mode determines what the roots
706     // of the call chain are, and establishes the set of methods
707     // reachable from the roots that will be analyzed
708     
709     if( state.TASK ) {
710       System.out.println( "Bamboo mode..." );
711       
712       Iterator taskItr = state.getTaskSymbolTable().getDescriptorsIterator();      
713       while( taskItr.hasNext() ) {
714         TaskDescriptor td = (TaskDescriptor) taskItr.next();
715         if( !descriptorsToAnalyze.contains( td ) ) {
716           // add all methods transitively reachable from the
717           // tasks as well
718           descriptorsToAnalyze.add( td );
719           descriptorsToAnalyze.addAll( callGraph.getAllMethods( td ) );
720         }         
721       }
722       
723     } else {
724       System.out.println( "Java mode..." );
725
726       // add all methods transitively reachable from the
727       // source's main to set for analysis
728       mdSourceEntry = typeUtil.getMain();
729       descriptorsToAnalyze.add( mdSourceEntry );
730       descriptorsToAnalyze.addAll( callGraph.getAllMethods( mdSourceEntry ) );
731       
732       // fabricate an empty calling context that will call
733       // the source's main, but call graph doesn't know
734       // about it, so explicitly add it
735       makeAnalysisEntryMethod( mdSourceEntry );
736       descriptorsToAnalyze.add( mdAnalysisEntry );
737     }
738
739
740     // now, depending on the interprocedural mode for visiting 
741     // methods, set up the needed data structures
742
743     if( state.DISJOINTDVISITPQUE ) {
744     
745       // topologically sort according to the call graph so 
746       // leaf calls are last, helps build contexts up first
747       LinkedList<Descriptor> sortedDescriptors = 
748         topologicalSort( descriptorsToAnalyze );
749
750       // add sorted descriptors to priority queue, and duplicate
751       // the queue as a set for efficiently testing whether some
752       // method is marked for analysis
753       int p = 0;
754       Iterator<Descriptor> dItr;
755
756       // for the priority queue, give items at the head
757       // of the sorted list a low number (highest priority)
758       while( !sortedDescriptors.isEmpty() ) {
759         Descriptor d = sortedDescriptors.removeFirst();
760         mapDescriptorToPriority.put( d, new Integer( p ) );
761         descriptorsToVisitQ.add( new DescriptorQWrapper( p, d ) );
762         descriptorsToVisitSet.add( d );
763         ++p;
764       }
765
766     } else if( state.DISJOINTDVISITSTACK ||
767                state.DISJOINTDVISITSTACKEESONTOP 
768                ) {
769       // if we're doing the stack scheme, just throw the root
770       // method or tasks on the stack
771       if( state.TASK ) {
772         Iterator taskItr = state.getTaskSymbolTable().getDescriptorsIterator();      
773         while( taskItr.hasNext() ) {
774           TaskDescriptor td = (TaskDescriptor) taskItr.next();
775           descriptorsToVisitStack.add( td );
776           descriptorsToVisitSet.add( td );
777         }
778         
779       } else {
780         descriptorsToVisitStack.add( mdAnalysisEntry );
781         descriptorsToVisitSet.add( mdAnalysisEntry );
782       }
783
784     } else {
785       throw new Error( "Unknown method scheduling mode" );
786     }
787
788
789     // analyze scheduled methods until there are no more to visit
790     while( moreDescriptorsToVisit() ) {
791       Descriptor d = null;
792
793       if( state.DISJOINTDVISITSTACK ||
794           state.DISJOINTDVISITSTACKEESONTOP
795           ) {
796         d = descriptorsToVisitStack.pop();
797
798       } else if( state.DISJOINTDVISITPQUE ) {
799         d = descriptorsToVisitQ.poll().getDescriptor();
800       }
801
802       assert descriptorsToVisitSet.contains( d );
803       descriptorsToVisitSet.remove( d );
804
805       // because the task or method descriptor just extracted
806       // was in the "to visit" set it either hasn't been analyzed
807       // yet, or some method that it depends on has been
808       // updated.  Recompute a complete reachability graph for
809       // this task/method and compare it to any previous result.
810       // If there is a change detected, add any methods/tasks
811       // that depend on this one to the "to visit" set.
812
813       System.out.println( "Analyzing " + d );
814
815       if( state.DISJOINTDVISITSTACKEESONTOP ) {
816         assert calleesToEnqueue.isEmpty();
817       }
818
819       ReachGraph rg     = analyzeMethod( d );
820       ReachGraph rgPrev = getPartial( d );
821       
822       if( !rg.equals( rgPrev ) ) {
823         setPartial( d, rg );
824         
825         if( state.DISJOINTDEBUGSCHEDULING ) {
826           System.out.println( "  complete graph changed, scheduling callers for analysis:" );
827         }
828
829         // results for d changed, so enqueue dependents
830         // of d for further analysis
831         Iterator<Descriptor> depsItr = getDependents( d ).iterator();
832         while( depsItr.hasNext() ) {
833           Descriptor dNext = depsItr.next();
834           enqueue( dNext );
835
836           if( state.DISJOINTDEBUGSCHEDULING ) {
837             System.out.println( "    "+dNext );
838           }
839         }
840       }
841
842       // whether or not the method under analysis changed,
843       // we may have some callees that are scheduled for 
844       // more analysis, and they should go on the top of
845       // the stack now (in other method-visiting modes they
846       // are already enqueued at this point
847       if( state.DISJOINTDVISITSTACKEESONTOP ) {
848         Iterator<Descriptor> depsItr = calleesToEnqueue.iterator();
849         while( depsItr.hasNext() ) {
850           Descriptor dNext = depsItr.next();
851           enqueue( dNext );
852         }
853         calleesToEnqueue.clear();
854       }     
855
856     }   
857   }
858
859   protected ReachGraph analyzeMethod( Descriptor d ) 
860     throws java.io.IOException {
861
862     // get the flat code for this descriptor
863     FlatMethod fm;
864     if( d == mdAnalysisEntry ) {
865       fm = fmAnalysisEntry;
866     } else {
867       fm = state.getMethodFlat( d );
868     }
869     pm.analyzeMethod( fm );
870
871     // intraprocedural work set
872     Set<FlatNode> flatNodesToVisit = new HashSet<FlatNode>();
873     flatNodesToVisit.add( fm );
874
875     // if determinism is desired by client, shadow the
876     // set with a queue to make visit order deterministic
877     Queue<FlatNode> flatNodesToVisitQ = null;
878     if( determinismDesired ) {
879       flatNodesToVisitQ = new LinkedList<FlatNode>();
880       flatNodesToVisitQ.add( fm );
881     }
882     
883     // mapping of current partial results
884     Hashtable<FlatNode, ReachGraph> mapFlatNodeToReachGraph =
885       new Hashtable<FlatNode, ReachGraph>();
886
887     // the set of return nodes partial results that will be combined as
888     // the final, conservative approximation of the entire method
889     HashSet<FlatReturnNode> setReturns = new HashSet<FlatReturnNode>();
890
891     while( !flatNodesToVisit.isEmpty() ) {
892
893       FlatNode fn;      
894       if( determinismDesired ) {
895         assert !flatNodesToVisitQ.isEmpty();
896         fn = flatNodesToVisitQ.remove();
897       } else {
898         fn = flatNodesToVisit.iterator().next();
899       }
900       flatNodesToVisit.remove( fn );
901
902       // effect transfer function defined by this node,
903       // then compare it to the old graph at this node
904       // to see if anything was updated.
905
906       ReachGraph rg = new ReachGraph();
907       TaskDescriptor taskDesc;
908       if(fn instanceof FlatMethod && (taskDesc=((FlatMethod)fn).getTask())!=null){
909           if(mapDescriptorToReachGraph.containsKey(taskDesc)){
910                   // retrieve existing reach graph if it is not first time
911                   rg=mapDescriptorToReachGraph.get(taskDesc);
912           }else{
913                   // create initial reach graph for a task
914                   rg=createInitialTaskReachGraph((FlatMethod)fn);
915                   rg.globalSweep();
916                   mapDescriptorToReachGraph.put(taskDesc, rg);
917           }
918       }
919
920       // start by merging all node's parents' graphs
921       for( int i = 0; i < pm.numPrev(fn); ++i ) {
922         FlatNode pn = pm.getPrev(fn,i);
923         if( mapFlatNodeToReachGraph.containsKey( pn ) ) {
924           ReachGraph rgParent = mapFlatNodeToReachGraph.get( pn );
925           rg.merge( rgParent );
926         }
927       }
928       
929
930       if( takeDebugSnapshots && 
931           d.getSymbol().equals( descSymbolDebug ) 
932           ) {
933         debugSnapshot( rg, fn, true );
934       }
935
936
937       // modify rg with appropriate transfer function
938       rg = analyzeFlatNode( d, fm, fn, setReturns, rg );
939
940
941       if( takeDebugSnapshots && 
942           d.getSymbol().equals( descSymbolDebug ) 
943           ) {
944         debugSnapshot( rg, fn, false );
945         ++snapNodeCounter;
946       }
947           
948
949       // if the results of the new graph are different from
950       // the current graph at this node, replace the graph
951       // with the update and enqueue the children
952       ReachGraph rgPrev = mapFlatNodeToReachGraph.get( fn );
953       if( !rg.equals( rgPrev ) ) {
954         mapFlatNodeToReachGraph.put( fn, rg );
955
956         for( int i = 0; i < pm.numNext( fn ); i++ ) {
957           FlatNode nn = pm.getNext( fn, i );
958
959           flatNodesToVisit.add( nn );
960           if( determinismDesired ) {
961             flatNodesToVisitQ.add( nn );
962           }
963         }
964       }
965     }
966
967
968     // end by merging all return nodes into a complete
969     // reach graph that represents all possible heap
970     // states after the flat method returns
971     ReachGraph completeGraph = new ReachGraph();
972
973     assert !setReturns.isEmpty();
974     Iterator retItr = setReturns.iterator();
975     while( retItr.hasNext() ) {
976       FlatReturnNode frn = (FlatReturnNode) retItr.next();
977
978       assert mapFlatNodeToReachGraph.containsKey( frn );
979       ReachGraph rgRet = mapFlatNodeToReachGraph.get( frn );
980
981       completeGraph.merge( rgRet );
982     }
983
984
985     if( takeDebugSnapshots && 
986         d.getSymbol().equals( descSymbolDebug ) 
987         ) {
988       // increment that we've visited the debug snap
989       // method, and reset the node counter
990       System.out.println( "    @@@ debug snap at visit "+snapVisitCounter );
991       ++snapVisitCounter;
992       snapNodeCounter = 0;
993
994       if( snapVisitCounter == visitStartCapture + numVisitsToCapture && 
995           stopAfterCapture 
996           ) {
997         System.out.println( "!!! Stopping analysis after debug snap captures. !!!" );
998         System.exit( 0 );
999       }
1000     }
1001
1002
1003     return completeGraph;
1004   }
1005
1006   
1007   protected ReachGraph
1008     analyzeFlatNode( Descriptor              d,
1009                      FlatMethod              fmContaining,
1010                      FlatNode                fn,
1011                      HashSet<FlatReturnNode> setRetNodes,
1012                      ReachGraph              rg
1013                      ) throws java.io.IOException {
1014
1015     
1016     // any variables that are no longer live should be
1017     // nullified in the graph to reduce edges
1018     //rg.nullifyDeadVars( liveness.getLiveInTemps( fmContaining, fn ) );
1019
1020     /*
1021       if( doEffectsAnalysis &&  && fmContaining != fmAnalysisEntry
1022         rra.isEndOfRegion(fn)){
1023       rg.clearAccessibleVarSet();
1024       also need to clear stall mapping
1025     }
1026     */
1027           
1028     TempDescriptor  lhs;
1029     TempDescriptor  rhs;
1030     FieldDescriptor fld;
1031
1032     // use node type to decide what transfer function
1033     // to apply to the reachability graph
1034     switch( fn.kind() ) {
1035
1036     case FKind.FlatMethod: {
1037       // construct this method's initial heap model (IHM)
1038       // since we're working on the FlatMethod, we know
1039       // the incoming ReachGraph 'rg' is empty
1040
1041       Hashtable<FlatCall, ReachGraph> heapsFromCallers = 
1042         getIHMcontributions( d );
1043
1044       Set entrySet = heapsFromCallers.entrySet();
1045       Iterator itr = entrySet.iterator();
1046       while( itr.hasNext() ) {
1047         Map.Entry  me        = (Map.Entry)  itr.next();
1048         FlatCall   fc        = (FlatCall)   me.getKey();
1049         ReachGraph rgContrib = (ReachGraph) me.getValue();
1050
1051         assert fc.getMethod().equals( d );
1052
1053         rg.merge( rgContrib );
1054       }
1055
1056       // additionally, we are enforcing STRICT MONOTONICITY for the
1057       // method's initial context, so grow the context by whatever
1058       // the previously computed context was, and put the most
1059       // up-to-date context back in the map
1060       ReachGraph rgPrevContext = mapDescriptorToInitialContext.get( d );
1061       rg.merge( rgPrevContext );      
1062       mapDescriptorToInitialContext.put( d, rg );
1063
1064     } break;
1065       
1066     case FKind.FlatOpNode:
1067       FlatOpNode fon = (FlatOpNode) fn;
1068       if( fon.getOp().getOp() == Operation.ASSIGN ) {
1069         lhs = fon.getDest();
1070         rhs = fon.getLeft();
1071         rg.assignTempXEqualToTempY( lhs, rhs );
1072         
1073         if( doEffectsAnalysis && fmContaining != fmAnalysisEntry ) {
1074           if(rblockStatus.isInCriticalRegion(fmContaining, fn)){
1075             // x gets status of y
1076             if(rg.getAccessibleVar().contains(rhs)){
1077               rg.addAccessibleVar(lhs);
1078             }
1079           }    
1080         }
1081         
1082       }
1083       break;
1084
1085     case FKind.FlatCastNode:
1086       FlatCastNode fcn = (FlatCastNode) fn;
1087       lhs = fcn.getDst();
1088       rhs = fcn.getSrc();
1089
1090       TypeDescriptor td = fcn.getType();
1091       assert td != null;
1092       
1093       rg.assignTempXEqualToCastedTempY( lhs, rhs, td );
1094       break;
1095
1096     case FKind.FlatFieldNode:
1097       FlatFieldNode ffn = (FlatFieldNode) fn;
1098       lhs = ffn.getDst();
1099       rhs = ffn.getSrc();
1100       fld = ffn.getField();
1101
1102       if( shouldAnalysisTrack( fld.getType() ) ) {
1103         
1104         // before graph transform, possible inject
1105         // a stall-site taint
1106         if( doEffectsAnalysis && fmContaining != fmAnalysisEntry ) {
1107
1108           if(rblockStatus.isInCriticalRegion(fmContaining, fn)){
1109             // x=y.f, stall y if not accessible
1110             // contributes read effects on stall site of y
1111             if(!rg.isAccessible(rhs)) {
1112               rg.taintStallSite(fn, rhs);
1113             }
1114
1115             // after this, x and y are accessbile. 
1116             rg.addAccessibleVar(lhs);
1117             rg.addAccessibleVar(rhs);            
1118           }
1119         }
1120
1121         // transfer func
1122         rg.assignTempXEqualToTempYFieldF( lhs, rhs, fld );
1123
1124         // after transfer, use updated graph to
1125         // do effects analysis
1126         if( doEffectsAnalysis && fmContaining != fmAnalysisEntry ) {
1127           effectsAnalysis.analyzeFlatFieldNode( rg, rhs, fld );          
1128         }
1129       }          
1130       break;
1131
1132     case FKind.FlatSetFieldNode:
1133       FlatSetFieldNode fsfn = (FlatSetFieldNode) fn;
1134       lhs = fsfn.getDst();
1135       fld = fsfn.getField();
1136       rhs = fsfn.getSrc();
1137
1138       if( shouldAnalysisTrack( fld.getType() ) ) {
1139
1140         // before transfer func, possibly inject
1141         // stall-site taints
1142         if( doEffectsAnalysis && fmContaining != fmAnalysisEntry ) {
1143
1144           if(rblockStatus.isInCriticalRegion(fmContaining, fn)){
1145             // x.y=f , stall x and y if they are not accessible
1146             // also contribute write effects on stall site of x
1147             if(!rg.isAccessible(lhs)) {
1148               rg.taintStallSite(fn, lhs);
1149             }
1150
1151             if(!rg.isAccessible(rhs)) {
1152               rg.taintStallSite(fn, rhs);
1153             }
1154
1155             // accessible status update
1156             rg.addAccessibleVar(lhs);
1157             rg.addAccessibleVar(rhs);            
1158           }
1159         }
1160
1161         // transfer func
1162         boolean strongUpdate = rg.assignTempXFieldFEqualToTempY( lhs, fld, rhs );
1163
1164         // use transformed graph to do effects analysis
1165         if( doEffectsAnalysis && fmContaining != fmAnalysisEntry ) {
1166           effectsAnalysis.analyzeFlatSetFieldNode( rg, lhs, fld, strongUpdate );          
1167         }
1168       }           
1169       break;
1170
1171     case FKind.FlatElementNode:
1172       FlatElementNode fen = (FlatElementNode) fn;
1173       lhs = fen.getDst();
1174       rhs = fen.getSrc();
1175       if( shouldAnalysisTrack( lhs.getType() ) ) {
1176
1177         assert rhs.getType() != null;
1178         assert rhs.getType().isArray();
1179         
1180         TypeDescriptor  tdElement = rhs.getType().dereference();
1181         FieldDescriptor fdElement = getArrayField( tdElement );
1182   
1183         // before transfer func, possibly inject
1184         // stall-site taint
1185         if( doEffectsAnalysis && fmContaining != fmAnalysisEntry ) {
1186           
1187           if(rblockStatus.isInCriticalRegion(fmContaining, fn)){
1188             // x=y.f, stall y if not accessible
1189             // contributes read effects on stall site of y
1190             // after this, x and y are accessbile. 
1191             if(!rg.isAccessible(rhs)) {
1192               rg.taintStallSite(fn, rhs);
1193             }
1194
1195             rg.addAccessibleVar(lhs);
1196             rg.addAccessibleVar(rhs);            
1197           }
1198         }
1199
1200         // transfer func
1201         rg.assignTempXEqualToTempYFieldF( lhs, rhs, fdElement );
1202         
1203         // use transformed graph to do effects analysis
1204         if( doEffectsAnalysis && fmContaining != fmAnalysisEntry ) {
1205           effectsAnalysis.analyzeFlatFieldNode( rg, rhs, fdElement );                    
1206         }
1207       }
1208       break;
1209
1210     case FKind.FlatSetElementNode:
1211       FlatSetElementNode fsen = (FlatSetElementNode) fn;
1212
1213       if( arrayReferencees.doesNotCreateNewReaching( fsen ) ) {
1214         // skip this node if it cannot create new reachability paths
1215         break;
1216       }
1217
1218       lhs = fsen.getDst();
1219       rhs = fsen.getSrc();
1220       if( shouldAnalysisTrack( rhs.getType() ) ) {
1221
1222         assert lhs.getType() != null;
1223         assert lhs.getType().isArray();
1224         
1225         TypeDescriptor  tdElement = lhs.getType().dereference();
1226         FieldDescriptor fdElement = getArrayField( tdElement );
1227
1228         // before transfer func, possibly inject
1229         // stall-site taints
1230         if( doEffectsAnalysis && fmContaining != fmAnalysisEntry ) {
1231           
1232           if(rblockStatus.isInCriticalRegion(fmContaining, fn)){
1233             // x.y=f , stall x and y if they are not accessible
1234             // also contribute write effects on stall site of x
1235             if(!rg.isAccessible(lhs)) {
1236               rg.taintStallSite(fn, lhs);
1237             }
1238
1239             if(!rg.isAccessible(rhs)) {
1240               rg.taintStallSite(fn, rhs);
1241             }
1242             
1243             // accessible status update
1244             rg.addAccessibleVar(lhs);
1245             rg.addAccessibleVar(rhs);            
1246           }
1247         }
1248
1249         // transfer func
1250         rg.assignTempXFieldFEqualToTempY( lhs, fdElement, rhs );
1251
1252         // use transformed graph to do effects analysis
1253         if( doEffectsAnalysis && fmContaining != fmAnalysisEntry ) {
1254           effectsAnalysis.analyzeFlatSetFieldNode( rg, lhs, fdElement,
1255                                                    false );          
1256         }
1257       }
1258       break;
1259       
1260     case FKind.FlatNew:
1261       FlatNew fnn = (FlatNew) fn;
1262       lhs = fnn.getDst();
1263       if( shouldAnalysisTrack( lhs.getType() ) ) {
1264         AllocSite as = getAllocSiteFromFlatNewPRIVATE( fnn );   
1265         rg.assignTempEqualToNewAlloc( lhs, as );
1266         
1267         if (doEffectsAnalysis && fmContaining != fmAnalysisEntry) {
1268           if (rblockStatus.isInCriticalRegion(fmContaining, fn)) {
1269             // after creating new object, lhs is accessible
1270             rg.addAccessibleVar(lhs);
1271           }
1272         } 
1273         
1274       }
1275       break;
1276
1277     case FKind.FlatSESEEnterNode:
1278       if( doEffectsAnalysis && fmContaining != fmAnalysisEntry ) {
1279         
1280         // always remove ALL stall site taints at enter
1281         rg.removeAllStallSiteTaints();
1282
1283         // inject taints for in-set vars
1284         FlatSESEEnterNode sese = (FlatSESEEnterNode) fn;
1285         rg.taintInSetVars( sese );                         
1286       }
1287       break;
1288
1289     case FKind.FlatSESEExitNode:
1290       if( doEffectsAnalysis && fmContaining != fmAnalysisEntry ) {
1291
1292         // always remove ALL stall site taints at exit
1293         rg.removeAllStallSiteTaints();
1294         
1295         // remove in-set vars for the exiting rblock
1296         FlatSESEExitNode fsexn = (FlatSESEExitNode) fn;
1297         rg.removeInContextTaints( fsexn.getFlatEnter() );
1298
1299         // sese exit clears all mappings of accessible vars and stall sites
1300         // need to wipe out stall site taints
1301         rg.clearAccessibleVarSet();        
1302       }
1303       break;
1304
1305
1306     case FKind.FlatCall: {
1307       Descriptor mdCaller;
1308       if( fmContaining.getMethod() != null ){
1309         mdCaller = fmContaining.getMethod();
1310       } else {
1311         mdCaller = fmContaining.getTask();
1312       }      
1313       FlatCall         fc       = (FlatCall) fn;
1314       MethodDescriptor mdCallee = fc.getMethod();
1315       FlatMethod       fmCallee = state.getMethodFlat( mdCallee );
1316
1317
1318       boolean debugCallSite =
1319         mdCaller.getSymbol().equals( state.DISJOINTDEBUGCALLER ) &&
1320         mdCallee.getSymbol().equals( state.DISJOINTDEBUGCALLEE );
1321
1322       boolean writeDebugDOTs = false;
1323       boolean stopAfter      = false;
1324       if( debugCallSite ) {
1325         ++ReachGraph.debugCallSiteVisitCounter;
1326         System.out.println( "    $$$ Debug call site visit "+
1327                             ReachGraph.debugCallSiteVisitCounter+
1328                             " $$$"
1329                             );
1330         if( 
1331            (ReachGraph.debugCallSiteVisitCounter >= 
1332             ReachGraph.debugCallSiteVisitStartCapture)  &&
1333            
1334            (ReachGraph.debugCallSiteVisitCounter < 
1335             ReachGraph.debugCallSiteVisitStartCapture + 
1336             ReachGraph.debugCallSiteNumVisitsToCapture)
1337             ) {
1338           writeDebugDOTs = true;
1339           System.out.println( "      $$$ Capturing this call site visit $$$" );
1340           if( ReachGraph.debugCallSiteStopAfter &&
1341               (ReachGraph.debugCallSiteVisitCounter == 
1342                ReachGraph.debugCallSiteVisitStartCapture + 
1343                ReachGraph.debugCallSiteNumVisitsToCapture - 1)
1344               ) {
1345             stopAfter = true;
1346           }
1347         }
1348       }
1349
1350
1351       // calculate the heap this call site can reach--note this is
1352       // not used for the current call site transform, we are
1353       // grabbing this heap model for future analysis of the callees,
1354       // so if different results emerge we will return to this site
1355       ReachGraph heapForThisCall_old = 
1356         getIHMcontribution( mdCallee, fc );
1357
1358       // the computation of the callee-reachable heap
1359       // is useful for making the callee starting point
1360       // and for applying the call site transfer function
1361       Set<Integer> callerNodeIDsCopiedToCallee = 
1362         new HashSet<Integer>();
1363
1364       ReachGraph heapForThisCall_cur = 
1365         rg.makeCalleeView( fc, 
1366                            fmCallee,
1367                            callerNodeIDsCopiedToCallee,
1368                            writeDebugDOTs
1369                            );
1370
1371       if( !heapForThisCall_cur.equals( heapForThisCall_old ) ) {        
1372         // if heap at call site changed, update the contribution,
1373         // and reschedule the callee for analysis
1374         addIHMcontribution( mdCallee, fc, heapForThisCall_cur );        
1375
1376         // map a FlatCall to its enclosing method/task descriptor 
1377         // so we can write that info out later
1378         fc2enclosing.put( fc, mdCaller );
1379
1380         if( state.DISJOINTDEBUGSCHEDULING ) {
1381           System.out.println( "  context changed, scheduling callee: "+mdCallee );
1382         }
1383
1384         if( state.DISJOINTDVISITSTACKEESONTOP ) {
1385           calleesToEnqueue.add( mdCallee );
1386         } else {
1387           enqueue( mdCallee );
1388         }
1389
1390       }
1391
1392       // the transformation for a call site should update the
1393       // current heap abstraction with any effects from the callee,
1394       // or if the method is virtual, the effects from any possible
1395       // callees, so find the set of callees...
1396       Set<MethodDescriptor> setPossibleCallees;
1397       if( determinismDesired ) {
1398         // use an ordered set
1399         setPossibleCallees = new TreeSet<MethodDescriptor>( dComp );        
1400       } else {
1401         // otherwise use a speedy hashset
1402         setPossibleCallees = new HashSet<MethodDescriptor>();
1403       }
1404
1405       if( mdCallee.isStatic() ) {        
1406         setPossibleCallees.add( mdCallee );
1407       } else {
1408         TypeDescriptor typeDesc = fc.getThis().getType();
1409         setPossibleCallees.addAll( callGraph.getMethods( mdCallee, 
1410                                                          typeDesc )
1411                                    );
1412       }
1413
1414       ReachGraph rgMergeOfEffects = new ReachGraph();
1415
1416       Iterator<MethodDescriptor> mdItr = setPossibleCallees.iterator();
1417       while( mdItr.hasNext() ) {
1418         MethodDescriptor mdPossible = mdItr.next();
1419         FlatMethod       fmPossible = state.getMethodFlat( mdPossible );
1420
1421         addDependent( mdPossible, // callee
1422                       d );        // caller
1423
1424         // don't alter the working graph (rg) until we compute a 
1425         // result for every possible callee, merge them all together,
1426         // then set rg to that
1427         ReachGraph rgCopy = new ReachGraph();
1428         rgCopy.merge( rg );             
1429                 
1430         ReachGraph rgEffect = getPartial( mdPossible );
1431
1432         if( rgEffect == null ) {
1433           // if this method has never been analyzed just schedule it 
1434           // for analysis and skip over this call site for now
1435           if( state.DISJOINTDVISITSTACKEESONTOP ) {
1436             calleesToEnqueue.add( mdPossible );
1437           } else {
1438             enqueue( mdPossible );
1439           }
1440           
1441           if( state.DISJOINTDEBUGSCHEDULING ) {
1442             System.out.println( "  callee hasn't been analyzed, scheduling: "+mdPossible );
1443           }
1444
1445
1446         } else {
1447           // calculate the method call transform         
1448           rgCopy.resolveMethodCall( fc, 
1449                                     fmPossible, 
1450                                     rgEffect,
1451                                     callerNodeIDsCopiedToCallee,
1452                                     writeDebugDOTs
1453                                     );
1454         }
1455         
1456         rgMergeOfEffects.merge( rgCopy );        
1457       }
1458
1459
1460       if( stopAfter ) {
1461         System.out.println( "$$$ Exiting after requested captures of call site. $$$" );
1462         System.exit( 0 );
1463       }
1464
1465
1466       // now that we've taken care of building heap models for
1467       // callee analysis, finish this transformation
1468       rg = rgMergeOfEffects;
1469     } break;
1470       
1471
1472     case FKind.FlatReturnNode:
1473       FlatReturnNode frn = (FlatReturnNode) fn;
1474       rhs = frn.getReturnTemp();
1475       if( rhs != null && shouldAnalysisTrack( rhs.getType() ) ) {
1476         rg.assignReturnEqualToTemp( rhs );
1477       }
1478       setRetNodes.add( frn );
1479       break;
1480
1481     } // end switch
1482
1483     
1484     // dead variables were removed before the above transfer function
1485     // was applied, so eliminate heap regions and edges that are no
1486     // longer part of the abstractly-live heap graph, and sweep up
1487     // and reachability effects that are altered by the reduction
1488     //rg.abstractGarbageCollect();
1489     //rg.globalSweep();
1490
1491
1492     // back edges are strictly monotonic
1493     if( pm.isBackEdge( fn ) ) {
1494       ReachGraph rgPrevResult = mapBackEdgeToMonotone.get( fn );
1495       rg.merge( rgPrevResult );
1496       mapBackEdgeToMonotone.put( fn, rg );
1497     }
1498     
1499     // at this point rg should be the correct update
1500     // by an above transfer function, or untouched if
1501     // the flat node type doesn't affect the heap
1502     return rg;
1503   }
1504
1505
1506   
1507   // this method should generate integers strictly greater than zero!
1508   // special "shadow" regions are made from a heap region by negating
1509   // the ID
1510   static public Integer generateUniqueHeapRegionNodeID() {
1511     ++uniqueIDcount;
1512     return new Integer( uniqueIDcount );
1513   }
1514
1515
1516   
1517   static public FieldDescriptor getArrayField( TypeDescriptor tdElement ) {
1518     FieldDescriptor fdElement = mapTypeToArrayField.get( tdElement );
1519     if( fdElement == null ) {
1520       fdElement = new FieldDescriptor( new Modifiers( Modifiers.PUBLIC ),
1521                                        tdElement,
1522                                        arrayElementFieldName,
1523                                        null,
1524                                        false );
1525       mapTypeToArrayField.put( tdElement, fdElement );
1526     }
1527     return fdElement;
1528   }
1529
1530   
1531   
1532   private void writeFinalGraphs() {
1533     Set entrySet = mapDescriptorToCompleteReachGraph.entrySet();
1534     Iterator itr = entrySet.iterator();
1535     while( itr.hasNext() ) {
1536       Map.Entry  me = (Map.Entry)  itr.next();
1537       Descriptor  d = (Descriptor) me.getKey();
1538       ReachGraph rg = (ReachGraph) me.getValue();
1539
1540       rg.writeGraph( "COMPLETE"+d,
1541                      true,    // write labels (variables)                
1542                      true,    // selectively hide intermediate temp vars 
1543                      true,    // prune unreachable heap regions          
1544                      false,   // hide reachability altogether
1545                      true,    // hide subset reachability states         
1546                      true,    // hide predicates
1547                      false ); // hide edge taints                        
1548     }
1549   }
1550
1551   private void writeFinalIHMs() {
1552     Iterator d2IHMsItr = mapDescriptorToIHMcontributions.entrySet().iterator();
1553     while( d2IHMsItr.hasNext() ) {
1554       Map.Entry                        me1 = (Map.Entry)                       d2IHMsItr.next();
1555       Descriptor                         d = (Descriptor)                      me1.getKey();
1556       Hashtable<FlatCall, ReachGraph> IHMs = (Hashtable<FlatCall, ReachGraph>) me1.getValue();
1557
1558       Iterator fc2rgItr = IHMs.entrySet().iterator();
1559       while( fc2rgItr.hasNext() ) {
1560         Map.Entry  me2 = (Map.Entry)  fc2rgItr.next();
1561         FlatCall   fc  = (FlatCall)   me2.getKey();
1562         ReachGraph rg  = (ReachGraph) me2.getValue();
1563                 
1564         rg.writeGraph( "IHMPARTFOR"+d+"FROM"+fc2enclosing.get( fc )+fc,
1565                        true,   // write labels (variables)
1566                        true,   // selectively hide intermediate temp vars
1567                        true,   // hide reachability altogether
1568                        true,   // prune unreachable heap regions
1569                        true,   // hide subset reachability states
1570                        false,  // hide predicates
1571                        true ); // hide edge taints
1572       }
1573     }
1574   }
1575
1576   private void writeInitialContexts() {
1577     Set entrySet = mapDescriptorToInitialContext.entrySet();
1578     Iterator itr = entrySet.iterator();
1579     while( itr.hasNext() ) {
1580       Map.Entry  me = (Map.Entry)  itr.next();
1581       Descriptor  d = (Descriptor) me.getKey();
1582       ReachGraph rg = (ReachGraph) me.getValue();
1583
1584       rg.writeGraph( "INITIAL"+d,
1585                      true,   // write labels (variables)                
1586                      true,   // selectively hide intermediate temp vars 
1587                      true,   // prune unreachable heap regions          
1588                      false,  // hide all reachability
1589                      true,   // hide subset reachability states         
1590                      true,   // hide predicates
1591                      false );// hide edge taints                        
1592     }
1593   }
1594    
1595
1596   protected ReachGraph getPartial( Descriptor d ) {
1597     return mapDescriptorToCompleteReachGraph.get( d );
1598   }
1599
1600   protected void setPartial( Descriptor d, ReachGraph rg ) {
1601     mapDescriptorToCompleteReachGraph.put( d, rg );
1602
1603     // when the flag for writing out every partial
1604     // result is set, we should spit out the graph,
1605     // but in order to give it a unique name we need
1606     // to track how many partial results for this
1607     // descriptor we've already written out
1608     if( writeAllIncrementalDOTs ) {
1609       if( !mapDescriptorToNumUpdates.containsKey( d ) ) {
1610         mapDescriptorToNumUpdates.put( d, new Integer( 0 ) );
1611       }
1612       Integer n = mapDescriptorToNumUpdates.get( d );
1613       
1614       rg.writeGraph( d+"COMPLETE"+String.format( "%05d", n ),
1615                      true,   // write labels (variables)
1616                      true,   // selectively hide intermediate temp vars
1617                      true,   // prune unreachable heap regions
1618                      false,  // hide all reachability
1619                      true,   // hide subset reachability states
1620                      false,  // hide predicates
1621                      false); // hide edge taints
1622       
1623       mapDescriptorToNumUpdates.put( d, n + 1 );
1624     }
1625   }
1626
1627
1628
1629   // return just the allocation site associated with one FlatNew node
1630   protected AllocSite getAllocSiteFromFlatNewPRIVATE( FlatNew fnew ) {
1631
1632     if( !mapFlatNewToAllocSite.containsKey( fnew ) ) {
1633       AllocSite as = AllocSite.factory( allocationDepth, 
1634                                         fnew, 
1635                                         fnew.getDisjointId(),
1636                                         false
1637                                         );
1638
1639       // the newest nodes are single objects
1640       for( int i = 0; i < allocationDepth; ++i ) {
1641         Integer id = generateUniqueHeapRegionNodeID();
1642         as.setIthOldest( i, id );
1643         mapHrnIdToAllocSite.put( id, as );
1644       }
1645
1646       // the oldest node is a summary node
1647       as.setSummary( generateUniqueHeapRegionNodeID() );
1648
1649       mapFlatNewToAllocSite.put( fnew, as );
1650     }
1651
1652     return mapFlatNewToAllocSite.get( fnew );
1653   }
1654
1655
1656   public static boolean shouldAnalysisTrack( TypeDescriptor type ) {
1657     // don't track primitive types, but an array
1658     // of primitives is heap memory
1659     if( type.isImmutable() ) {
1660       return type.isArray();
1661     }
1662
1663     // everything else is an object
1664     return true;
1665   }
1666
1667   protected int numMethodsAnalyzed() {    
1668     return descriptorsToAnalyze.size();
1669   }
1670   
1671
1672   
1673   
1674   
1675   // Take in source entry which is the program's compiled entry and
1676   // create a new analysis entry, a method that takes no parameters
1677   // and appears to allocate the command line arguments and call the
1678   // source entry with them.  The purpose of this analysis entry is
1679   // to provide a top-level method context with no parameters left.
1680   protected void makeAnalysisEntryMethod( MethodDescriptor mdSourceEntry ) {
1681
1682     Modifiers mods = new Modifiers();
1683     mods.addModifier( Modifiers.PUBLIC );
1684     mods.addModifier( Modifiers.STATIC );
1685
1686     TypeDescriptor returnType = 
1687       new TypeDescriptor( TypeDescriptor.VOID );
1688
1689     this.mdAnalysisEntry = 
1690       new MethodDescriptor( mods,
1691                             returnType,
1692                             "analysisEntryMethod"
1693                             );
1694
1695     TempDescriptor cmdLineArgs = 
1696       new TempDescriptor( "args",
1697                           mdSourceEntry.getParamType( 0 )
1698                           );
1699
1700     FlatNew fn = 
1701       new FlatNew( mdSourceEntry.getParamType( 0 ),
1702                    cmdLineArgs,
1703                    false // is global 
1704                    );
1705     
1706     TempDescriptor[] sourceEntryArgs = new TempDescriptor[1];
1707     sourceEntryArgs[0] = cmdLineArgs;
1708     
1709     FlatCall fc = 
1710       new FlatCall( mdSourceEntry,
1711                     null, // dst temp
1712                     null, // this temp
1713                     sourceEntryArgs
1714                     );
1715
1716     FlatReturnNode frn = new FlatReturnNode( null );
1717
1718     FlatExit fe = new FlatExit();
1719
1720     this.fmAnalysisEntry = 
1721       new FlatMethod( mdAnalysisEntry, 
1722                       fe
1723                       );
1724
1725     this.fmAnalysisEntry.addNext( fn );
1726     fn.addNext( fc );
1727     fc.addNext( frn );
1728     frn.addNext( fe );
1729   }
1730
1731
1732   protected LinkedList<Descriptor> topologicalSort( Set<Descriptor> toSort ) {
1733
1734     Set<Descriptor> discovered;
1735
1736     if( determinismDesired ) {
1737       // use an ordered set
1738       discovered = new TreeSet<Descriptor>( dComp );      
1739     } else {
1740       // otherwise use a speedy hashset
1741       discovered = new HashSet<Descriptor>();
1742     }
1743
1744     LinkedList<Descriptor> sorted = new LinkedList<Descriptor>();
1745   
1746     Iterator<Descriptor> itr = toSort.iterator();
1747     while( itr.hasNext() ) {
1748       Descriptor d = itr.next();
1749           
1750       if( !discovered.contains( d ) ) {
1751         dfsVisit( d, toSort, sorted, discovered );
1752       }
1753     }
1754     
1755     return sorted;
1756   }
1757   
1758   // While we're doing DFS on call graph, remember
1759   // dependencies for efficient queuing of methods
1760   // during interprocedural analysis:
1761   //
1762   // a dependent of a method decriptor d for this analysis is:
1763   //  1) a method or task that invokes d
1764   //  2) in the descriptorsToAnalyze set
1765   protected void dfsVisit( Descriptor             d,
1766                            Set       <Descriptor> toSort,                        
1767                            LinkedList<Descriptor> sorted,
1768                            Set       <Descriptor> discovered ) {
1769     discovered.add( d );
1770     
1771     // only methods have callers, tasks never do
1772     if( d instanceof MethodDescriptor ) {
1773
1774       MethodDescriptor md = (MethodDescriptor) d;
1775
1776       // the call graph is not aware that we have a fabricated
1777       // analysis entry that calls the program source's entry
1778       if( md == mdSourceEntry ) {
1779         if( !discovered.contains( mdAnalysisEntry ) ) {
1780           addDependent( mdSourceEntry,  // callee
1781                         mdAnalysisEntry // caller
1782                         );
1783           dfsVisit( mdAnalysisEntry, toSort, sorted, discovered );
1784         }
1785       }
1786
1787       // otherwise call graph guides DFS
1788       Iterator itr = callGraph.getCallerSet( md ).iterator();
1789       while( itr.hasNext() ) {
1790         Descriptor dCaller = (Descriptor) itr.next();
1791         
1792         // only consider callers in the original set to analyze
1793         if( !toSort.contains( dCaller ) ) {
1794           continue;
1795         }
1796           
1797         if( !discovered.contains( dCaller ) ) {
1798           addDependent( md,     // callee
1799                         dCaller // caller
1800                         );
1801
1802           dfsVisit( dCaller, toSort, sorted, discovered );
1803         }
1804       }
1805     }
1806     
1807     // for leaf-nodes last now!
1808     sorted.addLast( d );
1809   }
1810
1811
1812   protected void enqueue( Descriptor d ) {
1813
1814     if( !descriptorsToVisitSet.contains( d ) ) {
1815
1816       if( state.DISJOINTDVISITSTACK ||
1817           state.DISJOINTDVISITSTACKEESONTOP
1818           ) {
1819         descriptorsToVisitStack.add( d );
1820
1821       } else if( state.DISJOINTDVISITPQUE ) {
1822         Integer priority = mapDescriptorToPriority.get( d );
1823         descriptorsToVisitQ.add( new DescriptorQWrapper( priority, 
1824                                                          d ) 
1825                                  );
1826       }
1827
1828       descriptorsToVisitSet.add( d );
1829     }
1830   }
1831
1832
1833   // a dependent of a method decriptor d for this analysis is:
1834   //  1) a method or task that invokes d
1835   //  2) in the descriptorsToAnalyze set
1836   protected void addDependent( Descriptor callee, Descriptor caller ) {
1837     Set<Descriptor> deps = mapDescriptorToSetDependents.get( callee );
1838     if( deps == null ) {
1839       deps = new HashSet<Descriptor>();
1840     }
1841     deps.add( caller );
1842     mapDescriptorToSetDependents.put( callee, deps );
1843   }
1844   
1845   protected Set<Descriptor> getDependents( Descriptor callee ) {
1846     Set<Descriptor> deps = mapDescriptorToSetDependents.get( callee );
1847     if( deps == null ) {
1848       deps = new HashSet<Descriptor>();
1849       mapDescriptorToSetDependents.put( callee, deps );
1850     }
1851     return deps;
1852   }
1853
1854   
1855   public Hashtable<FlatCall, ReachGraph> getIHMcontributions( Descriptor d ) {
1856
1857     Hashtable<FlatCall, ReachGraph> heapsFromCallers = 
1858       mapDescriptorToIHMcontributions.get( d );
1859     
1860     if( heapsFromCallers == null ) {
1861       heapsFromCallers = new Hashtable<FlatCall, ReachGraph>();
1862       mapDescriptorToIHMcontributions.put( d, heapsFromCallers );
1863     }
1864     
1865     return heapsFromCallers;
1866   }
1867
1868   public ReachGraph getIHMcontribution( Descriptor d, 
1869                                         FlatCall   fc
1870                                         ) {
1871     Hashtable<FlatCall, ReachGraph> heapsFromCallers = 
1872       getIHMcontributions( d );
1873
1874     if( !heapsFromCallers.containsKey( fc ) ) {
1875       return null;
1876     }
1877
1878     return heapsFromCallers.get( fc );
1879   }
1880
1881
1882   public void addIHMcontribution( Descriptor d,
1883                                   FlatCall   fc,
1884                                   ReachGraph rg
1885                                   ) {
1886     Hashtable<FlatCall, ReachGraph> heapsFromCallers = 
1887       getIHMcontributions( d );
1888
1889     heapsFromCallers.put( fc, rg );
1890   }
1891
1892
1893   private AllocSite createParameterAllocSite( ReachGraph     rg, 
1894                                               TempDescriptor tempDesc,
1895                                               boolean        flagRegions
1896                                               ) {
1897     
1898     FlatNew flatNew;
1899     if( flagRegions ) {
1900       flatNew = new FlatNew( tempDesc.getType(), // type
1901                              tempDesc,           // param temp
1902                              false,              // global alloc?
1903                              "param"+tempDesc    // disjoint site ID string
1904                              );
1905     } else {
1906       flatNew = new FlatNew( tempDesc.getType(), // type
1907                              tempDesc,           // param temp
1908                              false,              // global alloc?
1909                              null                // disjoint site ID string
1910                              );
1911     }
1912
1913     // create allocation site
1914     AllocSite as = AllocSite.factory( allocationDepth, 
1915                                       flatNew, 
1916                                       flatNew.getDisjointId(),
1917                                       false
1918                                       );
1919     for (int i = 0; i < allocationDepth; ++i) {
1920         Integer id = generateUniqueHeapRegionNodeID();
1921         as.setIthOldest(i, id);
1922         mapHrnIdToAllocSite.put(id, as);
1923     }
1924     // the oldest node is a summary node
1925     as.setSummary( generateUniqueHeapRegionNodeID() );
1926     
1927     rg.age(as);
1928     
1929     return as;
1930     
1931   }
1932
1933 private Set<FieldDescriptor> getFieldSetTobeAnalyzed(TypeDescriptor typeDesc){
1934         
1935         Set<FieldDescriptor> fieldSet=new HashSet<FieldDescriptor>();
1936     if(!typeDesc.isImmutable()){
1937             ClassDescriptor classDesc = typeDesc.getClassDesc();                    
1938             for (Iterator it = classDesc.getFields(); it.hasNext();) {
1939                     FieldDescriptor field = (FieldDescriptor) it.next();
1940                     TypeDescriptor fieldType = field.getType();
1941                     if (shouldAnalysisTrack( fieldType )) {
1942                         fieldSet.add(field);                    
1943                     }
1944             }
1945     }
1946     return fieldSet;
1947         
1948 }
1949
1950   private HeapRegionNode createMultiDeimensionalArrayHRN(ReachGraph rg, AllocSite alloc, HeapRegionNode srcHRN, FieldDescriptor fd, Hashtable<HeapRegionNode, HeapRegionNode> map, Hashtable<TypeDescriptor, HeapRegionNode> mapToExistingNode, ReachSet alpha ){
1951
1952         int dimCount=fd.getType().getArrayCount();
1953         HeapRegionNode prevNode=null;
1954         HeapRegionNode arrayEntryNode=null;
1955         for(int i=dimCount;i>0;i--){
1956                 TypeDescriptor typeDesc=fd.getType().dereference();//hack to get instance of type desc
1957                 typeDesc.setArrayCount(i);
1958                 TempDescriptor tempDesc=new TempDescriptor(typeDesc.getSymbol(),typeDesc);
1959                 HeapRegionNode hrnSummary ;
1960                 if(!mapToExistingNode.containsKey(typeDesc)){
1961                         AllocSite as;
1962                         if(i==dimCount){
1963                                 as = alloc;
1964                         }else{
1965                           as = createParameterAllocSite(rg, tempDesc, false);
1966                         }
1967                         // make a new reference to allocated node
1968                     hrnSummary = 
1969                                 rg.createNewHeapRegionNode(as.getSummary(), // id or null to generate a new one
1970                                                            false, // single object?
1971                                                            true, // summary?
1972                                                            false, // out-of-context?
1973                                                            as.getType(), // type
1974                                                            as, // allocation site
1975                                                            alpha, // inherent reach
1976                                                            alpha, // current reach
1977                                                            ExistPredSet.factory(rg.predTrue), // predicates
1978                                                            tempDesc.toString() // description
1979                                                            );
1980                     rg.id2hrn.put(as.getSummary(),hrnSummary);
1981                     
1982                     mapToExistingNode.put(typeDesc, hrnSummary);
1983                 }else{
1984                         hrnSummary=mapToExistingNode.get(typeDesc);
1985                 }
1986             
1987             if(prevNode==null){
1988                     // make a new reference between new summary node and source
1989               RefEdge edgeToSummary = new RefEdge(srcHRN, // source
1990                                                         hrnSummary, // dest
1991                                                         typeDesc, // type
1992                                                         fd.getSymbol(), // field name
1993                                                         alpha, // beta
1994                                                   ExistPredSet.factory(rg.predTrue), // predicates
1995                                                   null
1996                                                         );
1997                     
1998                     rg.addRefEdge(srcHRN, hrnSummary, edgeToSummary);
1999                     prevNode=hrnSummary;
2000                     arrayEntryNode=hrnSummary;
2001             }else{
2002                     // make a new reference between summary nodes of array
2003                     RefEdge edgeToSummary = new RefEdge(prevNode, // source
2004                                                         hrnSummary, // dest
2005                                                         typeDesc, // type
2006                                                         arrayElementFieldName, // field name
2007                                                         alpha, // beta
2008                                                         ExistPredSet.factory(rg.predTrue), // predicates
2009                                                         null
2010                                                         );
2011                     
2012                     rg.addRefEdge(prevNode, hrnSummary, edgeToSummary);
2013                     prevNode=hrnSummary;
2014             }
2015             
2016         }
2017         
2018         // create a new obj node if obj has at least one non-primitive field
2019         TypeDescriptor type=fd.getType();
2020     if(getFieldSetTobeAnalyzed(type).size()>0){
2021         TypeDescriptor typeDesc=type.dereference();
2022         typeDesc.setArrayCount(0);
2023         if(!mapToExistingNode.containsKey(typeDesc)){
2024                 TempDescriptor tempDesc=new TempDescriptor(type.getSymbol(),typeDesc);
2025                 AllocSite as = createParameterAllocSite(rg, tempDesc, false);
2026                 // make a new reference to allocated node
2027                     HeapRegionNode hrnSummary = 
2028                                 rg.createNewHeapRegionNode(as.getSummary(), // id or null to generate a new one
2029                                                            false, // single object?
2030                                                            true, // summary?
2031                                                            false, // out-of-context?
2032                                                            typeDesc, // type
2033                                                            as, // allocation site
2034                                                            alpha, // inherent reach
2035                                                            alpha, // current reach
2036                                                            ExistPredSet.factory(rg.predTrue), // predicates
2037                                                            tempDesc.toString() // description
2038                                                            );
2039                     rg.id2hrn.put(as.getSummary(),hrnSummary);
2040                     mapToExistingNode.put(typeDesc, hrnSummary);
2041                     RefEdge edgeToSummary = new RefEdge(prevNode, // source
2042                                         hrnSummary, // dest
2043                                         typeDesc, // type
2044                                         arrayElementFieldName, // field name
2045                                         alpha, // beta
2046                                                         ExistPredSet.factory(rg.predTrue), // predicates
2047                                                         null
2048                                         );
2049                     rg.addRefEdge(prevNode, hrnSummary, edgeToSummary);
2050                     prevNode=hrnSummary;
2051         }else{
2052           HeapRegionNode hrnSummary=mapToExistingNode.get(typeDesc);
2053                 if(prevNode.getReferenceTo(hrnSummary, typeDesc, arrayElementFieldName)==null){
2054                         RefEdge edgeToSummary = new RefEdge(prevNode, // source
2055                                         hrnSummary, // dest
2056                                         typeDesc, // type
2057                                         arrayElementFieldName, // field name
2058                                         alpha, // beta
2059                                                             ExistPredSet.factory(rg.predTrue), // predicates
2060                                                             null
2061                                         );
2062                     rg.addRefEdge(prevNode, hrnSummary, edgeToSummary);
2063                 }
2064                  prevNode=hrnSummary;
2065         }
2066     }
2067         
2068         map.put(arrayEntryNode, prevNode);
2069         return arrayEntryNode;
2070 }
2071
2072 private ReachGraph createInitialTaskReachGraph(FlatMethod fm) {
2073     ReachGraph rg = new ReachGraph();
2074     TaskDescriptor taskDesc = fm.getTask();
2075     
2076     for (int idx = 0; idx < taskDesc.numParameters(); idx++) {
2077         Descriptor paramDesc = taskDesc.getParameter(idx);
2078         TypeDescriptor paramTypeDesc = taskDesc.getParamType(idx);
2079         
2080         // setup data structure
2081         Set<HashMap<HeapRegionNode, FieldDescriptor>> workSet = 
2082             new HashSet<HashMap<HeapRegionNode, FieldDescriptor>>();
2083         Hashtable<TypeDescriptor, HeapRegionNode> mapTypeToExistingSummaryNode = 
2084             new Hashtable<TypeDescriptor, HeapRegionNode>();
2085         Hashtable<HeapRegionNode, HeapRegionNode> mapToFirstDimensionArrayNode = 
2086             new Hashtable<HeapRegionNode, HeapRegionNode>();
2087         Set<String> doneSet = new HashSet<String>();
2088         
2089         TempDescriptor tempDesc = fm.getParameter(idx);
2090         
2091         AllocSite as = createParameterAllocSite(rg, tempDesc, true);
2092         VariableNode lnX = rg.getVariableNodeFromTemp(tempDesc);
2093         Integer idNewest = as.getIthOldest(0);
2094         HeapRegionNode hrnNewest = rg.id2hrn.get(idNewest);
2095
2096         // make a new reference to allocated node
2097         RefEdge edgeNew = new RefEdge(lnX, // source
2098                                       hrnNewest, // dest
2099                                       taskDesc.getParamType(idx), // type
2100                                       null, // field name
2101                                       hrnNewest.getAlpha(), // beta
2102                                       ExistPredSet.factory(rg.predTrue), // predicates
2103                                       null
2104                                       );
2105         rg.addRefEdge(lnX, hrnNewest, edgeNew);
2106
2107         // set-up a work set for class field
2108         ClassDescriptor classDesc = paramTypeDesc.getClassDesc();
2109         for (Iterator it = classDesc.getFields(); it.hasNext();) {
2110             FieldDescriptor fd = (FieldDescriptor) it.next();
2111             TypeDescriptor fieldType = fd.getType();
2112             if (shouldAnalysisTrack( fieldType )) {
2113                 HashMap<HeapRegionNode, FieldDescriptor> newMap = new HashMap<HeapRegionNode, FieldDescriptor>();
2114                 newMap.put(hrnNewest, fd);
2115                 workSet.add(newMap);
2116             }
2117         }
2118         
2119         int uniqueIdentifier = 0;
2120         while (!workSet.isEmpty()) {
2121             HashMap<HeapRegionNode, FieldDescriptor> map = workSet
2122                 .iterator().next();
2123             workSet.remove(map);
2124             
2125             Set<HeapRegionNode> key = map.keySet();
2126             HeapRegionNode srcHRN = key.iterator().next();
2127             FieldDescriptor fd = map.get(srcHRN);
2128             TypeDescriptor type = fd.getType();
2129             String doneSetIdentifier = srcHRN.getIDString() + "_" + fd;
2130             
2131             if (!doneSet.contains(doneSetIdentifier)) {
2132                 doneSet.add(doneSetIdentifier);
2133                 if (!mapTypeToExistingSummaryNode.containsKey(type)) {
2134                     // create new summary Node
2135                     TempDescriptor td = new TempDescriptor("temp"
2136                                                            + uniqueIdentifier, type);
2137                     
2138                     AllocSite allocSite;
2139                     if(type.equals(paramTypeDesc)){
2140                     //corresponding allocsite has already been created for a parameter variable.
2141                         allocSite=as;
2142                     }else{
2143                       allocSite = createParameterAllocSite(rg, td, false);
2144                     }
2145                     String strDesc = allocSite.toStringForDOT()
2146                         + "\\nsummary";
2147                     TypeDescriptor allocType=allocSite.getType();
2148                     
2149                     HeapRegionNode      hrnSummary;
2150                     if(allocType.isArray() && allocType.getArrayCount()>0){
2151                       hrnSummary=createMultiDeimensionalArrayHRN(rg,allocSite,srcHRN,fd,mapToFirstDimensionArrayNode,mapTypeToExistingSummaryNode,hrnNewest.getAlpha());
2152                     }else{                  
2153                         hrnSummary = 
2154                                         rg.createNewHeapRegionNode(allocSite.getSummary(), // id or null to generate a new one
2155                                                                    false, // single object?
2156                                                                    true, // summary?
2157                                                                    false, // out-of-context?
2158                                                                    allocSite.getType(), // type
2159                                                                    allocSite, // allocation site
2160                                                                    hrnNewest.getAlpha(), // inherent reach
2161                                                                    hrnNewest.getAlpha(), // current reach
2162                                                                    ExistPredSet.factory(rg.predTrue), // predicates
2163                                                                    strDesc // description
2164                                                                    );
2165                                     rg.id2hrn.put(allocSite.getSummary(),hrnSummary);
2166                     
2167                     // make a new reference to summary node
2168                     RefEdge edgeToSummary = new RefEdge(srcHRN, // source
2169                                                         hrnSummary, // dest
2170                                                         type, // type
2171                                                         fd.getSymbol(), // field name
2172                                                         hrnNewest.getAlpha(), // beta
2173                                                         ExistPredSet.factory(rg.predTrue), // predicates
2174                                                         null
2175                                                         );
2176                     
2177                     rg.addRefEdge(srcHRN, hrnSummary, edgeToSummary);
2178                     }               
2179                     uniqueIdentifier++;
2180                     
2181                     mapTypeToExistingSummaryNode.put(type, hrnSummary);
2182                     
2183                     // set-up a work set for  fields of the class
2184                     Set<FieldDescriptor> fieldTobeAnalyzed=getFieldSetTobeAnalyzed(type);
2185                     for (Iterator iterator = fieldTobeAnalyzed.iterator(); iterator
2186                                         .hasNext();) {
2187                                 FieldDescriptor fieldDescriptor = (FieldDescriptor) iterator
2188                                                 .next();
2189                                 HeapRegionNode newDstHRN;
2190                                 if(mapToFirstDimensionArrayNode.containsKey(hrnSummary)){
2191                                         //related heap region node is already exsited.
2192                                         newDstHRN=mapToFirstDimensionArrayNode.get(hrnSummary);
2193                                 }else{
2194                                         newDstHRN=hrnSummary;
2195                                 }
2196                                  doneSetIdentifier = newDstHRN.getIDString() + "_" + fieldDescriptor;                                                            
2197                                  if(!doneSet.contains(doneSetIdentifier)){
2198                                  // add new work item
2199                                          HashMap<HeapRegionNode, FieldDescriptor> newMap = 
2200                                             new HashMap<HeapRegionNode, FieldDescriptor>();
2201                                          newMap.put(newDstHRN, fieldDescriptor);
2202                                          workSet.add(newMap);
2203                                   }                             
2204                         }
2205                     
2206                 }else{
2207                     // if there exists corresponding summary node
2208                     HeapRegionNode hrnDst=mapTypeToExistingSummaryNode.get(type);
2209                     
2210                     RefEdge edgeToSummary = new RefEdge(srcHRN, // source
2211                                                         hrnDst, // dest
2212                                                         fd.getType(), // type
2213                                                         fd.getSymbol(), // field name
2214                                                         srcHRN.getAlpha(), // beta
2215                                                         ExistPredSet.factory(rg.predTrue), // predicates  
2216                                                         null
2217                                                         );
2218                     rg.addRefEdge(srcHRN, hrnDst, edgeToSummary);
2219                     
2220                 }               
2221             }       
2222         }           
2223     }   
2224 //    debugSnapshot(rg, fm, true);
2225     return rg;
2226 }
2227
2228 // return all allocation sites in the method (there is one allocation
2229 // site per FlatNew node in a method)
2230 private HashSet<AllocSite> getAllocationSiteSet(Descriptor d) {
2231   if( !mapDescriptorToAllocSiteSet.containsKey(d) ) {
2232     buildAllocationSiteSet(d);
2233   }
2234
2235   return mapDescriptorToAllocSiteSet.get(d);
2236
2237 }
2238
2239 private void buildAllocationSiteSet(Descriptor d) {
2240     HashSet<AllocSite> s = new HashSet<AllocSite>();
2241
2242     FlatMethod fm;
2243     if( d instanceof MethodDescriptor ) {
2244       fm = state.getMethodFlat( (MethodDescriptor) d);
2245     } else {
2246       assert d instanceof TaskDescriptor;
2247       fm = state.getMethodFlat( (TaskDescriptor) d);
2248     }
2249     pm.analyzeMethod(fm);
2250
2251     // visit every node in this FlatMethod's IR graph
2252     // and make a set of the allocation sites from the
2253     // FlatNew node's visited
2254     HashSet<FlatNode> visited = new HashSet<FlatNode>();
2255     HashSet<FlatNode> toVisit = new HashSet<FlatNode>();
2256     toVisit.add(fm);
2257
2258     while( !toVisit.isEmpty() ) {
2259       FlatNode n = toVisit.iterator().next();
2260
2261       if( n instanceof FlatNew ) {
2262         s.add(getAllocSiteFromFlatNewPRIVATE( (FlatNew) n) );
2263       }
2264
2265       toVisit.remove(n);
2266       visited.add(n);
2267
2268       for( int i = 0; i < pm.numNext(n); ++i ) {
2269         FlatNode child = pm.getNext(n, i);
2270         if( !visited.contains(child) ) {
2271           toVisit.add(child);
2272         }
2273       }
2274     }
2275
2276     mapDescriptorToAllocSiteSet.put(d, s);
2277   }
2278
2279         private HashSet<AllocSite> getFlaggedAllocationSites(Descriptor dIn) {
2280
2281                 HashSet<AllocSite> out = new HashSet<AllocSite>();
2282                 HashSet<Descriptor> toVisit = new HashSet<Descriptor>();
2283                 HashSet<Descriptor> visited = new HashSet<Descriptor>();
2284
2285                 toVisit.add(dIn);
2286
2287                 while (!toVisit.isEmpty()) {
2288                         Descriptor d = toVisit.iterator().next();
2289                         toVisit.remove(d);
2290                         visited.add(d);
2291
2292                         HashSet<AllocSite> asSet = getAllocationSiteSet(d);
2293                         Iterator asItr = asSet.iterator();
2294                         while (asItr.hasNext()) {
2295                                 AllocSite as = (AllocSite) asItr.next();
2296                                 if (as.getDisjointAnalysisId() != null) {
2297                                         out.add(as);
2298                                 }
2299                         }
2300
2301                         // enqueue callees of this method to be searched for
2302                         // allocation sites also
2303                         Set callees = callGraph.getCalleeSet(d);
2304                         if (callees != null) {
2305                                 Iterator methItr = callees.iterator();
2306                                 while (methItr.hasNext()) {
2307                                         MethodDescriptor md = (MethodDescriptor) methItr.next();
2308
2309                                         if (!visited.contains(md)) {
2310                                                 toVisit.add(md);
2311                                         }
2312                                 }
2313                         }
2314                 }
2315
2316                 return out;
2317         }
2318  
2319     
2320 private HashSet<AllocSite>
2321 getFlaggedAllocationSitesReachableFromTaskPRIVATE(TaskDescriptor td) {
2322
2323   HashSet<AllocSite> asSetTotal = new HashSet<AllocSite>();
2324   HashSet<Descriptor>     toVisit    = new HashSet<Descriptor>();
2325   HashSet<Descriptor>     visited    = new HashSet<Descriptor>();
2326
2327   toVisit.add(td);
2328
2329   // traverse this task and all methods reachable from this task
2330   while( !toVisit.isEmpty() ) {
2331     Descriptor d = toVisit.iterator().next();
2332     toVisit.remove(d);
2333     visited.add(d);
2334
2335     HashSet<AllocSite> asSet = getAllocationSiteSet(d);
2336     Iterator asItr = asSet.iterator();
2337     while( asItr.hasNext() ) {
2338         AllocSite as = (AllocSite) asItr.next();
2339         TypeDescriptor typed = as.getType();
2340         if( typed != null ) {
2341           ClassDescriptor cd = typed.getClassDesc();
2342           if( cd != null && cd.hasFlags() ) {
2343             asSetTotal.add(as);
2344           }
2345         }
2346     }
2347
2348     // enqueue callees of this method to be searched for
2349     // allocation sites also
2350     Set callees = callGraph.getCalleeSet(d);
2351     if( callees != null ) {
2352         Iterator methItr = callees.iterator();
2353         while( methItr.hasNext() ) {
2354           MethodDescriptor md = (MethodDescriptor) methItr.next();
2355
2356           if( !visited.contains(md) ) {
2357             toVisit.add(md);
2358           }
2359         }
2360     }
2361   }
2362
2363   return asSetTotal;
2364 }
2365
2366   public Set<Descriptor> getDescriptorsToAnalyze() {
2367     return descriptorsToAnalyze;
2368   }
2369
2370   public EffectsAnalysis getEffectsAnalysis(){
2371     return effectsAnalysis;
2372   }
2373   
2374   
2375   // get successive captures of the analysis state, use compiler
2376   // flags to control
2377   boolean takeDebugSnapshots = false;
2378   String  descSymbolDebug    = null;
2379   boolean stopAfterCapture   = false;
2380   int     snapVisitCounter   = 0;
2381   int     snapNodeCounter    = 0;
2382   int     visitStartCapture  = 0;
2383   int     numVisitsToCapture = 0;
2384
2385
2386   void debugSnapshot( ReachGraph rg, FlatNode fn, boolean in ) {
2387     if( snapVisitCounter > visitStartCapture + numVisitsToCapture ) {
2388       return;
2389     }
2390
2391     if( in ) {
2392
2393     }
2394
2395     if( snapVisitCounter >= visitStartCapture ) {
2396       System.out.println( "    @@@ snapping visit="+snapVisitCounter+
2397                           ", node="+snapNodeCounter+
2398                           " @@@" );
2399       String graphName;
2400       if( in ) {
2401         graphName = String.format( "snap%03d_%04din",
2402                                    snapVisitCounter,
2403                                    snapNodeCounter );
2404       } else {
2405         graphName = String.format( "snap%03d_%04dout",
2406                                    snapVisitCounter,
2407                                    snapNodeCounter );
2408       }
2409       if( fn != null ) {
2410         graphName = graphName + fn;
2411       }
2412       rg.writeGraph( graphName,
2413                      true,   // write labels (variables)
2414                      true,   // selectively hide intermediate temp vars
2415                      true,   // prune unreachable heap regions
2416                      false,  // hide reachability
2417                      true,   // hide subset reachability states
2418                      true,   // hide predicates
2419                      false );// hide edge taints
2420     }
2421   }
2422
2423 }