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 TempDescriptor returnTemp = fc.getReturnTemp();
1338 if( returnTemp != null && !returnTemp.getType().isImmutable() ) {
1340 LabelNode lnLhsCaller = getLabelNodeFromTemp(returnTemp);
1341 clearReferenceEdgesFrom(lnLhsCaller, null, true);
1343 LabelNode lnReturnCallee = ogCallee.getLabelNodeFromTemp(tdReturn);
1344 Iterator<ReferenceEdge> edgeCalleeItr = lnReturnCallee.iteratorToReferencees();
1345 while( edgeCalleeItr.hasNext() ) {
1346 ReferenceEdge edgeCallee = edgeCalleeItr.next();
1348 ReferenceEdge edgeNewInCallerTemplate = new ReferenceEdge(null,
1350 edgeCallee.getFieldDesc(),
1352 toShadowTokens(ogCallee, edgeCallee.getBeta() )
1354 rewriteCallerEdgeBeta(fm.numParameters(),
1356 edgeNewInCallerTemplate,
1357 paramIndex2rewriteJ,
1358 paramIndex2rewriteD,
1359 paramIndex2paramToken,
1360 paramIndex2paramTokenStar,
1364 edgeNewInCallerTemplate.applyBetaNew();
1367 HashSet<HeapRegionNode> assignCallerRhs =
1368 getHRNSetThatPossiblyMapToCalleeHRN(ogCallee,
1369 edgeCallee.getDst(),
1370 paramIndex2reachableCallerNodes);
1372 Iterator<HeapRegionNode> itrHrn = assignCallerRhs.iterator();
1373 while( itrHrn.hasNext() ) {
1374 HeapRegionNode hrnCaller = itrHrn.next();
1376 if( !hasMatchingType(edgeCallee, hrnCaller) ) {
1381 // otherwise caller node can match callee edge, so make it
1382 ReferenceEdge edgeNewInCaller = edgeNewInCallerTemplate.copy();
1383 edgeNewInCaller.setSrc(lnLhsCaller);
1384 edgeNewInCaller.setDst(hrnCaller);
1386 ReferenceEdge edgeExisting = lnLhsCaller.getReferenceTo(hrnCaller, edgeNewInCaller.getFieldDesc() );
1387 if( edgeExisting == null ) {
1389 // if this edge doesn't exist in the caller, create it
1390 addReferenceEdge(lnLhsCaller, hrnCaller, edgeNewInCaller);
1392 // if it already exists, merge with it
1393 edgeExisting.setBeta(edgeExisting.getBeta().union(edgeNewInCaller.getBeta() ) );
1400 // merge the shadow nodes of allocation sites back down to normal capacity
1401 Iterator<AllocationSite> allocItr = ogCallee.allocationSites.iterator();
1402 while( allocItr.hasNext() ) {
1403 AllocationSite as = allocItr.next();
1405 // first age each allocation site enough times to make room for the shadow nodes
1406 for( int i = 0; i < as.getAllocationDepth(); ++i ) {
1410 // then merge the shadow summary into the normal summary
1411 HeapRegionNode hrnSummary = getSummaryNode(as);
1412 assert hrnSummary != null;
1414 HeapRegionNode hrnSummaryShadow = getShadowSummaryNode(as);
1415 assert hrnSummaryShadow != null;
1417 mergeIntoSummary(hrnSummaryShadow, hrnSummary);
1419 // then clear off after merge
1420 clearReferenceEdgesFrom(hrnSummaryShadow, null, true);
1421 clearReferenceEdgesTo(hrnSummaryShadow, null, true);
1422 hrnSummaryShadow.setAlpha(new ReachabilitySet().makeCanonical() );
1424 // then transplant shadow nodes onto the now clean normal nodes
1425 for( int i = 0; i < as.getAllocationDepth(); ++i ) {
1427 Integer idIth = as.getIthOldest(i);
1428 HeapRegionNode hrnIth = id2hrn.get(idIth);
1430 Integer idIthShadow = as.getIthOldestShadow(i);
1431 HeapRegionNode hrnIthShadow = id2hrn.get(idIthShadow);
1433 transferOnto(hrnIthShadow, hrnIth);
1435 // clear off shadow nodes after transfer
1436 clearReferenceEdgesFrom(hrnIthShadow, null, true);
1437 clearReferenceEdgesTo(hrnIthShadow, null, true);
1438 hrnIthShadow.setAlpha(new ReachabilitySet().makeCanonical() );
1441 // finally, globally change shadow tokens into normal tokens
1442 Iterator itrAllLabelNodes = td2ln.entrySet().iterator();
1443 while( itrAllLabelNodes.hasNext() ) {
1444 Map.Entry me = (Map.Entry)itrAllLabelNodes.next();
1445 LabelNode ln = (LabelNode) me.getValue();
1447 Iterator<ReferenceEdge> itrEdges = ln.iteratorToReferencees();
1448 while( itrEdges.hasNext() ) {
1449 unshadowTokens(as, itrEdges.next() );
1453 Iterator itrAllHRNodes = id2hrn.entrySet().iterator();
1454 while( itrAllHRNodes.hasNext() ) {
1455 Map.Entry me = (Map.Entry)itrAllHRNodes.next();
1456 HeapRegionNode hrnToAge = (HeapRegionNode) me.getValue();
1458 unshadowTokens(as, hrnToAge);
1460 Iterator<ReferenceEdge> itrEdges = hrnToAge.iteratorToReferencees();
1461 while( itrEdges.hasNext() ) {
1462 unshadowTokens(as, itrEdges.next() );
1469 protected boolean hasMatchingField(HeapRegionNode src, ReferenceEdge edge) {
1471 // if no allocation site, then it's a match-everything region
1472 AllocationSite asSrc = src.getAllocationSite();
1473 if( asSrc == null ) {
1477 TypeDescriptor tdSrc = asSrc.getType();
1478 assert tdSrc != null;
1480 // if it's not a class, it doesn't have any fields to match
1481 if( !tdSrc.isClass() ) {
1485 Iterator fieldsSrcItr = tdSrc.getClassDesc().getFields();
1486 while( fieldsSrcItr.hasNext() ) {
1487 FieldDescriptor fd = (FieldDescriptor) fieldsSrcItr.next();
1488 if( fd == edge.getFieldDesc() ) {
1493 // otherwise it is a class with fields
1494 // but we didn't find a match
1499 protected boolean hasMatchingType(ReferenceEdge edge, HeapRegionNode dst) {
1501 // if the region has no type, matches everything
1502 AllocationSite asDst = dst.getAllocationSite();
1503 if( asDst == null ) {
1507 TypeDescriptor tdDst = asDst.getType();
1508 assert tdDst != null;
1510 // if the type is not a class don't match because
1511 // primitives are copied, no memory aliases
1512 ClassDescriptor cdDst = tdDst.getClassDesc();
1513 if( cdDst == null ) {
1517 // if the field is null, it matches everything
1518 FieldDescriptor fd = edge.getFieldDesc();
1522 TypeDescriptor tdFd = fd.getType();
1523 assert tdFd != null;
1525 return typeUtil.isSuperorType(tdFd, tdDst);
1530 protected void unshadowTokens(AllocationSite as, ReferenceEdge edge) {
1531 edge.setBeta(edge.getBeta().unshadowTokens(as) );
1534 protected void unshadowTokens(AllocationSite as, HeapRegionNode hrn) {
1535 hrn.setAlpha(hrn.getAlpha().unshadowTokens(as) );
1539 private ReachabilitySet toShadowTokens(OwnershipGraph ogCallee,
1540 ReachabilitySet rsIn) {
1542 ReachabilitySet rsOut = new ReachabilitySet(rsIn);
1544 Iterator<AllocationSite> allocItr = ogCallee.allocationSites.iterator();
1545 while( allocItr.hasNext() ) {
1546 AllocationSite as = allocItr.next();
1548 rsOut = rsOut.toShadowTokens(as);
1551 return rsOut.makeCanonical();
1555 private void rewriteCallerNodeAlpha(int numParameters,
1558 Hashtable<Integer, ReachabilitySet> paramIndex2rewriteH,
1559 Hashtable<Integer, ReachabilitySet> paramIndex2rewriteD,
1560 Hashtable<Integer, TokenTuple> paramIndex2paramToken,
1561 Hashtable<Integer, TokenTuple> paramIndex2paramTokenStar) {
1563 ReachabilitySet rules = paramIndex2rewriteH.get(paramIndex);
1564 assert rules != null;
1566 TokenTuple tokenToRewrite = paramIndex2paramToken.get(paramIndex);
1567 assert tokenToRewrite != null;
1569 ReachabilitySet r0 = new ReachabilitySet().makeCanonical();
1570 Iterator<TokenTupleSet> ttsItr = rules.iterator();
1571 while( ttsItr.hasNext() ) {
1572 TokenTupleSet tts = ttsItr.next();
1573 r0 = r0.union(tts.rewriteToken(tokenToRewrite,
1579 ReachabilitySet r1 = new ReachabilitySet().makeCanonical();
1580 ttsItr = r0.iterator();
1581 while( ttsItr.hasNext() ) {
1582 TokenTupleSet tts = ttsItr.next();
1583 r1 = r1.union(rewriteDpass(numParameters,
1586 paramIndex2rewriteD,
1587 paramIndex2paramToken,
1588 paramIndex2paramTokenStar) );
1591 hrn.setAlphaNew(hrn.getAlphaNew().union(r1) );
1595 private void rewriteCallerEdgeBeta(int numParameters,
1598 Hashtable<Integer, ReachabilitySet> paramIndex2rewriteJorK,
1599 Hashtable<Integer, ReachabilitySet> paramIndex2rewriteD,
1600 Hashtable<Integer, TokenTuple> paramIndex2paramToken,
1601 Hashtable<Integer, TokenTuple> paramIndex2paramTokenStar,
1602 boolean makeChangeSet,
1603 Hashtable<ReferenceEdge, ChangeTupleSet> edgePlannedChanges) {
1605 ReachabilitySet rules = paramIndex2rewriteJorK.get(paramIndex);
1606 assert rules != null;
1608 TokenTuple tokenToRewrite = paramIndex2paramToken.get(paramIndex);
1609 assert tokenToRewrite != null;
1611 ChangeTupleSet cts0 = new ChangeTupleSet().makeCanonical();
1613 Iterator<TokenTupleSet> ttsItr = rules.iterator();
1614 while( ttsItr.hasNext() ) {
1615 TokenTupleSet tts = ttsItr.next();
1617 Hashtable<TokenTupleSet, HashSet<TokenTupleSet> > forChangeSet =
1618 new Hashtable<TokenTupleSet, HashSet<TokenTupleSet> >();
1620 ReachabilitySet rTemp = tts.rewriteToken(tokenToRewrite,
1625 Iterator fcsItr = forChangeSet.entrySet().iterator();
1626 while( fcsItr.hasNext() ) {
1627 Map.Entry me = (Map.Entry)fcsItr.next();
1628 TokenTupleSet ttsMatch = (TokenTupleSet) me.getKey();
1629 HashSet<TokenTupleSet> ttsAddSet = (HashSet<TokenTupleSet>) me.getValue();
1630 Iterator<TokenTupleSet> ttsAddItr = ttsAddSet.iterator();
1631 while( ttsAddItr.hasNext() ) {
1632 TokenTupleSet ttsAdd = ttsAddItr.next();
1634 ChangeTuple ct = new ChangeTuple(ttsMatch,
1638 cts0 = cts0.union(ct);
1644 ReachabilitySet r1 = new ReachabilitySet().makeCanonical();
1645 ChangeTupleSet cts1 = new ChangeTupleSet().makeCanonical();
1647 Iterator<ChangeTuple> ctItr = cts0.iterator();
1648 while( ctItr.hasNext() ) {
1649 ChangeTuple ct = ctItr.next();
1651 ReachabilitySet rTemp = rewriteDpass(numParameters,
1654 paramIndex2rewriteD,
1655 paramIndex2paramToken,
1656 paramIndex2paramTokenStar
1658 r1 = r1.union(rTemp);
1660 if( makeChangeSet ) {
1661 assert edgePlannedChanges != null;
1663 Iterator<TokenTupleSet> ttsTempItr = rTemp.iterator();
1664 while( ttsTempItr.hasNext() ) {
1665 TokenTupleSet tts = ttsTempItr.next();
1667 ChangeTuple ctFinal = new ChangeTuple(ct.getSetToMatch(),
1671 cts1 = cts1.union(ctFinal);
1676 if( makeChangeSet ) {
1677 edgePlannedChanges.put(edge, cts1);
1680 edge.setBetaNew(edge.getBetaNew().union(r1) );
1684 private ReachabilitySet rewriteDpass(int numParameters,
1686 TokenTupleSet ttsIn,
1687 Hashtable<Integer, ReachabilitySet> paramIndex2rewriteD,
1688 Hashtable<Integer, TokenTuple> paramIndex2paramToken,
1689 Hashtable<Integer, TokenTuple> paramIndex2paramTokenStar) {
1691 ReachabilitySet rsOut = new ReachabilitySet().makeCanonical();
1693 boolean rewritten = false;
1695 for( int j = 0; j < numParameters; ++j ) {
1696 Integer paramIndexJ = new Integer(j);
1697 ReachabilitySet D_j = paramIndex2rewriteD.get(paramIndexJ);
1700 if( paramIndexJ != paramIndex ) {
1701 TokenTuple tokenToRewriteJ = paramIndex2paramToken.get(paramIndexJ);
1702 assert tokenToRewriteJ != null;
1703 if( ttsIn.containsTuple(tokenToRewriteJ) ) {
1704 ReachabilitySet r = ttsIn.rewriteToken(tokenToRewriteJ,
1708 Iterator<TokenTupleSet> ttsItr = r.iterator();
1709 while( ttsItr.hasNext() ) {
1710 TokenTupleSet tts = ttsItr.next();
1711 rsOut = rsOut.union(rewriteDpass(numParameters,
1714 paramIndex2rewriteD,
1715 paramIndex2paramToken,
1716 paramIndex2paramTokenStar) );
1722 TokenTuple tokenStarToRewriteJ = paramIndex2paramTokenStar.get(paramIndexJ);
1723 assert tokenStarToRewriteJ != null;
1724 if( ttsIn.containsTuple(tokenStarToRewriteJ) ) {
1725 ReachabilitySet r = ttsIn.rewriteToken(tokenStarToRewriteJ,
1729 Iterator<TokenTupleSet> ttsItr = r.iterator();
1730 while( ttsItr.hasNext() ) {
1731 TokenTupleSet tts = ttsItr.next();
1732 rsOut = rsOut.union(rewriteDpass(numParameters,
1735 paramIndex2rewriteD,
1736 paramIndex2paramToken,
1737 paramIndex2paramTokenStar) );
1744 rsOut = rsOut.union(ttsIn);
1751 private HashSet<HeapRegionNode>
1752 getHRNSetThatPossiblyMapToCalleeHRN(OwnershipGraph ogCallee,
1753 HeapRegionNode hrnCallee,
1754 Hashtable<Integer, HashSet<HeapRegionNode> > paramIndex2reachableCallerNodes
1757 HashSet<HeapRegionNode> possibleCallerHRNs = new HashSet<HeapRegionNode>();
1759 Integer paramIndexCallee = ogCallee.id2paramIndex.get(hrnCallee.getID() );
1761 if( paramIndexCallee == null ) {
1762 // this is a node allocated in the callee then and it has
1763 // exactly one shadow node in the caller to map to
1764 AllocationSite as = hrnCallee.getAllocationSite();
1767 int age = as.getAgeCategory(hrnCallee.getID() );
1768 assert age != AllocationSite.AGE_notInThisSite;
1771 if( age == AllocationSite.AGE_summary ) {
1772 idCaller = as.getSummaryShadow();
1773 } else if( age == AllocationSite.AGE_oldest ) {
1774 idCaller = as.getOldestShadow();
1776 assert age == AllocationSite.AGE_in_I;
1778 Integer I = as.getAge(hrnCallee.getID() );
1781 idCaller = as.getIthOldestShadow(I);
1784 assert id2hrn.containsKey(idCaller);
1785 HeapRegionNode hrnCaller = id2hrn.get(idCaller);
1786 possibleCallerHRNs.add(hrnCaller);
1789 // this is a node that was created to represent a parameter
1790 // so it maps to a whole mess of heap regions
1791 assert paramIndex2reachableCallerNodes.containsKey(paramIndexCallee);
1792 possibleCallerHRNs = paramIndex2reachableCallerNodes.get(paramIndexCallee);
1795 return possibleCallerHRNs;
1800 ////////////////////////////////////////////////////
1801 // in merge() and equals() methods the suffix A
1802 // represents the passed in graph and the suffix
1803 // B refers to the graph in this object
1804 // Merging means to take the incoming graph A and
1805 // merge it into B, so after the operation graph B
1806 // is the final result.
1807 ////////////////////////////////////////////////////
1808 public void merge(OwnershipGraph og) {
1814 mergeOwnershipNodes(og);
1815 mergeReferenceEdges(og);
1816 mergeId2paramIndex(og);
1817 mergeAllocationSites(og);
1821 protected void mergeOwnershipNodes(OwnershipGraph og) {
1822 Set sA = og.id2hrn.entrySet();
1823 Iterator iA = sA.iterator();
1824 while( iA.hasNext() ) {
1825 Map.Entry meA = (Map.Entry)iA.next();
1826 Integer idA = (Integer) meA.getKey();
1827 HeapRegionNode hrnA = (HeapRegionNode) meA.getValue();
1829 // if this graph doesn't have a node the
1830 // incoming graph has, allocate it
1831 if( !id2hrn.containsKey(idA) ) {
1832 HeapRegionNode hrnB = hrnA.copy();
1833 id2hrn.put(idA, hrnB);
1836 // otherwise this is a node present in both graphs
1837 // so make the new reachability set a union of the
1838 // nodes' reachability sets
1839 HeapRegionNode hrnB = id2hrn.get(idA);
1840 hrnB.setAlpha(hrnB.getAlpha().union(hrnA.getAlpha() ) );
1844 // now add any label nodes that are in graph B but
1846 sA = og.td2ln.entrySet();
1848 while( iA.hasNext() ) {
1849 Map.Entry meA = (Map.Entry)iA.next();
1850 TempDescriptor tdA = (TempDescriptor) meA.getKey();
1851 LabelNode lnA = (LabelNode) meA.getValue();
1853 // if the label doesn't exist in B, allocate and add it
1854 LabelNode lnB = getLabelNodeFromTemp(tdA);
1858 protected void mergeReferenceEdges(OwnershipGraph og) {
1861 Set sA = og.id2hrn.entrySet();
1862 Iterator iA = sA.iterator();
1863 while( iA.hasNext() ) {
1864 Map.Entry meA = (Map.Entry)iA.next();
1865 Integer idA = (Integer) meA.getKey();
1866 HeapRegionNode hrnA = (HeapRegionNode) meA.getValue();
1868 Iterator<ReferenceEdge> heapRegionsItrA = hrnA.iteratorToReferencees();
1869 while( heapRegionsItrA.hasNext() ) {
1870 ReferenceEdge edgeA = heapRegionsItrA.next();
1871 HeapRegionNode hrnChildA = edgeA.getDst();
1872 Integer idChildA = hrnChildA.getID();
1874 // at this point we know an edge in graph A exists
1875 // idA -> idChildA, does this exist in B?
1876 assert id2hrn.containsKey(idA);
1877 HeapRegionNode hrnB = id2hrn.get(idA);
1878 ReferenceEdge edgeToMerge = null;
1880 Iterator<ReferenceEdge> heapRegionsItrB = hrnB.iteratorToReferencees();
1881 while( heapRegionsItrB.hasNext() &&
1882 edgeToMerge == null ) {
1884 ReferenceEdge edgeB = heapRegionsItrB.next();
1885 HeapRegionNode hrnChildB = edgeB.getDst();
1886 Integer idChildB = hrnChildB.getID();
1888 // don't use the ReferenceEdge.equals() here because
1889 // we're talking about existence between graphs
1890 if( idChildB.equals(idChildA) &&
1891 edgeB.getFieldDesc() == edgeA.getFieldDesc() ) {
1892 edgeToMerge = edgeB;
1896 // if the edge from A was not found in B,
1898 if( edgeToMerge == null ) {
1899 assert id2hrn.containsKey(idChildA);
1900 HeapRegionNode hrnChildB = id2hrn.get(idChildA);
1901 edgeToMerge = edgeA.copy();
1902 edgeToMerge.setSrc(hrnB);
1903 edgeToMerge.setDst(hrnChildB);
1904 addReferenceEdge(hrnB, hrnChildB, edgeToMerge);
1906 // otherwise, the edge already existed in both graphs
1907 // so merge their reachability sets
1909 // just replace this beta set with the union
1910 assert edgeToMerge != null;
1911 edgeToMerge.setBeta(
1912 edgeToMerge.getBeta().union(edgeA.getBeta() )
1914 if( !edgeA.isInitialParamReflexive() ) {
1915 edgeToMerge.setIsInitialParamReflexive(false);
1921 // and then again with label nodes
1922 sA = og.td2ln.entrySet();
1924 while( iA.hasNext() ) {
1925 Map.Entry meA = (Map.Entry)iA.next();
1926 TempDescriptor tdA = (TempDescriptor) meA.getKey();
1927 LabelNode lnA = (LabelNode) meA.getValue();
1929 Iterator<ReferenceEdge> heapRegionsItrA = lnA.iteratorToReferencees();
1930 while( heapRegionsItrA.hasNext() ) {
1931 ReferenceEdge edgeA = heapRegionsItrA.next();
1932 HeapRegionNode hrnChildA = edgeA.getDst();
1933 Integer idChildA = hrnChildA.getID();
1935 // at this point we know an edge in graph A exists
1936 // tdA -> idChildA, does this exist in B?
1937 assert td2ln.containsKey(tdA);
1938 LabelNode lnB = td2ln.get(tdA);
1939 ReferenceEdge edgeToMerge = null;
1941 // labels never have edges with a field
1942 //assert edgeA.getFieldDesc() == null;
1944 Iterator<ReferenceEdge> heapRegionsItrB = lnB.iteratorToReferencees();
1945 while( heapRegionsItrB.hasNext() &&
1946 edgeToMerge == null ) {
1948 ReferenceEdge edgeB = heapRegionsItrB.next();
1949 HeapRegionNode hrnChildB = edgeB.getDst();
1950 Integer idChildB = hrnChildB.getID();
1952 // labels never have edges with a field
1953 //assert edgeB.getFieldDesc() == null;
1955 // don't use the ReferenceEdge.equals() here because
1956 // we're talking about existence between graphs
1957 if( idChildB.equals(idChildA) &&
1958 edgeB.getFieldDesc() == edgeA.getFieldDesc() ) {
1959 edgeToMerge = edgeB;
1963 // if the edge from A was not found in B,
1965 if( edgeToMerge == null ) {
1966 assert id2hrn.containsKey(idChildA);
1967 HeapRegionNode hrnChildB = id2hrn.get(idChildA);
1968 edgeToMerge = edgeA.copy();
1969 edgeToMerge.setSrc(lnB);
1970 edgeToMerge.setDst(hrnChildB);
1971 addReferenceEdge(lnB, hrnChildB, edgeToMerge);
1973 // otherwise, the edge already existed in both graphs
1974 // so merge their reachability sets
1976 // just replace this beta set with the union
1977 edgeToMerge.setBeta(
1978 edgeToMerge.getBeta().union(edgeA.getBeta() )
1980 if( !edgeA.isInitialParamReflexive() ) {
1981 edgeToMerge.setIsInitialParamReflexive(false);
1988 // you should only merge ownership graphs that have the
1989 // same number of parameters, or if one or both parameter
1990 // index tables are empty
1991 protected void mergeId2paramIndex(OwnershipGraph og) {
1992 if( id2paramIndex.size() == 0 ) {
1993 id2paramIndex = og.id2paramIndex;
1994 paramIndex2id = og.paramIndex2id;
1995 paramIndex2tdQ = og.paramIndex2tdQ;
1999 if( og.id2paramIndex.size() == 0 ) {
2003 assert id2paramIndex.size() == og.id2paramIndex.size();
2006 protected void mergeAllocationSites(OwnershipGraph og) {
2007 allocationSites.addAll(og.allocationSites);
2012 // it is necessary in the equals() member functions
2013 // to "check both ways" when comparing the data
2014 // structures of two graphs. For instance, if all
2015 // edges between heap region nodes in graph A are
2016 // present and equal in graph B it is not sufficient
2017 // to say the graphs are equal. Consider that there
2018 // may be edges in graph B that are not in graph A.
2019 // the only way to know that all edges in both graphs
2020 // are equally present is to iterate over both data
2021 // structures and compare against the other graph.
2022 public boolean equals(OwnershipGraph og) {
2028 if( !areHeapRegionNodesEqual(og) ) {
2032 if( !areLabelNodesEqual(og) ) {
2036 if( !areReferenceEdgesEqual(og) ) {
2040 if( !areId2paramIndexEqual(og) ) {
2044 // if everything is equal up to this point,
2045 // assert that allocationSites is also equal--
2046 // this data is redundant and kept for efficiency
2047 assert allocationSites.equals(og.allocationSites);
2052 protected boolean areHeapRegionNodesEqual(OwnershipGraph og) {
2054 if( !areallHRNinAalsoinBandequal(this, og) ) {
2058 if( !areallHRNinAalsoinBandequal(og, this) ) {
2065 static protected boolean areallHRNinAalsoinBandequal(OwnershipGraph ogA,
2066 OwnershipGraph ogB) {
2067 Set sA = ogA.id2hrn.entrySet();
2068 Iterator iA = sA.iterator();
2069 while( iA.hasNext() ) {
2070 Map.Entry meA = (Map.Entry)iA.next();
2071 Integer idA = (Integer) meA.getKey();
2072 HeapRegionNode hrnA = (HeapRegionNode) meA.getValue();
2074 if( !ogB.id2hrn.containsKey(idA) ) {
2078 HeapRegionNode hrnB = ogB.id2hrn.get(idA);
2079 if( !hrnA.equalsIncludingAlpha(hrnB) ) {
2088 protected boolean areLabelNodesEqual(OwnershipGraph og) {
2090 if( !areallLNinAalsoinBandequal(this, og) ) {
2094 if( !areallLNinAalsoinBandequal(og, this) ) {
2101 static protected boolean areallLNinAalsoinBandequal(OwnershipGraph ogA,
2102 OwnershipGraph ogB) {
2103 Set sA = ogA.td2ln.entrySet();
2104 Iterator iA = sA.iterator();
2105 while( iA.hasNext() ) {
2106 Map.Entry meA = (Map.Entry)iA.next();
2107 TempDescriptor tdA = (TempDescriptor) meA.getKey();
2109 if( !ogB.td2ln.containsKey(tdA) ) {
2118 protected boolean areReferenceEdgesEqual(OwnershipGraph og) {
2119 if( !areallREinAandBequal(this, og) ) {
2126 static protected boolean areallREinAandBequal(OwnershipGraph ogA,
2127 OwnershipGraph ogB) {
2129 // check all the heap region->heap region edges
2130 Set sA = ogA.id2hrn.entrySet();
2131 Iterator iA = sA.iterator();
2132 while( iA.hasNext() ) {
2133 Map.Entry meA = (Map.Entry)iA.next();
2134 Integer idA = (Integer) meA.getKey();
2135 HeapRegionNode hrnA = (HeapRegionNode) meA.getValue();
2137 // we should have already checked that the same
2138 // heap regions exist in both graphs
2139 assert ogB.id2hrn.containsKey(idA);
2141 if( !areallREfromAequaltoB(ogA, hrnA, ogB) ) {
2145 // then check every edge in B for presence in A, starting
2146 // from the same parent HeapRegionNode
2147 HeapRegionNode hrnB = ogB.id2hrn.get(idA);
2149 if( !areallREfromAequaltoB(ogB, hrnB, ogA) ) {
2154 // then check all the label->heap region edges
2155 sA = ogA.td2ln.entrySet();
2157 while( iA.hasNext() ) {
2158 Map.Entry meA = (Map.Entry)iA.next();
2159 TempDescriptor tdA = (TempDescriptor) meA.getKey();
2160 LabelNode lnA = (LabelNode) meA.getValue();
2162 // we should have already checked that the same
2163 // label nodes exist in both graphs
2164 assert ogB.td2ln.containsKey(tdA);
2166 if( !areallREfromAequaltoB(ogA, lnA, ogB) ) {
2170 // then check every edge in B for presence in A, starting
2171 // from the same parent LabelNode
2172 LabelNode lnB = ogB.td2ln.get(tdA);
2174 if( !areallREfromAequaltoB(ogB, lnB, ogA) ) {
2183 static protected boolean areallREfromAequaltoB(OwnershipGraph ogA,
2185 OwnershipGraph ogB) {
2187 Iterator<ReferenceEdge> itrA = onA.iteratorToReferencees();
2188 while( itrA.hasNext() ) {
2189 ReferenceEdge edgeA = itrA.next();
2190 HeapRegionNode hrnChildA = edgeA.getDst();
2191 Integer idChildA = hrnChildA.getID();
2193 assert ogB.id2hrn.containsKey(idChildA);
2195 // at this point we know an edge in graph A exists
2196 // onA -> idChildA, does this exact edge exist in B?
2197 boolean edgeFound = false;
2199 OwnershipNode onB = null;
2200 if( onA instanceof HeapRegionNode ) {
2201 HeapRegionNode hrnA = (HeapRegionNode) onA;
2202 onB = ogB.id2hrn.get(hrnA.getID() );
2204 LabelNode lnA = (LabelNode) onA;
2205 onB = ogB.td2ln.get(lnA.getTempDescriptor() );
2208 Iterator<ReferenceEdge> itrB = onB.iteratorToReferencees();
2209 while( itrB.hasNext() ) {
2210 ReferenceEdge edgeB = itrB.next();
2211 HeapRegionNode hrnChildB = edgeB.getDst();
2212 Integer idChildB = hrnChildB.getID();
2214 if( idChildA.equals(idChildB) &&
2215 edgeA.getFieldDesc() == edgeB.getFieldDesc() ) {
2217 // there is an edge in the right place with the right field,
2218 // but do they have the same attributes?
2219 if( edgeA.getBeta().equals(edgeB.getBeta() ) ) {
2237 protected boolean areId2paramIndexEqual(OwnershipGraph og) {
2238 return id2paramIndex.size() == og.id2paramIndex.size();
2242 public boolean hasPotentialAlias(Integer paramIndex1, Integer paramIndex2) {
2244 // get parameter's heap region
2245 assert paramIndex2id.containsKey(paramIndex1);
2246 Integer idParam1 = paramIndex2id.get(paramIndex1);
2248 assert id2hrn.containsKey(idParam1);
2249 HeapRegionNode hrnParam1 = id2hrn.get(idParam1);
2250 assert hrnParam1 != null;
2252 // get tokens for this parameter
2253 TokenTuple p1 = new TokenTuple(hrnParam1.getID(),
2255 TokenTuple.ARITY_ONE).makeCanonical();
2257 TokenTuple pStar1 = new TokenTuple(hrnParam1.getID(),
2259 TokenTuple.ARITY_MANY).makeCanonical();
2262 // get tokens for the other parameter
2263 assert paramIndex2id.containsKey(paramIndex2);
2264 Integer idParam2 = paramIndex2id.get(paramIndex2);
2266 assert id2hrn.containsKey(idParam2);
2267 HeapRegionNode hrnParam2 = id2hrn.get(idParam2);
2268 assert hrnParam2 != null;
2270 TokenTuple p2 = new TokenTuple(hrnParam2.getID(),
2272 TokenTuple.ARITY_ONE).makeCanonical();
2274 TokenTuple pStar2 = new TokenTuple(hrnParam2.getID(),
2276 TokenTuple.ARITY_MANY).makeCanonical();
2279 // get special label p_q for first parameter
2280 TempDescriptor tdParamQ1 = paramIndex2tdQ.get(paramIndex1);
2281 assert tdParamQ1 != null;
2282 LabelNode lnParamQ1 = td2ln.get(tdParamQ1);
2283 assert lnParamQ1 != null;
2285 // then get the edge from label q to parameter's hrn
2286 ReferenceEdge edgeSpecialQ1 = lnParamQ1.getReferenceTo(hrnParam1, null);
2287 assert edgeSpecialQ1 != null;
2289 // if the beta of this edge has tokens from both parameters in one
2290 // token tuple set, then there is a potential alias between them
2291 ReachabilitySet beta1 = edgeSpecialQ1.getBeta();
2292 assert beta1 != null;
2294 if( beta1.containsTupleSetWithBoth(p1, p2) ) {
2297 if( beta1.containsTupleSetWithBoth(pStar1, p2) ) {
2300 if( beta1.containsTupleSetWithBoth(p1, pStar2) ) {
2303 if( beta1.containsTupleSetWithBoth(pStar1, pStar2) ) {
2311 public boolean hasPotentialAlias(Integer paramIndex, AllocationSite as) {
2313 // get parameter's heap region
2314 assert paramIndex2id.containsKey(paramIndex);
2315 Integer idParam = paramIndex2id.get(paramIndex);
2317 assert id2hrn.containsKey(idParam);
2318 HeapRegionNode hrnParam = id2hrn.get(idParam);
2319 assert hrnParam != null;
2321 // get tokens for this parameter
2322 TokenTuple p = new TokenTuple(hrnParam.getID(),
2324 TokenTuple.ARITY_ONE).makeCanonical();
2326 TokenTuple pStar = new TokenTuple(hrnParam.getID(),
2328 TokenTuple.ARITY_MANY).makeCanonical();
2330 // get special label p_q
2331 TempDescriptor tdParamQ = paramIndex2tdQ.get(paramIndex);
2332 assert tdParamQ != null;
2333 LabelNode lnParamQ = td2ln.get(tdParamQ);
2334 assert lnParamQ != null;
2336 // then get the edge from label q to parameter's hrn
2337 ReferenceEdge edgeSpecialQ = lnParamQ.getReferenceTo(hrnParam, null);
2338 assert edgeSpecialQ != null;
2340 // look through this beta set for potential aliases
2341 ReachabilitySet beta = edgeSpecialQ.getBeta();
2342 assert beta != null;
2345 // get tokens for summary node
2346 TokenTuple gs = new TokenTuple(as.getSummary(),
2348 TokenTuple.ARITY_ONE).makeCanonical();
2350 TokenTuple gsStar = new TokenTuple(as.getSummary(),
2352 TokenTuple.ARITY_MANY).makeCanonical();
2354 if( beta.containsTupleSetWithBoth(p, gs) ) {
2357 if( beta.containsTupleSetWithBoth(pStar, gs) ) {
2360 if( beta.containsTupleSetWithBoth(p, gsStar) ) {
2363 if( beta.containsTupleSetWithBoth(pStar, gsStar) ) {
2367 // check for other nodes
2368 for( int i = 0; i < as.getAllocationDepth(); ++i ) {
2370 // the other nodes of an allocation site are single, no stars
2371 TokenTuple gi = new TokenTuple(as.getIthOldest(i),
2373 TokenTuple.ARITY_ONE).makeCanonical();
2375 if( beta.containsTupleSetWithBoth(p, gi) ) {
2378 if( beta.containsTupleSetWithBoth(pStar, gi) ) {
2387 public boolean hasPotentialAlias(AllocationSite as1, AllocationSite as2) {
2389 // get tokens for summary nodes
2390 TokenTuple gs1 = new TokenTuple(as1.getSummary(),
2392 TokenTuple.ARITY_ONE).makeCanonical();
2394 TokenTuple gsStar1 = new TokenTuple(as1.getSummary(),
2396 TokenTuple.ARITY_MANY).makeCanonical();
2398 // get summary node's alpha
2399 Integer idSum1 = as1.getSummary();
2400 assert id2hrn.containsKey(idSum1);
2401 HeapRegionNode hrnSum1 = id2hrn.get(idSum1);
2402 assert hrnSum1 != null;
2403 ReachabilitySet alphaSum1 = hrnSum1.getAlpha();
2404 assert alphaSum1 != null;
2407 // and for the other one
2408 TokenTuple gs2 = new TokenTuple(as2.getSummary(),
2410 TokenTuple.ARITY_ONE).makeCanonical();
2412 TokenTuple gsStar2 = new TokenTuple(as2.getSummary(),
2414 TokenTuple.ARITY_MANY).makeCanonical();
2416 // get summary node's alpha
2417 Integer idSum2 = as2.getSummary();
2418 assert id2hrn.containsKey(idSum2);
2419 HeapRegionNode hrnSum2 = id2hrn.get(idSum2);
2420 assert hrnSum2 != null;
2421 ReachabilitySet alphaSum2 = hrnSum2.getAlpha();
2422 assert alphaSum2 != null;
2424 // does either one report reachability from the other tokens?
2425 if( alphaSum1.containsTuple(gsStar2) ) {
2428 if( alphaSum2.containsTuple(gsStar1) ) {
2432 // only check non-star token if they are different sites
2434 if( alphaSum1.containsTuple(gs2) ) {
2437 if( alphaSum2.containsTuple(gs1) ) {
2443 // check sum2 against alloc1 nodes
2444 for( int i = 0; i < as1.getAllocationDepth(); ++i ) {
2445 Integer idI1 = as1.getIthOldest(i);
2446 assert id2hrn.containsKey(idI1);
2447 HeapRegionNode hrnI1 = id2hrn.get(idI1);
2448 assert hrnI1 != null;
2449 ReachabilitySet alphaI1 = hrnI1.getAlpha();
2450 assert alphaI1 != null;
2452 // the other nodes of an allocation site are single, no stars
2453 TokenTuple gi1 = new TokenTuple(as1.getIthOldest(i),
2455 TokenTuple.ARITY_ONE).makeCanonical();
2457 if( alphaSum2.containsTuple(gi1) ) {
2460 if( alphaI1.containsTuple(gs2) ) {
2463 if( alphaI1.containsTuple(gsStar2) ) {
2468 // check sum1 against alloc2 nodes
2469 for( int i = 0; i < as2.getAllocationDepth(); ++i ) {
2470 Integer idI2 = as2.getIthOldest(i);
2471 assert id2hrn.containsKey(idI2);
2472 HeapRegionNode hrnI2 = id2hrn.get(idI2);
2473 assert hrnI2 != null;
2474 ReachabilitySet alphaI2 = hrnI2.getAlpha();
2475 assert alphaI2 != null;
2477 TokenTuple gi2 = new TokenTuple(as2.getIthOldest(i),
2479 TokenTuple.ARITY_ONE).makeCanonical();
2481 if( alphaSum1.containsTuple(gi2) ) {
2484 if( alphaI2.containsTuple(gs1) ) {
2487 if( alphaI2.containsTuple(gsStar1) ) {
2491 // while we're at it, do an inner loop for alloc2 vs alloc1 nodes
2492 for( int j = 0; j < as1.getAllocationDepth(); ++j ) {
2493 Integer idI1 = as1.getIthOldest(j);
2495 // if these are the same site, don't look for the same token, no alias
2496 // different tokens of the same site could alias together though
2497 if( idI1 == idI2 ) {
2501 HeapRegionNode hrnI1 = id2hrn.get(idI1);
2502 ReachabilitySet alphaI1 = hrnI1.getAlpha();
2503 TokenTuple gi1 = new TokenTuple(as1.getIthOldest(j),
2505 TokenTuple.ARITY_ONE).makeCanonical();
2506 if( alphaI2.containsTuple(gi1) ) {
2509 if( alphaI1.containsTuple(gi2) ) {
2519 // for writing ownership graphs to dot files
2520 public void writeGraph(Descriptor methodDesc,
2522 boolean writeLabels,
2523 boolean labelSelect,
2524 boolean pruneGarbage,
2525 boolean writeReferencers,
2526 boolean writeParamMappings
2527 ) throws java.io.IOException {
2529 methodDesc.getSymbol() +
2530 methodDesc.getNum() +
2540 public void writeGraph(Descriptor methodDesc,
2541 boolean writeLabels,
2542 boolean labelSelect,
2543 boolean pruneGarbage,
2544 boolean writeReferencers,
2545 boolean writeParamMappings
2546 ) throws java.io.IOException {
2548 writeGraph(methodDesc+"COMPLETE",
2557 public void writeGraph(Descriptor methodDesc,
2559 boolean writeLabels,
2560 boolean labelSelect,
2561 boolean pruneGarbage,
2562 boolean writeReferencers,
2563 boolean writeParamMappings
2564 ) throws java.io.IOException {
2566 writeGraph(methodDesc+"COMPLETE"+String.format("%05d", numUpdate),
2575 public void writeGraph(String graphName,
2576 boolean writeLabels,
2577 boolean labelSelect,
2578 boolean pruneGarbage,
2579 boolean writeReferencers,
2580 boolean writeParamMappings
2581 ) throws java.io.IOException {
2583 // remove all non-word characters from the graph name so
2584 // the filename and identifier in dot don't cause errors
2585 graphName = graphName.replaceAll("[\\W]", "");
2587 BufferedWriter bw = new BufferedWriter(new FileWriter(graphName+".dot") );
2588 bw.write("digraph "+graphName+" {\n");
2590 HashSet<HeapRegionNode> visited = new HashSet<HeapRegionNode>();
2592 // then visit every heap region node
2593 if( !pruneGarbage ) {
2594 Set s = id2hrn.entrySet();
2595 Iterator i = s.iterator();
2596 while( i.hasNext() ) {
2597 Map.Entry me = (Map.Entry)i.next();
2598 HeapRegionNode hrn = (HeapRegionNode) me.getValue();
2599 if( !visited.contains(hrn) ) {
2600 traverseHeapRegionNodes(VISIT_HRN_WRITE_FULL,
2610 bw.write(" graphTitle[label=\""+graphName+"\",shape=box];\n");
2612 if( writeParamMappings ) {
2613 Set df = paramIndex2id.entrySet();
2614 Iterator ih = df.iterator();
2615 while( ih.hasNext() ) {
2616 Map.Entry meh = (Map.Entry)ih.next();
2617 Integer pi = (Integer) meh.getKey();
2618 Integer id = (Integer) meh.getValue();
2619 bw.write(" pindex"+pi+"[label=\""+pi+" to "+id+"\",shape=box];\n");
2623 // then visit every label node, useful for debugging
2625 Set s = td2ln.entrySet();
2626 Iterator i = s.iterator();
2627 while( i.hasNext() ) {
2628 Map.Entry me = (Map.Entry)i.next();
2629 LabelNode ln = (LabelNode) me.getValue();
2632 String labelStr = ln.getTempDescriptorString();
2633 if( labelStr.startsWith("___temp") ||
2634 labelStr.startsWith("___dst") ||
2635 labelStr.startsWith("___srctmp") ||
2636 labelStr.startsWith("___neverused") ) {
2641 bw.write(ln.toString() + ";\n");
2643 Iterator<ReferenceEdge> heapRegionsItr = ln.iteratorToReferencees();
2644 while( heapRegionsItr.hasNext() ) {
2645 ReferenceEdge edge = heapRegionsItr.next();
2646 HeapRegionNode hrn = edge.getDst();
2648 if( pruneGarbage && !visited.contains(hrn) ) {
2649 traverseHeapRegionNodes(VISIT_HRN_WRITE_FULL,
2657 bw.write(" " + ln.toString() +
2658 " -> " + hrn.toString() +
2659 "[label=\"" + edge.toGraphEdgeString() +
2670 protected void traverseHeapRegionNodes(int mode,
2674 HashSet<HeapRegionNode> visited,
2675 boolean writeReferencers
2676 ) throws java.io.IOException {
2678 if( visited.contains(hrn) ) {
2684 case VISIT_HRN_WRITE_FULL:
2686 String attributes = "[";
2688 if( hrn.isSingleObject() ) {
2689 attributes += "shape=box";
2691 attributes += "shape=Msquare";
2694 if( hrn.isFlagged() ) {
2695 attributes += ",style=filled,fillcolor=lightgrey";
2698 attributes += ",label=\"ID" +
2701 hrn.getDescription() +
2703 hrn.getAlphaString() +
2706 bw.write(" " + hrn.toString() + attributes + ";\n");
2711 // useful for debugging
2712 if( writeReferencers ) {
2713 OwnershipNode onRef = null;
2714 Iterator refItr = hrn.iteratorToReferencers();
2715 while( refItr.hasNext() ) {
2716 onRef = (OwnershipNode) refItr.next();
2719 case VISIT_HRN_WRITE_FULL:
2720 bw.write(" " + hrn.toString() +
2721 " -> " + onRef.toString() +
2722 "[color=lightgray];\n");
2728 Iterator<ReferenceEdge> childRegionsItr = hrn.iteratorToReferencees();
2729 while( childRegionsItr.hasNext() ) {
2730 ReferenceEdge edge = childRegionsItr.next();
2731 HeapRegionNode hrnChild = edge.getDst();
2734 case VISIT_HRN_WRITE_FULL:
2735 bw.write(" " + hrn.toString() +
2736 " -> " + hrnChild.toString() +
2737 "[label=\"" + edge.toGraphEdgeString() +
2742 traverseHeapRegionNodes(mode,