1 package Analysis.OwnershipAnalysis;
3 import Analysis.CallGraph.*;
10 public class OwnershipAnalysis {
12 ///////////////////////////////////////////
14 // Public interface to discover possible
15 // aliases in the program under analysis
17 ///////////////////////////////////////////
19 public HashSet<AllocationSite>
20 getFlaggedAllocationSitesReachableFromTask( TaskDescriptor td ) {
22 return getFlaggedAllocationSitesReachableFromTaskPRIVATE( td );
25 public AllocationSite getAllocationSiteFromFlatNew( FlatNew fn ) {
26 return getAllocationSiteFromFlatNewPRIVATE( fn );
29 public boolean createsPotentialAliases( Descriptor taskOrMethod,
33 OwnershipGraph og = mapDescriptorToCompleteOwnershipGraph.get( taskOrMethod );
36 return createsPotentialAliases( og,
37 getHeapRegionIDset( og, paramIndex1 ),
38 getHeapRegionIDset( og, paramIndex2 ) );
41 public boolean createsPotentialAliases( Descriptor taskOrMethod,
43 AllocationSite alloc ) {
45 OwnershipGraph og = mapDescriptorToCompleteOwnershipGraph.get( taskOrMethod );
48 return createsPotentialAliases( og,
49 getHeapRegionIDset( og, paramIndex ),
50 getHeapRegionIDset( alloc ) );
53 public boolean createsPotentialAliases( Descriptor taskOrMethod,
57 OwnershipGraph og = mapDescriptorToCompleteOwnershipGraph.get( taskOrMethod );
60 return createsPotentialAliases( og,
61 getHeapRegionIDset( og, paramIndex ),
62 getHeapRegionIDset( alloc ) );
65 public boolean createsPotentialAliases( Descriptor taskOrMethod,
66 AllocationSite alloc1,
67 AllocationSite alloc2 ) {
69 OwnershipGraph og = mapDescriptorToCompleteOwnershipGraph.get( taskOrMethod );
72 return createsPotentialAliases( og,
73 getHeapRegionIDset( alloc1 ),
74 getHeapRegionIDset( alloc2 ) );
77 public boolean createsPotentialAliases( Descriptor taskOrMethod,
79 HashSet<AllocationSite> allocSet ) {
81 OwnershipGraph og = mapDescriptorToCompleteOwnershipGraph.get( taskOrMethod );
84 return createsPotentialAliases( og,
85 getHeapRegionIDset( alloc ),
86 getHeapRegionIDset( allocSet ) );
90 // use the methods given above to check every possible alias
91 // between task parameters and flagged allocation sites reachable
93 public void writeAllAliases( String outputFile ) throws java.io.IOException {
95 BufferedWriter bw = new BufferedWriter( new FileWriter( outputFile ) );
97 // look through every task for potential aliases
98 Iterator taskItr = state.getTaskSymbolTable().getDescriptorsIterator();
99 while( taskItr.hasNext() ) {
100 TaskDescriptor td = (TaskDescriptor) taskItr.next();
102 HashSet<AllocationSite> allocSites = getFlaggedAllocationSitesReachableFromTask( td );
104 // for each task parameter, check for aliases with
105 // other task parameters and every allocation site
106 // reachable from this task
107 FlatMethod fm = state.getMethodFlat( td );
108 for( int i = 0; i < fm.numParameters(); ++i ) {
110 // for the ith parameter check for aliases to all
111 // higher numbered parameters
112 for( int j = i + 1; j < fm.numParameters(); ++j ) {
113 if( createsPotentialAliases( td, i, j ) ) {
114 bw.write( "Task "+td+" potentially aliases parameters "+i+" and "+j+".\n" );
118 // for the ith parameter, check for aliases against
119 // the set of allocation sites reachable from this
121 Iterator allocItr = allocSites.iterator();
122 while( allocItr.hasNext() ) {
123 AllocationSite as = (AllocationSite) allocItr.next();
124 if( createsPotentialAliases( td, i, as ) ) {
125 bw.write( "Task "+td+" potentially aliases parameter "+i+" and "+as+".\n" );
130 // for each allocation site check for aliases with
131 // other allocation sites in the context of execution
133 Iterator allocItr = allocSites.iterator();
134 while( allocItr.hasNext() ) {
135 AllocationSite as = (AllocationSite) allocItr.next();
136 if( createsPotentialAliases( td, as, allocSites ) ) {
137 bw.write( "Task "+td+" potentially aliases "+as+" and the rest of the set.\n" );
146 ///////////////////////////////////////////
148 // end public interface
150 ///////////////////////////////////////////
159 // data from the compiler
161 private CallGraph callGraph;
162 private int allocationDepth;
164 // used to identify HeapRegionNode objects
165 // A unique ID equates an object in one
166 // ownership graph with an object in another
167 // graph that logically represents the same
169 static private int uniqueIDcount = 0;
172 // Use these data structures to track progress of
173 // processing all methods in the program, and by methods
174 // TaskDescriptor and MethodDescriptor are combined
175 // together, with a common parent class Descriptor
176 private HashSet <Descriptor> descriptorsToVisit;
177 private Hashtable<Descriptor, OwnershipGraph> mapDescriptorToCompleteOwnershipGraph;
178 private Hashtable<FlatNew, AllocationSite> mapFlatNewToAllocationSite;
179 private Hashtable<Descriptor, HashSet<AllocationSite> > mapDescriptorToAllocationSiteSet;
181 // Use these data structures to track progress of one pass of
182 // processing the FlatNodes of a particular method
183 private HashSet <FlatNode> flatNodesToVisit;
184 private Hashtable<FlatNode, OwnershipGraph> mapFlatNodeToOwnershipGraph;
185 private HashSet <FlatReturnNode> returnNodesToCombineForCompleteOwnershipGraph;
188 // this analysis generates an ownership graph for every task
190 public OwnershipAnalysis( State state,
192 int allocationDepth ) throws java.io.IOException {
194 this.callGraph = callGraph;
195 this.allocationDepth = allocationDepth;
197 descriptorsToVisit = new HashSet<Descriptor>();
199 mapDescriptorToCompleteOwnershipGraph =
200 new Hashtable<Descriptor, OwnershipGraph>();
202 mapFlatNewToAllocationSite =
203 new Hashtable<FlatNew, AllocationSite>();
205 mapDescriptorToAllocationSiteSet =
206 new Hashtable<Descriptor, HashSet<AllocationSite> >();
208 // use this set to prevent infinite recursion when
209 // traversing the call graph
210 HashSet<Descriptor> calleesScheduled = new HashSet<Descriptor>();
213 // initialize methods to visit as the set of all tasks in the
214 // program and then any method that could be called starting
216 Iterator taskItr = state.getTaskSymbolTable().getDescriptorsIterator();
217 while( taskItr.hasNext() ) {
218 Descriptor d = (Descriptor) taskItr.next();
219 descriptorsToVisit.add( d );
221 // recursively find all callees from this task
222 scheduleAllCallees( calleesScheduled, d );
225 // before beginning analysis, initialize every scheduled method
226 // with an ownership graph that has populated parameter index tables
227 // by analyzing the first node which is always a FlatMethod node
228 Iterator<Descriptor> dItr = calleesScheduled.iterator();
229 while( dItr.hasNext() ) {
230 Descriptor d = dItr.next();
231 OwnershipGraph og = new OwnershipGraph( allocationDepth );
234 if( d instanceof MethodDescriptor ) {
235 fm = state.getMethodFlat( (MethodDescriptor) d );
237 assert d instanceof TaskDescriptor;
238 fm = state.getMethodFlat( (TaskDescriptor) d );
241 analyzeFlatNode( d, fm, null, og );
242 mapDescriptorToCompleteOwnershipGraph.put( d, og );
245 // as mentioned above, analyze methods one-by-one, possibly revisiting
246 // a method if the methods that it calls are updated
250 // called from the constructor to help initialize the set
251 // of methods that needs to be analyzed by ownership analysis
252 private void scheduleAllCallees( HashSet<Descriptor> calleesScheduled,
254 if( calleesScheduled.contains( d ) ) {
257 calleesScheduled.add( d );
259 Set callees = callGraph.getCalleeSet( d );
260 if( callees == null ) {
264 Iterator methItr = callees.iterator();
265 while( methItr.hasNext() ) {
266 MethodDescriptor md = (MethodDescriptor) methItr.next();
267 descriptorsToVisit.add( md );
269 // recursively find all callees from this task
270 scheduleAllCallees( calleesScheduled, md );
275 // manage the set of tasks and methods to be analyzed
276 // and be sure to reschedule tasks/methods when the methods
277 // they call are updated
278 private void analyzeMethods() throws java.io.IOException {
280 while( !descriptorsToVisit.isEmpty() ) {
281 Descriptor d = (Descriptor) descriptorsToVisit.iterator().next();
282 descriptorsToVisit.remove( d );
284 // because the task or method descriptor just extracted
285 // was in the "to visit" set it either hasn't been analyzed
286 // yet, or some method that it depends on has been
287 // updated. Recompute a complete ownership graph for
288 // this task/method and compare it to any previous result.
289 // If there is a change detected, add any methods/tasks
290 // that depend on this one to the "to visit" set.
292 System.out.println( "Analyzing " + d );
295 if( d instanceof MethodDescriptor ) {
296 fm = state.getMethodFlat( (MethodDescriptor) d );
298 assert d instanceof TaskDescriptor;
299 fm = state.getMethodFlat( (TaskDescriptor) d );
302 OwnershipGraph og = analyzeFlatMethod( d, fm );
303 OwnershipGraph ogPrev = mapDescriptorToCompleteOwnershipGraph.get( d );
304 if( !og.equals( ogPrev ) ) {
305 mapDescriptorToCompleteOwnershipGraph.put( d, og );
310 boolean pruneGarbage,
311 boolean writeReferencers
313 og.writeGraph( d, true, true, true, false );
315 // only methods have dependents, tasks cannot
316 // be invoked by any user program calls
317 if( d instanceof MethodDescriptor ) {
318 MethodDescriptor md = (MethodDescriptor) d;
319 Set dependents = callGraph.getCallerSet( md );
320 if( dependents != null ) {
321 descriptorsToVisit.addAll( dependents );
333 // keep passing the Descriptor of the method along for debugging
334 // and dot file writing
335 private OwnershipGraph
336 analyzeFlatMethod( Descriptor mDesc,
337 FlatMethod flatm ) throws java.io.IOException {
339 // initialize flat nodes to visit as the flat method
340 // because all other nodes in this flat method are
341 // decendents of the flat method itself
342 flatNodesToVisit = new HashSet<FlatNode>();
343 flatNodesToVisit.add( flatm );
345 // initilize the mapping of flat nodes in this flat method to
346 // ownership graph results to an empty mapping
347 mapFlatNodeToOwnershipGraph = new Hashtable<FlatNode, OwnershipGraph>();
349 // initialize the set of return nodes that will be combined as
350 // the final ownership graph result to return as an empty set
351 returnNodesToCombineForCompleteOwnershipGraph = new HashSet<FlatReturnNode>();
353 while( !flatNodesToVisit.isEmpty() ) {
354 FlatNode fn = (FlatNode) flatNodesToVisit.iterator().next();
355 flatNodesToVisit.remove( fn );
357 // perform this node's contributions to the ownership
358 // graph on a new copy, then compare it to the old graph
359 // at this node to see if anything was updated.
360 OwnershipGraph og = new OwnershipGraph( allocationDepth );
362 // start by merging all node's parents' graphs
363 for( int i = 0; i < fn.numPrev(); ++i ) {
364 FlatNode pn = fn.getPrev( i );
365 OwnershipGraph ogParent = getGraphFromFlatNode( pn );
366 og.merge( ogParent );
369 // apply the analysis of the flat node to the
370 // ownership graph made from the merge of the
372 analyzeFlatNode( mDesc,
374 returnNodesToCombineForCompleteOwnershipGraph,
377 // if the results of the new graph are different from
378 // the current graph at this node, replace the graph
379 // with the update and enqueue the children for
381 OwnershipGraph ogPrev = getGraphFromFlatNode( fn );
383 if( !og.equals( ogPrev ) ) {
384 setGraphForFlatNode( fn, og );
390 String s = String.format( "debug%04d", x );
391 //og.writeGraph( s, true, true, true, false );
396 for( int i = 0; i < fn.numNext(); i++ ) {
397 FlatNode nn = fn.getNext( i );
398 flatNodesToVisit.add( nn );
403 // end by merging all return nodes into a complete
404 // ownership graph that represents all possible heap
405 // states after the flat method returns
406 OwnershipGraph completeGraph = new OwnershipGraph( allocationDepth );
407 Iterator retItr = returnNodesToCombineForCompleteOwnershipGraph.iterator();
408 while( retItr.hasNext() ) {
409 FlatReturnNode frn = (FlatReturnNode) retItr.next();
410 OwnershipGraph ogr = getGraphFromFlatNode( frn );
411 completeGraph.merge( ogr );
413 return completeGraph;
418 analyzeFlatNode( Descriptor methodDesc,
420 HashSet<FlatReturnNode> setRetNodes,
421 OwnershipGraph og ) throws java.io.IOException {
427 // use node type to decide what alterations to make
428 // to the ownership graph
429 switch( fn.kind() ) {
431 case FKind.FlatMethod:
432 FlatMethod fm = (FlatMethod) fn;
434 // there should only be one FlatMethod node as the
435 // parent of all other FlatNode objects, so take
436 // the opportunity to construct the initial graph by
437 // adding parameters labels to new heap regions
438 for( int i = 0; i < fm.numParameters(); ++i ) {
439 TempDescriptor tdParam = fm.getParameter( i );
440 og.assignParameterAllocationToTemp( methodDesc instanceof TaskDescriptor,
447 case FKind.FlatOpNode:
448 FlatOpNode fon = (FlatOpNode) fn;
449 if( fon.getOp().getOp() == Operation.ASSIGN ) {
452 og.assignTempYToTempX( src, dst );
456 case FKind.FlatFieldNode:
457 FlatFieldNode ffn = (FlatFieldNode) fn;
460 fld = ffn.getField();
461 if( !fld.getType().isPrimitive() ) {
462 og.assignTempYFieldFToTempX( src, fld, dst );
466 case FKind.FlatSetFieldNode:
467 FlatSetFieldNode fsfn = (FlatSetFieldNode) fn;
470 fld = fsfn.getField();
471 og.assignTempYToTempXFieldF( src, dst, fld );
475 FlatNew fnn = (FlatNew) fn;
477 AllocationSite as = getAllocationSiteFromFlatNewPRIVATE( fnn );
479 og.assignNewAllocationToTempX( dst, as );
483 FlatCall fc = (FlatCall) fn;
484 MethodDescriptor md = fc.getMethod();
485 FlatMethod flatm = state.getMethodFlat( md );
486 //HashSet<AllocationSite> allocSiteSet = getAllocationSiteSet( md );
487 OwnershipGraph ogAllPossibleCallees = new OwnershipGraph( allocationDepth );
489 if( md.isStatic() ) {
490 // a static method is simply always the same, makes life easy
491 OwnershipGraph onlyPossibleCallee = mapDescriptorToCompleteOwnershipGraph.get( md );
492 ogAllPossibleCallees.merge( onlyPossibleCallee );
495 if( onlyPossibleCallee != null ) {
496 onlyPossibleCallee.writeGraph( "only", false, false );
497 System.out.println( "There was only one possible callee, "+md );
502 // if the method descriptor is virtual, then there could be a
503 // set of possible methods that will actually be invoked, so
504 // find all of them and merge all of their graphs together
505 TypeDescriptor typeDesc = fc.getThis().getType();
506 Set possibleCallees = callGraph.getMethods( md, typeDesc );
510 Iterator i = possibleCallees.iterator();
511 while( i.hasNext() ) {
512 MethodDescriptor possibleMd = (MethodDescriptor) i.next();
513 //allocSiteSet.addAll( getAllocationSiteSet( possibleMd ) );
514 OwnershipGraph ogPotentialCallee = mapDescriptorToCompleteOwnershipGraph.get( possibleMd );
517 if( ogPotentialCallee != null ) {
518 ogPotentialCallee.writeGraph( "potential"+j, false, false );
523 ogAllPossibleCallees.merge( ogPotentialCallee );
526 //System.out.println( "There were "+j+" potential callees merged together." );
529 //System.out.println( "AllocationSiteSet has "+allocSiteSet.size()+" items." );
531 // now we should have the following information to resolve this method call:
533 // 1. A FlatCall fc to query for the caller's context (argument labels, etc)
535 // 2. Whether the method is static; if not we need to deal with the "this" pointer
537 // *******************************************************************************************
538 // 3. The original FlatMethod flatm to query for callee's context (paramter labels)
539 // NOTE! I assume FlatMethod before virtual dispatch accurately describes all possible methods!
540 // *******************************************************************************************
542 // 4. The OwnershipGraph ogAllPossibleCallees is a merge of every ownership graph of all the possible
543 // methods to capture any possible references made.
545 // 5. The Set of AllocationSite objects, allocSiteSet that is the set of allocation sites from
546 // every possible method we might have chosen
548 og.resolveMethodCall( fc, md.isStatic(), flatm, ogAllPossibleCallees );
551 case FKind.FlatReturnNode:
552 FlatReturnNode frn = (FlatReturnNode) fn;
553 setRetNodes.add( frn );
559 // this method should generate integers strictly greater than zero!
560 // special "shadow" regions are made from a heap region by negating
562 static public Integer generateUniqueHeapRegionNodeID() {
564 return new Integer( uniqueIDcount );
568 private OwnershipGraph getGraphFromFlatNode( FlatNode fn ) {
569 if( !mapFlatNodeToOwnershipGraph.containsKey( fn ) ) {
570 mapFlatNodeToOwnershipGraph.put( fn, new OwnershipGraph( allocationDepth ) );
573 return mapFlatNodeToOwnershipGraph.get( fn );
576 private void setGraphForFlatNode( FlatNode fn, OwnershipGraph og ) {
577 mapFlatNodeToOwnershipGraph.put( fn, og );
585 // return just the allocation site associated with one FlatNew node
586 private AllocationSite getAllocationSiteFromFlatNewPRIVATE( FlatNew fn ) {
588 if( !mapFlatNewToAllocationSite.containsKey( fn ) ) {
589 AllocationSite as = new AllocationSite( allocationDepth, fn.getType() );
591 // the newest nodes are single objects
592 for( int i = 0; i < allocationDepth; ++i ) {
593 Integer id = generateUniqueHeapRegionNodeID();
594 as.setIthOldest( i, id );
597 // the oldest node is a summary node
598 Integer idSummary = generateUniqueHeapRegionNodeID();
599 as.setSummary( idSummary );
601 mapFlatNewToAllocationSite.put( fn, as );
604 return mapFlatNewToAllocationSite.get( fn );
608 // return all allocation sites in the method (there is one allocation
609 // site per FlatNew node in a method)
610 private HashSet<AllocationSite> getAllocationSiteSet( Descriptor d ) {
611 if( !mapDescriptorToAllocationSiteSet.containsKey( d ) ) {
612 buildAllocationSiteSet( d );
615 return mapDescriptorToAllocationSiteSet.get( d );
619 private void buildAllocationSiteSet( Descriptor d ) {
620 HashSet<AllocationSite> s = new HashSet<AllocationSite>();
623 if( d instanceof MethodDescriptor ) {
624 fm = state.getMethodFlat( (MethodDescriptor) d );
626 assert d instanceof TaskDescriptor;
627 fm = state.getMethodFlat( (TaskDescriptor) d );
630 // visit every node in this FlatMethod's IR graph
631 // and make a set of the allocation sites from the
632 // FlatNew node's visited
633 HashSet<FlatNode> visited = new HashSet<FlatNode>();
634 HashSet<FlatNode> toVisit = new HashSet<FlatNode>();
637 while( !toVisit.isEmpty() ) {
638 FlatNode n = toVisit.iterator().next();
640 if( n instanceof FlatNew ) {
641 s.add( getAllocationSiteFromFlatNewPRIVATE( (FlatNew) n ) );
647 for( int i = 0; i < n.numNext(); ++i ) {
648 FlatNode child = n.getNext( i );
649 if( !visited.contains( child ) ) {
650 toVisit.add( child );
655 mapDescriptorToAllocationSiteSet.put( d, s );
659 private HashSet<AllocationSite>
660 getFlaggedAllocationSitesReachableFromTaskPRIVATE( TaskDescriptor td ) {
662 HashSet<AllocationSite> asSetTotal = new HashSet<AllocationSite>();
663 HashSet<Descriptor> toVisit = new HashSet<Descriptor>();
664 HashSet<Descriptor> visited = new HashSet<Descriptor>();
668 // traverse this task and all methods reachable from this task
669 while( !toVisit.isEmpty() ) {
670 Descriptor d = toVisit.iterator().next();
674 HashSet<AllocationSite> asSet = getAllocationSiteSet( d );
675 Iterator asItr = asSet.iterator();
676 while( asItr.hasNext() ) {
677 AllocationSite as = (AllocationSite) asItr.next();
678 if( as.getType().getClassDesc().hasFlags() ) {
679 asSetTotal.add( as );
683 // enqueue callees of this method to be searched for
684 // allocation sites also
685 Set callees = callGraph.getCalleeSet( d );
686 if( callees != null ) {
687 Iterator methItr = callees.iterator();
688 while( methItr.hasNext() ) {
689 MethodDescriptor md = (MethodDescriptor) methItr.next();
691 if( !visited.contains( md ) ) {
704 private HashSet<Integer> getHeapRegionIDset( OwnershipGraph og,
707 assert og.paramIndex2id.containsKey( paramIndex );
708 Integer idParam = og.paramIndex2id.get( paramIndex );
710 HashSet<Integer> idSet = new HashSet<Integer>();
711 idSet.add( idParam );
717 private HashSet<Integer> getHeapRegionIDset( AllocationSite alloc ) {
719 HashSet<Integer> idSet = new HashSet<Integer>();
721 for( int i = 0; i < alloc.getAllocationDepth(); ++i ) {
722 Integer id = alloc.getIthOldest( i );
726 Integer idSummary = alloc.getSummary();
727 idSet.add( idSummary );
732 private HashSet<Integer> getHeapRegionIDset( HashSet<AllocationSite> allocSet ) {
734 HashSet<Integer> idSet = new HashSet<Integer>();
736 Iterator allocItr = allocSet.iterator();
737 while( allocItr.hasNext() ) {
738 AllocationSite alloc = (AllocationSite) allocItr.next();
740 for( int i = 0; i < alloc.getAllocationDepth(); ++i ) {
741 Integer id = alloc.getIthOldest( i );
745 Integer idSummary = alloc.getSummary();
746 idSet.add( idSummary );
752 private boolean createsPotentialAliases( OwnershipGraph og,
753 HashSet<Integer> idSetA,
754 HashSet<Integer> idSetB ) {
755 boolean potentialAlias = false;
758 // first expand set B into the set of all heap region node ID's
759 // reachable from the nodes in set B
760 HashSet<Integer> idSetReachableFromB = og.getReachableSet( idSetB );
762 // then see if anything in A can reach a node in the set reachable
763 // from B. If so, there is a potential alias.
764 Iterator i = idSetA.iterator();
765 while( i.hasNext() ) {
766 Integer id = (Integer) i.next();
767 if( og.canIdReachSet( id, idSetB ) ) {