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