1 package Analysis.OwnershipAnalysis;
8 public class OwnershipGraph {
10 private int allocationDepth;
11 private TypeUtil typeUtil;
13 // there was already one other very similar reason
14 // for traversing heap nodes that is no longer needed
15 // instead of writing a new heap region visitor, use
16 // the existing method with a new mode to describe what
17 // actions to take during the traversal
18 protected static final int VISIT_HRN_WRITE_FULL = 0;
20 protected static TempDescriptor tdReturn = new TempDescriptor("_Return___");
23 public Hashtable<Integer, HeapRegionNode> id2hrn;
24 public Hashtable<TempDescriptor, LabelNode > td2ln;
25 public Hashtable<Integer, Integer > id2paramIndex;
26 public Hashtable<Integer, Integer > paramIndex2id;
27 public Hashtable<Integer, TempDescriptor> paramIndex2tdQ;
29 public HashSet<AllocationSite> allocationSites;
34 public OwnershipGraph(int allocationDepth, TypeUtil typeUtil) {
35 this.allocationDepth = allocationDepth;
36 this.typeUtil = typeUtil;
38 id2hrn = new Hashtable<Integer, HeapRegionNode>();
39 td2ln = new Hashtable<TempDescriptor, LabelNode >();
40 id2paramIndex = new Hashtable<Integer, Integer >();
41 paramIndex2id = new Hashtable<Integer, Integer >();
42 paramIndex2tdQ = new Hashtable<Integer, TempDescriptor>();
44 allocationSites = new HashSet <AllocationSite>();
48 // label nodes are much easier to deal with than
49 // heap region nodes. Whenever there is a request
50 // for the label node that is associated with a
51 // temp descriptor we can either find it or make a
52 // new one and return it. This is because temp
53 // descriptors are globally unique and every label
54 // node is mapped to exactly one temp descriptor.
55 protected LabelNode getLabelNodeFromTemp(TempDescriptor td) {
58 if( !td2ln.containsKey(td) ) {
59 td2ln.put(td, new LabelNode(td) );
66 // the reason for this method is to have the option
67 // creating new heap regions with specific IDs, or
68 // duplicating heap regions with specific IDs (especially
69 // in the merge() operation) or to create new heap
70 // regions with a new unique ID.
71 protected HeapRegionNode
72 createNewHeapRegionNode(Integer id,
73 boolean isSingleObject,
77 AllocationSite allocSite,
78 ReachabilitySet alpha,
82 id = OwnershipAnalysis.generateUniqueHeapRegionNodeID();
86 if( isFlagged || isParameter ) {
87 alpha = new ReachabilitySet(new TokenTuple(id,
92 alpha = new ReachabilitySet(new TokenTupleSet()
97 HeapRegionNode hrn = new HeapRegionNode(id,
110 ////////////////////////////////////////////////
112 // Low-level referencee and referencer methods
114 // These methods provide the lowest level for
115 // creating references between ownership nodes
116 // and handling the details of maintaining both
117 // list of referencers and referencees.
119 ////////////////////////////////////////////////
120 protected void addReferenceEdge(OwnershipNode referencer,
121 HeapRegionNode referencee,
122 ReferenceEdge edge) {
123 assert referencer != null;
124 assert referencee != null;
126 assert edge.getSrc() == referencer;
127 assert edge.getDst() == referencee;
129 referencer.addReferencee(edge);
130 referencee.addReferencer(edge);
133 protected void removeReferenceEdge(OwnershipNode referencer,
134 HeapRegionNode referencee,
135 FieldDescriptor fieldDesc) {
136 assert referencer != null;
137 assert referencee != null;
139 ReferenceEdge edge = referencer.getReferenceTo(referencee,
142 assert edge == referencee.getReferenceFrom(referencer,
145 referencer.removeReferencee(edge);
146 referencee.removeReferencer(edge);
149 protected void clearReferenceEdgesFrom(OwnershipNode referencer,
150 FieldDescriptor fieldDesc,
152 assert referencer != null;
154 // get a copy of the set to iterate over, otherwise
155 // we will be trying to take apart the set as we
156 // are iterating over it, which won't work
157 Iterator<ReferenceEdge> i = referencer.iteratorToReferenceesClone();
158 while( i.hasNext() ) {
159 ReferenceEdge edge = i.next();
161 if( removeAll || edge.getFieldDesc() == fieldDesc ) {
162 HeapRegionNode referencee = edge.getDst();
164 removeReferenceEdge(referencer,
166 edge.getFieldDesc() );
171 protected void clearReferenceEdgesTo(HeapRegionNode referencee,
172 FieldDescriptor fieldDesc,
174 assert referencee != null;
176 // get a copy of the set to iterate over, otherwise
177 // we will be trying to take apart the set as we
178 // are iterating over it, which won't work
179 Iterator<ReferenceEdge> i = referencee.iteratorToReferencersClone();
180 while( i.hasNext() ) {
181 ReferenceEdge edge = i.next();
183 if( removeAll || edge.getFieldDesc() == fieldDesc ) {
184 OwnershipNode referencer = edge.getSrc();
185 removeReferenceEdge(referencer,
187 edge.getFieldDesc() );
193 protected void propagateTokensOverNodes(HeapRegionNode nPrime,
195 HashSet<HeapRegionNode> nodesWithNewAlpha,
196 HashSet<ReferenceEdge> edgesWithNewBeta) {
198 HashSet<HeapRegionNode> todoNodes
199 = new HashSet<HeapRegionNode>();
200 todoNodes.add(nPrime);
202 HashSet<ReferenceEdge> todoEdges
203 = new HashSet<ReferenceEdge>();
205 Hashtable<HeapRegionNode, ChangeTupleSet> nodePlannedChanges
206 = new Hashtable<HeapRegionNode, ChangeTupleSet>();
207 nodePlannedChanges.put(nPrime, c0);
209 Hashtable<ReferenceEdge, ChangeTupleSet> edgePlannedChanges
210 = new Hashtable<ReferenceEdge, ChangeTupleSet>();
213 while( !todoNodes.isEmpty() ) {
214 HeapRegionNode n = todoNodes.iterator().next();
215 ChangeTupleSet C = nodePlannedChanges.get(n);
217 Iterator itrC = C.iterator();
218 while( itrC.hasNext() ) {
219 ChangeTuple c = (ChangeTuple) itrC.next();
221 if( n.getAlpha().contains(c.getSetToMatch() ) ) {
222 ReachabilitySet withChange = n.getAlpha().union(c.getSetToAdd() );
223 n.setAlphaNew(n.getAlphaNew().union(withChange) );
224 nodesWithNewAlpha.add(n);
228 Iterator<ReferenceEdge> referItr = n.iteratorToReferencers();
229 while( referItr.hasNext() ) {
230 ReferenceEdge edge = referItr.next();
233 if( !edgePlannedChanges.containsKey(edge) ) {
234 edgePlannedChanges.put(edge, new ChangeTupleSet().makeCanonical() );
237 edgePlannedChanges.put(edge, edgePlannedChanges.get(edge).union(C) );
240 Iterator<ReferenceEdge> refeeItr = n.iteratorToReferencees();
241 while( refeeItr.hasNext() ) {
242 ReferenceEdge edgeF = refeeItr.next();
243 HeapRegionNode m = edgeF.getDst();
245 ChangeTupleSet changesToPass = new ChangeTupleSet().makeCanonical();
247 Iterator<ChangeTuple> itrCprime = C.iterator();
248 while( itrCprime.hasNext() ) {
249 ChangeTuple c = itrCprime.next();
250 if( edgeF.getBeta().contains(c.getSetToMatch() ) ) {
251 changesToPass = changesToPass.union(c);
255 if( !changesToPass.isEmpty() ) {
256 if( !nodePlannedChanges.containsKey(m) ) {
257 nodePlannedChanges.put(m, new ChangeTupleSet().makeCanonical() );
260 ChangeTupleSet currentChanges = nodePlannedChanges.get(m);
262 if( !changesToPass.isSubset(currentChanges) ) {
264 nodePlannedChanges.put(m, currentChanges.union(changesToPass) );
273 propagateTokensOverEdges(todoEdges, edgePlannedChanges, edgesWithNewBeta);
277 protected void propagateTokensOverEdges(
278 HashSet<ReferenceEdge> todoEdges,
279 Hashtable<ReferenceEdge, ChangeTupleSet> edgePlannedChanges,
280 HashSet<ReferenceEdge> edgesWithNewBeta) {
283 while( !todoEdges.isEmpty() ) {
284 ReferenceEdge edgeE = todoEdges.iterator().next();
285 todoEdges.remove(edgeE);
287 if( !edgePlannedChanges.containsKey(edgeE) ) {
288 edgePlannedChanges.put(edgeE, new ChangeTupleSet().makeCanonical() );
291 ChangeTupleSet C = edgePlannedChanges.get(edgeE);
293 ChangeTupleSet changesToPass = new ChangeTupleSet().makeCanonical();
295 Iterator<ChangeTuple> itrC = C.iterator();
296 while( itrC.hasNext() ) {
297 ChangeTuple c = itrC.next();
298 if( edgeE.getBeta().contains(c.getSetToMatch() ) ) {
299 ReachabilitySet withChange = edgeE.getBeta().union(c.getSetToAdd() );
300 edgeE.setBetaNew(edgeE.getBetaNew().union(withChange) );
301 edgesWithNewBeta.add(edgeE);
302 changesToPass = changesToPass.union(c);
306 OwnershipNode onSrc = edgeE.getSrc();
308 if( !changesToPass.isEmpty() && onSrc instanceof HeapRegionNode ) {
309 HeapRegionNode n = (HeapRegionNode) onSrc;
311 Iterator<ReferenceEdge> referItr = n.iteratorToReferencers();
312 while( referItr.hasNext() ) {
313 ReferenceEdge edgeF = referItr.next();
315 if( !edgePlannedChanges.containsKey(edgeF) ) {
316 edgePlannedChanges.put(edgeF, new ChangeTupleSet().makeCanonical() );
319 ChangeTupleSet currentChanges = edgePlannedChanges.get(edgeF);
321 if( !changesToPass.isSubset(currentChanges) ) {
322 todoEdges.add(edgeF);
323 edgePlannedChanges.put(edgeF, currentChanges.union(changesToPass) );
331 ////////////////////////////////////////////////////
333 // Assignment Operation Methods
335 // These methods are high-level operations for
336 // modeling program assignment statements using
337 // the low-level reference create/remove methods
340 // The destination in an assignment statement is
341 // going to have new references. The method of
342 // determining the references depends on the type
343 // of the FlatNode assignment and the predicates
344 // of the nodes and edges involved.
346 ////////////////////////////////////////////////////
347 public void assignTempXEqualToTempY(TempDescriptor x,
350 LabelNode lnX = getLabelNodeFromTemp(x);
351 LabelNode lnY = getLabelNodeFromTemp(y);
353 clearReferenceEdgesFrom(lnX, null, true);
355 Iterator<ReferenceEdge> itrYhrn = lnY.iteratorToReferencees();
356 while( itrYhrn.hasNext() ) {
357 ReferenceEdge edgeY = itrYhrn.next();
358 HeapRegionNode referencee = edgeY.getDst();
359 ReferenceEdge edgeNew = edgeY.copy();
362 addReferenceEdge(lnX, referencee, edgeNew);
367 public void assignTempXEqualToTempYFieldF(TempDescriptor x,
370 LabelNode lnX = getLabelNodeFromTemp(x);
371 LabelNode lnY = getLabelNodeFromTemp(y);
373 clearReferenceEdgesFrom(lnX, null, true);
375 Iterator<ReferenceEdge> itrYhrn = lnY.iteratorToReferencees();
376 while( itrYhrn.hasNext() ) {
377 ReferenceEdge edgeY = itrYhrn.next();
378 HeapRegionNode hrnY = edgeY.getDst();
379 ReachabilitySet betaY = edgeY.getBeta();
381 Iterator<ReferenceEdge> itrHrnFhrn = hrnY.iteratorToReferencees();
382 while( itrHrnFhrn.hasNext() ) {
383 ReferenceEdge edgeHrn = itrHrnFhrn.next();
384 HeapRegionNode hrnHrn = edgeHrn.getDst();
385 ReachabilitySet betaHrn = edgeHrn.getBeta();
387 if( edgeHrn.getFieldDesc() == null ||
388 edgeHrn.getFieldDesc() == f ) {
390 ReferenceEdge edgeNew = new ReferenceEdge(lnX,
394 betaY.intersection(betaHrn) );
396 addReferenceEdge(lnX, hrnHrn, edgeNew);
403 public void assignTempXFieldFEqualToTempY(TempDescriptor x,
406 LabelNode lnX = getLabelNodeFromTemp(x);
407 LabelNode lnY = getLabelNodeFromTemp(y);
409 HashSet<HeapRegionNode> nodesWithNewAlpha = new HashSet<HeapRegionNode>();
410 HashSet<ReferenceEdge> edgesWithNewBeta = new HashSet<ReferenceEdge>();
412 Iterator<ReferenceEdge> itrXhrn = lnX.iteratorToReferencees();
413 while( itrXhrn.hasNext() ) {
414 ReferenceEdge edgeX = itrXhrn.next();
415 HeapRegionNode hrnX = edgeX.getDst();
416 ReachabilitySet betaX = edgeX.getBeta();
418 ReachabilitySet R = hrnX.getAlpha().intersection(edgeX.getBeta() );
420 Iterator<ReferenceEdge> itrYhrn = lnY.iteratorToReferencees();
421 while( itrYhrn.hasNext() ) {
422 ReferenceEdge edgeY = itrYhrn.next();
423 HeapRegionNode hrnY = edgeY.getDst();
424 ReachabilitySet O = edgeY.getBeta();
427 // propagate tokens over nodes starting from hrnSrc, and it will
428 // take care of propagating back up edges from any touched nodes
429 ChangeTupleSet Cy = O.unionUpArityToChangeSet(R);
430 propagateTokensOverNodes(hrnY, Cy, nodesWithNewAlpha, edgesWithNewBeta);
433 // then propagate back just up the edges from hrn
434 ChangeTupleSet Cx = R.unionUpArityToChangeSet(O);
436 HashSet<ReferenceEdge> todoEdges = new HashSet<ReferenceEdge>();
438 Hashtable<ReferenceEdge, ChangeTupleSet> edgePlannedChanges =
439 new Hashtable<ReferenceEdge, ChangeTupleSet>();
441 Iterator<ReferenceEdge> referItr = hrnX.iteratorToReferencers();
442 while( referItr.hasNext() ) {
443 ReferenceEdge edgeUpstream = referItr.next();
444 todoEdges.add(edgeUpstream);
445 edgePlannedChanges.put(edgeUpstream, Cx);
448 propagateTokensOverEdges(todoEdges,
454 //System.out.println( edgeY.getBetaNew() + "\nbeing pruned by\n" + hrnX.getAlpha() );
456 // create the actual reference edge hrnX.f -> hrnY
457 ReferenceEdge edgeNew = new ReferenceEdge(hrnX,
461 edgeY.getBetaNew().pruneBy(hrnX.getAlpha() )
462 //edgeY.getBeta().pruneBy( hrnX.getAlpha() )
464 addReferenceEdge(hrnX, hrnY, edgeNew);
468 // we can do a strong update here if one of two cases holds
469 // SAVE FOR LATER, WITHOUT STILL CORRECT
470 if( (hrnX.getNumReferencers() == 1) ||
471 ( lnX.getNumReferencees() == 1 && hrnX.isSingleObject() )
473 clearReferenceEdgesFrom( hrnX, f, false );
476 addReferenceEdge( hrnX, hrnY, edgeNew );
479 // if the field is null, or "any" field, then
480 // look to see if an any field already exists
481 // and merge with it, otherwise just add the edge
482 ReferenceEdge edgeExisting = hrnX.getReferenceTo( hrnY, f );
484 if( edgeExisting != null ) {
485 edgeExisting.setBetaNew(
486 edgeExisting.getBetaNew().union( edgeNew.getBeta() )
488 // a new edge here cannot be reflexive, so existing will
489 // always be also not reflexive anymore
490 edgeExisting.setIsInitialParamReflexive( false );
493 addReferenceEdge( hrnX, hrnY, edgeNew );
500 Iterator<HeapRegionNode> nodeItr = nodesWithNewAlpha.iterator();
501 while( nodeItr.hasNext() ) {
502 nodeItr.next().applyAlphaNew();
505 Iterator<ReferenceEdge> edgeItr = edgesWithNewBeta.iterator();
506 while( edgeItr.hasNext() ) {
507 edgeItr.next().applyBetaNew();
512 public void assignTempEqualToParamAlloc(TempDescriptor td,
514 Integer paramIndex) {
517 LabelNode lnParam = getLabelNodeFromTemp(td);
518 HeapRegionNode hrn = createNewHeapRegionNode(null,
525 "param" + paramIndex);
527 // this is a non-program-accessible label that picks up beta
528 // info to be used for fixing a caller of this method
529 TempDescriptor tdParamQ = new TempDescriptor(td+"specialQ");
530 LabelNode lnParamQ = getLabelNodeFromTemp(tdParamQ);
532 // keep track of heap regions that were created for
533 // parameter labels, the index of the parameter they
534 // are for is important when resolving method calls
535 Integer newID = hrn.getID();
536 assert !id2paramIndex.containsKey(newID);
537 assert !id2paramIndex.containsValue(paramIndex);
538 id2paramIndex.put(newID, paramIndex);
539 paramIndex2id.put(paramIndex, newID);
540 paramIndex2tdQ.put(paramIndex, tdParamQ);
542 ReachabilitySet beta = new ReachabilitySet(new TokenTuple(newID,
544 TokenTuple.ARITY_ONE) );
546 // heap regions for parameters are always multiple object (see above)
547 // and have a reference to themselves, because we can't know the
548 // structure of memory that is passed into the method. We're assuming
551 ReferenceEdge edgeFromLabel =
552 new ReferenceEdge(lnParam, hrn, null, false, beta);
554 ReferenceEdge edgeFromLabelQ =
555 new ReferenceEdge(lnParamQ, hrn, null, false, beta);
557 ReferenceEdge edgeReflexive =
558 new ReferenceEdge(hrn, hrn, null, true, beta);
560 addReferenceEdge(lnParam, hrn, edgeFromLabel);
561 addReferenceEdge(lnParamQ, hrn, edgeFromLabelQ);
562 addReferenceEdge(hrn, hrn, edgeReflexive);
566 public void assignReturnEqualToTemp(TempDescriptor x) {
568 LabelNode lnR = getLabelNodeFromTemp(tdReturn);
569 LabelNode lnX = getLabelNodeFromTemp(x);
571 clearReferenceEdgesFrom(lnR, null, true);
573 Iterator<ReferenceEdge> itrXhrn = lnX.iteratorToReferencees();
574 while( itrXhrn.hasNext() ) {
575 ReferenceEdge edgeX = itrXhrn.next();
576 HeapRegionNode referencee = edgeX.getDst();
577 ReferenceEdge edgeNew = edgeX.copy();
580 addReferenceEdge(lnR, referencee, edgeNew);
585 public void assignTempEqualToNewAlloc(TempDescriptor x,
592 // after the age operation the newest (or zero-ith oldest)
593 // node associated with the allocation site should have
594 // no references to it as if it were a newly allocated
595 // heap region, so make a reference to it to complete
598 Integer idNewest = as.getIthOldest(0);
599 HeapRegionNode hrnNewest = id2hrn.get(idNewest);
600 assert hrnNewest != null;
602 LabelNode lnX = getLabelNodeFromTemp(x);
603 clearReferenceEdgesFrom(lnX, null, true);
605 ReferenceEdge edgeNew =
606 new ReferenceEdge(lnX, hrnNewest, null, false, hrnNewest.getAlpha() );
608 addReferenceEdge(lnX, hrnNewest, edgeNew);
612 // use the allocation site (unique to entire analysis) to
613 // locate the heap region nodes in this ownership graph
614 // that should be aged. The process models the allocation
615 // of new objects and collects all the oldest allocations
616 // in a summary node to allow for a finite analysis
618 // There is an additional property of this method. After
619 // running it on a particular ownership graph (many graphs
620 // may have heap regions related to the same allocation site)
621 // the heap region node objects in this ownership graph will be
622 // allocated. Therefore, after aging a graph for an allocation
623 // site, attempts to retrieve the heap region nodes using the
624 // integer id's contained in the allocation site should always
625 // return non-null heap regions.
626 public void age(AllocationSite as) {
628 // aging adds this allocation site to the graph's
629 // list of sites that exist in the graph, or does
630 // nothing if the site is already in the list
631 allocationSites.add(as);
633 // get the summary node for the allocation site in the context
634 // of this particular ownership graph
635 HeapRegionNode hrnSummary = getSummaryNode(as);
637 // merge oldest node into summary
638 Integer idK = as.getOldest();
639 HeapRegionNode hrnK = id2hrn.get(idK);
640 mergeIntoSummary(hrnK, hrnSummary);
642 // move down the line of heap region nodes
643 // clobbering the ith and transferring all references
644 // to and from i-1 to node i. Note that this clobbers
645 // the oldest node (hrnK) that was just merged into
647 for( int i = allocationDepth - 1; i > 0; --i ) {
649 // move references from the i-1 oldest to the ith oldest
650 Integer idIth = as.getIthOldest(i);
651 HeapRegionNode hrnI = id2hrn.get(idIth);
652 Integer idImin1th = as.getIthOldest(i - 1);
653 HeapRegionNode hrnImin1 = id2hrn.get(idImin1th);
655 transferOnto(hrnImin1, hrnI);
658 // as stated above, the newest node should have had its
659 // references moved over to the second oldest, so we wipe newest
660 // in preparation for being the new object to assign something to
661 Integer id0th = as.getIthOldest(0);
662 HeapRegionNode hrn0 = id2hrn.get(id0th);
665 // clear all references in and out of newest node
666 clearReferenceEdgesFrom(hrn0, null, true);
667 clearReferenceEdgesTo(hrn0, null, true);
670 // now tokens in reachability sets need to "age" also
671 Iterator itrAllLabelNodes = td2ln.entrySet().iterator();
672 while( itrAllLabelNodes.hasNext() ) {
673 Map.Entry me = (Map.Entry)itrAllLabelNodes.next();
674 LabelNode ln = (LabelNode) me.getValue();
676 Iterator<ReferenceEdge> itrEdges = ln.iteratorToReferencees();
677 while( itrEdges.hasNext() ) {
678 ageTokens(as, itrEdges.next() );
682 Iterator itrAllHRNodes = id2hrn.entrySet().iterator();
683 while( itrAllHRNodes.hasNext() ) {
684 Map.Entry me = (Map.Entry)itrAllHRNodes.next();
685 HeapRegionNode hrnToAge = (HeapRegionNode) me.getValue();
687 ageTokens(as, hrnToAge);
689 Iterator<ReferenceEdge> itrEdges = hrnToAge.iteratorToReferencees();
690 while( itrEdges.hasNext() ) {
691 ageTokens(as, itrEdges.next() );
696 // after tokens have been aged, reset newest node's reachability
697 if( hrn0.isFlagged() ) {
698 hrn0.setAlpha(new ReachabilitySet(new TokenTupleSet(
704 hrn0.setAlpha(new ReachabilitySet(new TokenTupleSet()
711 protected HeapRegionNode getSummaryNode(AllocationSite as) {
713 Integer idSummary = as.getSummary();
714 HeapRegionNode hrnSummary = id2hrn.get(idSummary);
716 // If this is null then we haven't touched this allocation site
717 // in the context of the current ownership graph, so allocate
718 // heap region nodes appropriate for the entire allocation site.
719 // This should only happen once per ownership graph per allocation site,
720 // and a particular integer id can be used to locate the heap region
721 // in different ownership graphs that represents the same part of an
723 if( hrnSummary == null ) {
725 boolean hasFlags = false;
726 if( as.getType().isClass() ) {
727 hasFlags = as.getType().getClassDesc().hasFlags();
730 hrnSummary = createNewHeapRegionNode(idSummary,
737 as + "\\n" + as.getType() + "\\nsummary");
739 for( int i = 0; i < as.getAllocationDepth(); ++i ) {
740 Integer idIth = as.getIthOldest(i);
741 assert !id2hrn.containsKey(idIth);
742 createNewHeapRegionNode(idIth,
749 as + "\\n" + as.getType() + "\\n" + i + " oldest");
757 protected HeapRegionNode getShadowSummaryNode(AllocationSite as) {
759 Integer idShadowSummary = as.getSummaryShadow();
760 HeapRegionNode hrnShadowSummary = id2hrn.get(idShadowSummary);
762 if( hrnShadowSummary == null ) {
764 boolean hasFlags = false;
765 if( as.getType().isClass() ) {
766 hasFlags = as.getType().getClassDesc().hasFlags();
769 hrnShadowSummary = createNewHeapRegionNode(idShadowSummary,
776 as + "\\n" + as.getType() + "\\nshadowSum");
778 for( int i = 0; i < as.getAllocationDepth(); ++i ) {
779 Integer idShadowIth = as.getIthOldestShadow(i);
780 assert !id2hrn.containsKey(idShadowIth);
781 createNewHeapRegionNode(idShadowIth,
788 as + "\\n" + as.getType() + "\\n" + i + " shadow");
792 return hrnShadowSummary;
796 protected void mergeIntoSummary(HeapRegionNode hrn, HeapRegionNode hrnSummary) {
797 assert hrnSummary.isNewSummary();
799 // transfer references _from_ hrn over to hrnSummary
800 Iterator<ReferenceEdge> itrReferencee = hrn.iteratorToReferencees();
801 while( itrReferencee.hasNext() ) {
802 ReferenceEdge edge = itrReferencee.next();
803 ReferenceEdge edgeMerged = edge.copy();
804 edgeMerged.setSrc(hrnSummary);
806 HeapRegionNode hrnReferencee = edge.getDst();
807 ReferenceEdge edgeSummary = hrnSummary.getReferenceTo(hrnReferencee, edge.getFieldDesc() );
809 if( edgeSummary == null ) {
810 // the merge is trivial, nothing to be done
812 // otherwise an edge from the referencer to hrnSummary exists already
813 // and the edge referencer->hrn should be merged with it
814 edgeMerged.setBeta(edgeMerged.getBeta().union(edgeSummary.getBeta() ) );
817 addReferenceEdge(hrnSummary, hrnReferencee, edgeMerged);
820 // next transfer references _to_ hrn over to hrnSummary
821 Iterator<ReferenceEdge> itrReferencer = hrn.iteratorToReferencers();
822 while( itrReferencer.hasNext() ) {
823 ReferenceEdge edge = itrReferencer.next();
824 ReferenceEdge edgeMerged = edge.copy();
825 edgeMerged.setDst(hrnSummary);
827 OwnershipNode onReferencer = edge.getSrc();
828 ReferenceEdge edgeSummary = onReferencer.getReferenceTo(hrnSummary, edge.getFieldDesc() );
830 if( edgeSummary == null ) {
831 // the merge is trivial, nothing to be done
833 // otherwise an edge from the referencer to alpha_S exists already
834 // and the edge referencer->alpha_K should be merged with it
835 edgeMerged.setBeta(edgeMerged.getBeta().union(edgeSummary.getBeta() ) );
838 addReferenceEdge(onReferencer, hrnSummary, edgeMerged);
841 // then merge hrn reachability into hrnSummary
842 hrnSummary.setAlpha(hrnSummary.getAlpha().union(hrn.getAlpha() ) );
846 protected void transferOnto(HeapRegionNode hrnA, HeapRegionNode hrnB) {
848 // clear references in and out of node i
849 clearReferenceEdgesFrom(hrnB, null, true);
850 clearReferenceEdgesTo(hrnB, null, true);
852 // copy each edge in and out of A to B
853 Iterator<ReferenceEdge> itrReferencee = hrnA.iteratorToReferencees();
854 while( itrReferencee.hasNext() ) {
855 ReferenceEdge edge = itrReferencee.next();
856 HeapRegionNode hrnReferencee = edge.getDst();
857 ReferenceEdge edgeNew = edge.copy();
858 edgeNew.setSrc(hrnB);
860 addReferenceEdge(hrnB, hrnReferencee, edgeNew);
863 Iterator<ReferenceEdge> itrReferencer = hrnA.iteratorToReferencers();
864 while( itrReferencer.hasNext() ) {
865 ReferenceEdge edge = itrReferencer.next();
866 OwnershipNode onReferencer = edge.getSrc();
867 ReferenceEdge edgeNew = edge.copy();
868 edgeNew.setDst(hrnB);
870 addReferenceEdge(onReferencer, hrnB, edgeNew);
873 // replace hrnB reachability with hrnA's
874 hrnB.setAlpha(hrnA.getAlpha() );
878 protected void ageTokens(AllocationSite as, ReferenceEdge edge) {
879 edge.setBeta(edge.getBeta().ageTokens(as) );
882 protected void ageTokens(AllocationSite as, HeapRegionNode hrn) {
883 hrn.setAlpha(hrn.getAlpha().ageTokens(as) );
887 public void resolveMethodCall(FlatCall fc,
890 OwnershipGraph ogCallee) {
892 // define rewrite rules and other structures to organize
893 // data by parameter/argument index
894 Hashtable<Integer, ReachabilitySet> paramIndex2rewriteH =
895 new Hashtable<Integer, ReachabilitySet>();
897 Hashtable<Integer, ReachabilitySet> paramIndex2rewriteJ =
898 new Hashtable<Integer, ReachabilitySet>();
900 Hashtable<Integer, ReachabilitySet> paramIndex2rewriteK =
901 new Hashtable<Integer, ReachabilitySet>();
903 Hashtable<Integer, ReachabilitySet> paramIndex2rewriteD =
904 new Hashtable<Integer, ReachabilitySet>();
906 // helpful structures
907 Hashtable<TokenTuple, Integer> paramToken2paramIndex =
908 new Hashtable<TokenTuple, Integer>();
910 Hashtable<Integer, TokenTuple> paramIndex2paramToken =
911 new Hashtable<Integer, TokenTuple>();
913 Hashtable<TokenTuple, Integer> paramTokenStar2paramIndex =
914 new Hashtable<TokenTuple, Integer>();
916 Hashtable<Integer, TokenTuple> paramIndex2paramTokenStar =
917 new Hashtable<Integer, TokenTuple>();
919 Hashtable<Integer, LabelNode> paramIndex2ln =
920 new Hashtable<Integer, LabelNode>();
922 Hashtable<Integer, HashSet<HeapRegionNode> > paramIndex2reachableCallerNodes =
923 new Hashtable<Integer, HashSet<HeapRegionNode> >();
926 // add a bogus entry with the identity rule for easy rewrite
927 // of new callee nodes and edges, doesn't belong to any parameter
928 Integer bogusID = new Integer(-1);
929 Integer bogusIndex = new Integer(-1);
930 TokenTuple bogusToken = new TokenTuple(bogusID, true, TokenTuple.ARITY_ONE);
931 TokenTuple bogusTokenStar = new TokenTuple(bogusID, true, TokenTuple.ARITY_MANY);
932 ReachabilitySet rsIdentity =
933 new ReachabilitySet(new TokenTupleSet(bogusToken).makeCanonical() ).makeCanonical();
935 paramIndex2rewriteH.put(bogusIndex, rsIdentity);
936 paramIndex2rewriteJ.put(bogusIndex, rsIdentity);
937 paramToken2paramIndex.put(bogusToken, bogusIndex);
938 paramIndex2paramToken.put(bogusIndex, bogusToken);
939 paramTokenStar2paramIndex.put(bogusTokenStar, bogusIndex);
940 paramIndex2paramTokenStar.put(bogusIndex, bogusTokenStar);
943 for( int i = 0; i < fm.numParameters(); ++i ) {
944 Integer paramIndex = new Integer(i);
946 assert ogCallee.paramIndex2id.containsKey(paramIndex);
947 Integer idParam = ogCallee.paramIndex2id.get(paramIndex);
949 assert ogCallee.id2hrn.containsKey(idParam);
950 HeapRegionNode hrnParam = ogCallee.id2hrn.get(idParam);
951 assert hrnParam != null;
952 paramIndex2rewriteH.put(paramIndex,
954 toShadowTokens(ogCallee, hrnParam.getAlpha() )
957 ReferenceEdge edgeReflexive_i = hrnParam.getReferenceTo(hrnParam, null);
958 assert edgeReflexive_i != null;
959 paramIndex2rewriteJ.put(paramIndex,
960 toShadowTokens(ogCallee, edgeReflexive_i.getBeta() )
963 TempDescriptor tdParamQ = ogCallee.paramIndex2tdQ.get(paramIndex);
964 assert tdParamQ != null;
965 LabelNode lnParamQ = ogCallee.td2ln.get(tdParamQ);
966 assert lnParamQ != null;
967 ReferenceEdge edgeSpecialQ_i = lnParamQ.getReferenceTo(hrnParam, null);
968 assert edgeSpecialQ_i != null;
969 paramIndex2rewriteK.put(paramIndex,
970 toShadowTokens(ogCallee, edgeSpecialQ_i.getBeta() )
973 TokenTuple p_i = new TokenTuple(hrnParam.getID(),
975 TokenTuple.ARITY_ONE).makeCanonical();
976 paramToken2paramIndex.put(p_i, paramIndex);
977 paramIndex2paramToken.put(paramIndex, p_i);
979 TokenTuple p_i_star = new TokenTuple(hrnParam.getID(),
981 TokenTuple.ARITY_MANY).makeCanonical();
982 paramTokenStar2paramIndex.put(p_i_star, paramIndex);
983 paramIndex2paramTokenStar.put(paramIndex, p_i_star);
985 // now depending on whether the callee is static or not
986 // we need to account for a "this" argument in order to
987 // find the matching argument in the caller context
988 TempDescriptor argTemp_i;
990 argTemp_i = fc.getArg(paramIndex);
992 if( paramIndex == 0 ) {
993 argTemp_i = fc.getThis();
995 argTemp_i = fc.getArg(paramIndex - 1);
999 // in non-static methods there is a "this" pointer
1000 // that should be taken into account
1002 assert fc.numArgs() == fm.numParameters();
1004 assert fc.numArgs() + 1 == fm.numParameters();
1007 LabelNode argLabel_i = getLabelNodeFromTemp(argTemp_i);
1008 paramIndex2ln.put(paramIndex, argLabel_i);
1010 ReachabilitySet D_i = new ReachabilitySet().makeCanonical();
1011 Iterator<ReferenceEdge> edgeItr = argLabel_i.iteratorToReferencees();
1012 while( edgeItr.hasNext() ) {
1013 ReferenceEdge edge = edgeItr.next();
1014 D_i = D_i.union(edge.getBeta() );
1017 D_i = D_i.exhaustiveArityCombinations();
1019 paramIndex2rewriteD.put(paramIndex, D_i);
1023 HashSet<HeapRegionNode> nodesWithNewAlpha = new HashSet<HeapRegionNode>();
1024 HashSet<ReferenceEdge> edgesWithNewBeta = new HashSet<ReferenceEdge>();
1026 HashSet<ReferenceEdge> edgesReachable = new HashSet<ReferenceEdge>();
1027 HashSet<ReferenceEdge> edgesUpstream = new HashSet<ReferenceEdge>();
1029 Iterator lnArgItr = paramIndex2ln.entrySet().iterator();
1030 while( lnArgItr.hasNext() ) {
1031 Map.Entry me = (Map.Entry)lnArgItr.next();
1032 Integer index = (Integer) me.getKey();
1033 LabelNode lnArg_i = (LabelNode) me.getValue();
1035 // rewrite alpha for the nodes reachable from argument label i
1036 HashSet<HeapRegionNode> reachableNodes = new HashSet<HeapRegionNode>();
1037 HashSet<HeapRegionNode> todoNodes = new HashSet<HeapRegionNode>();
1039 // to find all reachable nodes, start with label referencees
1040 Iterator<ReferenceEdge> edgeArgItr = lnArg_i.iteratorToReferencees();
1041 while( edgeArgItr.hasNext() ) {
1042 ReferenceEdge edge = edgeArgItr.next();
1043 todoNodes.add(edge.getDst() );
1046 // then follow links until all reachable nodes have been found
1047 while( !todoNodes.isEmpty() ) {
1048 HeapRegionNode hrn = todoNodes.iterator().next();
1049 todoNodes.remove(hrn);
1050 reachableNodes.add(hrn);
1052 Iterator<ReferenceEdge> edgeItr = hrn.iteratorToReferencees();
1053 while( edgeItr.hasNext() ) {
1054 ReferenceEdge edge = edgeItr.next();
1056 if( !reachableNodes.contains(edge.getDst() ) ) {
1057 todoNodes.add(edge.getDst() );
1063 paramIndex2reachableCallerNodes.put(index, reachableNodes);
1065 // now iterate over reachable nodes to update their alpha, and
1066 // classify edges found as "argument reachable" or "upstream"
1067 Iterator<HeapRegionNode> hrnItr = reachableNodes.iterator();
1068 while( hrnItr.hasNext() ) {
1069 HeapRegionNode hrn = hrnItr.next();
1071 rewriteCallerNodeAlpha(fm.numParameters(),
1074 paramIndex2rewriteH,
1075 paramIndex2rewriteD,
1076 paramIndex2paramToken,
1077 paramIndex2paramTokenStar);
1079 nodesWithNewAlpha.add(hrn);
1081 // look at all incoming edges to the reachable nodes
1082 // and sort them as edges reachable from the argument
1083 // label node, or upstream edges
1084 Iterator<ReferenceEdge> edgeItr = hrn.iteratorToReferencers();
1085 while( edgeItr.hasNext() ) {
1086 ReferenceEdge edge = edgeItr.next();
1088 OwnershipNode on = edge.getSrc();
1090 if( on instanceof LabelNode ) {
1092 LabelNode ln0 = (LabelNode) on;
1093 if( ln0.equals(lnArg_i) ) {
1094 edgesReachable.add(edge);
1096 edgesUpstream.add(edge);
1101 HeapRegionNode hrn0 = (HeapRegionNode) on;
1102 if( reachableNodes.contains(hrn0) ) {
1103 edgesReachable.add(edge);
1105 edgesUpstream.add(edge);
1111 // update reachable edges
1112 Iterator<ReferenceEdge> edgeReachableItr = edgesReachable.iterator();
1113 while( edgeReachableItr.hasNext() ) {
1114 ReferenceEdge edgeReachable = edgeReachableItr.next();
1116 rewriteCallerEdgeBeta(fm.numParameters(),
1119 paramIndex2rewriteJ,
1120 paramIndex2rewriteD,
1121 paramIndex2paramToken,
1122 paramIndex2paramTokenStar,
1126 edgesWithNewBeta.add(edgeReachable);
1129 // update upstream edges
1130 Hashtable<ReferenceEdge, ChangeTupleSet> edgeUpstreamPlannedChanges
1131 = new Hashtable<ReferenceEdge, ChangeTupleSet>();
1133 Iterator<ReferenceEdge> edgeUpstreamItr = edgesUpstream.iterator();
1134 while( edgeUpstreamItr.hasNext() ) {
1135 ReferenceEdge edgeUpstream = edgeUpstreamItr.next();
1137 rewriteCallerEdgeBeta(fm.numParameters(),
1140 paramIndex2rewriteK,
1141 paramIndex2rewriteD,
1142 paramIndex2paramToken,
1143 paramIndex2paramTokenStar,
1145 edgeUpstreamPlannedChanges);
1147 edgesWithNewBeta.add(edgeUpstream);
1150 propagateTokensOverEdges(edgesUpstream,
1151 edgeUpstreamPlannedChanges,
1156 // commit changes to alpha and beta
1157 Iterator<HeapRegionNode> nodeItr = nodesWithNewAlpha.iterator();
1158 while( nodeItr.hasNext() ) {
1159 nodeItr.next().applyAlphaNew();
1162 Iterator<ReferenceEdge> edgeItr = edgesWithNewBeta.iterator();
1163 while( edgeItr.hasNext() ) {
1164 edgeItr.next().applyBetaNew();
1168 // verify the existence of allocation sites and their
1169 // shadows from the callee in the context of this caller graph
1170 // then map allocated nodes of callee onto the caller shadows
1172 Iterator<AllocationSite> asItr = ogCallee.allocationSites.iterator();
1173 while( asItr.hasNext() ) {
1174 AllocationSite allocSite = asItr.next();
1175 HeapRegionNode hrnSummary = getSummaryNode(allocSite);
1177 // assert that the shadow nodes have no reference edges
1178 // because they're brand new to the graph, or last time
1179 // they were used they should have been cleared of edges
1180 HeapRegionNode hrnShadowSummary = getShadowSummaryNode(allocSite);
1181 assert hrnShadowSummary.getNumReferencers() == 0;
1182 assert hrnShadowSummary.getNumReferencees() == 0;
1184 // then bring g_ij onto g'_ij and rewrite
1185 transferOnto(hrnSummary, hrnShadowSummary);
1187 HeapRegionNode hrnSummaryCallee = ogCallee.getSummaryNode(allocSite);
1188 hrnShadowSummary.setAlpha(toShadowTokens(ogCallee, hrnSummaryCallee.getAlpha() ) );
1190 // shadow nodes only are touched by a rewrite one time,
1191 // so rewrite and immediately commit--and they don't belong
1192 // to a particular parameter, so use a bogus param index
1193 // that pulls a self-rewrite out of H
1194 rewriteCallerNodeAlpha(fm.numParameters(),
1197 paramIndex2rewriteH,
1198 paramIndex2rewriteD,
1199 paramIndex2paramToken,
1200 paramIndex2paramTokenStar);
1202 hrnShadowSummary.applyAlphaNew();
1205 for( int i = 0; i < allocSite.getAllocationDepth(); ++i ) {
1206 Integer idIth = allocSite.getIthOldest(i);
1207 assert id2hrn.containsKey(idIth);
1208 HeapRegionNode hrnIth = id2hrn.get(idIth);
1210 Integer idShadowIth = -(allocSite.getIthOldest(i));
1211 assert id2hrn.containsKey(idShadowIth);
1212 HeapRegionNode hrnIthShadow = id2hrn.get(idShadowIth);
1213 assert hrnIthShadow.getNumReferencers() == 0;
1214 assert hrnIthShadow.getNumReferencees() == 0;
1216 transferOnto(hrnIth, hrnIthShadow);
1218 assert ogCallee.id2hrn.containsKey(idIth);
1219 HeapRegionNode hrnIthCallee = ogCallee.id2hrn.get(idIth);
1220 hrnIthShadow.setAlpha(toShadowTokens(ogCallee, hrnIthCallee.getAlpha() ) );
1222 rewriteCallerNodeAlpha(fm.numParameters(),
1225 paramIndex2rewriteH,
1226 paramIndex2rewriteD,
1227 paramIndex2paramToken,
1228 paramIndex2paramTokenStar);
1230 hrnIthShadow.applyAlphaNew();
1235 // for every heap region->heap region edge in the
1236 // callee graph, create the matching edge or edges
1237 // in the caller graph
1238 Set sCallee = ogCallee.id2hrn.entrySet();
1239 Iterator iCallee = sCallee.iterator();
1240 while( iCallee.hasNext() ) {
1241 Map.Entry meCallee = (Map.Entry)iCallee.next();
1242 Integer idCallee = (Integer) meCallee.getKey();
1243 HeapRegionNode hrnCallee = (HeapRegionNode) meCallee.getValue();
1245 Iterator<ReferenceEdge> heapRegionsItrCallee = hrnCallee.iteratorToReferencees();
1246 while( heapRegionsItrCallee.hasNext() ) {
1247 ReferenceEdge edgeCallee = heapRegionsItrCallee.next();
1248 HeapRegionNode hrnChildCallee = edgeCallee.getDst();
1249 Integer idChildCallee = hrnChildCallee.getID();
1251 // only address this edge if it is not a special reflexive edge
1252 if( !edgeCallee.isInitialParamReflexive() ) {
1254 // now we know that in the callee method's ownership graph
1255 // there is a heap region->heap region reference edge given
1256 // by heap region pointers:
1257 // hrnCallee -> heapChildCallee
1259 // or by the ownership-graph independent ID's:
1260 // idCallee -> idChildCallee
1262 // make the edge with src and dst so beta info is
1263 // calculated once, then copy it for each new edge in caller
1264 ReferenceEdge edgeNewInCallerTemplate = new ReferenceEdge(null,
1266 edgeCallee.getFieldDesc(),
1268 toShadowTokens(ogCallee, edgeCallee.getBeta() )
1270 rewriteCallerEdgeBeta(fm.numParameters(),
1272 edgeNewInCallerTemplate,
1273 paramIndex2rewriteJ,
1274 paramIndex2rewriteD,
1275 paramIndex2paramToken,
1276 paramIndex2paramTokenStar,
1280 edgeNewInCallerTemplate.applyBetaNew();
1283 // So now make a set of possible source heaps in the caller graph
1284 // and a set of destination heaps in the caller graph, and make
1285 // a reference edge in the caller for every possible (src,dst) pair
1286 HashSet<HeapRegionNode> possibleCallerSrcs =
1287 getHRNSetThatPossiblyMapToCalleeHRN(ogCallee,
1288 (HeapRegionNode) edgeCallee.getSrc(),
1289 paramIndex2reachableCallerNodes);
1291 HashSet<HeapRegionNode> possibleCallerDsts =
1292 getHRNSetThatPossiblyMapToCalleeHRN(ogCallee,
1293 edgeCallee.getDst(),
1294 paramIndex2reachableCallerNodes);
1297 // make every possible pair of {srcSet} -> {dstSet} edges in the caller
1298 Iterator srcItr = possibleCallerSrcs.iterator();
1299 while( srcItr.hasNext() ) {
1300 HeapRegionNode src = (HeapRegionNode) srcItr.next();
1302 if( !hasMatchingField(src, edgeCallee) ) {
1303 // prune this source node possibility
1307 Iterator dstItr = possibleCallerDsts.iterator();
1308 while( dstItr.hasNext() ) {
1309 HeapRegionNode dst = (HeapRegionNode) dstItr.next();
1311 if( !hasMatchingType(edgeCallee, dst) ) {
1316 // otherwise the caller src and dst pair can match the edge, so make it
1317 ReferenceEdge edgeNewInCaller = edgeNewInCallerTemplate.copy();
1318 edgeNewInCaller.setSrc(src);
1319 edgeNewInCaller.setDst(dst);
1321 ReferenceEdge edgeExisting = src.getReferenceTo(dst, edgeNewInCaller.getFieldDesc() );
1322 if( edgeExisting == null ) {
1323 // if this edge doesn't exist in the caller, create it
1324 addReferenceEdge(src, dst, edgeNewInCaller);
1326 // if it already exists, merge with it
1327 edgeExisting.setBeta(edgeExisting.getBeta().union(edgeNewInCaller.getBeta() ) );
1336 // return value may need to be assigned in caller
1337 if( fc.getReturnTemp() != null ) {
1339 LabelNode lnLhsCaller = getLabelNodeFromTemp(fc.getReturnTemp() );
1340 clearReferenceEdgesFrom(lnLhsCaller, null, true);
1342 LabelNode lnReturnCallee = ogCallee.getLabelNodeFromTemp(tdReturn);
1343 Iterator<ReferenceEdge> edgeCalleeItr = lnReturnCallee.iteratorToReferencees();
1344 while( edgeCalleeItr.hasNext() ) {
1345 ReferenceEdge edgeCallee = edgeCalleeItr.next();
1347 ReferenceEdge edgeNewInCallerTemplate = new ReferenceEdge(null,
1349 edgeCallee.getFieldDesc(),
1351 toShadowTokens(ogCallee, edgeCallee.getBeta() )
1353 rewriteCallerEdgeBeta(fm.numParameters(),
1355 edgeNewInCallerTemplate,
1356 paramIndex2rewriteJ,
1357 paramIndex2rewriteD,
1358 paramIndex2paramToken,
1359 paramIndex2paramTokenStar,
1363 edgeNewInCallerTemplate.applyBetaNew();
1366 HashSet<HeapRegionNode> assignCallerRhs =
1367 getHRNSetThatPossiblyMapToCalleeHRN(ogCallee,
1368 edgeCallee.getDst(),
1369 paramIndex2reachableCallerNodes);
1371 Iterator<HeapRegionNode> itrHrn = assignCallerRhs.iterator();
1372 while( itrHrn.hasNext() ) {
1373 HeapRegionNode hrnCaller = itrHrn.next();
1375 if( !hasMatchingType(edgeCallee, hrnCaller) ) {
1380 // otherwise caller node can match callee edge, so make it
1381 ReferenceEdge edgeNewInCaller = edgeNewInCallerTemplate.copy();
1382 edgeNewInCaller.setSrc(lnLhsCaller);
1383 edgeNewInCaller.setDst(hrnCaller);
1385 ReferenceEdge edgeExisting = lnLhsCaller.getReferenceTo(hrnCaller, edgeNewInCaller.getFieldDesc() );
1386 if( edgeExisting == null ) {
1388 // if this edge doesn't exist in the caller, create it
1389 addReferenceEdge(lnLhsCaller, hrnCaller, edgeNewInCaller);
1391 // if it already exists, merge with it
1392 edgeExisting.setBeta(edgeExisting.getBeta().union(edgeNewInCaller.getBeta() ) );
1399 // merge the shadow nodes of allocation sites back down to normal capacity
1400 Iterator<AllocationSite> allocItr = ogCallee.allocationSites.iterator();
1401 while( allocItr.hasNext() ) {
1402 AllocationSite as = allocItr.next();
1404 // first age each allocation site enough times to make room for the shadow nodes
1405 for( int i = 0; i < as.getAllocationDepth(); ++i ) {
1409 // then merge the shadow summary into the normal summary
1410 HeapRegionNode hrnSummary = getSummaryNode(as);
1411 assert hrnSummary != null;
1413 HeapRegionNode hrnSummaryShadow = getShadowSummaryNode(as);
1414 assert hrnSummaryShadow != null;
1416 mergeIntoSummary(hrnSummaryShadow, hrnSummary);
1418 // then clear off after merge
1419 clearReferenceEdgesFrom(hrnSummaryShadow, null, true);
1420 clearReferenceEdgesTo(hrnSummaryShadow, null, true);
1421 hrnSummaryShadow.setAlpha(new ReachabilitySet().makeCanonical() );
1423 // then transplant shadow nodes onto the now clean normal nodes
1424 for( int i = 0; i < as.getAllocationDepth(); ++i ) {
1426 Integer idIth = as.getIthOldest(i);
1427 HeapRegionNode hrnIth = id2hrn.get(idIth);
1429 Integer idIthShadow = as.getIthOldestShadow(i);
1430 HeapRegionNode hrnIthShadow = id2hrn.get(idIthShadow);
1432 transferOnto(hrnIthShadow, hrnIth);
1434 // clear off shadow nodes after transfer
1435 clearReferenceEdgesFrom(hrnIthShadow, null, true);
1436 clearReferenceEdgesTo(hrnIthShadow, null, true);
1437 hrnIthShadow.setAlpha(new ReachabilitySet().makeCanonical() );
1440 // finally, globally change shadow tokens into normal tokens
1441 Iterator itrAllLabelNodes = td2ln.entrySet().iterator();
1442 while( itrAllLabelNodes.hasNext() ) {
1443 Map.Entry me = (Map.Entry)itrAllLabelNodes.next();
1444 LabelNode ln = (LabelNode) me.getValue();
1446 Iterator<ReferenceEdge> itrEdges = ln.iteratorToReferencees();
1447 while( itrEdges.hasNext() ) {
1448 unshadowTokens(as, itrEdges.next() );
1452 Iterator itrAllHRNodes = id2hrn.entrySet().iterator();
1453 while( itrAllHRNodes.hasNext() ) {
1454 Map.Entry me = (Map.Entry)itrAllHRNodes.next();
1455 HeapRegionNode hrnToAge = (HeapRegionNode) me.getValue();
1457 unshadowTokens(as, hrnToAge);
1459 Iterator<ReferenceEdge> itrEdges = hrnToAge.iteratorToReferencees();
1460 while( itrEdges.hasNext() ) {
1461 unshadowTokens(as, itrEdges.next() );
1468 protected boolean hasMatchingField(HeapRegionNode src, ReferenceEdge edge) {
1470 // if no allocation site, then it's a match-everything region
1471 AllocationSite asSrc = src.getAllocationSite();
1472 if( asSrc == null ) {
1476 TypeDescriptor tdSrc = asSrc.getType();
1477 assert tdSrc != null;
1479 // if it's not a class, it doesn't have any fields to match
1480 if( !tdSrc.isClass() ) {
1484 Iterator fieldsSrcItr = tdSrc.getClassDesc().getFields();
1485 while( fieldsSrcItr.hasNext() ) {
1486 FieldDescriptor fd = (FieldDescriptor) fieldsSrcItr.next();
1487 if( fd == edge.getFieldDesc() ) {
1492 // otherwise it is a class with fields
1493 // but we didn't find a match
1498 protected boolean hasMatchingType(ReferenceEdge edge, HeapRegionNode dst) {
1500 // if the region has no type, matches everything
1501 AllocationSite asDst = dst.getAllocationSite();
1502 if( asDst == null ) {
1506 TypeDescriptor tdDst = asDst.getType();
1507 assert tdDst != null;
1509 // if the type is not a class don't match because
1510 // primitives are copied, no memory aliases
1511 ClassDescriptor cdDst = tdDst.getClassDesc();
1512 if( cdDst == null ) {
1516 // if the field is null, it matches everything
1517 FieldDescriptor fd = edge.getFieldDesc();
1521 TypeDescriptor tdFd = fd.getType();
1522 assert tdFd != null;
1524 return typeUtil.isSuperorType(tdFd, tdDst);
1529 protected void unshadowTokens(AllocationSite as, ReferenceEdge edge) {
1530 edge.setBeta(edge.getBeta().unshadowTokens(as) );
1533 protected void unshadowTokens(AllocationSite as, HeapRegionNode hrn) {
1534 hrn.setAlpha(hrn.getAlpha().unshadowTokens(as) );
1538 private ReachabilitySet toShadowTokens(OwnershipGraph ogCallee,
1539 ReachabilitySet rsIn) {
1541 ReachabilitySet rsOut = new ReachabilitySet(rsIn);
1543 Iterator<AllocationSite> allocItr = ogCallee.allocationSites.iterator();
1544 while( allocItr.hasNext() ) {
1545 AllocationSite as = allocItr.next();
1547 rsOut = rsOut.toShadowTokens(as);
1550 return rsOut.makeCanonical();
1554 private void rewriteCallerNodeAlpha(int numParameters,
1557 Hashtable<Integer, ReachabilitySet> paramIndex2rewriteH,
1558 Hashtable<Integer, ReachabilitySet> paramIndex2rewriteD,
1559 Hashtable<Integer, TokenTuple> paramIndex2paramToken,
1560 Hashtable<Integer, TokenTuple> paramIndex2paramTokenStar) {
1562 ReachabilitySet rules = paramIndex2rewriteH.get(paramIndex);
1563 assert rules != null;
1565 TokenTuple tokenToRewrite = paramIndex2paramToken.get(paramIndex);
1566 assert tokenToRewrite != null;
1568 ReachabilitySet r0 = new ReachabilitySet().makeCanonical();
1569 Iterator<TokenTupleSet> ttsItr = rules.iterator();
1570 while( ttsItr.hasNext() ) {
1571 TokenTupleSet tts = ttsItr.next();
1572 r0 = r0.union(tts.rewriteToken(tokenToRewrite,
1578 ReachabilitySet r1 = new ReachabilitySet().makeCanonical();
1579 ttsItr = r0.iterator();
1580 while( ttsItr.hasNext() ) {
1581 TokenTupleSet tts = ttsItr.next();
1582 r1 = r1.union(rewriteDpass(numParameters,
1585 paramIndex2rewriteD,
1586 paramIndex2paramToken,
1587 paramIndex2paramTokenStar) );
1590 hrn.setAlphaNew(hrn.getAlphaNew().union(r1) );
1594 private void rewriteCallerEdgeBeta(int numParameters,
1597 Hashtable<Integer, ReachabilitySet> paramIndex2rewriteJorK,
1598 Hashtable<Integer, ReachabilitySet> paramIndex2rewriteD,
1599 Hashtable<Integer, TokenTuple> paramIndex2paramToken,
1600 Hashtable<Integer, TokenTuple> paramIndex2paramTokenStar,
1601 boolean makeChangeSet,
1602 Hashtable<ReferenceEdge, ChangeTupleSet> edgePlannedChanges) {
1604 ReachabilitySet rules = paramIndex2rewriteJorK.get(paramIndex);
1605 assert rules != null;
1607 TokenTuple tokenToRewrite = paramIndex2paramToken.get(paramIndex);
1608 assert tokenToRewrite != null;
1610 ChangeTupleSet cts0 = new ChangeTupleSet().makeCanonical();
1612 Iterator<TokenTupleSet> ttsItr = rules.iterator();
1613 while( ttsItr.hasNext() ) {
1614 TokenTupleSet tts = ttsItr.next();
1616 Hashtable<TokenTupleSet, HashSet<TokenTupleSet> > forChangeSet =
1617 new Hashtable<TokenTupleSet, HashSet<TokenTupleSet> >();
1619 ReachabilitySet rTemp = tts.rewriteToken(tokenToRewrite,
1624 Iterator fcsItr = forChangeSet.entrySet().iterator();
1625 while( fcsItr.hasNext() ) {
1626 Map.Entry me = (Map.Entry)fcsItr.next();
1627 TokenTupleSet ttsMatch = (TokenTupleSet) me.getKey();
1628 HashSet<TokenTupleSet> ttsAddSet = (HashSet<TokenTupleSet>) me.getValue();
1629 Iterator<TokenTupleSet> ttsAddItr = ttsAddSet.iterator();
1630 while( ttsAddItr.hasNext() ) {
1631 TokenTupleSet ttsAdd = ttsAddItr.next();
1633 ChangeTuple ct = new ChangeTuple(ttsMatch,
1637 cts0 = cts0.union(ct);
1643 ReachabilitySet r1 = new ReachabilitySet().makeCanonical();
1644 ChangeTupleSet cts1 = new ChangeTupleSet().makeCanonical();
1646 Iterator<ChangeTuple> ctItr = cts0.iterator();
1647 while( ctItr.hasNext() ) {
1648 ChangeTuple ct = ctItr.next();
1650 ReachabilitySet rTemp = rewriteDpass(numParameters,
1653 paramIndex2rewriteD,
1654 paramIndex2paramToken,
1655 paramIndex2paramTokenStar
1657 r1 = r1.union(rTemp);
1659 if( makeChangeSet ) {
1660 assert edgePlannedChanges != null;
1662 Iterator<TokenTupleSet> ttsTempItr = rTemp.iterator();
1663 while( ttsTempItr.hasNext() ) {
1664 TokenTupleSet tts = ttsTempItr.next();
1666 ChangeTuple ctFinal = new ChangeTuple(ct.getSetToMatch(),
1670 cts1 = cts1.union(ctFinal);
1675 if( makeChangeSet ) {
1676 edgePlannedChanges.put(edge, cts1);
1679 edge.setBetaNew(edge.getBetaNew().union(r1) );
1683 private ReachabilitySet rewriteDpass(int numParameters,
1685 TokenTupleSet ttsIn,
1686 Hashtable<Integer, ReachabilitySet> paramIndex2rewriteD,
1687 Hashtable<Integer, TokenTuple> paramIndex2paramToken,
1688 Hashtable<Integer, TokenTuple> paramIndex2paramTokenStar) {
1690 ReachabilitySet rsOut = new ReachabilitySet().makeCanonical();
1692 boolean rewritten = false;
1694 for( int j = 0; j < numParameters; ++j ) {
1695 Integer paramIndexJ = new Integer(j);
1696 ReachabilitySet D_j = paramIndex2rewriteD.get(paramIndexJ);
1699 if( paramIndexJ != paramIndex ) {
1700 TokenTuple tokenToRewriteJ = paramIndex2paramToken.get(paramIndexJ);
1701 assert tokenToRewriteJ != null;
1702 if( ttsIn.containsTuple(tokenToRewriteJ) ) {
1703 ReachabilitySet r = ttsIn.rewriteToken(tokenToRewriteJ,
1707 Iterator<TokenTupleSet> ttsItr = r.iterator();
1708 while( ttsItr.hasNext() ) {
1709 TokenTupleSet tts = ttsItr.next();
1710 rsOut = rsOut.union(rewriteDpass(numParameters,
1713 paramIndex2rewriteD,
1714 paramIndex2paramToken,
1715 paramIndex2paramTokenStar) );
1721 TokenTuple tokenStarToRewriteJ = paramIndex2paramTokenStar.get(paramIndexJ);
1722 assert tokenStarToRewriteJ != null;
1723 if( ttsIn.containsTuple(tokenStarToRewriteJ) ) {
1724 ReachabilitySet r = ttsIn.rewriteToken(tokenStarToRewriteJ,
1728 Iterator<TokenTupleSet> ttsItr = r.iterator();
1729 while( ttsItr.hasNext() ) {
1730 TokenTupleSet tts = ttsItr.next();
1731 rsOut = rsOut.union(rewriteDpass(numParameters,
1734 paramIndex2rewriteD,
1735 paramIndex2paramToken,
1736 paramIndex2paramTokenStar) );
1743 rsOut = rsOut.union(ttsIn);
1750 private HashSet<HeapRegionNode>
1751 getHRNSetThatPossiblyMapToCalleeHRN(OwnershipGraph ogCallee,
1752 HeapRegionNode hrnCallee,
1753 Hashtable<Integer, HashSet<HeapRegionNode> > paramIndex2reachableCallerNodes
1756 HashSet<HeapRegionNode> possibleCallerHRNs = new HashSet<HeapRegionNode>();
1758 Integer paramIndexCallee = ogCallee.id2paramIndex.get(hrnCallee.getID() );
1760 if( paramIndexCallee == null ) {
1761 // this is a node allocated in the callee then and it has
1762 // exactly one shadow node in the caller to map to
1763 AllocationSite as = hrnCallee.getAllocationSite();
1766 int age = as.getAgeCategory(hrnCallee.getID() );
1767 assert age != AllocationSite.AGE_notInThisSite;
1770 if( age == AllocationSite.AGE_summary ) {
1771 idCaller = as.getSummaryShadow();
1772 } else if( age == AllocationSite.AGE_oldest ) {
1773 idCaller = as.getOldestShadow();
1775 assert age == AllocationSite.AGE_in_I;
1777 Integer I = as.getAge(hrnCallee.getID() );
1780 idCaller = as.getIthOldestShadow(I);
1783 assert id2hrn.containsKey(idCaller);
1784 HeapRegionNode hrnCaller = id2hrn.get(idCaller);
1785 possibleCallerHRNs.add(hrnCaller);
1788 // this is a node that was created to represent a parameter
1789 // so it maps to a whole mess of heap regions
1790 assert paramIndex2reachableCallerNodes.containsKey(paramIndexCallee);
1791 possibleCallerHRNs = paramIndex2reachableCallerNodes.get(paramIndexCallee);
1794 return possibleCallerHRNs;
1799 ////////////////////////////////////////////////////
1800 // in merge() and equals() methods the suffix A
1801 // represents the passed in graph and the suffix
1802 // B refers to the graph in this object
1803 // Merging means to take the incoming graph A and
1804 // merge it into B, so after the operation graph B
1805 // is the final result.
1806 ////////////////////////////////////////////////////
1807 public void merge(OwnershipGraph og) {
1813 mergeOwnershipNodes(og);
1814 mergeReferenceEdges(og);
1815 mergeId2paramIndex(og);
1816 mergeAllocationSites(og);
1820 protected void mergeOwnershipNodes(OwnershipGraph og) {
1821 Set sA = og.id2hrn.entrySet();
1822 Iterator iA = sA.iterator();
1823 while( iA.hasNext() ) {
1824 Map.Entry meA = (Map.Entry)iA.next();
1825 Integer idA = (Integer) meA.getKey();
1826 HeapRegionNode hrnA = (HeapRegionNode) meA.getValue();
1828 // if this graph doesn't have a node the
1829 // incoming graph has, allocate it
1830 if( !id2hrn.containsKey(idA) ) {
1831 HeapRegionNode hrnB = hrnA.copy();
1832 id2hrn.put(idA, hrnB);
1835 // otherwise this is a node present in both graphs
1836 // so make the new reachability set a union of the
1837 // nodes' reachability sets
1838 HeapRegionNode hrnB = id2hrn.get(idA);
1839 hrnB.setAlpha(hrnB.getAlpha().union(hrnA.getAlpha() ) );
1843 // now add any label nodes that are in graph B but
1845 sA = og.td2ln.entrySet();
1847 while( iA.hasNext() ) {
1848 Map.Entry meA = (Map.Entry)iA.next();
1849 TempDescriptor tdA = (TempDescriptor) meA.getKey();
1850 LabelNode lnA = (LabelNode) meA.getValue();
1852 // if the label doesn't exist in B, allocate and add it
1853 LabelNode lnB = getLabelNodeFromTemp(tdA);
1857 protected void mergeReferenceEdges(OwnershipGraph og) {
1860 Set sA = og.id2hrn.entrySet();
1861 Iterator iA = sA.iterator();
1862 while( iA.hasNext() ) {
1863 Map.Entry meA = (Map.Entry)iA.next();
1864 Integer idA = (Integer) meA.getKey();
1865 HeapRegionNode hrnA = (HeapRegionNode) meA.getValue();
1867 Iterator<ReferenceEdge> heapRegionsItrA = hrnA.iteratorToReferencees();
1868 while( heapRegionsItrA.hasNext() ) {
1869 ReferenceEdge edgeA = heapRegionsItrA.next();
1870 HeapRegionNode hrnChildA = edgeA.getDst();
1871 Integer idChildA = hrnChildA.getID();
1873 // at this point we know an edge in graph A exists
1874 // idA -> idChildA, does this exist in B?
1875 assert id2hrn.containsKey(idA);
1876 HeapRegionNode hrnB = id2hrn.get(idA);
1877 ReferenceEdge edgeToMerge = null;
1879 Iterator<ReferenceEdge> heapRegionsItrB = hrnB.iteratorToReferencees();
1880 while( heapRegionsItrB.hasNext() &&
1881 edgeToMerge == null ) {
1883 ReferenceEdge edgeB = heapRegionsItrB.next();
1884 HeapRegionNode hrnChildB = edgeB.getDst();
1885 Integer idChildB = hrnChildB.getID();
1887 // don't use the ReferenceEdge.equals() here because
1888 // we're talking about existence between graphs
1889 if( idChildB.equals(idChildA) &&
1890 edgeB.getFieldDesc() == edgeA.getFieldDesc() ) {
1891 edgeToMerge = edgeB;
1895 // if the edge from A was not found in B,
1897 if( edgeToMerge == null ) {
1898 assert id2hrn.containsKey(idChildA);
1899 HeapRegionNode hrnChildB = id2hrn.get(idChildA);
1900 edgeToMerge = edgeA.copy();
1901 edgeToMerge.setSrc(hrnB);
1902 edgeToMerge.setDst(hrnChildB);
1903 addReferenceEdge(hrnB, hrnChildB, edgeToMerge);
1905 // otherwise, the edge already existed in both graphs
1906 // so merge their reachability sets
1908 // just replace this beta set with the union
1909 assert edgeToMerge != null;
1910 edgeToMerge.setBeta(
1911 edgeToMerge.getBeta().union(edgeA.getBeta() )
1913 if( !edgeA.isInitialParamReflexive() ) {
1914 edgeToMerge.setIsInitialParamReflexive(false);
1920 // and then again with label nodes
1921 sA = og.td2ln.entrySet();
1923 while( iA.hasNext() ) {
1924 Map.Entry meA = (Map.Entry)iA.next();
1925 TempDescriptor tdA = (TempDescriptor) meA.getKey();
1926 LabelNode lnA = (LabelNode) meA.getValue();
1928 Iterator<ReferenceEdge> heapRegionsItrA = lnA.iteratorToReferencees();
1929 while( heapRegionsItrA.hasNext() ) {
1930 ReferenceEdge edgeA = heapRegionsItrA.next();
1931 HeapRegionNode hrnChildA = edgeA.getDst();
1932 Integer idChildA = hrnChildA.getID();
1934 // at this point we know an edge in graph A exists
1935 // tdA -> idChildA, does this exist in B?
1936 assert td2ln.containsKey(tdA);
1937 LabelNode lnB = td2ln.get(tdA);
1938 ReferenceEdge edgeToMerge = null;
1940 // labels never have edges with a field
1941 //assert edgeA.getFieldDesc() == null;
1943 Iterator<ReferenceEdge> heapRegionsItrB = lnB.iteratorToReferencees();
1944 while( heapRegionsItrB.hasNext() &&
1945 edgeToMerge == null ) {
1947 ReferenceEdge edgeB = heapRegionsItrB.next();
1948 HeapRegionNode hrnChildB = edgeB.getDst();
1949 Integer idChildB = hrnChildB.getID();
1951 // labels never have edges with a field
1952 //assert edgeB.getFieldDesc() == null;
1954 // don't use the ReferenceEdge.equals() here because
1955 // we're talking about existence between graphs
1956 if( idChildB.equals(idChildA) &&
1957 edgeB.getFieldDesc() == edgeA.getFieldDesc() ) {
1958 edgeToMerge = edgeB;
1962 // if the edge from A was not found in B,
1964 if( edgeToMerge == null ) {
1965 assert id2hrn.containsKey(idChildA);
1966 HeapRegionNode hrnChildB = id2hrn.get(idChildA);
1967 edgeToMerge = edgeA.copy();
1968 edgeToMerge.setSrc(lnB);
1969 edgeToMerge.setDst(hrnChildB);
1970 addReferenceEdge(lnB, hrnChildB, edgeToMerge);
1972 // otherwise, the edge already existed in both graphs
1973 // so merge their reachability sets
1975 // just replace this beta set with the union
1976 edgeToMerge.setBeta(
1977 edgeToMerge.getBeta().union(edgeA.getBeta() )
1979 if( !edgeA.isInitialParamReflexive() ) {
1980 edgeToMerge.setIsInitialParamReflexive(false);
1987 // you should only merge ownership graphs that have the
1988 // same number of parameters, or if one or both parameter
1989 // index tables are empty
1990 protected void mergeId2paramIndex(OwnershipGraph og) {
1991 if( id2paramIndex.size() == 0 ) {
1992 id2paramIndex = og.id2paramIndex;
1993 paramIndex2id = og.paramIndex2id;
1994 paramIndex2tdQ = og.paramIndex2tdQ;
1998 if( og.id2paramIndex.size() == 0 ) {
2002 assert id2paramIndex.size() == og.id2paramIndex.size();
2005 protected void mergeAllocationSites(OwnershipGraph og) {
2006 allocationSites.addAll(og.allocationSites);
2011 // it is necessary in the equals() member functions
2012 // to "check both ways" when comparing the data
2013 // structures of two graphs. For instance, if all
2014 // edges between heap region nodes in graph A are
2015 // present and equal in graph B it is not sufficient
2016 // to say the graphs are equal. Consider that there
2017 // may be edges in graph B that are not in graph A.
2018 // the only way to know that all edges in both graphs
2019 // are equally present is to iterate over both data
2020 // structures and compare against the other graph.
2021 public boolean equals(OwnershipGraph og) {
2027 if( !areHeapRegionNodesEqual(og) ) {
2031 if( !areLabelNodesEqual(og) ) {
2035 if( !areReferenceEdgesEqual(og) ) {
2039 if( !areId2paramIndexEqual(og) ) {
2043 // if everything is equal up to this point,
2044 // assert that allocationSites is also equal--
2045 // this data is redundant and kept for efficiency
2046 assert allocationSites.equals(og.allocationSites);
2051 protected boolean areHeapRegionNodesEqual(OwnershipGraph og) {
2053 if( !areallHRNinAalsoinBandequal(this, og) ) {
2057 if( !areallHRNinAalsoinBandequal(og, this) ) {
2064 static protected boolean areallHRNinAalsoinBandequal(OwnershipGraph ogA,
2065 OwnershipGraph ogB) {
2066 Set sA = ogA.id2hrn.entrySet();
2067 Iterator iA = sA.iterator();
2068 while( iA.hasNext() ) {
2069 Map.Entry meA = (Map.Entry)iA.next();
2070 Integer idA = (Integer) meA.getKey();
2071 HeapRegionNode hrnA = (HeapRegionNode) meA.getValue();
2073 if( !ogB.id2hrn.containsKey(idA) ) {
2077 HeapRegionNode hrnB = ogB.id2hrn.get(idA);
2078 if( !hrnA.equalsIncludingAlpha(hrnB) ) {
2087 protected boolean areLabelNodesEqual(OwnershipGraph og) {
2089 if( !areallLNinAalsoinBandequal(this, og) ) {
2093 if( !areallLNinAalsoinBandequal(og, this) ) {
2100 static protected boolean areallLNinAalsoinBandequal(OwnershipGraph ogA,
2101 OwnershipGraph ogB) {
2102 Set sA = ogA.td2ln.entrySet();
2103 Iterator iA = sA.iterator();
2104 while( iA.hasNext() ) {
2105 Map.Entry meA = (Map.Entry)iA.next();
2106 TempDescriptor tdA = (TempDescriptor) meA.getKey();
2108 if( !ogB.td2ln.containsKey(tdA) ) {
2117 protected boolean areReferenceEdgesEqual(OwnershipGraph og) {
2118 if( !areallREinAandBequal(this, og) ) {
2125 static protected boolean areallREinAandBequal(OwnershipGraph ogA,
2126 OwnershipGraph ogB) {
2128 // check all the heap region->heap region edges
2129 Set sA = ogA.id2hrn.entrySet();
2130 Iterator iA = sA.iterator();
2131 while( iA.hasNext() ) {
2132 Map.Entry meA = (Map.Entry)iA.next();
2133 Integer idA = (Integer) meA.getKey();
2134 HeapRegionNode hrnA = (HeapRegionNode) meA.getValue();
2136 // we should have already checked that the same
2137 // heap regions exist in both graphs
2138 assert ogB.id2hrn.containsKey(idA);
2140 if( !areallREfromAequaltoB(ogA, hrnA, ogB) ) {
2144 // then check every edge in B for presence in A, starting
2145 // from the same parent HeapRegionNode
2146 HeapRegionNode hrnB = ogB.id2hrn.get(idA);
2148 if( !areallREfromAequaltoB(ogB, hrnB, ogA) ) {
2153 // then check all the label->heap region edges
2154 sA = ogA.td2ln.entrySet();
2156 while( iA.hasNext() ) {
2157 Map.Entry meA = (Map.Entry)iA.next();
2158 TempDescriptor tdA = (TempDescriptor) meA.getKey();
2159 LabelNode lnA = (LabelNode) meA.getValue();
2161 // we should have already checked that the same
2162 // label nodes exist in both graphs
2163 assert ogB.td2ln.containsKey(tdA);
2165 if( !areallREfromAequaltoB(ogA, lnA, ogB) ) {
2169 // then check every edge in B for presence in A, starting
2170 // from the same parent LabelNode
2171 LabelNode lnB = ogB.td2ln.get(tdA);
2173 if( !areallREfromAequaltoB(ogB, lnB, ogA) ) {
2182 static protected boolean areallREfromAequaltoB(OwnershipGraph ogA,
2184 OwnershipGraph ogB) {
2186 Iterator<ReferenceEdge> itrA = onA.iteratorToReferencees();
2187 while( itrA.hasNext() ) {
2188 ReferenceEdge edgeA = itrA.next();
2189 HeapRegionNode hrnChildA = edgeA.getDst();
2190 Integer idChildA = hrnChildA.getID();
2192 assert ogB.id2hrn.containsKey(idChildA);
2194 // at this point we know an edge in graph A exists
2195 // onA -> idChildA, does this exact edge exist in B?
2196 boolean edgeFound = false;
2198 OwnershipNode onB = null;
2199 if( onA instanceof HeapRegionNode ) {
2200 HeapRegionNode hrnA = (HeapRegionNode) onA;
2201 onB = ogB.id2hrn.get(hrnA.getID() );
2203 LabelNode lnA = (LabelNode) onA;
2204 onB = ogB.td2ln.get(lnA.getTempDescriptor() );
2207 Iterator<ReferenceEdge> itrB = onB.iteratorToReferencees();
2208 while( itrB.hasNext() ) {
2209 ReferenceEdge edgeB = itrB.next();
2210 HeapRegionNode hrnChildB = edgeB.getDst();
2211 Integer idChildB = hrnChildB.getID();
2213 if( idChildA.equals(idChildB) &&
2214 edgeA.getFieldDesc() == edgeB.getFieldDesc() ) {
2216 // there is an edge in the right place with the right field,
2217 // but do they have the same attributes?
2218 if( edgeA.getBeta().equals(edgeB.getBeta() ) ) {
2236 protected boolean areId2paramIndexEqual(OwnershipGraph og) {
2237 return id2paramIndex.size() == og.id2paramIndex.size();
2241 public boolean hasPotentialAlias(Integer paramIndex1, Integer paramIndex2) {
2243 // get parameter's heap region
2244 assert paramIndex2id.containsKey(paramIndex1);
2245 Integer idParam1 = paramIndex2id.get(paramIndex1);
2247 assert id2hrn.containsKey(idParam1);
2248 HeapRegionNode hrnParam1 = id2hrn.get(idParam1);
2249 assert hrnParam1 != null;
2251 // get tokens for this parameter
2252 TokenTuple p1 = new TokenTuple(hrnParam1.getID(),
2254 TokenTuple.ARITY_ONE).makeCanonical();
2256 TokenTuple pStar1 = new TokenTuple(hrnParam1.getID(),
2258 TokenTuple.ARITY_MANY).makeCanonical();
2261 // get tokens for the other parameter
2262 assert paramIndex2id.containsKey(paramIndex2);
2263 Integer idParam2 = paramIndex2id.get(paramIndex2);
2265 assert id2hrn.containsKey(idParam2);
2266 HeapRegionNode hrnParam2 = id2hrn.get(idParam2);
2267 assert hrnParam2 != null;
2269 TokenTuple p2 = new TokenTuple(hrnParam2.getID(),
2271 TokenTuple.ARITY_ONE).makeCanonical();
2273 TokenTuple pStar2 = new TokenTuple(hrnParam2.getID(),
2275 TokenTuple.ARITY_MANY).makeCanonical();
2278 // get special label p_q for first parameter
2279 TempDescriptor tdParamQ1 = paramIndex2tdQ.get(paramIndex1);
2280 assert tdParamQ1 != null;
2281 LabelNode lnParamQ1 = td2ln.get(tdParamQ1);
2282 assert lnParamQ1 != null;
2284 // then get the edge from label q to parameter's hrn
2285 ReferenceEdge edgeSpecialQ1 = lnParamQ1.getReferenceTo(hrnParam1, null);
2286 assert edgeSpecialQ1 != null;
2288 // if the beta of this edge has tokens from both parameters in one
2289 // token tuple set, then there is a potential alias between them
2290 ReachabilitySet beta1 = edgeSpecialQ1.getBeta();
2291 assert beta1 != null;
2293 if( beta1.containsTupleSetWithBoth(p1, p2) ) {
2296 if( beta1.containsTupleSetWithBoth(pStar1, p2) ) {
2299 if( beta1.containsTupleSetWithBoth(p1, pStar2) ) {
2302 if( beta1.containsTupleSetWithBoth(pStar1, pStar2) ) {
2310 public boolean hasPotentialAlias(Integer paramIndex, AllocationSite as) {
2312 // get parameter's heap region
2313 assert paramIndex2id.containsKey(paramIndex);
2314 Integer idParam = paramIndex2id.get(paramIndex);
2316 assert id2hrn.containsKey(idParam);
2317 HeapRegionNode hrnParam = id2hrn.get(idParam);
2318 assert hrnParam != null;
2320 // get tokens for this parameter
2321 TokenTuple p = new TokenTuple(hrnParam.getID(),
2323 TokenTuple.ARITY_ONE).makeCanonical();
2325 TokenTuple pStar = new TokenTuple(hrnParam.getID(),
2327 TokenTuple.ARITY_MANY).makeCanonical();
2329 // get special label p_q
2330 TempDescriptor tdParamQ = paramIndex2tdQ.get(paramIndex);
2331 assert tdParamQ != null;
2332 LabelNode lnParamQ = td2ln.get(tdParamQ);
2333 assert lnParamQ != null;
2335 // then get the edge from label q to parameter's hrn
2336 ReferenceEdge edgeSpecialQ = lnParamQ.getReferenceTo(hrnParam, null);
2337 assert edgeSpecialQ != null;
2339 // look through this beta set for potential aliases
2340 ReachabilitySet beta = edgeSpecialQ.getBeta();
2341 assert beta != null;
2344 // get tokens for summary node
2345 TokenTuple gs = new TokenTuple(as.getSummary(),
2347 TokenTuple.ARITY_ONE).makeCanonical();
2349 TokenTuple gsStar = new TokenTuple(as.getSummary(),
2351 TokenTuple.ARITY_MANY).makeCanonical();
2353 if( beta.containsTupleSetWithBoth(p, gs) ) {
2356 if( beta.containsTupleSetWithBoth(pStar, gs) ) {
2359 if( beta.containsTupleSetWithBoth(p, gsStar) ) {
2362 if( beta.containsTupleSetWithBoth(pStar, gsStar) ) {
2366 // check for other nodes
2367 for( int i = 0; i < as.getAllocationDepth(); ++i ) {
2369 // the other nodes of an allocation site are single, no stars
2370 TokenTuple gi = new TokenTuple(as.getIthOldest(i),
2372 TokenTuple.ARITY_ONE).makeCanonical();
2374 if( beta.containsTupleSetWithBoth(p, gi) ) {
2377 if( beta.containsTupleSetWithBoth(pStar, gi) ) {
2386 public boolean hasPotentialAlias(AllocationSite as1, AllocationSite as2) {
2388 // get tokens for summary nodes
2389 TokenTuple gs1 = new TokenTuple(as1.getSummary(),
2391 TokenTuple.ARITY_ONE).makeCanonical();
2393 TokenTuple gsStar1 = new TokenTuple(as1.getSummary(),
2395 TokenTuple.ARITY_MANY).makeCanonical();
2397 // get summary node's alpha
2398 Integer idSum1 = as1.getSummary();
2399 assert id2hrn.containsKey(idSum1);
2400 HeapRegionNode hrnSum1 = id2hrn.get(idSum1);
2401 assert hrnSum1 != null;
2402 ReachabilitySet alphaSum1 = hrnSum1.getAlpha();
2403 assert alphaSum1 != null;
2406 // and for the other one
2407 TokenTuple gs2 = new TokenTuple(as2.getSummary(),
2409 TokenTuple.ARITY_ONE).makeCanonical();
2411 TokenTuple gsStar2 = new TokenTuple(as2.getSummary(),
2413 TokenTuple.ARITY_MANY).makeCanonical();
2415 // get summary node's alpha
2416 Integer idSum2 = as2.getSummary();
2417 assert id2hrn.containsKey(idSum2);
2418 HeapRegionNode hrnSum2 = id2hrn.get(idSum2);
2419 assert hrnSum2 != null;
2420 ReachabilitySet alphaSum2 = hrnSum2.getAlpha();
2421 assert alphaSum2 != null;
2423 // does either one report reachability from the other tokens?
2424 if( alphaSum1.containsTuple(gsStar2) ) {
2427 if( alphaSum2.containsTuple(gsStar1) ) {
2431 // only check non-star token if they are different sites
2433 if( alphaSum1.containsTuple(gs2) ) {
2436 if( alphaSum2.containsTuple(gs1) ) {
2442 // check sum2 against alloc1 nodes
2443 for( int i = 0; i < as1.getAllocationDepth(); ++i ) {
2444 Integer idI1 = as1.getIthOldest(i);
2445 assert id2hrn.containsKey(idI1);
2446 HeapRegionNode hrnI1 = id2hrn.get(idI1);
2447 assert hrnI1 != null;
2448 ReachabilitySet alphaI1 = hrnI1.getAlpha();
2449 assert alphaI1 != null;
2451 // the other nodes of an allocation site are single, no stars
2452 TokenTuple gi1 = new TokenTuple(as1.getIthOldest(i),
2454 TokenTuple.ARITY_ONE).makeCanonical();
2456 if( alphaSum2.containsTuple(gi1) ) {
2459 if( alphaI1.containsTuple(gs2) ) {
2462 if( alphaI1.containsTuple(gsStar2) ) {
2467 // check sum1 against alloc2 nodes
2468 for( int i = 0; i < as2.getAllocationDepth(); ++i ) {
2469 Integer idI2 = as2.getIthOldest(i);
2470 assert id2hrn.containsKey(idI2);
2471 HeapRegionNode hrnI2 = id2hrn.get(idI2);
2472 assert hrnI2 != null;
2473 ReachabilitySet alphaI2 = hrnI2.getAlpha();
2474 assert alphaI2 != null;
2476 TokenTuple gi2 = new TokenTuple(as2.getIthOldest(i),
2478 TokenTuple.ARITY_ONE).makeCanonical();
2480 if( alphaSum1.containsTuple(gi2) ) {
2483 if( alphaI2.containsTuple(gs1) ) {
2486 if( alphaI2.containsTuple(gsStar1) ) {
2490 // while we're at it, do an inner loop for alloc2 vs alloc1 nodes
2491 for( int j = 0; j < as1.getAllocationDepth(); ++j ) {
2492 Integer idI1 = as1.getIthOldest(j);
2494 // if these are the same site, don't look for the same token, no alias
2495 // different tokens of the same site could alias together though
2496 if( idI1 == idI2 ) {
2500 HeapRegionNode hrnI1 = id2hrn.get(idI1);
2501 ReachabilitySet alphaI1 = hrnI1.getAlpha();
2502 TokenTuple gi1 = new TokenTuple(as1.getIthOldest(j),
2504 TokenTuple.ARITY_ONE).makeCanonical();
2505 if( alphaI2.containsTuple(gi1) ) {
2508 if( alphaI1.containsTuple(gi2) ) {
2518 // for writing ownership graphs to dot files
2519 public void writeGraph(Descriptor methodDesc,
2521 boolean writeLabels,
2522 boolean labelSelect,
2523 boolean pruneGarbage,
2524 boolean writeReferencers,
2525 boolean writeParamMappings
2526 ) throws java.io.IOException {
2528 methodDesc.getSymbol() +
2529 methodDesc.getNum() +
2539 public void writeGraph(Descriptor methodDesc,
2540 boolean writeLabels,
2541 boolean labelSelect,
2542 boolean pruneGarbage,
2543 boolean writeReferencers,
2544 boolean writeParamMappings
2545 ) throws java.io.IOException {
2547 writeGraph(methodDesc+"COMPLETE",
2556 public void writeGraph(Descriptor methodDesc,
2558 boolean writeLabels,
2559 boolean labelSelect,
2560 boolean pruneGarbage,
2561 boolean writeReferencers,
2562 boolean writeParamMappings
2563 ) throws java.io.IOException {
2565 writeGraph(methodDesc+"COMPLETE"+String.format("%05d", numUpdate),
2574 public void writeGraph(String graphName,
2575 boolean writeLabels,
2576 boolean labelSelect,
2577 boolean pruneGarbage,
2578 boolean writeReferencers,
2579 boolean writeParamMappings
2580 ) throws java.io.IOException {
2582 // remove all non-word characters from the graph name so
2583 // the filename and identifier in dot don't cause errors
2584 graphName = graphName.replaceAll("[\\W]", "");
2586 BufferedWriter bw = new BufferedWriter(new FileWriter(graphName+".dot") );
2587 bw.write("digraph "+graphName+" {\n");
2589 HashSet<HeapRegionNode> visited = new HashSet<HeapRegionNode>();
2591 // then visit every heap region node
2592 if( !pruneGarbage ) {
2593 Set s = id2hrn.entrySet();
2594 Iterator i = s.iterator();
2595 while( i.hasNext() ) {
2596 Map.Entry me = (Map.Entry)i.next();
2597 HeapRegionNode hrn = (HeapRegionNode) me.getValue();
2598 if( !visited.contains(hrn) ) {
2599 traverseHeapRegionNodes(VISIT_HRN_WRITE_FULL,
2609 bw.write(" graphTitle[label=\""+graphName+"\",shape=box];\n");
2611 if( writeParamMappings ) {
2612 Set df = paramIndex2id.entrySet();
2613 Iterator ih = df.iterator();
2614 while( ih.hasNext() ) {
2615 Map.Entry meh = (Map.Entry)ih.next();
2616 Integer pi = (Integer) meh.getKey();
2617 Integer id = (Integer) meh.getValue();
2618 bw.write(" pindex"+pi+"[label=\""+pi+" to "+id+"\",shape=box];\n");
2622 // then visit every label node, useful for debugging
2624 Set s = td2ln.entrySet();
2625 Iterator i = s.iterator();
2626 while( i.hasNext() ) {
2627 Map.Entry me = (Map.Entry)i.next();
2628 LabelNode ln = (LabelNode) me.getValue();
2631 String labelStr = ln.getTempDescriptorString();
2632 if( labelStr.startsWith("___temp") ||
2633 labelStr.startsWith("___dst") ||
2634 labelStr.startsWith("___srctmp") ||
2635 labelStr.startsWith("___neverused") ) {
2640 bw.write(ln.toString() + ";\n");
2642 Iterator<ReferenceEdge> heapRegionsItr = ln.iteratorToReferencees();
2643 while( heapRegionsItr.hasNext() ) {
2644 ReferenceEdge edge = heapRegionsItr.next();
2645 HeapRegionNode hrn = edge.getDst();
2647 if( pruneGarbage && !visited.contains(hrn) ) {
2648 traverseHeapRegionNodes(VISIT_HRN_WRITE_FULL,
2656 bw.write(" " + ln.toString() +
2657 " -> " + hrn.toString() +
2658 "[label=\"" + edge.toGraphEdgeString() +
2669 protected void traverseHeapRegionNodes(int mode,
2673 HashSet<HeapRegionNode> visited,
2674 boolean writeReferencers
2675 ) throws java.io.IOException {
2677 if( visited.contains(hrn) ) {
2683 case VISIT_HRN_WRITE_FULL:
2685 String attributes = "[";
2687 if( hrn.isSingleObject() ) {
2688 attributes += "shape=box";
2690 attributes += "shape=Msquare";
2693 if( hrn.isFlagged() ) {
2694 attributes += ",style=filled,fillcolor=lightgrey";
2697 attributes += ",label=\"ID" +
2700 hrn.getDescription() +
2702 hrn.getAlphaString() +
2705 bw.write(" " + hrn.toString() + attributes + ";\n");
2710 // useful for debugging
2711 if( writeReferencers ) {
2712 OwnershipNode onRef = null;
2713 Iterator refItr = hrn.iteratorToReferencers();
2714 while( refItr.hasNext() ) {
2715 onRef = (OwnershipNode) refItr.next();
2718 case VISIT_HRN_WRITE_FULL:
2719 bw.write(" " + hrn.toString() +
2720 " -> " + onRef.toString() +
2721 "[color=lightgray];\n");
2727 Iterator<ReferenceEdge> childRegionsItr = hrn.iteratorToReferencees();
2728 while( childRegionsItr.hasNext() ) {
2729 ReferenceEdge edge = childRegionsItr.next();
2730 HeapRegionNode hrnChild = edge.getDst();
2733 case VISIT_HRN_WRITE_FULL:
2734 bw.write(" " + hrn.toString() +
2735 " -> " + hrnChild.toString() +
2736 "[label=\"" + edge.toGraphEdgeString() +
2741 traverseHeapRegionNodes(mode,