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