changed organization and brought in a few new pieces for new disjoint+ooojava
[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       if( shouldAnalysisTrack( fld.getType() ) ) {
1102         rg.assignTempXEqualToTempYFieldF( lhs, rhs, fld );
1103
1104         if( doEffectsAnalysis && fmContaining != fmAnalysisEntry ) {
1105           effectsAnalysis.analyzeFlatFieldNode( rg, rhs, fld );
1106           
1107           if(rblockStatus.isInCriticalRegion(fmContaining, fn)){
1108             // x=y.f, stall y if not accessible
1109             // contributes read effects on stall site of y
1110             // after this, x and y are accessbile. 
1111             
1112             rg.addAccessibleVar(lhs);
1113             rg.addAccessibleVar(rhs);            
1114           }
1115         }
1116       }          
1117       break;
1118
1119     case FKind.FlatSetFieldNode:
1120       FlatSetFieldNode fsfn = (FlatSetFieldNode) fn;
1121       lhs = fsfn.getDst();
1122       fld = fsfn.getField();
1123       rhs = fsfn.getSrc();
1124
1125       if( shouldAnalysisTrack( fld.getType() ) ) {
1126         boolean strongUpdate = rg.assignTempXFieldFEqualToTempY( lhs, fld, rhs );
1127
1128         if( doEffectsAnalysis && fmContaining != fmAnalysisEntry ) {
1129           effectsAnalysis.analyzeFlatSetFieldNode( rg, lhs, fld, strongUpdate );
1130           
1131           if(rblockStatus.isInCriticalRegion(fmContaining, fn)){
1132             // x.y=f , stall x and y if they are not accessible
1133             // also contribute write effects on stall site of x
1134             
1135             // accessible status update
1136             rg.addAccessibleVar(lhs);
1137             rg.addAccessibleVar(rhs);            
1138           }
1139           
1140         }
1141       }           
1142       break;
1143
1144     case FKind.FlatElementNode:
1145       FlatElementNode fen = (FlatElementNode) fn;
1146       lhs = fen.getDst();
1147       rhs = fen.getSrc();
1148       if( shouldAnalysisTrack( lhs.getType() ) ) {
1149
1150         assert rhs.getType() != null;
1151         assert rhs.getType().isArray();
1152         
1153         TypeDescriptor  tdElement = rhs.getType().dereference();
1154         FieldDescriptor fdElement = getArrayField( tdElement );
1155   
1156         rg.assignTempXEqualToTempYFieldF( lhs, rhs, fdElement );
1157         
1158         if( doEffectsAnalysis && fmContaining != fmAnalysisEntry ) {
1159           effectsAnalysis.analyzeFlatFieldNode( rg, rhs, fdElement );       
1160           
1161           if(rblockStatus.isInCriticalRegion(fmContaining, fn)){
1162             // x=y.f, stall y if not accessible
1163             // contributes read effects on stall site of y
1164             // after this, x and y are accessbile. 
1165             
1166             rg.addAccessibleVar(lhs);
1167             rg.addAccessibleVar(rhs);            
1168           }
1169           
1170         }
1171       }
1172       break;
1173
1174     case FKind.FlatSetElementNode:
1175       FlatSetElementNode fsen = (FlatSetElementNode) fn;
1176
1177       if( arrayReferencees.doesNotCreateNewReaching( fsen ) ) {
1178         // skip this node if it cannot create new reachability paths
1179         break;
1180       }
1181
1182       lhs = fsen.getDst();
1183       rhs = fsen.getSrc();
1184       if( shouldAnalysisTrack( rhs.getType() ) ) {
1185
1186         assert lhs.getType() != null;
1187         assert lhs.getType().isArray();
1188         
1189         TypeDescriptor  tdElement = lhs.getType().dereference();
1190         FieldDescriptor fdElement = getArrayField( tdElement );
1191
1192         rg.assignTempXFieldFEqualToTempY( lhs, fdElement, rhs );
1193
1194         if( doEffectsAnalysis && fmContaining != fmAnalysisEntry ) {
1195           effectsAnalysis.analyzeFlatSetFieldNode( rg, lhs, fdElement,
1196                                                    false );
1197           
1198           if(rblockStatus.isInCriticalRegion(fmContaining, fn)){
1199             // x.y=f , stall x and y if they are not accessible
1200             // also contribute write effects on stall site of x
1201             
1202             // accessible status update
1203             rg.addAccessibleVar(lhs);
1204             rg.addAccessibleVar(rhs);            
1205           }
1206           
1207         }
1208       }
1209       break;
1210       
1211     case FKind.FlatNew:
1212       FlatNew fnn = (FlatNew) fn;
1213       lhs = fnn.getDst();
1214       if( shouldAnalysisTrack( lhs.getType() ) ) {
1215         AllocSite as = getAllocSiteFromFlatNewPRIVATE( fnn );   
1216         rg.assignTempEqualToNewAlloc( lhs, as );
1217         
1218         if (doEffectsAnalysis && fmContaining != fmAnalysisEntry) {
1219           if (rblockStatus.isInCriticalRegion(fmContaining, fn)) {
1220             // after creating new object, lhs is accessible
1221             rg.addAccessibleVar(lhs);
1222           }
1223         } 
1224         
1225       }
1226       break;
1227
1228     case FKind.FlatSESEEnterNode:
1229       if( doEffectsAnalysis && fmContaining != fmAnalysisEntry ) {
1230         FlatSESEEnterNode sese = (FlatSESEEnterNode) fn;
1231         rg.taintInSetVars( sese );                         
1232       }
1233       break;
1234
1235     case FKind.FlatSESEExitNode:
1236       if( doEffectsAnalysis && fmContaining != fmAnalysisEntry ) {
1237         FlatSESEExitNode fsexn = (FlatSESEExitNode) fn;
1238         rg.removeInContextTaints( fsexn.getFlatEnter() );
1239         // sese exit clears all mappings of accessible vars and stall sites
1240         // need to wipe out stall site taints
1241         rg.clearAccessibleVarSet();        
1242       }
1243       break;
1244
1245
1246     case FKind.FlatCall: {
1247       Descriptor mdCaller;
1248       if( fmContaining.getMethod() != null ){
1249         mdCaller = fmContaining.getMethod();
1250       } else {
1251         mdCaller = fmContaining.getTask();
1252       }      
1253       FlatCall         fc       = (FlatCall) fn;
1254       MethodDescriptor mdCallee = fc.getMethod();
1255       FlatMethod       fmCallee = state.getMethodFlat( mdCallee );
1256
1257
1258       boolean debugCallSite =
1259         mdCaller.getSymbol().equals( state.DISJOINTDEBUGCALLER ) &&
1260         mdCallee.getSymbol().equals( state.DISJOINTDEBUGCALLEE );
1261
1262       boolean writeDebugDOTs = false;
1263       boolean stopAfter      = false;
1264       if( debugCallSite ) {
1265         ++ReachGraph.debugCallSiteVisitCounter;
1266         System.out.println( "    $$$ Debug call site visit "+
1267                             ReachGraph.debugCallSiteVisitCounter+
1268                             " $$$"
1269                             );
1270         if( 
1271            (ReachGraph.debugCallSiteVisitCounter >= 
1272             ReachGraph.debugCallSiteVisitStartCapture)  &&
1273            
1274            (ReachGraph.debugCallSiteVisitCounter < 
1275             ReachGraph.debugCallSiteVisitStartCapture + 
1276             ReachGraph.debugCallSiteNumVisitsToCapture)
1277             ) {
1278           writeDebugDOTs = true;
1279           System.out.println( "      $$$ Capturing this call site visit $$$" );
1280           if( ReachGraph.debugCallSiteStopAfter &&
1281               (ReachGraph.debugCallSiteVisitCounter == 
1282                ReachGraph.debugCallSiteVisitStartCapture + 
1283                ReachGraph.debugCallSiteNumVisitsToCapture - 1)
1284               ) {
1285             stopAfter = true;
1286           }
1287         }
1288       }
1289
1290
1291       // calculate the heap this call site can reach--note this is
1292       // not used for the current call site transform, we are
1293       // grabbing this heap model for future analysis of the callees,
1294       // so if different results emerge we will return to this site
1295       ReachGraph heapForThisCall_old = 
1296         getIHMcontribution( mdCallee, fc );
1297
1298       // the computation of the callee-reachable heap
1299       // is useful for making the callee starting point
1300       // and for applying the call site transfer function
1301       Set<Integer> callerNodeIDsCopiedToCallee = 
1302         new HashSet<Integer>();
1303
1304       ReachGraph heapForThisCall_cur = 
1305         rg.makeCalleeView( fc, 
1306                            fmCallee,
1307                            callerNodeIDsCopiedToCallee,
1308                            writeDebugDOTs
1309                            );
1310
1311       if( !heapForThisCall_cur.equals( heapForThisCall_old ) ) {        
1312         // if heap at call site changed, update the contribution,
1313         // and reschedule the callee for analysis
1314         addIHMcontribution( mdCallee, fc, heapForThisCall_cur );        
1315
1316         // map a FlatCall to its enclosing method/task descriptor 
1317         // so we can write that info out later
1318         fc2enclosing.put( fc, mdCaller );
1319
1320         if( state.DISJOINTDEBUGSCHEDULING ) {
1321           System.out.println( "  context changed, scheduling callee: "+mdCallee );
1322         }
1323
1324         if( state.DISJOINTDVISITSTACKEESONTOP ) {
1325           calleesToEnqueue.add( mdCallee );
1326         } else {
1327           enqueue( mdCallee );
1328         }
1329
1330       }
1331
1332       // the transformation for a call site should update the
1333       // current heap abstraction with any effects from the callee,
1334       // or if the method is virtual, the effects from any possible
1335       // callees, so find the set of callees...
1336       Set<MethodDescriptor> setPossibleCallees;
1337       if( determinismDesired ) {
1338         // use an ordered set
1339         setPossibleCallees = new TreeSet<MethodDescriptor>( dComp );        
1340       } else {
1341         // otherwise use a speedy hashset
1342         setPossibleCallees = new HashSet<MethodDescriptor>();
1343       }
1344
1345       if( mdCallee.isStatic() ) {        
1346         setPossibleCallees.add( mdCallee );
1347       } else {
1348         TypeDescriptor typeDesc = fc.getThis().getType();
1349         setPossibleCallees.addAll( callGraph.getMethods( mdCallee, 
1350                                                          typeDesc )
1351                                    );
1352       }
1353
1354       ReachGraph rgMergeOfEffects = new ReachGraph();
1355
1356       Iterator<MethodDescriptor> mdItr = setPossibleCallees.iterator();
1357       while( mdItr.hasNext() ) {
1358         MethodDescriptor mdPossible = mdItr.next();
1359         FlatMethod       fmPossible = state.getMethodFlat( mdPossible );
1360
1361         addDependent( mdPossible, // callee
1362                       d );        // caller
1363
1364         // don't alter the working graph (rg) until we compute a 
1365         // result for every possible callee, merge them all together,
1366         // then set rg to that
1367         ReachGraph rgCopy = new ReachGraph();
1368         rgCopy.merge( rg );             
1369                 
1370         ReachGraph rgEffect = getPartial( mdPossible );
1371
1372         if( rgEffect == null ) {
1373           // if this method has never been analyzed just schedule it 
1374           // for analysis and skip over this call site for now
1375           if( state.DISJOINTDVISITSTACKEESONTOP ) {
1376             calleesToEnqueue.add( mdPossible );
1377           } else {
1378             enqueue( mdPossible );
1379           }
1380           
1381           if( state.DISJOINTDEBUGSCHEDULING ) {
1382             System.out.println( "  callee hasn't been analyzed, scheduling: "+mdPossible );
1383           }
1384
1385
1386         } else {
1387           // calculate the method call transform         
1388           rgCopy.resolveMethodCall( fc, 
1389                                     fmPossible, 
1390                                     rgEffect,
1391                                     callerNodeIDsCopiedToCallee,
1392                                     writeDebugDOTs
1393                                     );
1394         }
1395         
1396         rgMergeOfEffects.merge( rgCopy );        
1397       }
1398
1399
1400       if( stopAfter ) {
1401         System.out.println( "$$$ Exiting after requested captures of call site. $$$" );
1402         System.exit( 0 );
1403       }
1404
1405
1406       // now that we've taken care of building heap models for
1407       // callee analysis, finish this transformation
1408       rg = rgMergeOfEffects;
1409     } break;
1410       
1411
1412     case FKind.FlatReturnNode:
1413       FlatReturnNode frn = (FlatReturnNode) fn;
1414       rhs = frn.getReturnTemp();
1415       if( rhs != null && shouldAnalysisTrack( rhs.getType() ) ) {
1416         rg.assignReturnEqualToTemp( rhs );
1417       }
1418       setRetNodes.add( frn );
1419       break;
1420
1421     } // end switch
1422
1423     
1424     // dead variables were removed before the above transfer function
1425     // was applied, so eliminate heap regions and edges that are no
1426     // longer part of the abstractly-live heap graph, and sweep up
1427     // and reachability effects that are altered by the reduction
1428     //rg.abstractGarbageCollect();
1429     //rg.globalSweep();
1430
1431
1432     // back edges are strictly monotonic
1433     if( pm.isBackEdge( fn ) ) {
1434       ReachGraph rgPrevResult = mapBackEdgeToMonotone.get( fn );
1435       rg.merge( rgPrevResult );
1436       mapBackEdgeToMonotone.put( fn, rg );
1437     }
1438     
1439     // at this point rg should be the correct update
1440     // by an above transfer function, or untouched if
1441     // the flat node type doesn't affect the heap
1442     return rg;
1443   }
1444
1445
1446   
1447   // this method should generate integers strictly greater than zero!
1448   // special "shadow" regions are made from a heap region by negating
1449   // the ID
1450   static public Integer generateUniqueHeapRegionNodeID() {
1451     ++uniqueIDcount;
1452     return new Integer( uniqueIDcount );
1453   }
1454
1455
1456   
1457   static public FieldDescriptor getArrayField( TypeDescriptor tdElement ) {
1458     FieldDescriptor fdElement = mapTypeToArrayField.get( tdElement );
1459     if( fdElement == null ) {
1460       fdElement = new FieldDescriptor( new Modifiers( Modifiers.PUBLIC ),
1461                                        tdElement,
1462                                        arrayElementFieldName,
1463                                        null,
1464                                        false );
1465       mapTypeToArrayField.put( tdElement, fdElement );
1466     }
1467     return fdElement;
1468   }
1469
1470   
1471   
1472   private void writeFinalGraphs() {
1473     Set entrySet = mapDescriptorToCompleteReachGraph.entrySet();
1474     Iterator itr = entrySet.iterator();
1475     while( itr.hasNext() ) {
1476       Map.Entry  me = (Map.Entry)  itr.next();
1477       Descriptor  d = (Descriptor) me.getKey();
1478       ReachGraph rg = (ReachGraph) me.getValue();
1479
1480       rg.writeGraph( "COMPLETE"+d,
1481                      true,    // write labels (variables)                
1482                      true,    // selectively hide intermediate temp vars 
1483                      true,    // prune unreachable heap regions          
1484                      false,   // hide reachability altogether
1485                      true,    // hide subset reachability states         
1486                      true,    // hide predicates
1487                      false ); // hide edge taints                        
1488     }
1489   }
1490
1491   private void writeFinalIHMs() {
1492     Iterator d2IHMsItr = mapDescriptorToIHMcontributions.entrySet().iterator();
1493     while( d2IHMsItr.hasNext() ) {
1494       Map.Entry                        me1 = (Map.Entry)                       d2IHMsItr.next();
1495       Descriptor                         d = (Descriptor)                      me1.getKey();
1496       Hashtable<FlatCall, ReachGraph> IHMs = (Hashtable<FlatCall, ReachGraph>) me1.getValue();
1497
1498       Iterator fc2rgItr = IHMs.entrySet().iterator();
1499       while( fc2rgItr.hasNext() ) {
1500         Map.Entry  me2 = (Map.Entry)  fc2rgItr.next();
1501         FlatCall   fc  = (FlatCall)   me2.getKey();
1502         ReachGraph rg  = (ReachGraph) me2.getValue();
1503                 
1504         rg.writeGraph( "IHMPARTFOR"+d+"FROM"+fc2enclosing.get( fc )+fc,
1505                        true,   // write labels (variables)
1506                        true,   // selectively hide intermediate temp vars
1507                        true,   // hide reachability altogether
1508                        true,   // prune unreachable heap regions
1509                        true,   // hide subset reachability states
1510                        false,  // hide predicates
1511                        true ); // hide edge taints
1512       }
1513     }
1514   }
1515
1516   private void writeInitialContexts() {
1517     Set entrySet = mapDescriptorToInitialContext.entrySet();
1518     Iterator itr = entrySet.iterator();
1519     while( itr.hasNext() ) {
1520       Map.Entry  me = (Map.Entry)  itr.next();
1521       Descriptor  d = (Descriptor) me.getKey();
1522       ReachGraph rg = (ReachGraph) me.getValue();
1523
1524       rg.writeGraph( "INITIAL"+d,
1525                      true,   // write labels (variables)                
1526                      true,   // selectively hide intermediate temp vars 
1527                      true,   // prune unreachable heap regions          
1528                      false,  // hide all reachability
1529                      true,   // hide subset reachability states         
1530                      true,   // hide predicates
1531                      false );// hide edge taints                        
1532     }
1533   }
1534    
1535
1536   protected ReachGraph getPartial( Descriptor d ) {
1537     return mapDescriptorToCompleteReachGraph.get( d );
1538   }
1539
1540   protected void setPartial( Descriptor d, ReachGraph rg ) {
1541     mapDescriptorToCompleteReachGraph.put( d, rg );
1542
1543     // when the flag for writing out every partial
1544     // result is set, we should spit out the graph,
1545     // but in order to give it a unique name we need
1546     // to track how many partial results for this
1547     // descriptor we've already written out
1548     if( writeAllIncrementalDOTs ) {
1549       if( !mapDescriptorToNumUpdates.containsKey( d ) ) {
1550         mapDescriptorToNumUpdates.put( d, new Integer( 0 ) );
1551       }
1552       Integer n = mapDescriptorToNumUpdates.get( d );
1553       
1554       rg.writeGraph( d+"COMPLETE"+String.format( "%05d", n ),
1555                      true,   // write labels (variables)
1556                      true,   // selectively hide intermediate temp vars
1557                      true,   // prune unreachable heap regions
1558                      false,  // hide all reachability
1559                      true,   // hide subset reachability states
1560                      false,  // hide predicates
1561                      false); // hide edge taints
1562       
1563       mapDescriptorToNumUpdates.put( d, n + 1 );
1564     }
1565   }
1566
1567
1568
1569   // return just the allocation site associated with one FlatNew node
1570   protected AllocSite getAllocSiteFromFlatNewPRIVATE( FlatNew fnew ) {
1571
1572     if( !mapFlatNewToAllocSite.containsKey( fnew ) ) {
1573       AllocSite as = AllocSite.factory( allocationDepth, 
1574                                         fnew, 
1575                                         fnew.getDisjointId(),
1576                                         false
1577                                         );
1578
1579       // the newest nodes are single objects
1580       for( int i = 0; i < allocationDepth; ++i ) {
1581         Integer id = generateUniqueHeapRegionNodeID();
1582         as.setIthOldest( i, id );
1583         mapHrnIdToAllocSite.put( id, as );
1584       }
1585
1586       // the oldest node is a summary node
1587       as.setSummary( generateUniqueHeapRegionNodeID() );
1588
1589       mapFlatNewToAllocSite.put( fnew, as );
1590     }
1591
1592     return mapFlatNewToAllocSite.get( fnew );
1593   }
1594
1595
1596   public static boolean shouldAnalysisTrack( TypeDescriptor type ) {
1597     // don't track primitive types, but an array
1598     // of primitives is heap memory
1599     if( type.isImmutable() ) {
1600       return type.isArray();
1601     }
1602
1603     // everything else is an object
1604     return true;
1605   }
1606
1607   protected int numMethodsAnalyzed() {    
1608     return descriptorsToAnalyze.size();
1609   }
1610   
1611
1612   
1613   
1614   
1615   // Take in source entry which is the program's compiled entry and
1616   // create a new analysis entry, a method that takes no parameters
1617   // and appears to allocate the command line arguments and call the
1618   // source entry with them.  The purpose of this analysis entry is
1619   // to provide a top-level method context with no parameters left.
1620   protected void makeAnalysisEntryMethod( MethodDescriptor mdSourceEntry ) {
1621
1622     Modifiers mods = new Modifiers();
1623     mods.addModifier( Modifiers.PUBLIC );
1624     mods.addModifier( Modifiers.STATIC );
1625
1626     TypeDescriptor returnType = 
1627       new TypeDescriptor( TypeDescriptor.VOID );
1628
1629     this.mdAnalysisEntry = 
1630       new MethodDescriptor( mods,
1631                             returnType,
1632                             "analysisEntryMethod"
1633                             );
1634
1635     TempDescriptor cmdLineArgs = 
1636       new TempDescriptor( "args",
1637                           mdSourceEntry.getParamType( 0 )
1638                           );
1639
1640     FlatNew fn = 
1641       new FlatNew( mdSourceEntry.getParamType( 0 ),
1642                    cmdLineArgs,
1643                    false // is global 
1644                    );
1645     
1646     TempDescriptor[] sourceEntryArgs = new TempDescriptor[1];
1647     sourceEntryArgs[0] = cmdLineArgs;
1648     
1649     FlatCall fc = 
1650       new FlatCall( mdSourceEntry,
1651                     null, // dst temp
1652                     null, // this temp
1653                     sourceEntryArgs
1654                     );
1655
1656     FlatReturnNode frn = new FlatReturnNode( null );
1657
1658     FlatExit fe = new FlatExit();
1659
1660     this.fmAnalysisEntry = 
1661       new FlatMethod( mdAnalysisEntry, 
1662                       fe
1663                       );
1664
1665     this.fmAnalysisEntry.addNext( fn );
1666     fn.addNext( fc );
1667     fc.addNext( frn );
1668     frn.addNext( fe );
1669   }
1670
1671
1672   protected LinkedList<Descriptor> topologicalSort( Set<Descriptor> toSort ) {
1673
1674     Set<Descriptor> discovered;
1675
1676     if( determinismDesired ) {
1677       // use an ordered set
1678       discovered = new TreeSet<Descriptor>( dComp );      
1679     } else {
1680       // otherwise use a speedy hashset
1681       discovered = new HashSet<Descriptor>();
1682     }
1683
1684     LinkedList<Descriptor> sorted = new LinkedList<Descriptor>();
1685   
1686     Iterator<Descriptor> itr = toSort.iterator();
1687     while( itr.hasNext() ) {
1688       Descriptor d = itr.next();
1689           
1690       if( !discovered.contains( d ) ) {
1691         dfsVisit( d, toSort, sorted, discovered );
1692       }
1693     }
1694     
1695     return sorted;
1696   }
1697   
1698   // While we're doing DFS on call graph, remember
1699   // dependencies for efficient queuing of methods
1700   // during interprocedural analysis:
1701   //
1702   // a dependent of a method decriptor d for this analysis is:
1703   //  1) a method or task that invokes d
1704   //  2) in the descriptorsToAnalyze set
1705   protected void dfsVisit( Descriptor             d,
1706                            Set       <Descriptor> toSort,                        
1707                            LinkedList<Descriptor> sorted,
1708                            Set       <Descriptor> discovered ) {
1709     discovered.add( d );
1710     
1711     // only methods have callers, tasks never do
1712     if( d instanceof MethodDescriptor ) {
1713
1714       MethodDescriptor md = (MethodDescriptor) d;
1715
1716       // the call graph is not aware that we have a fabricated
1717       // analysis entry that calls the program source's entry
1718       if( md == mdSourceEntry ) {
1719         if( !discovered.contains( mdAnalysisEntry ) ) {
1720           addDependent( mdSourceEntry,  // callee
1721                         mdAnalysisEntry // caller
1722                         );
1723           dfsVisit( mdAnalysisEntry, toSort, sorted, discovered );
1724         }
1725       }
1726
1727       // otherwise call graph guides DFS
1728       Iterator itr = callGraph.getCallerSet( md ).iterator();
1729       while( itr.hasNext() ) {
1730         Descriptor dCaller = (Descriptor) itr.next();
1731         
1732         // only consider callers in the original set to analyze
1733         if( !toSort.contains( dCaller ) ) {
1734           continue;
1735         }
1736           
1737         if( !discovered.contains( dCaller ) ) {
1738           addDependent( md,     // callee
1739                         dCaller // caller
1740                         );
1741
1742           dfsVisit( dCaller, toSort, sorted, discovered );
1743         }
1744       }
1745     }
1746     
1747     // for leaf-nodes last now!
1748     sorted.addLast( d );
1749   }
1750
1751
1752   protected void enqueue( Descriptor d ) {
1753
1754     if( !descriptorsToVisitSet.contains( d ) ) {
1755
1756       if( state.DISJOINTDVISITSTACK ||
1757           state.DISJOINTDVISITSTACKEESONTOP
1758           ) {
1759         descriptorsToVisitStack.add( d );
1760
1761       } else if( state.DISJOINTDVISITPQUE ) {
1762         Integer priority = mapDescriptorToPriority.get( d );
1763         descriptorsToVisitQ.add( new DescriptorQWrapper( priority, 
1764                                                          d ) 
1765                                  );
1766       }
1767
1768       descriptorsToVisitSet.add( d );
1769     }
1770   }
1771
1772
1773   // a dependent of a method decriptor d for this analysis is:
1774   //  1) a method or task that invokes d
1775   //  2) in the descriptorsToAnalyze set
1776   protected void addDependent( Descriptor callee, Descriptor caller ) {
1777     Set<Descriptor> deps = mapDescriptorToSetDependents.get( callee );
1778     if( deps == null ) {
1779       deps = new HashSet<Descriptor>();
1780     }
1781     deps.add( caller );
1782     mapDescriptorToSetDependents.put( callee, deps );
1783   }
1784   
1785   protected Set<Descriptor> getDependents( Descriptor callee ) {
1786     Set<Descriptor> deps = mapDescriptorToSetDependents.get( callee );
1787     if( deps == null ) {
1788       deps = new HashSet<Descriptor>();
1789       mapDescriptorToSetDependents.put( callee, deps );
1790     }
1791     return deps;
1792   }
1793
1794   
1795   public Hashtable<FlatCall, ReachGraph> getIHMcontributions( Descriptor d ) {
1796
1797     Hashtable<FlatCall, ReachGraph> heapsFromCallers = 
1798       mapDescriptorToIHMcontributions.get( d );
1799     
1800     if( heapsFromCallers == null ) {
1801       heapsFromCallers = new Hashtable<FlatCall, ReachGraph>();
1802       mapDescriptorToIHMcontributions.put( d, heapsFromCallers );
1803     }
1804     
1805     return heapsFromCallers;
1806   }
1807
1808   public ReachGraph getIHMcontribution( Descriptor d, 
1809                                         FlatCall   fc
1810                                         ) {
1811     Hashtable<FlatCall, ReachGraph> heapsFromCallers = 
1812       getIHMcontributions( d );
1813
1814     if( !heapsFromCallers.containsKey( fc ) ) {
1815       return null;
1816     }
1817
1818     return heapsFromCallers.get( fc );
1819   }
1820
1821
1822   public void addIHMcontribution( Descriptor d,
1823                                   FlatCall   fc,
1824                                   ReachGraph rg
1825                                   ) {
1826     Hashtable<FlatCall, ReachGraph> heapsFromCallers = 
1827       getIHMcontributions( d );
1828
1829     heapsFromCallers.put( fc, rg );
1830   }
1831
1832
1833   private AllocSite createParameterAllocSite( ReachGraph     rg, 
1834                                               TempDescriptor tempDesc,
1835                                               boolean        flagRegions
1836                                               ) {
1837     
1838     FlatNew flatNew;
1839     if( flagRegions ) {
1840       flatNew = new FlatNew( tempDesc.getType(), // type
1841                              tempDesc,           // param temp
1842                              false,              // global alloc?
1843                              "param"+tempDesc    // disjoint site ID string
1844                              );
1845     } else {
1846       flatNew = new FlatNew( tempDesc.getType(), // type
1847                              tempDesc,           // param temp
1848                              false,              // global alloc?
1849                              null                // disjoint site ID string
1850                              );
1851     }
1852
1853     // create allocation site
1854     AllocSite as = AllocSite.factory( allocationDepth, 
1855                                       flatNew, 
1856                                       flatNew.getDisjointId(),
1857                                       false
1858                                       );
1859     for (int i = 0; i < allocationDepth; ++i) {
1860         Integer id = generateUniqueHeapRegionNodeID();
1861         as.setIthOldest(i, id);
1862         mapHrnIdToAllocSite.put(id, as);
1863     }
1864     // the oldest node is a summary node
1865     as.setSummary( generateUniqueHeapRegionNodeID() );
1866     
1867     rg.age(as);
1868     
1869     return as;
1870     
1871   }
1872
1873 private Set<FieldDescriptor> getFieldSetTobeAnalyzed(TypeDescriptor typeDesc){
1874         
1875         Set<FieldDescriptor> fieldSet=new HashSet<FieldDescriptor>();
1876     if(!typeDesc.isImmutable()){
1877             ClassDescriptor classDesc = typeDesc.getClassDesc();                    
1878             for (Iterator it = classDesc.getFields(); it.hasNext();) {
1879                     FieldDescriptor field = (FieldDescriptor) it.next();
1880                     TypeDescriptor fieldType = field.getType();
1881                     if (shouldAnalysisTrack( fieldType )) {
1882                         fieldSet.add(field);                    
1883                     }
1884             }
1885     }
1886     return fieldSet;
1887         
1888 }
1889
1890   private HeapRegionNode createMultiDeimensionalArrayHRN(ReachGraph rg, AllocSite alloc, HeapRegionNode srcHRN, FieldDescriptor fd, Hashtable<HeapRegionNode, HeapRegionNode> map, Hashtable<TypeDescriptor, HeapRegionNode> mapToExistingNode, ReachSet alpha ){
1891
1892         int dimCount=fd.getType().getArrayCount();
1893         HeapRegionNode prevNode=null;
1894         HeapRegionNode arrayEntryNode=null;
1895         for(int i=dimCount;i>0;i--){
1896                 TypeDescriptor typeDesc=fd.getType().dereference();//hack to get instance of type desc
1897                 typeDesc.setArrayCount(i);
1898                 TempDescriptor tempDesc=new TempDescriptor(typeDesc.getSymbol(),typeDesc);
1899                 HeapRegionNode hrnSummary ;
1900                 if(!mapToExistingNode.containsKey(typeDesc)){
1901                         AllocSite as;
1902                         if(i==dimCount){
1903                                 as = alloc;
1904                         }else{
1905                           as = createParameterAllocSite(rg, tempDesc, false);
1906                         }
1907                         // make a new reference to allocated node
1908                     hrnSummary = 
1909                                 rg.createNewHeapRegionNode(as.getSummary(), // id or null to generate a new one
1910                                                            false, // single object?
1911                                                            true, // summary?
1912                                                            false, // out-of-context?
1913                                                            as.getType(), // type
1914                                                            as, // allocation site
1915                                                            alpha, // inherent reach
1916                                                            alpha, // current reach
1917                                                            ExistPredSet.factory(rg.predTrue), // predicates
1918                                                            tempDesc.toString() // description
1919                                                            );
1920                     rg.id2hrn.put(as.getSummary(),hrnSummary);
1921                     
1922                     mapToExistingNode.put(typeDesc, hrnSummary);
1923                 }else{
1924                         hrnSummary=mapToExistingNode.get(typeDesc);
1925                 }
1926             
1927             if(prevNode==null){
1928                     // make a new reference between new summary node and source
1929               RefEdge edgeToSummary = new RefEdge(srcHRN, // source
1930                                                         hrnSummary, // dest
1931                                                         typeDesc, // type
1932                                                         fd.getSymbol(), // field name
1933                                                         alpha, // beta
1934                                                   ExistPredSet.factory(rg.predTrue), // predicates
1935                                                   null
1936                                                         );
1937                     
1938                     rg.addRefEdge(srcHRN, hrnSummary, edgeToSummary);
1939                     prevNode=hrnSummary;
1940                     arrayEntryNode=hrnSummary;
1941             }else{
1942                     // make a new reference between summary nodes of array
1943                     RefEdge edgeToSummary = new RefEdge(prevNode, // source
1944                                                         hrnSummary, // dest
1945                                                         typeDesc, // type
1946                                                         arrayElementFieldName, // field name
1947                                                         alpha, // beta
1948                                                         ExistPredSet.factory(rg.predTrue), // predicates
1949                                                         null
1950                                                         );
1951                     
1952                     rg.addRefEdge(prevNode, hrnSummary, edgeToSummary);
1953                     prevNode=hrnSummary;
1954             }
1955             
1956         }
1957         
1958         // create a new obj node if obj has at least one non-primitive field
1959         TypeDescriptor type=fd.getType();
1960     if(getFieldSetTobeAnalyzed(type).size()>0){
1961         TypeDescriptor typeDesc=type.dereference();
1962         typeDesc.setArrayCount(0);
1963         if(!mapToExistingNode.containsKey(typeDesc)){
1964                 TempDescriptor tempDesc=new TempDescriptor(type.getSymbol(),typeDesc);
1965                 AllocSite as = createParameterAllocSite(rg, tempDesc, false);
1966                 // make a new reference to allocated node
1967                     HeapRegionNode hrnSummary = 
1968                                 rg.createNewHeapRegionNode(as.getSummary(), // id or null to generate a new one
1969                                                            false, // single object?
1970                                                            true, // summary?
1971                                                            false, // out-of-context?
1972                                                            typeDesc, // type
1973                                                            as, // allocation site
1974                                                            alpha, // inherent reach
1975                                                            alpha, // current reach
1976                                                            ExistPredSet.factory(rg.predTrue), // predicates
1977                                                            tempDesc.toString() // description
1978                                                            );
1979                     rg.id2hrn.put(as.getSummary(),hrnSummary);
1980                     mapToExistingNode.put(typeDesc, hrnSummary);
1981                     RefEdge edgeToSummary = new RefEdge(prevNode, // source
1982                                         hrnSummary, // dest
1983                                         typeDesc, // type
1984                                         arrayElementFieldName, // field name
1985                                         alpha, // beta
1986                                                         ExistPredSet.factory(rg.predTrue), // predicates
1987                                                         null
1988                                         );
1989                     rg.addRefEdge(prevNode, hrnSummary, edgeToSummary);
1990                     prevNode=hrnSummary;
1991         }else{
1992           HeapRegionNode hrnSummary=mapToExistingNode.get(typeDesc);
1993                 if(prevNode.getReferenceTo(hrnSummary, typeDesc, arrayElementFieldName)==null){
1994                         RefEdge edgeToSummary = new RefEdge(prevNode, // source
1995                                         hrnSummary, // dest
1996                                         typeDesc, // type
1997                                         arrayElementFieldName, // field name
1998                                         alpha, // beta
1999                                                             ExistPredSet.factory(rg.predTrue), // predicates
2000                                                             null
2001                                         );
2002                     rg.addRefEdge(prevNode, hrnSummary, edgeToSummary);
2003                 }
2004                  prevNode=hrnSummary;
2005         }
2006     }
2007         
2008         map.put(arrayEntryNode, prevNode);
2009         return arrayEntryNode;
2010 }
2011
2012 private ReachGraph createInitialTaskReachGraph(FlatMethod fm) {
2013     ReachGraph rg = new ReachGraph();
2014     TaskDescriptor taskDesc = fm.getTask();
2015     
2016     for (int idx = 0; idx < taskDesc.numParameters(); idx++) {
2017         Descriptor paramDesc = taskDesc.getParameter(idx);
2018         TypeDescriptor paramTypeDesc = taskDesc.getParamType(idx);
2019         
2020         // setup data structure
2021         Set<HashMap<HeapRegionNode, FieldDescriptor>> workSet = 
2022             new HashSet<HashMap<HeapRegionNode, FieldDescriptor>>();
2023         Hashtable<TypeDescriptor, HeapRegionNode> mapTypeToExistingSummaryNode = 
2024             new Hashtable<TypeDescriptor, HeapRegionNode>();
2025         Hashtable<HeapRegionNode, HeapRegionNode> mapToFirstDimensionArrayNode = 
2026             new Hashtable<HeapRegionNode, HeapRegionNode>();
2027         Set<String> doneSet = new HashSet<String>();
2028         
2029         TempDescriptor tempDesc = fm.getParameter(idx);
2030         
2031         AllocSite as = createParameterAllocSite(rg, tempDesc, true);
2032         VariableNode lnX = rg.getVariableNodeFromTemp(tempDesc);
2033         Integer idNewest = as.getIthOldest(0);
2034         HeapRegionNode hrnNewest = rg.id2hrn.get(idNewest);
2035
2036         // make a new reference to allocated node
2037         RefEdge edgeNew = new RefEdge(lnX, // source
2038                                       hrnNewest, // dest
2039                                       taskDesc.getParamType(idx), // type
2040                                       null, // field name
2041                                       hrnNewest.getAlpha(), // beta
2042                                       ExistPredSet.factory(rg.predTrue), // predicates
2043                                       null
2044                                       );
2045         rg.addRefEdge(lnX, hrnNewest, edgeNew);
2046
2047         // set-up a work set for class field
2048         ClassDescriptor classDesc = paramTypeDesc.getClassDesc();
2049         for (Iterator it = classDesc.getFields(); it.hasNext();) {
2050             FieldDescriptor fd = (FieldDescriptor) it.next();
2051             TypeDescriptor fieldType = fd.getType();
2052             if (shouldAnalysisTrack( fieldType )) {
2053                 HashMap<HeapRegionNode, FieldDescriptor> newMap = new HashMap<HeapRegionNode, FieldDescriptor>();
2054                 newMap.put(hrnNewest, fd);
2055                 workSet.add(newMap);
2056             }
2057         }
2058         
2059         int uniqueIdentifier = 0;
2060         while (!workSet.isEmpty()) {
2061             HashMap<HeapRegionNode, FieldDescriptor> map = workSet
2062                 .iterator().next();
2063             workSet.remove(map);
2064             
2065             Set<HeapRegionNode> key = map.keySet();
2066             HeapRegionNode srcHRN = key.iterator().next();
2067             FieldDescriptor fd = map.get(srcHRN);
2068             TypeDescriptor type = fd.getType();
2069             String doneSetIdentifier = srcHRN.getIDString() + "_" + fd;
2070             
2071             if (!doneSet.contains(doneSetIdentifier)) {
2072                 doneSet.add(doneSetIdentifier);
2073                 if (!mapTypeToExistingSummaryNode.containsKey(type)) {
2074                     // create new summary Node
2075                     TempDescriptor td = new TempDescriptor("temp"
2076                                                            + uniqueIdentifier, type);
2077                     
2078                     AllocSite allocSite;
2079                     if(type.equals(paramTypeDesc)){
2080                     //corresponding allocsite has already been created for a parameter variable.
2081                         allocSite=as;
2082                     }else{
2083                       allocSite = createParameterAllocSite(rg, td, false);
2084                     }
2085                     String strDesc = allocSite.toStringForDOT()
2086                         + "\\nsummary";
2087                     TypeDescriptor allocType=allocSite.getType();
2088                     
2089                     HeapRegionNode      hrnSummary;
2090                     if(allocType.isArray() && allocType.getArrayCount()>0){
2091                       hrnSummary=createMultiDeimensionalArrayHRN(rg,allocSite,srcHRN,fd,mapToFirstDimensionArrayNode,mapTypeToExistingSummaryNode,hrnNewest.getAlpha());
2092                     }else{                  
2093                         hrnSummary = 
2094                                         rg.createNewHeapRegionNode(allocSite.getSummary(), // id or null to generate a new one
2095                                                                    false, // single object?
2096                                                                    true, // summary?
2097                                                                    false, // out-of-context?
2098                                                                    allocSite.getType(), // type
2099                                                                    allocSite, // allocation site
2100                                                                    hrnNewest.getAlpha(), // inherent reach
2101                                                                    hrnNewest.getAlpha(), // current reach
2102                                                                    ExistPredSet.factory(rg.predTrue), // predicates
2103                                                                    strDesc // description
2104                                                                    );
2105                                     rg.id2hrn.put(allocSite.getSummary(),hrnSummary);
2106                     
2107                     // make a new reference to summary node
2108                     RefEdge edgeToSummary = new RefEdge(srcHRN, // source
2109                                                         hrnSummary, // dest
2110                                                         type, // type
2111                                                         fd.getSymbol(), // field name
2112                                                         hrnNewest.getAlpha(), // beta
2113                                                         ExistPredSet.factory(rg.predTrue), // predicates
2114                                                         null
2115                                                         );
2116                     
2117                     rg.addRefEdge(srcHRN, hrnSummary, edgeToSummary);
2118                     }               
2119                     uniqueIdentifier++;
2120                     
2121                     mapTypeToExistingSummaryNode.put(type, hrnSummary);
2122                     
2123                     // set-up a work set for  fields of the class
2124                     Set<FieldDescriptor> fieldTobeAnalyzed=getFieldSetTobeAnalyzed(type);
2125                     for (Iterator iterator = fieldTobeAnalyzed.iterator(); iterator
2126                                         .hasNext();) {
2127                                 FieldDescriptor fieldDescriptor = (FieldDescriptor) iterator
2128                                                 .next();
2129                                 HeapRegionNode newDstHRN;
2130                                 if(mapToFirstDimensionArrayNode.containsKey(hrnSummary)){
2131                                         //related heap region node is already exsited.
2132                                         newDstHRN=mapToFirstDimensionArrayNode.get(hrnSummary);
2133                                 }else{
2134                                         newDstHRN=hrnSummary;
2135                                 }
2136                                  doneSetIdentifier = newDstHRN.getIDString() + "_" + fieldDescriptor;                                                            
2137                                  if(!doneSet.contains(doneSetIdentifier)){
2138                                  // add new work item
2139                                          HashMap<HeapRegionNode, FieldDescriptor> newMap = 
2140                                             new HashMap<HeapRegionNode, FieldDescriptor>();
2141                                          newMap.put(newDstHRN, fieldDescriptor);
2142                                          workSet.add(newMap);
2143                                   }                             
2144                         }
2145                     
2146                 }else{
2147                     // if there exists corresponding summary node
2148                     HeapRegionNode hrnDst=mapTypeToExistingSummaryNode.get(type);
2149                     
2150                     RefEdge edgeToSummary = new RefEdge(srcHRN, // source
2151                                                         hrnDst, // dest
2152                                                         fd.getType(), // type
2153                                                         fd.getSymbol(), // field name
2154                                                         srcHRN.getAlpha(), // beta
2155                                                         ExistPredSet.factory(rg.predTrue), // predicates  
2156                                                         null
2157                                                         );
2158                     rg.addRefEdge(srcHRN, hrnDst, edgeToSummary);
2159                     
2160                 }               
2161             }       
2162         }           
2163     }   
2164 //    debugSnapshot(rg, fm, true);
2165     return rg;
2166 }
2167
2168 // return all allocation sites in the method (there is one allocation
2169 // site per FlatNew node in a method)
2170 private HashSet<AllocSite> getAllocationSiteSet(Descriptor d) {
2171   if( !mapDescriptorToAllocSiteSet.containsKey(d) ) {
2172     buildAllocationSiteSet(d);
2173   }
2174
2175   return mapDescriptorToAllocSiteSet.get(d);
2176
2177 }
2178
2179 private void buildAllocationSiteSet(Descriptor d) {
2180     HashSet<AllocSite> s = new HashSet<AllocSite>();
2181
2182     FlatMethod fm;
2183     if( d instanceof MethodDescriptor ) {
2184       fm = state.getMethodFlat( (MethodDescriptor) d);
2185     } else {
2186       assert d instanceof TaskDescriptor;
2187       fm = state.getMethodFlat( (TaskDescriptor) d);
2188     }
2189     pm.analyzeMethod(fm);
2190
2191     // visit every node in this FlatMethod's IR graph
2192     // and make a set of the allocation sites from the
2193     // FlatNew node's visited
2194     HashSet<FlatNode> visited = new HashSet<FlatNode>();
2195     HashSet<FlatNode> toVisit = new HashSet<FlatNode>();
2196     toVisit.add(fm);
2197
2198     while( !toVisit.isEmpty() ) {
2199       FlatNode n = toVisit.iterator().next();
2200
2201       if( n instanceof FlatNew ) {
2202         s.add(getAllocSiteFromFlatNewPRIVATE( (FlatNew) n) );
2203       }
2204
2205       toVisit.remove(n);
2206       visited.add(n);
2207
2208       for( int i = 0; i < pm.numNext(n); ++i ) {
2209         FlatNode child = pm.getNext(n, i);
2210         if( !visited.contains(child) ) {
2211           toVisit.add(child);
2212         }
2213       }
2214     }
2215
2216     mapDescriptorToAllocSiteSet.put(d, s);
2217   }
2218
2219         private HashSet<AllocSite> getFlaggedAllocationSites(Descriptor dIn) {
2220
2221                 HashSet<AllocSite> out = new HashSet<AllocSite>();
2222                 HashSet<Descriptor> toVisit = new HashSet<Descriptor>();
2223                 HashSet<Descriptor> visited = new HashSet<Descriptor>();
2224
2225                 toVisit.add(dIn);
2226
2227                 while (!toVisit.isEmpty()) {
2228                         Descriptor d = toVisit.iterator().next();
2229                         toVisit.remove(d);
2230                         visited.add(d);
2231
2232                         HashSet<AllocSite> asSet = getAllocationSiteSet(d);
2233                         Iterator asItr = asSet.iterator();
2234                         while (asItr.hasNext()) {
2235                                 AllocSite as = (AllocSite) asItr.next();
2236                                 if (as.getDisjointAnalysisId() != null) {
2237                                         out.add(as);
2238                                 }
2239                         }
2240
2241                         // enqueue callees of this method to be searched for
2242                         // allocation sites also
2243                         Set callees = callGraph.getCalleeSet(d);
2244                         if (callees != null) {
2245                                 Iterator methItr = callees.iterator();
2246                                 while (methItr.hasNext()) {
2247                                         MethodDescriptor md = (MethodDescriptor) methItr.next();
2248
2249                                         if (!visited.contains(md)) {
2250                                                 toVisit.add(md);
2251                                         }
2252                                 }
2253                         }
2254                 }
2255
2256                 return out;
2257         }
2258  
2259     
2260 private HashSet<AllocSite>
2261 getFlaggedAllocationSitesReachableFromTaskPRIVATE(TaskDescriptor td) {
2262
2263   HashSet<AllocSite> asSetTotal = new HashSet<AllocSite>();
2264   HashSet<Descriptor>     toVisit    = new HashSet<Descriptor>();
2265   HashSet<Descriptor>     visited    = new HashSet<Descriptor>();
2266
2267   toVisit.add(td);
2268
2269   // traverse this task and all methods reachable from this task
2270   while( !toVisit.isEmpty() ) {
2271     Descriptor d = toVisit.iterator().next();
2272     toVisit.remove(d);
2273     visited.add(d);
2274
2275     HashSet<AllocSite> asSet = getAllocationSiteSet(d);
2276     Iterator asItr = asSet.iterator();
2277     while( asItr.hasNext() ) {
2278         AllocSite as = (AllocSite) asItr.next();
2279         TypeDescriptor typed = as.getType();
2280         if( typed != null ) {
2281           ClassDescriptor cd = typed.getClassDesc();
2282           if( cd != null && cd.hasFlags() ) {
2283             asSetTotal.add(as);
2284           }
2285         }
2286     }
2287
2288     // enqueue callees of this method to be searched for
2289     // allocation sites also
2290     Set callees = callGraph.getCalleeSet(d);
2291     if( callees != null ) {
2292         Iterator methItr = callees.iterator();
2293         while( methItr.hasNext() ) {
2294           MethodDescriptor md = (MethodDescriptor) methItr.next();
2295
2296           if( !visited.contains(md) ) {
2297             toVisit.add(md);
2298           }
2299         }
2300     }
2301   }
2302
2303   return asSetTotal;
2304 }
2305
2306   public Set<Descriptor> getDescriptorsToAnalyze() {
2307     return descriptorsToAnalyze;
2308   }
2309
2310   public EffectsAnalysis getEffectsAnalysis(){
2311     return effectsAnalysis;
2312   }
2313   
2314   
2315   // get successive captures of the analysis state, use compiler
2316   // flags to control
2317   boolean takeDebugSnapshots = false;
2318   String  descSymbolDebug    = null;
2319   boolean stopAfterCapture   = false;
2320   int     snapVisitCounter   = 0;
2321   int     snapNodeCounter    = 0;
2322   int     visitStartCapture  = 0;
2323   int     numVisitsToCapture = 0;
2324
2325
2326   void debugSnapshot( ReachGraph rg, FlatNode fn, boolean in ) {
2327     if( snapVisitCounter > visitStartCapture + numVisitsToCapture ) {
2328       return;
2329     }
2330
2331     if( in ) {
2332
2333     }
2334
2335     if( snapVisitCounter >= visitStartCapture ) {
2336       System.out.println( "    @@@ snapping visit="+snapVisitCounter+
2337                           ", node="+snapNodeCounter+
2338                           " @@@" );
2339       String graphName;
2340       if( in ) {
2341         graphName = String.format( "snap%03d_%04din",
2342                                    snapVisitCounter,
2343                                    snapNodeCounter );
2344       } else {
2345         graphName = String.format( "snap%03d_%04dout",
2346                                    snapVisitCounter,
2347                                    snapNodeCounter );
2348       }
2349       if( fn != null ) {
2350         graphName = graphName + fn;
2351       }
2352       rg.writeGraph( graphName,
2353                      true,   // write labels (variables)
2354                      true,   // selectively hide intermediate temp vars
2355                      true,   // prune unreachable heap regions
2356                      false,  // hide reachability
2357                      true,   // hide subset reachability states
2358                      true,   // hide predicates
2359                      false );// hide edge taints
2360     }
2361   }
2362
2363 }