1 package Analysis.OwnershipAnalysis;
8 public class OwnershipGraph {
10 private int allocationDepth;
12 // there was already one other very similar reason
13 // for traversing heap nodes that is no longer needed
14 // instead of writing a new heap region visitor, use
15 // the existing method with a new mode to describe what
16 // actions to take during the traversal
17 protected static final int VISIT_HRN_WRITE_FULL = 0;
20 public Hashtable<Integer, HeapRegionNode> id2hrn;
21 public Hashtable<TempDescriptor, LabelNode > td2ln;
22 public Hashtable<Integer, Integer > id2paramIndex;
23 public Hashtable<Integer, Integer > paramIndex2id;
25 public HashSet<AllocationSite> allocationSites;
28 public OwnershipGraph( int allocationDepth ) {
29 this.allocationDepth = allocationDepth;
31 id2hrn = new Hashtable<Integer, HeapRegionNode>();
32 td2ln = new Hashtable<TempDescriptor, LabelNode >();
33 id2paramIndex = new Hashtable<Integer, Integer >();
34 paramIndex2id = new Hashtable<Integer, Integer >();
36 allocationSites = new HashSet <AllocationSite>();
40 // label nodes are much easier to deal with than
41 // heap region nodes. Whenever there is a request
42 // for the label node that is associated with a
43 // temp descriptor we can either find it or make a
44 // new one and return it. This is because temp
45 // descriptors are globally unique and every label
46 // node is mapped to exactly one temp descriptor.
47 protected LabelNode getLabelNodeFromTemp( TempDescriptor td ) {
50 if( !td2ln.containsKey( td ) ) {
51 td2ln.put( td, new LabelNode( td ) );
54 return td2ln.get( td );
58 // the reason for this method is to have the option
59 // creating new heap regions with specific IDs, or
60 // duplicating heap regions with specific IDs (especially
61 // in the merge() operation) or to create new heap
62 // regions with a new unique ID.
63 protected HeapRegionNode
64 createNewHeapRegionNode( Integer id,
65 boolean isSingleObject,
68 AllocationSite allocSite,
69 String description ) {
72 id = OwnershipAnalysis.generateUniqueHeapRegionNodeID();
75 HeapRegionNode hrn = new HeapRegionNode( id,
81 id2hrn.put( id, hrn );
87 ////////////////////////////////////////////////
89 // Low-level referencee and referencer methods
91 // These methods provide the lowest level for
92 // creating references between ownership nodes
93 // and handling the details of maintaining both
94 // list of referencers and referencees.
96 ////////////////////////////////////////////////
97 protected void addReferenceEdge( OwnershipNode referencer,
98 HeapRegionNode referencee,
99 ReferenceEdgeProperties rep ) {
100 assert referencer != null;
101 assert referencee != null;
103 referencer.addReferencedRegion( referencee, rep );
104 referencee.addReferencer( referencer );
107 protected void removeReferenceEdge( OwnershipNode referencer,
108 HeapRegionNode referencee ) {
109 assert referencer != null;
110 assert referencee != null;
111 assert referencer.getReferenceTo( referencee ) != null;
112 assert referencee.isReferencedBy( referencer );
114 referencer.removeReferencedRegion( referencee );
115 referencee.removeReferencer( referencer );
118 protected void clearReferenceEdgesFrom( OwnershipNode referencer ) {
119 assert referencer != null;
121 // get a copy of the table to iterate over, otherwise
122 // we will be trying to take apart the table as we
123 // are iterating over it, which won't work
124 Iterator i = referencer.setIteratorToReferencedRegionsClone();
125 while( i.hasNext() ) {
126 Map.Entry me = (Map.Entry) i.next();
127 HeapRegionNode referencee = (HeapRegionNode) me.getKey();
128 removeReferenceEdge( referencer, referencee );
132 protected void clearReferenceEdgesTo( HeapRegionNode referencee ) {
133 assert referencee != null;
135 // get a copy of the table to iterate over, otherwise
136 // we will be trying to take apart the table as we
137 // are iterating over it, which won't work
138 Iterator i = referencee.iteratorToReferencersClone();
139 while( i.hasNext() ) {
140 OwnershipNode referencer = (OwnershipNode) i.next();
141 removeReferenceEdge( referencer, referencee );
146 ////////////////////////////////////////////////////
148 // Assignment Operation Methods
150 // These methods are high-level operations for
151 // modeling program assignment statements using
152 // the low-level reference create/remove methods
155 // The destination in an assignment statement is
156 // going to have new references. The method of
157 // determining the references depends on the type
158 // of the FlatNode assignment and the predicates
159 // of the nodes and edges involved.
161 ////////////////////////////////////////////////////
162 public void assignTempToTemp( TempDescriptor src,
163 TempDescriptor dst ) {
164 LabelNode srcln = getLabelNodeFromTemp( src );
165 LabelNode dstln = getLabelNodeFromTemp( dst );
167 clearReferenceEdgesFrom( dstln );
168 HeapRegionNode newReferencee = null;
169 Iterator srcRegionsItr = srcln.setIteratorToReferencedRegions();
170 while( srcRegionsItr.hasNext() ) {
171 Map.Entry me = (Map.Entry) srcRegionsItr.next();
172 newReferencee = (HeapRegionNode) me.getKey();
174 ReferenceEdgeProperties rep = new ReferenceEdgeProperties();
175 addReferenceEdge( dstln, newReferencee, rep );
179 public void assignTempToField( TempDescriptor src,
181 FieldDescriptor fd ) {
182 LabelNode srcln = getLabelNodeFromTemp( src );
183 LabelNode dstln = getLabelNodeFromTemp( dst );
185 clearReferenceEdgesFrom( dstln );
187 HeapRegionNode hrn = null;
188 Iterator srcRegionsItr = srcln.setIteratorToReferencedRegions();
189 while( srcRegionsItr.hasNext() ) {
190 Map.Entry me = (Map.Entry) srcRegionsItr.next();
191 hrn = (HeapRegionNode) me.getKey();
193 HeapRegionNode hrnOneHop = null;
194 Iterator hrnRegionsItr = hrn.setIteratorToReferencedRegions();
195 while( hrnRegionsItr.hasNext() ) {
196 Map.Entry meH = (Map.Entry) hrnRegionsItr.next();
197 hrnOneHop = (HeapRegionNode) meH.getKey();
199 ReferenceEdgeProperties rep = new ReferenceEdgeProperties();
200 addReferenceEdge( dstln, hrnOneHop, rep );
205 public void assignFieldToTemp( TempDescriptor src,
207 FieldDescriptor fd ) {
208 LabelNode srcln = getLabelNodeFromTemp( src );
209 LabelNode dstln = getLabelNodeFromTemp( dst );
211 HeapRegionNode hrn = null;
212 Iterator dstRegionsItr = dstln.setIteratorToReferencedRegions();
213 while( dstRegionsItr.hasNext() ) {
214 Map.Entry me = (Map.Entry) dstRegionsItr.next();
215 hrn = (HeapRegionNode) me.getKey();
217 HeapRegionNode hrnSrc = null;
218 Iterator srcRegionsItr = srcln.setIteratorToReferencedRegions();
219 while( srcRegionsItr.hasNext() ) {
220 Map.Entry meS = (Map.Entry) srcRegionsItr.next();
221 hrnSrc = (HeapRegionNode) meS.getKey();
223 ReferenceEdgeProperties rep = new ReferenceEdgeProperties();
224 addReferenceEdge( hrn, hrnSrc, rep );
229 public void assignTempToParameterAllocation( boolean isTask,
231 Integer paramIndex ) {
234 LabelNode lnParam = getLabelNodeFromTemp( td );
235 HeapRegionNode hrn = createNewHeapRegionNode( null,
240 "param" + paramIndex );
242 // keep track of heap regions that were created for
243 // parameter labels, the index of the parameter they
244 // are for is important when resolving method calls
245 Integer newID = hrn.getID();
246 assert !id2paramIndex.containsKey ( newID );
247 assert !id2paramIndex.containsValue( paramIndex );
248 id2paramIndex.put( newID, paramIndex );
249 paramIndex2id.put( paramIndex, newID );
251 // heap regions for parameters are always multiple object (see above)
252 // and have a reference to themselves, because we can't know the
253 // structure of memory that is passed into the method. We're assuming
255 addReferenceEdge( lnParam, hrn, new ReferenceEdgeProperties( false ) );
256 addReferenceEdge( hrn, hrn, new ReferenceEdgeProperties( false, true ) );
259 public void assignTempToNewAllocation( TempDescriptor td,
260 AllocationSite as ) {
266 // after the age operation the newest (or zero-ith oldest)
267 // node associated with the allocation site should have
268 // no references to it as if it were a newly allocated
269 // heap region, so make a reference to it to complete
271 Integer id = as.getIthOldest( 0 );
272 HeapRegionNode hrnNewest = id2hrn.get( id );
273 assert hrnNewest != null;
275 LabelNode dst = getLabelNodeFromTemp( td );
277 clearReferenceEdgesFrom( dst );
278 addReferenceEdge( dst, hrnNewest, new ReferenceEdgeProperties( false ) );
282 // use the allocation site (unique to entire analysis) to
283 // locate the heap region nodes in this ownership graph
284 // that should be aged. The process models the allocation
285 // of new objects and collects all the oldest allocations
286 // in a summary node to allow for a finite analysis
288 // There is an additional property of this method. After
289 // running it on a particular ownership graph (many graphs
290 // may have heap regions related to the same allocation site)
291 // the heap region node objects in this ownership graph will be
292 // allocated. Therefore, after aging a graph for an allocation
293 // site, attempts to retrieve the heap region nodes using the
294 // integer id's contained in the allocation site should always
295 // return non-null heap regions.
296 public void age( AllocationSite as ) {
298 // aging adds this allocation site to the graph's
299 // list of sites that exist in the graph, or does
300 // nothing if the site is already in the list
301 allocationSites.add( as );
304 //////////////////////////////////////////////////////////////////
306 // move existing references down the line toward
307 // the oldest element, starting with the oldest
310 // TempDescriptor = the td passed into this function, left side of new statement
311 // AllocationSite = { alpha0, alpha1, alpha2, alphaSummary }
313 // 1. Specially merge refs in/out at alpha2 into alphaSummary
314 // 2. Move refs in/out at alpha1 over to alpha2 (alpha1 becomes alpha2)
315 // 3. Move refs in/out at alpha0 over to alpha1
316 // 4. Assign reference from td to alpha0, which now represents a freshly allocated object
318 //////////////////////////////////////////////////////////////////
321 // first specially merge the references from the oldest
322 // node into the summary node, keeping track of 1-to-1 edges
323 Integer idSummary = as.getSummary();
324 HeapRegionNode hrnSummary = id2hrn.get( idSummary );
326 // if this is null then we haven't touched this allocation site
327 // in the context of the current ownership graph, so simply
328 // allocate an appropriate heap region node
329 // this should only happen once per ownership per allocation site,
330 // and a particular integer id can be used to locate the heap region
331 // in different ownership graphs that represents the same part of an
333 if( hrnSummary == null ) {
335 boolean hasFlags = false;
336 if( as.getType().isClass() ) {
337 hasFlags = as.getType().getClassDesc().hasFlags();
340 hrnSummary = createNewHeapRegionNode( idSummary,
345 as + "\\n" + as.getType() + "\\nsummary" );
347 for( int i = 0; i < as.getAllocationDepth(); ++i ) {
348 Integer idIth = as.getIthOldest( i );
349 assert !id2hrn.containsKey( idIth );
350 createNewHeapRegionNode( idIth,
355 as + "\\n" + as.getType() + "\\n" + i + " oldest" );
359 // first transfer the references out of alpha_k to alpha_s
360 Integer idK = as.getOldest();
361 HeapRegionNode hrnK = id2hrn.get( idK );
363 HeapRegionNode hrnReferencee = null;
364 Iterator itrReferencee = hrnK.setIteratorToReferencedRegions();
365 while( itrReferencee.hasNext() ) {
366 Map.Entry me = (Map.Entry) itrReferencee.next();
367 hrnReferencee = (HeapRegionNode) me.getKey();
368 ReferenceEdgeProperties rep = (ReferenceEdgeProperties) me.getValue();
370 // determine if another summary node is already referencing this referencee
371 boolean hasSummaryReferencer = false;
372 OwnershipNode onReferencer = null;
373 Iterator itrReferencer = hrnReferencee.iteratorToReferencers();
374 while( itrReferencer.hasNext() ) {
375 onReferencer = (OwnershipNode) itrReferencer.next();
376 if( onReferencer instanceof HeapRegionNode ) {
377 HeapRegionNode hrnPossibleSummary = (HeapRegionNode) onReferencer;
378 if( hrnPossibleSummary.isNewSummary() ) {
379 hasSummaryReferencer = true;
384 addReferenceEdge( hrnSummary,
386 new ReferenceEdgeProperties( !hasSummaryReferencer ) );
389 // next transfer references to alpha_k over to alpha_s
390 OwnershipNode onReferencer = null;
391 Iterator itrReferencer = hrnK.iteratorToReferencers();
392 while( itrReferencer.hasNext() ) {
393 onReferencer = (OwnershipNode) itrReferencer.next();
395 ReferenceEdgeProperties rep = onReferencer.getReferenceTo( hrnK );
398 addReferenceEdge( onReferencer, hrnSummary, rep.copy() );
402 // then move down the line of heap region nodes
403 // clobbering the ith and transferring all references
404 // to and from i-1 to node i. Note that this clobbers
405 // the oldest node (alpha_k) that was just merged into
406 // the summary above and should move everything from
407 // alpha_0 to alpha_1 before we finish
408 for( int i = allocationDepth - 1; i > 0; --i ) {
410 // move references from the i-1 oldest to the ith oldest
411 Integer idIth = as.getIthOldest( i );
412 HeapRegionNode hrnI = id2hrn.get( idIth );
413 Integer idImin1th = as.getIthOldest( i - 1 );
414 HeapRegionNode hrnImin1 = id2hrn.get( idImin1th );
416 // clear references in and out of node i
417 clearReferenceEdgesFrom( hrnI );
418 clearReferenceEdgesTo ( hrnI );
420 // copy each edge in and out of i-1 to i
421 hrnReferencee = null;
422 itrReferencee = hrnImin1.setIteratorToReferencedRegions();
423 while( itrReferencee.hasNext() ) {
424 Map.Entry me = (Map.Entry) itrReferencee.next();
425 hrnReferencee = (HeapRegionNode) me.getKey();
426 ReferenceEdgeProperties rep = (ReferenceEdgeProperties) me.getValue();
428 addReferenceEdge( hrnI, hrnReferencee, rep.copy() );
432 itrReferencer = hrnImin1.iteratorToReferencers();
433 while( itrReferencer.hasNext() ) {
434 onReferencer = (OwnershipNode) itrReferencer.next();
436 ReferenceEdgeProperties rep = onReferencer.getReferenceTo( hrnImin1 );
439 addReferenceEdge( onReferencer, hrnI, rep.copy() );
443 // as stated above, the newest node alpha_0 should have had its
444 // references moved over to alpha_1, so we can wipe alpha_0 clean
445 // in preparation for operations that want to reference a freshly
446 // allocated object from this allocation site
447 Integer id0th = as.getIthOldest( 0 );
448 HeapRegionNode hrn0 = id2hrn.get( id0th );
450 // the loop to move references from i-1 to i should
451 // have touched this node, therefore assert it is non-null
454 // clear all references in and out of newest node
455 clearReferenceEdgesFrom( hrn0 );
456 clearReferenceEdgesTo ( hrn0 );
462 // the heap regions that are specially allocated as multiple-object
463 // regions for method parameters need to be remembered in order to
464 // resolve a function call. So actually, we need a mapping from
465 // caller argument descriptors to the callee parameter heap regions
466 // to apply reference edges in the callee to the caller graph.
468 // also, Constructors and virtual dispatch methods have a "this"
469 // argument that make the mapping of arguments to parameters a little
470 // tricky. What happens to that this region?
473 public void resolveMethodCall( FlatCall fc,
476 OwnershipGraph ogCallee ) { //,
477 //HashSet<AllocationSite> allocSiteSet ) {
479 // first age all of the allocation sites from
480 // the callee graph in this graph
481 Iterator i = ogCallee.allocationSites.iterator();
482 while( i.hasNext() ) {
483 AllocationSite allocSite = (AllocationSite) i.next();
484 this.age( allocSite );
487 // in non-static methods there is a "this" pointer
488 // that should be taken into account
490 assert fc.numArgs() == fm.numParameters();
492 assert fc.numArgs() + 1 == fm.numParameters();
495 // the heap regions represented by the arguments (caller graph)
496 // and heap regions for the parameters (callee graph)
497 // don't correspond to each other by heap region ID. In fact,
498 // an argument label node can be referencing several heap regions
499 // so the parameter label always references a multiple-object
500 // heap region in order to handle the range of possible contexts
501 // for a method call. This means we need to make a special mapping
502 // of argument->parameter regions in order to update the caller graph
504 // for every heap region->heap region edge in the
505 // callee graph, create the matching edge or edges
506 // in the caller graph
507 Set sCallee = ogCallee.id2hrn.entrySet();
508 Iterator iCallee = sCallee.iterator();
509 while( iCallee.hasNext() ) {
510 Map.Entry meCallee = (Map.Entry) iCallee.next();
511 Integer idCallee = (Integer) meCallee.getKey();
512 HeapRegionNode hrnCallee = (HeapRegionNode) meCallee.getValue();
514 HeapRegionNode hrnChildCallee = null;
515 Iterator heapRegionsItrCallee = hrnCallee.setIteratorToReferencedRegions();
516 while( heapRegionsItrCallee.hasNext() ) {
517 Map.Entry me = (Map.Entry) heapRegionsItrCallee.next();
518 hrnChildCallee = (HeapRegionNode) me.getKey();
519 ReferenceEdgeProperties repC = (ReferenceEdgeProperties) me.getValue();
521 Integer idChildCallee = hrnChildCallee.getID();
523 // only address this edge if it is not a special reflexive edge
524 if( !repC.isInitialParamReflexive() ) {
526 // now we know that in the callee method's ownership graph
527 // there is a heap region->heap region reference edge given
528 // by heap region pointers:
529 // hrnCallee -> heapChildCallee
531 // or by the ownership-graph independent ID's:
532 // idCallee -> idChildCallee
534 // So now make a set of possible source heaps in the caller graph
535 // and a set of destination heaps in the caller graph, and make
536 // a reference edge in the caller for every possible (src,dst) pair
537 if( !ogCallee.id2hrn.contains( idChildCallee ) ) {
538 //System.out.println( "Houston, we got a problem." );
539 //System.out.println( "idCallee is "+idCallee );
540 //System.out.println( "idChildCallee is "+idChildCallee );
543 writeGraph( "caller", false, false );
544 ogCallee.writeGraph( "callee", false, false );
545 } catch( IOException e ) {}
548 HashSet<HeapRegionNode> possibleCallerSrcs =
549 getHRNSetThatPossiblyMapToCalleeHRN( ogCallee,
554 HashSet<HeapRegionNode> possibleCallerDsts =
555 getHRNSetThatPossiblyMapToCalleeHRN( ogCallee,
560 // make every possible pair of {srcSet} -> {dstSet} edges in the caller
561 Iterator srcItr = possibleCallerSrcs.iterator();
562 while( srcItr.hasNext() ) {
563 HeapRegionNode src = (HeapRegionNode) srcItr.next();
565 Iterator dstItr = possibleCallerDsts.iterator();
566 while( dstItr.hasNext() ) {
567 HeapRegionNode dst = (HeapRegionNode) dstItr.next();
569 addReferenceEdge( src, dst, repC.copy() );
577 private HashSet<HeapRegionNode> getHRNSetThatPossiblyMapToCalleeHRN( OwnershipGraph ogCallee,
582 HashSet<HeapRegionNode> possibleCallerHRNs = new HashSet<HeapRegionNode>();
584 if( ogCallee.id2paramIndex.containsKey( idCallee ) ) {
585 // the heap region that is part of this
586 // reference edge won't have a matching ID in the
587 // caller graph because it is specifically allocated
588 // for a particular parameter. Use that information
589 // to find the corresponding argument label in the
590 // caller in order to create the proper reference edge
592 assert !id2hrn.containsKey( idCallee );
594 Integer paramIndex = ogCallee.id2paramIndex.get( idCallee );
595 TempDescriptor argTemp;
597 // now depending on whether the callee is static or not
598 // we need to account for a "this" argument in order to
599 // find the matching argument in the caller context
601 argTemp = fc.getArg( paramIndex );
603 if( paramIndex == 0 ) {
604 argTemp = fc.getThis();
606 argTemp = fc.getArg( paramIndex - 1 );
610 LabelNode argLabel = getLabelNodeFromTemp( argTemp );
611 Iterator argHeapRegionsItr = argLabel.setIteratorToReferencedRegions();
612 while( argHeapRegionsItr.hasNext() ) {
613 Map.Entry meArg = (Map.Entry) argHeapRegionsItr.next();
614 HeapRegionNode argHeapRegion = (HeapRegionNode) meArg.getKey();
615 ReferenceEdgeProperties repArg = (ReferenceEdgeProperties) meArg.getValue();
617 possibleCallerHRNs.add( (HeapRegionNode) argHeapRegion );
621 // this heap region is not a parameter, so it should
622 // have a matching heap region in the caller graph
623 assert id2hrn.containsKey( idCallee );
624 possibleCallerHRNs.add( id2hrn.get( idCallee ) );
627 return possibleCallerHRNs;
632 ////////////////////////////////////////////////////
633 // in merge() and equals() methods the suffix A
634 // represents the passed in graph and the suffix
635 // B refers to the graph in this object
636 ////////////////////////////////////////////////////
637 public void merge( OwnershipGraph og ) {
643 mergeOwnershipNodes ( og );
644 mergeReferenceEdges ( og );
645 mergeId2paramIndex ( og );
646 mergeAllocationSites( og );
649 protected void mergeOwnershipNodes( OwnershipGraph og ) {
650 Set sA = og.id2hrn.entrySet();
651 Iterator iA = sA.iterator();
652 while( iA.hasNext() ) {
653 Map.Entry meA = (Map.Entry) iA.next();
654 Integer idA = (Integer) meA.getKey();
655 HeapRegionNode hrnA = (HeapRegionNode) meA.getValue();
657 // if this graph doesn't have a node the
658 // incoming graph has, allocate it
659 if( !id2hrn.containsKey( idA ) ) {
660 HeapRegionNode hrnB = hrnA.copy();
661 id2hrn.put( idA, hrnB );
665 // now add any label nodes that are in graph B but
667 sA = og.td2ln.entrySet();
669 while( iA.hasNext() ) {
670 Map.Entry meA = (Map.Entry) iA.next();
671 TempDescriptor tdA = (TempDescriptor) meA.getKey();
672 LabelNode lnA = (LabelNode) meA.getValue();
674 // if the label doesn't exist in B, allocate and add it
675 LabelNode lnB = getLabelNodeFromTemp( tdA );
679 protected void mergeReferenceEdges( OwnershipGraph og ) {
680 // there is a data structure for storing label nodes
681 // retireved by temp descriptors, and a data structure
682 // for stroing heap region nodes retrieved by integer
683 // ids. Because finding edges requires interacting
684 // with these disparate data structures frequently the
685 // process is nearly duplicated, one for each
688 Set sA = og.id2hrn.entrySet();
689 Iterator iA = sA.iterator();
690 while( iA.hasNext() ) {
691 Map.Entry meA = (Map.Entry) iA.next();
692 Integer idA = (Integer) meA.getKey();
693 HeapRegionNode hrnA = (HeapRegionNode) meA.getValue();
695 HeapRegionNode hrnChildA = null;
696 Iterator heapRegionsItrA = hrnA.setIteratorToReferencedRegions();
697 while( heapRegionsItrA.hasNext() ) {
698 Map.Entry me = (Map.Entry) heapRegionsItrA.next();
699 hrnChildA = (HeapRegionNode) me.getKey();
700 ReferenceEdgeProperties repA = (ReferenceEdgeProperties) me.getValue();
702 Integer idChildA = hrnChildA.getID();
704 // at this point we know an edge in graph A exists
705 // idA -> idChildA, does this exist in B?
706 boolean edgeFound = false;
707 assert id2hrn.containsKey( idA );
708 HeapRegionNode hrnB = id2hrn.get( idA );
710 HeapRegionNode hrnChildB = null;
711 Iterator heapRegionsItrB = hrnB.setIteratorToReferencedRegions();
712 while( heapRegionsItrB.hasNext() ) {
713 Map.Entry meC = (Map.Entry) heapRegionsItrB.next();
714 hrnChildB = (HeapRegionNode) meC.getKey();
716 if( hrnChildB.equals( idChildA ) ) {
721 // if the edge from A was not found in B,
724 assert id2hrn.containsKey( idChildA );
725 hrnChildB = id2hrn.get( idChildA );
726 ReferenceEdgeProperties repB = repA.copy();
727 addReferenceEdge( hrnB, hrnChildB, repB );
729 // otherwise, the edge already existed in both graphs.
730 // if this is the case, check to see whether the isUnique
731 // predicate of the edges might change
739 // and then again with label nodes
740 sA = og.td2ln.entrySet();
742 while( iA.hasNext() ) {
743 Map.Entry meA = (Map.Entry) iA.next();
744 TempDescriptor tdA = (TempDescriptor) meA.getKey();
745 LabelNode lnA = (LabelNode) meA.getValue();
747 HeapRegionNode hrnChildA = null;
748 Iterator heapRegionsItrA = lnA.setIteratorToReferencedRegions();
749 while( heapRegionsItrA.hasNext() ) {
750 Map.Entry meH = (Map.Entry) heapRegionsItrA.next();
751 hrnChildA = (HeapRegionNode) meH.getKey();
752 ReferenceEdgeProperties repA = (ReferenceEdgeProperties) meH.getValue();
754 Integer idChildA = hrnChildA.getID();
756 // at this point we know an edge in graph A exists
757 // tdA -> idChildA, does this exist in B?
758 boolean edgeFound = false;
759 assert td2ln.containsKey( tdA );
760 LabelNode lnB = td2ln.get( tdA );
762 HeapRegionNode hrnChildB = null;
763 Iterator heapRegionsItrB = lnB.setIteratorToReferencedRegions();
764 while( heapRegionsItrB.hasNext() ) {
765 Map.Entry meC = (Map.Entry) heapRegionsItrB.next();
766 hrnChildB = (HeapRegionNode) meC.getKey();
768 if( hrnChildB.equals( idChildA ) ) {
773 // if the edge from A was not found in B,
776 assert id2hrn.containsKey( idChildA );
777 hrnChildB = id2hrn.get( idChildA );
778 ReferenceEdgeProperties repB = repA.copy();
779 addReferenceEdge( lnB, hrnChildB, repB );
781 // otherwise, the edge already existed in both graphs.
782 // if this is the case, check to see whether the isUnique
783 // predicate of the edges might change
792 // you should only merge ownership graphs that have the
793 // same number of parameters, or if one or both parameter
794 // index tables are empty
795 protected void mergeId2paramIndex( OwnershipGraph og ) {
796 if( id2paramIndex.size() == 0 ) {
797 id2paramIndex = og.id2paramIndex;
798 paramIndex2id = og.paramIndex2id;
802 if( og.id2paramIndex.size() == 0 ) {
806 assert id2paramIndex.size() == og.id2paramIndex.size();
809 protected void mergeAllocationSites( OwnershipGraph og ) {
810 allocationSites.addAll( og.allocationSites );
814 // it is necessary in the equals() member functions
815 // to "check both ways" when comparing the data
816 // structures of two graphs. For instance, if all
817 // edges between heap region nodes in graph A are
818 // present and equal in graph B it is not sufficient
819 // to say the graphs are equal. Consider that there
820 // may be edges in graph B that are not in graph A.
821 // the only way to know that all edges in both graphs
822 // are equally present is to iterate over both data
823 // structures and compare against the other graph.
824 public boolean equals( OwnershipGraph og ) {
830 if( !areHeapRegionNodesEqual( og ) ) {
834 if( !areHeapRegionToHeapRegionEdgesEqual( og ) ) {
838 if( !areLabelNodesEqual( og ) ) {
842 if( !areLabelToHeapRegionEdgesEqual( og ) ) {
846 if( !areId2paramIndexEqual( og ) ) {
850 // if everything is equal up to this point,
851 // assert that allocationSites is also equal--
852 // this data is redundant and kept for efficiency
853 assert allocationSites.equals( og.allocationSites );
858 protected boolean areHeapRegionNodesEqual( OwnershipGraph og ) {
859 // check all nodes in A for presence in graph B
860 Set sA = og.id2hrn.entrySet();
861 Iterator iA = sA.iterator();
862 while( iA.hasNext() ) {
863 Map.Entry meA = (Map.Entry) iA.next();
864 Integer idA = (Integer) meA.getKey();
865 HeapRegionNode hrnA = (HeapRegionNode) meA.getValue();
867 if( !id2hrn.containsKey( idA ) ) {
871 HeapRegionNode hrnB = og.id2hrn.get( idA );
872 if( !hrnA.equals( hrnB ) ) {
877 // then check all nodes in B verses graph A
878 Set sB = id2hrn.entrySet();
879 Iterator iB = sB.iterator();
880 while( iB.hasNext() ) {
881 Map.Entry meB = (Map.Entry) iB.next();
882 Integer idB = (Integer) meB.getKey();
883 HeapRegionNode hrnB = (HeapRegionNode) meB.getValue();
885 if( !og.id2hrn.containsKey( idB ) ) {
889 // we should have already checked the equality
890 // of this pairing in the last pass if they both
891 // exist so assert that they are equal now
892 HeapRegionNode hrnA = og.id2hrn.get( idB );
893 assert hrnB.equals( hrnA );
899 protected boolean areHeapRegionToHeapRegionEdgesEqual( OwnershipGraph og ) {
900 Set sA = og.id2hrn.entrySet();
901 Iterator iA = sA.iterator();
902 while( iA.hasNext() ) {
903 Map.Entry meA = (Map.Entry) iA.next();
904 Integer idA = (Integer) meA.getKey();
905 HeapRegionNode hrnA = (HeapRegionNode) meA.getValue();
907 // we should have already checked that the same
908 // heap regions exist in both graphs
909 assert id2hrn.containsKey( idA );
911 // and are their edges the same? first check every
912 // edge in A for presence and equality in B
913 HeapRegionNode hrnChildA = null;
914 Iterator heapRegionsItrA = hrnA.setIteratorToReferencedRegions();
915 while( heapRegionsItrA.hasNext() ) {
916 Map.Entry me = (Map.Entry) heapRegionsItrA.next();
917 hrnChildA = (HeapRegionNode) me.getKey();
918 ReferenceEdgeProperties repA = (ReferenceEdgeProperties) me.getValue();
920 Integer idChildA = hrnChildA.getID();
921 assert id2hrn.containsKey( idChildA );
923 // at this point we know an edge in graph A exists
924 // idA -> idChildA, does this edge exist in B?
925 boolean edgeFound = false;
926 HeapRegionNode hrnB = id2hrn.get( idA );
928 HeapRegionNode hrnChildB = null;
929 Iterator heapRegionsItrB = hrnB.setIteratorToReferencedRegions();
930 while( heapRegionsItrB.hasNext() ) {
931 Map.Entry meH = (Map.Entry) heapRegionsItrB.next();
932 hrnChildB = (HeapRegionNode) meH.getKey();
933 ReferenceEdgeProperties repB = (ReferenceEdgeProperties) meH.getValue();
935 if( idChildA.equals( hrnChildB.getID() ) ) {
936 if( !repA.equals( repB ) ) {
948 // then check every edge in B for presence in A, starting
949 // from the same parent HeapRegionNode
950 HeapRegionNode hrnB = id2hrn.get( idA );
952 HeapRegionNode hrnChildB = null;
953 Iterator heapRegionsItrB = hrnB.setIteratorToReferencedRegions();
954 while( heapRegionsItrB.hasNext() ) {
955 Map.Entry me = (Map.Entry) heapRegionsItrB.next();
956 hrnChildB = (HeapRegionNode) me.getKey();
957 ReferenceEdgeProperties repB = (ReferenceEdgeProperties) me.getValue();
959 Integer idChildB = hrnChildB.getID();
961 // at this point we know an edge in graph B exists
962 // idB -> idChildB, does this edge exist in A?
963 boolean edgeFound = false;
966 heapRegionsItrA = hrnA.setIteratorToReferencedRegions();
967 while( heapRegionsItrA.hasNext() ) {
968 Map.Entry meH = (Map.Entry) heapRegionsItrA.next();
969 hrnChildA = (HeapRegionNode) meH.getKey();
970 ReferenceEdgeProperties repA = (ReferenceEdgeProperties) meH.getValue();
972 if( idChildB.equals( hrnChildA.getID() ) ) {
973 assert repB.equals( repA );
987 protected boolean areLabelNodesEqual( OwnershipGraph og ) {
988 // are all label nodes in A also in graph B?
989 Set sA = og.td2ln.entrySet();
990 Iterator iA = sA.iterator();
991 while( iA.hasNext() ) {
992 Map.Entry meA = (Map.Entry) iA.next();
993 TempDescriptor tdA = (TempDescriptor) meA.getKey();
995 if( !td2ln.containsKey( tdA ) ) {
1000 // are all label nodes in B also in A?
1001 Set sB = td2ln.entrySet();
1002 Iterator iB = sB.iterator();
1003 while( iB.hasNext() ) {
1004 Map.Entry meB = (Map.Entry) iB.next();
1005 TempDescriptor tdB = (TempDescriptor) meB.getKey();
1007 if( !og.td2ln.containsKey( tdB ) ) {
1015 protected boolean areLabelToHeapRegionEdgesEqual( OwnershipGraph og ) {
1016 Set sA = og.td2ln.entrySet();
1017 Iterator iA = sA.iterator();
1018 while( iA.hasNext() ) {
1019 Map.Entry meA = (Map.Entry) iA.next();
1020 TempDescriptor tdA = (TempDescriptor) meA.getKey();
1021 LabelNode lnA = (LabelNode) meA.getValue();
1023 // we should have already checked that the same
1024 // label nodes exist in both graphs
1025 assert td2ln.containsKey( tdA );
1027 // and are their edges the same? first check every
1028 // edge in A for presence and equality in B
1029 HeapRegionNode hrnChildA = null;
1030 Iterator heapRegionsItrA = lnA.setIteratorToReferencedRegions();
1031 while( heapRegionsItrA.hasNext() ) {
1032 Map.Entry me = (Map.Entry) heapRegionsItrA.next();
1033 hrnChildA = (HeapRegionNode) me.getKey();
1034 ReferenceEdgeProperties repA = (ReferenceEdgeProperties) me.getValue();
1036 Integer idChildA = hrnChildA.getID();
1037 assert id2hrn.containsKey( idChildA );
1039 // at this point we know an edge in graph A exists
1040 // tdA -> idChildA, does this edge exist in B?
1041 boolean edgeFound = false;
1042 LabelNode lnB = td2ln.get( tdA );
1044 HeapRegionNode hrnChildB = null;
1045 Iterator heapRegionsItrB = lnB.setIteratorToReferencedRegions();
1046 while( heapRegionsItrB.hasNext() ) {
1047 Map.Entry meH = (Map.Entry) heapRegionsItrB.next();
1048 hrnChildB = (HeapRegionNode) meH.getKey();
1049 ReferenceEdgeProperties repB = (ReferenceEdgeProperties) meH.getValue();
1051 if( idChildA.equals( hrnChildB.getID() ) ) {
1052 if( !repA.equals( repB ) ) {
1064 // then check every edge in B for presence in A, starting
1065 // from the same parent LabelNode
1066 LabelNode lnB = td2ln.get( tdA );
1068 HeapRegionNode hrnChildB = null;
1069 Iterator heapRegionsItrB = lnB.setIteratorToReferencedRegions();
1070 while( heapRegionsItrB.hasNext() ) {
1071 Map.Entry me = (Map.Entry) heapRegionsItrB.next();
1072 hrnChildB = (HeapRegionNode) me.getKey();
1073 ReferenceEdgeProperties repB = (ReferenceEdgeProperties) me.getValue();
1075 Integer idChildB = hrnChildB.getID();
1077 // at this point we know an edge in graph B exists
1078 // tdB -> idChildB, does this edge exist in A?
1079 boolean edgeFound = false;
1082 heapRegionsItrA = lnA.setIteratorToReferencedRegions();
1083 while( heapRegionsItrA.hasNext() ) {
1084 Map.Entry meH = (Map.Entry) heapRegionsItrA.next();
1085 hrnChildA = (HeapRegionNode) meH.getKey();
1086 ReferenceEdgeProperties repA = (ReferenceEdgeProperties) meH.getValue();
1088 if( idChildB.equals( hrnChildA.getID() ) ) {
1089 assert repB.equals( repA );
1104 protected boolean areId2paramIndexEqual( OwnershipGraph og ) {
1105 return id2paramIndex.size() == og.id2paramIndex.size();
1110 // given a set B of heap region node ID's, return the set of heap
1111 // region node ID's that is reachable from B
1112 public HashSet<Integer> getReachableSet( HashSet<Integer> idSetB ) {
1114 HashSet<HeapRegionNode> toVisit = new HashSet<HeapRegionNode>();
1115 HashSet<HeapRegionNode> visited = new HashSet<HeapRegionNode>();
1117 // initial nodes to visit are from set B
1118 Iterator initialItr = idSetB.iterator();
1119 while( initialItr.hasNext() ) {
1120 Integer idInitial = (Integer) initialItr.next();
1121 assert id2hrn.contains( idInitial );
1122 HeapRegionNode hrnInitial = id2hrn.get( idInitial );
1123 toVisit.add( hrnInitial );
1126 HashSet<Integer> idSetReachableFromB = new HashSet<Integer>();
1128 // do a heap traversal
1129 while( !toVisit.isEmpty() ) {
1130 HeapRegionNode hrnVisited = (HeapRegionNode) toVisit.iterator().next();
1131 toVisit.remove( hrnVisited );
1132 visited.add ( hrnVisited );
1134 // for every node visited, add it to the total
1136 idSetReachableFromB.add( hrnVisited.getID() );
1138 // find other reachable nodes
1139 Iterator referenceeItr = hrnVisited.setIteratorToReferencedRegions();
1140 while( referenceeItr.hasNext() ) {
1141 Map.Entry me = (Map.Entry) referenceeItr.next();
1142 HeapRegionNode hrnReferencee = (HeapRegionNode) me.getKey();
1143 ReferenceEdgeProperties rep = (ReferenceEdgeProperties) me.getValue();
1145 if( !visited.contains( hrnReferencee ) ) {
1146 toVisit.add( hrnReferencee );
1151 return idSetReachableFromB;
1155 // used to find if a heap region can possibly have a reference to
1156 // any of the heap regions in the given set
1157 // if the id supplied is in the set, then a self-referencing edge
1158 // would return true, but that special case is specifically allowed
1159 // meaning that it isn't an external alias
1160 public boolean canIdReachSet( Integer id, HashSet<Integer> idSet ) {
1162 assert id2hrn.contains( id );
1163 HeapRegionNode hrn = id2hrn.get( id );
1166 HashSet<HeapRegionNode> hrnSet = new HashSet<HeapRegionNode>();
1168 Iterator i = idSet.iterator();
1169 while( i.hasNext() ) {
1170 Integer idFromSet = (Integer) i.next();
1171 assert id2hrn.contains( idFromSet );
1172 hrnSet.add( id2hrn.get( idFromSet ) );
1176 // do a traversal from hrn and see if any of the
1177 // heap regions from the set come up during that
1178 HashSet<HeapRegionNode> toVisit = new HashSet<HeapRegionNode>();
1179 HashSet<HeapRegionNode> visited = new HashSet<HeapRegionNode>();
1182 while( !toVisit.isEmpty() ) {
1183 HeapRegionNode hrnVisited = (HeapRegionNode) toVisit.iterator().next();
1184 toVisit.remove( hrnVisited );
1185 visited.add ( hrnVisited );
1187 Iterator referenceeItr = hrnVisited.setIteratorToReferencedRegions();
1188 while( referenceeItr.hasNext() ) {
1189 Map.Entry me = (Map.Entry) referenceeItr.next();
1190 HeapRegionNode hrnReferencee = (HeapRegionNode) me.getKey();
1191 ReferenceEdgeProperties rep = (ReferenceEdgeProperties) me.getValue();
1193 if( idSet.contains( hrnReferencee.getID() ) ) {
1194 if( !id.equals( hrnReferencee.getID() ) ) {
1199 if( !visited.contains( hrnReferencee ) ) {
1200 toVisit.add( hrnReferencee );
1210 // for writing ownership graphs to dot files
1211 public void writeGraph( Descriptor methodDesc,
1213 boolean writeLabels,
1214 boolean writeReferencers
1215 ) throws java.io.IOException {
1217 methodDesc.getSymbol() +
1218 methodDesc.getNum() +
1225 public void writeGraph( Descriptor methodDesc,
1226 boolean writeLabels,
1227 boolean writeReferencers
1228 ) throws java.io.IOException {
1230 methodDesc.getSymbol() +
1231 methodDesc.getNum() +
1238 public void writeGraph( String graphName,
1239 boolean writeLabels,
1240 boolean writeReferencers
1241 ) throws java.io.IOException {
1243 // remove all non-word characters from the graph name so
1244 // the filename and identifier in dot don't cause errors
1245 graphName = graphName.replaceAll( "[\\W]", "" );
1247 BufferedWriter bw = new BufferedWriter( new FileWriter( graphName+".dot" ) );
1248 bw.write( "digraph "+graphName+" {\n" );
1249 //bw.write( " size=\"7.5,10\";\n" );
1252 // then visit every heap region node
1253 HashSet<HeapRegionNode> visited = new HashSet<HeapRegionNode>();
1255 Set s = id2hrn.entrySet();
1256 Iterator i = s.iterator();
1257 while( i.hasNext() ) {
1258 Map.Entry me = (Map.Entry) i.next();
1259 HeapRegionNode hrn = (HeapRegionNode) me.getValue();
1260 if( !visited.contains( hrn ) ) {
1261 traverseHeapRegionNodes( VISIT_HRN_WRITE_FULL,
1270 bw.write( " graphTitle[label=\""+graphName+"\",shape=box];\n" );
1273 // then visit every label node, useful for debugging
1275 s = td2ln.entrySet();
1277 while( i.hasNext() ) {
1278 Map.Entry me = (Map.Entry) i.next();
1279 LabelNode ln = (LabelNode) me.getValue();
1281 HeapRegionNode hrn = null;
1282 Iterator heapRegionsItr = ln.setIteratorToReferencedRegions();
1283 while( heapRegionsItr.hasNext() ) {
1284 Map.Entry meH = (Map.Entry) heapRegionsItr.next();
1285 hrn = (HeapRegionNode) meH.getKey();
1286 ReferenceEdgeProperties rep = (ReferenceEdgeProperties) meH.getValue();
1288 String edgeLabel = "";
1289 if( rep.isUnique() ) {
1290 edgeLabel = "Unique";
1292 bw.write( " " + ln.toString() +
1293 " -> " + hrn.toString() +
1294 "[label=\"" + edgeLabel +
1305 protected void traverseHeapRegionNodes( int mode,
1309 HashSet<HeapRegionNode> visited,
1310 boolean writeReferencers
1311 ) throws java.io.IOException {
1313 if( visited.contains( hrn ) ) {
1319 case VISIT_HRN_WRITE_FULL:
1321 String attributes = "[";
1323 if( hrn.isSingleObject() ) {
1324 attributes += "shape=box";
1326 attributes += "shape=Msquare";
1329 if( hrn.isFlagged() ) {
1330 attributes += ",style=filled,fillcolor=lightgrey";
1333 attributes += ",label=\"ID" +
1336 hrn.getDescription() +
1339 bw.write( " " + hrn.toString() + attributes + ";\n" );
1344 // useful for debugging
1345 if( writeReferencers ) {
1346 OwnershipNode onRef = null;
1347 Iterator refItr = hrn.iteratorToReferencers();
1348 while( refItr.hasNext() ) {
1349 onRef = (OwnershipNode) refItr.next();
1352 case VISIT_HRN_WRITE_FULL:
1353 bw.write( " " + hrn.toString() +
1354 " -> " + onRef.toString() +
1355 "[color=lightgray];\n" );
1362 HeapRegionNode hrnChild = null;
1363 Iterator childRegionsItr = hrn.setIteratorToReferencedRegions();
1364 while( childRegionsItr.hasNext() ) {
1365 Map.Entry me = (Map.Entry) childRegionsItr.next();
1366 hrnChild = (HeapRegionNode) me.getKey();
1367 ReferenceEdgeProperties rep = (ReferenceEdgeProperties) me.getValue();
1370 case VISIT_HRN_WRITE_FULL:
1371 String edgeLabel = "";
1372 if( rep.isUnique() ) {
1375 if( rep.isInitialParamReflexive() ) {
1378 bw.write( " " + hrn.toString() +
1379 " -> " + hrnChild.toString() +
1380 "[label=\"" + edgeLabel +
1385 traverseHeapRegionNodes( mode,