1 package Analysis.OwnershipAnalysis;
3 import Analysis.CallGraph.*;
4 import Analysis.Liveness;
5 import Analysis.ArrayReferencees;
8 import IR.Tree.Modifiers;
13 public class OwnershipAnalysis {
16 ///////////////////////////////////////////
18 // Public interface to discover possible
19 // aliases in the program under analysis
21 ///////////////////////////////////////////
23 public HashSet<AllocationSite>
24 getFlaggedAllocationSitesReachableFromTask(TaskDescriptor td) {
25 checkAnalysisComplete();
26 return getFlaggedAllocationSitesReachableFromTaskPRIVATE(td);
29 public AllocationSite getAllocationSiteFromFlatNew(FlatNew fn) {
30 checkAnalysisComplete();
31 return getAllocationSiteFromFlatNewPRIVATE(fn);
34 public AllocationSite getAllocationSiteFromHeapRegionNodeID(Integer id) {
35 checkAnalysisComplete();
36 return mapHrnIdToAllocationSite.get(id);
39 public Set<HeapRegionNode> createsPotentialAliases(Descriptor taskOrMethod,
42 checkAnalysisComplete();
43 OwnershipGraph og = getGraphOfAllContextsFromDescriptor(taskOrMethod);
45 return og.hasPotentialAlias(paramIndex1, paramIndex2);
48 public Set<HeapRegionNode> createsPotentialAliases(Descriptor taskOrMethod,
50 AllocationSite alloc) {
51 checkAnalysisComplete();
52 OwnershipGraph og = getGraphOfAllContextsFromDescriptor(taskOrMethod);
54 return og.hasPotentialAlias(paramIndex, alloc);
57 public Set<HeapRegionNode> createsPotentialAliases(Descriptor taskOrMethod,
60 checkAnalysisComplete();
61 OwnershipGraph og = getGraphOfAllContextsFromDescriptor(taskOrMethod);
63 return og.hasPotentialAlias(paramIndex, alloc);
66 public Set<HeapRegionNode> createsPotentialAliases(Descriptor taskOrMethod,
67 AllocationSite alloc1,
68 AllocationSite alloc2) {
69 checkAnalysisComplete();
70 OwnershipGraph og = getGraphOfAllContextsFromDescriptor(taskOrMethod);
72 return og.hasPotentialAlias(alloc1, alloc2);
76 protected OwnershipGraph getGraphOfAllContextsFromDescriptor(Descriptor d) {
77 checkAnalysisComplete();
81 OwnershipGraph og = new OwnershipGraph();
83 assert mapDescriptorToAllMethodContexts.containsKey( d );
84 HashSet<MethodContext> contexts = mapDescriptorToAllMethodContexts.get( d );
85 Iterator<MethodContext> mcItr = contexts.iterator();
86 while( mcItr.hasNext() ) {
87 MethodContext mc = mcItr.next();
89 OwnershipGraph ogContext = mapMethodContextToCompleteOwnershipGraph.get(mc);
90 assert ogContext != null;
92 og.merge( ogContext );
99 public String prettyPrintNodeSet( Set<HeapRegionNode> s ) {
100 checkAnalysisComplete();
104 Iterator<HeapRegionNode> i = s.iterator();
105 while( i.hasNext() ) {
106 HeapRegionNode n = i.next();
108 AllocationSite as = n.getAllocationSite();
110 out += " "+n.toString()+",\n";
112 out += " "+n.toString()+": "+as.toStringVerbose()+",\n";
121 // use the methods given above to check every possible alias
122 // between task parameters and flagged allocation sites reachable
124 public void writeAllAliases(String outputFile,
127 boolean tabularOutput,
129 ) throws java.io.IOException {
130 checkAnalysisComplete();
132 BufferedWriter bw = new BufferedWriter(new FileWriter(outputFile) );
134 if( !tabularOutput ) {
135 bw.write("Conducting ownership analysis with allocation depth = "+allocationDepth+"\n");
136 bw.write(timeReport+"\n");
141 // look through every task for potential aliases
142 Iterator taskItr = state.getTaskSymbolTable().getDescriptorsIterator();
143 while( taskItr.hasNext() ) {
144 TaskDescriptor td = (TaskDescriptor) taskItr.next();
146 if( !tabularOutput ) {
147 bw.write("\n---------"+td+"--------\n");
150 HashSet<AllocationSite> allocSites = getFlaggedAllocationSitesReachableFromTask(td);
152 Set<HeapRegionNode> common;
154 // for each task parameter, check for aliases with
155 // other task parameters and every allocation site
156 // reachable from this task
157 boolean foundSomeAlias = false;
159 FlatMethod fm = state.getMethodFlat(td);
160 for( int i = 0; i < fm.numParameters(); ++i ) {
162 // for the ith parameter check for aliases to all
163 // higher numbered parameters
164 for( int j = i + 1; j < fm.numParameters(); ++j ) {
165 common = createsPotentialAliases(td, i, j);
166 if( !common.isEmpty() ) {
167 foundSomeAlias = true;
168 if( !tabularOutput ) {
169 bw.write("Potential alias between parameters "+i+" and "+j+".\n");
170 bw.write(prettyPrintNodeSet( common )+"\n" );
177 // for the ith parameter, check for aliases against
178 // the set of allocation sites reachable from this
180 Iterator allocItr = allocSites.iterator();
181 while( allocItr.hasNext() ) {
182 AllocationSite as = (AllocationSite) allocItr.next();
183 common = createsPotentialAliases(td, i, as);
184 if( !common.isEmpty() ) {
185 foundSomeAlias = true;
186 if( !tabularOutput ) {
187 bw.write("Potential alias between parameter "+i+" and "+as.getFlatNew()+".\n");
188 bw.write(prettyPrintNodeSet( common )+"\n" );
196 // for each allocation site check for aliases with
197 // other allocation sites in the context of execution
199 HashSet<AllocationSite> outerChecked = new HashSet<AllocationSite>();
200 Iterator allocItr1 = allocSites.iterator();
201 while( allocItr1.hasNext() ) {
202 AllocationSite as1 = (AllocationSite) allocItr1.next();
204 Iterator allocItr2 = allocSites.iterator();
205 while( allocItr2.hasNext() ) {
206 AllocationSite as2 = (AllocationSite) allocItr2.next();
208 if( !outerChecked.contains(as2) ) {
209 common = createsPotentialAliases(td, as1, as2);
211 if( !common.isEmpty() ) {
212 foundSomeAlias = true;
213 if( !tabularOutput ) {
214 bw.write("Potential alias between "+as1.getFlatNew()+" and "+as2.getFlatNew()+".\n");
215 bw.write(prettyPrintNodeSet( common )+"\n" );
223 outerChecked.add(as1);
226 if( !foundSomeAlias ) {
227 if( !tabularOutput ) {
228 bw.write("No aliases between flagged objects in Task "+td+".\n");
233 if( !tabularOutput ) {
234 bw.write( "\n"+computeAliasContextHistogram() );
236 bw.write( " & "+numAlias+
239 " & "+numMethodsAnalyzed()+
247 // this version of writeAllAliases is for Java programs that have no tasks
248 public void writeAllAliasesJava(String outputFile,
251 boolean tabularOutput,
253 ) throws java.io.IOException {
254 checkAnalysisComplete();
258 BufferedWriter bw = new BufferedWriter(new FileWriter(outputFile) );
260 bw.write("Conducting ownership analysis with allocation depth = "+allocationDepth+"\n");
261 bw.write(timeReport+"\n\n");
263 boolean foundSomeAlias = false;
265 Descriptor d = typeUtil.getMain();
266 HashSet<AllocationSite> allocSites = getFlaggedAllocationSites(d);
268 // for each allocation site check for aliases with
269 // other allocation sites in the context of execution
271 HashSet<AllocationSite> outerChecked = new HashSet<AllocationSite>();
272 Iterator allocItr1 = allocSites.iterator();
273 while( allocItr1.hasNext() ) {
274 AllocationSite as1 = (AllocationSite) allocItr1.next();
276 Iterator allocItr2 = allocSites.iterator();
277 while( allocItr2.hasNext() ) {
278 AllocationSite as2 = (AllocationSite) allocItr2.next();
280 if( !outerChecked.contains(as2) ) {
281 Set<HeapRegionNode> common = createsPotentialAliases(d, as1, as2);
283 if( !common.isEmpty() ) {
284 foundSomeAlias = true;
285 bw.write("Potential alias between "+as1.getDisjointId()+" and "+as2.getDisjointId()+".\n");
286 bw.write( prettyPrintNodeSet( common )+"\n" );
291 outerChecked.add(as1);
294 if( !foundSomeAlias ) {
295 bw.write("No aliases between flagged objects found.\n");
298 bw.write( "\n"+computeAliasContextHistogram() );
301 ///////////////////////////////////////////
303 // end public interface
305 ///////////////////////////////////////////
307 protected void checkAnalysisComplete() {
308 if( !analysisComplete ) {
309 throw new Error("Warning: public interface method called while analysis is running.");
317 // data from the compiler
319 public CallGraph callGraph;
320 public Liveness liveness;
321 public ArrayReferencees arrayReferencees;
322 public TypeUtil typeUtil;
323 public int allocationDepth;
325 // for public interface methods to warn that they
326 // are grabbing results during analysis
327 private boolean analysisComplete;
329 // used to identify HeapRegionNode objects
330 // A unique ID equates an object in one
331 // ownership graph with an object in another
332 // graph that logically represents the same
334 // start at 10 and increment to leave some
335 // reserved IDs for special purposes
336 static private int uniqueIDcount = 10;
338 // Use these data structures to track progress of
339 // processing all methods in the program, and by methods
340 // TaskDescriptor and MethodDescriptor are combined
341 // together, with a common parent class Descriptor
342 private Hashtable<MethodContext, OwnershipGraph> mapMethodContextToInitialParamAllocGraph;
343 private Hashtable<MethodContext, OwnershipGraph> mapMethodContextToCompleteOwnershipGraph;
344 private Hashtable<FlatNew, AllocationSite> mapFlatNewToAllocationSite;
345 private Hashtable<Descriptor, HashSet<AllocationSite> > mapDescriptorToAllocationSiteSet;
346 private Hashtable<MethodContext, Integer> mapMethodContextToNumUpdates;
347 private Hashtable<Descriptor, HashSet<MethodContext> > mapDescriptorToAllMethodContexts;
348 private Hashtable<MethodContext, HashSet<MethodContext> > mapMethodContextToDependentContexts;
349 private Hashtable<Integer, AllocationSite> mapHrnIdToAllocationSite;
351 // Use these data structures to track progress of one pass of
352 // processing the FlatNodes of a particular method
353 private HashSet <FlatNode> flatNodesToVisit;
354 private Hashtable<FlatNode, OwnershipGraph> mapFlatNodeToOwnershipGraph;
355 private HashSet <FlatReturnNode> returnNodesToCombineForCompleteOwnershipGraph;
357 // descriptorsToAnalyze identifies the set of tasks and methods
358 // that are reachable from the program tasks, this set is initialized
359 // and then remains static
360 public HashSet<Descriptor> descriptorsToAnalyze;
362 // descriptorsToVisit is initialized to descriptorsToAnalyze and is
363 // reduced by visiting a descriptor during analysis. When dependents
364 // must be scheduled, only those contained in descriptorsToAnalyze
365 // should be re-added to this queue
366 private PriorityQueue<MethodContextQWrapper> methodContextsToVisitQ;
367 private Set <MethodContext> methodContextsToVisitSet;
368 private Hashtable<Descriptor, Integer> mapDescriptorToPriority;
371 // special field descriptors for array elements
372 public static final String arrayElementFieldName = "___element_";
373 private static Hashtable<TypeDescriptor, FieldDescriptor> mapTypeToArrayField =
374 new Hashtable<TypeDescriptor, FieldDescriptor>();
377 // for controlling DOT file output
378 private boolean writeDOTs;
379 private boolean writeAllDOTs;
381 // for controlling method effects
382 private boolean methodEffects;
384 //map each FlatNode to its own internal ownership graph
385 private MethodEffectsAnalysis meAnalysis;
387 //keep internal ownership graph by method context and flat node
388 private Hashtable<MethodContext, Hashtable<FlatNode, OwnershipGraph>> mapMethodContextToFlatNodeOwnershipGraph;
390 //map method context to a set of allocation sites of live-in vars
391 private Hashtable<MethodContext, HashSet<AllocationSite>> mapMethodContextToLiveInAllocationSiteSet;
395 // this analysis generates an ownership graph for every task
397 public OwnershipAnalysis(State state,
404 boolean writeAllDOTs,
405 String aliasFile) throws java.io.IOException {
407 this.methodEffects = false;
408 init(state,tu,callGraph,liveness,ar,allocationDepth,writeDOTs,writeAllDOTs,aliasFile);
412 public OwnershipAnalysis(State state,
419 boolean writeAllDOTs,
421 boolean methodEffects) throws java.io.IOException {
423 this.methodEffects = methodEffects;
424 init(state,tu,callGraph,liveness,ar,allocationDepth,writeDOTs,writeAllDOTs,aliasFile);
428 // new constructor for on-demand disjoint analysis
429 public OwnershipAnalysis(
437 boolean writeAllDOTs,
439 boolean methodEffects,
440 Hashtable<MethodContext, HashSet<AllocationSite>> mapMethodContextToLiveInAllocationSiteSet)
441 throws java.io.IOException {
443 this.methodEffects = methodEffects;
444 this.mapMethodContextToLiveInAllocationSiteSet=mapMethodContextToLiveInAllocationSiteSet;
445 init(state, tu, callGraph, liveness, ar, allocationDepth, writeDOTs, writeAllDOTs,
450 private void init(State state,
457 boolean writeAllDOTs,
458 String aliasFile) throws java.io.IOException {
460 analysisComplete = false;
464 this.callGraph = callGraph;
465 this.liveness = liveness;
466 this.arrayReferencees = ar;
467 this.allocationDepth = allocationDepth;
468 this.writeDOTs = writeDOTs;
469 this.writeAllDOTs = writeAllDOTs;
471 // set some static configuration for OwnershipGraphs
472 OwnershipGraph.allocationDepth = allocationDepth;
473 OwnershipGraph.typeUtil = typeUtil;
474 OwnershipGraph.debugCallMapCount = state.OWNERSHIPDEBUGCALLCOUNT;
475 OwnershipGraph.debugCallee = state.OWNERSHIPDEBUGCALLEE;
476 OwnershipGraph.debugCaller = state.OWNERSHIPDEBUGCALLER;
477 if( OwnershipGraph.debugCallee != null &&
478 OwnershipGraph.debugCaller != null ) {
479 OwnershipGraph.debugCallMap = true;
482 descriptorsToAnalyze = new HashSet<Descriptor>();
484 mapMethodContextToInitialParamAllocGraph =
485 new Hashtable<MethodContext, OwnershipGraph>();
487 mapMethodContextToCompleteOwnershipGraph =
488 new Hashtable<MethodContext, OwnershipGraph>();
490 mapFlatNewToAllocationSite =
491 new Hashtable<FlatNew, AllocationSite>();
493 mapDescriptorToAllocationSiteSet =
494 new Hashtable<Descriptor, HashSet<AllocationSite> >();
496 mapDescriptorToAllMethodContexts =
497 new Hashtable<Descriptor, HashSet<MethodContext> >();
499 mapMethodContextToDependentContexts =
500 new Hashtable<MethodContext, HashSet<MethodContext> >();
502 mapDescriptorToPriority =
503 new Hashtable<Descriptor, Integer>();
505 mapHrnIdToAllocationSite =
506 new Hashtable<Integer, AllocationSite>();
508 if( methodEffects ) {
509 mapMethodContextToFlatNodeOwnershipGraph=new Hashtable<MethodContext, Hashtable<FlatNode, OwnershipGraph>>();
512 meAnalysis=new MethodEffectsAnalysis(methodEffects);
516 mapMethodContextToNumUpdates = new Hashtable<MethodContext, Integer>();
520 double timeStartAnalysis = (double) System.nanoTime();
524 // initialize methods to visit as the set of all tasks in the
525 // program and then any method that could be called starting
527 Iterator taskItr = state.getTaskSymbolTable().getDescriptorsIterator();
528 while( taskItr.hasNext() ) {
529 Descriptor d = (Descriptor) taskItr.next();
530 scheduleAllCallees(d);
534 // we are not in task mode, just normal Java, so start with
536 Descriptor d = typeUtil.getMain();
537 scheduleAllCallees(d);
541 // before beginning analysis, initialize every scheduled method
542 // with an ownership graph that has populated parameter index tables
543 // by analyzing the first node which is always a FlatMethod node
544 Iterator<Descriptor> dItr = descriptorsToAnalyze.iterator();
545 while( dItr.hasNext() ) {
546 Descriptor d = dItr.next();
547 OwnershipGraph og = new OwnershipGraph();
550 if( d instanceof MethodDescriptor ) {
551 fm = state.getMethodFlat( (MethodDescriptor) d);
553 assert d instanceof TaskDescriptor;
554 fm = state.getMethodFlat( (TaskDescriptor) d);
557 MethodContext mc = new MethodContext( d );
558 assert !mapDescriptorToAllMethodContexts.containsKey( d );
559 HashSet<MethodContext> s = new HashSet<MethodContext>();
561 mapDescriptorToAllMethodContexts.put( d, s );
563 //System.out.println("Previsiting " + mc);
565 meAnalysis.createNewMapping(mc);
567 og = analyzeFlatNode(mc, fm, fm, null, og);
568 setGraphForMethodContext(mc, og);
571 // as mentioned above, analyze methods one-by-one, possibly revisiting
572 // a method if the methods that it calls are updated
574 analysisComplete = true;
577 double timeEndAnalysis = (double) System.nanoTime();
578 double dt = (timeEndAnalysis - timeStartAnalysis)/(Math.pow( 10.0, 9.0 ) );
579 String treport = String.format( "The reachability analysis took %.3f sec.", dt );
580 String justtime = String.format( "%.2f", dt );
581 System.out.println( treport );
583 if( writeDOTs && !writeAllDOTs ) {
584 writeFinalContextGraphs();
588 meAnalysis.writeMethodEffectsResult();
591 if( aliasFile != null ) {
593 writeAllAliases(aliasFile, treport, justtime, state.OWNERSHIPALIASTAB, state.lines);
595 writeAllAliasesJava(aliasFile, treport, justtime, state.OWNERSHIPALIASTAB, state.lines);
601 // called from the constructor to help initialize the set
602 // of methods that needs to be analyzed by ownership analysis
603 private void scheduleAllCallees(Descriptor d) {
604 if( descriptorsToAnalyze.contains(d) ) {
607 descriptorsToAnalyze.add(d);
609 // start with all method calls to further schedule
610 Set moreMethodsToCheck = moreMethodsToCheck = callGraph.getMethodCalls(d);
612 if( d instanceof MethodDescriptor ) {
613 // see if this method has virtual dispatch
614 Set virtualMethods = callGraph.getMethods( (MethodDescriptor)d);
615 moreMethodsToCheck.addAll(virtualMethods);
618 // keep following any further methods identified in
620 Iterator methItr = moreMethodsToCheck.iterator();
621 while( methItr.hasNext() ) {
622 Descriptor m = (Descriptor) methItr.next();
623 scheduleAllCallees(m);
628 // manage the set of tasks and methods to be analyzed
629 // and be sure to reschedule tasks/methods when the methods
630 // they call are updated
631 private void analyzeMethods() throws java.io.IOException {
633 // first gather all of the method contexts to analyze
634 HashSet<MethodContext> allContexts = new HashSet<MethodContext>();
635 Iterator<Descriptor> itrd2a = descriptorsToAnalyze.iterator();
636 while( itrd2a.hasNext() ) {
637 HashSet<MethodContext> mcs = mapDescriptorToAllMethodContexts.get( itrd2a.next() );
640 Iterator<MethodContext> itrmc = mcs.iterator();
641 while( itrmc.hasNext() ) {
642 allContexts.add( itrmc.next() );
646 // topologically sort them according to the caller graph so leaf calls are
647 // ordered first; use that ordering to give method contexts priorities
648 LinkedList<MethodContext> sortedMethodContexts = topologicalSort( allContexts );
650 methodContextsToVisitQ = new PriorityQueue<MethodContextQWrapper>();
651 methodContextsToVisitSet = new HashSet<MethodContext>();
654 Iterator<MethodContext> mcItr = sortedMethodContexts.iterator();
655 while( mcItr.hasNext() ) {
656 MethodContext mc = mcItr.next();
657 mapDescriptorToPriority.put( mc.getDescriptor(), new Integer( p ) );
658 methodContextsToVisitQ.add( new MethodContextQWrapper( p, mc ) );
659 methodContextsToVisitSet.add( mc );
663 // analyze methods from the priority queue until it is empty
664 while( !methodContextsToVisitQ.isEmpty() ) {
665 MethodContext mc = methodContextsToVisitQ.poll().getMethodContext();
666 assert methodContextsToVisitSet.contains( mc );
667 methodContextsToVisitSet.remove( mc );
669 // because the task or method descriptor just extracted
670 // was in the "to visit" set it either hasn't been analyzed
671 // yet, or some method that it depends on has been
672 // updated. Recompute a complete ownership graph for
673 // this task/method and compare it to any previous result.
674 // If there is a change detected, add any methods/tasks
675 // that depend on this one to the "to visit" set.
677 System.out.println("Analyzing " + mc);
679 Descriptor d = mc.getDescriptor();
681 if( d instanceof MethodDescriptor ) {
682 fm = state.getMethodFlat( (MethodDescriptor) d);
684 assert d instanceof TaskDescriptor;
685 fm = state.getMethodFlat( (TaskDescriptor) d);
688 OwnershipGraph og = analyzeFlatMethod(mc, fm);
689 OwnershipGraph ogPrev = mapMethodContextToCompleteOwnershipGraph.get(mc);
690 if( !og.equals(ogPrev) ) {
691 setGraphForMethodContext(mc, og);
693 Iterator<MethodContext> depsItr = iteratorDependents( mc );
694 while( depsItr.hasNext() ) {
695 MethodContext mcNext = depsItr.next();
697 if( !methodContextsToVisitSet.contains( mcNext ) ) {
698 methodContextsToVisitQ.add( new MethodContextQWrapper( mapDescriptorToPriority.get( mcNext.getDescriptor() ),
700 methodContextsToVisitSet.add( mcNext );
709 // keep passing the Descriptor of the method along for debugging
710 // and dot file writing
711 private OwnershipGraph
712 analyzeFlatMethod(MethodContext mc,
713 FlatMethod flatm) throws java.io.IOException {
715 // initialize flat nodes to visit as the flat method
716 // because it is the entry point
718 flatNodesToVisit = new HashSet<FlatNode>();
719 flatNodesToVisit.add(flatm);
721 // initilize the mapping of flat nodes in this flat method to
722 // ownership graph results to an empty mapping
723 mapFlatNodeToOwnershipGraph = new Hashtable<FlatNode, OwnershipGraph>();
725 // initialize the set of return nodes that will be combined as
726 // the final ownership graph result to return as an empty set
727 returnNodesToCombineForCompleteOwnershipGraph = new HashSet<FlatReturnNode>();
730 while( !flatNodesToVisit.isEmpty() ) {
731 FlatNode fn = (FlatNode) flatNodesToVisit.iterator().next();
732 flatNodesToVisit.remove(fn);
734 //System.out.println( " "+fn );
736 // perform this node's contributions to the ownership
737 // graph on a new copy, then compare it to the old graph
738 // at this node to see if anything was updated.
739 OwnershipGraph og = new OwnershipGraph();
741 // start by merging all node's parents' graphs
742 for( int i = 0; i < fn.numPrev(); ++i ) {
743 FlatNode pn = fn.getPrev(i);
744 if( mapFlatNodeToOwnershipGraph.containsKey(pn) ) {
745 OwnershipGraph ogParent = mapFlatNodeToOwnershipGraph.get(pn);
750 // apply the analysis of the flat node to the
751 // ownership graph made from the merge of the
753 og = analyzeFlatNode(mc,
756 returnNodesToCombineForCompleteOwnershipGraph,
762 if( takeDebugSnapshots &&
763 mc.getDescriptor().getSymbol().equals( mcDescSymbolDebug ) ) {
764 debugSnapshot(og,fn);
768 // if the results of the new graph are different from
769 // the current graph at this node, replace the graph
770 // with the update and enqueue the children for
772 OwnershipGraph ogPrev = mapFlatNodeToOwnershipGraph.get(fn);
773 if( !og.equals(ogPrev) ) {
774 mapFlatNodeToOwnershipGraph.put(fn, og);
776 for( int i = 0; i < fn.numNext(); i++ ) {
777 FlatNode nn = fn.getNext(i);
778 flatNodesToVisit.add(nn);
783 // end by merging all return nodes into a complete
784 // ownership graph that represents all possible heap
785 // states after the flat method returns
786 OwnershipGraph completeGraph = new OwnershipGraph();
787 Iterator retItr = returnNodesToCombineForCompleteOwnershipGraph.iterator();
788 while( retItr.hasNext() ) {
789 FlatReturnNode frn = (FlatReturnNode) retItr.next();
790 assert mapFlatNodeToOwnershipGraph.containsKey(frn);
791 OwnershipGraph ogr = mapFlatNodeToOwnershipGraph.get(frn);
792 completeGraph.merge(ogr);
795 return completeGraph;
799 private OwnershipGraph
800 analyzeFlatNode(MethodContext mc,
801 FlatMethod fmContaining,
803 HashSet<FlatReturnNode> setRetNodes,
804 OwnershipGraph og) throws java.io.IOException {
807 // any variables that are no longer live should be
808 // nullified in the graph to reduce edges
809 // NOTE: it is not clear we need this. It costs a
810 // liveness calculation for every method, so only
811 // turn it on if we find we actually need it.
812 //og.nullifyDeadVars( liveness.getLiveInTemps( fmContaining, fn ) );
819 // use node type to decide what alterations to make
820 // to the ownership graph
821 switch( fn.kind() ) {
823 case FKind.FlatMethod:
824 FlatMethod fm = (FlatMethod) fn;
826 // there should only be one FlatMethod node as the
827 // parent of all other FlatNode objects, so take
828 // the opportunity to construct the initial graph by
829 // adding parameters labels to new heap regions
830 // AND this should be done once globally so that the
831 // parameter IDs are consistent between analysis
832 // iterations, so if this step has been done already
833 // just merge in the cached version
834 OwnershipGraph ogInitParamAlloc = mapMethodContextToInitialParamAllocGraph.get(mc);
835 if( ogInitParamAlloc == null ) {
837 // if the method context has aliased parameters, make sure
838 // there is a blob region for all those param to reference
839 Set<Integer> aliasedParamIndices = mc.getAliasedParamIndices();
841 if( !aliasedParamIndices.isEmpty() ) {
842 og.makeAliasedParamHeapRegionNode(fm);
845 // set up each parameter
846 for( int i = 0; i < fm.numParameters(); ++i ) {
847 TempDescriptor tdParam = fm.getParameter( i );
848 TypeDescriptor typeParam = tdParam.getType();
849 Integer paramIndex = new Integer( i );
851 if( typeParam.isImmutable() && !typeParam.isArray() ) {
852 // don't bother with this primitive parameter, it
853 // cannot affect reachability
857 if( aliasedParamIndices.contains( paramIndex ) ) {
858 // use the alias blob but give parameters their
859 // own primary obj region
860 og.assignTempEqualToAliasedParam( tdParam,
863 // this parameter is not aliased to others, give it
864 // a fresh primary obj and secondary object
865 og.assignTempEqualToParamAlloc( tdParam,
866 mc.getDescriptor() instanceof TaskDescriptor,
871 // add additional edges for aliased regions if necessary
872 if( !aliasedParamIndices.isEmpty() ) {
873 og.addParam2ParamAliasEdges( fm, aliasedParamIndices );
876 // clean up reachability on initial parameter shapes
879 // this maps tokens to parameter indices and vice versa
880 // for when this method is a callee
881 og.prepareParamTokenMaps( fm );
884 OwnershipGraph ogResult = new OwnershipGraph();
886 mapMethodContextToInitialParamAllocGraph.put(mc, ogResult);
889 // or just leverage the cached copy
890 og.merge(ogInitParamAlloc);
894 case FKind.FlatOpNode:
895 FlatOpNode fon = (FlatOpNode) fn;
896 if( fon.getOp().getOp() == Operation.ASSIGN ) {
899 og.assignTempXEqualToTempY(lhs, rhs);
903 case FKind.FlatCastNode:
904 FlatCastNode fcn = (FlatCastNode) fn;
908 TypeDescriptor td = fcn.getType();
911 og.assignTempXEqualToCastedTempY(lhs, rhs, td);
914 case FKind.FlatFieldNode:
915 FlatFieldNode ffn = (FlatFieldNode) fn;
918 fld = ffn.getField();
919 if( !fld.getType().isImmutable() || fld.getType().isArray() ) {
920 og.assignTempXEqualToTempYFieldF(lhs, rhs, fld);
923 meAnalysis.analyzeFlatFieldNode(mc, og, rhs, fld);
927 case FKind.FlatSetFieldNode:
928 FlatSetFieldNode fsfn = (FlatSetFieldNode) fn;
930 fld = fsfn.getField();
932 if( !fld.getType().isImmutable() || fld.getType().isArray() ) {
933 og.assignTempXFieldFEqualToTempY(lhs, fld, rhs);
936 meAnalysis.analyzeFlatSetFieldNode(mc, og, lhs, fld);
940 case FKind.FlatElementNode:
941 FlatElementNode fen = (FlatElementNode) fn;
945 if( !lhs.getType().isImmutable() || lhs.getType().isArray() ) {
947 assert rhs.getType() != null;
948 assert rhs.getType().isArray();
950 TypeDescriptor tdElement = rhs.getType().dereference();
951 FieldDescriptor fdElement = getArrayField( tdElement );
952 og.assignTempXEqualToTempYFieldF(lhs, rhs, fdElement);
953 meAnalysis.analyzeFlatElementNode(mc, og, lhs, fdElement);
958 case FKind.FlatSetElementNode:
959 FlatSetElementNode fsen = (FlatSetElementNode) fn;
963 if( !lhs.getType().isImmutable() || lhs.getType().isArray() ) {
964 TypeDescriptor tdElement = lhs.getType().dereference();
965 FieldDescriptor fdElement = getArrayField( tdElement );
966 meAnalysis.analyzeFlatSetElementNode(mc, og, lhs, fdElement);
969 if( arrayReferencees.doesNotCreateNewReaching( fsen ) ) {
970 // skip this node if it cannot create new reachability paths
976 if( !rhs.getType().isImmutable() || rhs.getType().isArray() ) {
978 assert lhs.getType() != null;
979 assert lhs.getType().isArray();
981 TypeDescriptor tdElement = lhs.getType().dereference();
982 FieldDescriptor fdElement = getArrayField( tdElement );
984 og.assignTempXFieldFEqualToTempY(lhs, fdElement, rhs);
985 meAnalysis.analyzeFlatSetElementNode(mc, og, lhs, fdElement);
991 FlatNew fnn = (FlatNew) fn;
993 if( !lhs.getType().isImmutable() || lhs.getType().isArray() ) {
994 AllocationSite as = getAllocationSiteFromFlatNewPRIVATE(fnn);
996 if (mapMethodContextToLiveInAllocationSiteSet != null){
997 HashSet<AllocationSite> alllocSet=mapMethodContextToLiveInAllocationSiteSet.get(mc);
999 for (Iterator iterator = alllocSet.iterator(); iterator
1001 AllocationSite allocationSite = (AllocationSite) iterator
1003 if(allocationSite.flatNew.equals(as.flatNew)){
1010 og.assignTempEqualToNewAlloc(lhs, as);
1014 case FKind.FlatCall:
1015 FlatCall fc = (FlatCall) fn;
1016 MethodDescriptor md = fc.getMethod();
1017 FlatMethod flatm = state.getMethodFlat(md);
1018 OwnershipGraph ogMergeOfAllPossibleCalleeResults = new OwnershipGraph();
1020 if( md.isStatic() ) {
1021 // a static method is simply always the same, makes life easy
1022 ogMergeOfAllPossibleCalleeResults = og;
1024 Set<Integer> aliasedParamIndices =
1025 ogMergeOfAllPossibleCalleeResults.calculateAliasedParamSet(fc, md.isStatic(), flatm);
1027 MethodContext mcNew = new MethodContext( md, aliasedParamIndices );
1028 Set contexts = mapDescriptorToAllMethodContexts.get( md );
1029 assert contexts != null;
1030 contexts.add( mcNew );
1032 addDependent( mc, mcNew );
1034 OwnershipGraph onlyPossibleCallee = mapMethodContextToCompleteOwnershipGraph.get( mcNew );
1036 if( onlyPossibleCallee == null ) {
1037 // if this method context has never been analyzed just schedule it for analysis
1038 // and skip over this call site for now
1039 if( !methodContextsToVisitSet.contains( mcNew ) ) {
1040 methodContextsToVisitQ.add( new MethodContextQWrapper( mapDescriptorToPriority.get( md ),
1042 methodContextsToVisitSet.add( mcNew );
1046 ogMergeOfAllPossibleCalleeResults.resolveMethodCall(fc, md.isStatic(), flatm, onlyPossibleCallee, mc, null);
1049 meAnalysis.createNewMapping(mcNew);
1050 meAnalysis.analyzeFlatCall(ogMergeOfAllPossibleCalleeResults, mcNew, mc, fc);
1054 // if the method descriptor is virtual, then there could be a
1055 // set of possible methods that will actually be invoked, so
1056 // find all of them and merge all of their results together
1057 TypeDescriptor typeDesc = fc.getThis().getType();
1058 Set possibleCallees = callGraph.getMethods(md, typeDesc);
1060 Iterator i = possibleCallees.iterator();
1061 while( i.hasNext() ) {
1062 MethodDescriptor possibleMd = (MethodDescriptor) i.next();
1063 FlatMethod pflatm = state.getMethodFlat(possibleMd);
1065 // don't alter the working graph (og) until we compute a result for every
1066 // possible callee, merge them all together, then set og to that
1067 OwnershipGraph ogCopy = new OwnershipGraph();
1070 Set<Integer> aliasedParamIndices =
1071 ogCopy.calculateAliasedParamSet(fc, possibleMd.isStatic(), pflatm);
1073 MethodContext mcNew = new MethodContext( possibleMd, aliasedParamIndices );
1074 Set contexts = mapDescriptorToAllMethodContexts.get( md );
1075 assert contexts != null;
1076 contexts.add( mcNew );
1079 meAnalysis.createNewMapping(mcNew);
1082 addDependent( mc, mcNew );
1084 OwnershipGraph ogPotentialCallee = mapMethodContextToCompleteOwnershipGraph.get( mcNew );
1086 if( ogPotentialCallee == null ) {
1087 // if this method context has never been analyzed just schedule it for analysis
1088 // and skip over this call site for now
1089 if( !methodContextsToVisitSet.contains( mcNew ) ) {
1090 methodContextsToVisitQ.add( new MethodContextQWrapper( mapDescriptorToPriority.get( md ),
1092 methodContextsToVisitSet.add( mcNew );
1096 ogCopy.resolveMethodCall(fc, possibleMd.isStatic(), pflatm, ogPotentialCallee, mc, null);
1099 ogMergeOfAllPossibleCalleeResults.merge(ogCopy);
1101 meAnalysis.analyzeFlatCall(ogMergeOfAllPossibleCalleeResults, mcNew, mc, fc);
1106 og = ogMergeOfAllPossibleCalleeResults;
1109 case FKind.FlatReturnNode:
1110 FlatReturnNode frn = (FlatReturnNode) fn;
1111 rhs = frn.getReturnTemp();
1112 if( rhs != null && !rhs.getType().isImmutable() ) {
1113 og.assignReturnEqualToTemp(rhs);
1115 setRetNodes.add(frn);
1120 if( methodEffects ) {
1121 Hashtable<FlatNode, OwnershipGraph> table=mapMethodContextToFlatNodeOwnershipGraph.get(mc);
1123 table=new Hashtable<FlatNode, OwnershipGraph>();
1126 mapMethodContextToFlatNodeOwnershipGraph.put(mc, table);
1133 // this method should generate integers strictly greater than zero!
1134 // special "shadow" regions are made from a heap region by negating
1136 static public Integer generateUniqueHeapRegionNodeID() {
1138 return new Integer(uniqueIDcount);
1142 static public FieldDescriptor getArrayField( TypeDescriptor tdElement ) {
1143 FieldDescriptor fdElement = mapTypeToArrayField.get( tdElement );
1144 if( fdElement == null ) {
1145 fdElement = new FieldDescriptor(new Modifiers(Modifiers.PUBLIC),
1147 arrayElementFieldName,
1150 mapTypeToArrayField.put( tdElement, fdElement );
1156 private void setGraphForMethodContext(MethodContext mc, OwnershipGraph og) {
1158 mapMethodContextToCompleteOwnershipGraph.put(mc, og);
1160 if( writeDOTs && writeAllDOTs ) {
1161 if( !mapMethodContextToNumUpdates.containsKey(mc) ) {
1162 mapMethodContextToNumUpdates.put(mc, new Integer(0) );
1164 Integer n = mapMethodContextToNumUpdates.get(mc);
1166 og.writeGraph(mc+"COMPLETE"+String.format("%05d", n),
1167 true, // write labels (variables)
1168 true, // selectively hide intermediate temp vars
1169 true, // prune unreachable heap regions
1170 false, // show back edges to confirm graph validity
1171 false, // show parameter indices (unmaintained!)
1172 true, // hide subset reachability states
1173 true); // hide edge taints
1174 } catch( IOException e ) {}
1175 mapMethodContextToNumUpdates.put(mc, n + 1);
1180 private void addDependent( MethodContext caller, MethodContext callee ) {
1181 HashSet<MethodContext> deps = mapMethodContextToDependentContexts.get( callee );
1182 if( deps == null ) {
1183 deps = new HashSet<MethodContext>();
1186 mapMethodContextToDependentContexts.put( callee, deps );
1189 private Iterator<MethodContext> iteratorDependents( MethodContext callee ) {
1190 HashSet<MethodContext> deps = mapMethodContextToDependentContexts.get( callee );
1191 if( deps == null ) {
1192 deps = new HashSet<MethodContext>();
1193 mapMethodContextToDependentContexts.put( callee, deps );
1195 return deps.iterator();
1199 private void writeFinalContextGraphs() {
1200 Set entrySet = mapMethodContextToCompleteOwnershipGraph.entrySet();
1201 Iterator itr = entrySet.iterator();
1202 while( itr.hasNext() ) {
1203 Map.Entry me = (Map.Entry) itr.next();
1204 MethodContext mc = (MethodContext) me.getKey();
1205 OwnershipGraph og = (OwnershipGraph) me.getValue();
1208 og.writeGraph(mc+"COMPLETE",
1209 true, // write labels (variables)
1210 true, // selectively hide intermediate temp vars
1211 true, // prune unreachable heap regions
1212 false, // show back edges to confirm graph validity
1213 false, // show parameter indices (unmaintained!)
1214 true, // hide subset reachability states
1215 true); // hide edge taints
1216 } catch( IOException e ) {}
1222 // return just the allocation site associated with one FlatNew node
1223 private AllocationSite getAllocationSiteFromFlatNewPRIVATE(FlatNew fn) {
1225 if( !mapFlatNewToAllocationSite.containsKey(fn) ) {
1226 AllocationSite as = new AllocationSite(allocationDepth, fn, fn.getDisjointId());
1228 // the newest nodes are single objects
1229 for( int i = 0; i < allocationDepth; ++i ) {
1230 Integer id = generateUniqueHeapRegionNodeID();
1231 as.setIthOldest(i, id);
1232 mapHrnIdToAllocationSite.put( id, as );
1235 // the oldest node is a summary node
1236 Integer idSummary = generateUniqueHeapRegionNodeID();
1237 as.setSummary(idSummary);
1239 mapFlatNewToAllocationSite.put(fn, as);
1242 return mapFlatNewToAllocationSite.get(fn);
1246 // return all allocation sites in the method (there is one allocation
1247 // site per FlatNew node in a method)
1248 private HashSet<AllocationSite> getAllocationSiteSet(Descriptor d) {
1249 if( !mapDescriptorToAllocationSiteSet.containsKey(d) ) {
1250 buildAllocationSiteSet(d);
1253 return mapDescriptorToAllocationSiteSet.get(d);
1257 private void buildAllocationSiteSet(Descriptor d) {
1258 HashSet<AllocationSite> s = new HashSet<AllocationSite>();
1261 if( d instanceof MethodDescriptor ) {
1262 fm = state.getMethodFlat( (MethodDescriptor) d);
1264 assert d instanceof TaskDescriptor;
1265 fm = state.getMethodFlat( (TaskDescriptor) d);
1268 // visit every node in this FlatMethod's IR graph
1269 // and make a set of the allocation sites from the
1270 // FlatNew node's visited
1271 HashSet<FlatNode> visited = new HashSet<FlatNode>();
1272 HashSet<FlatNode> toVisit = new HashSet<FlatNode>();
1275 while( !toVisit.isEmpty() ) {
1276 FlatNode n = toVisit.iterator().next();
1278 if( n instanceof FlatNew ) {
1279 s.add(getAllocationSiteFromFlatNewPRIVATE( (FlatNew) n) );
1285 for( int i = 0; i < n.numNext(); ++i ) {
1286 FlatNode child = n.getNext(i);
1287 if( !visited.contains(child) ) {
1293 mapDescriptorToAllocationSiteSet.put(d, s);
1297 private HashSet<AllocationSite> getFlaggedAllocationSites(Descriptor dIn) {
1299 HashSet<AllocationSite> out = new HashSet<AllocationSite>();
1300 HashSet<Descriptor> toVisit = new HashSet<Descriptor>();
1301 HashSet<Descriptor> visited = new HashSet<Descriptor>();
1305 while( !toVisit.isEmpty() ) {
1306 Descriptor d = toVisit.iterator().next();
1310 HashSet<AllocationSite> asSet = getAllocationSiteSet(d);
1311 Iterator asItr = asSet.iterator();
1312 while( asItr.hasNext() ) {
1313 AllocationSite as = (AllocationSite) asItr.next();
1314 if( as.getDisjointId() != null ) {
1319 // enqueue callees of this method to be searched for
1320 // allocation sites also
1321 Set callees = callGraph.getCalleeSet(d);
1322 if( callees != null ) {
1323 Iterator methItr = callees.iterator();
1324 while( methItr.hasNext() ) {
1325 MethodDescriptor md = (MethodDescriptor) methItr.next();
1327 if( !visited.contains(md) ) {
1338 private HashSet<AllocationSite>
1339 getFlaggedAllocationSitesReachableFromTaskPRIVATE(TaskDescriptor td) {
1341 HashSet<AllocationSite> asSetTotal = new HashSet<AllocationSite>();
1342 HashSet<Descriptor> toVisit = new HashSet<Descriptor>();
1343 HashSet<Descriptor> visited = new HashSet<Descriptor>();
1347 // traverse this task and all methods reachable from this task
1348 while( !toVisit.isEmpty() ) {
1349 Descriptor d = toVisit.iterator().next();
1353 HashSet<AllocationSite> asSet = getAllocationSiteSet(d);
1354 Iterator asItr = asSet.iterator();
1355 while( asItr.hasNext() ) {
1356 AllocationSite as = (AllocationSite) asItr.next();
1357 TypeDescriptor typed = as.getType();
1358 if( typed != null ) {
1359 ClassDescriptor cd = typed.getClassDesc();
1360 if( cd != null && cd.hasFlags() ) {
1366 // enqueue callees of this method to be searched for
1367 // allocation sites also
1368 Set callees = callGraph.getCalleeSet(d);
1369 if( callees != null ) {
1370 Iterator methItr = callees.iterator();
1371 while( methItr.hasNext() ) {
1372 MethodDescriptor md = (MethodDescriptor) methItr.next();
1374 if( !visited.contains(md) ) {
1386 private LinkedList<MethodContext> topologicalSort( HashSet<MethodContext> set ) {
1387 HashSet <MethodContext> discovered = new HashSet <MethodContext>();
1388 LinkedList<MethodContext> sorted = new LinkedList<MethodContext>();
1390 Iterator<MethodContext> itr = set.iterator();
1391 while( itr.hasNext() ) {
1392 MethodContext mc = itr.next();
1394 if( !discovered.contains( mc ) ) {
1395 dfsVisit( set, mc, sorted, discovered );
1402 private void dfsVisit( HashSet<MethodContext> set,
1404 LinkedList<MethodContext> sorted,
1405 HashSet <MethodContext> discovered ) {
1406 discovered.add( mc );
1408 Descriptor d = mc.getDescriptor();
1409 if( d instanceof MethodDescriptor ) {
1410 MethodDescriptor md = (MethodDescriptor) d;
1411 Iterator itr = callGraph.getCallerSet( md ).iterator();
1412 while( itr.hasNext() ) {
1413 Descriptor dCaller = (Descriptor) itr.next();
1415 // only consider the callers in the original set to analyze
1416 Set<MethodContext> callerContexts = mapDescriptorToAllMethodContexts.get( dCaller );
1417 if( callerContexts == null )
1420 // since the analysis hasn't started, there should be exactly one
1421 // context if there are any at all
1422 assert callerContexts.size() == 1;
1423 MethodContext mcCaller = callerContexts.iterator().next();
1424 assert set.contains( mcCaller );
1426 if( !discovered.contains( mcCaller ) ) {
1427 dfsVisit( set, mcCaller, sorted, discovered );
1432 sorted.addFirst( mc );
1437 private String computeAliasContextHistogram() {
1439 Hashtable<Integer, Integer> mapNumContexts2NumDesc =
1440 new Hashtable<Integer, Integer>();
1442 Iterator itr = mapDescriptorToAllMethodContexts.entrySet().iterator();
1443 while( itr.hasNext() ) {
1444 Map.Entry me = (Map.Entry) itr.next();
1445 HashSet<MethodContext> s = (HashSet<MethodContext>) me.getValue();
1447 Integer i = mapNumContexts2NumDesc.get( s.size() );
1449 i = new Integer( 0 );
1451 mapNumContexts2NumDesc.put( s.size(), i + 1 );
1457 itr = mapNumContexts2NumDesc.entrySet().iterator();
1458 while( itr.hasNext() ) {
1459 Map.Entry me = (Map.Entry) itr.next();
1460 Integer c0 = (Integer) me.getKey();
1461 Integer d0 = (Integer) me.getValue();
1463 s += String.format( "%4d methods had %4d unique alias contexts.\n", d0, c0 );
1466 s += String.format( "\n%4d total methods analayzed.\n", total );
1471 private int numMethodsAnalyzed() {
1472 return descriptorsToAnalyze.size();
1478 // insert a call to debugSnapshot() somewhere in the analysis
1479 // to get successive captures of the analysis state
1480 boolean takeDebugSnapshots = false;
1481 String mcDescSymbolDebug = "setRoute";
1482 boolean stopAfterCapture = true;
1484 // increments every visit to debugSnapshot, don't fiddle with it
1485 // IMPORTANT NOTE FOR SETTING THE FOLLOWING VALUES: this
1486 // counter increments just after every node is analyzed
1487 // from the body of the method whose symbol is specified
1489 int debugCounter = 0;
1491 // the value of debugCounter to start reporting the debugCounter
1492 // to the screen to let user know what debug iteration we're at
1493 int numStartCountReport = 0;
1495 // the frequency of debugCounter values to print out, 0 no report
1496 int freqCountReport = 0;
1498 // the debugCounter value at which to start taking snapshots
1499 int iterStartCapture = 0;
1501 // the number of snapshots to take
1502 int numIterToCapture = 300;
1504 void debugSnapshot(OwnershipGraph og, FlatNode fn) {
1505 if( debugCounter > iterStartCapture + numIterToCapture ) {
1510 if( debugCounter > numStartCountReport &&
1511 freqCountReport > 0 &&
1512 debugCounter % freqCountReport == 0 ) {
1513 System.out.println(" @@@ debug counter = "+debugCounter);
1515 if( debugCounter > iterStartCapture ) {
1516 System.out.println(" @@@ capturing debug "+(debugCounter-iterStartCapture)+" @@@");
1517 String graphName = String.format("snap%04d",debugCounter-iterStartCapture);
1519 graphName = graphName+fn;
1522 og.writeGraph(graphName,
1523 true, // write labels (variables)
1524 true, // selectively hide intermediate temp vars
1525 true, // prune unreachable heap regions
1526 false, // show back edges to confirm graph validity
1527 false, // show parameter indices (unmaintained!)
1528 true, // hide subset reachability states
1529 true); // hide edge taints
1530 } catch( Exception e ) {
1531 System.out.println("Error writing debug capture.");
1536 if( debugCounter == iterStartCapture + numIterToCapture && stopAfterCapture ) {
1537 System.out.println("Stopping analysis after debug captures.");
1542 public MethodEffectsAnalysis getMethodEffectsAnalysis(){
1546 public OwnershipGraph getOwnvershipGraphByMethodContext(MethodContext mc){
1547 return mapMethodContextToCompleteOwnershipGraph.get(mc);
1550 public HashSet<MethodContext> getAllMethodContextSetByDescriptor(Descriptor d){
1551 return mapDescriptorToAllMethodContexts.get(d);
1554 public MethodContext getCalleeMethodContext(MethodContext callerMC, FlatCall fc){
1556 Hashtable<FlatNode, OwnershipGraph> table=mapMethodContextToFlatNodeOwnershipGraph.get(callerMC);
1558 // merge previous ownership graph to calculate corresponding method context
1559 OwnershipGraph mergeOG = new OwnershipGraph();
1561 for(int i=0;i<fc.numPrev();i++){
1562 FlatNode prevNode=fc.getPrev(i);
1564 OwnershipGraph prevOG=table.get(prevNode);
1565 mergeOG.merge(prevOG);
1569 MethodDescriptor md=fc.getMethod();
1570 FlatMethod flatm = state.getMethodFlat(md);
1571 Set<Integer> aliasedParamIndices = mergeOG.calculateAliasedParamSet(fc, md.isStatic(), flatm);
1572 MethodContext calleeMC = new MethodContext( md, aliasedParamIndices );