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,
84 id = OwnershipAnalysis.generateUniqueHeapRegionNodeID();
88 if( isFlagged || isParameter ) {
89 alpha = new ReachabilitySet(
96 alpha = new ReachabilitySet(
97 new TokenTupleSet().makeCanonical()
102 HeapRegionNode hrn = new HeapRegionNode(id,
116 ////////////////////////////////////////////////
118 // Low-level referencee and referencer methods
120 // These methods provide the lowest level for
121 // creating references between ownership nodes
122 // and handling the details of maintaining both
123 // list of referencers and referencees.
125 ////////////////////////////////////////////////
126 protected void addReferenceEdge(OwnershipNode referencer,
127 HeapRegionNode referencee,
128 ReferenceEdge edge) {
129 assert referencer != null;
130 assert referencee != null;
132 assert edge.getSrc() == referencer;
133 assert edge.getDst() == referencee;
135 referencer.addReferencee(edge);
136 referencee.addReferencer(edge);
139 protected void removeReferenceEdge(OwnershipNode referencer,
140 HeapRegionNode referencee,
141 FieldDescriptor fieldDesc) {
142 assert referencer != null;
143 assert referencee != null;
145 ReferenceEdge edge = referencer.getReferenceTo(referencee,
148 assert edge == referencee.getReferenceFrom(referencer,
151 referencer.removeReferencee(edge);
152 referencee.removeReferencer(edge);
155 protected void clearReferenceEdgesFrom(OwnershipNode referencer,
156 FieldDescriptor fieldDesc,
158 assert referencer != null;
160 // get a copy of the set to iterate over, otherwise
161 // we will be trying to take apart the set as we
162 // are iterating over it, which won't work
163 Iterator<ReferenceEdge> i = referencer.iteratorToReferenceesClone();
164 while( i.hasNext() ) {
165 ReferenceEdge edge = i.next();
167 if( removeAll || edge.getFieldDesc() == fieldDesc ) {
168 HeapRegionNode referencee = edge.getDst();
170 removeReferenceEdge(referencer,
172 edge.getFieldDesc() );
177 protected void clearReferenceEdgesTo(HeapRegionNode referencee,
178 FieldDescriptor fieldDesc,
180 assert referencee != null;
182 // get a copy of the set to iterate over, otherwise
183 // we will be trying to take apart the set as we
184 // are iterating over it, which won't work
185 Iterator<ReferenceEdge> i = referencee.iteratorToReferencersClone();
186 while( i.hasNext() ) {
187 ReferenceEdge edge = i.next();
189 if( removeAll || edge.getFieldDesc() == fieldDesc ) {
190 OwnershipNode referencer = edge.getSrc();
191 removeReferenceEdge(referencer,
193 edge.getFieldDesc() );
199 protected void propagateTokensOverNodes(HeapRegionNode nPrime,
201 HashSet<HeapRegionNode> nodesWithNewAlpha,
202 HashSet<ReferenceEdge> edgesWithNewBeta) {
204 HashSet<HeapRegionNode> todoNodes
205 = new HashSet<HeapRegionNode>();
206 todoNodes.add(nPrime);
208 HashSet<ReferenceEdge> todoEdges
209 = new HashSet<ReferenceEdge>();
211 Hashtable<HeapRegionNode, ChangeTupleSet> nodePlannedChanges
212 = new Hashtable<HeapRegionNode, ChangeTupleSet>();
213 nodePlannedChanges.put(nPrime, c0);
215 Hashtable<ReferenceEdge, ChangeTupleSet> edgePlannedChanges
216 = new Hashtable<ReferenceEdge, ChangeTupleSet>();
219 while( !todoNodes.isEmpty() ) {
220 HeapRegionNode n = todoNodes.iterator().next();
221 ChangeTupleSet C = nodePlannedChanges.get(n);
223 Iterator itrC = C.iterator();
224 while( itrC.hasNext() ) {
225 ChangeTuple c = (ChangeTuple) itrC.next();
227 if( n.getAlpha().contains(c.getSetToMatch() ) ) {
228 ReachabilitySet withChange = n.getAlpha().union(c.getSetToAdd() );
229 n.setAlphaNew(n.getAlphaNew().union(withChange) );
230 nodesWithNewAlpha.add(n);
234 Iterator<ReferenceEdge> referItr = n.iteratorToReferencers();
235 while( referItr.hasNext() ) {
236 ReferenceEdge edge = referItr.next();
239 if( !edgePlannedChanges.containsKey(edge) ) {
240 edgePlannedChanges.put(edge, new ChangeTupleSet().makeCanonical() );
243 edgePlannedChanges.put(edge, edgePlannedChanges.get(edge).union(C) );
246 Iterator<ReferenceEdge> refeeItr = n.iteratorToReferencees();
247 while( refeeItr.hasNext() ) {
248 ReferenceEdge edgeF = refeeItr.next();
249 HeapRegionNode m = edgeF.getDst();
251 ChangeTupleSet changesToPass = new ChangeTupleSet().makeCanonical();
253 Iterator<ChangeTuple> itrCprime = C.iterator();
254 while( itrCprime.hasNext() ) {
255 ChangeTuple c = itrCprime.next();
256 if( edgeF.getBeta().contains(c.getSetToMatch() ) ) {
257 changesToPass = changesToPass.union(c);
261 if( !changesToPass.isEmpty() ) {
262 if( !nodePlannedChanges.containsKey(m) ) {
263 nodePlannedChanges.put(m, new ChangeTupleSet().makeCanonical() );
266 ChangeTupleSet currentChanges = nodePlannedChanges.get(m);
268 if( !changesToPass.isSubset(currentChanges) ) {
270 nodePlannedChanges.put(m, currentChanges.union(changesToPass) );
279 propagateTokensOverEdges(todoEdges, edgePlannedChanges, edgesWithNewBeta);
283 protected void propagateTokensOverEdges(
284 HashSet<ReferenceEdge> todoEdges,
285 Hashtable<ReferenceEdge, ChangeTupleSet> edgePlannedChanges,
286 HashSet<ReferenceEdge> edgesWithNewBeta) {
289 while( !todoEdges.isEmpty() ) {
290 ReferenceEdge edgeE = todoEdges.iterator().next();
291 todoEdges.remove(edgeE);
293 if( !edgePlannedChanges.containsKey(edgeE) ) {
294 edgePlannedChanges.put(edgeE, new ChangeTupleSet().makeCanonical() );
297 ChangeTupleSet C = edgePlannedChanges.get(edgeE);
299 ChangeTupleSet changesToPass = new ChangeTupleSet().makeCanonical();
301 Iterator<ChangeTuple> itrC = C.iterator();
302 while( itrC.hasNext() ) {
303 ChangeTuple c = itrC.next();
304 if( edgeE.getBeta().contains(c.getSetToMatch() ) ) {
305 ReachabilitySet withChange = edgeE.getBeta().union(c.getSetToAdd() );
306 edgeE.setBetaNew(edgeE.getBetaNew().union(withChange) );
307 edgesWithNewBeta.add(edgeE);
308 changesToPass = changesToPass.union(c);
312 OwnershipNode onSrc = edgeE.getSrc();
314 if( !changesToPass.isEmpty() && onSrc instanceof HeapRegionNode ) {
315 HeapRegionNode n = (HeapRegionNode) onSrc;
317 Iterator<ReferenceEdge> referItr = n.iteratorToReferencers();
318 while( referItr.hasNext() ) {
319 ReferenceEdge edgeF = referItr.next();
321 if( !edgePlannedChanges.containsKey(edgeF) ) {
322 edgePlannedChanges.put(edgeF, new ChangeTupleSet().makeCanonical() );
325 ChangeTupleSet currentChanges = edgePlannedChanges.get(edgeF);
327 if( !changesToPass.isSubset(currentChanges) ) {
328 todoEdges.add(edgeF);
329 edgePlannedChanges.put(edgeF, currentChanges.union(changesToPass) );
337 ////////////////////////////////////////////////////
339 // Assignment Operation Methods
341 // These methods are high-level operations for
342 // modeling program assignment statements using
343 // the low-level reference create/remove methods
346 // The destination in an assignment statement is
347 // going to have new references. The method of
348 // determining the references depends on the type
349 // of the FlatNode assignment and the predicates
350 // of the nodes and edges involved.
352 ////////////////////////////////////////////////////
353 public void assignTempXEqualToTempY(TempDescriptor x,
356 LabelNode lnX = getLabelNodeFromTemp(x);
357 LabelNode lnY = getLabelNodeFromTemp(y);
359 clearReferenceEdgesFrom(lnX, null, true);
361 Iterator<ReferenceEdge> itrYhrn = lnY.iteratorToReferencees();
362 while( itrYhrn.hasNext() ) {
363 ReferenceEdge edgeY = itrYhrn.next();
364 HeapRegionNode referencee = edgeY.getDst();
365 ReferenceEdge edgeNew = edgeY.copy();
368 addReferenceEdge(lnX, referencee, edgeNew);
373 public void assignTempXEqualToTempYFieldF(TempDescriptor x,
376 LabelNode lnX = getLabelNodeFromTemp(x);
377 LabelNode lnY = getLabelNodeFromTemp(y);
379 clearReferenceEdgesFrom(lnX, null, true);
381 Iterator<ReferenceEdge> itrYhrn = lnY.iteratorToReferencees();
382 while( itrYhrn.hasNext() ) {
383 ReferenceEdge edgeY = itrYhrn.next();
384 HeapRegionNode hrnY = edgeY.getDst();
385 ReachabilitySet betaY = edgeY.getBeta();
387 Iterator<ReferenceEdge> itrHrnFhrn = hrnY.iteratorToReferencees();
388 while( itrHrnFhrn.hasNext() ) {
389 ReferenceEdge edgeHrn = itrHrnFhrn.next();
390 HeapRegionNode hrnHrn = edgeHrn.getDst();
391 ReachabilitySet betaHrn = edgeHrn.getBeta();
393 if( edgeHrn.getFieldDesc() == null ||
394 edgeHrn.getFieldDesc() == f ) {
396 ReferenceEdge edgeNew = new ReferenceEdge(lnX,
400 betaY.intersection(betaHrn) );
402 addReferenceEdge(lnX, hrnHrn, edgeNew);
409 public void assignTempXFieldFEqualToTempY(TempDescriptor x,
412 LabelNode lnX = getLabelNodeFromTemp(x);
413 LabelNode lnY = getLabelNodeFromTemp(y);
415 HashSet<HeapRegionNode> nodesWithNewAlpha = new HashSet<HeapRegionNode>();
416 HashSet<ReferenceEdge> edgesWithNewBeta = new HashSet<ReferenceEdge>();
419 // first look for possible strong updates and remove those edges
420 boolean strongUpdate = false;
422 Iterator<ReferenceEdge> itrXhrn = lnX.iteratorToReferencees();
423 while( itrXhrn.hasNext() ) {
424 ReferenceEdge edgeX = itrXhrn.next();
425 HeapRegionNode hrnX = edgeX.getDst();
427 Iterator<ReferenceEdge> itrYhrn = lnY.iteratorToReferencees();
428 while( itrYhrn.hasNext() ) {
429 ReferenceEdge edgeY = itrYhrn.next();
430 HeapRegionNode hrnY = edgeY.getDst();
432 // we can do a strong update here if one of two cases holds
434 hrnX.isSingleObject() &&
435 ( (hrnX.getNumReferencers() == 1) ||
436 ( lnX.getNumReferencees() == 1)
440 clearReferenceEdgesFrom( hrnX, f, false );
446 // then do all token propagation
447 itrXhrn = lnX.iteratorToReferencees();
448 while( itrXhrn.hasNext() ) {
449 ReferenceEdge edgeX = itrXhrn.next();
450 HeapRegionNode hrnX = edgeX.getDst();
451 ReachabilitySet betaX = edgeX.getBeta();
453 ReachabilitySet R = hrnX.getAlpha().intersection(edgeX.getBeta() );
455 Iterator<ReferenceEdge> itrYhrn = lnY.iteratorToReferencees();
456 while( itrYhrn.hasNext() ) {
457 ReferenceEdge edgeY = itrYhrn.next();
458 HeapRegionNode hrnY = edgeY.getDst();
459 ReachabilitySet O = edgeY.getBeta();
462 // propagate tokens over nodes starting from hrnSrc, and it will
463 // take care of propagating back up edges from any touched nodes
464 ChangeTupleSet Cy = O.unionUpArityToChangeSet(R);
465 propagateTokensOverNodes(hrnY, Cy, nodesWithNewAlpha, edgesWithNewBeta);
468 // then propagate back just up the edges from hrn
469 ChangeTupleSet Cx = R.unionUpArityToChangeSet(O);
472 HashSet<ReferenceEdge> todoEdges = new HashSet<ReferenceEdge>();
474 Hashtable<ReferenceEdge, ChangeTupleSet> edgePlannedChanges =
475 new Hashtable<ReferenceEdge, ChangeTupleSet>();
477 Iterator<ReferenceEdge> referItr = hrnX.iteratorToReferencers();
478 while( referItr.hasNext() ) {
479 ReferenceEdge edgeUpstream = referItr.next();
480 todoEdges.add(edgeUpstream);
481 edgePlannedChanges.put(edgeUpstream, Cx);
484 propagateTokensOverEdges(todoEdges,
491 // apply the updates to reachability
492 Iterator<HeapRegionNode> nodeItr = nodesWithNewAlpha.iterator();
493 while( nodeItr.hasNext() ) {
494 nodeItr.next().applyAlphaNew();
497 Iterator<ReferenceEdge> edgeItr = edgesWithNewBeta.iterator();
498 while( edgeItr.hasNext() ) {
499 edgeItr.next().applyBetaNew();
503 // then go back through and add the new edges
504 itrXhrn = lnX.iteratorToReferencees();
505 while( itrXhrn.hasNext() ) {
506 ReferenceEdge edgeX = itrXhrn.next();
507 HeapRegionNode hrnX = edgeX.getDst();
509 Iterator<ReferenceEdge> itrYhrn = lnY.iteratorToReferencees();
510 while( itrYhrn.hasNext() ) {
511 ReferenceEdge edgeY = itrYhrn.next();
512 HeapRegionNode hrnY = edgeY.getDst();
514 // prepare the new reference edge hrnX.f -> hrnY
515 ReferenceEdge edgeNew = new ReferenceEdge(hrnX,
519 edgeY.getBeta().pruneBy( hrnX.getAlpha() )
522 // look to see if an edge with same field exists
523 // and merge with it, otherwise just add the edge
524 ReferenceEdge edgeExisting = hrnX.getReferenceTo( hrnY, f );
526 if( edgeExisting != null ) {
527 edgeExisting.setBeta(
528 edgeExisting.getBeta().union( edgeNew.getBeta() )
530 // a new edge here cannot be reflexive, so existing will
531 // always be also not reflexive anymore
532 edgeExisting.setIsInitialParamReflexive( false );
534 addReferenceEdge( hrnX, hrnY, edgeNew );
540 // if there was a strong update, make sure to improve
541 // reachability with a global sweep
548 public void assignTempEqualToParamAlloc(TempDescriptor td,
550 Integer paramIndex) {
553 LabelNode lnParam = getLabelNodeFromTemp(td);
554 HeapRegionNode hrn = createNewHeapRegionNode(null,
561 "param" + paramIndex);
563 // this is a non-program-accessible label that picks up beta
564 // info to be used for fixing a caller of this method
565 TempDescriptor tdParamQ = new TempDescriptor(td+"specialQ");
566 LabelNode lnParamQ = getLabelNodeFromTemp(tdParamQ);
568 // keep track of heap regions that were created for
569 // parameter labels, the index of the parameter they
570 // are for is important when resolving method calls
571 Integer newID = hrn.getID();
572 assert !id2paramIndexSet.containsKey(newID);
573 Set s = new HashSet<Integer>();
575 id2paramIndexSet.put(newID, s);
576 paramIndex2id.put(paramIndex, newID);
577 paramIndex2tdQ.put(paramIndex, tdParamQ);
579 ReachabilitySet beta = new ReachabilitySet(new TokenTuple(newID,
581 TokenTuple.ARITY_ONE).makeCanonical()
584 // heap regions for parameters are always multiple object (see above)
585 // and have a reference to themselves, because we can't know the
586 // structure of memory that is passed into the method. We're assuming
589 ReferenceEdge edgeFromLabel =
590 new ReferenceEdge(lnParam, hrn, null, false, beta);
592 ReferenceEdge edgeFromLabelQ =
593 new ReferenceEdge(lnParamQ, hrn, null, false, beta);
595 ReferenceEdge edgeReflexive =
596 new ReferenceEdge(hrn, hrn, null, true, beta);
598 addReferenceEdge(lnParam, hrn, edgeFromLabel);
599 addReferenceEdge(lnParamQ, hrn, edgeFromLabelQ);
600 addReferenceEdge(hrn, hrn, edgeReflexive);
603 public void makeAliasedParamHeapRegionNode(TempDescriptor td) {
606 LabelNode lnParam = getLabelNodeFromTemp(td);
607 HeapRegionNode hrn = createNewHeapRegionNode(null,
617 ReachabilitySet beta = new ReachabilitySet(new TokenTuple(hrn.getID(),
619 TokenTuple.ARITY_ONE).makeCanonical()
622 // heap regions for parameters are always multiple object (see above)
623 // and have a reference to themselves, because we can't know the
624 // structure of memory that is passed into the method. We're assuming
627 ReferenceEdge edgeFromLabel =
628 new ReferenceEdge(lnParam, hrn, null, false, beta);
630 ReferenceEdge edgeReflexive =
631 new ReferenceEdge(hrn, hrn, null, true, beta);
633 addReferenceEdge(lnParam, hrn, edgeFromLabel);
634 addReferenceEdge(hrn, hrn, edgeReflexive);
637 public void assignTempEqualToAliasedParam(TempDescriptor tdParam,
638 TempDescriptor tdAliased,
639 Integer paramIndex ) {
641 assert tdParam != null;
642 assert tdAliased != null;
644 LabelNode lnParam = getLabelNodeFromTemp(tdParam);
645 LabelNode lnAliased = getLabelNodeFromTemp(tdAliased);
647 // this is a non-program-accessible label that picks up beta
648 // info to be used for fixing a caller of this method
649 TempDescriptor tdParamQ = new TempDescriptor(tdParam+"specialQ");
650 LabelNode lnParamQ = getLabelNodeFromTemp(tdParamQ);
652 // the lnAliased should always only reference one node, and that
653 // heap region node is the aliased param blob
654 assert lnAliased.getNumReferencees() == 1;
655 HeapRegionNode hrnAliasBlob = lnAliased.iteratorToReferencees().next().getDst();
657 // keep track of heap regions that were created for
658 // parameter labels, the index of the parameter they
659 // are for is important when resolving method calls
660 Integer idAliased = hrnAliasBlob.getID();
661 Set s = id2paramIndexSet.get( idAliased );
663 s = new HashSet<Integer>();
666 id2paramIndexSet.put(idAliased, s);
667 paramIndex2id.put(paramIndex, idAliased);
668 paramIndex2tdQ.put(paramIndex, tdParamQ);
670 ReachabilitySet beta = new ReachabilitySet(new TokenTuple(idAliased,
672 TokenTuple.ARITY_ONE).makeCanonical()
675 // heap regions for parameters are always multiple object (see above)
676 // and have a reference to themselves, because we can't know the
677 // structure of memory that is passed into the method. We're assuming
680 ReferenceEdge edgeFromLabel =
681 new ReferenceEdge(lnParam, hrnAliasBlob, null, false, beta);
683 ReferenceEdge edgeFromLabelQ =
684 new ReferenceEdge(lnParamQ, hrnAliasBlob, null, false, beta);
686 addReferenceEdge(lnParam, hrnAliasBlob, edgeFromLabel);
687 addReferenceEdge(lnParamQ, hrnAliasBlob, edgeFromLabelQ);
692 public void assignReturnEqualToTemp(TempDescriptor x) {
694 LabelNode lnR = getLabelNodeFromTemp(tdReturn);
695 LabelNode lnX = getLabelNodeFromTemp(x);
697 clearReferenceEdgesFrom(lnR, null, true);
699 Iterator<ReferenceEdge> itrXhrn = lnX.iteratorToReferencees();
700 while( itrXhrn.hasNext() ) {
701 ReferenceEdge edgeX = itrXhrn.next();
702 HeapRegionNode referencee = edgeX.getDst();
703 ReferenceEdge edgeNew = edgeX.copy();
706 addReferenceEdge(lnR, referencee, edgeNew);
711 public void assignTempEqualToNewAlloc(TempDescriptor x,
718 // after the age operation the newest (or zero-ith oldest)
719 // node associated with the allocation site should have
720 // no references to it as if it were a newly allocated
721 // heap region, so make a reference to it to complete
724 Integer idNewest = as.getIthOldest(0);
725 HeapRegionNode hrnNewest = id2hrn.get(idNewest);
726 assert hrnNewest != null;
728 LabelNode lnX = getLabelNodeFromTemp(x);
729 clearReferenceEdgesFrom(lnX, null, true);
731 ReferenceEdge edgeNew =
732 new ReferenceEdge(lnX, hrnNewest, null, false, hrnNewest.getAlpha() );
734 addReferenceEdge(lnX, hrnNewest, edgeNew);
738 // use the allocation site (unique to entire analysis) to
739 // locate the heap region nodes in this ownership graph
740 // that should be aged. The process models the allocation
741 // of new objects and collects all the oldest allocations
742 // in a summary node to allow for a finite analysis
744 // There is an additional property of this method. After
745 // running it on a particular ownership graph (many graphs
746 // may have heap regions related to the same allocation site)
747 // the heap region node objects in this ownership graph will be
748 // allocated. Therefore, after aging a graph for an allocation
749 // site, attempts to retrieve the heap region nodes using the
750 // integer id's contained in the allocation site should always
751 // return non-null heap regions.
752 public void age(AllocationSite as) {
754 // aging adds this allocation site to the graph's
755 // list of sites that exist in the graph, or does
756 // nothing if the site is already in the list
757 allocationSites.add(as);
759 // get the summary node for the allocation site in the context
760 // of this particular ownership graph
761 HeapRegionNode hrnSummary = getSummaryNode(as);
763 // merge oldest node into summary
764 Integer idK = as.getOldest();
765 HeapRegionNode hrnK = id2hrn.get(idK);
766 mergeIntoSummary(hrnK, hrnSummary);
768 // move down the line of heap region nodes
769 // clobbering the ith and transferring all references
770 // to and from i-1 to node i. Note that this clobbers
771 // the oldest node (hrnK) that was just merged into
773 for( int i = allocationDepth - 1; i > 0; --i ) {
775 // move references from the i-1 oldest to the ith oldest
776 Integer idIth = as.getIthOldest(i);
777 HeapRegionNode hrnI = id2hrn.get(idIth);
778 Integer idImin1th = as.getIthOldest(i - 1);
779 HeapRegionNode hrnImin1 = id2hrn.get(idImin1th);
781 transferOnto(hrnImin1, hrnI);
784 // as stated above, the newest node should have had its
785 // references moved over to the second oldest, so we wipe newest
786 // in preparation for being the new object to assign something to
787 Integer id0th = as.getIthOldest(0);
788 HeapRegionNode hrn0 = id2hrn.get(id0th);
791 // clear all references in and out of newest node
792 clearReferenceEdgesFrom(hrn0, null, true);
793 clearReferenceEdgesTo(hrn0, null, true);
796 // now tokens in reachability sets need to "age" also
797 Iterator itrAllLabelNodes = td2ln.entrySet().iterator();
798 while( itrAllLabelNodes.hasNext() ) {
799 Map.Entry me = (Map.Entry)itrAllLabelNodes.next();
800 LabelNode ln = (LabelNode) me.getValue();
802 Iterator<ReferenceEdge> itrEdges = ln.iteratorToReferencees();
803 while( itrEdges.hasNext() ) {
804 ageTokens(as, itrEdges.next() );
808 Iterator itrAllHRNodes = id2hrn.entrySet().iterator();
809 while( itrAllHRNodes.hasNext() ) {
810 Map.Entry me = (Map.Entry)itrAllHRNodes.next();
811 HeapRegionNode hrnToAge = (HeapRegionNode) me.getValue();
813 ageTokens(as, hrnToAge);
815 Iterator<ReferenceEdge> itrEdges = hrnToAge.iteratorToReferencees();
816 while( itrEdges.hasNext() ) {
817 ageTokens(as, itrEdges.next() );
822 // after tokens have been aged, reset newest node's reachability
823 if( hrn0.isFlagged() ) {
824 hrn0.setAlpha(new ReachabilitySet(
826 new TokenTuple(hrn0).makeCanonical()
831 hrn0.setAlpha(new ReachabilitySet(
832 new TokenTupleSet().makeCanonical()
839 protected HeapRegionNode getSummaryNode(AllocationSite as) {
841 Integer idSummary = as.getSummary();
842 HeapRegionNode hrnSummary = id2hrn.get(idSummary);
844 // If this is null then we haven't touched this allocation site
845 // in the context of the current ownership graph, so allocate
846 // heap region nodes appropriate for the entire allocation site.
847 // This should only happen once per ownership graph per allocation site,
848 // and a particular integer id can be used to locate the heap region
849 // in different ownership graphs that represents the same part of an
851 if( hrnSummary == null ) {
853 boolean hasFlags = false;
854 if( as.getType().isClass() ) {
855 hasFlags = as.getType().getClassDesc().hasFlags();
858 hrnSummary = createNewHeapRegionNode(idSummary,
865 as + "\\n" + as.getType() + "\\nsummary");
867 for( int i = 0; i < as.getAllocationDepth(); ++i ) {
868 Integer idIth = as.getIthOldest(i);
869 assert !id2hrn.containsKey(idIth);
870 createNewHeapRegionNode(idIth,
877 as + "\\n" + as.getType() + "\\n" + i + " oldest");
885 protected HeapRegionNode getShadowSummaryNode(AllocationSite as) {
887 Integer idShadowSummary = as.getSummaryShadow();
888 HeapRegionNode hrnShadowSummary = id2hrn.get(idShadowSummary);
890 if( hrnShadowSummary == null ) {
892 boolean hasFlags = false;
893 if( as.getType().isClass() ) {
894 hasFlags = as.getType().getClassDesc().hasFlags();
897 hrnShadowSummary = createNewHeapRegionNode(idShadowSummary,
904 as + "\\n" + as.getType() + "\\nshadowSum");
906 for( int i = 0; i < as.getAllocationDepth(); ++i ) {
907 Integer idShadowIth = as.getIthOldestShadow(i);
908 assert !id2hrn.containsKey(idShadowIth);
909 createNewHeapRegionNode(idShadowIth,
916 as + "\\n" + as.getType() + "\\n" + i + " shadow");
920 return hrnShadowSummary;
924 protected void mergeIntoSummary(HeapRegionNode hrn, HeapRegionNode hrnSummary) {
925 assert hrnSummary.isNewSummary();
927 // transfer references _from_ hrn over to hrnSummary
928 Iterator<ReferenceEdge> itrReferencee = hrn.iteratorToReferencees();
929 while( itrReferencee.hasNext() ) {
930 ReferenceEdge edge = itrReferencee.next();
931 ReferenceEdge edgeMerged = edge.copy();
932 edgeMerged.setSrc(hrnSummary);
934 HeapRegionNode hrnReferencee = edge.getDst();
935 ReferenceEdge edgeSummary = hrnSummary.getReferenceTo(hrnReferencee, edge.getFieldDesc() );
937 if( edgeSummary == null ) {
938 // the merge is trivial, nothing to be done
940 // otherwise an edge from the referencer to hrnSummary exists already
941 // and the edge referencer->hrn should be merged with it
942 edgeMerged.setBeta(edgeMerged.getBeta().union(edgeSummary.getBeta() ) );
945 addReferenceEdge(hrnSummary, hrnReferencee, edgeMerged);
948 // next transfer references _to_ hrn over to hrnSummary
949 Iterator<ReferenceEdge> itrReferencer = hrn.iteratorToReferencers();
950 while( itrReferencer.hasNext() ) {
951 ReferenceEdge edge = itrReferencer.next();
952 ReferenceEdge edgeMerged = edge.copy();
953 edgeMerged.setDst(hrnSummary);
955 OwnershipNode onReferencer = edge.getSrc();
956 ReferenceEdge edgeSummary = onReferencer.getReferenceTo(hrnSummary, edge.getFieldDesc() );
958 if( edgeSummary == null ) {
959 // the merge is trivial, nothing to be done
961 // otherwise an edge from the referencer to alpha_S exists already
962 // and the edge referencer->alpha_K should be merged with it
963 edgeMerged.setBeta(edgeMerged.getBeta().union(edgeSummary.getBeta() ) );
966 addReferenceEdge(onReferencer, hrnSummary, edgeMerged);
969 // then merge hrn reachability into hrnSummary
970 hrnSummary.setAlpha(hrnSummary.getAlpha().union(hrn.getAlpha() ) );
974 protected void transferOnto(HeapRegionNode hrnA, HeapRegionNode hrnB) {
976 // clear references in and out of node b
977 clearReferenceEdgesFrom(hrnB, null, true);
978 clearReferenceEdgesTo(hrnB, null, true);
980 // copy each edge in and out of A to B
981 Iterator<ReferenceEdge> itrReferencee = hrnA.iteratorToReferencees();
982 while( itrReferencee.hasNext() ) {
983 ReferenceEdge edge = itrReferencee.next();
984 HeapRegionNode hrnReferencee = edge.getDst();
985 ReferenceEdge edgeNew = edge.copy();
986 edgeNew.setSrc(hrnB);
988 addReferenceEdge(hrnB, hrnReferencee, edgeNew);
991 Iterator<ReferenceEdge> itrReferencer = hrnA.iteratorToReferencers();
992 while( itrReferencer.hasNext() ) {
993 ReferenceEdge edge = itrReferencer.next();
994 OwnershipNode onReferencer = edge.getSrc();
995 ReferenceEdge edgeNew = edge.copy();
996 edgeNew.setDst(hrnB);
998 addReferenceEdge(onReferencer, hrnB, edgeNew);
1001 // replace hrnB reachability with hrnA's
1002 hrnB.setAlpha(hrnA.getAlpha() );
1006 protected void ageTokens(AllocationSite as, ReferenceEdge edge) {
1007 edge.setBeta(edge.getBeta().ageTokens(as) );
1010 protected void ageTokens(AllocationSite as, HeapRegionNode hrn) {
1011 hrn.setAlpha(hrn.getAlpha().ageTokens(as) );
1015 public Set<Integer> calculateAliasedParamSet(FlatCall fc,
1019 Hashtable<Integer, LabelNode> paramIndex2ln =
1020 new Hashtable<Integer, LabelNode>();
1022 Hashtable<Integer, HashSet<HeapRegionNode> > paramIndex2reachableCallerNodes =
1023 new Hashtable<Integer, HashSet<HeapRegionNode> >();
1025 for( int i = 0; i < fm.numParameters(); ++i ) {
1026 Integer paramIndex = new Integer(i);
1028 // now depending on whether the callee is static or not
1029 // we need to account for a "this" argument in order to
1030 // find the matching argument in the caller context
1031 TempDescriptor argTemp_i;
1033 argTemp_i = fc.getArg(paramIndex);
1035 if( paramIndex.equals(0) ) {
1036 argTemp_i = fc.getThis();
1038 argTemp_i = fc.getArg(paramIndex - 1);
1042 // in non-static methods there is a "this" pointer
1043 // that should be taken into account
1045 assert fc.numArgs() == fm.numParameters();
1047 assert fc.numArgs() + 1 == fm.numParameters();
1050 LabelNode argLabel_i = getLabelNodeFromTemp(argTemp_i);
1051 paramIndex2ln.put(paramIndex, argLabel_i);
1054 Iterator lnArgItr = paramIndex2ln.entrySet().iterator();
1055 while( lnArgItr.hasNext() ) {
1056 Map.Entry me = (Map.Entry)lnArgItr.next();
1057 Integer index = (Integer) me.getKey();
1058 LabelNode lnArg_i = (LabelNode) me.getValue();
1060 // rewrite alpha for the nodes reachable from argument label i
1061 HashSet<HeapRegionNode> reachableNodes = new HashSet<HeapRegionNode>();
1062 HashSet<HeapRegionNode> todoNodes = new HashSet<HeapRegionNode>();
1064 // to find all reachable nodes, start with label referencees
1065 Iterator<ReferenceEdge> edgeArgItr = lnArg_i.iteratorToReferencees();
1066 while( edgeArgItr.hasNext() ) {
1067 ReferenceEdge edge = edgeArgItr.next();
1068 todoNodes.add(edge.getDst() );
1071 // then follow links until all reachable nodes have been found
1072 while( !todoNodes.isEmpty() ) {
1073 HeapRegionNode hrn = todoNodes.iterator().next();
1074 todoNodes.remove(hrn);
1075 reachableNodes.add(hrn);
1077 Iterator<ReferenceEdge> edgeItr = hrn.iteratorToReferencees();
1078 while( edgeItr.hasNext() ) {
1079 ReferenceEdge edge = edgeItr.next();
1081 if( !reachableNodes.contains(edge.getDst() ) ) {
1082 todoNodes.add(edge.getDst() );
1088 paramIndex2reachableCallerNodes.put(index, reachableNodes);
1091 Set<Integer> aliasedIndices = new HashSet<Integer>();
1093 // check for arguments that are aliased
1094 for( int i = 0; i < fm.numParameters(); ++i ) {
1095 for( int j = 0; j < i; ++j ) {
1096 HashSet<HeapRegionNode> s1 = paramIndex2reachableCallerNodes.get( i );
1097 HashSet<HeapRegionNode> s2 = paramIndex2reachableCallerNodes.get( j );
1099 Set<HeapRegionNode> intersection = new HashSet<HeapRegionNode>(s1);
1100 intersection.retainAll(s2);
1102 if( !intersection.isEmpty() ) {
1103 aliasedIndices.add( new Integer( i ) );
1104 aliasedIndices.add( new Integer( j ) );
1109 return aliasedIndices;
1113 public void resolveMethodCall(FlatCall fc,
1116 OwnershipGraph ogCallee) {
1118 // define rewrite rules and other structures to organize
1119 // data by parameter/argument index
1120 Hashtable<Integer, ReachabilitySet> paramIndex2rewriteH =
1121 new Hashtable<Integer, ReachabilitySet>();
1123 Hashtable<Integer, ReachabilitySet> paramIndex2rewriteJ =
1124 new Hashtable<Integer, ReachabilitySet>();
1126 Hashtable<Integer, ReachabilitySet> paramIndex2rewriteK =
1127 new Hashtable<Integer, ReachabilitySet>();
1129 Hashtable<Integer, ReachabilitySet> paramIndex2rewrite_d =
1130 new Hashtable<Integer, ReachabilitySet>();
1132 Hashtable<Integer, ReachabilitySet> paramIndex2rewriteD =
1133 new Hashtable<Integer, ReachabilitySet>();
1135 // helpful structures
1136 Hashtable<TokenTuple, Integer> paramToken2paramIndex =
1137 new Hashtable<TokenTuple, Integer>();
1139 Hashtable<Integer, TokenTuple> paramIndex2paramToken =
1140 new Hashtable<Integer, TokenTuple>();
1142 Hashtable<TokenTuple, Integer> paramTokenPlus2paramIndex =
1143 new Hashtable<TokenTuple, Integer>();
1145 Hashtable<Integer, TokenTuple> paramIndex2paramTokenPlus =
1146 new Hashtable<Integer, TokenTuple>();
1148 Hashtable<Integer, LabelNode> paramIndex2ln =
1149 new Hashtable<Integer, LabelNode>();
1151 Hashtable<Integer, HashSet<HeapRegionNode> > paramIndex2reachableCallerNodes =
1152 new Hashtable<Integer, HashSet<HeapRegionNode> >();
1155 // add a bogus entry with the identity rule for easy rewrite
1156 // of new callee nodes and edges, doesn't belong to any parameter
1157 Integer bogusID = new Integer(bogusParamIndexInt);
1158 Integer bogusIndex = new Integer(bogusParamIndexInt);
1159 TokenTuple bogusToken = new TokenTuple(bogusID, true, TokenTuple.ARITY_ONE).makeCanonical();
1160 TokenTuple bogusTokenPlus = new TokenTuple(bogusID, true, TokenTuple.ARITY_ONEORMORE).makeCanonical();
1161 ReachabilitySet rsIdentity =
1162 new ReachabilitySet(
1163 new TokenTupleSet(bogusToken).makeCanonical()
1166 paramIndex2rewriteH.put(bogusIndex, rsIdentity);
1167 paramIndex2rewriteJ.put(bogusIndex, rsIdentity);
1168 paramToken2paramIndex.put(bogusToken, bogusIndex);
1169 paramIndex2paramToken.put(bogusIndex, bogusToken);
1170 paramTokenPlus2paramIndex.put(bogusTokenPlus, bogusIndex);
1171 paramIndex2paramTokenPlus.put(bogusIndex, bogusTokenPlus);
1174 for( int i = 0; i < fm.numParameters(); ++i ) {
1175 Integer paramIndex = new Integer(i);
1177 assert ogCallee.paramIndex2id.containsKey(paramIndex);
1178 Integer idParam = ogCallee.paramIndex2id.get(paramIndex);
1180 assert ogCallee.id2hrn.containsKey(idParam);
1181 HeapRegionNode hrnParam = ogCallee.id2hrn.get(idParam);
1182 assert hrnParam != null;
1183 paramIndex2rewriteH.put(paramIndex,
1185 toShadowTokens(ogCallee, hrnParam.getAlpha() )
1188 ReferenceEdge edgeReflexive_i = hrnParam.getReferenceTo(hrnParam, null);
1189 assert edgeReflexive_i != null;
1190 paramIndex2rewriteJ.put(paramIndex,
1191 toShadowTokens(ogCallee, edgeReflexive_i.getBeta() )
1194 TempDescriptor tdParamQ = ogCallee.paramIndex2tdQ.get(paramIndex);
1195 assert tdParamQ != null;
1196 LabelNode lnParamQ = ogCallee.td2ln.get(tdParamQ);
1197 assert lnParamQ != null;
1198 ReferenceEdge edgeSpecialQ_i = lnParamQ.getReferenceTo(hrnParam, null);
1199 assert edgeSpecialQ_i != null;
1200 paramIndex2rewriteK.put(paramIndex,
1201 toShadowTokens(ogCallee, edgeSpecialQ_i.getBeta() )
1204 TokenTuple p_i = new TokenTuple(hrnParam.getID(),
1206 TokenTuple.ARITY_ONE).makeCanonical();
1207 paramToken2paramIndex.put(p_i, paramIndex);
1208 paramIndex2paramToken.put(paramIndex, p_i);
1210 TokenTuple p_i_plus = new TokenTuple(hrnParam.getID(),
1212 TokenTuple.ARITY_ONEORMORE).makeCanonical();
1213 paramTokenPlus2paramIndex.put(p_i_plus, paramIndex);
1214 paramIndex2paramTokenPlus.put(paramIndex, p_i_plus);
1216 // now depending on whether the callee is static or not
1217 // we need to account for a "this" argument in order to
1218 // find the matching argument in the caller context
1219 TempDescriptor argTemp_i;
1221 argTemp_i = fc.getArg(paramIndex);
1223 if( paramIndex.equals(0) ) {
1224 argTemp_i = fc.getThis();
1226 argTemp_i = fc.getArg(paramIndex - 1);
1230 // in non-static methods there is a "this" pointer
1231 // that should be taken into account
1233 assert fc.numArgs() == fm.numParameters();
1235 assert fc.numArgs() + 1 == fm.numParameters();
1238 LabelNode argLabel_i = getLabelNodeFromTemp(argTemp_i);
1239 paramIndex2ln.put(paramIndex, argLabel_i);
1241 ReachabilitySet d_i = new ReachabilitySet().makeCanonical();
1242 Iterator<ReferenceEdge> edgeItr = argLabel_i.iteratorToReferencees();
1243 while( edgeItr.hasNext() ) {
1244 ReferenceEdge edge = edgeItr.next();
1245 d_i = d_i.union(edge.getBeta());
1247 paramIndex2rewrite_d.put(paramIndex, d_i);
1249 ReachabilitySet D_i = d_i.exhaustiveArityCombinations();
1250 paramIndex2rewriteD.put(paramIndex, D_i);
1254 HashSet<HeapRegionNode> nodesWithNewAlpha = new HashSet<HeapRegionNode>();
1255 HashSet<ReferenceEdge> edgesWithNewBeta = new HashSet<ReferenceEdge>();
1257 HashSet<ReferenceEdge> edgesReachable = new HashSet<ReferenceEdge>();
1258 HashSet<ReferenceEdge> edgesUpstream = new HashSet<ReferenceEdge>();
1260 Iterator lnArgItr = paramIndex2ln.entrySet().iterator();
1261 while( lnArgItr.hasNext() ) {
1262 Map.Entry me = (Map.Entry)lnArgItr.next();
1263 Integer index = (Integer) me.getKey();
1264 LabelNode lnArg_i = (LabelNode) me.getValue();
1266 // rewrite alpha for the nodes reachable from argument label i
1267 HashSet<HeapRegionNode> reachableNodes = new HashSet<HeapRegionNode>();
1268 HashSet<HeapRegionNode> todoNodes = new HashSet<HeapRegionNode>();
1270 // to find all reachable nodes, start with label referencees
1271 Iterator<ReferenceEdge> edgeArgItr = lnArg_i.iteratorToReferencees();
1272 while( edgeArgItr.hasNext() ) {
1273 ReferenceEdge edge = edgeArgItr.next();
1274 todoNodes.add(edge.getDst() );
1277 // then follow links until all reachable nodes have been found
1278 while( !todoNodes.isEmpty() ) {
1279 HeapRegionNode hrn = todoNodes.iterator().next();
1280 todoNodes.remove(hrn);
1281 reachableNodes.add(hrn);
1283 Iterator<ReferenceEdge> edgeItr = hrn.iteratorToReferencees();
1284 while( edgeItr.hasNext() ) {
1285 ReferenceEdge edge = edgeItr.next();
1287 if( !reachableNodes.contains(edge.getDst() ) ) {
1288 todoNodes.add(edge.getDst() );
1294 paramIndex2reachableCallerNodes.put(index, reachableNodes);
1296 // now iterate over reachable nodes to update their alpha, and
1297 // classify edges found as "argument reachable" or "upstream"
1298 Iterator<HeapRegionNode> hrnItr = reachableNodes.iterator();
1299 while( hrnItr.hasNext() ) {
1300 HeapRegionNode hrn = hrnItr.next();
1302 rewriteCallerReachability(index,
1305 paramIndex2rewriteH.get(index),
1306 paramIndex2rewrite_d,
1307 paramIndex2rewriteD,
1308 paramIndex2paramToken.get(index),
1309 paramToken2paramIndex,
1310 paramTokenPlus2paramIndex,
1314 nodesWithNewAlpha.add(hrn);
1316 // look at all incoming edges to the reachable nodes
1317 // and sort them as edges reachable from the argument
1318 // label node, or upstream edges
1319 Iterator<ReferenceEdge> edgeItr = hrn.iteratorToReferencers();
1320 while( edgeItr.hasNext() ) {
1321 ReferenceEdge edge = edgeItr.next();
1323 OwnershipNode on = edge.getSrc();
1325 if( on instanceof LabelNode ) {
1327 LabelNode ln0 = (LabelNode) on;
1328 if( ln0.equals(lnArg_i) ) {
1329 edgesReachable.add(edge);
1331 edgesUpstream.add(edge);
1336 HeapRegionNode hrn0 = (HeapRegionNode) on;
1337 if( reachableNodes.contains(hrn0) ) {
1338 edgesReachable.add(edge);
1340 edgesUpstream.add(edge);
1346 // update reachable edges
1347 Iterator<ReferenceEdge> edgeReachableItr = edgesReachable.iterator();
1348 while( edgeReachableItr.hasNext() ) {
1349 ReferenceEdge edgeReachable = edgeReachableItr.next();
1351 rewriteCallerReachability(index,
1354 paramIndex2rewriteJ.get(index),
1355 paramIndex2rewrite_d,
1356 paramIndex2rewriteD,
1357 paramIndex2paramToken.get(index),
1358 paramToken2paramIndex,
1359 paramTokenPlus2paramIndex,
1363 edgesWithNewBeta.add(edgeReachable);
1366 // update upstream edges
1367 Hashtable<ReferenceEdge, ChangeTupleSet> edgeUpstreamPlannedChanges =
1368 new Hashtable<ReferenceEdge, ChangeTupleSet>();
1370 Iterator<ReferenceEdge> edgeUpstreamItr = edgesUpstream.iterator();
1371 while( edgeUpstreamItr.hasNext() ) {
1372 ReferenceEdge edgeUpstream = edgeUpstreamItr.next();
1374 rewriteCallerReachability(index,
1377 paramIndex2rewriteK.get(index),
1378 paramIndex2rewrite_d,
1379 paramIndex2rewriteD,
1380 paramIndex2paramToken.get(index),
1381 paramToken2paramIndex,
1382 paramTokenPlus2paramIndex,
1384 edgeUpstreamPlannedChanges);
1386 edgesWithNewBeta.add(edgeUpstream);
1389 propagateTokensOverEdges(edgesUpstream,
1390 edgeUpstreamPlannedChanges,
1395 // commit changes to alpha and beta
1396 Iterator<HeapRegionNode> nodeItr = nodesWithNewAlpha.iterator();
1397 while( nodeItr.hasNext() ) {
1398 nodeItr.next().applyAlphaNew();
1401 Iterator<ReferenceEdge> edgeItr = edgesWithNewBeta.iterator();
1402 while( edgeItr.hasNext() ) {
1403 edgeItr.next().applyBetaNew();
1407 // verify the existence of allocation sites and their
1408 // shadows from the callee in the context of this caller graph
1409 // then map allocated nodes of callee onto the caller shadows
1411 Iterator<AllocationSite> asItr = ogCallee.allocationSites.iterator();
1412 while( asItr.hasNext() ) {
1413 AllocationSite allocSite = asItr.next();
1415 // grab the summary in the caller just to make sure
1416 // the allocation site has nodes in the caller
1417 HeapRegionNode hrnSummary = getSummaryNode(allocSite);
1419 // assert that the shadow nodes have no reference edges
1420 // because they're brand new to the graph, or last time
1421 // they were used they should have been cleared of edges
1422 HeapRegionNode hrnShadowSummary = getShadowSummaryNode(allocSite);
1423 assert hrnShadowSummary.getNumReferencers() == 0;
1424 assert hrnShadowSummary.getNumReferencees() == 0;
1426 // then bring g_ij onto g'_ij and rewrite
1427 HeapRegionNode hrnSummaryCallee = ogCallee.getSummaryNode(allocSite);
1428 hrnShadowSummary.setAlpha(toShadowTokens(ogCallee, hrnSummaryCallee.getAlpha() ) );
1430 // shadow nodes only are touched by a rewrite one time,
1431 // so rewrite and immediately commit--and they don't belong
1432 // to a particular parameter, so use a bogus param index
1433 // that pulls a self-rewrite out of H
1434 rewriteCallerReachability(bogusIndex,
1437 hrnShadowSummary.getAlpha(),
1438 paramIndex2rewrite_d,
1439 paramIndex2rewriteD,
1441 paramToken2paramIndex,
1442 paramTokenPlus2paramIndex,
1446 hrnShadowSummary.applyAlphaNew();
1449 for( int i = 0; i < allocSite.getAllocationDepth(); ++i ) {
1450 Integer idIth = allocSite.getIthOldest(i);
1451 assert id2hrn.containsKey(idIth);
1452 HeapRegionNode hrnIth = id2hrn.get(idIth);
1454 Integer idShadowIth = -(allocSite.getIthOldest(i));
1455 assert id2hrn.containsKey(idShadowIth);
1456 HeapRegionNode hrnIthShadow = id2hrn.get(idShadowIth);
1457 assert hrnIthShadow.getNumReferencers() == 0;
1458 assert hrnIthShadow.getNumReferencees() == 0;
1460 assert ogCallee.id2hrn.containsKey(idIth);
1461 HeapRegionNode hrnIthCallee = ogCallee.id2hrn.get(idIth);
1462 hrnIthShadow.setAlpha(toShadowTokens(ogCallee, hrnIthCallee.getAlpha() ) );
1464 rewriteCallerReachability(bogusIndex,
1467 hrnIthShadow.getAlpha(),
1468 paramIndex2rewrite_d,
1469 paramIndex2rewriteD,
1471 paramToken2paramIndex,
1472 paramTokenPlus2paramIndex,
1476 hrnIthShadow.applyAlphaNew();
1481 // for every heap region->heap region edge in the
1482 // callee graph, create the matching edge or edges
1483 // in the caller graph
1484 Set sCallee = ogCallee.id2hrn.entrySet();
1485 Iterator iCallee = sCallee.iterator();
1486 while( iCallee.hasNext() ) {
1487 Map.Entry meCallee = (Map.Entry)iCallee.next();
1488 Integer idCallee = (Integer) meCallee.getKey();
1489 HeapRegionNode hrnCallee = (HeapRegionNode) meCallee.getValue();
1491 Iterator<ReferenceEdge> heapRegionsItrCallee = hrnCallee.iteratorToReferencees();
1492 while( heapRegionsItrCallee.hasNext() ) {
1493 ReferenceEdge edgeCallee = heapRegionsItrCallee.next();
1494 HeapRegionNode hrnChildCallee = edgeCallee.getDst();
1495 Integer idChildCallee = hrnChildCallee.getID();
1497 // only address this edge if it is not a special reflexive edge
1498 if( !edgeCallee.isInitialParamReflexive() ) {
1500 // now we know that in the callee method's ownership graph
1501 // there is a heap region->heap region reference edge given
1502 // by heap region pointers:
1503 // hrnCallee -> heapChildCallee
1505 // or by the ownership-graph independent ID's:
1506 // idCallee -> idChildCallee
1508 // make the edge with src and dst so beta info is
1509 // calculated once, then copy it for each new edge in caller
1510 ReferenceEdge edgeNewInCallerTemplate = new ReferenceEdge(null,
1512 edgeCallee.getFieldDesc(),
1514 toShadowTokens(ogCallee,
1515 edgeCallee.getBeta() )
1517 rewriteCallerReachability(bogusIndex,
1519 edgeNewInCallerTemplate,
1520 edgeNewInCallerTemplate.getBeta(),
1521 paramIndex2rewrite_d,
1522 paramIndex2rewriteD,
1524 paramToken2paramIndex,
1525 paramTokenPlus2paramIndex,
1529 edgeNewInCallerTemplate.applyBetaNew();
1532 // So now make a set of possible source heaps in the caller graph
1533 // and a set of destination heaps in the caller graph, and make
1534 // a reference edge in the caller for every possible (src,dst) pair
1535 HashSet<HeapRegionNode> possibleCallerSrcs =
1536 getHRNSetThatPossiblyMapToCalleeHRN(ogCallee,
1537 (HeapRegionNode) edgeCallee.getSrc(),
1538 paramIndex2reachableCallerNodes);
1540 HashSet<HeapRegionNode> possibleCallerDsts =
1541 getHRNSetThatPossiblyMapToCalleeHRN(ogCallee,
1542 edgeCallee.getDst(),
1543 paramIndex2reachableCallerNodes);
1546 // make every possible pair of {srcSet} -> {dstSet} edges in the caller
1547 Iterator srcItr = possibleCallerSrcs.iterator();
1548 while( srcItr.hasNext() ) {
1549 HeapRegionNode src = (HeapRegionNode) srcItr.next();
1551 if( !hasMatchingField(src, edgeCallee) ) {
1552 // prune this source node possibility
1556 Iterator dstItr = possibleCallerDsts.iterator();
1557 while( dstItr.hasNext() ) {
1558 HeapRegionNode dst = (HeapRegionNode) dstItr.next();
1560 if( !hasMatchingType(edgeCallee, dst) ) {
1565 // otherwise the caller src and dst pair can match the edge, so make it
1566 ReferenceEdge edgeNewInCaller = edgeNewInCallerTemplate.copy();
1567 edgeNewInCaller.setSrc(src);
1568 edgeNewInCaller.setDst(dst);
1570 ReferenceEdge edgeExisting = src.getReferenceTo(dst, edgeNewInCaller.getFieldDesc() );
1571 if( edgeExisting == null ) {
1572 // if this edge doesn't exist in the caller, create it
1573 addReferenceEdge(src, dst, edgeNewInCaller);
1575 // if it already exists, merge with it
1576 edgeExisting.setBeta(edgeExisting.getBeta().union(edgeNewInCaller.getBeta() ) );
1585 // return value may need to be assigned in caller
1586 TempDescriptor returnTemp = fc.getReturnTemp();
1587 if( returnTemp != null && !returnTemp.getType().isImmutable() ) {
1589 LabelNode lnLhsCaller = getLabelNodeFromTemp(returnTemp);
1590 clearReferenceEdgesFrom(lnLhsCaller, null, true);
1592 LabelNode lnReturnCallee = ogCallee.getLabelNodeFromTemp(tdReturn);
1593 Iterator<ReferenceEdge> edgeCalleeItr = lnReturnCallee.iteratorToReferencees();
1594 while( edgeCalleeItr.hasNext() ) {
1595 ReferenceEdge edgeCallee = edgeCalleeItr.next();
1597 ReferenceEdge edgeNewInCallerTemplate = new ReferenceEdge(null,
1599 edgeCallee.getFieldDesc(),
1601 toShadowTokens(ogCallee,
1602 edgeCallee.getBeta() )
1604 rewriteCallerReachability(bogusIndex,
1606 edgeNewInCallerTemplate,
1607 edgeNewInCallerTemplate.getBeta(),
1608 paramIndex2rewrite_d,
1609 paramIndex2rewriteD,
1611 paramToken2paramIndex,
1612 paramTokenPlus2paramIndex,
1616 edgeNewInCallerTemplate.applyBetaNew();
1619 HashSet<HeapRegionNode> assignCallerRhs =
1620 getHRNSetThatPossiblyMapToCalleeHRN(ogCallee,
1621 edgeCallee.getDst(),
1622 paramIndex2reachableCallerNodes);
1624 Iterator<HeapRegionNode> itrHrn = assignCallerRhs.iterator();
1625 while( itrHrn.hasNext() ) {
1626 HeapRegionNode hrnCaller = itrHrn.next();
1628 if( !hasMatchingType(edgeCallee, hrnCaller) ) {
1633 // otherwise caller node can match callee edge, so make it
1634 ReferenceEdge edgeNewInCaller = edgeNewInCallerTemplate.copy();
1635 edgeNewInCaller.setSrc(lnLhsCaller);
1636 edgeNewInCaller.setDst(hrnCaller);
1638 ReferenceEdge edgeExisting = lnLhsCaller.getReferenceTo(hrnCaller, edgeNewInCaller.getFieldDesc() );
1639 if( edgeExisting == null ) {
1641 // if this edge doesn't exist in the caller, create it
1642 addReferenceEdge(lnLhsCaller, hrnCaller, edgeNewInCaller);
1644 // if it already exists, merge with it
1645 edgeExisting.setBeta(edgeExisting.getBeta().union(edgeNewInCaller.getBeta() ) );
1652 // merge the shadow nodes of allocation sites back down to normal capacity
1653 Iterator<AllocationSite> allocItr = ogCallee.allocationSites.iterator();
1654 while( allocItr.hasNext() ) {
1655 AllocationSite as = allocItr.next();
1657 // first age each allocation site enough times to make room for the shadow nodes
1658 for( int i = 0; i < as.getAllocationDepth(); ++i ) {
1662 // then merge the shadow summary into the normal summary
1663 HeapRegionNode hrnSummary = getSummaryNode(as);
1664 assert hrnSummary != null;
1666 HeapRegionNode hrnSummaryShadow = getShadowSummaryNode(as);
1667 assert hrnSummaryShadow != null;
1669 mergeIntoSummary(hrnSummaryShadow, hrnSummary);
1671 // then clear off after merge
1672 clearReferenceEdgesFrom(hrnSummaryShadow, null, true);
1673 clearReferenceEdgesTo(hrnSummaryShadow, null, true);
1674 hrnSummaryShadow.setAlpha(new ReachabilitySet().makeCanonical() );
1676 // then transplant shadow nodes onto the now clean normal nodes
1677 for( int i = 0; i < as.getAllocationDepth(); ++i ) {
1679 Integer idIth = as.getIthOldest(i);
1680 HeapRegionNode hrnIth = id2hrn.get(idIth);
1682 Integer idIthShadow = as.getIthOldestShadow(i);
1683 HeapRegionNode hrnIthShadow = id2hrn.get(idIthShadow);
1685 transferOnto(hrnIthShadow, hrnIth);
1687 // clear off shadow nodes after transfer
1688 clearReferenceEdgesFrom(hrnIthShadow, null, true);
1689 clearReferenceEdgesTo(hrnIthShadow, null, true);
1690 hrnIthShadow.setAlpha(new ReachabilitySet().makeCanonical() );
1693 // finally, globally change shadow tokens into normal tokens
1694 Iterator itrAllLabelNodes = td2ln.entrySet().iterator();
1695 while( itrAllLabelNodes.hasNext() ) {
1696 Map.Entry me = (Map.Entry)itrAllLabelNodes.next();
1697 LabelNode ln = (LabelNode) me.getValue();
1699 Iterator<ReferenceEdge> itrEdges = ln.iteratorToReferencees();
1700 while( itrEdges.hasNext() ) {
1701 unshadowTokens(as, itrEdges.next() );
1705 Iterator itrAllHRNodes = id2hrn.entrySet().iterator();
1706 while( itrAllHRNodes.hasNext() ) {
1707 Map.Entry me = (Map.Entry)itrAllHRNodes.next();
1708 HeapRegionNode hrnToAge = (HeapRegionNode) me.getValue();
1710 unshadowTokens(as, hrnToAge);
1712 Iterator<ReferenceEdge> itrEdges = hrnToAge.iteratorToReferencees();
1713 while( itrEdges.hasNext() ) {
1714 unshadowTokens(as, itrEdges.next() );
1719 // improve reachability as much as possible
1724 protected boolean hasMatchingField(HeapRegionNode src, ReferenceEdge edge) {
1726 // if no allocation site, then it's a match-everything region
1727 AllocationSite asSrc = src.getAllocationSite();
1728 if( asSrc == null ) {
1732 TypeDescriptor tdSrc = asSrc.getType();
1733 assert tdSrc != null;
1735 // if it's not a class, it doesn't have any fields to match
1736 if( !tdSrc.isClass() ) {
1740 Iterator fieldsSrcItr = tdSrc.getClassDesc().getFields();
1741 while( fieldsSrcItr.hasNext() ) {
1742 FieldDescriptor fd = (FieldDescriptor) fieldsSrcItr.next();
1743 if( fd == edge.getFieldDesc() ) {
1748 // otherwise it is a class with fields
1749 // but we didn't find a match
1754 protected boolean hasMatchingType(ReferenceEdge edge, HeapRegionNode dst) {
1756 // if the region has no type, matches everything
1757 AllocationSite asDst = dst.getAllocationSite();
1758 if( asDst == null ) {
1762 TypeDescriptor tdDst = asDst.getType();
1763 assert tdDst != null;
1765 // if the type is not a class don't match because
1766 // primitives are copied, no memory aliases
1767 ClassDescriptor cdDst = tdDst.getClassDesc();
1768 if( cdDst == null ) {
1772 // if the field is null, it matches everything
1773 FieldDescriptor fd = edge.getFieldDesc();
1777 TypeDescriptor tdFd = fd.getType();
1778 assert tdFd != null;
1780 return typeUtil.isSuperorType(tdFd, tdDst);
1785 protected void unshadowTokens(AllocationSite as, ReferenceEdge edge) {
1786 edge.setBeta(edge.getBeta().unshadowTokens(as) );
1789 protected void unshadowTokens(AllocationSite as, HeapRegionNode hrn) {
1790 hrn.setAlpha(hrn.getAlpha().unshadowTokens(as) );
1794 private ReachabilitySet toShadowTokens(OwnershipGraph ogCallee,
1795 ReachabilitySet rsIn) {
1797 ReachabilitySet rsOut = new ReachabilitySet(rsIn).makeCanonical();
1799 Iterator<AllocationSite> allocItr = ogCallee.allocationSites.iterator();
1800 while( allocItr.hasNext() ) {
1801 AllocationSite as = allocItr.next();
1803 rsOut = rsOut.toShadowTokens(as);
1806 return rsOut.makeCanonical();
1810 private void rewriteCallerReachability(Integer paramIndex,
1813 ReachabilitySet rules,
1814 Hashtable<Integer, ReachabilitySet> paramIndex2rewrite_d,
1815 Hashtable<Integer, ReachabilitySet> paramIndex2rewriteD,
1817 Hashtable<TokenTuple, Integer> paramToken2paramIndex,
1818 Hashtable<TokenTuple, Integer> paramTokenPlus2paramIndex,
1819 boolean makeChangeSet,
1820 Hashtable<ReferenceEdge, ChangeTupleSet> edgePlannedChanges) {
1821 assert(hrn == null && edge != null) ||
1822 (hrn != null && edge == null);
1824 assert rules != null;
1827 ReachabilitySet callerReachabilityCurrent;
1829 callerReachabilityCurrent = edge.getBeta();
1831 callerReachabilityCurrent = hrn.getAlpha();
1834 ReachabilitySet callerReachabilityNew = new ReachabilitySet().makeCanonical();
1836 // for initializing structures in this method
1837 TokenTupleSet ttsEmpty = new TokenTupleSet().makeCanonical();
1839 // use this to construct a change set if required; the idea is to
1840 // map every partially rewritten token tuple set to the set of
1841 // caller-context token tuple sets that were used to generate it
1842 Hashtable<TokenTupleSet, HashSet<TokenTupleSet> > rewritten2source =
1843 new Hashtable<TokenTupleSet, HashSet<TokenTupleSet> >();
1844 rewritten2source.put(ttsEmpty, new HashSet<TokenTupleSet>() );
1847 Iterator<TokenTupleSet> rulesItr = rules.iterator();
1848 while(rulesItr.hasNext()) {
1849 TokenTupleSet rule = rulesItr.next();
1851 ReachabilitySet rewrittenRule = new ReachabilitySet(ttsEmpty).makeCanonical();
1853 Iterator<TokenTuple> ruleItr = rule.iterator();
1854 while(ruleItr.hasNext()) {
1855 TokenTuple ttCallee = ruleItr.next();
1857 // compute the possibilities for rewriting this callee token
1858 ReachabilitySet ttCalleeRewrites = null;
1859 boolean callerSourceUsed = false;
1861 if( ttCallee.equals(p_i) ) {
1862 // replace the arity-one token of the current parameter with the reachability
1863 // information from the caller edge
1864 ttCalleeRewrites = callerReachabilityCurrent;
1865 callerSourceUsed = true;
1867 } else if( paramToken2paramIndex.containsKey(ttCallee) ) {
1869 Integer paramIndex_j = paramToken2paramIndex.get(ttCallee);
1870 assert paramIndex_j != null;
1871 ttCalleeRewrites = paramIndex2rewrite_d.get(paramIndex_j);
1872 assert ttCalleeRewrites != null;
1874 } else if( paramTokenPlus2paramIndex.containsKey(ttCallee) ) {
1876 Integer paramIndex_j = paramTokenPlus2paramIndex.get(ttCallee);
1877 assert paramIndex_j != null;
1878 ttCalleeRewrites = paramIndex2rewriteD.get(paramIndex_j);
1879 assert ttCalleeRewrites != null;
1882 // otherwise there's no need for a rewrite, just pass this one on
1883 TokenTupleSet ttsCaller = new TokenTupleSet(ttCallee).makeCanonical();
1884 ttCalleeRewrites = new ReachabilitySet(ttsCaller).makeCanonical();
1887 // branch every version of the working rewritten rule with
1888 // the possibilities for rewriting the current callee token
1889 ReachabilitySet rewrittenRuleWithTTCallee = new ReachabilitySet().makeCanonical();
1891 Iterator<TokenTupleSet> rewrittenRuleItr = rewrittenRule.iterator();
1892 while( rewrittenRuleItr.hasNext() ) {
1893 TokenTupleSet ttsRewritten = rewrittenRuleItr.next();
1895 Iterator<TokenTupleSet> ttCalleeRewritesItr = ttCalleeRewrites.iterator();
1896 while( ttCalleeRewritesItr.hasNext() ) {
1897 TokenTupleSet ttsBranch = ttCalleeRewritesItr.next();
1899 TokenTupleSet ttsRewrittenNext = ttsRewritten.unionUpArity(ttsBranch);
1901 if( makeChangeSet ) {
1902 // in order to keep the list of source token tuple sets
1903 // start with the sets used to make the partially rewritten
1904 // rule up to this point
1905 HashSet<TokenTupleSet> sourceSets = rewritten2source.get(ttsRewritten);
1906 assert sourceSets != null;
1908 // make a shallow copy for possible modification
1909 sourceSets = (HashSet<TokenTupleSet>)sourceSets.clone();
1911 // if we used something from the caller to rewrite it, remember
1912 if( callerSourceUsed ) {
1913 sourceSets.add(ttsBranch);
1916 // set mapping for the further rewritten rule
1917 rewritten2source.put(ttsRewrittenNext, sourceSets);
1920 rewrittenRuleWithTTCallee =
1921 rewrittenRuleWithTTCallee.union(ttsRewrittenNext);
1925 // now the rewritten rule's possibilities have been extended by
1926 // rewriting the current callee token, remember result
1927 rewrittenRule = rewrittenRuleWithTTCallee;
1930 // the rule has been entirely rewritten into the caller context
1931 // now, so add it to the new reachability information
1932 callerReachabilityNew =
1933 callerReachabilityNew.union(rewrittenRule);
1936 if( makeChangeSet ) {
1937 ChangeTupleSet callerChangeSet = new ChangeTupleSet().makeCanonical();
1939 // each possibility for the final reachability should have a set of
1940 // caller sources mapped to it, use to create the change set
1941 Iterator<TokenTupleSet> callerReachabilityItr = callerReachabilityNew.iterator();
1942 while( callerReachabilityItr.hasNext() ) {
1943 TokenTupleSet ttsRewrittenFinal = callerReachabilityItr.next();
1944 HashSet<TokenTupleSet> sourceSets = rewritten2source.get(ttsRewrittenFinal);
1945 assert sourceSets != null;
1947 Iterator<TokenTupleSet> sourceSetsItr = sourceSets.iterator();
1948 while( sourceSetsItr.hasNext() ) {
1949 TokenTupleSet ttsSource = sourceSetsItr.next();
1952 callerChangeSet.union(new ChangeTuple(ttsSource, ttsRewrittenFinal) );
1956 assert edgePlannedChanges != null;
1957 edgePlannedChanges.put(edge, callerChangeSet);
1961 edge.setBetaNew(edge.getBetaNew().union(callerReachabilityNew) );
1963 hrn.setAlphaNew(hrn.getAlphaNew().union(callerReachabilityNew) );
1969 private HashSet<HeapRegionNode>
1970 getHRNSetThatPossiblyMapToCalleeHRN(OwnershipGraph ogCallee,
1971 HeapRegionNode hrnCallee,
1972 Hashtable<Integer, HashSet<HeapRegionNode> > paramIndex2reachableCallerNodes
1975 HashSet<HeapRegionNode> possibleCallerHRNs = new HashSet<HeapRegionNode>();
1977 Set<Integer> paramIndicesCallee = ogCallee.id2paramIndexSet.get( hrnCallee.getID() );
1979 if( paramIndicesCallee == null ) {
1980 // this is a node allocated in the callee then and it has
1981 // exactly one shadow node in the caller to map to
1982 AllocationSite as = hrnCallee.getAllocationSite();
1985 int age = as.getAgeCategory(hrnCallee.getID() );
1986 assert age != AllocationSite.AGE_notInThisSite;
1989 if( age == AllocationSite.AGE_summary ) {
1990 idCaller = as.getSummaryShadow();
1991 } else if( age == AllocationSite.AGE_oldest ) {
1992 idCaller = as.getOldestShadow();
1994 assert age == AllocationSite.AGE_in_I;
1996 Integer I = as.getAge(hrnCallee.getID() );
1999 idCaller = as.getIthOldestShadow(I);
2002 assert id2hrn.containsKey(idCaller);
2003 HeapRegionNode hrnCaller = id2hrn.get(idCaller);
2004 possibleCallerHRNs.add(hrnCaller);
2007 // this is a node that was created to represent a parameter
2008 // so it maps to a whole mess of heap regions
2009 Iterator<Integer> itrIndex = paramIndicesCallee.iterator();
2010 while( itrIndex.hasNext() ) {
2011 Integer paramIndexCallee = itrIndex.next();
2012 assert paramIndex2reachableCallerNodes.containsKey(paramIndexCallee);
2013 possibleCallerHRNs.addAll( paramIndex2reachableCallerNodes.get(paramIndexCallee) );
2017 return possibleCallerHRNs;
2022 ////////////////////////////////////////////////////
2024 // This global sweep is an optional step to prune
2025 // reachability sets that are not internally
2026 // consistent with the global graph. It should be
2027 // invoked after strong updates or method calls.
2029 ////////////////////////////////////////////////////
2030 protected void globalSweep() {
2032 // a work set for performing the sweep
2033 Hashtable<HeapRegionNode, HashSet<TokenTupleSet> > workSet =
2034 new Hashtable<HeapRegionNode, HashSet<TokenTupleSet> >();
2036 // first initialize every alphaNew for a flagged region
2037 // (or parameter region) to a set with just that token
2038 Set hrns = id2hrn.entrySet();
2039 Iterator itrHrns = hrns.iterator();
2040 while( itrHrns.hasNext() ) {
2041 Map.Entry me = (Map.Entry)itrHrns.next();
2042 Integer token = (Integer) me.getKey();
2043 HeapRegionNode hrn = (HeapRegionNode) me.getValue();
2045 // assert that this node and incoming edges have clean alphaNew
2046 // and betaNew sets, respectively
2047 ReachabilitySet rsEmpty = new ReachabilitySet().makeCanonical();
2048 assert rsEmpty.equals( hrn.getAlphaNew() );
2050 Iterator<ReferenceEdge> itrRes = hrn.iteratorToReferencers();
2051 while( itrRes.hasNext() ) {
2052 ReferenceEdge edge = itrRes.next();
2053 assert rsEmpty.equals( edge.getBetaNew() );
2056 TokenTuple tt = new TokenTuple( token, !hrn.isSingleObject(), TokenTuple.ARITY_ONE ).makeCanonical();
2057 TokenTuple ttPlus = new TokenTuple( token, !hrn.isSingleObject(), TokenTuple.ARITY_ONEORMORE ).makeCanonical();
2058 TokenTuple ttStar = new TokenTuple( token, !hrn.isSingleObject(), TokenTuple.ARITY_ZEROORMORE ).makeCanonical();
2060 TokenTupleSet tts = new TokenTupleSet( tt ).makeCanonical();
2061 TokenTupleSet ttsPlus = new TokenTupleSet( ttPlus ).makeCanonical();
2062 TokenTupleSet ttsStar = new TokenTupleSet( ttStar ).makeCanonical();
2063 TokenTupleSet ttsEmpty = new TokenTupleSet( ).makeCanonical();
2065 if( hrn.isFlagged() || hrn.isParameter() ) {
2066 HashSet<TokenTupleSet> subWorkSet = new HashSet<TokenTupleSet>();
2067 subWorkSet.add( tts );
2068 subWorkSet.add( ttsPlus );
2069 subWorkSet.add( ttsStar );
2070 workSet.put( hrn, subWorkSet );
2072 hrn.setAlphaNew( new ReachabilitySet( tts ).makeCanonical() );
2074 hrn.setAlphaNew( new ReachabilitySet( ttsEmpty ).makeCanonical() );
2078 // then propagate tokens forward one step at a time
2079 while( !workSet.isEmpty() ) {
2080 HeapRegionNode hrn = workSet.keySet().iterator().next();
2082 HashSet<TokenTupleSet> subWorkSet = workSet.get( hrn );
2083 assert subWorkSet != null;
2085 if( subWorkSet.isEmpty() ) {
2086 // we're currently done with sub work at this heap region, although
2087 // more work may get queued up later, but remove it for now and continue
2088 workSet.remove( hrn );
2092 TokenTupleSet tts = subWorkSet.iterator().next();
2093 subWorkSet.remove( tts );
2095 // try to push this TokenTupleSet over all outgoing edges
2096 Iterator<ReferenceEdge> itrRes = hrn.iteratorToReferencees();
2097 while( itrRes.hasNext() ) {
2098 ReferenceEdge edge = itrRes.next();
2100 if( edge.getBeta().containsSuperSet( tts ) ) {
2101 HeapRegionNode dst = edge.getDst();
2103 // make a set of possible contributions this token
2104 // might have on the alpha set here
2105 HashSet<TokenTupleSet> ttsNewSet = new HashSet<TokenTupleSet>();
2107 Iterator<TokenTupleSet> itrDstAlphaNew = dst.getAlphaNew().iterator();
2108 while( itrDstAlphaNew.hasNext() ) {
2109 TokenTupleSet ttsDstAlphaNew = itrDstAlphaNew.next();
2110 ttsNewSet.add( tts.unionUpArity( ttsDstAlphaNew ) );
2113 // only add this to the dst alpha new if it is in the beta of
2114 // the edge we crossed to get here, and then only continue the
2115 // propagation if it isn't already in the dst alpha new
2116 Iterator<TokenTupleSet> itrNewSet = ttsNewSet.iterator();
2117 while( itrNewSet.hasNext() ) {
2118 TokenTupleSet ttsNew = itrNewSet.next();
2120 if( edge.getBeta().containsSuperSet( ttsNew ) &&
2121 !dst.getAlphaNew().contains( ttsNew ) ) {
2123 // okay, this is a valid propagation, and add to the
2124 // work set to further propagate it
2125 dst.setAlphaNew( dst.getAlphaNew().union( ttsNew ) );
2127 HashSet<TokenTupleSet> subWorkSetDst = workSet.get( dst );
2128 if( subWorkSetDst == null ) {
2129 subWorkSetDst = new HashSet<TokenTupleSet>();
2132 subWorkSetDst.add( ttsNew );
2133 workSet.put( dst, subWorkSetDst );
2140 // now prepare work sets to propagate token sets backwards
2141 // from heap regions across all edges
2142 assert workSet.isEmpty();
2143 hrns = id2hrn.entrySet();
2144 itrHrns = hrns.iterator();
2145 while( itrHrns.hasNext() ) {
2146 Map.Entry me = (Map.Entry)itrHrns.next();
2147 HeapRegionNode hrn = (HeapRegionNode) me.getValue();
2149 HashSet<TokenTupleSet> subWorkSet = new HashSet<TokenTupleSet>();
2151 Iterator<TokenTupleSet> itrAlphaNewSets = hrn.getAlphaNew().iterator();
2152 while( itrAlphaNewSets.hasNext() ) {
2153 TokenTupleSet tts = itrAlphaNewSets.next();
2154 subWorkSet.add( tts );
2157 workSet.put( hrn, subWorkSet );
2160 // propagate token sets backwards across edges one step at a time
2161 while( !workSet.isEmpty() ) {
2162 HeapRegionNode hrn = workSet.keySet().iterator().next();
2164 HashSet<TokenTupleSet> subWorkSet = workSet.get( hrn );
2165 assert subWorkSet != null;
2167 if( subWorkSet.isEmpty() ) {
2168 // we're currently done with sub work at this heap region, although
2169 // more work may get queued up later, but remove it for now and continue
2170 workSet.remove( hrn );
2174 TokenTupleSet tts = subWorkSet.iterator().next();
2175 subWorkSet.remove( tts );
2177 // try to push this TokenTupleSet back up incoming edges
2178 Iterator<ReferenceEdge> itrRes = hrn.iteratorToReferencers();
2179 while( itrRes.hasNext() ) {
2180 ReferenceEdge edge = itrRes.next();
2181 if( edge.getBeta().containsWithZeroes( tts ) &&
2182 !edge.getBetaNew().contains( tts ) ) {
2183 // okay, this is a valid propagation, and add to the
2184 // work set to further propagate it
2185 edge.setBetaNew( edge.getBetaNew().union( tts ) );
2187 OwnershipNode src = edge.getSrc();
2188 if( src instanceof HeapRegionNode ) {
2190 HashSet<TokenTupleSet> subWorkSetSrc = workSet.get( (HeapRegionNode) src );
2191 if( subWorkSetSrc == null ) {
2192 subWorkSetSrc = new HashSet<TokenTupleSet>();
2195 subWorkSetSrc.add( tts );
2196 workSet.put( (HeapRegionNode) src, subWorkSetSrc );
2202 // apply alphaNew and betaNew to all nodes and edges
2203 HashSet<ReferenceEdge> res = new HashSet<ReferenceEdge>();
2205 Iterator<HeapRegionNode> nodeItr = id2hrn.values().iterator();
2206 while( nodeItr.hasNext() ) {
2207 HeapRegionNode hrn = nodeItr.next();
2208 hrn.applyAlphaNew();
2209 Iterator<ReferenceEdge> itrRes = hrn.iteratorToReferencers();
2210 while( itrRes.hasNext() ) {
2211 res.add( itrRes.next() );
2215 Iterator<ReferenceEdge> edgeItr = res.iterator();
2216 while( edgeItr.hasNext() ) {
2217 edgeItr.next().applyBetaNew();
2223 ////////////////////////////////////////////////////
2224 // in merge() and equals() methods the suffix A
2225 // represents the passed in graph and the suffix
2226 // B refers to the graph in this object
2227 // Merging means to take the incoming graph A and
2228 // merge it into B, so after the operation graph B
2229 // is the final result.
2230 ////////////////////////////////////////////////////
2231 public void merge(OwnershipGraph og) {
2237 mergeOwnershipNodes(og);
2238 mergeReferenceEdges(og);
2239 mergeId2paramIndex(og);
2240 mergeAllocationSites(og);
2244 protected void mergeOwnershipNodes(OwnershipGraph og) {
2245 Set sA = og.id2hrn.entrySet();
2246 Iterator iA = sA.iterator();
2247 while( iA.hasNext() ) {
2248 Map.Entry meA = (Map.Entry)iA.next();
2249 Integer idA = (Integer) meA.getKey();
2250 HeapRegionNode hrnA = (HeapRegionNode) meA.getValue();
2252 // if this graph doesn't have a node the
2253 // incoming graph has, allocate it
2254 if( !id2hrn.containsKey(idA) ) {
2255 HeapRegionNode hrnB = hrnA.copy();
2256 id2hrn.put(idA, hrnB);
2259 // otherwise this is a node present in both graphs
2260 // so make the new reachability set a union of the
2261 // nodes' reachability sets
2262 HeapRegionNode hrnB = id2hrn.get(idA);
2263 hrnB.setAlpha(hrnB.getAlpha().union(hrnA.getAlpha() ) );
2267 // now add any label nodes that are in graph B but
2269 sA = og.td2ln.entrySet();
2271 while( iA.hasNext() ) {
2272 Map.Entry meA = (Map.Entry)iA.next();
2273 TempDescriptor tdA = (TempDescriptor) meA.getKey();
2274 LabelNode lnA = (LabelNode) meA.getValue();
2276 // if the label doesn't exist in B, allocate and add it
2277 LabelNode lnB = getLabelNodeFromTemp(tdA);
2281 protected void mergeReferenceEdges(OwnershipGraph og) {
2284 Set sA = og.id2hrn.entrySet();
2285 Iterator iA = sA.iterator();
2286 while( iA.hasNext() ) {
2287 Map.Entry meA = (Map.Entry)iA.next();
2288 Integer idA = (Integer) meA.getKey();
2289 HeapRegionNode hrnA = (HeapRegionNode) meA.getValue();
2291 Iterator<ReferenceEdge> heapRegionsItrA = hrnA.iteratorToReferencees();
2292 while( heapRegionsItrA.hasNext() ) {
2293 ReferenceEdge edgeA = heapRegionsItrA.next();
2294 HeapRegionNode hrnChildA = edgeA.getDst();
2295 Integer idChildA = hrnChildA.getID();
2297 // at this point we know an edge in graph A exists
2298 // idA -> idChildA, does this exist in B?
2299 assert id2hrn.containsKey(idA);
2300 HeapRegionNode hrnB = id2hrn.get(idA);
2301 ReferenceEdge edgeToMerge = null;
2303 Iterator<ReferenceEdge> heapRegionsItrB = hrnB.iteratorToReferencees();
2304 while( heapRegionsItrB.hasNext() &&
2305 edgeToMerge == null ) {
2307 ReferenceEdge edgeB = heapRegionsItrB.next();
2308 HeapRegionNode hrnChildB = edgeB.getDst();
2309 Integer idChildB = hrnChildB.getID();
2311 // don't use the ReferenceEdge.equals() here because
2312 // we're talking about existence between graphs
2313 if( idChildB.equals(idChildA) &&
2314 edgeB.getFieldDesc() == edgeA.getFieldDesc() ) {
2315 edgeToMerge = edgeB;
2319 // if the edge from A was not found in B,
2321 if( edgeToMerge == null ) {
2322 assert id2hrn.containsKey(idChildA);
2323 HeapRegionNode hrnChildB = id2hrn.get(idChildA);
2324 edgeToMerge = edgeA.copy();
2325 edgeToMerge.setSrc(hrnB);
2326 edgeToMerge.setDst(hrnChildB);
2327 addReferenceEdge(hrnB, hrnChildB, edgeToMerge);
2329 // otherwise, the edge already existed in both graphs
2330 // so merge their reachability sets
2332 // just replace this beta set with the union
2333 assert edgeToMerge != null;
2334 edgeToMerge.setBeta(
2335 edgeToMerge.getBeta().union(edgeA.getBeta() )
2337 if( !edgeA.isInitialParamReflexive() ) {
2338 edgeToMerge.setIsInitialParamReflexive(false);
2344 // and then again with label nodes
2345 sA = og.td2ln.entrySet();
2347 while( iA.hasNext() ) {
2348 Map.Entry meA = (Map.Entry)iA.next();
2349 TempDescriptor tdA = (TempDescriptor) meA.getKey();
2350 LabelNode lnA = (LabelNode) meA.getValue();
2352 Iterator<ReferenceEdge> heapRegionsItrA = lnA.iteratorToReferencees();
2353 while( heapRegionsItrA.hasNext() ) {
2354 ReferenceEdge edgeA = heapRegionsItrA.next();
2355 HeapRegionNode hrnChildA = edgeA.getDst();
2356 Integer idChildA = hrnChildA.getID();
2358 // at this point we know an edge in graph A exists
2359 // tdA -> idChildA, does this exist in B?
2360 assert td2ln.containsKey(tdA);
2361 LabelNode lnB = td2ln.get(tdA);
2362 ReferenceEdge edgeToMerge = null;
2364 // labels never have edges with a field
2365 //assert edgeA.getFieldDesc() == null;
2367 Iterator<ReferenceEdge> heapRegionsItrB = lnB.iteratorToReferencees();
2368 while( heapRegionsItrB.hasNext() &&
2369 edgeToMerge == null ) {
2371 ReferenceEdge edgeB = heapRegionsItrB.next();
2372 HeapRegionNode hrnChildB = edgeB.getDst();
2373 Integer idChildB = hrnChildB.getID();
2375 // labels never have edges with a field
2376 //assert edgeB.getFieldDesc() == null;
2378 // don't use the ReferenceEdge.equals() here because
2379 // we're talking about existence between graphs
2380 if( idChildB.equals(idChildA) &&
2381 edgeB.getFieldDesc() == edgeA.getFieldDesc() ) {
2382 edgeToMerge = edgeB;
2386 // if the edge from A was not found in B,
2388 if( edgeToMerge == null ) {
2389 assert id2hrn.containsKey(idChildA);
2390 HeapRegionNode hrnChildB = id2hrn.get(idChildA);
2391 edgeToMerge = edgeA.copy();
2392 edgeToMerge.setSrc(lnB);
2393 edgeToMerge.setDst(hrnChildB);
2394 addReferenceEdge(lnB, hrnChildB, edgeToMerge);
2396 // otherwise, the edge already existed in both graphs
2397 // so merge their reachability sets
2399 // just replace this beta set with the union
2400 edgeToMerge.setBeta(
2401 edgeToMerge.getBeta().union(edgeA.getBeta() )
2403 if( !edgeA.isInitialParamReflexive() ) {
2404 edgeToMerge.setIsInitialParamReflexive(false);
2411 // you should only merge ownership graphs that have the
2412 // same number of parameters, or if one or both parameter
2413 // index tables are empty
2414 protected void mergeId2paramIndex(OwnershipGraph og) {
2415 if( id2paramIndexSet.size() == 0 ) {
2416 id2paramIndexSet = og.id2paramIndexSet;
2417 paramIndex2id = og.paramIndex2id;
2418 paramIndex2tdQ = og.paramIndex2tdQ;
2422 if( og.id2paramIndexSet.size() == 0 ) {
2426 assert id2paramIndexSet.size() == og.id2paramIndexSet.size();
2429 protected void mergeAllocationSites(OwnershipGraph og) {
2430 allocationSites.addAll(og.allocationSites);
2435 // it is necessary in the equals() member functions
2436 // to "check both ways" when comparing the data
2437 // structures of two graphs. For instance, if all
2438 // edges between heap region nodes in graph A are
2439 // present and equal in graph B it is not sufficient
2440 // to say the graphs are equal. Consider that there
2441 // may be edges in graph B that are not in graph A.
2442 // the only way to know that all edges in both graphs
2443 // are equally present is to iterate over both data
2444 // structures and compare against the other graph.
2445 public boolean equals(OwnershipGraph og) {
2451 if( !areHeapRegionNodesEqual(og) ) {
2455 if( !areLabelNodesEqual(og) ) {
2459 if( !areReferenceEdgesEqual(og) ) {
2463 if( !areId2paramIndexEqual(og) ) {
2467 // if everything is equal up to this point,
2468 // assert that allocationSites is also equal--
2469 // this data is redundant and kept for efficiency
2470 assert allocationSites.equals(og.allocationSites);
2475 protected boolean areHeapRegionNodesEqual(OwnershipGraph og) {
2477 if( !areallHRNinAalsoinBandequal(this, og) ) {
2481 if( !areallHRNinAalsoinBandequal(og, this) ) {
2488 static protected boolean areallHRNinAalsoinBandequal(OwnershipGraph ogA,
2489 OwnershipGraph ogB) {
2490 Set sA = ogA.id2hrn.entrySet();
2491 Iterator iA = sA.iterator();
2492 while( iA.hasNext() ) {
2493 Map.Entry meA = (Map.Entry)iA.next();
2494 Integer idA = (Integer) meA.getKey();
2495 HeapRegionNode hrnA = (HeapRegionNode) meA.getValue();
2497 if( !ogB.id2hrn.containsKey(idA) ) {
2501 HeapRegionNode hrnB = ogB.id2hrn.get(idA);
2502 if( !hrnA.equalsIncludingAlpha(hrnB) ) {
2511 protected boolean areLabelNodesEqual(OwnershipGraph og) {
2513 if( !areallLNinAalsoinBandequal(this, og) ) {
2517 if( !areallLNinAalsoinBandequal(og, this) ) {
2524 static protected boolean areallLNinAalsoinBandequal(OwnershipGraph ogA,
2525 OwnershipGraph ogB) {
2526 Set sA = ogA.td2ln.entrySet();
2527 Iterator iA = sA.iterator();
2528 while( iA.hasNext() ) {
2529 Map.Entry meA = (Map.Entry)iA.next();
2530 TempDescriptor tdA = (TempDescriptor) meA.getKey();
2532 if( !ogB.td2ln.containsKey(tdA) ) {
2541 protected boolean areReferenceEdgesEqual(OwnershipGraph og) {
2542 if( !areallREinAandBequal(this, og) ) {
2549 static protected boolean areallREinAandBequal(OwnershipGraph ogA,
2550 OwnershipGraph ogB) {
2552 // check all the heap region->heap region edges
2553 Set sA = ogA.id2hrn.entrySet();
2554 Iterator iA = sA.iterator();
2555 while( iA.hasNext() ) {
2556 Map.Entry meA = (Map.Entry)iA.next();
2557 Integer idA = (Integer) meA.getKey();
2558 HeapRegionNode hrnA = (HeapRegionNode) meA.getValue();
2560 // we should have already checked that the same
2561 // heap regions exist in both graphs
2562 assert ogB.id2hrn.containsKey(idA);
2564 if( !areallREfromAequaltoB(ogA, hrnA, ogB) ) {
2568 // then check every edge in B for presence in A, starting
2569 // from the same parent HeapRegionNode
2570 HeapRegionNode hrnB = ogB.id2hrn.get(idA);
2572 if( !areallREfromAequaltoB(ogB, hrnB, ogA) ) {
2577 // then check all the label->heap region edges
2578 sA = ogA.td2ln.entrySet();
2580 while( iA.hasNext() ) {
2581 Map.Entry meA = (Map.Entry)iA.next();
2582 TempDescriptor tdA = (TempDescriptor) meA.getKey();
2583 LabelNode lnA = (LabelNode) meA.getValue();
2585 // we should have already checked that the same
2586 // label nodes exist in both graphs
2587 assert ogB.td2ln.containsKey(tdA);
2589 if( !areallREfromAequaltoB(ogA, lnA, ogB) ) {
2593 // then check every edge in B for presence in A, starting
2594 // from the same parent LabelNode
2595 LabelNode lnB = ogB.td2ln.get(tdA);
2597 if( !areallREfromAequaltoB(ogB, lnB, ogA) ) {
2606 static protected boolean areallREfromAequaltoB(OwnershipGraph ogA,
2608 OwnershipGraph ogB) {
2610 Iterator<ReferenceEdge> itrA = onA.iteratorToReferencees();
2611 while( itrA.hasNext() ) {
2612 ReferenceEdge edgeA = itrA.next();
2613 HeapRegionNode hrnChildA = edgeA.getDst();
2614 Integer idChildA = hrnChildA.getID();
2616 assert ogB.id2hrn.containsKey(idChildA);
2618 // at this point we know an edge in graph A exists
2619 // onA -> idChildA, does this exact edge exist in B?
2620 boolean edgeFound = false;
2622 OwnershipNode onB = null;
2623 if( onA instanceof HeapRegionNode ) {
2624 HeapRegionNode hrnA = (HeapRegionNode) onA;
2625 onB = ogB.id2hrn.get(hrnA.getID() );
2627 LabelNode lnA = (LabelNode) onA;
2628 onB = ogB.td2ln.get(lnA.getTempDescriptor() );
2631 Iterator<ReferenceEdge> itrB = onB.iteratorToReferencees();
2632 while( itrB.hasNext() ) {
2633 ReferenceEdge edgeB = itrB.next();
2634 HeapRegionNode hrnChildB = edgeB.getDst();
2635 Integer idChildB = hrnChildB.getID();
2637 if( idChildA.equals(idChildB) &&
2638 edgeA.getFieldDesc() == edgeB.getFieldDesc() ) {
2640 // there is an edge in the right place with the right field,
2641 // but do they have the same attributes?
2642 if( edgeA.getBeta().equals(edgeB.getBeta() ) ) {
2660 protected boolean areId2paramIndexEqual(OwnershipGraph og) {
2661 return id2paramIndexSet.size() == og.id2paramIndexSet.size();
2664 public boolean hasPotentialAlias(Integer paramIndex1, Integer paramIndex2) {
2666 // get parameter's heap region
2667 assert paramIndex2id.containsKey(paramIndex1);
2668 Integer idParam1 = paramIndex2id.get(paramIndex1);
2670 assert id2hrn.containsKey(idParam1);
2671 HeapRegionNode hrnParam1 = id2hrn.get(idParam1);
2672 assert hrnParam1 != null;
2674 // get tokens for this parameter
2675 TokenTuple p1 = new TokenTuple(hrnParam1.getID(),
2677 TokenTuple.ARITY_ONE).makeCanonical();
2679 TokenTuple pPlus1 = new TokenTuple(hrnParam1.getID(),
2681 TokenTuple.ARITY_ONEORMORE).makeCanonical();
2683 TokenTuple pStar1 = new TokenTuple(hrnParam1.getID(),
2685 TokenTuple.ARITY_ZEROORMORE).makeCanonical();
2688 // get tokens for the other parameter
2689 assert paramIndex2id.containsKey(paramIndex2);
2690 Integer idParam2 = paramIndex2id.get(paramIndex2);
2692 assert id2hrn.containsKey(idParam2);
2693 HeapRegionNode hrnParam2 = id2hrn.get(idParam2);
2694 assert hrnParam2 != null;
2696 TokenTuple p2 = new TokenTuple(hrnParam2.getID(),
2698 TokenTuple.ARITY_ONE).makeCanonical();
2700 TokenTuple pPlus2 = new TokenTuple(hrnParam2.getID(),
2702 TokenTuple.ARITY_ONEORMORE).makeCanonical();
2704 TokenTuple pStar2 = new TokenTuple(hrnParam2.getID(),
2706 TokenTuple.ARITY_ZEROORMORE).makeCanonical();
2709 // get special label p_q for first parameter
2710 TempDescriptor tdParamQ1 = paramIndex2tdQ.get(paramIndex1);
2711 assert tdParamQ1 != null;
2712 LabelNode lnParamQ1 = td2ln.get(tdParamQ1);
2713 assert lnParamQ1 != null;
2715 // then get the edge from label q to parameter's hrn
2716 ReferenceEdge edgeSpecialQ1 = lnParamQ1.getReferenceTo(hrnParam1, null);
2717 assert edgeSpecialQ1 != null;
2719 // if the beta of this edge has tokens from both parameters in one
2720 // token tuple set, then there is a potential alias between them
2721 ReachabilitySet beta1 = edgeSpecialQ1.getBeta();
2722 assert beta1 != null;
2724 if( beta1.containsTupleSetWithBoth(p1, p2) ) {
2727 if( beta1.containsTupleSetWithBoth(pPlus1, p2) ) {
2730 if( beta1.containsTupleSetWithBoth(pStar1, p2) ) {
2733 if( beta1.containsTupleSetWithBoth(p1, pPlus2) ) {
2736 if( beta1.containsTupleSetWithBoth(pPlus1, pPlus2) ) {
2739 if( beta1.containsTupleSetWithBoth(pStar1, pPlus2) ) {
2742 if( beta1.containsTupleSetWithBoth(p1, pStar2) ) {
2745 if( beta1.containsTupleSetWithBoth(pPlus1, pStar2) ) {
2748 if( beta1.containsTupleSetWithBoth(pStar1, pStar2) ) {
2756 public boolean hasPotentialAlias(Integer paramIndex, AllocationSite as) {
2758 // get parameter's heap region
2759 assert paramIndex2id.containsKey(paramIndex);
2760 Integer idParam = paramIndex2id.get(paramIndex);
2762 assert id2hrn.containsKey(idParam);
2763 HeapRegionNode hrnParam = id2hrn.get(idParam);
2764 assert hrnParam != null;
2766 // get tokens for this parameter
2767 TokenTuple p = new TokenTuple(hrnParam.getID(),
2769 TokenTuple.ARITY_ONE).makeCanonical();
2771 TokenTuple pPlus = new TokenTuple(hrnParam.getID(),
2773 TokenTuple.ARITY_ONEORMORE).makeCanonical();
2775 TokenTuple pStar = new TokenTuple(hrnParam.getID(),
2777 TokenTuple.ARITY_ZEROORMORE).makeCanonical();
2779 // get special label p_q
2780 TempDescriptor tdParamQ = paramIndex2tdQ.get(paramIndex);
2781 assert tdParamQ != null;
2782 LabelNode lnParamQ = td2ln.get(tdParamQ);
2783 assert lnParamQ != null;
2785 // then get the edge from label q to parameter's hrn
2786 ReferenceEdge edgeSpecialQ = lnParamQ.getReferenceTo(hrnParam, null);
2787 assert edgeSpecialQ != null;
2789 // look through this beta set for potential aliases
2790 ReachabilitySet beta = edgeSpecialQ.getBeta();
2791 assert beta != null;
2794 // get tokens for summary node
2795 TokenTuple gs = new TokenTuple(as.getSummary(),
2797 TokenTuple.ARITY_ONE).makeCanonical();
2799 TokenTuple gsPlus = new TokenTuple(as.getSummary(),
2801 TokenTuple.ARITY_ONEORMORE).makeCanonical();
2803 TokenTuple gsStar = new TokenTuple(as.getSummary(),
2805 TokenTuple.ARITY_ZEROORMORE).makeCanonical();
2808 if( beta.containsTupleSetWithBoth(p, gs) ) {
2811 if( beta.containsTupleSetWithBoth(pPlus, gs) ) {
2814 if( beta.containsTupleSetWithBoth(pStar, gs) ) {
2817 if( beta.containsTupleSetWithBoth(p, gsPlus) ) {
2820 if( beta.containsTupleSetWithBoth(pPlus, gsPlus) ) {
2823 if( beta.containsTupleSetWithBoth(pStar, gsPlus) ) {
2826 if( beta.containsTupleSetWithBoth(p, gsStar) ) {
2829 if( beta.containsTupleSetWithBoth(pPlus, gsStar) ) {
2832 if( beta.containsTupleSetWithBoth(pStar, gsStar) ) {
2836 // check for other nodes
2837 for( int i = 0; i < as.getAllocationDepth(); ++i ) {
2839 // the other nodes of an allocation site are single, no plus
2840 TokenTuple gi = new TokenTuple(as.getIthOldest(i),
2842 TokenTuple.ARITY_ONE).makeCanonical();
2844 TokenTuple giStar = new TokenTuple(as.getIthOldest(i),
2846 TokenTuple.ARITY_ZEROORMORE).makeCanonical();
2848 if( beta.containsTupleSetWithBoth(p, gi) ) {
2851 if( beta.containsTupleSetWithBoth(pPlus, gi) ) {
2854 if( beta.containsTupleSetWithBoth(pStar, gi) ) {
2857 if( beta.containsTupleSetWithBoth(p, giStar) ) {
2860 if( beta.containsTupleSetWithBoth(pPlus, giStar) ) {
2863 if( beta.containsTupleSetWithBoth(pStar, giStar) ) {
2872 public boolean hasPotentialAlias(AllocationSite as1, AllocationSite as2) {
2874 // get tokens for summary nodes
2875 TokenTuple gs1 = new TokenTuple(as1.getSummary(),
2877 TokenTuple.ARITY_ONE).makeCanonical();
2879 TokenTuple gsPlus1 = new TokenTuple(as1.getSummary(),
2881 TokenTuple.ARITY_ONEORMORE).makeCanonical();
2883 TokenTuple gsStar1 = new TokenTuple(as1.getSummary(),
2885 TokenTuple.ARITY_ZEROORMORE).makeCanonical();
2887 // get summary node's alpha
2888 Integer idSum1 = as1.getSummary();
2889 assert id2hrn.containsKey(idSum1);
2890 HeapRegionNode hrnSum1 = id2hrn.get(idSum1);
2891 assert hrnSum1 != null;
2892 ReachabilitySet alphaSum1 = hrnSum1.getAlpha();
2893 assert alphaSum1 != null;
2896 // and for the other one
2897 TokenTuple gs2 = new TokenTuple(as2.getSummary(),
2899 TokenTuple.ARITY_ONE).makeCanonical();
2901 TokenTuple gsPlus2 = new TokenTuple(as2.getSummary(),
2903 TokenTuple.ARITY_ONEORMORE).makeCanonical();
2905 TokenTuple gsStar2 = new TokenTuple(as2.getSummary(),
2907 TokenTuple.ARITY_ZEROORMORE).makeCanonical();
2909 // get summary node's alpha
2910 Integer idSum2 = as2.getSummary();
2911 assert id2hrn.containsKey(idSum2);
2912 HeapRegionNode hrnSum2 = id2hrn.get(idSum2);
2913 assert hrnSum2 != null;
2914 ReachabilitySet alphaSum2 = hrnSum2.getAlpha();
2915 assert alphaSum2 != null;
2917 // does either one report reachability from the other tokens?
2918 if( alphaSum1.containsTuple(gsPlus2) ) {
2921 if( alphaSum1.containsTuple(gsStar2) ) {
2924 if( alphaSum2.containsTuple(gsPlus1) ) {
2927 if( alphaSum2.containsTuple(gsStar1) ) {
2931 // only check ONE token if they are different sites
2933 if( alphaSum1.containsTuple(gs2) ) {
2936 if( alphaSum2.containsTuple(gs1) ) {
2942 // check sum2 against alloc1 nodes
2943 for( int i = 0; i < as1.getAllocationDepth(); ++i ) {
2944 Integer idI1 = as1.getIthOldest(i);
2945 assert id2hrn.containsKey(idI1);
2946 HeapRegionNode hrnI1 = id2hrn.get(idI1);
2947 assert hrnI1 != null;
2948 ReachabilitySet alphaI1 = hrnI1.getAlpha();
2949 assert alphaI1 != null;
2951 // the other nodes of an allocation site are single, no stars
2952 TokenTuple gi1 = new TokenTuple(as1.getIthOldest(i),
2954 TokenTuple.ARITY_ONE).makeCanonical();
2956 TokenTuple giStar1 = new TokenTuple(as1.getIthOldest(i),
2958 TokenTuple.ARITY_ZEROORMORE).makeCanonical();
2960 if( alphaSum2.containsTuple(gi1) ) {
2963 if( alphaSum2.containsTuple(giStar1) ) {
2966 if( alphaI1.containsTuple(gs2) ) {
2969 if( alphaI1.containsTuple(gsPlus2) ) {
2972 if( alphaI1.containsTuple(gsStar2) ) {
2977 // check sum1 against alloc2 nodes
2978 for( int i = 0; i < as2.getAllocationDepth(); ++i ) {
2979 Integer idI2 = as2.getIthOldest(i);
2980 assert id2hrn.containsKey(idI2);
2981 HeapRegionNode hrnI2 = id2hrn.get(idI2);
2982 assert hrnI2 != null;
2983 ReachabilitySet alphaI2 = hrnI2.getAlpha();
2984 assert alphaI2 != null;
2986 TokenTuple gi2 = new TokenTuple(as2.getIthOldest(i),
2988 TokenTuple.ARITY_ONE).makeCanonical();
2990 TokenTuple giStar2 = new TokenTuple(as2.getIthOldest(i),
2992 TokenTuple.ARITY_ZEROORMORE).makeCanonical();
2994 if( alphaSum1.containsTuple(gi2) ) {
2997 if( alphaSum1.containsTuple(giStar2) ) {
3000 if( alphaI2.containsTuple(gs1) ) {
3003 if( alphaI2.containsTuple(gsPlus1) ) {
3006 if( alphaI2.containsTuple(gsStar1) ) {
3010 // while we're at it, do an inner loop for alloc2 vs alloc1 nodes
3011 for( int j = 0; j < as1.getAllocationDepth(); ++j ) {
3012 Integer idI1 = as1.getIthOldest(j);
3014 // if these are the same site, don't look for the same token, no alias.
3015 // different tokens of the same site could alias together though
3016 if( idI1 == idI2 ) {
3020 HeapRegionNode hrnI1 = id2hrn.get(idI1);
3021 ReachabilitySet alphaI1 = hrnI1.getAlpha();
3022 TokenTuple gi1 = new TokenTuple(as1.getIthOldest(j),
3024 TokenTuple.ARITY_ONE).makeCanonical();
3026 TokenTuple giStar1 = new TokenTuple(as1.getIthOldest(j),
3028 TokenTuple.ARITY_ZEROORMORE).makeCanonical();
3030 if( alphaI2.containsTuple(gi1) ) {
3033 if( alphaI2.containsTuple(giStar1) ) {
3036 if( alphaI1.containsTuple(gi2) ) {
3039 if( alphaI1.containsTuple(giStar2) ) {
3049 // for writing ownership graphs to dot files
3050 public void writeGraph(MethodContext mc,
3052 boolean writeLabels,
3053 boolean labelSelect,
3054 boolean pruneGarbage,
3055 boolean writeReferencers,
3056 boolean writeParamMappings
3057 ) throws java.io.IOException {
3069 public void writeGraph(MethodContext mc,
3070 boolean writeLabels,
3071 boolean labelSelect,
3072 boolean pruneGarbage,
3073 boolean writeReferencers,
3074 boolean writeParamMappings
3075 ) throws java.io.IOException {
3077 writeGraph(mc+"COMPLETE",
3086 public void writeGraph(MethodContext mc,
3088 boolean writeLabels,
3089 boolean labelSelect,
3090 boolean pruneGarbage,
3091 boolean writeReferencers,
3092 boolean writeParamMappings
3093 ) throws java.io.IOException {
3095 writeGraph(mc+"COMPLETE"+String.format("%05d", numUpdate),
3104 public void writeGraph(String graphName,
3105 boolean writeLabels,
3106 boolean labelSelect,
3107 boolean pruneGarbage,
3108 boolean writeReferencers,
3109 boolean writeParamMappings
3110 ) throws java.io.IOException {
3112 // remove all non-word characters from the graph name so
3113 // the filename and identifier in dot don't cause errors
3114 graphName = graphName.replaceAll("[\\W]", "");
3116 BufferedWriter bw = new BufferedWriter(new FileWriter(graphName+".dot") );
3117 bw.write("digraph "+graphName+" {\n");
3119 HashSet<HeapRegionNode> visited = new HashSet<HeapRegionNode>();
3121 // then visit every heap region node
3122 Set s = id2hrn.entrySet();
3123 Iterator i = s.iterator();
3124 while( i.hasNext() ) {
3125 Map.Entry me = (Map.Entry)i.next();
3126 HeapRegionNode hrn = (HeapRegionNode) me.getValue();
3127 if( !pruneGarbage ||
3129 hrn.getDescription().startsWith("param")
3132 if( !visited.contains(hrn) ) {
3133 traverseHeapRegionNodes(VISIT_HRN_WRITE_FULL,
3143 bw.write(" graphTitle[label=\""+graphName+"\",shape=box];\n");
3145 if( writeParamMappings ) {
3146 Set df = paramIndex2id.entrySet();
3147 Iterator ih = df.iterator();
3148 while( ih.hasNext() ) {
3149 Map.Entry meh = (Map.Entry)ih.next();
3150 Integer pi = (Integer) meh.getKey();
3151 Integer id = (Integer) meh.getValue();
3152 bw.write(" pindex"+pi+"[label=\""+pi+" to "+id+"\",shape=box];\n");
3156 // then visit every label node, useful for debugging
3158 s = td2ln.entrySet();
3160 while( i.hasNext() ) {
3161 Map.Entry me = (Map.Entry)i.next();
3162 LabelNode ln = (LabelNode) me.getValue();
3165 String labelStr = ln.getTempDescriptorString();
3166 if( labelStr.startsWith("___temp") ||
3167 labelStr.startsWith("___dst") ||
3168 labelStr.startsWith("___srctmp") ||
3169 labelStr.startsWith("___neverused") ) {
3174 //bw.write(" "+ln.toString() + ";\n");
3176 Iterator<ReferenceEdge> heapRegionsItr = ln.iteratorToReferencees();
3177 while( heapRegionsItr.hasNext() ) {
3178 ReferenceEdge edge = heapRegionsItr.next();
3179 HeapRegionNode hrn = edge.getDst();
3181 if( pruneGarbage && !visited.contains(hrn) ) {
3182 traverseHeapRegionNodes(VISIT_HRN_WRITE_FULL,
3190 bw.write(" " + ln.toString() +
3191 " -> " + hrn.toString() +
3192 "[label=\"" + edge.toGraphEdgeString() +
3203 protected void traverseHeapRegionNodes(int mode,
3207 HashSet<HeapRegionNode> visited,
3208 boolean writeReferencers
3209 ) throws java.io.IOException {
3211 if( visited.contains(hrn) ) {
3217 case VISIT_HRN_WRITE_FULL:
3219 String attributes = "[";
3221 if( hrn.isSingleObject() ) {
3222 attributes += "shape=box";
3224 attributes += "shape=Msquare";
3227 if( hrn.isFlagged() ) {
3228 attributes += ",style=filled,fillcolor=lightgrey";
3231 attributes += ",label=\"ID" +
3234 hrn.getDescription() +
3236 hrn.getAlphaString() +
3239 bw.write(" " + hrn.toString() + attributes + ";\n");
3244 // useful for debugging
3245 if( writeReferencers ) {
3246 OwnershipNode onRef = null;
3247 Iterator refItr = hrn.iteratorToReferencers();
3248 while( refItr.hasNext() ) {
3249 onRef = (OwnershipNode) refItr.next();
3252 case VISIT_HRN_WRITE_FULL:
3253 bw.write(" " + hrn.toString() +
3254 " -> " + onRef.toString() +
3255 "[color=lightgray];\n");
3261 Iterator<ReferenceEdge> childRegionsItr = hrn.iteratorToReferencees();
3262 while( childRegionsItr.hasNext() ) {
3263 ReferenceEdge edge = childRegionsItr.next();
3264 HeapRegionNode hrnChild = edge.getDst();
3267 case VISIT_HRN_WRITE_FULL:
3268 bw.write(" " + hrn.toString() +
3269 " -> " + hrnChild.toString() +
3270 "[label=\"" + edge.toGraphEdgeString() +
3275 traverseHeapRegionNodes(mode,