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