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