1 package Analysis.OwnershipAnalysis;
3 import Analysis.CallGraph.*;
6 import IR.Tree.Modifiers;
11 public class OwnershipAnalysis {
14 ///////////////////////////////////////////
16 // Public interface to discover possible
17 // aliases in the program under analysis
19 ///////////////////////////////////////////
21 public HashSet<AllocationSite>
22 getFlaggedAllocationSitesReachableFromTask(TaskDescriptor td) {
23 return getFlaggedAllocationSitesReachableFromTaskPRIVATE(td);
26 public AllocationSite getAllocationSiteFromFlatNew(FlatNew fn) {
27 return getAllocationSiteFromFlatNewPRIVATE(fn);
31 public boolean createsPotentialAliases(Descriptor taskOrMethod,
35 OwnershipGraph og = getGraphOfAllContextsFromDescriptor(taskOrMethod);
37 return og.hasPotentialAlias(paramIndex1, paramIndex2);
40 public boolean createsPotentialAliases(Descriptor taskOrMethod,
42 AllocationSite alloc) {
44 OwnershipGraph og = getGraphOfAllContextsFromDescriptor(taskOrMethod);
46 return og.hasPotentialAlias(paramIndex, alloc);
49 public boolean createsPotentialAliases(Descriptor taskOrMethod,
53 OwnershipGraph og = getGraphOfAllContextsFromDescriptor(taskOrMethod);
55 return og.hasPotentialAlias(paramIndex, alloc);
58 public boolean createsPotentialAliases(Descriptor taskOrMethod,
59 AllocationSite alloc1,
60 AllocationSite alloc2) {
62 OwnershipGraph og = getGraphOfAllContextsFromDescriptor(taskOrMethod);
64 return og.hasPotentialAlias(alloc1, alloc2);
68 protected OwnershipGraph getGraphOfAllContextsFromDescriptor(Descriptor d) {
71 OwnershipGraph og = new OwnershipGraph( allocationDepth, typeUtil );
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();
79 OwnershipGraph ogContext = mapMethodContextToCompleteOwnershipGraph.get(mc);
80 assert ogContext != null;
82 og.merge( ogContext );
89 // use the methods given above to check every possible alias
90 // between task parameters and flagged allocation sites reachable
92 public void writeAllAliases(String outputFile) throws java.io.IOException {
94 BufferedWriter bw = new BufferedWriter(new FileWriter(outputFile) );
96 bw.write("Conducting ownership analysis with allocation depth = "+allocationDepth);
98 // look through every task for potential aliases
99 Iterator taskItr = state.getTaskSymbolTable().getDescriptorsIterator();
100 while( taskItr.hasNext() ) {
101 TaskDescriptor td = (TaskDescriptor) taskItr.next();
103 bw.write("\n---------"+td+"--------\n");
105 HashSet<AllocationSite> allocSites = getFlaggedAllocationSitesReachableFromTask(td);
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;
112 FlatMethod fm = state.getMethodFlat(td);
113 for( int i = 0; i < fm.numParameters(); ++i ) {
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");
124 // for the ith parameter, check for aliases against
125 // the set of allocation sites reachable from this
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");
137 // for each allocation site check for aliases with
138 // other allocation sites in the context of execution
140 HashSet<AllocationSite> outerChecked = new HashSet<AllocationSite>();
141 Iterator allocItr1 = allocSites.iterator();
142 while( allocItr1.hasNext() ) {
143 AllocationSite as1 = (AllocationSite) allocItr1.next();
145 Iterator allocItr2 = allocSites.iterator();
146 while( allocItr2.hasNext() ) {
147 AllocationSite as2 = (AllocationSite) allocItr2.next();
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");
156 outerChecked.add(as1);
159 if( !foundSomeAlias ) {
160 bw.write("No aliases between flagged objects in Task "+td+".\n");
168 // this version of writeAllAliases is for Java programs that have no tasks
169 public void writeAllAliasesJava(String outputFile) throws java.io.IOException {
172 BufferedWriter bw = new BufferedWriter(new FileWriter(outputFile) );
174 bw.write("Conducting ownership analysis with allocation depth = "+allocationDepth+"\n");
175 boolean foundSomeAlias = false;
177 Descriptor d = typeUtil.getMain();
178 HashSet<AllocationSite> allocSites = getFlaggedAllocationSites(d);
180 // for each allocation site check for aliases with
181 // other allocation sites in the context of execution
183 HashSet<AllocationSite> outerChecked = new HashSet<AllocationSite>();
184 Iterator allocItr1 = allocSites.iterator();
185 while( allocItr1.hasNext() ) {
186 AllocationSite as1 = (AllocationSite) allocItr1.next();
188 Iterator allocItr2 = allocSites.iterator();
189 while( allocItr2.hasNext() ) {
190 AllocationSite as2 = (AllocationSite) allocItr2.next();
192 if( !outerChecked.contains(as2) &&
193 createsPotentialAliases(d, as1, as2) ) {
194 foundSomeAlias = true;
195 bw.write("Potential alias between "+as1.getDisjointId()+" and "+as2.getDisjointId()+".\n");
199 outerChecked.add(as1);
202 if( !foundSomeAlias ) {
203 bw.write("No aliases between flagged objects found.\n");
208 ///////////////////////////////////////////
210 // end public interface
212 ///////////////////////////////////////////
221 // data from the compiler
223 private TypeUtil typeUtil;
224 private CallGraph callGraph;
225 private int allocationDepth;
227 // used to identify HeapRegionNode objects
228 // A unique ID equates an object in one
229 // ownership graph with an object in another
230 // graph that logically represents the same
232 // start at 10 and increment to leave some
233 // reserved IDs for special purposes
234 static private int uniqueIDcount = 10;
237 // Use these data structures to track progress of
238 // processing all methods in the program, and by methods
239 // TaskDescriptor and MethodDescriptor are combined
240 // together, with a common parent class Descriptor
241 private Hashtable<MethodContext, OwnershipGraph> mapMethodContextToInitialParamAllocGraph;
242 private Hashtable<MethodContext, OwnershipGraph> mapMethodContextToCompleteOwnershipGraph;
243 private Hashtable<FlatNew, AllocationSite> mapFlatNewToAllocationSite;
244 private Hashtable<Descriptor, HashSet<AllocationSite> > mapDescriptorToAllocationSiteSet;
245 private Hashtable<MethodContext, Integer> mapMethodContextToNumUpdates;
246 private Hashtable<Descriptor, HashSet<MethodContext> > mapDescriptorToAllMethodContexts;
248 // Use these data structures to track progress of one pass of
249 // processing the FlatNodes of a particular method
250 private HashSet <FlatNode> flatNodesToVisit;
251 private Hashtable<FlatNode, OwnershipGraph> mapFlatNodeToOwnershipGraph;
252 private HashSet <FlatReturnNode> returnNodesToCombineForCompleteOwnershipGraph;
254 // descriptorsToAnalyze identifies the set of tasks and methods
255 // that are reachable from the program tasks, this set is initialized
256 // and then remains static
257 private HashSet<Descriptor> descriptorsToAnalyze;
259 // descriptorsToVisit is initialized to descriptorsToAnalyze and is
260 // reduced by visiting a descriptor during analysis. When dependents
261 // must be scheduled, only those contained in descriptorsToAnalyze
262 // should be re-added to this set
263 private HashSet <MethodContext> methodContextsToVisit;
265 // used in conjunction with the methodContextsToVisit set, fill with
266 // a topological sort of methodContextsToVisit and then empty that set
267 // algorithm should analyze something in the linked list until it is
268 // empty, and then work on the set as normal. The sorted linked list
269 // is just another, specially sorted bucket that is part of the
270 // methodContextsToVisit set
271 private LinkedList<MethodContext> sortedMethodContextsToVisit;
274 // special field descriptors for array elements
275 private Hashtable<TypeDescriptor, FieldDescriptor> mapTypeToArrayField;
277 // special field descriptors for variables with type, no field name
278 private Hashtable<TypeDescriptor, FieldDescriptor> mapTypeToVarField;
281 // a special temp descriptor for setting more than one parameter label
282 // to the all-aliased-parameters heap region node
283 protected static TempDescriptor tdAliasedParams = new TempDescriptor("_AllAliasedParams___");
286 // for controlling DOT file output
287 private boolean writeDOTs;
288 private boolean writeAllDOTs;
292 // this analysis generates an ownership graph for every task
294 public OwnershipAnalysis(State state,
299 boolean writeAllDOTs,
300 String aliasFile) throws java.io.IOException {
302 double timeStartAnalysis = (double) System.nanoTime();
306 this.callGraph = callGraph;
307 this.allocationDepth = allocationDepth;
308 this.writeDOTs = writeDOTs;
309 this.writeAllDOTs = writeAllDOTs;
311 descriptorsToAnalyze = new HashSet<Descriptor>();
313 mapMethodContextToInitialParamAllocGraph =
314 new Hashtable<MethodContext, OwnershipGraph>();
316 mapMethodContextToCompleteOwnershipGraph =
317 new Hashtable<MethodContext, OwnershipGraph>();
319 mapFlatNewToAllocationSite =
320 new Hashtable<FlatNew, AllocationSite>();
322 mapDescriptorToAllocationSiteSet =
323 new Hashtable<Descriptor, HashSet<AllocationSite> >();
325 mapDescriptorToAllMethodContexts =
326 new Hashtable<Descriptor, HashSet<MethodContext> >();
328 mapTypeToArrayField =
329 new Hashtable<TypeDescriptor, FieldDescriptor>();
332 new Hashtable<TypeDescriptor, FieldDescriptor>();
335 mapMethodContextToNumUpdates = new Hashtable<MethodContext, Integer>();
340 // initialize methods to visit as the set of all tasks in the
341 // program and then any method that could be called starting
343 Iterator taskItr = state.getTaskSymbolTable().getDescriptorsIterator();
344 while( taskItr.hasNext() ) {
345 Descriptor d = (Descriptor) taskItr.next();
346 scheduleAllCallees(d);
350 // we are not in task mode, just normal Java, so start with
352 Descriptor d = typeUtil.getMain();
353 scheduleAllCallees(d);
357 // before beginning analysis, initialize every scheduled method
358 // with an ownership graph that has populated parameter index tables
359 // by analyzing the first node which is always a FlatMethod node
360 Iterator<Descriptor> dItr = descriptorsToAnalyze.iterator();
361 while( dItr.hasNext() ) {
362 Descriptor d = dItr.next();
363 OwnershipGraph og = new OwnershipGraph(allocationDepth, typeUtil);
366 if( d instanceof MethodDescriptor ) {
367 fm = state.getMethodFlat( (MethodDescriptor) d);
369 assert d instanceof TaskDescriptor;
370 fm = state.getMethodFlat( (TaskDescriptor) d);
373 MethodContext mc = new MethodContext( d );
374 assert !mapDescriptorToAllMethodContexts.containsKey( d );
375 HashSet<MethodContext> s = new HashSet<MethodContext>();
377 mapDescriptorToAllMethodContexts.put( d, s );
379 //System.out.println("Previsiting " + mc);
381 og = analyzeFlatNode(mc, fm, null, og);
382 setGraphForMethodContext(mc, og);
385 // as mentioned above, analyze methods one-by-one, possibly revisiting
386 // a method if the methods that it calls are updated
389 double timeEndAnalysis = (double) System.nanoTime();
390 double dt = (timeEndAnalysis - timeStartAnalysis)/(Math.pow( 10.0, 9.0 ) );
391 String treport = String.format( "The analysis took %.3f sec.", dt );
392 System.out.println( treport );
394 if( writeDOTs && !writeAllDOTs ) {
395 writeFinalContextGraphs();
398 if( aliasFile != null ) {
400 writeAllAliases(aliasFile);
402 writeAllAliasesJava(aliasFile);
407 // called from the constructor to help initialize the set
408 // of methods that needs to be analyzed by ownership analysis
409 private void scheduleAllCallees(Descriptor d) {
410 if( descriptorsToAnalyze.contains(d) ) {
413 descriptorsToAnalyze.add(d);
415 // start with all method calls to further schedule
416 Set moreMethodsToCheck = moreMethodsToCheck = callGraph.getMethodCalls(d);
418 if( d instanceof MethodDescriptor ) {
419 // see if this method has virtual dispatch
420 Set virtualMethods = callGraph.getMethods( (MethodDescriptor)d);
421 moreMethodsToCheck.addAll(virtualMethods);
424 // keep following any further methods identified in
426 Iterator methItr = moreMethodsToCheck.iterator();
427 while( methItr.hasNext() ) {
428 Descriptor m = (Descriptor) methItr.next();
429 scheduleAllCallees(m);
434 // manage the set of tasks and methods to be analyzed
435 // and be sure to reschedule tasks/methods when the methods
436 // they call are updated
437 private void analyzeMethods() throws java.io.IOException {
439 methodContextsToVisit = new HashSet <MethodContext>();
440 sortedMethodContextsToVisit = new LinkedList<MethodContext>();
442 Iterator<Descriptor> itrd2a = descriptorsToAnalyze.iterator();
443 while( itrd2a.hasNext() ) {
444 HashSet<MethodContext> mcs = mapDescriptorToAllMethodContexts.get( itrd2a.next() );
447 Iterator<MethodContext> itrmc = mcs.iterator();
448 while( itrmc.hasNext() ) {
449 methodContextsToVisit.add( itrmc.next() );
453 sortedMethodContextsToVisit = topologicalSort( methodContextsToVisit );
454 methodContextsToVisit.clear();
456 while( !methodContextsToVisit.isEmpty() ||
457 !sortedMethodContextsToVisit.isEmpty() ) {
459 MethodContext mc = null;
461 if( !sortedMethodContextsToVisit.isEmpty() ) {
462 mc = sortedMethodContextsToVisit.removeFirst();
464 mc = methodContextsToVisit.iterator().next();
465 methodContextsToVisit.remove(mc);
469 // because the task or method descriptor just extracted
470 // was in the "to visit" set it either hasn't been analyzed
471 // yet, or some method that it depends on has been
472 // updated. Recompute a complete ownership graph for
473 // this task/method and compare it to any previous result.
474 // If there is a change detected, add any methods/tasks
475 // that depend on this one to the "to visit" set.
477 System.out.println("Analyzing " + mc);
479 Descriptor d = mc.getDescriptor();
481 if( d instanceof MethodDescriptor ) {
482 fm = state.getMethodFlat( (MethodDescriptor) d);
484 assert d instanceof TaskDescriptor;
485 fm = state.getMethodFlat( (TaskDescriptor) d);
488 OwnershipGraph og = analyzeFlatMethod(mc, fm);
489 OwnershipGraph ogPrev = mapMethodContextToCompleteOwnershipGraph.get(mc);
490 if( !og.equals(ogPrev) ) {
491 setGraphForMethodContext(mc, og);
493 // only methods have dependents, tasks cannot
494 // be invoked by any user program calls
495 if( d instanceof MethodDescriptor ) {
496 MethodDescriptor md = (MethodDescriptor) d;
497 Set dependents = callGraph.getCallerSet(md);
498 if( dependents != null ) {
499 Iterator depItr = dependents.iterator();
500 while( depItr.hasNext() ) {
501 Descriptor dependent = (Descriptor) depItr.next();
502 if( descriptorsToAnalyze.contains(dependent) ) {
504 HashSet<MethodContext> mcs = mapDescriptorToAllMethodContexts.get( dependent );
507 Iterator<MethodContext> itrmc = mcs.iterator();
508 while( itrmc.hasNext() ) {
509 methodContextsToVisit.add( itrmc.next() );
521 // keep passing the Descriptor of the method along for debugging
522 // and dot file writing
523 private OwnershipGraph
524 analyzeFlatMethod(MethodContext mc,
525 FlatMethod flatm) throws java.io.IOException {
527 // initialize flat nodes to visit as the flat method
528 // because it is the entry point
530 flatNodesToVisit = new HashSet<FlatNode>();
531 flatNodesToVisit.add(flatm);
533 // initilize the mapping of flat nodes in this flat method to
534 // ownership graph results to an empty mapping
535 mapFlatNodeToOwnershipGraph = new Hashtable<FlatNode, OwnershipGraph>();
537 // initialize the set of return nodes that will be combined as
538 // the final ownership graph result to return as an empty set
539 returnNodesToCombineForCompleteOwnershipGraph = new HashSet<FlatReturnNode>();
542 while( !flatNodesToVisit.isEmpty() ) {
543 FlatNode fn = (FlatNode) flatNodesToVisit.iterator().next();
544 flatNodesToVisit.remove(fn);
546 //System.out.println( " "+fn );
548 // perform this node's contributions to the ownership
549 // graph on a new copy, then compare it to the old graph
550 // at this node to see if anything was updated.
551 OwnershipGraph og = new OwnershipGraph(allocationDepth, typeUtil);
553 // start by merging all node's parents' graphs
554 for( int i = 0; i < fn.numPrev(); ++i ) {
555 FlatNode pn = fn.getPrev(i);
556 if( mapFlatNodeToOwnershipGraph.containsKey(pn) ) {
557 OwnershipGraph ogParent = mapFlatNodeToOwnershipGraph.get(pn);
562 // apply the analysis of the flat node to the
563 // ownership graph made from the merge of the
565 og = analyzeFlatNode(mc,
567 returnNodesToCombineForCompleteOwnershipGraph,
571 if( mc.getDescriptor().getSymbol().equals( "addFlightPlan" ) ) {
572 debugSnapshot(og,fn);
577 // if the results of the new graph are different from
578 // the current graph at this node, replace the graph
579 // with the update and enqueue the children for
581 OwnershipGraph ogPrev = mapFlatNodeToOwnershipGraph.get(fn);
582 if( !og.equals(ogPrev) ) {
583 mapFlatNodeToOwnershipGraph.put(fn, og);
585 for( int i = 0; i < fn.numNext(); i++ ) {
586 FlatNode nn = fn.getNext(i);
587 flatNodesToVisit.add(nn);
592 // end by merging all return nodes into a complete
593 // ownership graph that represents all possible heap
594 // states after the flat method returns
595 OwnershipGraph completeGraph = new OwnershipGraph(allocationDepth, typeUtil);
596 Iterator retItr = returnNodesToCombineForCompleteOwnershipGraph.iterator();
597 while( retItr.hasNext() ) {
598 FlatReturnNode frn = (FlatReturnNode) retItr.next();
599 assert mapFlatNodeToOwnershipGraph.containsKey(frn);
600 OwnershipGraph ogr = mapFlatNodeToOwnershipGraph.get(frn);
601 completeGraph.merge(ogr);
604 return completeGraph;
608 private OwnershipGraph
609 analyzeFlatNode(MethodContext mc,
611 HashSet<FlatReturnNode> setRetNodes,
612 OwnershipGraph og) throws java.io.IOException {
618 // use node type to decide what alterations to make
619 // to the ownership graph
620 switch( fn.kind() ) {
622 case FKind.FlatMethod:
623 FlatMethod fm = (FlatMethod) fn;
625 // there should only be one FlatMethod node as the
626 // parent of all other FlatNode objects, so take
627 // the opportunity to construct the initial graph by
628 // adding parameters labels to new heap regions
629 // AND this should be done once globally so that the
630 // parameter IDs are consistent between analysis
631 // iterations, so if this step has been done already
632 // just merge in the cached version
633 OwnershipGraph ogInitParamAlloc = mapMethodContextToInitialParamAllocGraph.get(mc);
634 if( ogInitParamAlloc == null ) {
636 // if the method context has aliased parameters, make sure
637 // there is a blob region for all those param labels to
639 Set<Integer> aliasedParamIndices = mc.getAliasedParamIndices();
640 if( !aliasedParamIndices.isEmpty() ) {
641 og.makeAliasedParamHeapRegionNode( tdAliasedParams );
644 // set up each parameter
645 for( int i = 0; i < fm.numParameters(); ++i ) {
646 TempDescriptor tdParam = fm.getParameter( i );
647 Integer paramIndex = new Integer( i );
649 if( aliasedParamIndices.contains( paramIndex ) ) {
650 // just point this one to the alias blob
651 og.assignTempEqualToAliasedParam( tdParam,
655 // this parameter is not aliased to others, give it
656 // a fresh parameter heap region
658 og.assignTempEqualToParamAlloc(tdParam,
659 mc.getDescriptor() instanceof TaskDescriptor,
665 OwnershipGraph ogResult = new OwnershipGraph(allocationDepth, typeUtil);
667 mapMethodContextToInitialParamAllocGraph.put(mc, ogResult);
670 // or just leverage the cached copy
671 og.merge(ogInitParamAlloc);
675 case FKind.FlatOpNode:
676 FlatOpNode fon = (FlatOpNode) fn;
677 if( fon.getOp().getOp() == Operation.ASSIGN ) {
680 og.assignTempXEqualToTempY(lhs, rhs);
684 case FKind.FlatCastNode:
685 FlatCastNode fcn = (FlatCastNode) fn;
688 TypeDescriptor td = fcn.getType();
691 FieldDescriptor fd = mapTypeToVarField.get( td );
693 fd = new FieldDescriptor(new Modifiers(Modifiers.PUBLIC),
698 mapTypeToVarField.put( td, fd );
701 og.assignTypedTempXEqualToTempY(lhs, rhs, fd);
704 case FKind.FlatFieldNode:
705 FlatFieldNode ffn = (FlatFieldNode) fn;
708 fld = ffn.getField();
709 if( !fld.getType().isImmutable() || fld.getType().isArray() ) {
710 og.assignTempXEqualToTempYFieldF(lhs, rhs, fld);
714 case FKind.FlatSetFieldNode:
715 FlatSetFieldNode fsfn = (FlatSetFieldNode) fn;
717 fld = fsfn.getField();
719 if( !fld.getType().isImmutable() || fld.getType().isArray() ) {
720 og.assignTempXFieldFEqualToTempY(lhs, fld, rhs);
724 case FKind.FlatElementNode:
725 FlatElementNode fen = (FlatElementNode) fn;
728 if( !lhs.getType().isImmutable() || lhs.getType().isArray() ) {
730 assert rhs.getType() != null;
731 assert rhs.getType().isArray();
733 TypeDescriptor tdElement = rhs.getType().dereference();
734 FieldDescriptor fdElement = mapTypeToArrayField.get( tdElement );
735 if( fdElement == null ) {
736 fdElement = new FieldDescriptor(new Modifiers(Modifiers.PUBLIC),
741 mapTypeToArrayField.put( tdElement, fdElement );
744 og.assignTempXEqualToTempYFieldF(lhs, rhs, fdElement);
748 case FKind.FlatSetElementNode:
749 FlatSetElementNode fsen = (FlatSetElementNode) fn;
752 if( !rhs.getType().isImmutable() || rhs.getType().isArray() ) {
754 assert lhs.getType() != null;
755 assert lhs.getType().isArray();
757 TypeDescriptor tdElement = lhs.getType().dereference();
758 FieldDescriptor fdElement = mapTypeToArrayField.get( tdElement );
759 if( fdElement == null ) {
760 fdElement = new FieldDescriptor(new Modifiers(Modifiers.PUBLIC),
765 mapTypeToArrayField.put( tdElement, fdElement );
768 og.assignTempXFieldFEqualToTempY(lhs, fdElement, rhs);
773 FlatNew fnn = (FlatNew) fn;
775 if( !lhs.getType().isImmutable() || lhs.getType().isArray() ) {
776 AllocationSite as = getAllocationSiteFromFlatNewPRIVATE(fnn);
777 og.assignTempEqualToNewAlloc(lhs, as);
782 FlatCall fc = (FlatCall) fn;
783 MethodDescriptor md = fc.getMethod();
784 FlatMethod flatm = state.getMethodFlat(md);
785 OwnershipGraph ogMergeOfAllPossibleCalleeResults = new OwnershipGraph(allocationDepth, typeUtil);
787 if( md.isStatic() ) {
788 // a static method is simply always the same, makes life easy
789 ogMergeOfAllPossibleCalleeResults = og;
791 Set<Integer> aliasedParamIndices =
792 ogMergeOfAllPossibleCalleeResults.calculateAliasedParamSet(fc, md.isStatic(), flatm);
793 MethodContext mcNew = new MethodContext( md, aliasedParamIndices );
794 OwnershipGraph onlyPossibleCallee = mapMethodContextToCompleteOwnershipGraph.get( mcNew );
796 if( onlyPossibleCallee == null ) {
797 // if this method context has never been analyzed just schedule it for analysis
798 // and skip over this call site for now
799 methodContextsToVisit.add( mcNew );
802 ogMergeOfAllPossibleCalleeResults.resolveMethodCall(fc, md.isStatic(), flatm, onlyPossibleCallee);
806 // if the method descriptor is virtual, then there could be a
807 // set of possible methods that will actually be invoked, so
808 // find all of them and merge all of their results together
809 TypeDescriptor typeDesc = fc.getThis().getType();
810 Set possibleCallees = callGraph.getMethods(md, typeDesc);
812 Iterator i = possibleCallees.iterator();
813 while( i.hasNext() ) {
814 MethodDescriptor possibleMd = (MethodDescriptor) i.next();
815 FlatMethod pflatm = state.getMethodFlat(possibleMd);
817 // don't alter the working graph (og) until we compute a result for every
818 // possible callee, merge them all together, then set og to that
819 OwnershipGraph ogCopy = new OwnershipGraph(allocationDepth, typeUtil);
822 Set<Integer> aliasedParamIndices =
823 ogCopy.calculateAliasedParamSet(fc, possibleMd.isStatic(), pflatm);
824 MethodContext mcNew = new MethodContext( possibleMd, aliasedParamIndices );
825 OwnershipGraph ogPotentialCallee = mapMethodContextToCompleteOwnershipGraph.get( mcNew );
827 if( ogPotentialCallee == null ) {
828 // if this method context has never been analyzed just schedule it for analysis
829 // and skip over this call site for now
830 methodContextsToVisit.add( mcNew );
833 ogCopy.resolveMethodCall(fc, possibleMd.isStatic(), pflatm, ogPotentialCallee);
836 ogMergeOfAllPossibleCalleeResults.merge(ogCopy);
840 og = ogMergeOfAllPossibleCalleeResults;
843 case FKind.FlatReturnNode:
844 FlatReturnNode frn = (FlatReturnNode) fn;
845 rhs = frn.getReturnTemp();
846 if( rhs != null && !rhs.getType().isImmutable() ) {
847 og.assignReturnEqualToTemp(rhs);
849 setRetNodes.add(frn);
857 // insert a call to debugSnapshot() somewhere in the analysis to get
858 // successive captures of the analysis state
859 int debugCounter = 0;
860 int numStartCountReport = 0;
861 int freqCountReport = 1;
862 int iterStartCapture = 0;
863 int numIterToCapture = 500;
864 void debugSnapshot(OwnershipGraph og, FlatNode fn) {
865 if( debugCounter > numStartCountReport + numIterToCapture ) {
870 if( debugCounter > numStartCountReport &&
871 debugCounter % freqCountReport == 0 ) {
872 System.out.println(" @@@ debug counter = "+debugCounter);
874 if( debugCounter > iterStartCapture ) {
875 System.out.println(" @@@ capturing debug "+(debugCounter-iterStartCapture)+" @@@");
876 String graphName = String.format("snap%04d",debugCounter-iterStartCapture);
878 graphName = graphName+fn;
881 og.writeGraph(graphName, true, true, false, false, false);
882 } catch( Exception e ) {
883 System.out.println("Error writing debug capture.");
888 if( debugCounter == iterStartCapture + numIterToCapture ) {
889 System.out.println("Stopping analysis after debug captures.");
897 // this method should generate integers strictly greater than zero!
898 // special "shadow" regions are made from a heap region by negating
900 static public Integer generateUniqueHeapRegionNodeID() {
902 return new Integer(uniqueIDcount);
906 private void setGraphForMethodContext(MethodContext mc, OwnershipGraph og) {
908 mapMethodContextToCompleteOwnershipGraph.put(mc, og);
910 if( writeDOTs && writeAllDOTs ) {
911 if( !mapMethodContextToNumUpdates.containsKey(mc) ) {
912 mapMethodContextToNumUpdates.put(mc, new Integer(0) );
914 Integer n = mapMethodContextToNumUpdates.get(mc);
916 og.writeGraph(mc, n, true, true, true, false, false);
917 } catch( IOException e ) {}
918 mapMethodContextToNumUpdates.put(mc, n + 1);
923 private void writeFinalContextGraphs() {
924 // arguments to writeGraph are:
925 // boolean writeLabels,
926 // boolean labelSelect,
927 // boolean pruneGarbage,
928 // boolean writeReferencers
929 // boolean writeParamMappings
931 Set entrySet = mapMethodContextToCompleteOwnershipGraph.entrySet();
932 Iterator itr = entrySet.iterator();
933 while( itr.hasNext() ) {
934 Map.Entry me = (Map.Entry) itr.next();
935 MethodContext mc = (MethodContext) me.getKey();
936 OwnershipGraph og = (OwnershipGraph) me.getValue();
939 og.writeGraph(mc, true, true, true, false, false);
940 } catch( IOException e ) {}
945 // return just the allocation site associated with one FlatNew node
946 private AllocationSite getAllocationSiteFromFlatNewPRIVATE(FlatNew fn) {
948 if( !mapFlatNewToAllocationSite.containsKey(fn) ) {
949 AllocationSite as = new AllocationSite(allocationDepth, fn, fn.getDisjointId());
951 // the newest nodes are single objects
952 for( int i = 0; i < allocationDepth; ++i ) {
953 Integer id = generateUniqueHeapRegionNodeID();
954 as.setIthOldest(i, id);
957 // the oldest node is a summary node
958 Integer idSummary = generateUniqueHeapRegionNodeID();
959 as.setSummary(idSummary);
961 mapFlatNewToAllocationSite.put(fn, as);
964 return mapFlatNewToAllocationSite.get(fn);
968 // return all allocation sites in the method (there is one allocation
969 // site per FlatNew node in a method)
970 private HashSet<AllocationSite> getAllocationSiteSet(Descriptor d) {
971 if( !mapDescriptorToAllocationSiteSet.containsKey(d) ) {
972 buildAllocationSiteSet(d);
975 return mapDescriptorToAllocationSiteSet.get(d);
979 private void buildAllocationSiteSet(Descriptor d) {
980 HashSet<AllocationSite> s = new HashSet<AllocationSite>();
983 if( d instanceof MethodDescriptor ) {
984 fm = state.getMethodFlat( (MethodDescriptor) d);
986 assert d instanceof TaskDescriptor;
987 fm = state.getMethodFlat( (TaskDescriptor) d);
990 // visit every node in this FlatMethod's IR graph
991 // and make a set of the allocation sites from the
992 // FlatNew node's visited
993 HashSet<FlatNode> visited = new HashSet<FlatNode>();
994 HashSet<FlatNode> toVisit = new HashSet<FlatNode>();
997 while( !toVisit.isEmpty() ) {
998 FlatNode n = toVisit.iterator().next();
1000 if( n instanceof FlatNew ) {
1001 s.add(getAllocationSiteFromFlatNewPRIVATE( (FlatNew) n) );
1007 for( int i = 0; i < n.numNext(); ++i ) {
1008 FlatNode child = n.getNext(i);
1009 if( !visited.contains(child) ) {
1015 mapDescriptorToAllocationSiteSet.put(d, s);
1019 private HashSet<AllocationSite> getFlaggedAllocationSites(Descriptor dIn) {
1021 HashSet<AllocationSite> out = new HashSet<AllocationSite>();
1022 HashSet<Descriptor> toVisit = new HashSet<Descriptor>();
1023 HashSet<Descriptor> visited = new HashSet<Descriptor>();
1027 while( !toVisit.isEmpty() ) {
1028 Descriptor d = toVisit.iterator().next();
1032 HashSet<AllocationSite> asSet = getAllocationSiteSet(d);
1033 Iterator asItr = asSet.iterator();
1034 while( asItr.hasNext() ) {
1035 AllocationSite as = (AllocationSite) asItr.next();
1036 if( as.getDisjointId() != null ) {
1041 // enqueue callees of this method to be searched for
1042 // allocation sites also
1043 Set callees = callGraph.getCalleeSet(d);
1044 if( callees != null ) {
1045 Iterator methItr = callees.iterator();
1046 while( methItr.hasNext() ) {
1047 MethodDescriptor md = (MethodDescriptor) methItr.next();
1049 if( !visited.contains(md) ) {
1060 private HashSet<AllocationSite>
1061 getFlaggedAllocationSitesReachableFromTaskPRIVATE(TaskDescriptor td) {
1063 HashSet<AllocationSite> asSetTotal = new HashSet<AllocationSite>();
1064 HashSet<Descriptor> toVisit = new HashSet<Descriptor>();
1065 HashSet<Descriptor> visited = new HashSet<Descriptor>();
1069 // traverse this task and all methods reachable from this task
1070 while( !toVisit.isEmpty() ) {
1071 Descriptor d = toVisit.iterator().next();
1075 HashSet<AllocationSite> asSet = getAllocationSiteSet(d);
1076 Iterator asItr = asSet.iterator();
1077 while( asItr.hasNext() ) {
1078 AllocationSite as = (AllocationSite) asItr.next();
1079 TypeDescriptor typed = as.getType();
1080 if( typed != null ) {
1081 ClassDescriptor cd = typed.getClassDesc();
1082 if( cd != null && cd.hasFlags() ) {
1088 // enqueue callees of this method to be searched for
1089 // allocation sites also
1090 Set callees = callGraph.getCalleeSet(d);
1091 if( callees != null ) {
1092 Iterator methItr = callees.iterator();
1093 while( methItr.hasNext() ) {
1094 MethodDescriptor md = (MethodDescriptor) methItr.next();
1096 if( !visited.contains(md) ) {
1108 private LinkedList<MethodContext> topologicalSort( HashSet<MethodContext> set ) {
1109 HashSet <MethodContext> discovered = new HashSet <MethodContext>();
1110 LinkedList<MethodContext> sorted = new LinkedList<MethodContext>();
1112 Iterator<MethodContext> itr = set.iterator();
1113 while( itr.hasNext() ) {
1114 MethodContext mc = itr.next();
1116 if( !discovered.contains( mc ) ) {
1117 dfsVisit( set, mc, sorted, discovered );
1124 private void dfsVisit( HashSet<MethodContext> set,
1126 LinkedList<MethodContext> sorted,
1127 HashSet <MethodContext> discovered ) {
1128 discovered.add( mc );
1130 Descriptor d = mc.getDescriptor();
1131 if( d instanceof MethodDescriptor ) {
1132 MethodDescriptor md = (MethodDescriptor) d;
1133 Iterator itr = callGraph.getCallerSet( md ).iterator();
1134 while( itr.hasNext() ) {
1135 Descriptor dCaller = (Descriptor) itr.next();
1137 // only consider the callers in the original set to analyze
1138 Set<MethodContext> callerContexts = mapDescriptorToAllMethodContexts.get( dCaller );
1139 if( callerContexts == null )
1142 // since the analysis hasn't started, there should be exactly one
1143 // context if there are any at all
1144 assert callerContexts.size() == 1;
1145 MethodContext mcCaller = callerContexts.iterator().next();
1146 assert set.contains( mcCaller );
1148 if( !discovered.contains( mcCaller ) ) {
1149 dfsVisit( set, mcCaller, sorted, discovered );
1154 sorted.addFirst( mc );