1 package Analysis.OwnershipAnalysis;
3 import Analysis.CallGraph.*;
10 public class OwnershipAnalysis {
14 private CallGraph callGraph;
15 private int allocationDepth;
18 // used to identify HeapRegionNode objects
19 // A unique ID equates an object in one
20 // ownership graph with an object in another
21 // graph that logically represents the same
23 static private int uniqueIDcount = 0;
26 // Use these data structures to track progress of
27 // processing all methods in the program, and by methods
28 // TaskDescriptor and MethodDescriptor are combined
29 // together, with a common parent class Descriptor
30 private HashSet <Descriptor> descriptorsToVisit;
31 private Hashtable<Descriptor, OwnershipGraph> mapDescriptorToCompleteOwnershipGraph;
32 private Hashtable<FlatNew, AllocationSite> mapFlatNewToAllocationSite;
33 private Hashtable<Descriptor, HashSet<AllocationSite> > mapDescriptorToAllocationSiteSet;
35 // Use these data structures to track progress of one pass of
36 // processing the FlatNodes of a particular method
37 private HashSet <FlatNode> flatNodesToVisit;
38 private Hashtable<FlatNode, OwnershipGraph> mapFlatNodeToOwnershipGraph;
39 private HashSet <FlatReturnNode> returnNodesToCombineForCompleteOwnershipGraph;
42 // this analysis generates an ownership graph for every task
44 public OwnershipAnalysis( State state,
46 int allocationDepth ) throws java.io.IOException {
48 this.callGraph = callGraph;
49 this.allocationDepth = allocationDepth;
51 descriptorsToVisit = new HashSet<Descriptor>();
53 mapDescriptorToCompleteOwnershipGraph =
54 new Hashtable<Descriptor, OwnershipGraph>();
56 mapFlatNewToAllocationSite =
57 new Hashtable<FlatNew, AllocationSite>();
59 mapDescriptorToAllocationSiteSet =
60 new Hashtable<Descriptor, HashSet<AllocationSite> >();
62 // use this set to prevent infinite recursion when
63 // traversing the call graph
64 HashSet<Descriptor> calleesScheduled = new HashSet<Descriptor>();
66 // initialize methods to visit as the set of all tasks in the
67 // program and then any method that could be called starting
69 Iterator taskItr = state.getTaskSymbolTable().getDescriptorsIterator();
70 while( taskItr.hasNext() ) {
71 Descriptor d = (Descriptor) taskItr.next();
72 descriptorsToVisit.add( d );
74 // recursively find all callees from this task
75 scheduleAllCallees( calleesScheduled, d );
78 // as mentioned above, analyze methods one-by-one, possibly revisiting
79 // a method if the methods that it calls are updated
83 // called from the constructor to help initialize the set
84 // of methods that needs to be analyzed by ownership analysis
85 private void scheduleAllCallees( HashSet<Descriptor> calleesScheduled,
87 if( calleesScheduled.contains( d ) ) {
90 calleesScheduled.add( d );
92 Set callees = callGraph.getCalleeSet( d );
93 if( callees == null ) {
97 Iterator methItr = callees.iterator();
98 while( methItr.hasNext() ) {
99 MethodDescriptor md = (MethodDescriptor) methItr.next();
100 descriptorsToVisit.add( md );
102 // recursively find all callees from this task
103 scheduleAllCallees( calleesScheduled, md );
108 // manage the set of tasks and methods to be analyzed
109 // and be sure to reschedule tasks/methods when the methods
110 // they call are updated
111 private void analyzeMethods() throws java.io.IOException {
113 while( !descriptorsToVisit.isEmpty() ) {
114 Descriptor d = (Descriptor) descriptorsToVisit.iterator().next();
115 descriptorsToVisit.remove( d );
117 // because the task or method descriptor just extracted
118 // was in the "to visit" set it either hasn't been analyzed
119 // yet, or some method that it depends on has been
120 // updated. Recompute a complete ownership graph for
121 // this task/method and compare it to any previous result.
122 // If there is a change detected, add any methods/tasks
123 // that depend on this one to the "to visit" set.
125 System.out.println( "Analyzing " + d );
128 if( d instanceof MethodDescriptor ) {
129 fm = state.getMethodFlat( (MethodDescriptor) d );
131 assert d instanceof TaskDescriptor;
132 fm = state.getMethodFlat( (TaskDescriptor) d );
135 OwnershipGraph og = analyzeFlatMethod( d, fm );
136 OwnershipGraph ogPrev = mapDescriptorToCompleteOwnershipGraph.get( d );
138 if( !og.equals( ogPrev ) ) {
139 mapDescriptorToCompleteOwnershipGraph.put( d, og );
143 // only methods have dependents, tasks cannot
144 // be invoked by any user program calls
145 if( d instanceof MethodDescriptor ) {
146 MethodDescriptor md = (MethodDescriptor) d;
147 Set dependents = callGraph.getCallerSet( md );
148 if( dependents != null ) {
149 descriptorsToVisit.addAll( dependents );
158 // keep passing the Descriptor of the method along for debugging
159 // and dot file writing
160 private OwnershipGraph
161 analyzeFlatMethod( Descriptor mDesc,
162 FlatMethod flatm ) throws java.io.IOException {
164 // initialize flat nodes to visit as the flat method
165 // because all other nodes in this flat method are
166 // decendents of the flat method itself
167 flatNodesToVisit = new HashSet<FlatNode>();
168 flatNodesToVisit.add( flatm );
170 // initilize the mapping of flat nodes in this flat method to
171 // ownership graph results to an empty mapping
172 mapFlatNodeToOwnershipGraph = new Hashtable<FlatNode, OwnershipGraph>();
174 // initialize the set of return nodes that will be combined as
175 // the final ownership graph result to return as an empty set
176 returnNodesToCombineForCompleteOwnershipGraph = new HashSet<FlatReturnNode>();
178 while( !flatNodesToVisit.isEmpty() ) {
179 FlatNode fn = (FlatNode) flatNodesToVisit.iterator().next();
180 flatNodesToVisit.remove( fn );
182 // perform this node's contributions to the ownership
183 // graph on a new copy, then compare it to the old graph
184 // at this node to see if anything was updated.
185 OwnershipGraph og = new OwnershipGraph( allocationDepth );
187 // start by merging all node's parents' graphs
188 for( int i = 0; i < fn.numPrev(); ++i ) {
189 FlatNode pn = fn.getPrev( i );
190 OwnershipGraph ogParent = getGraphFromFlatNode( pn );
191 og.merge( ogParent );
194 // apply the analysis of the flat node to the
195 // ownership graph made from the merge of the
197 analyzeFlatNode( mDesc,
199 returnNodesToCombineForCompleteOwnershipGraph,
202 // if the results of the new graph are different from
203 // the current graph at this node, replace the graph
204 // with the update and enqueue the children for
206 OwnershipGraph ogPrev = getGraphFromFlatNode( fn );
208 if( !og.equals( ogPrev ) ) {
209 setGraphForFlatNode( fn, og );
211 for( int i = 0; i < fn.numNext(); i++ ) {
212 FlatNode nn = fn.getNext( i );
213 flatNodesToVisit.add( nn );
218 // end by merging all return nodes into a complete
219 // ownership graph that represents all possible heap
220 // states after the flat method returns
221 OwnershipGraph completeGraph = new OwnershipGraph( allocationDepth );
222 Iterator retItr = returnNodesToCombineForCompleteOwnershipGraph.iterator();
223 while( retItr.hasNext() ) {
224 FlatReturnNode frn = (FlatReturnNode) retItr.next();
225 OwnershipGraph ogr = getGraphFromFlatNode( frn );
226 completeGraph.merge( ogr );
228 return completeGraph;
233 analyzeFlatNode( Descriptor methodDesc,
235 HashSet<FlatReturnNode> setRetNodes,
236 OwnershipGraph og ) throws java.io.IOException {
242 // use node type to decide what alterations to make
243 // to the ownership graph
244 switch( fn.kind() ) {
246 case FKind.FlatMethod:
247 FlatMethod fm = (FlatMethod) fn;
249 // there should only be one FlatMethod node as the
250 // parent of all other FlatNode objects, so take
251 // the opportunity to construct the initial graph by
252 // adding parameters labels to new heap regions
253 for( int i = 0; i < fm.numParameters(); ++i ) {
254 TempDescriptor tdParam = fm.getParameter( i );
255 og.assignTempToParameterAllocation( methodDesc instanceof TaskDescriptor,
258 //og.writeGraph( methodDesc, fn );
263 case FKind.FlatOpNode:
264 FlatOpNode fon = (FlatOpNode) fn;
265 if( fon.getOp().getOp() == Operation.ASSIGN ) {
268 og.assignTempToTemp( src, dst );
269 //og.writeGraph( methodDesc, fn );
273 case FKind.FlatFieldNode:
274 FlatFieldNode ffn = (FlatFieldNode) fn;
277 fld = ffn.getField();
278 if( !fld.getType().isPrimitive() ) {
279 og.assignTempToField( src, dst, fld );
280 //og.writeGraph( methodDesc, fn );
284 case FKind.FlatSetFieldNode:
285 FlatSetFieldNode fsfn = (FlatSetFieldNode) fn;
288 fld = fsfn.getField();
289 og.assignFieldToTemp( src, dst, fld );
290 //og.writeGraph( methodDesc, fn );
294 FlatNew fnn = (FlatNew) fn;
296 AllocationSite as = getAllocationSiteFromFlatNew( fnn );
298 og.assignTempToNewAllocation( dst, as );
302 FlatCall fc = (FlatCall) fn;
303 MethodDescriptor md = fc.getMethod();
304 FlatMethod flatm = state.getMethodFlat( md );
305 HashSet<AllocationSite> allocSiteSet = getAllocationSiteSet( md );
306 OwnershipGraph ogAllPossibleCallees = new OwnershipGraph( allocationDepth );
308 if( md.isStatic() ) {
309 // a static method is simply always the same, makes life easy
310 OwnershipGraph onlyPossibleCallee = mapDescriptorToCompleteOwnershipGraph.get( md );
311 ogAllPossibleCallees.merge( onlyPossibleCallee );
314 // if the method descriptor is virtual, then there could be a
315 // set of possible methods that will actually be invoked, so
316 // find all of them and merge all of their graphs together
317 TypeDescriptor typeDesc = fc.getThis().getType();
318 Set possibleCallees = callGraph.getMethods( md, typeDesc );
320 Iterator i = possibleCallees.iterator();
321 while( i.hasNext() ) {
322 MethodDescriptor possibleMd = (MethodDescriptor) i.next();
323 allocSiteSet.addAll( getAllocationSiteSet( possibleMd ) );
324 OwnershipGraph ogPotentialCallee = mapDescriptorToCompleteOwnershipGraph.get( possibleMd );
325 ogAllPossibleCallees.merge( ogPotentialCallee );
329 // now we should have the following information to resolve this method call:
331 // 1. A FlatCall fc to query for the caller's context (argument labels, etc)
333 // 2. Whether the method is static; if not we need to deal with the "this" pointer
335 // *******************************************************************************************
336 // 3. The original FlatMethod flatm to query for callee's context (paramter labels)
337 // NOTE! I assume FlatMethod before virtual dispatch accurately describes all possible methods!
338 // *******************************************************************************************
340 // 4. The OwnershipGraph ogAllPossibleCallees is a merge of every ownership graph of all the possible
341 // methods to capture any possible references made.
343 // 5. The Set of AllocationSite objects, allocSiteSet that is the set of allocation sites from
344 // every possible method we might have chosen
346 og.resolveMethodCall( fc, md.isStatic(), flatm, ogAllPossibleCallees, allocSiteSet );
348 //og.writeGraph( methodDesc, fn );
351 case FKind.FlatReturnNode:
352 FlatReturnNode frn = (FlatReturnNode) fn;
353 setRetNodes.add( frn );
354 //og.writeGraph( methodDesc, fn );
360 static public Integer generateUniqueHeapRegionNodeID() {
362 return new Integer( uniqueIDcount );
366 private OwnershipGraph getGraphFromFlatNode( FlatNode fn ) {
367 if( !mapFlatNodeToOwnershipGraph.containsKey( fn ) ) {
368 mapFlatNodeToOwnershipGraph.put( fn, new OwnershipGraph( allocationDepth ) );
371 return mapFlatNodeToOwnershipGraph.get( fn );
374 private void setGraphForFlatNode( FlatNode fn, OwnershipGraph og ) {
375 mapFlatNodeToOwnershipGraph.put( fn, og );
379 // return just the allocation site associated with one FlatNew node
380 private AllocationSite getAllocationSiteFromFlatNew( FlatNew fn ) {
381 if( !mapFlatNewToAllocationSite.containsKey( fn ) ) {
382 AllocationSite as = new AllocationSite( allocationDepth );
384 // the newest nodes are single objects
385 for( int i = 0; i < allocationDepth; ++i ) {
386 Integer id = generateUniqueHeapRegionNodeID();
387 as.setIthOldest( i, id );
390 // the oldest node is a summary node
391 Integer idSummary = generateUniqueHeapRegionNodeID();
392 as.setSummary( idSummary );
394 mapFlatNewToAllocationSite.put( fn, as );
397 return mapFlatNewToAllocationSite.get( fn );
401 // return all allocation sites in the method (there is one allocation
402 // site per FlatNew node in a method)
403 private HashSet<AllocationSite> getAllocationSiteSet( Descriptor d ) {
404 if( !mapDescriptorToAllocationSiteSet.containsKey( d ) ) {
405 buildAllocationSiteSet( d );
408 return mapDescriptorToAllocationSiteSet.get( d );
412 private void buildAllocationSiteSet( Descriptor d ) {
413 HashSet<AllocationSite> s = new HashSet<AllocationSite>();
416 if( d instanceof MethodDescriptor ) {
417 fm = state.getMethodFlat( (MethodDescriptor) d );
419 assert d instanceof TaskDescriptor;
420 fm = state.getMethodFlat( (TaskDescriptor) d );
423 // visit every node in this FlatMethod's IR graph
424 // and make a set of the allocation sites from the
425 // FlatNew node's visited
426 HashSet<FlatNode> visited = new HashSet<FlatNode>();
427 HashSet<FlatNode> toVisit = new HashSet<FlatNode>();
430 while( !toVisit.isEmpty() ) {
431 FlatNode n = toVisit.iterator().next();
433 if( n instanceof FlatNew ) {
434 s.add( getAllocationSiteFromFlatNew( (FlatNew) n ) );
440 for( int i = 0; i < n.numNext(); ++i ) {
441 FlatNode child = n.getNext( i );
442 if( !visited.contains( child ) ) {
443 toVisit.add( child );
448 mapDescriptorToAllocationSiteSet.put( d, s );