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___");
22 protected static final int bogusParamIndexInt = -2;
25 public Hashtable<Integer, HeapRegionNode> id2hrn;
26 public Hashtable<TempDescriptor, LabelNode > td2ln;
27 public Hashtable<Integer, Set<Integer> > id2paramIndexSet;
28 public Hashtable<Integer, Integer > paramIndex2id;
29 public Hashtable<Integer, TempDescriptor> paramIndex2tdQ;
31 public HashSet<AllocationSite> allocationSites;
36 public OwnershipGraph(int allocationDepth, TypeUtil typeUtil) {
37 this.allocationDepth = allocationDepth;
38 this.typeUtil = typeUtil;
40 id2hrn = new Hashtable<Integer, HeapRegionNode>();
41 td2ln = new Hashtable<TempDescriptor, LabelNode >();
42 id2paramIndexSet = new Hashtable<Integer, Set<Integer> >();
43 paramIndex2id = new Hashtable<Integer, Integer >();
44 paramIndex2tdQ = new Hashtable<Integer, TempDescriptor>();
46 allocationSites = new HashSet <AllocationSite>();
50 // label nodes are much easier to deal with than
51 // heap region nodes. Whenever there is a request
52 // for the label node that is associated with a
53 // temp descriptor we can either find it or make a
54 // new one and return it. This is because temp
55 // descriptors are globally unique and every label
56 // node is mapped to exactly one temp descriptor.
57 protected LabelNode getLabelNodeFromTemp(TempDescriptor td) {
60 if( !td2ln.containsKey(td) ) {
61 td2ln.put(td, new LabelNode(td) );
68 // the reason for this method is to have the option
69 // creating new heap regions with specific IDs, or
70 // duplicating heap regions with specific IDs (especially
71 // in the merge() operation) or to create new heap
72 // regions with a new unique ID.
73 protected HeapRegionNode
74 createNewHeapRegionNode(Integer id,
75 boolean isSingleObject,
79 AllocationSite allocSite,
80 ReachabilitySet alpha,
83 boolean markForAnalysis = isFlagged || isParameter;
85 if( allocSite != null && allocSite.getDisjointId() != null ) {
86 markForAnalysis = true;
90 id = OwnershipAnalysis.generateUniqueHeapRegionNodeID();
94 if( markForAnalysis ) {
95 alpha = new ReachabilitySet(
102 alpha = new ReachabilitySet(
103 new TokenTupleSet().makeCanonical()
108 HeapRegionNode hrn = new HeapRegionNode(id,
122 ////////////////////////////////////////////////
124 // Low-level referencee and referencer methods
126 // These methods provide the lowest level for
127 // creating references between ownership nodes
128 // and handling the details of maintaining both
129 // list of referencers and referencees.
131 ////////////////////////////////////////////////
132 protected void addReferenceEdge(OwnershipNode referencer,
133 HeapRegionNode referencee,
134 ReferenceEdge edge) {
135 assert referencer != null;
136 assert referencee != null;
138 assert edge.getSrc() == referencer;
139 assert edge.getDst() == referencee;
141 referencer.addReferencee(edge);
142 referencee.addReferencer(edge);
145 protected void removeReferenceEdge(OwnershipNode referencer,
146 HeapRegionNode referencee,
147 FieldDescriptor fieldDesc) {
148 assert referencer != null;
149 assert referencee != null;
151 ReferenceEdge edge = referencer.getReferenceTo(referencee,
154 assert edge == referencee.getReferenceFrom(referencer,
157 referencer.removeReferencee(edge);
158 referencee.removeReferencer(edge);
161 protected void clearReferenceEdgesFrom(OwnershipNode referencer,
162 FieldDescriptor fieldDesc,
164 assert referencer != null;
166 // get a copy of the set to iterate over, otherwise
167 // we will be trying to take apart the set as we
168 // are iterating over it, which won't work
169 Iterator<ReferenceEdge> i = referencer.iteratorToReferenceesClone();
170 while( i.hasNext() ) {
171 ReferenceEdge edge = i.next();
173 if( removeAll || edge.getFieldDesc() == fieldDesc ) {
174 HeapRegionNode referencee = edge.getDst();
176 removeReferenceEdge(referencer,
178 edge.getFieldDesc() );
183 protected void clearReferenceEdgesTo(HeapRegionNode referencee,
184 FieldDescriptor fieldDesc,
186 assert referencee != null;
188 // get a copy of the set to iterate over, otherwise
189 // we will be trying to take apart the set as we
190 // are iterating over it, which won't work
191 Iterator<ReferenceEdge> i = referencee.iteratorToReferencersClone();
192 while( i.hasNext() ) {
193 ReferenceEdge edge = i.next();
195 if( removeAll || edge.getFieldDesc() == fieldDesc ) {
196 OwnershipNode referencer = edge.getSrc();
197 removeReferenceEdge(referencer,
199 edge.getFieldDesc() );
205 protected void propagateTokensOverNodes(HeapRegionNode nPrime,
207 HashSet<HeapRegionNode> nodesWithNewAlpha,
208 HashSet<ReferenceEdge> edgesWithNewBeta) {
210 HashSet<HeapRegionNode> todoNodes
211 = new HashSet<HeapRegionNode>();
212 todoNodes.add(nPrime);
214 HashSet<ReferenceEdge> todoEdges
215 = new HashSet<ReferenceEdge>();
217 Hashtable<HeapRegionNode, ChangeTupleSet> nodePlannedChanges
218 = new Hashtable<HeapRegionNode, ChangeTupleSet>();
219 nodePlannedChanges.put(nPrime, c0);
221 Hashtable<ReferenceEdge, ChangeTupleSet> edgePlannedChanges
222 = new Hashtable<ReferenceEdge, ChangeTupleSet>();
225 while( !todoNodes.isEmpty() ) {
226 HeapRegionNode n = todoNodes.iterator().next();
227 ChangeTupleSet C = nodePlannedChanges.get(n);
229 Iterator itrC = C.iterator();
230 while( itrC.hasNext() ) {
231 ChangeTuple c = (ChangeTuple) itrC.next();
233 if( n.getAlpha().contains(c.getSetToMatch() ) ) {
234 ReachabilitySet withChange =
235 n.getAlpha().remove( c.getSetToMatch() ).union( c.getSetToAdd() );
237 n.setAlphaNew( n.getAlphaNew().union(withChange) );
238 nodesWithNewAlpha.add(n);
242 Iterator<ReferenceEdge> referItr = n.iteratorToReferencers();
243 while( referItr.hasNext() ) {
244 ReferenceEdge edge = referItr.next();
247 if( !edgePlannedChanges.containsKey(edge) ) {
248 edgePlannedChanges.put(edge, new ChangeTupleSet().makeCanonical() );
251 edgePlannedChanges.put(edge, edgePlannedChanges.get(edge).union(C) );
254 Iterator<ReferenceEdge> refeeItr = n.iteratorToReferencees();
255 while( refeeItr.hasNext() ) {
256 ReferenceEdge edgeF = refeeItr.next();
257 HeapRegionNode m = edgeF.getDst();
259 ChangeTupleSet changesToPass = new ChangeTupleSet().makeCanonical();
261 Iterator<ChangeTuple> itrCprime = C.iterator();
262 while( itrCprime.hasNext() ) {
263 ChangeTuple c = itrCprime.next();
264 if( edgeF.getBeta().contains(c.getSetToMatch() ) ) {
265 changesToPass = changesToPass.union(c);
269 if( !changesToPass.isEmpty() ) {
270 if( !nodePlannedChanges.containsKey(m) ) {
271 nodePlannedChanges.put(m, new ChangeTupleSet().makeCanonical() );
274 ChangeTupleSet currentChanges = nodePlannedChanges.get(m);
276 if( !changesToPass.isSubset(currentChanges) ) {
278 nodePlannedChanges.put(m, currentChanges.union(changesToPass) );
287 propagateTokensOverEdges(todoEdges, edgePlannedChanges, edgesWithNewBeta);
291 protected void propagateTokensOverEdges(
292 HashSet<ReferenceEdge> todoEdges,
293 Hashtable<ReferenceEdge, ChangeTupleSet> edgePlannedChanges,
294 HashSet<ReferenceEdge> edgesWithNewBeta) {
297 while( !todoEdges.isEmpty() ) {
298 ReferenceEdge edgeE = todoEdges.iterator().next();
299 todoEdges.remove(edgeE);
301 if( !edgePlannedChanges.containsKey(edgeE) ) {
302 edgePlannedChanges.put(edgeE, new ChangeTupleSet().makeCanonical() );
305 ChangeTupleSet C = edgePlannedChanges.get(edgeE);
307 ChangeTupleSet changesToPass = new ChangeTupleSet().makeCanonical();
309 Iterator<ChangeTuple> itrC = C.iterator();
310 while( itrC.hasNext() ) {
311 ChangeTuple c = itrC.next();
312 if( edgeE.getBeta().contains(c.getSetToMatch() ) ) {
313 ReachabilitySet withChange =
314 edgeE.getBeta().remove( c.getSetToMatch() ).union( c.getSetToAdd() );
316 edgeE.setBetaNew(edgeE.getBetaNew().union(withChange) );
317 edgesWithNewBeta.add(edgeE);
318 changesToPass = changesToPass.union(c);
322 OwnershipNode onSrc = edgeE.getSrc();
324 if( !changesToPass.isEmpty() && onSrc instanceof HeapRegionNode ) {
325 HeapRegionNode n = (HeapRegionNode) onSrc;
327 Iterator<ReferenceEdge> referItr = n.iteratorToReferencers();
328 while( referItr.hasNext() ) {
329 ReferenceEdge edgeF = referItr.next();
331 if( !edgePlannedChanges.containsKey(edgeF) ) {
332 edgePlannedChanges.put(edgeF, new ChangeTupleSet().makeCanonical() );
335 ChangeTupleSet currentChanges = edgePlannedChanges.get(edgeF);
337 if( !changesToPass.isSubset(currentChanges) ) {
338 todoEdges.add(edgeF);
339 edgePlannedChanges.put(edgeF, currentChanges.union(changesToPass) );
347 ////////////////////////////////////////////////////
349 // Assignment Operation Methods
351 // These methods are high-level operations for
352 // modeling program assignment statements using
353 // the low-level reference create/remove methods
356 // The destination in an assignment statement is
357 // going to have new references. The method of
358 // determining the references depends on the type
359 // of the FlatNode assignment and the predicates
360 // of the nodes and edges involved.
362 ////////////////////////////////////////////////////
363 public void assignTempXEqualToTempY(TempDescriptor x,
366 LabelNode lnX = getLabelNodeFromTemp(x);
367 LabelNode lnY = getLabelNodeFromTemp(y);
369 clearReferenceEdgesFrom(lnX, null, true);
371 Iterator<ReferenceEdge> itrYhrn = lnY.iteratorToReferencees();
372 while( itrYhrn.hasNext() ) {
373 ReferenceEdge edgeY = itrYhrn.next();
374 HeapRegionNode referencee = edgeY.getDst();
375 ReferenceEdge edgeNew = edgeY.copy();
378 addReferenceEdge(lnX, referencee, edgeNew);
383 public void assignTempXEqualToTempYFieldF(TempDescriptor x,
386 LabelNode lnX = getLabelNodeFromTemp(x);
387 LabelNode lnY = getLabelNodeFromTemp(y);
389 clearReferenceEdgesFrom(lnX, null, true);
391 Iterator<ReferenceEdge> itrYhrn = lnY.iteratorToReferencees();
392 while( itrYhrn.hasNext() ) {
393 ReferenceEdge edgeY = itrYhrn.next();
394 HeapRegionNode hrnY = edgeY.getDst();
395 ReachabilitySet betaY = edgeY.getBeta();
397 Iterator<ReferenceEdge> itrHrnFhrn = hrnY.iteratorToReferencees();
398 while( itrHrnFhrn.hasNext() ) {
399 ReferenceEdge edgeHrn = itrHrnFhrn.next();
400 HeapRegionNode hrnHrn = edgeHrn.getDst();
401 ReachabilitySet betaHrn = edgeHrn.getBeta();
403 if( edgeHrn.getFieldDesc() == null ||
404 edgeHrn.getFieldDesc() == f ) {
406 ReferenceEdge edgeNew = new ReferenceEdge(lnX,
410 betaY.intersection(betaHrn) );
412 addReferenceEdge(lnX, hrnHrn, edgeNew);
419 public void assignTempXFieldFEqualToTempY(TempDescriptor x,
422 LabelNode lnX = getLabelNodeFromTemp(x);
423 LabelNode lnY = getLabelNodeFromTemp(y);
425 HashSet<HeapRegionNode> nodesWithNewAlpha = new HashSet<HeapRegionNode>();
426 HashSet<ReferenceEdge> edgesWithNewBeta = new HashSet<ReferenceEdge>();
429 // first look for possible strong updates and remove those edges
430 boolean strongUpdate = false;
432 Iterator<ReferenceEdge> itrXhrn = lnX.iteratorToReferencees();
433 while( itrXhrn.hasNext() ) {
434 ReferenceEdge edgeX = itrXhrn.next();
435 HeapRegionNode hrnX = edgeX.getDst();
437 Iterator<ReferenceEdge> itrYhrn = lnY.iteratorToReferencees();
438 while( itrYhrn.hasNext() ) {
439 ReferenceEdge edgeY = itrYhrn.next();
440 HeapRegionNode hrnY = edgeY.getDst();
442 // we can do a strong update here if one of two cases holds
444 hrnX.isSingleObject() &&
445 ( (hrnX.getNumReferencers() == 1) ||
446 ( lnX.getNumReferencees() == 1)
450 clearReferenceEdgesFrom( hrnX, f, false );
456 // then do all token propagation
457 itrXhrn = lnX.iteratorToReferencees();
458 while( itrXhrn.hasNext() ) {
459 ReferenceEdge edgeX = itrXhrn.next();
460 HeapRegionNode hrnX = edgeX.getDst();
461 ReachabilitySet betaX = edgeX.getBeta();
463 ReachabilitySet R = hrnX.getAlpha().intersection(edgeX.getBeta() );
465 Iterator<ReferenceEdge> itrYhrn = lnY.iteratorToReferencees();
466 while( itrYhrn.hasNext() ) {
467 ReferenceEdge edgeY = itrYhrn.next();
468 HeapRegionNode hrnY = edgeY.getDst();
469 ReachabilitySet O = edgeY.getBeta();
472 // propagate tokens over nodes starting from hrnSrc, and it will
473 // take care of propagating back up edges from any touched nodes
474 ChangeTupleSet Cy = O.unionUpArityToChangeSet(R);
475 propagateTokensOverNodes(hrnY, Cy, nodesWithNewAlpha, edgesWithNewBeta);
478 // then propagate back just up the edges from hrn
479 ChangeTupleSet Cx = R.unionUpArityToChangeSet(O);
482 HashSet<ReferenceEdge> todoEdges = new HashSet<ReferenceEdge>();
484 Hashtable<ReferenceEdge, ChangeTupleSet> edgePlannedChanges =
485 new Hashtable<ReferenceEdge, ChangeTupleSet>();
487 Iterator<ReferenceEdge> referItr = hrnX.iteratorToReferencers();
488 while( referItr.hasNext() ) {
489 ReferenceEdge edgeUpstream = referItr.next();
490 todoEdges.add(edgeUpstream);
491 edgePlannedChanges.put(edgeUpstream, Cx);
494 propagateTokensOverEdges(todoEdges,
501 // apply the updates to reachability
502 Iterator<HeapRegionNode> nodeItr = nodesWithNewAlpha.iterator();
503 while( nodeItr.hasNext() ) {
504 nodeItr.next().applyAlphaNew();
507 Iterator<ReferenceEdge> edgeItr = edgesWithNewBeta.iterator();
508 while( edgeItr.hasNext() ) {
509 edgeItr.next().applyBetaNew();
512 // then go back through and add the new edges
513 itrXhrn = lnX.iteratorToReferencees();
514 while( itrXhrn.hasNext() ) {
515 ReferenceEdge edgeX = itrXhrn.next();
516 HeapRegionNode hrnX = edgeX.getDst();
518 Iterator<ReferenceEdge> itrYhrn = lnY.iteratorToReferencees();
519 while( itrYhrn.hasNext() ) {
520 ReferenceEdge edgeY = itrYhrn.next();
521 HeapRegionNode hrnY = edgeY.getDst();
523 // prepare the new reference edge hrnX.f -> hrnY
524 ReferenceEdge edgeNew = new ReferenceEdge(hrnX,
528 edgeY.getBeta().pruneBy( hrnX.getAlpha() )
531 // look to see if an edge with same field exists
532 // and merge with it, otherwise just add the edge
533 ReferenceEdge edgeExisting = hrnX.getReferenceTo( hrnY, f );
535 if( edgeExisting != null ) {
536 edgeExisting.setBeta(
537 edgeExisting.getBeta().union( edgeNew.getBeta() )
539 // a new edge here cannot be reflexive, so existing will
540 // always be also not reflexive anymore
541 edgeExisting.setIsInitialParamReflexive( false );
543 addReferenceEdge( hrnX, hrnY, edgeNew );
548 // if there was a strong update, make sure to improve
549 // reachability with a global sweep
556 public void assignTempEqualToParamAlloc(TempDescriptor td,
558 Integer paramIndex) {
561 LabelNode lnParam = getLabelNodeFromTemp(td);
562 HeapRegionNode hrn = createNewHeapRegionNode(null,
569 "param" + paramIndex);
571 // this is a non-program-accessible label that picks up beta
572 // info to be used for fixing a caller of this method
573 TempDescriptor tdParamQ = new TempDescriptor(td+"specialQ");
574 LabelNode lnParamQ = getLabelNodeFromTemp(tdParamQ);
576 // keep track of heap regions that were created for
577 // parameter labels, the index of the parameter they
578 // are for is important when resolving method calls
579 Integer newID = hrn.getID();
580 assert !id2paramIndexSet.containsKey(newID);
581 Set s = new HashSet<Integer>();
583 id2paramIndexSet.put(newID, s);
584 paramIndex2id.put(paramIndex, newID);
585 paramIndex2tdQ.put(paramIndex, tdParamQ);
587 ReachabilitySet beta = new ReachabilitySet(new TokenTuple(newID,
589 TokenTuple.ARITY_ONE).makeCanonical()
592 // heap regions for parameters are always multiple object (see above)
593 // and have a reference to themselves, because we can't know the
594 // structure of memory that is passed into the method. We're assuming
597 ReferenceEdge edgeFromLabel =
598 new ReferenceEdge(lnParam, hrn, null, false, beta);
600 ReferenceEdge edgeFromLabelQ =
601 new ReferenceEdge(lnParamQ, hrn, null, false, beta);
603 ReferenceEdge edgeReflexive =
604 new ReferenceEdge(hrn, hrn, null, true, beta);
606 addReferenceEdge(lnParam, hrn, edgeFromLabel);
607 addReferenceEdge(lnParamQ, hrn, edgeFromLabelQ);
608 addReferenceEdge(hrn, hrn, edgeReflexive);
611 public void makeAliasedParamHeapRegionNode(TempDescriptor td) {
614 LabelNode lnParam = getLabelNodeFromTemp(td);
615 HeapRegionNode hrn = createNewHeapRegionNode(null,
625 ReachabilitySet beta = new ReachabilitySet(new TokenTuple(hrn.getID(),
627 TokenTuple.ARITY_ONE).makeCanonical()
630 // heap regions for parameters are always multiple object (see above)
631 // and have a reference to themselves, because we can't know the
632 // structure of memory that is passed into the method. We're assuming
635 ReferenceEdge edgeFromLabel =
636 new ReferenceEdge(lnParam, hrn, null, false, beta);
638 ReferenceEdge edgeReflexive =
639 new ReferenceEdge(hrn, hrn, null, true, beta);
641 addReferenceEdge(lnParam, hrn, edgeFromLabel);
642 addReferenceEdge(hrn, hrn, edgeReflexive);
645 public void assignTempEqualToAliasedParam(TempDescriptor tdParam,
646 TempDescriptor tdAliased,
647 Integer paramIndex ) {
649 assert tdParam != null;
650 assert tdAliased != null;
652 LabelNode lnParam = getLabelNodeFromTemp(tdParam);
653 LabelNode lnAliased = getLabelNodeFromTemp(tdAliased);
655 // this is a non-program-accessible label that picks up beta
656 // info to be used for fixing a caller of this method
657 TempDescriptor tdParamQ = new TempDescriptor(tdParam+"specialQ");
658 LabelNode lnParamQ = getLabelNodeFromTemp(tdParamQ);
660 // the lnAliased should always only reference one node, and that
661 // heap region node is the aliased param blob
662 assert lnAliased.getNumReferencees() == 1;
663 HeapRegionNode hrnAliasBlob = lnAliased.iteratorToReferencees().next().getDst();
665 // keep track of heap regions that were created for
666 // parameter labels, the index of the parameter they
667 // are for is important when resolving method calls
668 Integer idAliased = hrnAliasBlob.getID();
669 Set s = id2paramIndexSet.get( idAliased );
671 s = new HashSet<Integer>();
674 id2paramIndexSet.put(idAliased, s);
675 paramIndex2id.put(paramIndex, idAliased);
676 paramIndex2tdQ.put(paramIndex, tdParamQ);
678 ReachabilitySet beta = new ReachabilitySet(new TokenTuple(idAliased,
680 TokenTuple.ARITY_ONE).makeCanonical()
683 // heap regions for parameters are always multiple object (see above)
684 // and have a reference to themselves, because we can't know the
685 // structure of memory that is passed into the method. We're assuming
688 ReferenceEdge edgeFromLabel =
689 new ReferenceEdge(lnParam, hrnAliasBlob, null, false, beta);
691 ReferenceEdge edgeFromLabelQ =
692 new ReferenceEdge(lnParamQ, hrnAliasBlob, null, false, beta);
694 addReferenceEdge(lnParam, hrnAliasBlob, edgeFromLabel);
695 addReferenceEdge(lnParamQ, hrnAliasBlob, edgeFromLabelQ);
700 public void assignReturnEqualToTemp(TempDescriptor x) {
702 LabelNode lnR = getLabelNodeFromTemp(tdReturn);
703 LabelNode lnX = getLabelNodeFromTemp(x);
705 clearReferenceEdgesFrom(lnR, null, true);
707 Iterator<ReferenceEdge> itrXhrn = lnX.iteratorToReferencees();
708 while( itrXhrn.hasNext() ) {
709 ReferenceEdge edgeX = itrXhrn.next();
710 HeapRegionNode referencee = edgeX.getDst();
711 ReferenceEdge edgeNew = edgeX.copy();
714 addReferenceEdge(lnR, referencee, edgeNew);
719 public void assignTempEqualToNewAlloc(TempDescriptor x,
726 // after the age operation the newest (or zero-ith oldest)
727 // node associated with the allocation site should have
728 // no references to it as if it were a newly allocated
729 // heap region, so make a reference to it to complete
732 Integer idNewest = as.getIthOldest(0);
733 HeapRegionNode hrnNewest = id2hrn.get(idNewest);
734 assert hrnNewest != null;
736 LabelNode lnX = getLabelNodeFromTemp(x);
737 clearReferenceEdgesFrom(lnX, null, true);
739 ReferenceEdge edgeNew =
740 new ReferenceEdge(lnX, hrnNewest, null, false, hrnNewest.getAlpha() );
742 addReferenceEdge(lnX, hrnNewest, edgeNew);
746 // use the allocation site (unique to entire analysis) to
747 // locate the heap region nodes in this ownership graph
748 // that should be aged. The process models the allocation
749 // of new objects and collects all the oldest allocations
750 // in a summary node to allow for a finite analysis
752 // There is an additional property of this method. After
753 // running it on a particular ownership graph (many graphs
754 // may have heap regions related to the same allocation site)
755 // the heap region node objects in this ownership graph will be
756 // allocated. Therefore, after aging a graph for an allocation
757 // site, attempts to retrieve the heap region nodes using the
758 // integer id's contained in the allocation site should always
759 // return non-null heap regions.
760 public void age(AllocationSite as) {
762 // aging adds this allocation site to the graph's
763 // list of sites that exist in the graph, or does
764 // nothing if the site is already in the list
765 allocationSites.add(as);
767 // get the summary node for the allocation site in the context
768 // of this particular ownership graph
769 HeapRegionNode hrnSummary = getSummaryNode(as);
771 // merge oldest node into summary
772 Integer idK = as.getOldest();
773 HeapRegionNode hrnK = id2hrn.get(idK);
774 mergeIntoSummary(hrnK, hrnSummary);
776 // move down the line of heap region nodes
777 // clobbering the ith and transferring all references
778 // to and from i-1 to node i. Note that this clobbers
779 // the oldest node (hrnK) that was just merged into
781 for( int i = allocationDepth - 1; i > 0; --i ) {
783 // move references from the i-1 oldest to the ith oldest
784 Integer idIth = as.getIthOldest(i);
785 HeapRegionNode hrnI = id2hrn.get(idIth);
786 Integer idImin1th = as.getIthOldest(i - 1);
787 HeapRegionNode hrnImin1 = id2hrn.get(idImin1th);
789 transferOnto(hrnImin1, hrnI);
792 // as stated above, the newest node should have had its
793 // references moved over to the second oldest, so we wipe newest
794 // in preparation for being the new object to assign something to
795 Integer id0th = as.getIthOldest(0);
796 HeapRegionNode hrn0 = id2hrn.get(id0th);
799 // clear all references in and out of newest node
800 clearReferenceEdgesFrom(hrn0, null, true);
801 clearReferenceEdgesTo(hrn0, null, true);
804 // now tokens in reachability sets need to "age" also
805 Iterator itrAllLabelNodes = td2ln.entrySet().iterator();
806 while( itrAllLabelNodes.hasNext() ) {
807 Map.Entry me = (Map.Entry)itrAllLabelNodes.next();
808 LabelNode ln = (LabelNode) me.getValue();
810 Iterator<ReferenceEdge> itrEdges = ln.iteratorToReferencees();
811 while( itrEdges.hasNext() ) {
812 ageTokens(as, itrEdges.next() );
816 Iterator itrAllHRNodes = id2hrn.entrySet().iterator();
817 while( itrAllHRNodes.hasNext() ) {
818 Map.Entry me = (Map.Entry)itrAllHRNodes.next();
819 HeapRegionNode hrnToAge = (HeapRegionNode) me.getValue();
821 ageTokens(as, hrnToAge);
823 Iterator<ReferenceEdge> itrEdges = hrnToAge.iteratorToReferencees();
824 while( itrEdges.hasNext() ) {
825 ageTokens(as, itrEdges.next() );
830 // after tokens have been aged, reset newest node's reachability
831 if( hrn0.isFlagged() ) {
832 hrn0.setAlpha(new ReachabilitySet(
834 new TokenTuple(hrn0).makeCanonical()
839 hrn0.setAlpha(new ReachabilitySet(
840 new TokenTupleSet().makeCanonical()
847 protected HeapRegionNode getSummaryNode(AllocationSite as) {
849 Integer idSummary = as.getSummary();
850 HeapRegionNode hrnSummary = id2hrn.get(idSummary);
852 // If this is null then we haven't touched this allocation site
853 // in the context of the current ownership graph, so allocate
854 // heap region nodes appropriate for the entire allocation site.
855 // This should only happen once per ownership graph per allocation site,
856 // and a particular integer id can be used to locate the heap region
857 // in different ownership graphs that represents the same part of an
859 if( hrnSummary == null ) {
861 boolean hasFlags = false;
862 if( as.getType().isClass() ) {
863 hasFlags = as.getType().getClassDesc().hasFlags();
866 hrnSummary = createNewHeapRegionNode(idSummary,
873 as.toStringForDOT() + "\\nsummary");
875 for( int i = 0; i < as.getAllocationDepth(); ++i ) {
876 Integer idIth = as.getIthOldest(i);
877 assert !id2hrn.containsKey(idIth);
878 createNewHeapRegionNode(idIth,
885 as.toStringForDOT() + "\\n" + i + " oldest");
893 protected HeapRegionNode getShadowSummaryNode(AllocationSite as) {
895 Integer idShadowSummary = as.getSummaryShadow();
896 HeapRegionNode hrnShadowSummary = id2hrn.get(idShadowSummary);
898 if( hrnShadowSummary == null ) {
900 boolean hasFlags = false;
901 if( as.getType().isClass() ) {
902 hasFlags = as.getType().getClassDesc().hasFlags();
905 hrnShadowSummary = createNewHeapRegionNode(idShadowSummary,
912 as + "\\n" + as.getType() + "\\nshadowSum");
914 for( int i = 0; i < as.getAllocationDepth(); ++i ) {
915 Integer idShadowIth = as.getIthOldestShadow(i);
916 assert !id2hrn.containsKey(idShadowIth);
917 createNewHeapRegionNode(idShadowIth,
924 as + "\\n" + as.getType() + "\\n" + i + " shadow");
928 return hrnShadowSummary;
932 protected void mergeIntoSummary(HeapRegionNode hrn, HeapRegionNode hrnSummary) {
933 assert hrnSummary.isNewSummary();
935 // transfer references _from_ hrn over to hrnSummary
936 Iterator<ReferenceEdge> itrReferencee = hrn.iteratorToReferencees();
937 while( itrReferencee.hasNext() ) {
938 ReferenceEdge edge = itrReferencee.next();
939 ReferenceEdge edgeMerged = edge.copy();
940 edgeMerged.setSrc(hrnSummary);
942 HeapRegionNode hrnReferencee = edge.getDst();
943 ReferenceEdge edgeSummary = hrnSummary.getReferenceTo(hrnReferencee, edge.getFieldDesc() );
945 if( edgeSummary == null ) {
946 // the merge is trivial, nothing to be done
948 // otherwise an edge from the referencer to hrnSummary exists already
949 // and the edge referencer->hrn should be merged with it
950 edgeMerged.setBeta(edgeMerged.getBeta().union(edgeSummary.getBeta() ) );
953 addReferenceEdge(hrnSummary, hrnReferencee, edgeMerged);
956 // next transfer references _to_ hrn over to hrnSummary
957 Iterator<ReferenceEdge> itrReferencer = hrn.iteratorToReferencers();
958 while( itrReferencer.hasNext() ) {
959 ReferenceEdge edge = itrReferencer.next();
960 ReferenceEdge edgeMerged = edge.copy();
961 edgeMerged.setDst(hrnSummary);
963 OwnershipNode onReferencer = edge.getSrc();
964 ReferenceEdge edgeSummary = onReferencer.getReferenceTo(hrnSummary, edge.getFieldDesc() );
966 if( edgeSummary == null ) {
967 // the merge is trivial, nothing to be done
969 // otherwise an edge from the referencer to alpha_S exists already
970 // and the edge referencer->alpha_K should be merged with it
971 edgeMerged.setBeta(edgeMerged.getBeta().union(edgeSummary.getBeta() ) );
974 addReferenceEdge(onReferencer, hrnSummary, edgeMerged);
977 // then merge hrn reachability into hrnSummary
978 hrnSummary.setAlpha(hrnSummary.getAlpha().union(hrn.getAlpha() ) );
982 protected void transferOnto(HeapRegionNode hrnA, HeapRegionNode hrnB) {
984 // clear references in and out of node b
985 clearReferenceEdgesFrom(hrnB, null, true);
986 clearReferenceEdgesTo(hrnB, null, true);
988 // copy each edge in and out of A to B
989 Iterator<ReferenceEdge> itrReferencee = hrnA.iteratorToReferencees();
990 while( itrReferencee.hasNext() ) {
991 ReferenceEdge edge = itrReferencee.next();
992 HeapRegionNode hrnReferencee = edge.getDst();
993 ReferenceEdge edgeNew = edge.copy();
994 edgeNew.setSrc(hrnB);
996 addReferenceEdge(hrnB, hrnReferencee, edgeNew);
999 Iterator<ReferenceEdge> itrReferencer = hrnA.iteratorToReferencers();
1000 while( itrReferencer.hasNext() ) {
1001 ReferenceEdge edge = itrReferencer.next();
1002 OwnershipNode onReferencer = edge.getSrc();
1003 ReferenceEdge edgeNew = edge.copy();
1004 edgeNew.setDst(hrnB);
1006 addReferenceEdge(onReferencer, hrnB, edgeNew);
1009 // replace hrnB reachability with hrnA's
1010 hrnB.setAlpha(hrnA.getAlpha() );
1014 protected void ageTokens(AllocationSite as, ReferenceEdge edge) {
1015 edge.setBeta(edge.getBeta().ageTokens(as) );
1018 protected void ageTokens(AllocationSite as, HeapRegionNode hrn) {
1019 hrn.setAlpha(hrn.getAlpha().ageTokens(as) );
1023 public Set<Integer> calculateAliasedParamSet(FlatCall fc,
1027 Hashtable<Integer, LabelNode> paramIndex2ln =
1028 new Hashtable<Integer, LabelNode>();
1030 Hashtable<Integer, HashSet<HeapRegionNode> > paramIndex2reachableCallerNodes =
1031 new Hashtable<Integer, HashSet<HeapRegionNode> >();
1033 for( int i = 0; i < fm.numParameters(); ++i ) {
1034 Integer paramIndex = new Integer(i);
1036 // now depending on whether the callee is static or not
1037 // we need to account for a "this" argument in order to
1038 // find the matching argument in the caller context
1039 TempDescriptor argTemp_i;
1041 argTemp_i = fc.getArg(paramIndex);
1043 if( paramIndex.equals(0) ) {
1044 argTemp_i = fc.getThis();
1046 argTemp_i = fc.getArg(paramIndex - 1);
1050 // in non-static methods there is a "this" pointer
1051 // that should be taken into account
1053 assert fc.numArgs() == fm.numParameters();
1055 assert fc.numArgs() + 1 == fm.numParameters();
1058 LabelNode argLabel_i = getLabelNodeFromTemp(argTemp_i);
1059 paramIndex2ln.put(paramIndex, argLabel_i);
1062 Iterator lnArgItr = paramIndex2ln.entrySet().iterator();
1063 while( lnArgItr.hasNext() ) {
1064 Map.Entry me = (Map.Entry)lnArgItr.next();
1065 Integer index = (Integer) me.getKey();
1066 LabelNode lnArg_i = (LabelNode) me.getValue();
1068 // rewrite alpha for the nodes reachable from argument label i
1069 HashSet<HeapRegionNode> reachableNodes = new HashSet<HeapRegionNode>();
1070 HashSet<HeapRegionNode> todoNodes = new HashSet<HeapRegionNode>();
1072 // to find all reachable nodes, start with label referencees
1073 Iterator<ReferenceEdge> edgeArgItr = lnArg_i.iteratorToReferencees();
1074 while( edgeArgItr.hasNext() ) {
1075 ReferenceEdge edge = edgeArgItr.next();
1076 todoNodes.add(edge.getDst() );
1079 // then follow links until all reachable nodes have been found
1080 while( !todoNodes.isEmpty() ) {
1081 HeapRegionNode hrn = todoNodes.iterator().next();
1082 todoNodes.remove(hrn);
1083 reachableNodes.add(hrn);
1085 Iterator<ReferenceEdge> edgeItr = hrn.iteratorToReferencees();
1086 while( edgeItr.hasNext() ) {
1087 ReferenceEdge edge = edgeItr.next();
1089 if( !reachableNodes.contains(edge.getDst() ) ) {
1090 todoNodes.add(edge.getDst() );
1096 paramIndex2reachableCallerNodes.put(index, reachableNodes);
1099 Set<Integer> aliasedIndices = new HashSet<Integer>();
1101 // check for arguments that are aliased
1102 for( int i = 0; i < fm.numParameters(); ++i ) {
1103 for( int j = 0; j < i; ++j ) {
1104 HashSet<HeapRegionNode> s1 = paramIndex2reachableCallerNodes.get( i );
1105 HashSet<HeapRegionNode> s2 = paramIndex2reachableCallerNodes.get( j );
1107 Set<HeapRegionNode> intersection = new HashSet<HeapRegionNode>(s1);
1108 intersection.retainAll(s2);
1110 if( !intersection.isEmpty() ) {
1111 aliasedIndices.add( new Integer( i ) );
1112 aliasedIndices.add( new Integer( j ) );
1117 return aliasedIndices;
1121 public void resolveMethodCall(FlatCall fc,
1124 OwnershipGraph ogCallee) {
1126 // define rewrite rules and other structures to organize
1127 // data by parameter/argument index
1128 Hashtable<Integer, ReachabilitySet> paramIndex2rewriteH =
1129 new Hashtable<Integer, ReachabilitySet>();
1131 Hashtable<Integer, ReachabilitySet> paramIndex2rewriteJ =
1132 new Hashtable<Integer, ReachabilitySet>();
1134 Hashtable<Integer, ReachabilitySet> paramIndex2rewriteK =
1135 new Hashtable<Integer, ReachabilitySet>();
1137 Hashtable<Integer, ReachabilitySet> paramIndex2rewrite_d =
1138 new Hashtable<Integer, ReachabilitySet>();
1140 Hashtable<Integer, ReachabilitySet> paramIndex2rewriteD =
1141 new Hashtable<Integer, ReachabilitySet>();
1143 // helpful structures
1144 Hashtable<TokenTuple, Integer> paramToken2paramIndex =
1145 new Hashtable<TokenTuple, Integer>();
1147 Hashtable<Integer, TokenTuple> paramIndex2paramToken =
1148 new Hashtable<Integer, TokenTuple>();
1150 Hashtable<TokenTuple, Integer> paramTokenPlus2paramIndex =
1151 new Hashtable<TokenTuple, Integer>();
1153 Hashtable<Integer, TokenTuple> paramIndex2paramTokenPlus =
1154 new Hashtable<Integer, TokenTuple>();
1156 Hashtable<Integer, LabelNode> paramIndex2ln =
1157 new Hashtable<Integer, LabelNode>();
1159 Hashtable<Integer, HashSet<HeapRegionNode> > paramIndex2reachableCallerNodes =
1160 new Hashtable<Integer, HashSet<HeapRegionNode> >();
1163 // add a bogus entry with the identity rule for easy rewrite
1164 // of new callee nodes and edges, doesn't belong to any parameter
1165 Integer bogusID = new Integer(bogusParamIndexInt);
1166 Integer bogusIndex = new Integer(bogusParamIndexInt);
1167 TokenTuple bogusToken = new TokenTuple(bogusID, true, TokenTuple.ARITY_ONE).makeCanonical();
1168 TokenTuple bogusTokenPlus = new TokenTuple(bogusID, true, TokenTuple.ARITY_ONEORMORE).makeCanonical();
1169 ReachabilitySet rsIdentity =
1170 new ReachabilitySet(
1171 new TokenTupleSet(bogusToken).makeCanonical()
1174 paramIndex2rewriteH.put(bogusIndex, rsIdentity);
1175 paramIndex2rewriteJ.put(bogusIndex, rsIdentity);
1176 paramToken2paramIndex.put(bogusToken, bogusIndex);
1177 paramIndex2paramToken.put(bogusIndex, bogusToken);
1178 paramTokenPlus2paramIndex.put(bogusTokenPlus, bogusIndex);
1179 paramIndex2paramTokenPlus.put(bogusIndex, bogusTokenPlus);
1182 for( int i = 0; i < fm.numParameters(); ++i ) {
1183 Integer paramIndex = new Integer(i);
1185 assert ogCallee.paramIndex2id.containsKey(paramIndex);
1186 Integer idParam = ogCallee.paramIndex2id.get(paramIndex);
1188 assert ogCallee.id2hrn.containsKey(idParam);
1189 HeapRegionNode hrnParam = ogCallee.id2hrn.get(idParam);
1190 assert hrnParam != null;
1191 paramIndex2rewriteH.put(paramIndex,
1193 toShadowTokens(ogCallee, hrnParam.getAlpha() )
1196 ReferenceEdge edgeReflexive_i = hrnParam.getReferenceTo(hrnParam, null);
1197 assert edgeReflexive_i != null;
1198 paramIndex2rewriteJ.put(paramIndex,
1199 toShadowTokens(ogCallee, edgeReflexive_i.getBeta() )
1202 TempDescriptor tdParamQ = ogCallee.paramIndex2tdQ.get(paramIndex);
1203 assert tdParamQ != null;
1204 LabelNode lnParamQ = ogCallee.td2ln.get(tdParamQ);
1205 assert lnParamQ != null;
1206 ReferenceEdge edgeSpecialQ_i = lnParamQ.getReferenceTo(hrnParam, null);
1207 assert edgeSpecialQ_i != null;
1208 paramIndex2rewriteK.put(paramIndex,
1209 toShadowTokens(ogCallee, edgeSpecialQ_i.getBeta() )
1212 TokenTuple p_i = new TokenTuple(hrnParam.getID(),
1214 TokenTuple.ARITY_ONE).makeCanonical();
1215 paramToken2paramIndex.put(p_i, paramIndex);
1216 paramIndex2paramToken.put(paramIndex, p_i);
1218 TokenTuple p_i_plus = new TokenTuple(hrnParam.getID(),
1220 TokenTuple.ARITY_ONEORMORE).makeCanonical();
1221 paramTokenPlus2paramIndex.put(p_i_plus, paramIndex);
1222 paramIndex2paramTokenPlus.put(paramIndex, p_i_plus);
1224 // now depending on whether the callee is static or not
1225 // we need to account for a "this" argument in order to
1226 // find the matching argument in the caller context
1227 TempDescriptor argTemp_i;
1229 argTemp_i = fc.getArg(paramIndex);
1231 if( paramIndex.equals(0) ) {
1232 argTemp_i = fc.getThis();
1234 argTemp_i = fc.getArg(paramIndex - 1);
1238 // in non-static methods there is a "this" pointer
1239 // that should be taken into account
1241 assert fc.numArgs() == fm.numParameters();
1243 assert fc.numArgs() + 1 == fm.numParameters();
1246 LabelNode argLabel_i = getLabelNodeFromTemp(argTemp_i);
1247 paramIndex2ln.put(paramIndex, argLabel_i);
1249 ReachabilitySet d_i = new ReachabilitySet().makeCanonical();
1250 Iterator<ReferenceEdge> edgeItr = argLabel_i.iteratorToReferencees();
1251 while( edgeItr.hasNext() ) {
1252 ReferenceEdge edge = edgeItr.next();
1253 d_i = d_i.union(edge.getBeta());
1255 paramIndex2rewrite_d.put(paramIndex, d_i);
1257 ReachabilitySet D_i = d_i.exhaustiveArityCombinations();
1258 paramIndex2rewriteD.put(paramIndex, D_i);
1262 HashSet<HeapRegionNode> nodesWithNewAlpha = new HashSet<HeapRegionNode>();
1263 HashSet<ReferenceEdge> edgesWithNewBeta = new HashSet<ReferenceEdge>();
1265 HashSet<ReferenceEdge> edgesReachable = new HashSet<ReferenceEdge>();
1266 HashSet<ReferenceEdge> edgesUpstream = new HashSet<ReferenceEdge>();
1268 Iterator lnArgItr = paramIndex2ln.entrySet().iterator();
1269 while( lnArgItr.hasNext() ) {
1270 Map.Entry me = (Map.Entry)lnArgItr.next();
1271 Integer index = (Integer) me.getKey();
1272 LabelNode lnArg_i = (LabelNode) me.getValue();
1274 // rewrite alpha for the nodes reachable from argument label i
1275 HashSet<HeapRegionNode> reachableNodes = new HashSet<HeapRegionNode>();
1276 HashSet<HeapRegionNode> todoNodes = new HashSet<HeapRegionNode>();
1278 // to find all reachable nodes, start with label referencees
1279 Iterator<ReferenceEdge> edgeArgItr = lnArg_i.iteratorToReferencees();
1280 while( edgeArgItr.hasNext() ) {
1281 ReferenceEdge edge = edgeArgItr.next();
1282 todoNodes.add(edge.getDst() );
1285 // then follow links until all reachable nodes have been found
1286 while( !todoNodes.isEmpty() ) {
1287 HeapRegionNode hrn = todoNodes.iterator().next();
1288 todoNodes.remove(hrn);
1289 reachableNodes.add(hrn);
1291 Iterator<ReferenceEdge> edgeItr = hrn.iteratorToReferencees();
1292 while( edgeItr.hasNext() ) {
1293 ReferenceEdge edge = edgeItr.next();
1295 if( !reachableNodes.contains(edge.getDst() ) ) {
1296 todoNodes.add(edge.getDst() );
1302 paramIndex2reachableCallerNodes.put(index, reachableNodes);
1304 // now iterate over reachable nodes to update their alpha, and
1305 // classify edges found as "argument reachable" or "upstream"
1306 Iterator<HeapRegionNode> hrnItr = reachableNodes.iterator();
1307 while( hrnItr.hasNext() ) {
1308 HeapRegionNode hrn = hrnItr.next();
1310 rewriteCallerReachability(index,
1313 paramIndex2rewriteH.get(index),
1314 paramIndex2rewrite_d,
1315 paramIndex2rewriteD,
1316 paramIndex2paramToken.get(index),
1317 paramToken2paramIndex,
1318 paramTokenPlus2paramIndex,
1322 nodesWithNewAlpha.add(hrn);
1324 // look at all incoming edges to the reachable nodes
1325 // and sort them as edges reachable from the argument
1326 // label node, or upstream edges
1327 Iterator<ReferenceEdge> edgeItr = hrn.iteratorToReferencers();
1328 while( edgeItr.hasNext() ) {
1329 ReferenceEdge edge = edgeItr.next();
1331 OwnershipNode on = edge.getSrc();
1333 if( on instanceof LabelNode ) {
1335 LabelNode ln0 = (LabelNode) on;
1336 if( ln0.equals(lnArg_i) ) {
1337 edgesReachable.add(edge);
1339 edgesUpstream.add(edge);
1344 HeapRegionNode hrn0 = (HeapRegionNode) on;
1345 if( reachableNodes.contains(hrn0) ) {
1346 edgesReachable.add(edge);
1348 edgesUpstream.add(edge);
1354 // update reachable edges
1355 Iterator<ReferenceEdge> edgeReachableItr = edgesReachable.iterator();
1356 while( edgeReachableItr.hasNext() ) {
1357 ReferenceEdge edgeReachable = edgeReachableItr.next();
1359 rewriteCallerReachability(index,
1362 paramIndex2rewriteJ.get(index),
1363 paramIndex2rewrite_d,
1364 paramIndex2rewriteD,
1365 paramIndex2paramToken.get(index),
1366 paramToken2paramIndex,
1367 paramTokenPlus2paramIndex,
1371 edgesWithNewBeta.add(edgeReachable);
1374 // update upstream edges
1375 Hashtable<ReferenceEdge, ChangeTupleSet> edgeUpstreamPlannedChanges =
1376 new Hashtable<ReferenceEdge, ChangeTupleSet>();
1378 Iterator<ReferenceEdge> edgeUpstreamItr = edgesUpstream.iterator();
1379 while( edgeUpstreamItr.hasNext() ) {
1380 ReferenceEdge edgeUpstream = edgeUpstreamItr.next();
1382 rewriteCallerReachability(index,
1385 paramIndex2rewriteK.get(index),
1386 paramIndex2rewrite_d,
1387 paramIndex2rewriteD,
1388 paramIndex2paramToken.get(index),
1389 paramToken2paramIndex,
1390 paramTokenPlus2paramIndex,
1392 edgeUpstreamPlannedChanges);
1394 edgesWithNewBeta.add(edgeUpstream);
1397 propagateTokensOverEdges(edgesUpstream,
1398 edgeUpstreamPlannedChanges,
1403 // commit changes to alpha and beta
1404 Iterator<HeapRegionNode> nodeItr = nodesWithNewAlpha.iterator();
1405 while( nodeItr.hasNext() ) {
1406 nodeItr.next().applyAlphaNew();
1409 Iterator<ReferenceEdge> edgeItr = edgesWithNewBeta.iterator();
1410 while( edgeItr.hasNext() ) {
1411 edgeItr.next().applyBetaNew();
1415 // verify the existence of allocation sites and their
1416 // shadows from the callee in the context of this caller graph
1417 // then map allocated nodes of callee onto the caller shadows
1419 Iterator<AllocationSite> asItr = ogCallee.allocationSites.iterator();
1420 while( asItr.hasNext() ) {
1421 AllocationSite allocSite = asItr.next();
1423 // grab the summary in the caller just to make sure
1424 // the allocation site has nodes in the caller
1425 HeapRegionNode hrnSummary = getSummaryNode(allocSite);
1427 // assert that the shadow nodes have no reference edges
1428 // because they're brand new to the graph, or last time
1429 // they were used they should have been cleared of edges
1430 HeapRegionNode hrnShadowSummary = getShadowSummaryNode(allocSite);
1431 assert hrnShadowSummary.getNumReferencers() == 0;
1432 assert hrnShadowSummary.getNumReferencees() == 0;
1434 // then bring g_ij onto g'_ij and rewrite
1435 HeapRegionNode hrnSummaryCallee = ogCallee.getSummaryNode(allocSite);
1436 hrnShadowSummary.setAlpha(toShadowTokens(ogCallee, hrnSummaryCallee.getAlpha() ) );
1438 // shadow nodes only are touched by a rewrite one time,
1439 // so rewrite and immediately commit--and they don't belong
1440 // to a particular parameter, so use a bogus param index
1441 // that pulls a self-rewrite out of H
1442 rewriteCallerReachability(bogusIndex,
1445 hrnShadowSummary.getAlpha(),
1446 paramIndex2rewrite_d,
1447 paramIndex2rewriteD,
1449 paramToken2paramIndex,
1450 paramTokenPlus2paramIndex,
1454 hrnShadowSummary.applyAlphaNew();
1457 for( int i = 0; i < allocSite.getAllocationDepth(); ++i ) {
1458 Integer idIth = allocSite.getIthOldest(i);
1459 assert id2hrn.containsKey(idIth);
1460 HeapRegionNode hrnIth = id2hrn.get(idIth);
1462 Integer idShadowIth = -(allocSite.getIthOldest(i));
1463 assert id2hrn.containsKey(idShadowIth);
1464 HeapRegionNode hrnIthShadow = id2hrn.get(idShadowIth);
1465 assert hrnIthShadow.getNumReferencers() == 0;
1466 assert hrnIthShadow.getNumReferencees() == 0;
1468 assert ogCallee.id2hrn.containsKey(idIth);
1469 HeapRegionNode hrnIthCallee = ogCallee.id2hrn.get(idIth);
1470 hrnIthShadow.setAlpha(toShadowTokens(ogCallee, hrnIthCallee.getAlpha() ) );
1472 rewriteCallerReachability(bogusIndex,
1475 hrnIthShadow.getAlpha(),
1476 paramIndex2rewrite_d,
1477 paramIndex2rewriteD,
1479 paramToken2paramIndex,
1480 paramTokenPlus2paramIndex,
1484 hrnIthShadow.applyAlphaNew();
1489 // for every heap region->heap region edge in the
1490 // callee graph, create the matching edge or edges
1491 // in the caller graph
1492 Set sCallee = ogCallee.id2hrn.entrySet();
1493 Iterator iCallee = sCallee.iterator();
1494 while( iCallee.hasNext() ) {
1495 Map.Entry meCallee = (Map.Entry)iCallee.next();
1496 Integer idCallee = (Integer) meCallee.getKey();
1497 HeapRegionNode hrnCallee = (HeapRegionNode) meCallee.getValue();
1499 Iterator<ReferenceEdge> heapRegionsItrCallee = hrnCallee.iteratorToReferencees();
1500 while( heapRegionsItrCallee.hasNext() ) {
1501 ReferenceEdge edgeCallee = heapRegionsItrCallee.next();
1502 HeapRegionNode hrnChildCallee = edgeCallee.getDst();
1503 Integer idChildCallee = hrnChildCallee.getID();
1505 // only address this edge if it is not a special reflexive edge
1506 if( !edgeCallee.isInitialParamReflexive() ) {
1508 // now we know that in the callee method's ownership graph
1509 // there is a heap region->heap region reference edge given
1510 // by heap region pointers:
1511 // hrnCallee -> heapChildCallee
1513 // or by the ownership-graph independent ID's:
1514 // idCallee -> idChildCallee
1516 // make the edge with src and dst so beta info is
1517 // calculated once, then copy it for each new edge in caller
1518 ReferenceEdge edgeNewInCallerTemplate = new ReferenceEdge(null,
1520 edgeCallee.getFieldDesc(),
1522 toShadowTokens(ogCallee,
1523 edgeCallee.getBeta() )
1525 rewriteCallerReachability(bogusIndex,
1527 edgeNewInCallerTemplate,
1528 edgeNewInCallerTemplate.getBeta(),
1529 paramIndex2rewrite_d,
1530 paramIndex2rewriteD,
1532 paramToken2paramIndex,
1533 paramTokenPlus2paramIndex,
1537 edgeNewInCallerTemplate.applyBetaNew();
1540 // So now make a set of possible source heaps in the caller graph
1541 // and a set of destination heaps in the caller graph, and make
1542 // a reference edge in the caller for every possible (src,dst) pair
1543 HashSet<HeapRegionNode> possibleCallerSrcs =
1544 getHRNSetThatPossiblyMapToCalleeHRN(ogCallee,
1545 (HeapRegionNode) edgeCallee.getSrc(),
1546 paramIndex2reachableCallerNodes);
1548 HashSet<HeapRegionNode> possibleCallerDsts =
1549 getHRNSetThatPossiblyMapToCalleeHRN(ogCallee,
1550 edgeCallee.getDst(),
1551 paramIndex2reachableCallerNodes);
1554 // make every possible pair of {srcSet} -> {dstSet} edges in the caller
1555 Iterator srcItr = possibleCallerSrcs.iterator();
1556 while( srcItr.hasNext() ) {
1557 HeapRegionNode src = (HeapRegionNode) srcItr.next();
1559 if( !hasMatchingField(src, edgeCallee) ) {
1560 // prune this source node possibility
1564 Iterator dstItr = possibleCallerDsts.iterator();
1565 while( dstItr.hasNext() ) {
1566 HeapRegionNode dst = (HeapRegionNode) dstItr.next();
1568 if( !hasMatchingType(edgeCallee, dst) ) {
1573 // otherwise the caller src and dst pair can match the edge, so make it
1574 ReferenceEdge edgeNewInCaller = edgeNewInCallerTemplate.copy();
1575 edgeNewInCaller.setSrc(src);
1576 edgeNewInCaller.setDst(dst);
1578 ReferenceEdge edgeExisting = src.getReferenceTo(dst, edgeNewInCaller.getFieldDesc() );
1579 if( edgeExisting == null ) {
1580 // if this edge doesn't exist in the caller, create it
1581 addReferenceEdge(src, dst, edgeNewInCaller);
1583 // if it already exists, merge with it
1584 edgeExisting.setBeta(edgeExisting.getBeta().union(edgeNewInCaller.getBeta() ) );
1593 // return value may need to be assigned in caller
1594 TempDescriptor returnTemp = fc.getReturnTemp();
1595 if( returnTemp != null && !returnTemp.getType().isImmutable() ) {
1597 LabelNode lnLhsCaller = getLabelNodeFromTemp(returnTemp);
1598 clearReferenceEdgesFrom(lnLhsCaller, null, true);
1600 LabelNode lnReturnCallee = ogCallee.getLabelNodeFromTemp(tdReturn);
1601 Iterator<ReferenceEdge> edgeCalleeItr = lnReturnCallee.iteratorToReferencees();
1602 while( edgeCalleeItr.hasNext() ) {
1603 ReferenceEdge edgeCallee = edgeCalleeItr.next();
1605 ReferenceEdge edgeNewInCallerTemplate = new ReferenceEdge(null,
1607 edgeCallee.getFieldDesc(),
1609 toShadowTokens(ogCallee,
1610 edgeCallee.getBeta() )
1612 rewriteCallerReachability(bogusIndex,
1614 edgeNewInCallerTemplate,
1615 edgeNewInCallerTemplate.getBeta(),
1616 paramIndex2rewrite_d,
1617 paramIndex2rewriteD,
1619 paramToken2paramIndex,
1620 paramTokenPlus2paramIndex,
1624 edgeNewInCallerTemplate.applyBetaNew();
1627 HashSet<HeapRegionNode> assignCallerRhs =
1628 getHRNSetThatPossiblyMapToCalleeHRN(ogCallee,
1629 edgeCallee.getDst(),
1630 paramIndex2reachableCallerNodes);
1632 Iterator<HeapRegionNode> itrHrn = assignCallerRhs.iterator();
1633 while( itrHrn.hasNext() ) {
1634 HeapRegionNode hrnCaller = itrHrn.next();
1636 if( !hasMatchingType(edgeCallee, hrnCaller) ) {
1641 // otherwise caller node can match callee edge, so make it
1642 ReferenceEdge edgeNewInCaller = edgeNewInCallerTemplate.copy();
1643 edgeNewInCaller.setSrc(lnLhsCaller);
1644 edgeNewInCaller.setDst(hrnCaller);
1646 ReferenceEdge edgeExisting = lnLhsCaller.getReferenceTo(hrnCaller, edgeNewInCaller.getFieldDesc() );
1647 if( edgeExisting == null ) {
1649 // if this edge doesn't exist in the caller, create it
1650 addReferenceEdge(lnLhsCaller, hrnCaller, edgeNewInCaller);
1652 // if it already exists, merge with it
1653 edgeExisting.setBeta(edgeExisting.getBeta().union(edgeNewInCaller.getBeta() ) );
1660 // merge the shadow nodes of allocation sites back down to normal capacity
1661 Iterator<AllocationSite> allocItr = ogCallee.allocationSites.iterator();
1662 while( allocItr.hasNext() ) {
1663 AllocationSite as = allocItr.next();
1665 // first age each allocation site enough times to make room for the shadow nodes
1666 for( int i = 0; i < as.getAllocationDepth(); ++i ) {
1670 // then merge the shadow summary into the normal summary
1671 HeapRegionNode hrnSummary = getSummaryNode(as);
1672 assert hrnSummary != null;
1674 HeapRegionNode hrnSummaryShadow = getShadowSummaryNode(as);
1675 assert hrnSummaryShadow != null;
1677 mergeIntoSummary(hrnSummaryShadow, hrnSummary);
1679 // then clear off after merge
1680 clearReferenceEdgesFrom(hrnSummaryShadow, null, true);
1681 clearReferenceEdgesTo(hrnSummaryShadow, null, true);
1682 hrnSummaryShadow.setAlpha(new ReachabilitySet().makeCanonical() );
1684 // then transplant shadow nodes onto the now clean normal nodes
1685 for( int i = 0; i < as.getAllocationDepth(); ++i ) {
1687 Integer idIth = as.getIthOldest(i);
1688 HeapRegionNode hrnIth = id2hrn.get(idIth);
1690 Integer idIthShadow = as.getIthOldestShadow(i);
1691 HeapRegionNode hrnIthShadow = id2hrn.get(idIthShadow);
1693 transferOnto(hrnIthShadow, hrnIth);
1695 // clear off shadow nodes after transfer
1696 clearReferenceEdgesFrom(hrnIthShadow, null, true);
1697 clearReferenceEdgesTo(hrnIthShadow, null, true);
1698 hrnIthShadow.setAlpha(new ReachabilitySet().makeCanonical() );
1701 // finally, globally change shadow tokens into normal tokens
1702 Iterator itrAllLabelNodes = td2ln.entrySet().iterator();
1703 while( itrAllLabelNodes.hasNext() ) {
1704 Map.Entry me = (Map.Entry)itrAllLabelNodes.next();
1705 LabelNode ln = (LabelNode) me.getValue();
1707 Iterator<ReferenceEdge> itrEdges = ln.iteratorToReferencees();
1708 while( itrEdges.hasNext() ) {
1709 unshadowTokens(as, itrEdges.next() );
1713 Iterator itrAllHRNodes = id2hrn.entrySet().iterator();
1714 while( itrAllHRNodes.hasNext() ) {
1715 Map.Entry me = (Map.Entry)itrAllHRNodes.next();
1716 HeapRegionNode hrnToAge = (HeapRegionNode) me.getValue();
1718 unshadowTokens(as, hrnToAge);
1720 Iterator<ReferenceEdge> itrEdges = hrnToAge.iteratorToReferencees();
1721 while( itrEdges.hasNext() ) {
1722 unshadowTokens(as, itrEdges.next() );
1727 // improve reachability as much as possible
1732 protected boolean hasMatchingField(HeapRegionNode src, ReferenceEdge edge) {
1734 // if no allocation site, then it's a match-everything region
1735 AllocationSite asSrc = src.getAllocationSite();
1736 if( asSrc == null ) {
1740 TypeDescriptor tdSrc = asSrc.getType();
1741 assert tdSrc != null;
1743 // if it's not a class, it doesn't have any fields to match
1744 if( !tdSrc.isClass() ) {
1748 Iterator fieldsSrcItr = tdSrc.getClassDesc().getFields();
1749 while( fieldsSrcItr.hasNext() ) {
1750 FieldDescriptor fd = (FieldDescriptor) fieldsSrcItr.next();
1751 if( fd == edge.getFieldDesc() ) {
1756 // otherwise it is a class with fields
1757 // but we didn't find a match
1762 protected boolean hasMatchingType(ReferenceEdge edge, HeapRegionNode dst) {
1764 // if the region has no type, matches everything
1765 AllocationSite asDst = dst.getAllocationSite();
1766 if( asDst == null ) {
1770 TypeDescriptor tdDst = asDst.getType();
1771 assert tdDst != null;
1773 // if the type is not a class don't match because
1774 // primitives are copied, no memory aliases
1775 ClassDescriptor cdDst = tdDst.getClassDesc();
1776 if( cdDst == null ) {
1780 // if the field is null, it matches everything
1781 FieldDescriptor fd = edge.getFieldDesc();
1785 TypeDescriptor tdFd = fd.getType();
1786 assert tdFd != null;
1788 return typeUtil.isSuperorType(tdFd, tdDst);
1793 protected void unshadowTokens(AllocationSite as, ReferenceEdge edge) {
1794 edge.setBeta(edge.getBeta().unshadowTokens(as) );
1797 protected void unshadowTokens(AllocationSite as, HeapRegionNode hrn) {
1798 hrn.setAlpha(hrn.getAlpha().unshadowTokens(as) );
1802 private ReachabilitySet toShadowTokens(OwnershipGraph ogCallee,
1803 ReachabilitySet rsIn) {
1805 ReachabilitySet rsOut = new ReachabilitySet(rsIn).makeCanonical();
1807 Iterator<AllocationSite> allocItr = ogCallee.allocationSites.iterator();
1808 while( allocItr.hasNext() ) {
1809 AllocationSite as = allocItr.next();
1811 rsOut = rsOut.toShadowTokens(as);
1814 return rsOut.makeCanonical();
1818 private void rewriteCallerReachability(Integer paramIndex,
1821 ReachabilitySet rules,
1822 Hashtable<Integer, ReachabilitySet> paramIndex2rewrite_d,
1823 Hashtable<Integer, ReachabilitySet> paramIndex2rewriteD,
1825 Hashtable<TokenTuple, Integer> paramToken2paramIndex,
1826 Hashtable<TokenTuple, Integer> paramTokenPlus2paramIndex,
1827 boolean makeChangeSet,
1828 Hashtable<ReferenceEdge, ChangeTupleSet> edgePlannedChanges) {
1829 assert(hrn == null && edge != null) ||
1830 (hrn != null && edge == null);
1832 assert rules != null;
1835 ReachabilitySet callerReachabilityCurrent;
1837 callerReachabilityCurrent = edge.getBeta();
1839 callerReachabilityCurrent = hrn.getAlpha();
1842 ReachabilitySet callerReachabilityNew = new ReachabilitySet().makeCanonical();
1844 // for initializing structures in this method
1845 TokenTupleSet ttsEmpty = new TokenTupleSet().makeCanonical();
1847 // use this to construct a change set if required; the idea is to
1848 // map every partially rewritten token tuple set to the set of
1849 // caller-context token tuple sets that were used to generate it
1850 Hashtable<TokenTupleSet, HashSet<TokenTupleSet> > rewritten2source =
1851 new Hashtable<TokenTupleSet, HashSet<TokenTupleSet> >();
1852 rewritten2source.put(ttsEmpty, new HashSet<TokenTupleSet>() );
1855 Iterator<TokenTupleSet> rulesItr = rules.iterator();
1856 while(rulesItr.hasNext()) {
1857 TokenTupleSet rule = rulesItr.next();
1859 ReachabilitySet rewrittenRule = new ReachabilitySet(ttsEmpty).makeCanonical();
1861 Iterator<TokenTuple> ruleItr = rule.iterator();
1862 while(ruleItr.hasNext()) {
1863 TokenTuple ttCallee = ruleItr.next();
1865 // compute the possibilities for rewriting this callee token
1866 ReachabilitySet ttCalleeRewrites = null;
1867 boolean callerSourceUsed = false;
1869 if( ttCallee.equals(p_i) ) {
1870 // replace the arity-one token of the current parameter with the reachability
1871 // information from the caller edge
1872 ttCalleeRewrites = callerReachabilityCurrent;
1873 callerSourceUsed = true;
1875 } else if( paramToken2paramIndex.containsKey(ttCallee) ) {
1877 Integer paramIndex_j = paramToken2paramIndex.get(ttCallee);
1878 assert paramIndex_j != null;
1879 ttCalleeRewrites = paramIndex2rewrite_d.get(paramIndex_j);
1880 assert ttCalleeRewrites != null;
1882 } else if( paramTokenPlus2paramIndex.containsKey(ttCallee) ) {
1884 Integer paramIndex_j = paramTokenPlus2paramIndex.get(ttCallee);
1885 assert paramIndex_j != null;
1886 ttCalleeRewrites = paramIndex2rewriteD.get(paramIndex_j);
1887 assert ttCalleeRewrites != null;
1890 // otherwise there's no need for a rewrite, just pass this one on
1891 TokenTupleSet ttsCaller = new TokenTupleSet(ttCallee).makeCanonical();
1892 ttCalleeRewrites = new ReachabilitySet(ttsCaller).makeCanonical();
1895 // branch every version of the working rewritten rule with
1896 // the possibilities for rewriting the current callee token
1897 ReachabilitySet rewrittenRuleWithTTCallee = new ReachabilitySet().makeCanonical();
1899 Iterator<TokenTupleSet> rewrittenRuleItr = rewrittenRule.iterator();
1900 while( rewrittenRuleItr.hasNext() ) {
1901 TokenTupleSet ttsRewritten = rewrittenRuleItr.next();
1903 Iterator<TokenTupleSet> ttCalleeRewritesItr = ttCalleeRewrites.iterator();
1904 while( ttCalleeRewritesItr.hasNext() ) {
1905 TokenTupleSet ttsBranch = ttCalleeRewritesItr.next();
1907 TokenTupleSet ttsRewrittenNext = ttsRewritten.unionUpArity(ttsBranch);
1909 if( makeChangeSet ) {
1910 // in order to keep the list of source token tuple sets
1911 // start with the sets used to make the partially rewritten
1912 // rule up to this point
1913 HashSet<TokenTupleSet> sourceSets = rewritten2source.get(ttsRewritten);
1914 assert sourceSets != null;
1916 // make a shallow copy for possible modification
1917 sourceSets = (HashSet<TokenTupleSet>)sourceSets.clone();
1919 // if we used something from the caller to rewrite it, remember
1920 if( callerSourceUsed ) {
1921 sourceSets.add(ttsBranch);
1924 // set mapping for the further rewritten rule
1925 rewritten2source.put(ttsRewrittenNext, sourceSets);
1928 rewrittenRuleWithTTCallee =
1929 rewrittenRuleWithTTCallee.union(ttsRewrittenNext);
1933 // now the rewritten rule's possibilities have been extended by
1934 // rewriting the current callee token, remember result
1935 rewrittenRule = rewrittenRuleWithTTCallee;
1938 // the rule has been entirely rewritten into the caller context
1939 // now, so add it to the new reachability information
1940 callerReachabilityNew =
1941 callerReachabilityNew.union(rewrittenRule);
1944 if( makeChangeSet ) {
1945 ChangeTupleSet callerChangeSet = new ChangeTupleSet().makeCanonical();
1947 // each possibility for the final reachability should have a set of
1948 // caller sources mapped to it, use to create the change set
1949 Iterator<TokenTupleSet> callerReachabilityItr = callerReachabilityNew.iterator();
1950 while( callerReachabilityItr.hasNext() ) {
1951 TokenTupleSet ttsRewrittenFinal = callerReachabilityItr.next();
1952 HashSet<TokenTupleSet> sourceSets = rewritten2source.get(ttsRewrittenFinal);
1953 assert sourceSets != null;
1955 Iterator<TokenTupleSet> sourceSetsItr = sourceSets.iterator();
1956 while( sourceSetsItr.hasNext() ) {
1957 TokenTupleSet ttsSource = sourceSetsItr.next();
1960 callerChangeSet.union(new ChangeTuple(ttsSource, ttsRewrittenFinal) );
1964 assert edgePlannedChanges != null;
1965 edgePlannedChanges.put(edge, callerChangeSet);
1969 edge.setBetaNew(edge.getBetaNew().union(callerReachabilityNew) );
1971 hrn.setAlphaNew(hrn.getAlphaNew().union(callerReachabilityNew) );
1977 private HashSet<HeapRegionNode>
1978 getHRNSetThatPossiblyMapToCalleeHRN(OwnershipGraph ogCallee,
1979 HeapRegionNode hrnCallee,
1980 Hashtable<Integer, HashSet<HeapRegionNode> > paramIndex2reachableCallerNodes
1983 HashSet<HeapRegionNode> possibleCallerHRNs = new HashSet<HeapRegionNode>();
1985 Set<Integer> paramIndicesCallee = ogCallee.id2paramIndexSet.get( hrnCallee.getID() );
1987 if( paramIndicesCallee == null ) {
1988 // this is a node allocated in the callee then and it has
1989 // exactly one shadow node in the caller to map to
1990 AllocationSite as = hrnCallee.getAllocationSite();
1993 int age = as.getAgeCategory(hrnCallee.getID() );
1994 assert age != AllocationSite.AGE_notInThisSite;
1997 if( age == AllocationSite.AGE_summary ) {
1998 idCaller = as.getSummaryShadow();
1999 } else if( age == AllocationSite.AGE_oldest ) {
2000 idCaller = as.getOldestShadow();
2002 assert age == AllocationSite.AGE_in_I;
2004 Integer I = as.getAge(hrnCallee.getID() );
2007 idCaller = as.getIthOldestShadow(I);
2010 assert id2hrn.containsKey(idCaller);
2011 HeapRegionNode hrnCaller = id2hrn.get(idCaller);
2012 possibleCallerHRNs.add(hrnCaller);
2015 // this is a node that was created to represent a parameter
2016 // so it maps to a whole mess of heap regions
2017 Iterator<Integer> itrIndex = paramIndicesCallee.iterator();
2018 while( itrIndex.hasNext() ) {
2019 Integer paramIndexCallee = itrIndex.next();
2020 assert paramIndex2reachableCallerNodes.containsKey(paramIndexCallee);
2021 possibleCallerHRNs.addAll( paramIndex2reachableCallerNodes.get(paramIndexCallee) );
2025 return possibleCallerHRNs;
2030 ////////////////////////////////////////////////////
2032 // This global sweep is an optional step to prune
2033 // reachability sets that are not internally
2034 // consistent with the global graph. It should be
2035 // invoked after strong updates or method calls.
2037 ////////////////////////////////////////////////////
2038 protected void globalSweep() {
2040 // a work set for performing the sweep
2041 Hashtable<HeapRegionNode, HashSet<TokenTupleSet> > workSet =
2042 new Hashtable<HeapRegionNode, HashSet<TokenTupleSet> >();
2044 // first initialize every alphaNew for a flagged region
2045 // (or parameter region) to a set with just that token
2046 Set hrns = id2hrn.entrySet();
2047 Iterator itrHrns = hrns.iterator();
2048 while( itrHrns.hasNext() ) {
2049 Map.Entry me = (Map.Entry)itrHrns.next();
2050 Integer token = (Integer) me.getKey();
2051 HeapRegionNode hrn = (HeapRegionNode) me.getValue();
2053 // assert that this node and incoming edges have clean alphaNew
2054 // and betaNew sets, respectively
2055 ReachabilitySet rsEmpty = new ReachabilitySet().makeCanonical();
2056 assert rsEmpty.equals( hrn.getAlphaNew() );
2058 Iterator<ReferenceEdge> itrRes = hrn.iteratorToReferencers();
2059 while( itrRes.hasNext() ) {
2060 ReferenceEdge edge = itrRes.next();
2061 assert rsEmpty.equals( edge.getBetaNew() );
2064 TokenTuple tt = new TokenTuple( token, !hrn.isSingleObject(), TokenTuple.ARITY_ONE ).makeCanonical();
2065 TokenTuple ttPlus = new TokenTuple( token, !hrn.isSingleObject(), TokenTuple.ARITY_ONEORMORE ).makeCanonical();
2066 TokenTuple ttStar = new TokenTuple( token, !hrn.isSingleObject(), TokenTuple.ARITY_ZEROORMORE ).makeCanonical();
2068 TokenTupleSet tts = new TokenTupleSet( tt ).makeCanonical();
2069 TokenTupleSet ttsPlus = new TokenTupleSet( ttPlus ).makeCanonical();
2070 TokenTupleSet ttsStar = new TokenTupleSet( ttStar ).makeCanonical();
2071 TokenTupleSet ttsEmpty = new TokenTupleSet( ).makeCanonical();
2073 if( hrn.isFlagged() || hrn.isParameter() ) {
2074 HashSet<TokenTupleSet> subWorkSet = new HashSet<TokenTupleSet>();
2075 subWorkSet.add( tts );
2076 subWorkSet.add( ttsPlus );
2077 subWorkSet.add( ttsStar );
2078 workSet.put( hrn, subWorkSet );
2080 hrn.setAlphaNew( new ReachabilitySet( tts ).makeCanonical() );
2082 hrn.setAlphaNew( new ReachabilitySet( ttsEmpty ).makeCanonical() );
2086 // then propagate tokens forward one step at a time
2087 while( !workSet.isEmpty() ) {
2088 HeapRegionNode hrn = workSet.keySet().iterator().next();
2090 HashSet<TokenTupleSet> subWorkSet = workSet.get( hrn );
2091 assert subWorkSet != null;
2093 if( subWorkSet.isEmpty() ) {
2094 // we're currently done with sub work at this heap region, although
2095 // more work may get queued up later, but remove it for now and continue
2096 workSet.remove( hrn );
2100 TokenTupleSet tts = subWorkSet.iterator().next();
2101 subWorkSet.remove( tts );
2103 // try to push this TokenTupleSet over all outgoing edges
2104 Iterator<ReferenceEdge> itrRes = hrn.iteratorToReferencees();
2105 while( itrRes.hasNext() ) {
2106 ReferenceEdge edge = itrRes.next();
2108 if( edge.getBeta().containsSuperSet( tts ) ) {
2109 HeapRegionNode dst = edge.getDst();
2111 // make a set of possible contributions this token
2112 // might have on the alpha set here
2113 HashSet<TokenTupleSet> ttsNewSet = new HashSet<TokenTupleSet>();
2115 Iterator<TokenTupleSet> itrDstAlphaNew = dst.getAlphaNew().iterator();
2116 while( itrDstAlphaNew.hasNext() ) {
2117 TokenTupleSet ttsDstAlphaNew = itrDstAlphaNew.next();
2118 ttsNewSet.add( tts.unionUpArity( ttsDstAlphaNew ) );
2121 // only add this to the dst alpha new if it is in the beta of
2122 // the edge we crossed to get here, and then only continue the
2123 // propagation if it isn't already in the dst alpha new
2124 Iterator<TokenTupleSet> itrNewSet = ttsNewSet.iterator();
2125 while( itrNewSet.hasNext() ) {
2126 TokenTupleSet ttsNew = itrNewSet.next();
2128 if( edge.getBeta().containsSuperSet( ttsNew ) &&
2129 !dst.getAlphaNew().contains( ttsNew ) ) {
2131 // okay, this is a valid propagation, and add to the
2132 // work set to further propagate it
2133 dst.setAlphaNew( dst.getAlphaNew().union( ttsNew ) );
2135 HashSet<TokenTupleSet> subWorkSetDst = workSet.get( dst );
2136 if( subWorkSetDst == null ) {
2137 subWorkSetDst = new HashSet<TokenTupleSet>();
2140 subWorkSetDst.add( ttsNew );
2141 workSet.put( dst, subWorkSetDst );
2148 // now prepare work sets to propagate token sets backwards
2149 // from heap regions across all edges
2150 assert workSet.isEmpty();
2151 hrns = id2hrn.entrySet();
2152 itrHrns = hrns.iterator();
2153 while( itrHrns.hasNext() ) {
2154 Map.Entry me = (Map.Entry)itrHrns.next();
2155 HeapRegionNode hrn = (HeapRegionNode) me.getValue();
2157 HashSet<TokenTupleSet> subWorkSet = new HashSet<TokenTupleSet>();
2159 Iterator<TokenTupleSet> itrAlphaNewSets = hrn.getAlphaNew().iterator();
2160 while( itrAlphaNewSets.hasNext() ) {
2161 TokenTupleSet tts = itrAlphaNewSets.next();
2162 subWorkSet.add( tts );
2165 workSet.put( hrn, subWorkSet );
2168 // propagate token sets backwards across edges one step at a time
2169 while( !workSet.isEmpty() ) {
2170 HeapRegionNode hrn = workSet.keySet().iterator().next();
2172 HashSet<TokenTupleSet> subWorkSet = workSet.get( hrn );
2173 assert subWorkSet != null;
2175 if( subWorkSet.isEmpty() ) {
2176 // we're currently done with sub work at this heap region, although
2177 // more work may get queued up later, but remove it for now and continue
2178 workSet.remove( hrn );
2182 TokenTupleSet tts = subWorkSet.iterator().next();
2183 subWorkSet.remove( tts );
2185 // try to push this TokenTupleSet back up incoming edges
2186 Iterator<ReferenceEdge> itrRes = hrn.iteratorToReferencers();
2187 while( itrRes.hasNext() ) {
2188 ReferenceEdge edge = itrRes.next();
2190 if( (edge.getBeta().containsWithZeroes( tts ) ||
2191 edge.getBeta().containsSuperSet ( tts )
2193 !edge.getBetaNew().contains( tts ) ) {
2195 // okay, this is a valid propagation, and add to the
2196 // work set to further propagate it
2197 edge.setBetaNew( edge.getBetaNew().union( tts ) );
2199 OwnershipNode src = edge.getSrc();
2200 if( src instanceof HeapRegionNode ) {
2202 HashSet<TokenTupleSet> subWorkSetSrc = workSet.get( (HeapRegionNode) src );
2203 if( subWorkSetSrc == null ) {
2204 subWorkSetSrc = new HashSet<TokenTupleSet>();
2207 subWorkSetSrc.add( tts );
2208 workSet.put( (HeapRegionNode) src, subWorkSetSrc );
2214 // apply alphaNew and betaNew to all nodes and edges
2215 HashSet<ReferenceEdge> res = new HashSet<ReferenceEdge>();
2217 Iterator<HeapRegionNode> nodeItr = id2hrn.values().iterator();
2218 while( nodeItr.hasNext() ) {
2219 HeapRegionNode hrn = nodeItr.next();
2220 hrn.applyAlphaNew();
2221 Iterator<ReferenceEdge> itrRes = hrn.iteratorToReferencers();
2222 while( itrRes.hasNext() ) {
2223 res.add( itrRes.next() );
2227 Iterator<ReferenceEdge> edgeItr = res.iterator();
2228 while( edgeItr.hasNext() ) {
2229 edgeItr.next().applyBetaNew();
2235 ////////////////////////////////////////////////////
2236 // in merge() and equals() methods the suffix A
2237 // represents the passed in graph and the suffix
2238 // B refers to the graph in this object
2239 // Merging means to take the incoming graph A and
2240 // merge it into B, so after the operation graph B
2241 // is the final result.
2242 ////////////////////////////////////////////////////
2243 public void merge(OwnershipGraph og) {
2249 mergeOwnershipNodes(og);
2250 mergeReferenceEdges(og);
2251 mergeId2paramIndex(og);
2252 mergeAllocationSites(og);
2256 protected void mergeOwnershipNodes(OwnershipGraph og) {
2257 Set sA = og.id2hrn.entrySet();
2258 Iterator iA = sA.iterator();
2259 while( iA.hasNext() ) {
2260 Map.Entry meA = (Map.Entry)iA.next();
2261 Integer idA = (Integer) meA.getKey();
2262 HeapRegionNode hrnA = (HeapRegionNode) meA.getValue();
2264 // if this graph doesn't have a node the
2265 // incoming graph has, allocate it
2266 if( !id2hrn.containsKey(idA) ) {
2267 HeapRegionNode hrnB = hrnA.copy();
2268 id2hrn.put(idA, hrnB);
2271 // otherwise this is a node present in both graphs
2272 // so make the new reachability set a union of the
2273 // nodes' reachability sets
2274 HeapRegionNode hrnB = id2hrn.get(idA);
2275 hrnB.setAlpha(hrnB.getAlpha().union(hrnA.getAlpha() ) );
2279 // now add any label nodes that are in graph B but
2281 sA = og.td2ln.entrySet();
2283 while( iA.hasNext() ) {
2284 Map.Entry meA = (Map.Entry)iA.next();
2285 TempDescriptor tdA = (TempDescriptor) meA.getKey();
2286 LabelNode lnA = (LabelNode) meA.getValue();
2288 // if the label doesn't exist in B, allocate and add it
2289 LabelNode lnB = getLabelNodeFromTemp(tdA);
2293 protected void mergeReferenceEdges(OwnershipGraph og) {
2296 Set sA = og.id2hrn.entrySet();
2297 Iterator iA = sA.iterator();
2298 while( iA.hasNext() ) {
2299 Map.Entry meA = (Map.Entry)iA.next();
2300 Integer idA = (Integer) meA.getKey();
2301 HeapRegionNode hrnA = (HeapRegionNode) meA.getValue();
2303 Iterator<ReferenceEdge> heapRegionsItrA = hrnA.iteratorToReferencees();
2304 while( heapRegionsItrA.hasNext() ) {
2305 ReferenceEdge edgeA = heapRegionsItrA.next();
2306 HeapRegionNode hrnChildA = edgeA.getDst();
2307 Integer idChildA = hrnChildA.getID();
2309 // at this point we know an edge in graph A exists
2310 // idA -> idChildA, does this exist in B?
2311 assert id2hrn.containsKey(idA);
2312 HeapRegionNode hrnB = id2hrn.get(idA);
2313 ReferenceEdge edgeToMerge = null;
2315 Iterator<ReferenceEdge> heapRegionsItrB = hrnB.iteratorToReferencees();
2316 while( heapRegionsItrB.hasNext() &&
2317 edgeToMerge == null ) {
2319 ReferenceEdge edgeB = heapRegionsItrB.next();
2320 HeapRegionNode hrnChildB = edgeB.getDst();
2321 Integer idChildB = hrnChildB.getID();
2323 // don't use the ReferenceEdge.equals() here because
2324 // we're talking about existence between graphs
2325 if( idChildB.equals(idChildA) &&
2326 edgeB.getFieldDesc() == edgeA.getFieldDesc() ) {
2327 edgeToMerge = edgeB;
2331 // if the edge from A was not found in B,
2333 if( edgeToMerge == null ) {
2334 assert id2hrn.containsKey(idChildA);
2335 HeapRegionNode hrnChildB = id2hrn.get(idChildA);
2336 edgeToMerge = edgeA.copy();
2337 edgeToMerge.setSrc(hrnB);
2338 edgeToMerge.setDst(hrnChildB);
2339 addReferenceEdge(hrnB, hrnChildB, edgeToMerge);
2341 // otherwise, the edge already existed in both graphs
2342 // so merge their reachability sets
2344 // just replace this beta set with the union
2345 assert edgeToMerge != null;
2346 edgeToMerge.setBeta(
2347 edgeToMerge.getBeta().union(edgeA.getBeta() )
2349 if( !edgeA.isInitialParamReflexive() ) {
2350 edgeToMerge.setIsInitialParamReflexive(false);
2356 // and then again with label nodes
2357 sA = og.td2ln.entrySet();
2359 while( iA.hasNext() ) {
2360 Map.Entry meA = (Map.Entry)iA.next();
2361 TempDescriptor tdA = (TempDescriptor) meA.getKey();
2362 LabelNode lnA = (LabelNode) meA.getValue();
2364 Iterator<ReferenceEdge> heapRegionsItrA = lnA.iteratorToReferencees();
2365 while( heapRegionsItrA.hasNext() ) {
2366 ReferenceEdge edgeA = heapRegionsItrA.next();
2367 HeapRegionNode hrnChildA = edgeA.getDst();
2368 Integer idChildA = hrnChildA.getID();
2370 // at this point we know an edge in graph A exists
2371 // tdA -> idChildA, does this exist in B?
2372 assert td2ln.containsKey(tdA);
2373 LabelNode lnB = td2ln.get(tdA);
2374 ReferenceEdge edgeToMerge = null;
2376 // labels never have edges with a field
2377 //assert edgeA.getFieldDesc() == null;
2379 Iterator<ReferenceEdge> heapRegionsItrB = lnB.iteratorToReferencees();
2380 while( heapRegionsItrB.hasNext() &&
2381 edgeToMerge == null ) {
2383 ReferenceEdge edgeB = heapRegionsItrB.next();
2384 HeapRegionNode hrnChildB = edgeB.getDst();
2385 Integer idChildB = hrnChildB.getID();
2387 // labels never have edges with a field
2388 //assert edgeB.getFieldDesc() == null;
2390 // don't use the ReferenceEdge.equals() here because
2391 // we're talking about existence between graphs
2392 if( idChildB.equals(idChildA) &&
2393 edgeB.getFieldDesc() == edgeA.getFieldDesc() ) {
2394 edgeToMerge = edgeB;
2398 // if the edge from A was not found in B,
2400 if( edgeToMerge == null ) {
2401 assert id2hrn.containsKey(idChildA);
2402 HeapRegionNode hrnChildB = id2hrn.get(idChildA);
2403 edgeToMerge = edgeA.copy();
2404 edgeToMerge.setSrc(lnB);
2405 edgeToMerge.setDst(hrnChildB);
2406 addReferenceEdge(lnB, hrnChildB, edgeToMerge);
2408 // otherwise, the edge already existed in both graphs
2409 // so merge their reachability sets
2411 // just replace this beta set with the union
2412 edgeToMerge.setBeta(
2413 edgeToMerge.getBeta().union(edgeA.getBeta() )
2415 if( !edgeA.isInitialParamReflexive() ) {
2416 edgeToMerge.setIsInitialParamReflexive(false);
2423 // you should only merge ownership graphs that have the
2424 // same number of parameters, or if one or both parameter
2425 // index tables are empty
2426 protected void mergeId2paramIndex(OwnershipGraph og) {
2427 if( id2paramIndexSet.size() == 0 ) {
2428 id2paramIndexSet = og.id2paramIndexSet;
2429 paramIndex2id = og.paramIndex2id;
2430 paramIndex2tdQ = og.paramIndex2tdQ;
2434 if( og.id2paramIndexSet.size() == 0 ) {
2438 assert id2paramIndexSet.size() == og.id2paramIndexSet.size();
2441 protected void mergeAllocationSites(OwnershipGraph og) {
2442 allocationSites.addAll(og.allocationSites);
2447 // it is necessary in the equals() member functions
2448 // to "check both ways" when comparing the data
2449 // structures of two graphs. For instance, if all
2450 // edges between heap region nodes in graph A are
2451 // present and equal in graph B it is not sufficient
2452 // to say the graphs are equal. Consider that there
2453 // may be edges in graph B that are not in graph A.
2454 // the only way to know that all edges in both graphs
2455 // are equally present is to iterate over both data
2456 // structures and compare against the other graph.
2457 public boolean equals(OwnershipGraph og) {
2463 if( !areHeapRegionNodesEqual(og) ) {
2467 if( !areLabelNodesEqual(og) ) {
2471 if( !areReferenceEdgesEqual(og) ) {
2475 if( !areId2paramIndexEqual(og) ) {
2479 // if everything is equal up to this point,
2480 // assert that allocationSites is also equal--
2481 // this data is redundant and kept for efficiency
2482 assert allocationSites.equals(og.allocationSites);
2487 protected boolean areHeapRegionNodesEqual(OwnershipGraph og) {
2489 if( !areallHRNinAalsoinBandequal(this, og) ) {
2493 if( !areallHRNinAalsoinBandequal(og, this) ) {
2500 static protected boolean areallHRNinAalsoinBandequal(OwnershipGraph ogA,
2501 OwnershipGraph ogB) {
2502 Set sA = ogA.id2hrn.entrySet();
2503 Iterator iA = sA.iterator();
2504 while( iA.hasNext() ) {
2505 Map.Entry meA = (Map.Entry)iA.next();
2506 Integer idA = (Integer) meA.getKey();
2507 HeapRegionNode hrnA = (HeapRegionNode) meA.getValue();
2509 if( !ogB.id2hrn.containsKey(idA) ) {
2513 HeapRegionNode hrnB = ogB.id2hrn.get(idA);
2514 if( !hrnA.equalsIncludingAlpha(hrnB) ) {
2523 protected boolean areLabelNodesEqual(OwnershipGraph og) {
2525 if( !areallLNinAalsoinBandequal(this, og) ) {
2529 if( !areallLNinAalsoinBandequal(og, this) ) {
2536 static protected boolean areallLNinAalsoinBandequal(OwnershipGraph ogA,
2537 OwnershipGraph ogB) {
2538 Set sA = ogA.td2ln.entrySet();
2539 Iterator iA = sA.iterator();
2540 while( iA.hasNext() ) {
2541 Map.Entry meA = (Map.Entry)iA.next();
2542 TempDescriptor tdA = (TempDescriptor) meA.getKey();
2544 if( !ogB.td2ln.containsKey(tdA) ) {
2553 protected boolean areReferenceEdgesEqual(OwnershipGraph og) {
2554 if( !areallREinAandBequal(this, og) ) {
2561 static protected boolean areallREinAandBequal(OwnershipGraph ogA,
2562 OwnershipGraph ogB) {
2564 // check all the heap region->heap region edges
2565 Set sA = ogA.id2hrn.entrySet();
2566 Iterator iA = sA.iterator();
2567 while( iA.hasNext() ) {
2568 Map.Entry meA = (Map.Entry)iA.next();
2569 Integer idA = (Integer) meA.getKey();
2570 HeapRegionNode hrnA = (HeapRegionNode) meA.getValue();
2572 // we should have already checked that the same
2573 // heap regions exist in both graphs
2574 assert ogB.id2hrn.containsKey(idA);
2576 if( !areallREfromAequaltoB(ogA, hrnA, ogB) ) {
2580 // then check every edge in B for presence in A, starting
2581 // from the same parent HeapRegionNode
2582 HeapRegionNode hrnB = ogB.id2hrn.get(idA);
2584 if( !areallREfromAequaltoB(ogB, hrnB, ogA) ) {
2589 // then check all the label->heap region edges
2590 sA = ogA.td2ln.entrySet();
2592 while( iA.hasNext() ) {
2593 Map.Entry meA = (Map.Entry)iA.next();
2594 TempDescriptor tdA = (TempDescriptor) meA.getKey();
2595 LabelNode lnA = (LabelNode) meA.getValue();
2597 // we should have already checked that the same
2598 // label nodes exist in both graphs
2599 assert ogB.td2ln.containsKey(tdA);
2601 if( !areallREfromAequaltoB(ogA, lnA, ogB) ) {
2605 // then check every edge in B for presence in A, starting
2606 // from the same parent LabelNode
2607 LabelNode lnB = ogB.td2ln.get(tdA);
2609 if( !areallREfromAequaltoB(ogB, lnB, ogA) ) {
2618 static protected boolean areallREfromAequaltoB(OwnershipGraph ogA,
2620 OwnershipGraph ogB) {
2622 Iterator<ReferenceEdge> itrA = onA.iteratorToReferencees();
2623 while( itrA.hasNext() ) {
2624 ReferenceEdge edgeA = itrA.next();
2625 HeapRegionNode hrnChildA = edgeA.getDst();
2626 Integer idChildA = hrnChildA.getID();
2628 assert ogB.id2hrn.containsKey(idChildA);
2630 // at this point we know an edge in graph A exists
2631 // onA -> idChildA, does this exact edge exist in B?
2632 boolean edgeFound = false;
2634 OwnershipNode onB = null;
2635 if( onA instanceof HeapRegionNode ) {
2636 HeapRegionNode hrnA = (HeapRegionNode) onA;
2637 onB = ogB.id2hrn.get(hrnA.getID() );
2639 LabelNode lnA = (LabelNode) onA;
2640 onB = ogB.td2ln.get(lnA.getTempDescriptor() );
2643 Iterator<ReferenceEdge> itrB = onB.iteratorToReferencees();
2644 while( itrB.hasNext() ) {
2645 ReferenceEdge edgeB = itrB.next();
2646 HeapRegionNode hrnChildB = edgeB.getDst();
2647 Integer idChildB = hrnChildB.getID();
2649 if( idChildA.equals(idChildB) &&
2650 edgeA.getFieldDesc() == edgeB.getFieldDesc() ) {
2652 // there is an edge in the right place with the right field,
2653 // but do they have the same attributes?
2654 if( edgeA.getBeta().equals(edgeB.getBeta() ) ) {
2672 protected boolean areId2paramIndexEqual(OwnershipGraph og) {
2673 return id2paramIndexSet.size() == og.id2paramIndexSet.size();
2677 public boolean hasPotentialAlias( HeapRegionNode hrn1, HeapRegionNode hrn2 ) {
2678 assert hrn1 != null;
2679 assert hrn2 != null;
2681 // then get the various tokens for these heap regions
2682 TokenTuple h1 = new TokenTuple(hrn1.getID(),
2683 !hrn1.isSingleObject(),
2684 TokenTuple.ARITY_ONE).makeCanonical();
2686 TokenTuple h1plus = new TokenTuple(hrn1.getID(),
2687 !hrn1.isSingleObject(),
2688 TokenTuple.ARITY_ONEORMORE).makeCanonical();
2690 TokenTuple h1star = new TokenTuple(hrn1.getID(),
2691 !hrn1.isSingleObject(),
2692 TokenTuple.ARITY_ZEROORMORE).makeCanonical();
2694 TokenTuple h2 = new TokenTuple(hrn2.getID(),
2695 !hrn2.isSingleObject(),
2696 TokenTuple.ARITY_ONE).makeCanonical();
2698 TokenTuple h2plus = new TokenTuple(hrn2.getID(),
2699 !hrn2.isSingleObject(),
2700 TokenTuple.ARITY_ONEORMORE).makeCanonical();
2702 TokenTuple h2star = new TokenTuple(hrn2.getID(),
2703 !hrn2.isSingleObject(),
2704 TokenTuple.ARITY_ZEROORMORE).makeCanonical();
2706 // then get the merged beta of all out-going edges from these heap regions
2707 ReachabilitySet beta1 = new ReachabilitySet();
2708 Iterator<ReferenceEdge> itrEdge = hrn1.iteratorToReferencees();
2709 while( itrEdge.hasNext() ) {
2710 ReferenceEdge edge = itrEdge.next();
2711 beta1 = beta1.union( edge.getBeta() );
2714 ReachabilitySet beta2 = new ReachabilitySet();
2715 itrEdge = hrn2.iteratorToReferencees();
2716 while( itrEdge.hasNext() ) {
2717 ReferenceEdge edge = itrEdge.next();
2718 beta2 = beta2.union( edge.getBeta() );
2721 // only do this one if they are different tokens
2723 beta1.containsTupleSetWithBoth(h1, h2) ) {
2726 if( beta1.containsTupleSetWithBoth(h1plus, h2) ) {
2729 if( beta1.containsTupleSetWithBoth(h1star, h2) ) {
2732 if( beta1.containsTupleSetWithBoth(h1, h2plus) ) {
2735 if( beta1.containsTupleSetWithBoth(h1plus, h2plus) ) {
2738 if( beta1.containsTupleSetWithBoth(h1star, h2plus) ) {
2741 if( beta1.containsTupleSetWithBoth(h1, h2star) ) {
2744 if( beta1.containsTupleSetWithBoth(h1plus, h2star) ) {
2747 if( beta1.containsTupleSetWithBoth(h1star, h2star) ) {
2752 beta2.containsTupleSetWithBoth(h1, h2) ) {
2755 if( beta2.containsTupleSetWithBoth(h1plus, h2) ) {
2758 if( beta2.containsTupleSetWithBoth(h1star, h2) ) {
2761 if( beta2.containsTupleSetWithBoth(h1, h2plus) ) {
2764 if( beta2.containsTupleSetWithBoth(h1plus, h2plus) ) {
2767 if( beta2.containsTupleSetWithBoth(h1star, h2plus) ) {
2770 if( beta2.containsTupleSetWithBoth(h1, h2star) ) {
2773 if( beta2.containsTupleSetWithBoth(h1plus, h2star) ) {
2776 if( beta2.containsTupleSetWithBoth(h1star, h2star) ) {
2784 public boolean hasPotentialAlias(Integer paramIndex1, Integer paramIndex2) {
2786 // get parameter's heap region
2787 assert paramIndex2id.containsKey(paramIndex1);
2788 Integer idParam1 = paramIndex2id.get(paramIndex1);
2790 assert id2hrn.containsKey(idParam1);
2791 HeapRegionNode hrnParam1 = id2hrn.get(idParam1);
2792 assert hrnParam1 != null;
2795 // get tokens for the other parameter
2796 assert paramIndex2id.containsKey(paramIndex2);
2797 Integer idParam2 = paramIndex2id.get(paramIndex2);
2799 assert id2hrn.containsKey(idParam2);
2800 HeapRegionNode hrnParam2 = id2hrn.get(idParam2);
2801 assert hrnParam2 != null;
2804 return hasPotentialAlias( hrnParam1, hrnParam2 );
2808 public boolean hasPotentialAlias(Integer paramIndex, AllocationSite as) {
2810 // get parameter's heap region
2811 assert paramIndex2id.containsKey(paramIndex);
2812 Integer idParam = paramIndex2id.get(paramIndex);
2814 assert id2hrn.containsKey(idParam);
2815 HeapRegionNode hrnParam = id2hrn.get(idParam);
2816 assert hrnParam != null;
2819 assert id2hrn.containsKey( as.getSummary() );
2820 HeapRegionNode hrnSummary = id2hrn.get( as.getSummary() );
2821 assert hrnSummary != null;
2823 if( hasPotentialAlias( hrnParam, hrnSummary ) ) {
2827 // check for other nodes
2828 for( int i = 0; i < as.getAllocationDepth(); ++i ) {
2830 assert id2hrn.containsKey( as.getIthOldest( i ) );
2831 HeapRegionNode hrnIthOldest = id2hrn.get( as.getIthOldest( i ) );
2832 assert hrnIthOldest != null;
2834 if( hasPotentialAlias( hrnParam, hrnIthOldest ) ) {
2843 public boolean hasPotentialAlias(AllocationSite as1, AllocationSite as2) {
2845 // get summary node 1's alpha
2846 Integer idSum1 = as1.getSummary();
2847 assert id2hrn.containsKey(idSum1);
2848 HeapRegionNode hrnSum1 = id2hrn.get(idSum1);
2849 assert hrnSum1 != null;
2851 // get summary node 2's alpha
2852 Integer idSum2 = as2.getSummary();
2853 assert id2hrn.containsKey(idSum2);
2854 HeapRegionNode hrnSum2 = id2hrn.get(idSum2);
2855 assert hrnSum2 != null;
2857 if( hasPotentialAlias( hrnSum1, hrnSum2 ) ) {
2861 // check sum2 against alloc1 nodes
2862 for( int i = 0; i < as1.getAllocationDepth(); ++i ) {
2863 Integer idI1 = as1.getIthOldest(i);
2864 assert id2hrn.containsKey(idI1);
2865 HeapRegionNode hrnI1 = id2hrn.get(idI1);
2866 assert hrnI1 != null;
2868 if( hasPotentialAlias( hrnI1, hrnSum2 ) ) {
2873 // check sum1 against alloc2 nodes
2874 for( int i = 0; i < as2.getAllocationDepth(); ++i ) {
2875 Integer idI2 = as2.getIthOldest(i);
2876 assert id2hrn.containsKey(idI2);
2877 HeapRegionNode hrnI2 = id2hrn.get(idI2);
2878 assert hrnI2 != null;
2880 if( hasPotentialAlias( hrnSum1, hrnI2 ) ) {
2884 // while we're at it, do an inner loop for alloc2 vs alloc1 nodes
2885 for( int j = 0; j < as1.getAllocationDepth(); ++j ) {
2886 Integer idI1 = as1.getIthOldest(j);
2888 // if these are the same site, don't look for the same token, no alias.
2889 // different tokens of the same site could alias together though
2890 if( idI1 == idI2 ) {
2894 HeapRegionNode hrnI1 = id2hrn.get(idI1);
2896 if( hasPotentialAlias( hrnI1, hrnI2 ) ) {
2906 // for writing ownership graphs to dot files
2907 public void writeGraph(MethodContext mc,
2909 boolean writeLabels,
2910 boolean labelSelect,
2911 boolean pruneGarbage,
2912 boolean writeReferencers,
2913 boolean writeParamMappings
2914 ) throws java.io.IOException {
2926 public void writeGraph(MethodContext mc,
2927 boolean writeLabels,
2928 boolean labelSelect,
2929 boolean pruneGarbage,
2930 boolean writeReferencers,
2931 boolean writeParamMappings
2932 ) throws java.io.IOException {
2934 writeGraph(mc+"COMPLETE",
2943 public void writeGraph(MethodContext mc,
2945 boolean writeLabels,
2946 boolean labelSelect,
2947 boolean pruneGarbage,
2948 boolean writeReferencers,
2949 boolean writeParamMappings
2950 ) throws java.io.IOException {
2952 writeGraph(mc+"COMPLETE"+String.format("%05d", numUpdate),
2961 public void writeGraph(String graphName,
2962 boolean writeLabels,
2963 boolean labelSelect,
2964 boolean pruneGarbage,
2965 boolean writeReferencers,
2966 boolean writeParamMappings
2967 ) throws java.io.IOException {
2969 // remove all non-word characters from the graph name so
2970 // the filename and identifier in dot don't cause errors
2971 graphName = graphName.replaceAll("[\\W]", "");
2973 BufferedWriter bw = new BufferedWriter(new FileWriter(graphName+".dot") );
2974 bw.write("digraph "+graphName+" {\n");
2976 HashSet<HeapRegionNode> visited = new HashSet<HeapRegionNode>();
2978 // then visit every heap region node
2979 Set s = id2hrn.entrySet();
2980 Iterator i = s.iterator();
2981 while( i.hasNext() ) {
2982 Map.Entry me = (Map.Entry)i.next();
2983 HeapRegionNode hrn = (HeapRegionNode) me.getValue();
2985 if( !pruneGarbage ||
2986 (hrn.isFlagged() && hrn.getID() > 0) ||
2987 hrn.getDescription().startsWith("param")
2990 if( !visited.contains(hrn) ) {
2991 traverseHeapRegionNodes(VISIT_HRN_WRITE_FULL,
3001 bw.write(" graphTitle[label=\""+graphName+"\",shape=box];\n");
3003 if( writeParamMappings ) {
3004 Set df = paramIndex2id.entrySet();
3005 Iterator ih = df.iterator();
3006 while( ih.hasNext() ) {
3007 Map.Entry meh = (Map.Entry)ih.next();
3008 Integer pi = (Integer) meh.getKey();
3009 Integer id = (Integer) meh.getValue();
3010 bw.write(" pindex"+pi+"[label=\""+pi+" to "+id+"\",shape=box];\n");
3014 // then visit every label node, useful for debugging
3016 s = td2ln.entrySet();
3018 while( i.hasNext() ) {
3019 Map.Entry me = (Map.Entry)i.next();
3020 LabelNode ln = (LabelNode) me.getValue();
3023 String labelStr = ln.getTempDescriptorString();
3024 if( labelStr.startsWith("___temp") ||
3025 labelStr.startsWith("___dst") ||
3026 labelStr.startsWith("___srctmp") ||
3027 labelStr.startsWith("___neverused") ) {
3032 //bw.write(" "+ln.toString() + ";\n");
3034 Iterator<ReferenceEdge> heapRegionsItr = ln.iteratorToReferencees();
3035 while( heapRegionsItr.hasNext() ) {
3036 ReferenceEdge edge = heapRegionsItr.next();
3037 HeapRegionNode hrn = edge.getDst();
3039 if( pruneGarbage && !visited.contains(hrn) ) {
3040 traverseHeapRegionNodes(VISIT_HRN_WRITE_FULL,
3048 bw.write(" " + ln.toString() +
3049 " -> " + hrn.toString() +
3050 "[label=\"" + edge.toGraphEdgeString() +
3061 protected void traverseHeapRegionNodes(int mode,
3065 HashSet<HeapRegionNode> visited,
3066 boolean writeReferencers
3067 ) throws java.io.IOException {
3069 if( visited.contains(hrn) ) {
3075 case VISIT_HRN_WRITE_FULL:
3077 String attributes = "[";
3079 if( hrn.isSingleObject() ) {
3080 attributes += "shape=box";
3082 attributes += "shape=Msquare";
3085 if( hrn.isFlagged() ) {
3086 attributes += ",style=filled,fillcolor=lightgrey";
3089 attributes += ",label=\"ID" +
3092 hrn.getDescription() +
3094 hrn.getAlphaString() +
3097 bw.write(" " + hrn.toString() + attributes + ";\n");
3102 // useful for debugging
3103 if( writeReferencers ) {
3104 OwnershipNode onRef = null;
3105 Iterator refItr = hrn.iteratorToReferencers();
3106 while( refItr.hasNext() ) {
3107 onRef = (OwnershipNode) refItr.next();
3110 case VISIT_HRN_WRITE_FULL:
3111 bw.write(" " + hrn.toString() +
3112 " -> " + onRef.toString() +
3113 "[color=lightgray];\n");
3119 Iterator<ReferenceEdge> childRegionsItr = hrn.iteratorToReferencees();
3120 while( childRegionsItr.hasNext() ) {
3121 ReferenceEdge edge = childRegionsItr.next();
3122 HeapRegionNode hrnChild = edge.getDst();
3125 case VISIT_HRN_WRITE_FULL:
3126 bw.write(" " + hrn.toString() +
3127 " -> " + hrnChild.toString() +
3128 "[label=\"" + edge.toGraphEdgeString() +
3133 traverseHeapRegionNodes(mode,