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>();
224 // first propagate change sets everywhere they can go
225 while( !todoNodes.isEmpty() ) {
226 HeapRegionNode n = todoNodes.iterator().next();
227 ChangeTupleSet C = nodePlannedChanges.get(n);
229 Iterator<ReferenceEdge> referItr = n.iteratorToReferencers();
230 while( referItr.hasNext() ) {
231 ReferenceEdge edge = referItr.next();
234 if( !edgePlannedChanges.containsKey(edge) ) {
235 edgePlannedChanges.put(edge, new ChangeTupleSet().makeCanonical() );
238 edgePlannedChanges.put(edge, edgePlannedChanges.get(edge).union(C) );
241 Iterator<ReferenceEdge> refeeItr = n.iteratorToReferencees();
242 while( refeeItr.hasNext() ) {
243 ReferenceEdge edgeF = refeeItr.next();
244 HeapRegionNode m = edgeF.getDst();
246 ChangeTupleSet changesToPass = new ChangeTupleSet().makeCanonical();
248 Iterator<ChangeTuple> itrCprime = C.iterator();
249 while( itrCprime.hasNext() ) {
250 ChangeTuple c = itrCprime.next();
251 if( edgeF.getBeta().contains( c.getSetToMatch() ) ) {
252 changesToPass = changesToPass.union(c);
256 if( !changesToPass.isEmpty() ) {
257 if( !nodePlannedChanges.containsKey(m) ) {
258 nodePlannedChanges.put(m, new ChangeTupleSet().makeCanonical() );
261 ChangeTupleSet currentChanges = nodePlannedChanges.get(m);
263 if( !changesToPass.isSubset(currentChanges) ) {
265 nodePlannedChanges.put(m, currentChanges.union(changesToPass) );
274 // then apply all of the changes for each node at once
275 Iterator itrMap = nodePlannedChanges.entrySet().iterator();
276 while( itrMap.hasNext() ) {
277 Map.Entry me = (Map.Entry) itrMap.next();
278 HeapRegionNode n = (HeapRegionNode) me.getKey();
279 ChangeTupleSet C = (ChangeTupleSet) me.getValue();
281 n.setAlphaNew( n.getAlpha().applyChangeSet( C, false ) );
282 nodesWithNewAlpha.add( n );
285 propagateTokensOverEdges(todoEdges, edgePlannedChanges, edgesWithNewBeta);
289 protected void propagateTokensOverEdges(
290 HashSet<ReferenceEdge> todoEdges,
291 Hashtable<ReferenceEdge, ChangeTupleSet> edgePlannedChanges,
292 HashSet<ReferenceEdge> edgesWithNewBeta) {
294 // first propagate all change tuples everywhere they can go
295 while( !todoEdges.isEmpty() ) {
296 ReferenceEdge edgeE = todoEdges.iterator().next();
297 todoEdges.remove(edgeE);
299 if( !edgePlannedChanges.containsKey(edgeE) ) {
300 edgePlannedChanges.put(edgeE, new ChangeTupleSet().makeCanonical() );
303 ChangeTupleSet C = edgePlannedChanges.get(edgeE);
305 ChangeTupleSet changesToPass = new ChangeTupleSet().makeCanonical();
308 Iterator<ChangeTuple> itrC = C.iterator();
309 while( itrC.hasNext() ) {
310 ChangeTuple c = itrC.next();
311 if( edgeE.getBeta().contains( c.getSetToMatch() ) ) {
312 changesToPass = changesToPass.union(c);
316 OwnershipNode onSrc = edgeE.getSrc();
318 if( !changesToPass.isEmpty() && onSrc instanceof HeapRegionNode ) {
319 HeapRegionNode n = (HeapRegionNode) onSrc;
321 Iterator<ReferenceEdge> referItr = n.iteratorToReferencers();
322 while( referItr.hasNext() ) {
323 ReferenceEdge edgeF = referItr.next();
325 if( !edgePlannedChanges.containsKey(edgeF) ) {
326 edgePlannedChanges.put(edgeF, new ChangeTupleSet().makeCanonical() );
329 ChangeTupleSet currentChanges = edgePlannedChanges.get(edgeF);
331 if( !changesToPass.isSubset(currentChanges) ) {
332 todoEdges.add(edgeF);
333 edgePlannedChanges.put(edgeF, currentChanges.union(changesToPass) );
339 // then apply all of the changes for each edge at once
340 Iterator itrMap = edgePlannedChanges.entrySet().iterator();
341 while( itrMap.hasNext() ) {
342 Map.Entry me = (Map.Entry) itrMap.next();
343 ReferenceEdge e = (ReferenceEdge) me.getKey();
344 ChangeTupleSet C = (ChangeTupleSet) me.getValue();
346 e.setBetaNew( e.getBeta().applyChangeSet( C, true ) );
347 edgesWithNewBeta.add( e );
352 ////////////////////////////////////////////////////
354 // Assignment Operation Methods
356 // These methods are high-level operations for
357 // modeling program assignment statements using
358 // the low-level reference create/remove methods
361 // The destination in an assignment statement is
362 // going to have new references. The method of
363 // determining the references depends on the type
364 // of the FlatNode assignment and the predicates
365 // of the nodes and edges involved.
367 ////////////////////////////////////////////////////
368 public void assignTempXEqualToTempY(TempDescriptor x,
371 LabelNode lnX = getLabelNodeFromTemp(x);
372 LabelNode lnY = getLabelNodeFromTemp(y);
374 clearReferenceEdgesFrom(lnX, null, true);
376 Iterator<ReferenceEdge> itrYhrn = lnY.iteratorToReferencees();
377 while( itrYhrn.hasNext() ) {
378 ReferenceEdge edgeY = itrYhrn.next();
379 HeapRegionNode referencee = edgeY.getDst();
380 ReferenceEdge edgeNew = edgeY.copy();
383 addReferenceEdge(lnX, referencee, edgeNew);
388 public void assignTypedTempXEqualToTempY(TempDescriptor x,
392 LabelNode lnX = getLabelNodeFromTemp(x);
393 LabelNode lnY = getLabelNodeFromTemp(y);
395 clearReferenceEdgesFrom(lnX, null, true);
397 Iterator<ReferenceEdge> itrYhrn = lnY.iteratorToReferencees();
398 while( itrYhrn.hasNext() ) {
399 ReferenceEdge edgeY = itrYhrn.next();
400 HeapRegionNode referencee = edgeY.getDst();
401 ReferenceEdge edgeNew = edgeY.copy();
403 edgeNew.setFieldDesc(f);
405 addReferenceEdge(lnX, referencee, edgeNew);
410 public void assignTempXEqualToTempYFieldF(TempDescriptor x,
413 LabelNode lnX = getLabelNodeFromTemp(x);
414 LabelNode lnY = getLabelNodeFromTemp(y);
416 clearReferenceEdgesFrom(lnX, null, true);
418 Iterator<ReferenceEdge> itrYhrn = lnY.iteratorToReferencees();
419 while( itrYhrn.hasNext() ) {
420 ReferenceEdge edgeY = itrYhrn.next();
421 HeapRegionNode hrnY = edgeY.getDst();
422 ReachabilitySet betaY = edgeY.getBeta();
424 Iterator<ReferenceEdge> itrHrnFhrn = hrnY.iteratorToReferencees();
425 while( itrHrnFhrn.hasNext() ) {
426 ReferenceEdge edgeHrn = itrHrnFhrn.next();
427 HeapRegionNode hrnHrn = edgeHrn.getDst();
428 ReachabilitySet betaHrn = edgeHrn.getBeta();
430 if( edgeHrn.getFieldDesc() == null ||
431 edgeHrn.getFieldDesc() == f ) {
433 ReferenceEdge edgeNew = new ReferenceEdge(lnX,
437 betaY.intersection(betaHrn) );
439 addReferenceEdge(lnX, hrnHrn, edgeNew);
446 public void assignTempXFieldFEqualToTempY(TempDescriptor x,
449 LabelNode lnX = getLabelNodeFromTemp(x);
450 LabelNode lnY = getLabelNodeFromTemp(y);
452 HashSet<HeapRegionNode> nodesWithNewAlpha = new HashSet<HeapRegionNode>();
453 HashSet<ReferenceEdge> edgesWithNewBeta = new HashSet<ReferenceEdge>();
456 // first look for possible strong updates and remove those edges
457 boolean strongUpdate = false;
459 Iterator<ReferenceEdge> itrXhrn = lnX.iteratorToReferencees();
460 while( itrXhrn.hasNext() ) {
461 ReferenceEdge edgeX = itrXhrn.next();
462 HeapRegionNode hrnX = edgeX.getDst();
464 Iterator<ReferenceEdge> itrYhrn = lnY.iteratorToReferencees();
465 while( itrYhrn.hasNext() ) {
466 ReferenceEdge edgeY = itrYhrn.next();
467 HeapRegionNode hrnY = edgeY.getDst();
469 // we can do a strong update here if one of two cases holds
471 hrnX.isSingleObject() &&
472 ( (hrnX.getNumReferencers() == 1) ||
473 ( lnX.getNumReferencees() == 1)
477 clearReferenceEdgesFrom( hrnX, f, false );
482 // then do all token propagation
483 itrXhrn = lnX.iteratorToReferencees();
484 while( itrXhrn.hasNext() ) {
485 ReferenceEdge edgeX = itrXhrn.next();
486 HeapRegionNode hrnX = edgeX.getDst();
487 ReachabilitySet betaX = edgeX.getBeta();
489 ReachabilitySet R = hrnX.getAlpha().intersection(edgeX.getBeta() );
491 Iterator<ReferenceEdge> itrYhrn = lnY.iteratorToReferencees();
492 while( itrYhrn.hasNext() ) {
493 ReferenceEdge edgeY = itrYhrn.next();
494 HeapRegionNode hrnY = edgeY.getDst();
495 ReachabilitySet O = edgeY.getBeta();
498 // propagate tokens over nodes starting from hrnSrc, and it will
499 // take care of propagating back up edges from any touched nodes
500 ChangeTupleSet Cy = O.unionUpArityToChangeSet(R);
501 propagateTokensOverNodes(hrnY, Cy, nodesWithNewAlpha, edgesWithNewBeta);
504 // then propagate back just up the edges from hrn
505 ChangeTupleSet Cx = R.unionUpArityToChangeSet(O);
508 HashSet<ReferenceEdge> todoEdges = new HashSet<ReferenceEdge>();
510 Hashtable<ReferenceEdge, ChangeTupleSet> edgePlannedChanges =
511 new Hashtable<ReferenceEdge, ChangeTupleSet>();
513 Iterator<ReferenceEdge> referItr = hrnX.iteratorToReferencers();
514 while( referItr.hasNext() ) {
515 ReferenceEdge edgeUpstream = referItr.next();
516 todoEdges.add(edgeUpstream);
517 edgePlannedChanges.put(edgeUpstream, Cx);
520 propagateTokensOverEdges(todoEdges,
527 // apply the updates to reachability
528 Iterator<HeapRegionNode> nodeItr = nodesWithNewAlpha.iterator();
529 while( nodeItr.hasNext() ) {
530 nodeItr.next().applyAlphaNew();
533 Iterator<ReferenceEdge> edgeItr = edgesWithNewBeta.iterator();
534 while( edgeItr.hasNext() ) {
535 edgeItr.next().applyBetaNew();
538 // then go back through and add the new edges
539 itrXhrn = lnX.iteratorToReferencees();
540 while( itrXhrn.hasNext() ) {
541 ReferenceEdge edgeX = itrXhrn.next();
542 HeapRegionNode hrnX = edgeX.getDst();
544 Iterator<ReferenceEdge> itrYhrn = lnY.iteratorToReferencees();
545 while( itrYhrn.hasNext() ) {
546 ReferenceEdge edgeY = itrYhrn.next();
547 HeapRegionNode hrnY = edgeY.getDst();
549 // prepare the new reference edge hrnX.f -> hrnY
550 ReferenceEdge edgeNew = new ReferenceEdge(hrnX,
554 edgeY.getBeta().pruneBy( hrnX.getAlpha() )
557 // look to see if an edge with same field exists
558 // and merge with it, otherwise just add the edge
559 ReferenceEdge edgeExisting = hrnX.getReferenceTo( hrnY, f );
561 if( edgeExisting != null ) {
562 edgeExisting.setBeta(
563 edgeExisting.getBeta().union( edgeNew.getBeta() )
565 // a new edge here cannot be reflexive, so existing will
566 // always be also not reflexive anymore
567 edgeExisting.setIsInitialParamReflexive( false );
569 addReferenceEdge( hrnX, hrnY, edgeNew );
574 // if there was a strong update, make sure to improve
575 // reachability with a global sweep
582 public void assignTempEqualToParamAlloc(TempDescriptor td,
584 Integer paramIndex) {
587 LabelNode lnParam = getLabelNodeFromTemp(td);
588 HeapRegionNode hrn = createNewHeapRegionNode(null,
595 "param" + paramIndex);
597 // this is a non-program-accessible label that picks up beta
598 // info to be used for fixing a caller of this method
599 TempDescriptor tdParamQ = new TempDescriptor(td+"specialQ");
600 LabelNode lnParamQ = getLabelNodeFromTemp(tdParamQ);
602 // keep track of heap regions that were created for
603 // parameter labels, the index of the parameter they
604 // are for is important when resolving method calls
605 Integer newID = hrn.getID();
606 assert !id2paramIndexSet.containsKey(newID);
607 Set s = new HashSet<Integer>();
609 id2paramIndexSet.put(newID, s);
610 paramIndex2id.put(paramIndex, newID);
611 paramIndex2tdQ.put(paramIndex, tdParamQ);
613 ReachabilitySet beta = new ReachabilitySet(new TokenTuple(newID,
615 TokenTuple.ARITY_ONE).makeCanonical()
618 // heap regions for parameters are always multiple object (see above)
619 // and have a reference to themselves, because we can't know the
620 // structure of memory that is passed into the method. We're assuming
623 ReferenceEdge edgeFromLabel =
624 new ReferenceEdge(lnParam, hrn, null, false, beta);
626 ReferenceEdge edgeFromLabelQ =
627 new ReferenceEdge(lnParamQ, hrn, null, false, beta);
629 ReferenceEdge edgeReflexive =
630 new ReferenceEdge(hrn, hrn, null, true, beta);
632 addReferenceEdge(lnParam, hrn, edgeFromLabel);
633 addReferenceEdge(lnParamQ, hrn, edgeFromLabelQ);
634 addReferenceEdge(hrn, hrn, edgeReflexive);
637 public void makeAliasedParamHeapRegionNode(TempDescriptor td) {
640 LabelNode lnParam = getLabelNodeFromTemp(td);
641 HeapRegionNode hrn = createNewHeapRegionNode(null,
651 ReachabilitySet beta = new ReachabilitySet(new TokenTuple(hrn.getID(),
653 TokenTuple.ARITY_ONE).makeCanonical()
656 // heap regions for parameters are always multiple object (see above)
657 // and have a reference to themselves, because we can't know the
658 // structure of memory that is passed into the method. We're assuming
661 ReferenceEdge edgeFromLabel =
662 new ReferenceEdge(lnParam, hrn, null, false, beta);
664 ReferenceEdge edgeReflexive =
665 new ReferenceEdge(hrn, hrn, null, true, beta);
667 addReferenceEdge(lnParam, hrn, edgeFromLabel);
668 addReferenceEdge(hrn, hrn, edgeReflexive);
671 public void assignTempEqualToAliasedParam(TempDescriptor tdParam,
672 TempDescriptor tdAliased,
673 Integer paramIndex ) {
674 assert tdParam != null;
675 assert tdAliased != null;
677 LabelNode lnParam = getLabelNodeFromTemp(tdParam);
679 LabelNode lnAliased = getLabelNodeFromTemp(tdAliased);
681 // this is a non-program-accessible label that picks up beta
682 // info to be used for fixing a caller of this method
683 TempDescriptor tdParamQ = new TempDescriptor(tdParam+"specialQ");
684 LabelNode lnParamQ = getLabelNodeFromTemp(tdParamQ);
686 // the lnAliased should always only reference one node, and that
687 // heap region node is the aliased param blob
688 assert lnAliased.getNumReferencees() == 1;
689 HeapRegionNode hrnAliasBlob = lnAliased.iteratorToReferencees().next().getDst();
691 // keep track of heap regions that were created for
692 // parameter labels, the index of the parameter they
693 // are for is important when resolving method calls
694 Integer idAliased = hrnAliasBlob.getID();
695 Set s = id2paramIndexSet.get( idAliased );
697 s = new HashSet<Integer>();
700 id2paramIndexSet.put(idAliased, s);
701 paramIndex2id.put(paramIndex, idAliased);
702 paramIndex2tdQ.put(paramIndex, tdParamQ);
704 ReachabilitySet beta = new ReachabilitySet(new TokenTuple(idAliased,
706 TokenTuple.ARITY_ONE).makeCanonical()
709 // heap regions for parameters are always multiple object (see above)
710 // and have a reference to themselves, because we can't know the
711 // structure of memory that is passed into the method. We're assuming
714 ReferenceEdge edgeFromLabel =
715 new ReferenceEdge(lnParam, hrnAliasBlob, null, false, beta);
717 ReferenceEdge edgeFromLabelQ =
718 new ReferenceEdge(lnParamQ, hrnAliasBlob, null, false, beta);
720 addReferenceEdge(lnParam, hrnAliasBlob, edgeFromLabel);
721 addReferenceEdge(lnParamQ, hrnAliasBlob, edgeFromLabelQ);
726 public void assignReturnEqualToTemp(TempDescriptor x) {
728 LabelNode lnR = getLabelNodeFromTemp(tdReturn);
729 LabelNode lnX = getLabelNodeFromTemp(x);
731 clearReferenceEdgesFrom(lnR, null, true);
733 Iterator<ReferenceEdge> itrXhrn = lnX.iteratorToReferencees();
734 while( itrXhrn.hasNext() ) {
735 ReferenceEdge edgeX = itrXhrn.next();
736 HeapRegionNode referencee = edgeX.getDst();
737 ReferenceEdge edgeNew = edgeX.copy();
740 addReferenceEdge(lnR, referencee, edgeNew);
745 public void assignTempEqualToNewAlloc(TempDescriptor x,
752 // after the age operation the newest (or zero-ith oldest)
753 // node associated with the allocation site should have
754 // no references to it as if it were a newly allocated
755 // heap region, so make a reference to it to complete
758 Integer idNewest = as.getIthOldest(0);
759 HeapRegionNode hrnNewest = id2hrn.get(idNewest);
760 assert hrnNewest != null;
762 LabelNode lnX = getLabelNodeFromTemp(x);
763 clearReferenceEdgesFrom(lnX, null, true);
765 ReferenceEdge edgeNew =
766 new ReferenceEdge(lnX, hrnNewest, null, false, hrnNewest.getAlpha() );
768 addReferenceEdge(lnX, hrnNewest, edgeNew);
772 // use the allocation site (unique to entire analysis) to
773 // locate the heap region nodes in this ownership graph
774 // that should be aged. The process models the allocation
775 // of new objects and collects all the oldest allocations
776 // in a summary node to allow for a finite analysis
778 // There is an additional property of this method. After
779 // running it on a particular ownership graph (many graphs
780 // may have heap regions related to the same allocation site)
781 // the heap region node objects in this ownership graph will be
782 // allocated. Therefore, after aging a graph for an allocation
783 // site, attempts to retrieve the heap region nodes using the
784 // integer id's contained in the allocation site should always
785 // return non-null heap regions.
786 public void age(AllocationSite as) {
788 // aging adds this allocation site to the graph's
789 // list of sites that exist in the graph, or does
790 // nothing if the site is already in the list
791 allocationSites.add(as);
793 // get the summary node for the allocation site in the context
794 // of this particular ownership graph
795 HeapRegionNode hrnSummary = getSummaryNode(as);
797 // merge oldest node into summary
798 Integer idK = as.getOldest();
799 HeapRegionNode hrnK = id2hrn.get(idK);
800 mergeIntoSummary(hrnK, hrnSummary);
802 // move down the line of heap region nodes
803 // clobbering the ith and transferring all references
804 // to and from i-1 to node i. Note that this clobbers
805 // the oldest node (hrnK) that was just merged into
807 for( int i = allocationDepth - 1; i > 0; --i ) {
809 // move references from the i-1 oldest to the ith oldest
810 Integer idIth = as.getIthOldest(i);
811 HeapRegionNode hrnI = id2hrn.get(idIth);
812 Integer idImin1th = as.getIthOldest(i - 1);
813 HeapRegionNode hrnImin1 = id2hrn.get(idImin1th);
815 transferOnto(hrnImin1, hrnI);
818 // as stated above, the newest node should have had its
819 // references moved over to the second oldest, so we wipe newest
820 // in preparation for being the new object to assign something to
821 Integer id0th = as.getIthOldest(0);
822 HeapRegionNode hrn0 = id2hrn.get(id0th);
825 // clear all references in and out of newest node
826 clearReferenceEdgesFrom(hrn0, null, true);
827 clearReferenceEdgesTo(hrn0, null, true);
830 // now tokens in reachability sets need to "age" also
831 Iterator itrAllLabelNodes = td2ln.entrySet().iterator();
832 while( itrAllLabelNodes.hasNext() ) {
833 Map.Entry me = (Map.Entry)itrAllLabelNodes.next();
834 LabelNode ln = (LabelNode) me.getValue();
836 Iterator<ReferenceEdge> itrEdges = ln.iteratorToReferencees();
837 while( itrEdges.hasNext() ) {
838 ageTokens(as, itrEdges.next() );
842 Iterator itrAllHRNodes = id2hrn.entrySet().iterator();
843 while( itrAllHRNodes.hasNext() ) {
844 Map.Entry me = (Map.Entry)itrAllHRNodes.next();
845 HeapRegionNode hrnToAge = (HeapRegionNode) me.getValue();
847 ageTokens(as, hrnToAge);
849 Iterator<ReferenceEdge> itrEdges = hrnToAge.iteratorToReferencees();
850 while( itrEdges.hasNext() ) {
851 ageTokens(as, itrEdges.next() );
856 // after tokens have been aged, reset newest node's reachability
857 if( hrn0.isFlagged() ) {
858 hrn0.setAlpha(new ReachabilitySet(
860 new TokenTuple(hrn0).makeCanonical()
865 hrn0.setAlpha(new ReachabilitySet(
866 new TokenTupleSet().makeCanonical()
873 protected HeapRegionNode getSummaryNode(AllocationSite as) {
875 Integer idSummary = as.getSummary();
876 HeapRegionNode hrnSummary = id2hrn.get(idSummary);
878 // If this is null then we haven't touched this allocation site
879 // in the context of the current ownership graph, so allocate
880 // heap region nodes appropriate for the entire allocation site.
881 // This should only happen once per ownership graph per allocation site,
882 // and a particular integer id can be used to locate the heap region
883 // in different ownership graphs that represents the same part of an
885 if( hrnSummary == null ) {
887 boolean hasFlags = false;
888 if( as.getType().isClass() ) {
889 hasFlags = as.getType().getClassDesc().hasFlags();
892 hrnSummary = createNewHeapRegionNode(idSummary,
899 as.toStringForDOT() + "\\nsummary");
901 for( int i = 0; i < as.getAllocationDepth(); ++i ) {
902 Integer idIth = as.getIthOldest(i);
903 assert !id2hrn.containsKey(idIth);
904 createNewHeapRegionNode(idIth,
911 as.toStringForDOT() + "\\n" + i + " oldest");
919 protected HeapRegionNode getShadowSummaryNode(AllocationSite as) {
921 Integer idShadowSummary = as.getSummaryShadow();
922 HeapRegionNode hrnShadowSummary = id2hrn.get(idShadowSummary);
924 if( hrnShadowSummary == null ) {
926 boolean hasFlags = false;
927 if( as.getType().isClass() ) {
928 hasFlags = as.getType().getClassDesc().hasFlags();
931 hrnShadowSummary = createNewHeapRegionNode(idShadowSummary,
938 as + "\\n" + as.getType() + "\\nshadowSum");
940 for( int i = 0; i < as.getAllocationDepth(); ++i ) {
941 Integer idShadowIth = as.getIthOldestShadow(i);
942 assert !id2hrn.containsKey(idShadowIth);
943 createNewHeapRegionNode(idShadowIth,
950 as + "\\n" + as.getType() + "\\n" + i + " shadow");
954 return hrnShadowSummary;
958 protected void mergeIntoSummary(HeapRegionNode hrn, HeapRegionNode hrnSummary) {
959 assert hrnSummary.isNewSummary();
961 // transfer references _from_ hrn over to hrnSummary
962 Iterator<ReferenceEdge> itrReferencee = hrn.iteratorToReferencees();
963 while( itrReferencee.hasNext() ) {
964 ReferenceEdge edge = itrReferencee.next();
965 ReferenceEdge edgeMerged = edge.copy();
966 edgeMerged.setSrc(hrnSummary);
968 HeapRegionNode hrnReferencee = edge.getDst();
969 ReferenceEdge edgeSummary = hrnSummary.getReferenceTo(hrnReferencee, edge.getFieldDesc() );
971 if( edgeSummary == null ) {
972 // the merge is trivial, nothing to be done
974 // otherwise an edge from the referencer to hrnSummary exists already
975 // and the edge referencer->hrn should be merged with it
976 edgeMerged.setBeta(edgeMerged.getBeta().union(edgeSummary.getBeta() ) );
979 addReferenceEdge(hrnSummary, hrnReferencee, edgeMerged);
982 // next transfer references _to_ hrn over to hrnSummary
983 Iterator<ReferenceEdge> itrReferencer = hrn.iteratorToReferencers();
984 while( itrReferencer.hasNext() ) {
985 ReferenceEdge edge = itrReferencer.next();
986 ReferenceEdge edgeMerged = edge.copy();
987 edgeMerged.setDst(hrnSummary);
989 OwnershipNode onReferencer = edge.getSrc();
990 ReferenceEdge edgeSummary = onReferencer.getReferenceTo(hrnSummary, edge.getFieldDesc() );
992 if( edgeSummary == null ) {
993 // the merge is trivial, nothing to be done
995 // otherwise an edge from the referencer to alpha_S exists already
996 // and the edge referencer->alpha_K should be merged with it
997 edgeMerged.setBeta(edgeMerged.getBeta().union(edgeSummary.getBeta() ) );
1000 addReferenceEdge(onReferencer, hrnSummary, edgeMerged);
1003 // then merge hrn reachability into hrnSummary
1004 hrnSummary.setAlpha(hrnSummary.getAlpha().union(hrn.getAlpha() ) );
1008 protected void transferOnto(HeapRegionNode hrnA, HeapRegionNode hrnB) {
1010 // clear references in and out of node b
1011 clearReferenceEdgesFrom(hrnB, null, true);
1012 clearReferenceEdgesTo(hrnB, null, true);
1014 // copy each edge in and out of A to B
1015 Iterator<ReferenceEdge> itrReferencee = hrnA.iteratorToReferencees();
1016 while( itrReferencee.hasNext() ) {
1017 ReferenceEdge edge = itrReferencee.next();
1018 HeapRegionNode hrnReferencee = edge.getDst();
1019 ReferenceEdge edgeNew = edge.copy();
1020 edgeNew.setSrc(hrnB);
1022 addReferenceEdge(hrnB, hrnReferencee, edgeNew);
1025 Iterator<ReferenceEdge> itrReferencer = hrnA.iteratorToReferencers();
1026 while( itrReferencer.hasNext() ) {
1027 ReferenceEdge edge = itrReferencer.next();
1028 OwnershipNode onReferencer = edge.getSrc();
1029 ReferenceEdge edgeNew = edge.copy();
1030 edgeNew.setDst(hrnB);
1032 addReferenceEdge(onReferencer, hrnB, edgeNew);
1035 // replace hrnB reachability with hrnA's
1036 hrnB.setAlpha(hrnA.getAlpha() );
1040 protected void ageTokens(AllocationSite as, ReferenceEdge edge) {
1041 edge.setBeta(edge.getBeta().ageTokens(as) );
1044 protected void ageTokens(AllocationSite as, HeapRegionNode hrn) {
1045 hrn.setAlpha(hrn.getAlpha().ageTokens(as) );
1049 public Set<Integer> calculateAliasedParamSet(FlatCall fc,
1053 Hashtable<Integer, LabelNode> paramIndex2ln =
1054 new Hashtable<Integer, LabelNode>();
1056 Hashtable<Integer, HashSet<HeapRegionNode> > paramIndex2reachableCallerNodes =
1057 new Hashtable<Integer, HashSet<HeapRegionNode> >();
1059 for( int i = 0; i < fm.numParameters(); ++i ) {
1060 Integer paramIndex = new Integer(i);
1062 // now depending on whether the callee is static or not
1063 // we need to account for a "this" argument in order to
1064 // find the matching argument in the caller context
1065 TempDescriptor argTemp_i;
1067 argTemp_i = fc.getArg(paramIndex);
1069 if( paramIndex.equals(0) ) {
1070 argTemp_i = fc.getThis();
1072 argTemp_i = fc.getArg(paramIndex - 1);
1076 // in non-static methods there is a "this" pointer
1077 // that should be taken into account
1079 assert fc.numArgs() == fm.numParameters();
1081 assert fc.numArgs() + 1 == fm.numParameters();
1084 LabelNode argLabel_i = getLabelNodeFromTemp(argTemp_i);
1085 paramIndex2ln.put(paramIndex, argLabel_i);
1088 Iterator lnArgItr = paramIndex2ln.entrySet().iterator();
1089 while( lnArgItr.hasNext() ) {
1090 Map.Entry me = (Map.Entry)lnArgItr.next();
1091 Integer index = (Integer) me.getKey();
1092 LabelNode lnArg_i = (LabelNode) me.getValue();
1094 // rewrite alpha for the nodes reachable from argument label i
1095 HashSet<HeapRegionNode> reachableNodes = new HashSet<HeapRegionNode>();
1096 HashSet<HeapRegionNode> todoNodes = new HashSet<HeapRegionNode>();
1098 // to find all reachable nodes, start with label referencees
1099 Iterator<ReferenceEdge> edgeArgItr = lnArg_i.iteratorToReferencees();
1100 while( edgeArgItr.hasNext() ) {
1101 ReferenceEdge edge = edgeArgItr.next();
1102 todoNodes.add(edge.getDst() );
1105 // then follow links until all reachable nodes have been found
1106 while( !todoNodes.isEmpty() ) {
1107 HeapRegionNode hrn = todoNodes.iterator().next();
1108 todoNodes.remove(hrn);
1109 reachableNodes.add(hrn);
1111 Iterator<ReferenceEdge> edgeItr = hrn.iteratorToReferencees();
1112 while( edgeItr.hasNext() ) {
1113 ReferenceEdge edge = edgeItr.next();
1115 if( !reachableNodes.contains(edge.getDst() ) ) {
1116 todoNodes.add(edge.getDst() );
1122 paramIndex2reachableCallerNodes.put(index, reachableNodes);
1125 Set<Integer> aliasedIndices = new HashSet<Integer>();
1127 // check for arguments that are aliased
1128 for( int i = 0; i < fm.numParameters(); ++i ) {
1129 for( int j = 0; j < i; ++j ) {
1130 HashSet<HeapRegionNode> s1 = paramIndex2reachableCallerNodes.get( i );
1131 HashSet<HeapRegionNode> s2 = paramIndex2reachableCallerNodes.get( j );
1133 Set<HeapRegionNode> intersection = new HashSet<HeapRegionNode>(s1);
1134 intersection.retainAll(s2);
1136 if( !intersection.isEmpty() ) {
1137 aliasedIndices.add( new Integer( i ) );
1138 aliasedIndices.add( new Integer( j ) );
1143 return aliasedIndices;
1147 public void resolveMethodCall(FlatCall fc,
1150 OwnershipGraph ogCallee,
1151 MethodContext mc // this is only included for identifying caller while debugging
1154 String debugCaller = "foo";
1155 String debugCallee = "bar";
1157 if( mc.getDescriptor().getSymbol().equals( debugCaller ) &&
1158 fm.getMethod().getSymbol().equals( debugCallee ) ) {
1161 writeGraph( "debug1Before", true, true, true, false, false );
1162 ogCallee.writeGraph( "debug0Callee", true, true, true, false, false );
1163 } catch( IOException e ) {}
1165 System.out.println( " "+mc+" is calling "+fm );
1169 // define rewrite rules and other structures to organize
1170 // data by parameter/argument index
1171 Hashtable<Integer, ReachabilitySet> paramIndex2rewriteH =
1172 new Hashtable<Integer, ReachabilitySet>();
1174 Hashtable<Integer, ReachabilitySet> paramIndex2rewriteJ =
1175 new Hashtable<Integer, ReachabilitySet>();
1177 Hashtable<Integer, ReachabilitySet> paramIndex2rewriteK =
1178 new Hashtable<Integer, ReachabilitySet>();
1180 Hashtable<Integer, ReachabilitySet> paramIndex2rewrite_d =
1181 new Hashtable<Integer, ReachabilitySet>();
1183 Hashtable<Integer, ReachabilitySet> paramIndex2rewriteD =
1184 new Hashtable<Integer, ReachabilitySet>();
1186 // helpful structures
1187 Hashtable<TokenTuple, Integer> paramToken2paramIndex =
1188 new Hashtable<TokenTuple, Integer>();
1190 Hashtable<Integer, TokenTuple> paramIndex2paramToken =
1191 new Hashtable<Integer, TokenTuple>();
1193 Hashtable<TokenTuple, Integer> paramTokenPlus2paramIndex =
1194 new Hashtable<TokenTuple, Integer>();
1196 Hashtable<Integer, TokenTuple> paramIndex2paramTokenPlus =
1197 new Hashtable<Integer, TokenTuple>();
1199 Hashtable<TokenTuple, Integer> paramTokenStar2paramIndex =
1200 new Hashtable<TokenTuple, Integer>();
1202 Hashtable<Integer, TokenTuple> paramIndex2paramTokenStar =
1203 new Hashtable<Integer, TokenTuple>();
1205 Hashtable<Integer, LabelNode> paramIndex2ln =
1206 new Hashtable<Integer, LabelNode>();
1208 Hashtable<Integer, HashSet<HeapRegionNode> > paramIndex2reachableCallerNodes =
1209 new Hashtable<Integer, HashSet<HeapRegionNode> >();
1212 // add a bogus entry with the identity rule for easy rewrite
1213 // of new callee nodes and edges, doesn't belong to any parameter
1214 Integer bogusID = new Integer(bogusParamIndexInt);
1215 Integer bogusIndex = new Integer(bogusParamIndexInt);
1216 TokenTuple bogusToken = new TokenTuple(bogusID, true, TokenTuple.ARITY_ONE).makeCanonical();
1217 TokenTuple bogusTokenPlus = new TokenTuple(bogusID, true, TokenTuple.ARITY_ONEORMORE).makeCanonical();
1218 TokenTuple bogusTokenStar = new TokenTuple(bogusID, true, TokenTuple.ARITY_ZEROORMORE).makeCanonical();
1219 ReachabilitySet rsIdentity =
1220 new ReachabilitySet(
1221 new TokenTupleSet(bogusToken).makeCanonical()
1224 paramIndex2rewriteH.put(bogusIndex, rsIdentity);
1225 paramIndex2rewriteJ.put(bogusIndex, rsIdentity);
1226 paramToken2paramIndex.put(bogusToken, bogusIndex);
1227 paramIndex2paramToken.put(bogusIndex, bogusToken);
1228 paramTokenPlus2paramIndex.put(bogusTokenPlus, bogusIndex);
1229 paramIndex2paramTokenPlus.put(bogusIndex, bogusTokenPlus);
1230 paramTokenStar2paramIndex.put(bogusTokenStar, bogusIndex);
1231 paramIndex2paramTokenStar.put(bogusIndex, bogusTokenStar);
1233 for( int i = 0; i < fm.numParameters(); ++i ) {
1234 Integer paramIndex = new Integer(i);
1236 assert ogCallee.paramIndex2id.containsKey(paramIndex);
1237 Integer idParam = ogCallee.paramIndex2id.get(paramIndex);
1239 assert ogCallee.id2hrn.containsKey(idParam);
1240 HeapRegionNode hrnParam = ogCallee.id2hrn.get(idParam);
1241 assert hrnParam != null;
1242 paramIndex2rewriteH.put(paramIndex,
1243 toShadowTokens(ogCallee, hrnParam.getAlpha() )
1246 ReferenceEdge edgeReflexive_i = hrnParam.getReferenceTo(hrnParam, null);
1247 assert edgeReflexive_i != null;
1248 paramIndex2rewriteJ.put(paramIndex,
1249 toShadowTokens(ogCallee, edgeReflexive_i.getBeta() )
1252 TempDescriptor tdParamQ = ogCallee.paramIndex2tdQ.get(paramIndex);
1253 assert tdParamQ != null;
1254 LabelNode lnParamQ = ogCallee.td2ln.get(tdParamQ);
1255 assert lnParamQ != null;
1256 ReferenceEdge edgeSpecialQ_i = lnParamQ.getReferenceTo(hrnParam, null);
1257 assert edgeSpecialQ_i != null;
1258 paramIndex2rewriteK.put(paramIndex,
1259 toShadowTokens(ogCallee, edgeSpecialQ_i.getBeta() )
1262 TokenTuple p_i = new TokenTuple(hrnParam.getID(),
1264 TokenTuple.ARITY_ONE).makeCanonical();
1265 paramToken2paramIndex.put(p_i, paramIndex);
1266 paramIndex2paramToken.put(paramIndex, p_i);
1268 TokenTuple p_i_plus = new TokenTuple(hrnParam.getID(),
1270 TokenTuple.ARITY_ONEORMORE).makeCanonical();
1271 paramTokenPlus2paramIndex.put(p_i_plus, paramIndex);
1272 paramIndex2paramTokenPlus.put(paramIndex, p_i_plus);
1274 TokenTuple p_i_star = new TokenTuple(hrnParam.getID(),
1276 TokenTuple.ARITY_ZEROORMORE).makeCanonical();
1277 paramTokenStar2paramIndex.put(p_i_star, paramIndex);
1278 paramIndex2paramTokenStar.put(paramIndex, p_i_star);
1280 // now depending on whether the callee is static or not
1281 // we need to account for a "this" argument in order to
1282 // find the matching argument in the caller context
1283 TempDescriptor argTemp_i;
1285 argTemp_i = fc.getArg(paramIndex);
1287 if( paramIndex.equals(0) ) {
1288 argTemp_i = fc.getThis();
1290 argTemp_i = fc.getArg(paramIndex - 1);
1294 // in non-static methods there is a "this" pointer
1295 // that should be taken into account
1297 assert fc.numArgs() == fm.numParameters();
1299 assert fc.numArgs() + 1 == fm.numParameters();
1302 LabelNode argLabel_i = getLabelNodeFromTemp(argTemp_i);
1303 paramIndex2ln.put(paramIndex, argLabel_i);
1305 ReachabilitySet d_i = new ReachabilitySet().makeCanonical();
1306 Iterator<ReferenceEdge> edgeItr = argLabel_i.iteratorToReferencees();
1307 while( edgeItr.hasNext() ) {
1308 ReferenceEdge edge = edgeItr.next();
1309 d_i = d_i.union(edge.getBeta());
1311 paramIndex2rewrite_d.put(paramIndex, d_i);
1313 ReachabilitySet D_i = d_i.exhaustiveArityCombinations();
1314 paramIndex2rewriteD.put(paramIndex, D_i);
1318 HashSet<HeapRegionNode> nodesWithNewAlpha = new HashSet<HeapRegionNode>();
1319 HashSet<ReferenceEdge> edgesWithNewBeta = new HashSet<ReferenceEdge>();
1321 HashSet<ReferenceEdge> edgesReachable = new HashSet<ReferenceEdge>();
1322 HashSet<ReferenceEdge> edgesUpstream = new HashSet<ReferenceEdge>();
1324 Iterator lnArgItr = paramIndex2ln.entrySet().iterator();
1325 while( lnArgItr.hasNext() ) {
1326 Map.Entry me = (Map.Entry) lnArgItr.next();
1327 Integer index = (Integer) me.getKey();
1328 LabelNode lnArg_i = (LabelNode) me.getValue();
1330 // rewrite alpha for the nodes reachable from argument label i
1331 HashSet<HeapRegionNode> reachableNodes = new HashSet<HeapRegionNode>();
1332 HashSet<HeapRegionNode> todoNodes = new HashSet<HeapRegionNode>();
1334 // to find all reachable nodes, start with label referencees
1335 Iterator<ReferenceEdge> edgeArgItr = lnArg_i.iteratorToReferencees();
1336 while( edgeArgItr.hasNext() ) {
1337 ReferenceEdge edge = edgeArgItr.next();
1338 todoNodes.add(edge.getDst() );
1341 // then follow links until all reachable nodes have been found
1342 while( !todoNodes.isEmpty() ) {
1343 HeapRegionNode hrn = todoNodes.iterator().next();
1344 todoNodes.remove(hrn);
1345 reachableNodes.add(hrn);
1347 Iterator<ReferenceEdge> edgeItr = hrn.iteratorToReferencees();
1348 while( edgeItr.hasNext() ) {
1349 ReferenceEdge edge = edgeItr.next();
1351 if( !reachableNodes.contains(edge.getDst() ) ) {
1352 todoNodes.add(edge.getDst() );
1358 paramIndex2reachableCallerNodes.put(index, reachableNodes);
1360 // now iterate over reachable nodes to update their alpha, and
1361 // classify edges found as "argument reachable" or "upstream"
1362 Iterator<HeapRegionNode> hrnItr = reachableNodes.iterator();
1363 while( hrnItr.hasNext() ) {
1364 HeapRegionNode hrn = hrnItr.next();
1366 rewriteCallerReachability(index,
1369 paramIndex2rewriteH.get(index),
1370 paramIndex2rewrite_d,
1371 paramIndex2rewriteD,
1372 paramIndex2paramToken.get(index),
1373 paramToken2paramIndex,
1374 paramTokenPlus2paramIndex,
1375 paramTokenStar2paramIndex,
1379 nodesWithNewAlpha.add(hrn);
1381 // look at all incoming edges to the reachable nodes
1382 // and sort them as edges reachable from the argument
1383 // label node, or upstream edges
1384 Iterator<ReferenceEdge> edgeItr = hrn.iteratorToReferencers();
1385 while( edgeItr.hasNext() ) {
1386 ReferenceEdge edge = edgeItr.next();
1388 OwnershipNode on = edge.getSrc();
1390 if( on instanceof LabelNode ) {
1392 LabelNode ln0 = (LabelNode) on;
1393 if( ln0.equals(lnArg_i) ) {
1394 edgesReachable.add(edge);
1396 edgesUpstream.add(edge);
1401 HeapRegionNode hrn0 = (HeapRegionNode) on;
1402 if( reachableNodes.contains(hrn0) ) {
1403 edgesReachable.add(edge);
1405 edgesUpstream.add(edge);
1411 // update reachable edges
1412 Iterator<ReferenceEdge> edgeReachableItr = edgesReachable.iterator();
1413 while( edgeReachableItr.hasNext() ) {
1414 ReferenceEdge edgeReachable = edgeReachableItr.next();
1416 rewriteCallerReachability(index,
1419 paramIndex2rewriteJ.get(index),
1420 paramIndex2rewrite_d,
1421 paramIndex2rewriteD,
1422 paramIndex2paramToken.get(index),
1423 paramToken2paramIndex,
1424 paramTokenPlus2paramIndex,
1425 paramTokenStar2paramIndex,
1429 edgesWithNewBeta.add(edgeReachable);
1432 // update upstream edges
1433 Hashtable<ReferenceEdge, ChangeTupleSet> edgeUpstreamPlannedChanges =
1434 new Hashtable<ReferenceEdge, ChangeTupleSet>();
1436 Iterator<ReferenceEdge> edgeUpstreamItr = edgesUpstream.iterator();
1437 while( edgeUpstreamItr.hasNext() ) {
1438 ReferenceEdge edgeUpstream = edgeUpstreamItr.next();
1440 rewriteCallerReachability(index,
1443 paramIndex2rewriteK.get(index),
1444 paramIndex2rewrite_d,
1445 paramIndex2rewriteD,
1446 paramIndex2paramToken.get(index),
1447 paramToken2paramIndex,
1448 paramTokenPlus2paramIndex,
1449 paramTokenStar2paramIndex,
1451 edgeUpstreamPlannedChanges);
1453 edgesWithNewBeta.add(edgeUpstream);
1456 propagateTokensOverEdges(edgesUpstream,
1457 edgeUpstreamPlannedChanges,
1462 // commit changes to alpha and beta
1463 Iterator<HeapRegionNode> nodeItr = nodesWithNewAlpha.iterator();
1464 while( nodeItr.hasNext() ) {
1465 nodeItr.next().applyAlphaNew();
1468 Iterator<ReferenceEdge> edgeItr = edgesWithNewBeta.iterator();
1469 while( edgeItr.hasNext() ) {
1470 edgeItr.next().applyBetaNew();
1474 // verify the existence of allocation sites and their
1475 // shadows from the callee in the context of this caller graph
1476 // then map allocated nodes of callee onto the caller shadows
1478 Iterator<AllocationSite> asItr = ogCallee.allocationSites.iterator();
1479 while( asItr.hasNext() ) {
1480 AllocationSite allocSite = asItr.next();
1482 // grab the summary in the caller just to make sure
1483 // the allocation site has nodes in the caller
1484 HeapRegionNode hrnSummary = getSummaryNode(allocSite);
1486 // assert that the shadow nodes have no reference edges
1487 // because they're brand new to the graph, or last time
1488 // they were used they should have been cleared of edges
1489 HeapRegionNode hrnShadowSummary = getShadowSummaryNode(allocSite);
1490 assert hrnShadowSummary.getNumReferencers() == 0;
1491 assert hrnShadowSummary.getNumReferencees() == 0;
1493 // then bring g_ij onto g'_ij and rewrite
1494 HeapRegionNode hrnSummaryCallee = ogCallee.getSummaryNode(allocSite);
1495 hrnShadowSummary.setAlpha(toShadowTokens(ogCallee, hrnSummaryCallee.getAlpha() ) );
1497 // shadow nodes only are touched by a rewrite one time,
1498 // so rewrite and immediately commit--and they don't belong
1499 // to a particular parameter, so use a bogus param index
1500 // that pulls a self-rewrite out of H
1501 rewriteCallerReachability(bogusIndex,
1504 hrnShadowSummary.getAlpha(),
1505 paramIndex2rewrite_d,
1506 paramIndex2rewriteD,
1508 paramToken2paramIndex,
1509 paramTokenPlus2paramIndex,
1510 paramTokenStar2paramIndex,
1514 hrnShadowSummary.applyAlphaNew();
1517 for( int i = 0; i < allocSite.getAllocationDepth(); ++i ) {
1518 Integer idIth = allocSite.getIthOldest(i);
1519 assert id2hrn.containsKey(idIth);
1520 HeapRegionNode hrnIth = id2hrn.get(idIth);
1522 Integer idShadowIth = -(allocSite.getIthOldest(i));
1523 assert id2hrn.containsKey(idShadowIth);
1524 HeapRegionNode hrnIthShadow = id2hrn.get(idShadowIth);
1525 assert hrnIthShadow.getNumReferencers() == 0;
1526 assert hrnIthShadow.getNumReferencees() == 0;
1528 assert ogCallee.id2hrn.containsKey(idIth);
1529 HeapRegionNode hrnIthCallee = ogCallee.id2hrn.get(idIth);
1530 hrnIthShadow.setAlpha(toShadowTokens(ogCallee, hrnIthCallee.getAlpha() ) );
1532 rewriteCallerReachability(bogusIndex,
1535 hrnIthShadow.getAlpha(),
1536 paramIndex2rewrite_d,
1537 paramIndex2rewriteD,
1539 paramToken2paramIndex,
1540 paramTokenPlus2paramIndex,
1541 paramTokenStar2paramIndex,
1545 hrnIthShadow.applyAlphaNew();
1550 // for every heap region->heap region edge in the
1551 // callee graph, create the matching edge or edges
1552 // in the caller graph
1553 Set sCallee = ogCallee.id2hrn.entrySet();
1554 Iterator iCallee = sCallee.iterator();
1555 while( iCallee.hasNext() ) {
1556 Map.Entry meCallee = (Map.Entry)iCallee.next();
1557 Integer idCallee = (Integer) meCallee.getKey();
1558 HeapRegionNode hrnCallee = (HeapRegionNode) meCallee.getValue();
1560 Iterator<ReferenceEdge> heapRegionsItrCallee = hrnCallee.iteratorToReferencees();
1561 while( heapRegionsItrCallee.hasNext() ) {
1562 ReferenceEdge edgeCallee = heapRegionsItrCallee.next();
1563 HeapRegionNode hrnChildCallee = edgeCallee.getDst();
1564 Integer idChildCallee = hrnChildCallee.getID();
1566 // only address this edge if it is not a special reflexive edge
1567 if( !edgeCallee.isInitialParamReflexive() ) {
1569 // now we know that in the callee method's ownership graph
1570 // there is a heap region->heap region reference edge given
1571 // by heap region pointers:
1572 // hrnCallee -> heapChildCallee
1574 // or by the ownership-graph independent ID's:
1575 // idCallee -> idChildCallee
1577 // make the edge with src and dst so beta info is
1578 // calculated once, then copy it for each new edge in caller
1579 ReferenceEdge edgeNewInCallerTemplate = new ReferenceEdge(null,
1581 edgeCallee.getFieldDesc(),
1583 toShadowTokens(ogCallee,
1584 edgeCallee.getBeta() )
1586 rewriteCallerReachability(bogusIndex,
1588 edgeNewInCallerTemplate,
1589 edgeNewInCallerTemplate.getBeta(),
1590 paramIndex2rewrite_d,
1591 paramIndex2rewriteD,
1593 paramToken2paramIndex,
1594 paramTokenPlus2paramIndex,
1595 paramTokenStar2paramIndex,
1599 edgeNewInCallerTemplate.applyBetaNew();
1602 // So now make a set of possible source heaps in the caller graph
1603 // and a set of destination heaps in the caller graph, and make
1604 // a reference edge in the caller for every possible (src,dst) pair
1605 HashSet<HeapRegionNode> possibleCallerSrcs =
1606 getHRNSetThatPossiblyMapToCalleeHRN(ogCallee,
1607 (HeapRegionNode) edgeCallee.getSrc(),
1608 paramIndex2reachableCallerNodes);
1610 HashSet<HeapRegionNode> possibleCallerDsts =
1611 getHRNSetThatPossiblyMapToCalleeHRN(ogCallee,
1612 edgeCallee.getDst(),
1613 paramIndex2reachableCallerNodes);
1616 // make every possible pair of {srcSet} -> {dstSet} edges in the caller
1617 Iterator srcItr = possibleCallerSrcs.iterator();
1618 while( srcItr.hasNext() ) {
1619 HeapRegionNode src = (HeapRegionNode) srcItr.next();
1621 if( !hasMatchingField(src, edgeCallee) ) {
1622 // prune this source node possibility
1626 Iterator dstItr = possibleCallerDsts.iterator();
1627 while( dstItr.hasNext() ) {
1628 HeapRegionNode dst = (HeapRegionNode) dstItr.next();
1630 if( !hasMatchingType(edgeCallee, dst) ) {
1635 // otherwise the caller src and dst pair can match the edge, so make it
1636 ReferenceEdge edgeNewInCaller = edgeNewInCallerTemplate.copy();
1637 edgeNewInCaller.setSrc(src);
1638 edgeNewInCaller.setDst(dst);
1640 ReferenceEdge edgeExisting = src.getReferenceTo(dst, edgeNewInCaller.getFieldDesc() );
1641 if( edgeExisting == null ) {
1642 // if this edge doesn't exist in the caller, create it
1643 addReferenceEdge(src, dst, edgeNewInCaller);
1646 // if it already exists, merge with it
1647 edgeExisting.setBeta(edgeExisting.getBeta().union(edgeNewInCaller.getBeta() ) );
1656 // return value may need to be assigned in caller
1657 TempDescriptor returnTemp = fc.getReturnTemp();
1658 if( returnTemp != null && !returnTemp.getType().isImmutable() ) {
1660 LabelNode lnLhsCaller = getLabelNodeFromTemp(returnTemp);
1661 clearReferenceEdgesFrom(lnLhsCaller, null, true);
1663 LabelNode lnReturnCallee = ogCallee.getLabelNodeFromTemp(tdReturn);
1664 Iterator<ReferenceEdge> edgeCalleeItr = lnReturnCallee.iteratorToReferencees();
1665 while( edgeCalleeItr.hasNext() ) {
1666 ReferenceEdge edgeCallee = edgeCalleeItr.next();
1668 ReferenceEdge edgeNewInCallerTemplate = new ReferenceEdge(null,
1670 edgeCallee.getFieldDesc(),
1672 toShadowTokens(ogCallee,
1673 edgeCallee.getBeta() )
1675 rewriteCallerReachability(bogusIndex,
1677 edgeNewInCallerTemplate,
1678 edgeNewInCallerTemplate.getBeta(),
1679 paramIndex2rewrite_d,
1680 paramIndex2rewriteD,
1682 paramToken2paramIndex,
1683 paramTokenPlus2paramIndex,
1684 paramTokenStar2paramIndex,
1688 edgeNewInCallerTemplate.applyBetaNew();
1691 HashSet<HeapRegionNode> assignCallerRhs =
1692 getHRNSetThatPossiblyMapToCalleeHRN(ogCallee,
1693 edgeCallee.getDst(),
1694 paramIndex2reachableCallerNodes);
1696 Iterator<HeapRegionNode> itrHrn = assignCallerRhs.iterator();
1697 while( itrHrn.hasNext() ) {
1698 HeapRegionNode hrnCaller = itrHrn.next();
1700 if( !hasMatchingType(edgeCallee, hrnCaller) ) {
1705 // otherwise caller node can match callee edge, so make it
1706 ReferenceEdge edgeNewInCaller = edgeNewInCallerTemplate.copy();
1707 edgeNewInCaller.setSrc(lnLhsCaller);
1708 edgeNewInCaller.setDst(hrnCaller);
1710 ReferenceEdge edgeExisting = lnLhsCaller.getReferenceTo(hrnCaller, edgeNewInCaller.getFieldDesc() );
1711 if( edgeExisting == null ) {
1713 // if this edge doesn't exist in the caller, create it
1714 addReferenceEdge(lnLhsCaller, hrnCaller, edgeNewInCaller);
1716 // if it already exists, merge with it
1717 edgeExisting.setBeta(edgeExisting.getBeta().union(edgeNewInCaller.getBeta() ) );
1724 // merge the shadow nodes of allocation sites back down to normal capacity
1725 Iterator<AllocationSite> allocItr = ogCallee.allocationSites.iterator();
1726 while( allocItr.hasNext() ) {
1727 AllocationSite as = allocItr.next();
1729 // first age each allocation site enough times to make room for the shadow nodes
1730 for( int i = 0; i < as.getAllocationDepth(); ++i ) {
1734 // then merge the shadow summary into the normal summary
1735 HeapRegionNode hrnSummary = getSummaryNode(as);
1736 assert hrnSummary != null;
1738 HeapRegionNode hrnSummaryShadow = getShadowSummaryNode(as);
1739 assert hrnSummaryShadow != null;
1741 mergeIntoSummary(hrnSummaryShadow, hrnSummary);
1743 // then clear off after merge
1744 clearReferenceEdgesFrom(hrnSummaryShadow, null, true);
1745 clearReferenceEdgesTo(hrnSummaryShadow, null, true);
1746 hrnSummaryShadow.setAlpha(new ReachabilitySet().makeCanonical() );
1748 // then transplant shadow nodes onto the now clean normal nodes
1749 for( int i = 0; i < as.getAllocationDepth(); ++i ) {
1751 Integer idIth = as.getIthOldest(i);
1752 HeapRegionNode hrnIth = id2hrn.get(idIth);
1754 Integer idIthShadow = as.getIthOldestShadow(i);
1755 HeapRegionNode hrnIthShadow = id2hrn.get(idIthShadow);
1757 transferOnto(hrnIthShadow, hrnIth);
1759 // clear off shadow nodes after transfer
1760 clearReferenceEdgesFrom(hrnIthShadow, null, true);
1761 clearReferenceEdgesTo(hrnIthShadow, null, true);
1762 hrnIthShadow.setAlpha(new ReachabilitySet().makeCanonical() );
1765 // finally, globally change shadow tokens into normal tokens
1766 Iterator itrAllLabelNodes = td2ln.entrySet().iterator();
1767 while( itrAllLabelNodes.hasNext() ) {
1768 Map.Entry me = (Map.Entry)itrAllLabelNodes.next();
1769 LabelNode ln = (LabelNode) me.getValue();
1771 Iterator<ReferenceEdge> itrEdges = ln.iteratorToReferencees();
1772 while( itrEdges.hasNext() ) {
1773 unshadowTokens(as, itrEdges.next() );
1777 Iterator itrAllHRNodes = id2hrn.entrySet().iterator();
1778 while( itrAllHRNodes.hasNext() ) {
1779 Map.Entry me = (Map.Entry)itrAllHRNodes.next();
1780 HeapRegionNode hrnToAge = (HeapRegionNode) me.getValue();
1782 unshadowTokens(as, hrnToAge);
1784 Iterator<ReferenceEdge> itrEdges = hrnToAge.iteratorToReferencees();
1785 while( itrEdges.hasNext() ) {
1786 unshadowTokens(as, itrEdges.next() );
1792 if( mc.getDescriptor().getSymbol().equals( debugCaller ) &&
1793 fm.getMethod().getSymbol().equals( debugCallee ) ) {
1795 writeGraph( "debug2JustBeforeSweep", true, true, true, false, false );
1796 } catch( IOException e ) {}
1800 // improve reachability as much as possible
1804 if( mc.getDescriptor().getSymbol().equals( debugCaller ) &&
1805 fm.getMethod().getSymbol().equals( debugCallee ) ) {
1807 writeGraph( "debug9endResolveCall", true, true, true, false, false );
1808 } catch( IOException e ) {}
1809 System.out.println( " "+mc+" done calling "+fm );
1814 protected boolean hasMatchingField(HeapRegionNode src, ReferenceEdge edge) {
1816 // if no allocation site, then it's a match-everything region
1817 AllocationSite asSrc = src.getAllocationSite();
1818 if( asSrc == null ) {
1822 TypeDescriptor tdSrc = asSrc.getType();
1823 assert tdSrc != null;
1825 if( tdSrc.isArray() ) {
1826 FieldDescriptor fd = edge.getFieldDesc();
1829 TypeDescriptor td = fd.getType();
1832 TypeDescriptor tdSrcDeref = tdSrc.dereference();
1833 assert tdSrcDeref != null;
1835 if( !typeUtil.isSuperorType( tdSrcDeref, td ) ) {
1839 return fd.getSymbol().equals( OwnershipAnalysis.arrayElementFieldName );
1842 // if it's not a class, it doesn't have any fields to match
1843 if( !tdSrc.isClass() ) {
1847 Iterator fieldsSrcItr = tdSrc.getClassDesc().getFields();
1848 while( fieldsSrcItr.hasNext() ) {
1849 FieldDescriptor fd = (FieldDescriptor) fieldsSrcItr.next();
1850 if( fd == edge.getFieldDesc() ) {
1855 // otherwise it is a class with fields
1856 // but we didn't find a match
1861 protected boolean hasMatchingType(ReferenceEdge edge, HeapRegionNode dst) {
1863 // if the region has no type, matches everything
1864 AllocationSite asDst = dst.getAllocationSite();
1865 if( asDst == null ) {
1869 TypeDescriptor tdDst = asDst.getType();
1870 assert tdDst != null;
1872 // if the type is not a class don't match because
1873 // primitives are copied, no memory aliases
1874 ClassDescriptor cdDst = tdDst.getClassDesc();
1875 if( cdDst == null && !tdDst.isArray() ) {
1879 // if the field is null, it matches everything
1880 FieldDescriptor fd = edge.getFieldDesc();
1884 TypeDescriptor tdFd = fd.getType();
1885 assert tdFd != null;
1887 return typeUtil.isSuperorType(tdFd, tdDst);
1892 protected void unshadowTokens(AllocationSite as, ReferenceEdge edge) {
1893 edge.setBeta(edge.getBeta().unshadowTokens(as) );
1896 protected void unshadowTokens(AllocationSite as, HeapRegionNode hrn) {
1897 hrn.setAlpha(hrn.getAlpha().unshadowTokens(as) );
1901 private ReachabilitySet toShadowTokens(OwnershipGraph ogCallee,
1902 ReachabilitySet rsIn) {
1904 ReachabilitySet rsOut = new ReachabilitySet(rsIn).makeCanonical();
1906 Iterator<AllocationSite> allocItr = ogCallee.allocationSites.iterator();
1907 while( allocItr.hasNext() ) {
1908 AllocationSite as = allocItr.next();
1910 rsOut = rsOut.toShadowTokens(as);
1913 return rsOut.makeCanonical();
1917 private void rewriteCallerReachability(Integer paramIndex,
1920 ReachabilitySet rules,
1921 Hashtable<Integer, ReachabilitySet> paramIndex2rewrite_d,
1922 Hashtable<Integer, ReachabilitySet> paramIndex2rewriteD,
1924 Hashtable<TokenTuple, Integer> paramToken2paramIndex,
1925 Hashtable<TokenTuple, Integer> paramTokenPlus2paramIndex,
1926 Hashtable<TokenTuple, Integer> paramTokenStar2paramIndex,
1927 boolean makeChangeSet,
1928 Hashtable<ReferenceEdge, ChangeTupleSet> edgePlannedChanges) {
1929 assert(hrn == null && edge != null) ||
1930 (hrn != null && edge == null);
1932 assert rules != null;
1935 ReachabilitySet callerReachabilityCurrent;
1937 callerReachabilityCurrent = edge.getBeta();
1939 callerReachabilityCurrent = hrn.getAlpha();
1942 ReachabilitySet callerReachabilityNew = new ReachabilitySet().makeCanonical();
1944 // for initializing structures in this method
1945 TokenTupleSet ttsEmpty = new TokenTupleSet().makeCanonical();
1947 // use this to construct a change set if required; the idea is to
1948 // map every partially rewritten token tuple set to the set of
1949 // caller-context token tuple sets that were used to generate it
1950 Hashtable<TokenTupleSet, HashSet<TokenTupleSet> > rewritten2source =
1951 new Hashtable<TokenTupleSet, HashSet<TokenTupleSet> >();
1952 rewritten2source.put(ttsEmpty, new HashSet<TokenTupleSet>() );
1955 Iterator<TokenTupleSet> rulesItr = rules.iterator();
1956 while(rulesItr.hasNext()) {
1957 TokenTupleSet rule = rulesItr.next();
1959 ReachabilitySet rewrittenRule = new ReachabilitySet(ttsEmpty).makeCanonical();
1961 Iterator<TokenTuple> ruleItr = rule.iterator();
1962 while(ruleItr.hasNext()) {
1963 TokenTuple ttCallee = ruleItr.next();
1965 // compute the possibilities for rewriting this callee token
1966 ReachabilitySet ttCalleeRewrites = null;
1967 boolean callerSourceUsed = false;
1969 if( ttCallee.equals(p_i) ) {
1970 // replace the arity-one token of the current parameter with the reachability
1971 // information from the caller edge
1972 ttCalleeRewrites = callerReachabilityCurrent;
1973 callerSourceUsed = true;
1975 } else if( paramToken2paramIndex.containsKey(ttCallee) ) {
1977 Integer paramIndex_j = paramToken2paramIndex.get(ttCallee);
1978 assert paramIndex_j != null;
1979 ttCalleeRewrites = paramIndex2rewrite_d.get(paramIndex_j);
1980 assert ttCalleeRewrites != null;
1982 } else if( paramTokenPlus2paramIndex.containsKey(ttCallee) ) {
1984 Integer paramIndex_j = paramTokenPlus2paramIndex.get(ttCallee);
1985 assert paramIndex_j != null;
1986 ttCalleeRewrites = paramIndex2rewriteD.get(paramIndex_j);
1987 assert ttCalleeRewrites != null;
1989 } else if( paramTokenStar2paramIndex.containsKey(ttCallee) ) {
1991 Integer paramIndex_j = paramTokenStar2paramIndex.get(ttCallee);
1992 assert paramIndex_j != null;
1993 ttCalleeRewrites = paramIndex2rewriteD.get(paramIndex_j);
1994 assert ttCalleeRewrites != null;
1997 // otherwise there's no need for a rewrite, just pass this one on
1998 TokenTupleSet ttsCaller = new TokenTupleSet(ttCallee).makeCanonical();
1999 ttCalleeRewrites = new ReachabilitySet(ttsCaller).makeCanonical();
2002 // branch every version of the working rewritten rule with
2003 // the possibilities for rewriting the current callee token
2004 ReachabilitySet rewrittenRuleWithTTCallee = new ReachabilitySet().makeCanonical();
2006 Iterator<TokenTupleSet> rewrittenRuleItr = rewrittenRule.iterator();
2007 while( rewrittenRuleItr.hasNext() ) {
2008 TokenTupleSet ttsRewritten = rewrittenRuleItr.next();
2010 Iterator<TokenTupleSet> ttCalleeRewritesItr = ttCalleeRewrites.iterator();
2011 while( ttCalleeRewritesItr.hasNext() ) {
2012 TokenTupleSet ttsBranch = ttCalleeRewritesItr.next();
2014 TokenTupleSet ttsRewrittenNext = ttsRewritten.unionUpArity(ttsBranch);
2016 if( makeChangeSet ) {
2017 // in order to keep the list of source token tuple sets
2018 // start with the sets used to make the partially rewritten
2019 // rule up to this point
2020 HashSet<TokenTupleSet> sourceSets = rewritten2source.get(ttsRewritten);
2021 assert sourceSets != null;
2023 // make a shallow copy for possible modification
2024 sourceSets = (HashSet<TokenTupleSet>)sourceSets.clone();
2026 // if we used something from the caller to rewrite it, remember
2027 if( callerSourceUsed ) {
2028 sourceSets.add(ttsBranch);
2031 // set mapping for the further rewritten rule
2032 rewritten2source.put(ttsRewrittenNext, sourceSets);
2035 rewrittenRuleWithTTCallee =
2036 rewrittenRuleWithTTCallee.union(ttsRewrittenNext);
2040 // now the rewritten rule's possibilities have been extended by
2041 // rewriting the current callee token, remember result
2042 rewrittenRule = rewrittenRuleWithTTCallee;
2045 // the rule has been entirely rewritten into the caller context
2046 // now, so add it to the new reachability information
2047 callerReachabilityNew =
2048 callerReachabilityNew.union(rewrittenRule);
2051 if( makeChangeSet ) {
2052 ChangeTupleSet callerChangeSet = new ChangeTupleSet().makeCanonical();
2054 // each possibility for the final reachability should have a set of
2055 // caller sources mapped to it, use to create the change set
2056 Iterator<TokenTupleSet> callerReachabilityItr = callerReachabilityNew.iterator();
2057 while( callerReachabilityItr.hasNext() ) {
2058 TokenTupleSet ttsRewrittenFinal = callerReachabilityItr.next();
2059 HashSet<TokenTupleSet> sourceSets = rewritten2source.get(ttsRewrittenFinal);
2060 assert sourceSets != null;
2062 Iterator<TokenTupleSet> sourceSetsItr = sourceSets.iterator();
2063 while( sourceSetsItr.hasNext() ) {
2064 TokenTupleSet ttsSource = sourceSetsItr.next();
2067 callerChangeSet.union(new ChangeTuple(ttsSource, ttsRewrittenFinal) );
2071 assert edgePlannedChanges != null;
2072 edgePlannedChanges.put(edge, callerChangeSet);
2076 edge.setBetaNew(edge.getBetaNew().union(callerReachabilityNew) );
2078 hrn.setAlphaNew(hrn.getAlphaNew().union(callerReachabilityNew) );
2084 private HashSet<HeapRegionNode>
2085 getHRNSetThatPossiblyMapToCalleeHRN(OwnershipGraph ogCallee,
2086 HeapRegionNode hrnCallee,
2087 Hashtable<Integer, HashSet<HeapRegionNode> > paramIndex2reachableCallerNodes
2090 HashSet<HeapRegionNode> possibleCallerHRNs = new HashSet<HeapRegionNode>();
2092 Set<Integer> paramIndicesCallee = ogCallee.id2paramIndexSet.get( hrnCallee.getID() );
2094 if( paramIndicesCallee == null ) {
2095 // this is a node allocated in the callee then and it has
2096 // exactly one shadow node in the caller to map to
2097 AllocationSite as = hrnCallee.getAllocationSite();
2100 int age = as.getAgeCategory(hrnCallee.getID() );
2101 assert age != AllocationSite.AGE_notInThisSite;
2104 if( age == AllocationSite.AGE_summary ) {
2105 idCaller = as.getSummaryShadow();
2106 } else if( age == AllocationSite.AGE_oldest ) {
2107 idCaller = as.getOldestShadow();
2109 assert age == AllocationSite.AGE_in_I;
2111 Integer I = as.getAge(hrnCallee.getID() );
2114 idCaller = as.getIthOldestShadow(I);
2117 assert id2hrn.containsKey(idCaller);
2118 HeapRegionNode hrnCaller = id2hrn.get(idCaller);
2119 possibleCallerHRNs.add(hrnCaller);
2122 // this is a node that was created to represent a parameter
2123 // so it maps to a whole mess of heap regions
2124 Iterator<Integer> itrIndex = paramIndicesCallee.iterator();
2125 while( itrIndex.hasNext() ) {
2126 Integer paramIndexCallee = itrIndex.next();
2127 assert paramIndex2reachableCallerNodes.containsKey(paramIndexCallee);
2128 possibleCallerHRNs.addAll( paramIndex2reachableCallerNodes.get(paramIndexCallee) );
2132 return possibleCallerHRNs;
2137 ////////////////////////////////////////////////////
2139 // This global sweep is an optional step to prune
2140 // reachability sets that are not internally
2141 // consistent with the global graph. It should be
2142 // invoked after strong updates or method calls.
2144 ////////////////////////////////////////////////////
2145 protected void globalSweep() {
2147 // boldB is part of the phase 1 sweep
2148 Hashtable< Integer, Hashtable<ReferenceEdge, ReachabilitySet> > boldB =
2149 new Hashtable< Integer, Hashtable<ReferenceEdge, ReachabilitySet> >();
2151 // visit every heap region to initialize alphaNew and calculate boldB
2152 Set hrns = id2hrn.entrySet();
2153 Iterator itrHrns = hrns.iterator();
2154 while( itrHrns.hasNext() ) {
2155 Map.Entry me = (Map.Entry)itrHrns.next();
2156 Integer token = (Integer) me.getKey();
2157 HeapRegionNode hrn = (HeapRegionNode) me.getValue();
2159 // assert that this node and incoming edges have clean alphaNew
2160 // and betaNew sets, respectively
2161 ReachabilitySet rsEmpty = new ReachabilitySet().makeCanonical();
2162 assert rsEmpty.equals( hrn.getAlphaNew() );
2164 Iterator<ReferenceEdge> itrRers = hrn.iteratorToReferencers();
2165 while( itrRers.hasNext() ) {
2166 ReferenceEdge edge = itrRers.next();
2167 assert rsEmpty.equals( edge.getBetaNew() );
2170 // calculate boldB for this flagged node
2171 if( hrn.isFlagged() || hrn.isParameter() ) {
2173 Hashtable<ReferenceEdge, ReachabilitySet> boldB_f =
2174 new Hashtable<ReferenceEdge, ReachabilitySet>();
2176 Set<ReferenceEdge> workSetEdges = new HashSet<ReferenceEdge>();
2178 // initial boldB_f constraints
2179 Iterator<ReferenceEdge> itrRees = hrn.iteratorToReferencees();
2180 while( itrRees.hasNext() ) {
2181 ReferenceEdge edge = itrRees.next();
2183 assert !boldB.containsKey( edge );
2184 boldB_f.put( edge, edge.getBeta() );
2186 assert !workSetEdges.contains( edge );
2187 workSetEdges.add( edge );
2190 // enforce the boldB_f constraint at edges until we reach a fixed point
2191 while( !workSetEdges.isEmpty() ) {
2192 ReferenceEdge edge = workSetEdges.iterator().next();
2193 workSetEdges.remove( edge );
2195 Iterator<ReferenceEdge> itrPrime = edge.getDst().iteratorToReferencees();
2196 while( itrPrime.hasNext() ) {
2197 ReferenceEdge edgePrime = itrPrime.next();
2199 ReachabilitySet prevResult = boldB_f.get( edgePrime );
2200 ReachabilitySet intersection = boldB_f.get( edge ).intersection( edgePrime.getBeta() );
2202 if( prevResult == null ||
2203 prevResult.union( intersection ).size() > prevResult.size() ) {
2205 if( prevResult == null ) {
2206 boldB_f.put( edgePrime, edgePrime.getBeta().union( intersection ) );
2208 boldB_f.put( edgePrime, prevResult.union( intersection ) );
2210 workSetEdges.add( edgePrime );
2215 boldB.put( token, boldB_f );
2220 // use boldB to prune tokens from alpha states that are impossible
2221 // and propagate the differences backwards across edges
2222 HashSet<ReferenceEdge> edgesForPropagation = new HashSet<ReferenceEdge>();
2224 Hashtable<ReferenceEdge, ChangeTupleSet> edgePlannedChanges =
2225 new Hashtable<ReferenceEdge, ChangeTupleSet>();
2227 hrns = id2hrn.entrySet();
2228 itrHrns = hrns.iterator();
2229 while( itrHrns.hasNext() ) {
2230 Map.Entry me = (Map.Entry)itrHrns.next();
2231 Integer token = (Integer) me.getKey();
2232 HeapRegionNode hrn = (HeapRegionNode) me.getValue();
2234 // never remove the identity token from a flagged region
2235 // because it is trivially satisfied
2236 TokenTuple ttException = new TokenTuple( token, !hrn.isSingleObject(), TokenTuple.ARITY_ONE ).makeCanonical();
2238 ChangeTupleSet cts = new ChangeTupleSet().makeCanonical();
2240 // mark tokens for removal
2241 Iterator<TokenTupleSet> stateItr = hrn.getAlpha().iterator();
2242 while( stateItr.hasNext() ) {
2243 TokenTupleSet ttsOld = stateItr.next();
2245 TokenTupleSet markedTokens = new TokenTupleSet().makeCanonical();
2247 Iterator<TokenTuple> ttItr = ttsOld.iterator();
2248 while( ttItr.hasNext() ) {
2249 TokenTuple ttOld = ttItr.next();
2251 // never remove the identity token from a flagged region
2252 // because it is trivially satisfied
2253 if( hrn.isFlagged() || hrn.isParameter() ) {
2254 if( ttOld == ttException ) {
2259 // does boldB_ttOld allow this token?
2260 boolean foundState = false;
2261 Iterator<ReferenceEdge> incidentEdgeItr = hrn.iteratorToReferencers();
2262 while( incidentEdgeItr.hasNext() ) {
2263 ReferenceEdge incidentEdge = incidentEdgeItr.next();
2265 // if it isn't allowed, mark for removal
2266 ReachabilitySet boldB_ttOld_incident = boldB.get( ttOld.getToken() ).get( incidentEdge );
2267 if( boldB_ttOld_incident != null &&
2268 boldB_ttOld_incident.contains( ttsOld ) ) {
2274 markedTokens = markedTokens.add( ttOld );
2278 // if there is nothing marked, just move on
2279 if( markedTokens.isEmpty() ) {
2280 hrn.setAlphaNew( hrn.getAlphaNew().union( ttsOld ) );
2284 // remove all marked tokens and establish a change set that should
2285 // propagate backwards over edges from this node
2286 TokenTupleSet ttsPruned = new TokenTupleSet().makeCanonical();
2287 ttItr = ttsOld.iterator();
2288 while( ttItr.hasNext() ) {
2289 TokenTuple ttOld = ttItr.next();
2291 if( !markedTokens.containsTuple( ttOld ) ) {
2292 ttsPruned = ttsPruned.union( ttOld );
2295 assert !ttsOld.equals( ttsPruned );
2297 hrn.setAlphaNew( hrn.getAlphaNew().union( ttsPruned ) );
2298 ChangeTuple ct = new ChangeTuple( ttsOld, ttsPruned ).makeCanonical();
2299 cts = cts.union( ct );
2302 // throw change tuple set on all incident edges
2303 if( !cts.isEmpty() ) {
2304 Iterator<ReferenceEdge> incidentEdgeItr = hrn.iteratorToReferencers();
2305 while( incidentEdgeItr.hasNext() ) {
2306 ReferenceEdge incidentEdge = incidentEdgeItr.next();
2308 edgesForPropagation.add( incidentEdge );
2310 if( edgePlannedChanges.get( incidentEdge ) == null ) {
2311 edgePlannedChanges.put( incidentEdge, cts );
2313 edgePlannedChanges.put(
2315 edgePlannedChanges.get( incidentEdge ).union( cts )
2322 HashSet<ReferenceEdge> edgesUpdated = new HashSet<ReferenceEdge>();
2324 propagateTokensOverEdges( edgesForPropagation,
2328 // at the end of the 1st phase reference edges have
2329 // beta, betaNew that correspond to beta and betaR
2331 // commit beta<-betaNew, so beta=betaR and betaNew
2332 // will represent the beta' calculation in 2nd phase
2334 // commit alpha<-alphaNew because it won't change
2335 HashSet<ReferenceEdge> res = new HashSet<ReferenceEdge>();
2337 Iterator<HeapRegionNode> nodeItr = id2hrn.values().iterator();
2338 while( nodeItr.hasNext() ) {
2339 HeapRegionNode hrn = nodeItr.next();
2340 hrn.applyAlphaNew();
2341 Iterator<ReferenceEdge> itrRes = hrn.iteratorToReferencers();
2342 while( itrRes.hasNext() ) {
2343 res.add( itrRes.next() );
2349 Iterator<ReferenceEdge> edgeItr = res.iterator();
2350 while( edgeItr.hasNext() ) {
2351 ReferenceEdge edge = edgeItr.next();
2352 HeapRegionNode hrn = edge.getDst();
2354 // commit results of last phase
2355 if( edgesUpdated.contains( edge ) ) {
2356 edge.applyBetaNew();
2359 // compute intial condition of 2nd phase
2360 edge.setBetaNew( edge.getBeta().intersection( hrn.getAlpha() ) );
2363 // every edge in the graph is the initial workset
2364 Set<ReferenceEdge> edgeWorkSet = (Set) res.clone();
2365 while( !edgeWorkSet.isEmpty() ) {
2366 ReferenceEdge edgePrime = edgeWorkSet.iterator().next();
2367 edgeWorkSet.remove( edgePrime );
2369 OwnershipNode on = edgePrime.getSrc();
2370 if( !(on instanceof HeapRegionNode) ) {
2373 HeapRegionNode hrn = (HeapRegionNode) on;
2375 Iterator<ReferenceEdge> itrEdge = hrn.iteratorToReferencers();
2376 while( itrEdge.hasNext() ) {
2377 ReferenceEdge edge = itrEdge.next();
2379 ReachabilitySet prevResult = edge.getBetaNew();
2380 assert prevResult != null;
2382 ReachabilitySet intersection = edge.getBeta().intersection( edgePrime.getBetaNew() );
2384 if( prevResult.union( intersection ).size() > prevResult.size() ) {
2385 edge.setBetaNew( prevResult.union( intersection ) );
2386 edgeWorkSet.add( edge );
2391 // commit beta' (beta<-betaNew)
2392 edgeItr = res.iterator();
2393 while( edgeItr.hasNext() ) {
2394 edgeItr.next().applyBetaNew();
2400 ////////////////////////////////////////////////////
2401 // in merge() and equals() methods the suffix A
2402 // represents the passed in graph and the suffix
2403 // B refers to the graph in this object
2404 // Merging means to take the incoming graph A and
2405 // merge it into B, so after the operation graph B
2406 // is the final result.
2407 ////////////////////////////////////////////////////
2408 public void merge(OwnershipGraph og) {
2414 mergeOwnershipNodes(og);
2415 mergeReferenceEdges(og);
2416 mergeId2paramIndex(og);
2417 mergeAllocationSites(og);
2421 protected void mergeOwnershipNodes(OwnershipGraph og) {
2422 Set sA = og.id2hrn.entrySet();
2423 Iterator iA = sA.iterator();
2424 while( iA.hasNext() ) {
2425 Map.Entry meA = (Map.Entry)iA.next();
2426 Integer idA = (Integer) meA.getKey();
2427 HeapRegionNode hrnA = (HeapRegionNode) meA.getValue();
2429 // if this graph doesn't have a node the
2430 // incoming graph has, allocate it
2431 if( !id2hrn.containsKey(idA) ) {
2432 HeapRegionNode hrnB = hrnA.copy();
2433 id2hrn.put(idA, hrnB);
2436 // otherwise this is a node present in both graphs
2437 // so make the new reachability set a union of the
2438 // nodes' reachability sets
2439 HeapRegionNode hrnB = id2hrn.get(idA);
2440 hrnB.setAlpha(hrnB.getAlpha().union(hrnA.getAlpha() ) );
2444 // now add any label nodes that are in graph B but
2446 sA = og.td2ln.entrySet();
2448 while( iA.hasNext() ) {
2449 Map.Entry meA = (Map.Entry)iA.next();
2450 TempDescriptor tdA = (TempDescriptor) meA.getKey();
2451 LabelNode lnA = (LabelNode) meA.getValue();
2453 // if the label doesn't exist in B, allocate and add it
2454 LabelNode lnB = getLabelNodeFromTemp(tdA);
2458 protected void mergeReferenceEdges(OwnershipGraph og) {
2461 Set sA = og.id2hrn.entrySet();
2462 Iterator iA = sA.iterator();
2463 while( iA.hasNext() ) {
2464 Map.Entry meA = (Map.Entry)iA.next();
2465 Integer idA = (Integer) meA.getKey();
2466 HeapRegionNode hrnA = (HeapRegionNode) meA.getValue();
2468 Iterator<ReferenceEdge> heapRegionsItrA = hrnA.iteratorToReferencees();
2469 while( heapRegionsItrA.hasNext() ) {
2470 ReferenceEdge edgeA = heapRegionsItrA.next();
2471 HeapRegionNode hrnChildA = edgeA.getDst();
2472 Integer idChildA = hrnChildA.getID();
2474 // at this point we know an edge in graph A exists
2475 // idA -> idChildA, does this exist in B?
2476 assert id2hrn.containsKey(idA);
2477 HeapRegionNode hrnB = id2hrn.get(idA);
2478 ReferenceEdge edgeToMerge = null;
2480 Iterator<ReferenceEdge> heapRegionsItrB = hrnB.iteratorToReferencees();
2481 while( heapRegionsItrB.hasNext() &&
2482 edgeToMerge == null ) {
2484 ReferenceEdge edgeB = heapRegionsItrB.next();
2485 HeapRegionNode hrnChildB = edgeB.getDst();
2486 Integer idChildB = hrnChildB.getID();
2488 // don't use the ReferenceEdge.equals() here because
2489 // we're talking about existence between graphs
2490 if( idChildB.equals(idChildA) &&
2491 edgeB.getFieldDesc() == edgeA.getFieldDesc() ) {
2492 edgeToMerge = edgeB;
2496 // if the edge from A was not found in B,
2498 if( edgeToMerge == null ) {
2499 assert id2hrn.containsKey(idChildA);
2500 HeapRegionNode hrnChildB = id2hrn.get(idChildA);
2501 edgeToMerge = edgeA.copy();
2502 edgeToMerge.setSrc(hrnB);
2503 edgeToMerge.setDst(hrnChildB);
2504 addReferenceEdge(hrnB, hrnChildB, edgeToMerge);
2506 // otherwise, the edge already existed in both graphs
2507 // so merge their reachability sets
2509 // just replace this beta set with the union
2510 assert edgeToMerge != null;
2511 edgeToMerge.setBeta(
2512 edgeToMerge.getBeta().union(edgeA.getBeta() )
2514 if( !edgeA.isInitialParamReflexive() ) {
2515 edgeToMerge.setIsInitialParamReflexive(false);
2521 // and then again with label nodes
2522 sA = og.td2ln.entrySet();
2524 while( iA.hasNext() ) {
2525 Map.Entry meA = (Map.Entry)iA.next();
2526 TempDescriptor tdA = (TempDescriptor) meA.getKey();
2527 LabelNode lnA = (LabelNode) meA.getValue();
2529 Iterator<ReferenceEdge> heapRegionsItrA = lnA.iteratorToReferencees();
2530 while( heapRegionsItrA.hasNext() ) {
2531 ReferenceEdge edgeA = heapRegionsItrA.next();
2532 HeapRegionNode hrnChildA = edgeA.getDst();
2533 Integer idChildA = hrnChildA.getID();
2535 // at this point we know an edge in graph A exists
2536 // tdA -> idChildA, does this exist in B?
2537 assert td2ln.containsKey(tdA);
2538 LabelNode lnB = td2ln.get(tdA);
2539 ReferenceEdge edgeToMerge = null;
2541 // labels never have edges with a field
2542 //assert edgeA.getFieldDesc() == null;
2544 Iterator<ReferenceEdge> heapRegionsItrB = lnB.iteratorToReferencees();
2545 while( heapRegionsItrB.hasNext() &&
2546 edgeToMerge == null ) {
2548 ReferenceEdge edgeB = heapRegionsItrB.next();
2549 HeapRegionNode hrnChildB = edgeB.getDst();
2550 Integer idChildB = hrnChildB.getID();
2552 // labels never have edges with a field
2553 //assert edgeB.getFieldDesc() == null;
2555 // don't use the ReferenceEdge.equals() here because
2556 // we're talking about existence between graphs
2557 if( idChildB.equals(idChildA) &&
2558 edgeB.getFieldDesc() == edgeA.getFieldDesc() ) {
2559 edgeToMerge = edgeB;
2563 // if the edge from A was not found in B,
2565 if( edgeToMerge == null ) {
2566 assert id2hrn.containsKey(idChildA);
2567 HeapRegionNode hrnChildB = id2hrn.get(idChildA);
2568 edgeToMerge = edgeA.copy();
2569 edgeToMerge.setSrc(lnB);
2570 edgeToMerge.setDst(hrnChildB);
2571 addReferenceEdge(lnB, hrnChildB, edgeToMerge);
2573 // otherwise, the edge already existed in both graphs
2574 // so merge their reachability sets
2576 // just replace this beta set with the union
2577 edgeToMerge.setBeta(
2578 edgeToMerge.getBeta().union(edgeA.getBeta() )
2580 if( !edgeA.isInitialParamReflexive() ) {
2581 edgeToMerge.setIsInitialParamReflexive(false);
2588 // you should only merge ownership graphs that have the
2589 // same number of parameters, or if one or both parameter
2590 // index tables are empty
2591 protected void mergeId2paramIndex(OwnershipGraph og) {
2592 if( id2paramIndexSet.size() == 0 ) {
2593 id2paramIndexSet = og.id2paramIndexSet;
2594 paramIndex2id = og.paramIndex2id;
2595 paramIndex2tdQ = og.paramIndex2tdQ;
2599 if( og.id2paramIndexSet.size() == 0 ) {
2603 assert id2paramIndexSet.size() == og.id2paramIndexSet.size();
2606 protected void mergeAllocationSites(OwnershipGraph og) {
2607 allocationSites.addAll(og.allocationSites);
2612 // it is necessary in the equals() member functions
2613 // to "check both ways" when comparing the data
2614 // structures of two graphs. For instance, if all
2615 // edges between heap region nodes in graph A are
2616 // present and equal in graph B it is not sufficient
2617 // to say the graphs are equal. Consider that there
2618 // may be edges in graph B that are not in graph A.
2619 // the only way to know that all edges in both graphs
2620 // are equally present is to iterate over both data
2621 // structures and compare against the other graph.
2622 public boolean equals(OwnershipGraph og) {
2628 if( !areHeapRegionNodesEqual(og) ) {
2632 if( !areLabelNodesEqual(og) ) {
2636 if( !areReferenceEdgesEqual(og) ) {
2640 if( !areId2paramIndexEqual(og) ) {
2644 // if everything is equal up to this point,
2645 // assert that allocationSites is also equal--
2646 // this data is redundant and kept for efficiency
2647 assert allocationSites.equals(og.allocationSites);
2652 protected boolean areHeapRegionNodesEqual(OwnershipGraph og) {
2654 if( !areallHRNinAalsoinBandequal(this, og) ) {
2658 if( !areallHRNinAalsoinBandequal(og, this) ) {
2665 static protected boolean areallHRNinAalsoinBandequal(OwnershipGraph ogA,
2666 OwnershipGraph ogB) {
2667 Set sA = ogA.id2hrn.entrySet();
2668 Iterator iA = sA.iterator();
2669 while( iA.hasNext() ) {
2670 Map.Entry meA = (Map.Entry)iA.next();
2671 Integer idA = (Integer) meA.getKey();
2672 HeapRegionNode hrnA = (HeapRegionNode) meA.getValue();
2674 if( !ogB.id2hrn.containsKey(idA) ) {
2678 HeapRegionNode hrnB = ogB.id2hrn.get(idA);
2679 if( !hrnA.equalsIncludingAlpha(hrnB) ) {
2688 protected boolean areLabelNodesEqual(OwnershipGraph og) {
2690 if( !areallLNinAalsoinBandequal(this, og) ) {
2694 if( !areallLNinAalsoinBandequal(og, this) ) {
2701 static protected boolean areallLNinAalsoinBandequal(OwnershipGraph ogA,
2702 OwnershipGraph ogB) {
2703 Set sA = ogA.td2ln.entrySet();
2704 Iterator iA = sA.iterator();
2705 while( iA.hasNext() ) {
2706 Map.Entry meA = (Map.Entry)iA.next();
2707 TempDescriptor tdA = (TempDescriptor) meA.getKey();
2709 if( !ogB.td2ln.containsKey(tdA) ) {
2718 protected boolean areReferenceEdgesEqual(OwnershipGraph og) {
2719 if( !areallREinAandBequal(this, og) ) {
2726 static protected boolean areallREinAandBequal(OwnershipGraph ogA,
2727 OwnershipGraph ogB) {
2729 // check all the heap region->heap region edges
2730 Set sA = ogA.id2hrn.entrySet();
2731 Iterator iA = sA.iterator();
2732 while( iA.hasNext() ) {
2733 Map.Entry meA = (Map.Entry)iA.next();
2734 Integer idA = (Integer) meA.getKey();
2735 HeapRegionNode hrnA = (HeapRegionNode) meA.getValue();
2737 // we should have already checked that the same
2738 // heap regions exist in both graphs
2739 assert ogB.id2hrn.containsKey(idA);
2741 if( !areallREfromAequaltoB(ogA, hrnA, ogB) ) {
2745 // then check every edge in B for presence in A, starting
2746 // from the same parent HeapRegionNode
2747 HeapRegionNode hrnB = ogB.id2hrn.get(idA);
2749 if( !areallREfromAequaltoB(ogB, hrnB, ogA) ) {
2754 // then check all the label->heap region edges
2755 sA = ogA.td2ln.entrySet();
2757 while( iA.hasNext() ) {
2758 Map.Entry meA = (Map.Entry)iA.next();
2759 TempDescriptor tdA = (TempDescriptor) meA.getKey();
2760 LabelNode lnA = (LabelNode) meA.getValue();
2762 // we should have already checked that the same
2763 // label nodes exist in both graphs
2764 assert ogB.td2ln.containsKey(tdA);
2766 if( !areallREfromAequaltoB(ogA, lnA, ogB) ) {
2770 // then check every edge in B for presence in A, starting
2771 // from the same parent LabelNode
2772 LabelNode lnB = ogB.td2ln.get(tdA);
2774 if( !areallREfromAequaltoB(ogB, lnB, ogA) ) {
2783 static protected boolean areallREfromAequaltoB(OwnershipGraph ogA,
2785 OwnershipGraph ogB) {
2787 Iterator<ReferenceEdge> itrA = onA.iteratorToReferencees();
2788 while( itrA.hasNext() ) {
2789 ReferenceEdge edgeA = itrA.next();
2790 HeapRegionNode hrnChildA = edgeA.getDst();
2791 Integer idChildA = hrnChildA.getID();
2793 assert ogB.id2hrn.containsKey(idChildA);
2795 // at this point we know an edge in graph A exists
2796 // onA -> idChildA, does this exact edge exist in B?
2797 boolean edgeFound = false;
2799 OwnershipNode onB = null;
2800 if( onA instanceof HeapRegionNode ) {
2801 HeapRegionNode hrnA = (HeapRegionNode) onA;
2802 onB = ogB.id2hrn.get(hrnA.getID() );
2804 LabelNode lnA = (LabelNode) onA;
2805 onB = ogB.td2ln.get(lnA.getTempDescriptor() );
2808 Iterator<ReferenceEdge> itrB = onB.iteratorToReferencees();
2809 while( itrB.hasNext() ) {
2810 ReferenceEdge edgeB = itrB.next();
2811 HeapRegionNode hrnChildB = edgeB.getDst();
2812 Integer idChildB = hrnChildB.getID();
2814 if( idChildA.equals(idChildB) &&
2815 edgeA.getFieldDesc() == edgeB.getFieldDesc() ) {
2817 // there is an edge in the right place with the right field,
2818 // but do they have the same attributes?
2819 if( edgeA.getBeta().equals(edgeB.getBeta() ) ) {
2837 protected boolean areId2paramIndexEqual(OwnershipGraph og) {
2838 return id2paramIndexSet.size() == og.id2paramIndexSet.size();
2842 public Set<HeapRegionNode> hasPotentialAlias( HeapRegionNode hrn1, HeapRegionNode hrn2 ) {
2843 assert hrn1 != null;
2844 assert hrn2 != null;
2846 // then get the various tokens for these heap regions
2847 TokenTuple h1 = new TokenTuple(hrn1.getID(),
2848 !hrn1.isSingleObject(),
2849 TokenTuple.ARITY_ONE).makeCanonical();
2851 TokenTuple h1plus = new TokenTuple(hrn1.getID(),
2852 !hrn1.isSingleObject(),
2853 TokenTuple.ARITY_ONEORMORE).makeCanonical();
2855 TokenTuple h1star = new TokenTuple(hrn1.getID(),
2856 !hrn1.isSingleObject(),
2857 TokenTuple.ARITY_ZEROORMORE).makeCanonical();
2859 TokenTuple h2 = new TokenTuple(hrn2.getID(),
2860 !hrn2.isSingleObject(),
2861 TokenTuple.ARITY_ONE).makeCanonical();
2863 TokenTuple h2plus = new TokenTuple(hrn2.getID(),
2864 !hrn2.isSingleObject(),
2865 TokenTuple.ARITY_ONEORMORE).makeCanonical();
2867 TokenTuple h2star = new TokenTuple(hrn2.getID(),
2868 !hrn2.isSingleObject(),
2869 TokenTuple.ARITY_ZEROORMORE).makeCanonical();
2871 // then get the merged beta of all out-going edges from these heap regions
2872 ReachabilitySet beta1 = new ReachabilitySet();
2873 Iterator<ReferenceEdge> itrEdge = hrn1.iteratorToReferencees();
2874 while( itrEdge.hasNext() ) {
2875 ReferenceEdge edge = itrEdge.next();
2876 beta1 = beta1.union( edge.getBeta() );
2879 ReachabilitySet beta2 = new ReachabilitySet();
2880 itrEdge = hrn2.iteratorToReferencees();
2881 while( itrEdge.hasNext() ) {
2882 ReferenceEdge edge = itrEdge.next();
2883 beta2 = beta2.union( edge.getBeta() );
2886 boolean aliasDetected = false;
2888 // only do this one if they are different tokens
2890 beta1.containsTupleSetWithBoth(h1, h2) ) {
2891 aliasDetected = true;
2893 if( beta1.containsTupleSetWithBoth(h1plus, h2) ) {
2894 aliasDetected = true;
2896 if( beta1.containsTupleSetWithBoth(h1star, h2) ) {
2897 aliasDetected = true;
2899 if( beta1.containsTupleSetWithBoth(h1, h2plus) ) {
2900 aliasDetected = true;
2902 if( beta1.containsTupleSetWithBoth(h1plus, h2plus) ) {
2903 aliasDetected = true;
2905 if( beta1.containsTupleSetWithBoth(h1star, h2plus) ) {
2906 aliasDetected = true;
2908 if( beta1.containsTupleSetWithBoth(h1, h2star) ) {
2909 aliasDetected = true;
2911 if( beta1.containsTupleSetWithBoth(h1plus, h2star) ) {
2912 aliasDetected = true;
2914 if( beta1.containsTupleSetWithBoth(h1star, h2star) ) {
2915 aliasDetected = true;
2919 beta2.containsTupleSetWithBoth(h1, h2) ) {
2920 aliasDetected = true;
2922 if( beta2.containsTupleSetWithBoth(h1plus, h2) ) {
2923 aliasDetected = true;
2925 if( beta2.containsTupleSetWithBoth(h1star, h2) ) {
2926 aliasDetected = true;
2928 if( beta2.containsTupleSetWithBoth(h1, h2plus) ) {
2929 aliasDetected = true;
2931 if( beta2.containsTupleSetWithBoth(h1plus, h2plus) ) {
2932 aliasDetected = true;
2934 if( beta2.containsTupleSetWithBoth(h1star, h2plus) ) {
2935 aliasDetected = true;
2937 if( beta2.containsTupleSetWithBoth(h1, h2star) ) {
2938 aliasDetected = true;
2940 if( beta2.containsTupleSetWithBoth(h1plus, h2star) ) {
2941 aliasDetected = true;
2943 if( beta2.containsTupleSetWithBoth(h1star, h2star) ) {
2944 aliasDetected = true;
2947 Set<HeapRegionNode> common = new HashSet<HeapRegionNode>();
2948 if( aliasDetected ) {
2949 common = findCommonReachableNodes( hrn1, hrn2 );
2950 assert !common.isEmpty();
2957 public Set<HeapRegionNode> hasPotentialAlias(Integer paramIndex1, Integer paramIndex2) {
2959 // get parameter's heap region
2960 assert paramIndex2id.containsKey(paramIndex1);
2961 Integer idParam1 = paramIndex2id.get(paramIndex1);
2963 assert id2hrn.containsKey(idParam1);
2964 HeapRegionNode hrnParam1 = id2hrn.get(idParam1);
2965 assert hrnParam1 != null;
2968 // get tokens for the other parameter
2969 assert paramIndex2id.containsKey(paramIndex2);
2970 Integer idParam2 = paramIndex2id.get(paramIndex2);
2972 assert id2hrn.containsKey(idParam2);
2973 HeapRegionNode hrnParam2 = id2hrn.get(idParam2);
2974 assert hrnParam2 != null;
2977 return hasPotentialAlias( hrnParam1, hrnParam2 );
2981 public Set<HeapRegionNode> hasPotentialAlias(Integer paramIndex, AllocationSite as) {
2983 // get parameter's heap region
2984 assert paramIndex2id.containsKey(paramIndex);
2985 Integer idParam = paramIndex2id.get(paramIndex);
2987 assert id2hrn.containsKey(idParam);
2988 HeapRegionNode hrnParam = id2hrn.get(idParam);
2989 assert hrnParam != null;
2992 assert id2hrn.containsKey( as.getSummary() );
2993 HeapRegionNode hrnSummary = id2hrn.get( as.getSummary() );
2994 assert hrnSummary != null;
2996 Set<HeapRegionNode> common = hasPotentialAlias( hrnParam, hrnSummary );
2997 if( !common.isEmpty() ) {
3001 // check for other nodes
3002 for( int i = 0; i < as.getAllocationDepth(); ++i ) {
3004 assert id2hrn.containsKey( as.getIthOldest( i ) );
3005 HeapRegionNode hrnIthOldest = id2hrn.get( as.getIthOldest( i ) );
3006 assert hrnIthOldest != null;
3008 common = hasPotentialAlias( hrnParam, hrnIthOldest );
3009 if( !common.isEmpty() ) {
3014 return new HashSet<HeapRegionNode>();
3018 public Set<HeapRegionNode> hasPotentialAlias(AllocationSite as1, AllocationSite as2) {
3020 // get summary node 1's alpha
3021 Integer idSum1 = as1.getSummary();
3022 assert id2hrn.containsKey(idSum1);
3023 HeapRegionNode hrnSum1 = id2hrn.get(idSum1);
3024 assert hrnSum1 != null;
3026 // get summary node 2's alpha
3027 Integer idSum2 = as2.getSummary();
3028 assert id2hrn.containsKey(idSum2);
3029 HeapRegionNode hrnSum2 = id2hrn.get(idSum2);
3030 assert hrnSum2 != null;
3032 Set<HeapRegionNode> common = hasPotentialAlias( hrnSum1, hrnSum2 );
3033 if( !common.isEmpty() ) {
3037 // check sum2 against alloc1 nodes
3038 for( int i = 0; i < as1.getAllocationDepth(); ++i ) {
3039 Integer idI1 = as1.getIthOldest(i);
3040 assert id2hrn.containsKey(idI1);
3041 HeapRegionNode hrnI1 = id2hrn.get(idI1);
3042 assert hrnI1 != null;
3044 common = hasPotentialAlias( hrnI1, hrnSum2 );
3045 if( !common.isEmpty() ) {
3050 // check sum1 against alloc2 nodes
3051 for( int i = 0; i < as2.getAllocationDepth(); ++i ) {
3052 Integer idI2 = as2.getIthOldest(i);
3053 assert id2hrn.containsKey(idI2);
3054 HeapRegionNode hrnI2 = id2hrn.get(idI2);
3055 assert hrnI2 != null;
3057 common = hasPotentialAlias( hrnSum1, hrnI2 );
3058 if( common.isEmpty() ) {
3062 // while we're at it, do an inner loop for alloc2 vs alloc1 nodes
3063 for( int j = 0; j < as1.getAllocationDepth(); ++j ) {
3064 Integer idI1 = as1.getIthOldest(j);
3066 // if these are the same site, don't look for the same token, no alias.
3067 // different tokens of the same site could alias together though
3068 if( idI1.equals( idI2 ) ) {
3072 HeapRegionNode hrnI1 = id2hrn.get(idI1);
3074 common = hasPotentialAlias( hrnI1, hrnI2 );
3075 if( !common.isEmpty() ) {
3081 return new HashSet<HeapRegionNode>();
3085 public Set<HeapRegionNode> findCommonReachableNodes( HeapRegionNode hrn1,
3086 HeapRegionNode hrn2 ) {
3087 //assert hrn1 != hrn2;
3089 Set<HeapRegionNode> reachableNodes1 = new HashSet<HeapRegionNode>();
3090 Set<HeapRegionNode> reachableNodes2 = new HashSet<HeapRegionNode>();
3092 Set<HeapRegionNode> todoNodes1 = new HashSet<HeapRegionNode>();
3093 todoNodes1.add( hrn1 );
3095 Set<HeapRegionNode> todoNodes2 = new HashSet<HeapRegionNode>();
3096 todoNodes2.add( hrn2 );
3098 // follow links until all reachable nodes have been found
3099 while( !todoNodes1.isEmpty() ) {
3100 HeapRegionNode hrn = todoNodes1.iterator().next();
3101 todoNodes1.remove( hrn );
3102 reachableNodes1.add(hrn);
3104 Iterator<ReferenceEdge> edgeItr = hrn.iteratorToReferencees();
3105 while( edgeItr.hasNext() ) {
3106 ReferenceEdge edge = edgeItr.next();
3108 if( !reachableNodes1.contains( edge.getDst() ) ) {
3109 todoNodes1.add( edge.getDst() );
3114 while( !todoNodes2.isEmpty() ) {
3115 HeapRegionNode hrn = todoNodes2.iterator().next();
3116 todoNodes2.remove( hrn );
3117 reachableNodes2.add(hrn);
3119 Iterator<ReferenceEdge> edgeItr = hrn.iteratorToReferencees();
3120 while( edgeItr.hasNext() ) {
3121 ReferenceEdge edge = edgeItr.next();
3123 if( !reachableNodes2.contains( edge.getDst() ) ) {
3124 todoNodes2.add( edge.getDst() );
3129 Set<HeapRegionNode> intersection =
3130 new HashSet<HeapRegionNode>( reachableNodes1 );
3132 intersection.retainAll( reachableNodes2 );
3134 return intersection;
3138 // for writing ownership graphs to dot files
3139 public void writeGraph(MethodContext mc,
3141 boolean writeLabels,
3142 boolean labelSelect,
3143 boolean pruneGarbage,
3144 boolean writeReferencers,
3145 boolean writeParamMappings
3146 ) throws java.io.IOException {
3158 public void writeGraph(MethodContext mc,
3159 boolean writeLabels,
3160 boolean labelSelect,
3161 boolean pruneGarbage,
3162 boolean writeReferencers,
3163 boolean writeParamMappings
3164 ) throws java.io.IOException {
3166 writeGraph(mc+"COMPLETE",
3175 public void writeGraph(MethodContext mc,
3177 boolean writeLabels,
3178 boolean labelSelect,
3179 boolean pruneGarbage,
3180 boolean writeReferencers,
3181 boolean writeParamMappings
3182 ) throws java.io.IOException {
3186 writeGraph(mc+"COMPLETE"+String.format("%05d", numUpdate),
3195 public void writeGraph(String graphName,
3196 boolean writeLabels,
3197 boolean labelSelect,
3198 boolean pruneGarbage,
3199 boolean writeReferencers,
3200 boolean writeParamMappings
3201 ) throws java.io.IOException {
3203 // remove all non-word characters from the graph name so
3204 // the filename and identifier in dot don't cause errors
3205 graphName = graphName.replaceAll("[\\W]", "");
3207 BufferedWriter bw = new BufferedWriter(new FileWriter(graphName+".dot") );
3208 bw.write("digraph "+graphName+" {\n");
3210 HashSet<HeapRegionNode> visited = new HashSet<HeapRegionNode>();
3212 // then visit every heap region node
3213 Set s = id2hrn.entrySet();
3214 Iterator i = s.iterator();
3215 while( i.hasNext() ) {
3216 Map.Entry me = (Map.Entry)i.next();
3217 HeapRegionNode hrn = (HeapRegionNode) me.getValue();
3219 if( !pruneGarbage ||
3220 (hrn.isFlagged() && hrn.getID() > 0) ||
3221 hrn.getDescription().startsWith("param")
3224 if( !visited.contains(hrn) ) {
3225 traverseHeapRegionNodes(VISIT_HRN_WRITE_FULL,
3235 bw.write(" graphTitle[label=\""+graphName+"\",shape=box];\n");
3237 if( writeParamMappings ) {
3238 Set df = paramIndex2id.entrySet();
3239 Iterator ih = df.iterator();
3240 while( ih.hasNext() ) {
3241 Map.Entry meh = (Map.Entry)ih.next();
3242 Integer pi = (Integer) meh.getKey();
3243 Integer id = (Integer) meh.getValue();
3244 bw.write(" pindex"+pi+"[label=\""+pi+" to "+id+"\",shape=box];\n");
3248 // then visit every label node, useful for debugging
3250 s = td2ln.entrySet();
3252 while( i.hasNext() ) {
3253 Map.Entry me = (Map.Entry)i.next();
3254 LabelNode ln = (LabelNode) me.getValue();
3257 String labelStr = ln.getTempDescriptorString();
3258 if( labelStr.startsWith("___temp") ||
3259 labelStr.startsWith("___dst") ||
3260 labelStr.startsWith("___srctmp") ||
3261 labelStr.startsWith("___neverused") ) {
3266 //bw.write(" "+ln.toString() + ";\n");
3268 Iterator<ReferenceEdge> heapRegionsItr = ln.iteratorToReferencees();
3269 while( heapRegionsItr.hasNext() ) {
3270 ReferenceEdge edge = heapRegionsItr.next();
3271 HeapRegionNode hrn = edge.getDst();
3273 if( pruneGarbage && !visited.contains(hrn) ) {
3274 traverseHeapRegionNodes(VISIT_HRN_WRITE_FULL,
3282 bw.write(" " + ln.toString() +
3283 " -> " + hrn.toString() +
3284 "[label=\"" + edge.toGraphEdgeString() +
3295 protected void traverseHeapRegionNodes(int mode,
3299 HashSet<HeapRegionNode> visited,
3300 boolean writeReferencers
3301 ) throws java.io.IOException {
3303 if( visited.contains(hrn) ) {
3309 case VISIT_HRN_WRITE_FULL:
3311 String attributes = "[";
3313 if( hrn.isSingleObject() ) {
3314 attributes += "shape=box";
3316 attributes += "shape=Msquare";
3319 if( hrn.isFlagged() ) {
3320 attributes += ",style=filled,fillcolor=lightgrey";
3323 attributes += ",label=\"ID" +
3326 hrn.getDescription() +
3328 hrn.getAlphaString() +
3331 bw.write(" " + hrn.toString() + attributes + ";\n");
3336 // useful for debugging
3338 if( writeReferencers ) {
3339 OwnershipNode onRef = null;
3340 Iterator refItr = hrn.iteratorToReferencers();
3341 while( refItr.hasNext() ) {
3342 onRef = (OwnershipNode) refItr.next();
3345 case VISIT_HRN_WRITE_FULL:
3346 bw.write(" " + hrn.toString() +
3347 " -> " + onRef.toString() +
3348 "[color=lightgray];\n");
3355 Iterator<ReferenceEdge> childRegionsItr = hrn.iteratorToReferencees();
3356 while( childRegionsItr.hasNext() ) {
3357 ReferenceEdge edge = childRegionsItr.next();
3358 HeapRegionNode hrnChild = edge.getDst();
3361 case VISIT_HRN_WRITE_FULL:
3362 bw.write(" " + hrn.toString() +
3363 " -> " + hrnChild.toString() +
3364 "[label=\"" + edge.toGraphEdgeString() +
3369 traverseHeapRegionNodes(mode,