Tighten up use of canonical objects and halt system if a canonical object's hashcode...
[IRC.git] / Robust / src / Analysis / OwnershipAnalysis / OwnershipAnalysis.java
1 package Analysis.OwnershipAnalysis;
2
3 import Analysis.CallGraph.*;
4 import IR.*;
5 import IR.Flat.*;
6 import IR.Tree.Modifiers;
7 import java.util.*;
8 import java.io.*;
9
10
11 public class OwnershipAnalysis {
12
13
14   ///////////////////////////////////////////
15   //
16   //  Public interface to discover possible
17   //  aliases in the program under analysis
18   //
19   ///////////////////////////////////////////
20
21   public HashSet<AllocationSite>
22   getFlaggedAllocationSitesReachableFromTask(TaskDescriptor td) {
23     return getFlaggedAllocationSitesReachableFromTaskPRIVATE(td);
24   }
25
26   public AllocationSite getAllocationSiteFromFlatNew(FlatNew fn) {
27     return getAllocationSiteFromFlatNewPRIVATE(fn);
28   }
29
30   public boolean createsPotentialAliases(Descriptor taskOrMethod,
31                                          int paramIndex1,
32                                          int paramIndex2) {
33
34     OwnershipGraph og = mapDescriptorToCompleteOwnershipGraph.get(taskOrMethod);
35     assert(og != null);
36     return og.hasPotentialAlias(paramIndex1, paramIndex2);
37   }
38
39   public boolean createsPotentialAliases(Descriptor taskOrMethod,
40                                          int paramIndex,
41                                          AllocationSite alloc) {
42
43     OwnershipGraph og = mapDescriptorToCompleteOwnershipGraph.get(taskOrMethod);
44     assert(og != null);
45     return og.hasPotentialAlias(paramIndex, alloc);
46   }
47
48   public boolean createsPotentialAliases(Descriptor taskOrMethod,
49                                          AllocationSite alloc,
50                                          int paramIndex) {
51
52     OwnershipGraph og = mapDescriptorToCompleteOwnershipGraph.get(taskOrMethod);
53     assert(og != null);
54     return og.hasPotentialAlias(paramIndex, alloc);
55   }
56
57   public boolean createsPotentialAliases(Descriptor taskOrMethod,
58                                          AllocationSite alloc1,
59                                          AllocationSite alloc2) {
60
61     OwnershipGraph og = mapDescriptorToCompleteOwnershipGraph.get(taskOrMethod);
62     assert(og != null);
63     return og.hasPotentialAlias(alloc1, alloc2);
64   }
65
66   // use the methods given above to check every possible alias
67   // between task parameters and flagged allocation sites reachable
68   // from the task
69   public void writeAllAliases(String outputFile) throws java.io.IOException {
70
71     BufferedWriter bw = new BufferedWriter(new FileWriter(outputFile) );
72
73     bw.write("Conducting ownership analysis with allocation depth = "+allocationDepth);
74
75     // look through every task for potential aliases
76     Iterator taskItr = state.getTaskSymbolTable().getDescriptorsIterator();
77     while( taskItr.hasNext() ) {
78       TaskDescriptor td = (TaskDescriptor) taskItr.next();
79
80       bw.write("\n---------"+td+"--------\n");
81
82       HashSet<AllocationSite> allocSites = getFlaggedAllocationSitesReachableFromTask(td);
83
84       // for each task parameter, check for aliases with
85       // other task parameters and every allocation site
86       // reachable from this task
87       boolean foundSomeAlias = false;
88
89       FlatMethod fm = state.getMethodFlat(td);
90       for( int i = 0; i < fm.numParameters(); ++i ) {
91
92         // for the ith parameter check for aliases to all
93         // higher numbered parameters
94         for( int j = i + 1; j < fm.numParameters(); ++j ) {
95           if( createsPotentialAliases(td, i, j) ) {
96             foundSomeAlias = true;
97             bw.write("Potential alias between parameters "+i+" and "+j+".\n");
98           }
99         }
100
101         // for the ith parameter, check for aliases against
102         // the set of allocation sites reachable from this
103         // task context
104         Iterator allocItr = allocSites.iterator();
105         while( allocItr.hasNext() ) {
106           AllocationSite as = (AllocationSite) allocItr.next();
107           if( createsPotentialAliases(td, i, as) ) {
108             foundSomeAlias = true;
109             bw.write("Potential alias between parameter "+i+" and "+as.getFlatNew()+".\n");
110           }
111         }
112       }
113
114       // for each allocation site check for aliases with
115       // other allocation sites in the context of execution
116       // of this task
117       HashSet<AllocationSite> outerChecked = new HashSet<AllocationSite>();
118       Iterator allocItr1 = allocSites.iterator();
119       while( allocItr1.hasNext() ) {
120         AllocationSite as1 = (AllocationSite) allocItr1.next();
121
122         Iterator allocItr2 = allocSites.iterator();
123         while( allocItr2.hasNext() ) {
124           AllocationSite as2 = (AllocationSite) allocItr2.next();
125
126           if( !outerChecked.contains(as2) &&
127               createsPotentialAliases(td, as1, as2) ) {
128             foundSomeAlias = true;
129             bw.write("Potential alias between "+as1.getFlatNew()+" and "+as2.getFlatNew()+".\n");
130           }
131         }
132
133         outerChecked.add(as1);
134       }
135
136       if( !foundSomeAlias ) {
137         bw.write("Task "+td+" contains no aliases between flagged objects.\n");
138       }
139     }
140
141     bw.close();
142   }
143
144   ///////////////////////////////////////////
145   //
146   // end public interface
147   //
148   ///////////////////////////////////////////
149
150
151
152
153
154
155
156
157   // data from the compiler
158   private State state;
159   private TypeUtil typeUtil;
160   private CallGraph callGraph;
161   private int allocationDepth;
162
163   // used to identify HeapRegionNode objects
164   // A unique ID equates an object in one
165   // ownership graph with an object in another
166   // graph that logically represents the same
167   // heap region
168   // start at 10 and incerement to leave some
169   // reserved IDs for special purposes
170   static private int uniqueIDcount = 10;
171
172
173   // Use these data structures to track progress of
174   // processing all methods in the program, and by methods
175   // TaskDescriptor and MethodDescriptor are combined
176   // together, with a common parent class Descriptor
177   private Hashtable<FlatMethod, OwnershipGraph>           mapFlatMethodToInitialParamAllocGraph;
178   private Hashtable<Descriptor, OwnershipGraph>           mapDescriptorToCompleteOwnershipGraph;
179   private Hashtable<FlatNew,    AllocationSite>           mapFlatNewToAllocationSite;
180   private Hashtable<Descriptor, HashSet<AllocationSite> > mapDescriptorToAllocationSiteSet;
181   private Hashtable<Descriptor, Integer>                  mapDescriptorToNumUpdates;
182
183   // Use these data structures to track progress of one pass of
184   // processing the FlatNodes of a particular method
185   private HashSet  <FlatNode>                 flatNodesToVisit;
186   private Hashtable<FlatNode, OwnershipGraph> mapFlatNodeToOwnershipGraph;
187   private HashSet  <FlatReturnNode>           returnNodesToCombineForCompleteOwnershipGraph;
188
189   // descriptorsToAnalyze identifies the set of tasks and methods
190   // that are reachable from the program tasks, this set is initialized
191   // and then remains static
192   private HashSet<Descriptor> descriptorsToAnalyze;
193
194   // descriptorsToVisit is initialized to descriptorsToAnalyze and is
195   // reduced by visiting a descriptor during analysis.  When dependents
196   // must be scheduled, only those contained in descriptorsToAnalyze
197   // should be re-added to this set
198   private HashSet<Descriptor> descriptorsToVisit;
199
200   // a special field descriptor for all array elements
201   private static FieldDescriptor fdElement = new FieldDescriptor(new Modifiers(Modifiers.PUBLIC),
202                                                                  new TypeDescriptor("Array[]"),
203                                                                  "elements",
204                                                                  null,
205                                                                  false);
206   // for controlling DOT file output
207   private boolean writeDOTs;
208   private boolean writeAllDOTs;
209
210
211
212   // this analysis generates an ownership graph for every task
213   // in the program
214   public OwnershipAnalysis(State state,
215                            TypeUtil tu,
216                            CallGraph callGraph,
217                            int allocationDepth,
218                            boolean writeDOTs,
219                            boolean writeAllDOTs,
220                            String aliasFile) throws java.io.IOException {
221
222     this.state           = state;
223     this.typeUtil        = tu;
224     this.callGraph       = callGraph;
225     this.allocationDepth = allocationDepth;
226     this.writeDOTs       = writeDOTs;
227     this.writeAllDOTs    = writeAllDOTs;
228
229     descriptorsToAnalyze = new HashSet<Descriptor>();
230
231     mapFlatMethodToInitialParamAllocGraph =
232       new Hashtable<FlatMethod, OwnershipGraph>();
233
234     mapDescriptorToCompleteOwnershipGraph =
235       new Hashtable<Descriptor, OwnershipGraph>();
236
237     mapFlatNewToAllocationSite =
238       new Hashtable<FlatNew, AllocationSite>();
239
240     mapDescriptorToAllocationSiteSet =
241       new Hashtable<Descriptor, HashSet<AllocationSite> >();
242
243     if( writeAllDOTs ) {
244       mapDescriptorToNumUpdates = new Hashtable<Descriptor, Integer>();
245     }
246
247     // initialize methods to visit as the set of all tasks in the
248     // program and then any method that could be called starting
249     // from those tasks
250     Iterator taskItr = state.getTaskSymbolTable().getDescriptorsIterator();
251     while( taskItr.hasNext() ) {
252       Descriptor d = (Descriptor) taskItr.next();
253       scheduleAllCallees(d);
254     }
255
256     // before beginning analysis, initialize every scheduled method
257     // with an ownership graph that has populated parameter index tables
258     // by analyzing the first node which is always a FlatMethod node
259     Iterator<Descriptor> dItr = descriptorsToAnalyze.iterator();
260     while( dItr.hasNext() ) {
261       Descriptor d  = dItr.next();
262       OwnershipGraph og = new OwnershipGraph(allocationDepth, typeUtil);
263
264       FlatMethod fm;
265       if( d instanceof MethodDescriptor ) {
266         fm = state.getMethodFlat( (MethodDescriptor) d);
267       } else {
268         assert d instanceof TaskDescriptor;
269         fm = state.getMethodFlat( (TaskDescriptor) d);
270       }
271
272       System.out.println("Previsiting " + d);
273
274       og = analyzeFlatNode(d, fm, null, og);
275       setGraphForDescriptor(d, og);
276     }
277
278     System.out.println("");
279
280     // as mentioned above, analyze methods one-by-one, possibly revisiting
281     // a method if the methods that it calls are updated
282     analyzeMethods();
283
284     System.out.println("");
285
286     if( aliasFile != null ) {
287       writeAllAliases(aliasFile);
288     }
289   }
290
291   // called from the constructor to help initialize the set
292   // of methods that needs to be analyzed by ownership analysis
293   private void scheduleAllCallees(Descriptor d) {
294     if( descriptorsToAnalyze.contains(d) ) {
295       return;
296     }
297     descriptorsToAnalyze.add(d);
298
299     // start with all method calls to further schedule
300     Set moreMethodsToCheck = moreMethodsToCheck = callGraph.getMethodCalls(d);
301
302     if( d instanceof MethodDescriptor ) {
303       // see if this method has virtual dispatch
304       Set virtualMethods = callGraph.getMethods( (MethodDescriptor)d);
305       moreMethodsToCheck.addAll(virtualMethods);
306     }
307
308     // keep following any further methods identified in
309     // the call chain
310     Iterator methItr = moreMethodsToCheck.iterator();
311     while( methItr.hasNext() ) {
312       Descriptor m = (Descriptor) methItr.next();
313       scheduleAllCallees(m);
314     }
315   }
316
317
318   // manage the set of tasks and methods to be analyzed
319   // and be sure to reschedule tasks/methods when the methods
320   // they call are updated
321   private void analyzeMethods() throws java.io.IOException {
322
323     descriptorsToVisit = (HashSet<Descriptor>)descriptorsToAnalyze.clone();
324
325     while( !descriptorsToVisit.isEmpty() ) {
326       Descriptor d = (Descriptor) descriptorsToVisit.iterator().next();
327       descriptorsToVisit.remove(d);
328
329       // because the task or method descriptor just extracted
330       // was in the "to visit" set it either hasn't been analyzed
331       // yet, or some method that it depends on has been
332       // updated.  Recompute a complete ownership graph for
333       // this task/method and compare it to any previous result.
334       // If there is a change detected, add any methods/tasks
335       // that depend on this one to the "to visit" set.
336
337       System.out.println("Analyzing " + d);
338
339       FlatMethod fm;
340       if( d instanceof MethodDescriptor ) {
341         fm = state.getMethodFlat( (MethodDescriptor) d);
342       } else {
343         assert d instanceof TaskDescriptor;
344         fm = state.getMethodFlat( (TaskDescriptor) d);
345       }
346
347       OwnershipGraph og = analyzeFlatMethod(d, fm);
348       OwnershipGraph ogPrev = mapDescriptorToCompleteOwnershipGraph.get(d);
349       if( !og.equals(ogPrev) ) {
350         setGraphForDescriptor(d, og);
351
352         // only methods have dependents, tasks cannot
353         // be invoked by any user program calls
354         if( d instanceof MethodDescriptor ) {
355           MethodDescriptor md = (MethodDescriptor) d;
356           Set dependents = callGraph.getCallerSet(md);
357           if( dependents != null ) {
358             Iterator depItr = dependents.iterator();
359             while( depItr.hasNext() ) {
360               Descriptor dependent = (Descriptor) depItr.next();
361               if( descriptorsToAnalyze.contains(dependent) ) {
362                 descriptorsToVisit.add(dependent);
363               }
364             }
365           }
366         }
367       }
368     }
369
370   }
371
372
373   // keep passing the Descriptor of the method along for debugging
374   // and dot file writing
375   private OwnershipGraph
376   analyzeFlatMethod(Descriptor mDesc,
377                     FlatMethod flatm) throws java.io.IOException {
378
379     // initialize flat nodes to visit as the flat method
380     // because all other nodes in this flat method are
381     // decendents of the flat method itself
382
383     flatNodesToVisit = new HashSet<FlatNode>();
384     flatNodesToVisit.add(flatm);
385
386     // initilize the mapping of flat nodes in this flat method to
387     // ownership graph results to an empty mapping
388     mapFlatNodeToOwnershipGraph = new Hashtable<FlatNode, OwnershipGraph>();
389
390     // initialize the set of return nodes that will be combined as
391     // the final ownership graph result to return as an empty set
392     returnNodesToCombineForCompleteOwnershipGraph = new HashSet<FlatReturnNode>();
393
394
395     while( !flatNodesToVisit.isEmpty() ) {
396       FlatNode fn = (FlatNode) flatNodesToVisit.iterator().next();
397       flatNodesToVisit.remove(fn);
398
399       //System.out.println( "  "+fn );
400
401       // perform this node's contributions to the ownership
402       // graph on a new copy, then compare it to the old graph
403       // at this node to see if anything was updated.
404       OwnershipGraph og = new OwnershipGraph(allocationDepth, typeUtil);
405
406       // start by merging all node's parents' graphs
407       for( int i = 0; i < fn.numPrev(); ++i ) {
408         FlatNode pn = fn.getPrev(i);    
409         if( mapFlatNodeToOwnershipGraph.containsKey(pn) ) {
410           OwnershipGraph ogParent = mapFlatNodeToOwnershipGraph.get(pn);
411           og.merge(ogParent);
412         }
413       }
414
415       // apply the analysis of the flat node to the
416       // ownership graph made from the merge of the
417       // parent graphs
418       og = analyzeFlatNode(mDesc,
419                            fn,
420                            returnNodesToCombineForCompleteOwnershipGraph,
421                            og);
422
423
424       //debugSnapshot(og,fn);
425
426
427
428       // if the results of the new graph are different from
429       // the current graph at this node, replace the graph
430       // with the update and enqueue the children for
431       // processing
432       OwnershipGraph ogPrev = mapFlatNodeToOwnershipGraph.get(fn);
433       if( !og.equals(ogPrev) ) {
434         mapFlatNodeToOwnershipGraph.put(fn, og);
435
436         for( int i = 0; i < fn.numNext(); i++ ) {
437           FlatNode nn = fn.getNext(i);
438           flatNodesToVisit.add(nn);
439         }
440       }
441     }
442
443     // end by merging all return nodes into a complete
444     // ownership graph that represents all possible heap
445     // states after the flat method returns
446     OwnershipGraph completeGraph = new OwnershipGraph(allocationDepth, typeUtil);
447     Iterator retItr = returnNodesToCombineForCompleteOwnershipGraph.iterator();
448     while( retItr.hasNext() ) {
449       FlatReturnNode frn = (FlatReturnNode) retItr.next();
450       assert mapFlatNodeToOwnershipGraph.containsKey(frn);
451       OwnershipGraph ogr = mapFlatNodeToOwnershipGraph.get(frn);
452       completeGraph.merge(ogr);
453     }   
454
455     return completeGraph;
456   }
457
458
459   private OwnershipGraph
460   analyzeFlatNode(Descriptor methodDesc,
461                   FlatNode fn,
462                   HashSet<FlatReturnNode> setRetNodes,
463                   OwnershipGraph og) throws java.io.IOException {
464
465     TempDescriptor lhs;
466     TempDescriptor rhs;
467     FieldDescriptor fld;
468
469     // use node type to decide what alterations to make
470     // to the ownership graph
471     switch( fn.kind() ) {
472
473     case FKind.FlatMethod:
474       FlatMethod fm = (FlatMethod) fn;
475
476       // there should only be one FlatMethod node as the
477       // parent of all other FlatNode objects, so take
478       // the opportunity to construct the initial graph by
479       // adding parameters labels to new heap regions
480       // AND this should be done once globally so that the
481       // parameter IDs are consistent between analysis
482       // iterations, so if this step has been done already
483       // just merge in the cached version
484       OwnershipGraph ogInitParamAlloc = mapFlatMethodToInitialParamAllocGraph.get(fm);
485       if( ogInitParamAlloc == null ) {
486
487         // analyze this node one time globally
488         for( int i = 0; i < fm.numParameters(); ++i ) {
489           TempDescriptor tdParam = fm.getParameter(i);
490           og.assignTempEqualToParamAlloc(tdParam,
491                                          methodDesc instanceof TaskDescriptor,
492                                          new Integer(i) );
493         }
494
495         // then remember it
496         OwnershipGraph ogResult = new OwnershipGraph(allocationDepth, typeUtil);
497         ogResult.merge(og);
498         mapFlatMethodToInitialParamAllocGraph.put(fm, ogResult);
499
500       } else {
501         // or just leverage the cached copy
502         og.merge(ogInitParamAlloc);
503       }
504       break;
505
506     case FKind.FlatOpNode:
507       FlatOpNode fon = (FlatOpNode) fn;
508       if( fon.getOp().getOp() == Operation.ASSIGN ) {
509         lhs = fon.getDest();
510         rhs = fon.getLeft();
511         og.assignTempXEqualToTempY(lhs, rhs);
512       }
513       break;
514
515     case FKind.FlatFieldNode:
516       FlatFieldNode ffn = (FlatFieldNode) fn;
517       lhs = ffn.getDst();
518       rhs = ffn.getSrc();
519       fld = ffn.getField();
520       if( !fld.getType().isImmutable() ) {
521         og.assignTempXEqualToTempYFieldF(lhs, rhs, fld);
522       }
523       break;
524
525     case FKind.FlatSetFieldNode:
526       FlatSetFieldNode fsfn = (FlatSetFieldNode) fn;
527       lhs = fsfn.getDst();
528       fld = fsfn.getField();
529       rhs = fsfn.getSrc();
530       if( !fld.getType().isImmutable() ) {
531         og.assignTempXFieldFEqualToTempY(lhs, fld, rhs);
532       }
533       break;
534
535     case FKind.FlatElementNode:
536       FlatElementNode fen = (FlatElementNode) fn;
537       lhs = fen.getDst();
538       rhs = fen.getSrc();
539       if( !lhs.getType().isImmutable() ) {
540         og.assignTempXEqualToTempYFieldF(lhs, rhs, fdElement);
541       }
542       break;
543
544     case FKind.FlatSetElementNode:
545       FlatSetElementNode fsen = (FlatSetElementNode) fn;
546       lhs = fsen.getDst();
547       rhs = fsen.getSrc();
548       if( !rhs.getType().isImmutable() ) {
549         og.assignTempXFieldFEqualToTempY(lhs, fdElement, rhs);
550       }
551       break;
552
553     case FKind.FlatNew:
554       FlatNew fnn = (FlatNew) fn;
555       lhs = fnn.getDst();
556       if( !lhs.getType().isImmutable() ) {
557         AllocationSite as = getAllocationSiteFromFlatNewPRIVATE(fnn);
558         og.assignTempEqualToNewAlloc(lhs, as);
559       }
560       break;
561
562     case FKind.FlatCall:
563       FlatCall fc = (FlatCall) fn;
564       MethodDescriptor md = fc.getMethod();
565       FlatMethod flatm = state.getMethodFlat(md);
566       OwnershipGraph ogMergeOfAllPossibleCalleeResults = new OwnershipGraph(allocationDepth, typeUtil);
567
568       if( md.isStatic() ) {
569         // a static method is simply always the same, makes life easy
570         OwnershipGraph onlyPossibleCallee = mapDescriptorToCompleteOwnershipGraph.get(md);
571         ogMergeOfAllPossibleCalleeResults = og;
572         ogMergeOfAllPossibleCalleeResults.resolveMethodCall(fc, md.isStatic(), flatm, onlyPossibleCallee);
573       } else {
574         // if the method descriptor is virtual, then there could be a
575         // set of possible methods that will actually be invoked, so
576         // find all of them and merge all of their results together
577         TypeDescriptor typeDesc = fc.getThis().getType();
578         Set possibleCallees = callGraph.getMethods(md, typeDesc);
579
580         Iterator i = possibleCallees.iterator();
581         while( i.hasNext() ) {
582           MethodDescriptor possibleMd = (MethodDescriptor) i.next();
583
584           // don't alter the working graph (og) until we compute a result for every
585           // possible callee, merge them all together, then set og to that
586           OwnershipGraph ogCopy = new OwnershipGraph(allocationDepth, typeUtil);
587           ogCopy.merge(og);
588
589           OwnershipGraph ogPotentialCallee = mapDescriptorToCompleteOwnershipGraph.get(possibleMd);
590           ogCopy.resolveMethodCall(fc, md.isStatic(), flatm, ogPotentialCallee);
591           ogMergeOfAllPossibleCalleeResults.merge(ogCopy);
592         }
593       }
594
595       og = ogMergeOfAllPossibleCalleeResults;      
596       break;
597
598     case FKind.FlatReturnNode:
599       FlatReturnNode frn = (FlatReturnNode) fn;
600       rhs = frn.getReturnTemp();
601       if( rhs != null && !rhs.getType().isImmutable() ) {
602         og.assignReturnEqualToTemp(rhs);
603       }
604       setRetNodes.add(frn);
605       break;
606     }
607
608     return og;
609   }
610
611
612   // insert a call to debugSnapshot() somewhere in the analysis to get
613   // successive captures of the analysis state
614   int debugCounter        = 0;
615   int numStartCountReport = 0;
616   int freqCountReport     = 1000;
617   int iterStartCapture    = 20000;
618   int numIterToCapture    = 400;
619   void debugSnapshot( OwnershipGraph og, FlatNode fn ) {
620     ++debugCounter;
621     if( debugCounter > numStartCountReport &&
622         debugCounter % freqCountReport == 0 ) {
623       System.out.println( "    @@@ debug counter = "+debugCounter );
624     }
625     if( debugCounter > iterStartCapture ) {
626       System.out.println( "    @@@ capturing debug "+(debugCounter-iterStartCapture)+" @@@" );
627       String graphName = String.format("snap%04d",debugCounter-iterStartCapture);
628       if( fn != null ) {
629         graphName = graphName+fn;
630       }
631       try {
632         og.writeGraph( graphName, true, true, false, false, false );
633       } catch( Exception e ) {
634         System.out.println( "Error writing debug capture." );
635         System.exit( 0 );       
636       }
637     }
638     if( debugCounter == iterStartCapture + numIterToCapture ) {
639       System.out.println( "Stopping analysis after debug captures." );
640       System.exit( 0 );
641     }
642   }
643
644
645
646   // this method should generate integers strictly greater than zero!
647   // special "shadow" regions are made from a heap region by negating
648   // the ID
649   static public Integer generateUniqueHeapRegionNodeID() {
650     ++uniqueIDcount;
651     return new Integer(uniqueIDcount);
652   }
653
654
655   private void setGraphForDescriptor(Descriptor d, OwnershipGraph og)
656   throws IOException {
657
658     mapDescriptorToCompleteOwnershipGraph.put(d, og);
659
660     // arguments to writeGraph are:
661     // boolean writeLabels,
662     // boolean labelSelect,
663     // boolean pruneGarbage,
664     // boolean writeReferencers
665     // boolean writeParamMappings
666
667     if( writeDOTs ) {
668
669       if( !writeAllDOTs ) {
670         og.writeGraph(d, true, true, true, false, false);
671
672       } else {
673         if( !mapDescriptorToNumUpdates.containsKey(d) ) {
674           mapDescriptorToNumUpdates.put(d, new Integer(0) );
675         }
676         Integer n = mapDescriptorToNumUpdates.get(d);
677         og.writeGraph(d, n, true, true, true, false, false);
678         mapDescriptorToNumUpdates.put(d, n + 1);
679       }
680     }
681   }
682
683
684   // return just the allocation site associated with one FlatNew node
685   private AllocationSite getAllocationSiteFromFlatNewPRIVATE(FlatNew fn) {
686
687     if( !mapFlatNewToAllocationSite.containsKey(fn) ) {
688       AllocationSite as = new AllocationSite(allocationDepth, fn );
689
690       // the newest nodes are single objects
691       for( int i = 0; i < allocationDepth; ++i ) {
692         Integer id = generateUniqueHeapRegionNodeID();
693         as.setIthOldest(i, id);
694       }
695
696       // the oldest node is a summary node
697       Integer idSummary = generateUniqueHeapRegionNodeID();
698       as.setSummary(idSummary);
699
700       mapFlatNewToAllocationSite.put(fn, as);
701     }
702
703     return mapFlatNewToAllocationSite.get(fn);
704   }
705
706
707   // return all allocation sites in the method (there is one allocation
708   // site per FlatNew node in a method)
709   private HashSet<AllocationSite> getAllocationSiteSet(Descriptor d) {
710     if( !mapDescriptorToAllocationSiteSet.containsKey(d) ) {
711       buildAllocationSiteSet(d);
712     }
713
714     return mapDescriptorToAllocationSiteSet.get(d);
715
716   }
717
718   private void buildAllocationSiteSet(Descriptor d) {
719     HashSet<AllocationSite> s = new HashSet<AllocationSite>();
720
721     FlatMethod fm;
722     if( d instanceof MethodDescriptor ) {
723       fm = state.getMethodFlat( (MethodDescriptor) d);
724     } else {
725       assert d instanceof TaskDescriptor;
726       fm = state.getMethodFlat( (TaskDescriptor) d);
727     }
728
729     // visit every node in this FlatMethod's IR graph
730     // and make a set of the allocation sites from the
731     // FlatNew node's visited
732     HashSet<FlatNode> visited = new HashSet<FlatNode>();
733     HashSet<FlatNode> toVisit = new HashSet<FlatNode>();
734     toVisit.add(fm);
735
736     while( !toVisit.isEmpty() ) {
737       FlatNode n = toVisit.iterator().next();
738
739       if( n instanceof FlatNew ) {
740         s.add(getAllocationSiteFromFlatNewPRIVATE( (FlatNew) n) );
741       }
742
743       toVisit.remove(n);
744       visited.add(n);
745
746       for( int i = 0; i < n.numNext(); ++i ) {
747         FlatNode child = n.getNext(i);
748         if( !visited.contains(child) ) {
749           toVisit.add(child);
750         }
751       }
752     }
753
754     mapDescriptorToAllocationSiteSet.put(d, s);
755   }
756
757
758   private HashSet<AllocationSite>
759   getFlaggedAllocationSitesReachableFromTaskPRIVATE(TaskDescriptor td) {
760
761     HashSet<AllocationSite> asSetTotal = new HashSet<AllocationSite>();
762     HashSet<Descriptor>     toVisit    = new HashSet<Descriptor>();
763     HashSet<Descriptor>     visited    = new HashSet<Descriptor>();
764
765     toVisit.add(td);
766
767     // traverse this task and all methods reachable from this task
768     while( !toVisit.isEmpty() ) {
769       Descriptor d = toVisit.iterator().next();
770       toVisit.remove(d);
771       visited.add(d);
772
773       HashSet<AllocationSite> asSet = getAllocationSiteSet(d);
774       Iterator asItr = asSet.iterator();
775       while( asItr.hasNext() ) {
776         AllocationSite as = (AllocationSite) asItr.next();
777         TypeDescriptor typed = as.getType();
778         if( typed != null ) {
779           ClassDescriptor cd = typed.getClassDesc();
780           if( cd != null && cd.hasFlags() ) {
781             asSetTotal.add(as);
782           }
783         }
784       }
785
786       // enqueue callees of this method to be searched for
787       // allocation sites also
788       Set callees = callGraph.getCalleeSet(d);
789       if( callees != null ) {
790         Iterator methItr = callees.iterator();
791         while( methItr.hasNext() ) {
792           MethodDescriptor md = (MethodDescriptor) methItr.next();
793
794           if( !visited.contains(md) ) {
795             toVisit.add(md);
796           }
797         }
798       }
799     }
800
801
802     return asSetTotal;
803   }
804 }