1 package Analysis.OwnershipAnalysis;
8 public class OwnershipGraph {
10 private int allocationDepth;
11 private TypeUtil typeUtil;
13 // there was already one other very similar reason
14 // for traversing heap nodes that is no longer needed
15 // instead of writing a new heap region visitor, use
16 // the existing method with a new mode to describe what
17 // actions to take during the traversal
18 protected static final int VISIT_HRN_WRITE_FULL = 0;
20 protected static TempDescriptor tdReturn = new TempDescriptor("_Return___");
23 public Hashtable<Integer, HeapRegionNode> id2hrn;
24 public Hashtable<TempDescriptor, LabelNode > td2ln;
25 public Hashtable<Integer, Integer > id2paramIndex;
26 public Hashtable<Integer, Integer > paramIndex2id;
27 public Hashtable<Integer, TempDescriptor> paramIndex2tdQ;
29 public HashSet<AllocationSite> allocationSites;
34 public OwnershipGraph(int allocationDepth, TypeUtil typeUtil) {
35 this.allocationDepth = allocationDepth;
36 this.typeUtil = typeUtil;
38 id2hrn = new Hashtable<Integer, HeapRegionNode>();
39 td2ln = new Hashtable<TempDescriptor, LabelNode >();
40 id2paramIndex = new Hashtable<Integer, Integer >();
41 paramIndex2id = new Hashtable<Integer, Integer >();
42 paramIndex2tdQ = new Hashtable<Integer, TempDescriptor>();
44 allocationSites = new HashSet <AllocationSite>();
48 // label nodes are much easier to deal with than
49 // heap region nodes. Whenever there is a request
50 // for the label node that is associated with a
51 // temp descriptor we can either find it or make a
52 // new one and return it. This is because temp
53 // descriptors are globally unique and every label
54 // node is mapped to exactly one temp descriptor.
55 protected LabelNode getLabelNodeFromTemp(TempDescriptor td) {
58 if( !td2ln.containsKey(td) ) {
59 td2ln.put(td, new LabelNode(td) );
66 // the reason for this method is to have the option
67 // creating new heap regions with specific IDs, or
68 // duplicating heap regions with specific IDs (especially
69 // in the merge() operation) or to create new heap
70 // regions with a new unique ID.
71 protected HeapRegionNode
72 createNewHeapRegionNode(Integer id,
73 boolean isSingleObject,
77 AllocationSite allocSite,
78 ReachabilitySet alpha,
82 id = OwnershipAnalysis.generateUniqueHeapRegionNodeID();
86 if( isFlagged || isParameter ) {
87 alpha = new ReachabilitySet(
94 alpha = new ReachabilitySet(
95 new TokenTupleSet().makeCanonical()
100 HeapRegionNode hrn = new HeapRegionNode(id,
113 ////////////////////////////////////////////////
115 // Low-level referencee and referencer methods
117 // These methods provide the lowest level for
118 // creating references between ownership nodes
119 // and handling the details of maintaining both
120 // list of referencers and referencees.
122 ////////////////////////////////////////////////
123 protected void addReferenceEdge(OwnershipNode referencer,
124 HeapRegionNode referencee,
125 ReferenceEdge edge) {
126 assert referencer != null;
127 assert referencee != null;
129 assert edge.getSrc() == referencer;
130 assert edge.getDst() == referencee;
132 referencer.addReferencee(edge);
133 referencee.addReferencer(edge);
136 protected void removeReferenceEdge(OwnershipNode referencer,
137 HeapRegionNode referencee,
138 FieldDescriptor fieldDesc) {
139 assert referencer != null;
140 assert referencee != null;
142 ReferenceEdge edge = referencer.getReferenceTo(referencee,
145 assert edge == referencee.getReferenceFrom(referencer,
148 referencer.removeReferencee(edge);
149 referencee.removeReferencer(edge);
152 protected void clearReferenceEdgesFrom(OwnershipNode referencer,
153 FieldDescriptor fieldDesc,
155 assert referencer != null;
157 // get a copy of the set to iterate over, otherwise
158 // we will be trying to take apart the set as we
159 // are iterating over it, which won't work
160 Iterator<ReferenceEdge> i = referencer.iteratorToReferenceesClone();
161 while( i.hasNext() ) {
162 ReferenceEdge edge = i.next();
164 if( removeAll || edge.getFieldDesc() == fieldDesc ) {
165 HeapRegionNode referencee = edge.getDst();
167 removeReferenceEdge(referencer,
169 edge.getFieldDesc() );
174 protected void clearReferenceEdgesTo(HeapRegionNode referencee,
175 FieldDescriptor fieldDesc,
177 assert referencee != null;
179 // get a copy of the set to iterate over, otherwise
180 // we will be trying to take apart the set as we
181 // are iterating over it, which won't work
182 Iterator<ReferenceEdge> i = referencee.iteratorToReferencersClone();
183 while( i.hasNext() ) {
184 ReferenceEdge edge = i.next();
186 if( removeAll || edge.getFieldDesc() == fieldDesc ) {
187 OwnershipNode referencer = edge.getSrc();
188 removeReferenceEdge(referencer,
190 edge.getFieldDesc() );
196 protected void propagateTokensOverNodes(HeapRegionNode nPrime,
198 HashSet<HeapRegionNode> nodesWithNewAlpha,
199 HashSet<ReferenceEdge> edgesWithNewBeta) {
201 HashSet<HeapRegionNode> todoNodes
202 = new HashSet<HeapRegionNode>();
203 todoNodes.add(nPrime);
205 HashSet<ReferenceEdge> todoEdges
206 = new HashSet<ReferenceEdge>();
208 Hashtable<HeapRegionNode, ChangeTupleSet> nodePlannedChanges
209 = new Hashtable<HeapRegionNode, ChangeTupleSet>();
210 nodePlannedChanges.put(nPrime, c0);
212 Hashtable<ReferenceEdge, ChangeTupleSet> edgePlannedChanges
213 = new Hashtable<ReferenceEdge, ChangeTupleSet>();
216 while( !todoNodes.isEmpty() ) {
217 HeapRegionNode n = todoNodes.iterator().next();
218 ChangeTupleSet C = nodePlannedChanges.get(n);
220 Iterator itrC = C.iterator();
221 while( itrC.hasNext() ) {
222 ChangeTuple c = (ChangeTuple) itrC.next();
224 if( n.getAlpha().contains(c.getSetToMatch() ) ) {
225 ReachabilitySet withChange = n.getAlpha().union(c.getSetToAdd() );
226 n.setAlphaNew(n.getAlphaNew().union(withChange) );
227 nodesWithNewAlpha.add(n);
231 Iterator<ReferenceEdge> referItr = n.iteratorToReferencers();
232 while( referItr.hasNext() ) {
233 ReferenceEdge edge = referItr.next();
236 if( !edgePlannedChanges.containsKey(edge) ) {
237 edgePlannedChanges.put(edge, new ChangeTupleSet().makeCanonical() );
240 edgePlannedChanges.put(edge, edgePlannedChanges.get(edge).union(C) );
243 Iterator<ReferenceEdge> refeeItr = n.iteratorToReferencees();
244 while( refeeItr.hasNext() ) {
245 ReferenceEdge edgeF = refeeItr.next();
246 HeapRegionNode m = edgeF.getDst();
248 ChangeTupleSet changesToPass = new ChangeTupleSet().makeCanonical();
250 Iterator<ChangeTuple> itrCprime = C.iterator();
251 while( itrCprime.hasNext() ) {
252 ChangeTuple c = itrCprime.next();
253 if( edgeF.getBeta().contains(c.getSetToMatch() ) ) {
254 changesToPass = changesToPass.union(c);
258 if( !changesToPass.isEmpty() ) {
259 if( !nodePlannedChanges.containsKey(m) ) {
260 nodePlannedChanges.put(m, new ChangeTupleSet().makeCanonical() );
263 ChangeTupleSet currentChanges = nodePlannedChanges.get(m);
265 if( !changesToPass.isSubset(currentChanges) ) {
267 nodePlannedChanges.put(m, currentChanges.union(changesToPass) );
276 propagateTokensOverEdges(todoEdges, edgePlannedChanges, edgesWithNewBeta);
280 protected void propagateTokensOverEdges(
281 HashSet<ReferenceEdge> todoEdges,
282 Hashtable<ReferenceEdge, ChangeTupleSet> edgePlannedChanges,
283 HashSet<ReferenceEdge> edgesWithNewBeta) {
286 while( !todoEdges.isEmpty() ) {
287 ReferenceEdge edgeE = todoEdges.iterator().next();
288 todoEdges.remove(edgeE);
290 if( !edgePlannedChanges.containsKey(edgeE) ) {
291 edgePlannedChanges.put(edgeE, new ChangeTupleSet().makeCanonical() );
294 ChangeTupleSet C = edgePlannedChanges.get(edgeE);
296 ChangeTupleSet changesToPass = new ChangeTupleSet().makeCanonical();
298 Iterator<ChangeTuple> itrC = C.iterator();
299 while( itrC.hasNext() ) {
300 ChangeTuple c = itrC.next();
301 if( edgeE.getBeta().contains(c.getSetToMatch() ) ) {
302 ReachabilitySet withChange = edgeE.getBeta().union(c.getSetToAdd() );
303 edgeE.setBetaNew(edgeE.getBetaNew().union(withChange) );
304 edgesWithNewBeta.add(edgeE);
305 changesToPass = changesToPass.union(c);
309 OwnershipNode onSrc = edgeE.getSrc();
311 if( !changesToPass.isEmpty() && onSrc instanceof HeapRegionNode ) {
312 HeapRegionNode n = (HeapRegionNode) onSrc;
314 Iterator<ReferenceEdge> referItr = n.iteratorToReferencers();
315 while( referItr.hasNext() ) {
316 ReferenceEdge edgeF = referItr.next();
318 if( !edgePlannedChanges.containsKey(edgeF) ) {
319 edgePlannedChanges.put(edgeF, new ChangeTupleSet().makeCanonical() );
322 ChangeTupleSet currentChanges = edgePlannedChanges.get(edgeF);
324 if( !changesToPass.isSubset(currentChanges) ) {
325 todoEdges.add(edgeF);
326 edgePlannedChanges.put(edgeF, currentChanges.union(changesToPass) );
334 ////////////////////////////////////////////////////
336 // Assignment Operation Methods
338 // These methods are high-level operations for
339 // modeling program assignment statements using
340 // the low-level reference create/remove methods
343 // The destination in an assignment statement is
344 // going to have new references. The method of
345 // determining the references depends on the type
346 // of the FlatNode assignment and the predicates
347 // of the nodes and edges involved.
349 ////////////////////////////////////////////////////
350 public void assignTempXEqualToTempY(TempDescriptor x,
353 LabelNode lnX = getLabelNodeFromTemp(x);
354 LabelNode lnY = getLabelNodeFromTemp(y);
356 clearReferenceEdgesFrom(lnX, null, true);
358 Iterator<ReferenceEdge> itrYhrn = lnY.iteratorToReferencees();
359 while( itrYhrn.hasNext() ) {
360 ReferenceEdge edgeY = itrYhrn.next();
361 HeapRegionNode referencee = edgeY.getDst();
362 ReferenceEdge edgeNew = edgeY.copy();
365 addReferenceEdge(lnX, referencee, edgeNew);
370 public void assignTempXEqualToTempYFieldF(TempDescriptor x,
373 LabelNode lnX = getLabelNodeFromTemp(x);
374 LabelNode lnY = getLabelNodeFromTemp(y);
376 clearReferenceEdgesFrom(lnX, null, true);
378 Iterator<ReferenceEdge> itrYhrn = lnY.iteratorToReferencees();
379 while( itrYhrn.hasNext() ) {
380 ReferenceEdge edgeY = itrYhrn.next();
381 HeapRegionNode hrnY = edgeY.getDst();
382 ReachabilitySet betaY = edgeY.getBeta();
384 Iterator<ReferenceEdge> itrHrnFhrn = hrnY.iteratorToReferencees();
385 while( itrHrnFhrn.hasNext() ) {
386 ReferenceEdge edgeHrn = itrHrnFhrn.next();
387 HeapRegionNode hrnHrn = edgeHrn.getDst();
388 ReachabilitySet betaHrn = edgeHrn.getBeta();
390 if( edgeHrn.getFieldDesc() == null ||
391 edgeHrn.getFieldDesc() == f ) {
393 ReferenceEdge edgeNew = new ReferenceEdge(lnX,
397 betaY.intersection(betaHrn) );
399 addReferenceEdge(lnX, hrnHrn, edgeNew);
406 public void assignTempXFieldFEqualToTempY(TempDescriptor x,
409 LabelNode lnX = getLabelNodeFromTemp(x);
410 LabelNode lnY = getLabelNodeFromTemp(y);
412 HashSet<HeapRegionNode> nodesWithNewAlpha = new HashSet<HeapRegionNode>();
413 HashSet<ReferenceEdge> edgesWithNewBeta = new HashSet<ReferenceEdge>();
415 Iterator<ReferenceEdge> itrXhrn = lnX.iteratorToReferencees();
416 while( itrXhrn.hasNext() ) {
417 ReferenceEdge edgeX = itrXhrn.next();
418 HeapRegionNode hrnX = edgeX.getDst();
419 ReachabilitySet betaX = edgeX.getBeta();
421 ReachabilitySet R = hrnX.getAlpha().intersection(edgeX.getBeta() );
423 Iterator<ReferenceEdge> itrYhrn = lnY.iteratorToReferencees();
424 while( itrYhrn.hasNext() ) {
425 ReferenceEdge edgeY = itrYhrn.next();
426 HeapRegionNode hrnY = edgeY.getDst();
427 ReachabilitySet O = edgeY.getBeta();
430 // propagate tokens over nodes starting from hrnSrc, and it will
431 // take care of propagating back up edges from any touched nodes
432 ChangeTupleSet Cy = O.unionUpArityToChangeSet(R);
433 propagateTokensOverNodes(hrnY, Cy, nodesWithNewAlpha, edgesWithNewBeta);
436 // then propagate back just up the edges from hrn
437 ChangeTupleSet Cx = R.unionUpArityToChangeSet(O);
440 HashSet<ReferenceEdge> todoEdges = new HashSet<ReferenceEdge>();
442 Hashtable<ReferenceEdge, ChangeTupleSet> edgePlannedChanges =
443 new Hashtable<ReferenceEdge, ChangeTupleSet>();
445 Iterator<ReferenceEdge> referItr = hrnX.iteratorToReferencers();
446 while( referItr.hasNext() ) {
447 ReferenceEdge edgeUpstream = referItr.next();
448 todoEdges.add(edgeUpstream);
449 edgePlannedChanges.put(edgeUpstream, Cx);
452 propagateTokensOverEdges(todoEdges,
456 // if edgeY's beta was updated, use that to calculate beta for new edge
457 // otherwise the edgeY didn't change and it is the source for the calc
458 ReachabilitySet sourceBetaForNewEdge;
459 if( edgesWithNewBeta.contains( edgeY ) ) {
460 sourceBetaForNewEdge = edgeY.getBetaNew();
462 sourceBetaForNewEdge = edgeY.getBeta();
465 // create the actual reference edge hrnX.f -> hrnY
466 ReferenceEdge edgeNew = new ReferenceEdge(hrnX,
470 sourceBetaForNewEdge.pruneBy(hrnX.getAlpha() )
472 addReferenceEdge(hrnX, hrnY, edgeNew);
476 // we can do a strong update here if one of two cases holds
477 // SAVE FOR LATER, WITHOUT STILL CORRECT
478 if( (hrnX.getNumReferencers() == 1) ||
479 ( lnX.getNumReferencees() == 1 && hrnX.isSingleObject() )
481 clearReferenceEdgesFrom( hrnX, f, false );
484 addReferenceEdge( hrnX, hrnY, edgeNew );
487 // if the field is null, or "any" field, then
488 // look to see if an any field already exists
489 // and merge with it, otherwise just add the edge
490 ReferenceEdge edgeExisting = hrnX.getReferenceTo( hrnY, f );
492 if( edgeExisting != null ) {
493 edgeExisting.setBetaNew(
494 edgeExisting.getBetaNew().union( edgeNew.getBeta() )
496 // a new edge here cannot be reflexive, so existing will
497 // always be also not reflexive anymore
498 edgeExisting.setIsInitialParamReflexive( false );
501 addReferenceEdge( hrnX, hrnY, edgeNew );
508 Iterator<HeapRegionNode> nodeItr = nodesWithNewAlpha.iterator();
509 while( nodeItr.hasNext() ) {
510 nodeItr.next().applyAlphaNew();
513 Iterator<ReferenceEdge> edgeItr = edgesWithNewBeta.iterator();
514 while( edgeItr.hasNext() ) {
515 edgeItr.next().applyBetaNew();
520 public void assignTempEqualToParamAlloc(TempDescriptor td,
522 Integer paramIndex) {
525 LabelNode lnParam = getLabelNodeFromTemp(td);
526 HeapRegionNode hrn = createNewHeapRegionNode(null,
533 "param" + paramIndex);
535 // this is a non-program-accessible label that picks up beta
536 // info to be used for fixing a caller of this method
537 TempDescriptor tdParamQ = new TempDescriptor(td+"specialQ");
538 LabelNode lnParamQ = getLabelNodeFromTemp(tdParamQ);
540 // keep track of heap regions that were created for
541 // parameter labels, the index of the parameter they
542 // are for is important when resolving method calls
543 Integer newID = hrn.getID();
544 assert !id2paramIndex.containsKey(newID);
545 assert !id2paramIndex.containsValue(paramIndex);
546 id2paramIndex.put(newID, paramIndex);
547 paramIndex2id.put(paramIndex, newID);
548 paramIndex2tdQ.put(paramIndex, tdParamQ);
550 ReachabilitySet beta = new ReachabilitySet(new TokenTuple(newID,
552 TokenTuple.ARITY_ONE).makeCanonical()
555 // heap regions for parameters are always multiple object (see above)
556 // and have a reference to themselves, because we can't know the
557 // structure of memory that is passed into the method. We're assuming
560 ReferenceEdge edgeFromLabel =
561 new ReferenceEdge(lnParam, hrn, null, false, beta);
563 ReferenceEdge edgeFromLabelQ =
564 new ReferenceEdge(lnParamQ, hrn, null, false, beta);
566 ReferenceEdge edgeReflexive =
567 new ReferenceEdge(hrn, hrn, null, true, beta);
569 addReferenceEdge(lnParam, hrn, edgeFromLabel);
570 addReferenceEdge(lnParamQ, hrn, edgeFromLabelQ);
571 addReferenceEdge(hrn, hrn, edgeReflexive);
575 public void assignReturnEqualToTemp(TempDescriptor x) {
577 LabelNode lnR = getLabelNodeFromTemp(tdReturn);
578 LabelNode lnX = getLabelNodeFromTemp(x);
580 clearReferenceEdgesFrom(lnR, null, true);
582 Iterator<ReferenceEdge> itrXhrn = lnX.iteratorToReferencees();
583 while( itrXhrn.hasNext() ) {
584 ReferenceEdge edgeX = itrXhrn.next();
585 HeapRegionNode referencee = edgeX.getDst();
586 ReferenceEdge edgeNew = edgeX.copy();
589 addReferenceEdge(lnR, referencee, edgeNew);
594 public void assignTempEqualToNewAlloc(TempDescriptor x,
601 // after the age operation the newest (or zero-ith oldest)
602 // node associated with the allocation site should have
603 // no references to it as if it were a newly allocated
604 // heap region, so make a reference to it to complete
607 Integer idNewest = as.getIthOldest(0);
608 HeapRegionNode hrnNewest = id2hrn.get(idNewest);
609 assert hrnNewest != null;
611 LabelNode lnX = getLabelNodeFromTemp(x);
612 clearReferenceEdgesFrom(lnX, null, true);
614 ReferenceEdge edgeNew =
615 new ReferenceEdge(lnX, hrnNewest, null, false, hrnNewest.getAlpha() );
617 addReferenceEdge(lnX, hrnNewest, edgeNew);
621 // use the allocation site (unique to entire analysis) to
622 // locate the heap region nodes in this ownership graph
623 // that should be aged. The process models the allocation
624 // of new objects and collects all the oldest allocations
625 // in a summary node to allow for a finite analysis
627 // There is an additional property of this method. After
628 // running it on a particular ownership graph (many graphs
629 // may have heap regions related to the same allocation site)
630 // the heap region node objects in this ownership graph will be
631 // allocated. Therefore, after aging a graph for an allocation
632 // site, attempts to retrieve the heap region nodes using the
633 // integer id's contained in the allocation site should always
634 // return non-null heap regions.
635 public void age(AllocationSite as) {
637 // aging adds this allocation site to the graph's
638 // list of sites that exist in the graph, or does
639 // nothing if the site is already in the list
640 allocationSites.add(as);
642 // get the summary node for the allocation site in the context
643 // of this particular ownership graph
644 HeapRegionNode hrnSummary = getSummaryNode(as);
646 // merge oldest node into summary
647 Integer idK = as.getOldest();
648 HeapRegionNode hrnK = id2hrn.get(idK);
649 mergeIntoSummary(hrnK, hrnSummary);
651 // move down the line of heap region nodes
652 // clobbering the ith and transferring all references
653 // to and from i-1 to node i. Note that this clobbers
654 // the oldest node (hrnK) that was just merged into
656 for( int i = allocationDepth - 1; i > 0; --i ) {
658 // move references from the i-1 oldest to the ith oldest
659 Integer idIth = as.getIthOldest(i);
660 HeapRegionNode hrnI = id2hrn.get(idIth);
661 Integer idImin1th = as.getIthOldest(i - 1);
662 HeapRegionNode hrnImin1 = id2hrn.get(idImin1th);
664 transferOnto(hrnImin1, hrnI);
667 // as stated above, the newest node should have had its
668 // references moved over to the second oldest, so we wipe newest
669 // in preparation for being the new object to assign something to
670 Integer id0th = as.getIthOldest(0);
671 HeapRegionNode hrn0 = id2hrn.get(id0th);
674 // clear all references in and out of newest node
675 clearReferenceEdgesFrom(hrn0, null, true);
676 clearReferenceEdgesTo(hrn0, null, true);
679 // now tokens in reachability sets need to "age" also
680 Iterator itrAllLabelNodes = td2ln.entrySet().iterator();
681 while( itrAllLabelNodes.hasNext() ) {
682 Map.Entry me = (Map.Entry)itrAllLabelNodes.next();
683 LabelNode ln = (LabelNode) me.getValue();
685 Iterator<ReferenceEdge> itrEdges = ln.iteratorToReferencees();
686 while( itrEdges.hasNext() ) {
687 ageTokens(as, itrEdges.next() );
691 Iterator itrAllHRNodes = id2hrn.entrySet().iterator();
692 while( itrAllHRNodes.hasNext() ) {
693 Map.Entry me = (Map.Entry)itrAllHRNodes.next();
694 HeapRegionNode hrnToAge = (HeapRegionNode) me.getValue();
696 ageTokens(as, hrnToAge);
698 Iterator<ReferenceEdge> itrEdges = hrnToAge.iteratorToReferencees();
699 while( itrEdges.hasNext() ) {
700 ageTokens(as, itrEdges.next() );
705 // after tokens have been aged, reset newest node's reachability
706 if( hrn0.isFlagged() ) {
707 hrn0.setAlpha(new ReachabilitySet(
709 new TokenTuple(hrn0).makeCanonical()
714 hrn0.setAlpha(new ReachabilitySet(
715 new TokenTupleSet().makeCanonical()
722 protected HeapRegionNode getSummaryNode(AllocationSite as) {
724 Integer idSummary = as.getSummary();
725 HeapRegionNode hrnSummary = id2hrn.get(idSummary);
727 // If this is null then we haven't touched this allocation site
728 // in the context of the current ownership graph, so allocate
729 // heap region nodes appropriate for the entire allocation site.
730 // This should only happen once per ownership graph per allocation site,
731 // and a particular integer id can be used to locate the heap region
732 // in different ownership graphs that represents the same part of an
734 if( hrnSummary == null ) {
736 boolean hasFlags = false;
737 if( as.getType().isClass() ) {
738 hasFlags = as.getType().getClassDesc().hasFlags();
741 hrnSummary = createNewHeapRegionNode(idSummary,
748 as + "\\n" + as.getType() + "\\nsummary");
750 for( int i = 0; i < as.getAllocationDepth(); ++i ) {
751 Integer idIth = as.getIthOldest(i);
752 assert !id2hrn.containsKey(idIth);
753 createNewHeapRegionNode(idIth,
760 as + "\\n" + as.getType() + "\\n" + i + " oldest");
768 protected HeapRegionNode getShadowSummaryNode(AllocationSite as) {
770 Integer idShadowSummary = as.getSummaryShadow();
771 HeapRegionNode hrnShadowSummary = id2hrn.get(idShadowSummary);
773 if( hrnShadowSummary == null ) {
775 boolean hasFlags = false;
776 if( as.getType().isClass() ) {
777 hasFlags = as.getType().getClassDesc().hasFlags();
780 hrnShadowSummary = createNewHeapRegionNode(idShadowSummary,
787 as + "\\n" + as.getType() + "\\nshadowSum");
789 for( int i = 0; i < as.getAllocationDepth(); ++i ) {
790 Integer idShadowIth = as.getIthOldestShadow(i);
791 assert !id2hrn.containsKey(idShadowIth);
792 createNewHeapRegionNode(idShadowIth,
799 as + "\\n" + as.getType() + "\\n" + i + " shadow");
803 return hrnShadowSummary;
807 protected void mergeIntoSummary(HeapRegionNode hrn, HeapRegionNode hrnSummary) {
808 assert hrnSummary.isNewSummary();
810 // transfer references _from_ hrn over to hrnSummary
811 Iterator<ReferenceEdge> itrReferencee = hrn.iteratorToReferencees();
812 while( itrReferencee.hasNext() ) {
813 ReferenceEdge edge = itrReferencee.next();
814 ReferenceEdge edgeMerged = edge.copy();
815 edgeMerged.setSrc(hrnSummary);
817 HeapRegionNode hrnReferencee = edge.getDst();
818 ReferenceEdge edgeSummary = hrnSummary.getReferenceTo(hrnReferencee, edge.getFieldDesc() );
820 if( edgeSummary == null ) {
821 // the merge is trivial, nothing to be done
823 // otherwise an edge from the referencer to hrnSummary exists already
824 // and the edge referencer->hrn should be merged with it
825 edgeMerged.setBeta(edgeMerged.getBeta().union(edgeSummary.getBeta() ) );
828 addReferenceEdge(hrnSummary, hrnReferencee, edgeMerged);
831 // next transfer references _to_ hrn over to hrnSummary
832 Iterator<ReferenceEdge> itrReferencer = hrn.iteratorToReferencers();
833 while( itrReferencer.hasNext() ) {
834 ReferenceEdge edge = itrReferencer.next();
835 ReferenceEdge edgeMerged = edge.copy();
836 edgeMerged.setDst(hrnSummary);
838 OwnershipNode onReferencer = edge.getSrc();
839 ReferenceEdge edgeSummary = onReferencer.getReferenceTo(hrnSummary, edge.getFieldDesc() );
841 if( edgeSummary == null ) {
842 // the merge is trivial, nothing to be done
844 // otherwise an edge from the referencer to alpha_S exists already
845 // and the edge referencer->alpha_K should be merged with it
846 edgeMerged.setBeta(edgeMerged.getBeta().union(edgeSummary.getBeta() ) );
849 addReferenceEdge(onReferencer, hrnSummary, edgeMerged);
852 // then merge hrn reachability into hrnSummary
853 hrnSummary.setAlpha(hrnSummary.getAlpha().union(hrn.getAlpha() ) );
857 protected void transferOnto(HeapRegionNode hrnA, HeapRegionNode hrnB) {
859 // clear references in and out of node i
860 clearReferenceEdgesFrom(hrnB, null, true);
861 clearReferenceEdgesTo(hrnB, null, true);
863 // copy each edge in and out of A to B
864 Iterator<ReferenceEdge> itrReferencee = hrnA.iteratorToReferencees();
865 while( itrReferencee.hasNext() ) {
866 ReferenceEdge edge = itrReferencee.next();
867 HeapRegionNode hrnReferencee = edge.getDst();
868 ReferenceEdge edgeNew = edge.copy();
869 edgeNew.setSrc(hrnB);
871 addReferenceEdge(hrnB, hrnReferencee, edgeNew);
874 Iterator<ReferenceEdge> itrReferencer = hrnA.iteratorToReferencers();
875 while( itrReferencer.hasNext() ) {
876 ReferenceEdge edge = itrReferencer.next();
877 OwnershipNode onReferencer = edge.getSrc();
878 ReferenceEdge edgeNew = edge.copy();
879 edgeNew.setDst(hrnB);
881 addReferenceEdge(onReferencer, hrnB, edgeNew);
884 // replace hrnB reachability with hrnA's
885 hrnB.setAlpha(hrnA.getAlpha() );
889 protected void ageTokens(AllocationSite as, ReferenceEdge edge) {
890 edge.setBeta(edge.getBeta().ageTokens(as) );
893 protected void ageTokens(AllocationSite as, HeapRegionNode hrn) {
894 hrn.setAlpha(hrn.getAlpha().ageTokens(as) );
898 public void resolveMethodCall(FlatCall fc,
901 OwnershipGraph ogCallee) {
903 // define rewrite rules and other structures to organize
904 // data by parameter/argument index
905 Hashtable<Integer, ReachabilitySet> paramIndex2rewriteH =
906 new Hashtable<Integer, ReachabilitySet>();
908 Hashtable<Integer, ReachabilitySet> paramIndex2rewriteJ =
909 new Hashtable<Integer, ReachabilitySet>();
911 Hashtable<Integer, ReachabilitySet> paramIndex2rewriteK =
912 new Hashtable<Integer, ReachabilitySet>();
914 Hashtable<Integer, ReachabilitySet> paramIndex2rewrite_d =
915 new Hashtable<Integer, ReachabilitySet>();
917 Hashtable<Integer, ReachabilitySet> paramIndex2rewriteD =
918 new Hashtable<Integer, ReachabilitySet>();
920 // helpful structures
921 Hashtable<TokenTuple, Integer> paramToken2paramIndex =
922 new Hashtable<TokenTuple, Integer>();
924 Hashtable<Integer, TokenTuple> paramIndex2paramToken =
925 new Hashtable<Integer, TokenTuple>();
927 Hashtable<TokenTuple, Integer> paramTokenPlus2paramIndex =
928 new Hashtable<TokenTuple, Integer>();
930 Hashtable<Integer, TokenTuple> paramIndex2paramTokenPlus =
931 new Hashtable<Integer, TokenTuple>();
933 Hashtable<Integer, LabelNode> paramIndex2ln =
934 new Hashtable<Integer, LabelNode>();
936 Hashtable<Integer, HashSet<HeapRegionNode> > paramIndex2reachableCallerNodes =
937 new Hashtable<Integer, HashSet<HeapRegionNode> >();
940 // add a bogus entry with the identity rule for easy rewrite
941 // of new callee nodes and edges, doesn't belong to any parameter
942 Integer bogusID = new Integer(-1);
943 Integer bogusIndex = new Integer(-1);
944 TokenTuple bogusToken = new TokenTuple(bogusID, true, TokenTuple.ARITY_ONE).makeCanonical();
945 TokenTuple bogusTokenPlus = new TokenTuple(bogusID, true, TokenTuple.ARITY_ONEORMORE).makeCanonical();
946 ReachabilitySet rsIdentity =
948 new TokenTupleSet(bogusToken).makeCanonical()
951 paramIndex2rewriteH.put(bogusIndex, rsIdentity);
952 paramIndex2rewriteJ.put(bogusIndex, rsIdentity);
953 paramToken2paramIndex.put(bogusToken, bogusIndex);
954 paramIndex2paramToken.put(bogusIndex, bogusToken);
955 paramTokenPlus2paramIndex.put(bogusTokenPlus, bogusIndex);
956 paramIndex2paramTokenPlus.put(bogusIndex, bogusTokenPlus);
959 for( int i = 0; i < fm.numParameters(); ++i ) {
960 Integer paramIndex = new Integer(i);
962 assert ogCallee.paramIndex2id.containsKey(paramIndex);
963 Integer idParam = ogCallee.paramIndex2id.get(paramIndex);
965 assert ogCallee.id2hrn.containsKey(idParam);
966 HeapRegionNode hrnParam = ogCallee.id2hrn.get(idParam);
967 assert hrnParam != null;
968 paramIndex2rewriteH.put(paramIndex,
970 toShadowTokens(ogCallee, hrnParam.getAlpha() )
973 ReferenceEdge edgeReflexive_i = hrnParam.getReferenceTo(hrnParam, null);
974 assert edgeReflexive_i != null;
975 paramIndex2rewriteJ.put(paramIndex,
976 toShadowTokens(ogCallee, edgeReflexive_i.getBeta() )
979 TempDescriptor tdParamQ = ogCallee.paramIndex2tdQ.get(paramIndex);
980 assert tdParamQ != null;
981 LabelNode lnParamQ = ogCallee.td2ln.get(tdParamQ);
982 assert lnParamQ != null;
983 ReferenceEdge edgeSpecialQ_i = lnParamQ.getReferenceTo(hrnParam, null);
984 assert edgeSpecialQ_i != null;
985 paramIndex2rewriteK.put(paramIndex,
986 toShadowTokens(ogCallee, edgeSpecialQ_i.getBeta() )
989 TokenTuple p_i = new TokenTuple(hrnParam.getID(),
991 TokenTuple.ARITY_ONE).makeCanonical();
992 paramToken2paramIndex.put(p_i, paramIndex);
993 paramIndex2paramToken.put(paramIndex, p_i);
995 TokenTuple p_i_plus = new TokenTuple(hrnParam.getID(),
997 TokenTuple.ARITY_ONEORMORE).makeCanonical();
998 paramTokenPlus2paramIndex.put(p_i_plus, paramIndex);
999 paramIndex2paramTokenPlus.put(paramIndex, p_i_plus);
1001 // now depending on whether the callee is static or not
1002 // we need to account for a "this" argument in order to
1003 // find the matching argument in the caller context
1004 TempDescriptor argTemp_i;
1006 argTemp_i = fc.getArg(paramIndex);
1008 if( paramIndex.equals(0) ) {
1009 argTemp_i = fc.getThis();
1011 argTemp_i = fc.getArg(paramIndex - 1);
1015 // in non-static methods there is a "this" pointer
1016 // that should be taken into account
1018 assert fc.numArgs() == fm.numParameters();
1020 assert fc.numArgs() + 1 == fm.numParameters();
1023 LabelNode argLabel_i = getLabelNodeFromTemp(argTemp_i);
1024 paramIndex2ln.put(paramIndex, argLabel_i);
1026 ReachabilitySet d_i = new ReachabilitySet().makeCanonical();
1027 Iterator<ReferenceEdge> edgeItr = argLabel_i.iteratorToReferencees();
1028 while( edgeItr.hasNext() ) {
1029 ReferenceEdge edge = edgeItr.next();
1030 d_i = d_i.union(edge.getBeta());
1032 paramIndex2rewrite_d.put(paramIndex, d_i);
1034 ReachabilitySet D_i = d_i.exhaustiveArityCombinations();
1035 paramIndex2rewriteD.put(paramIndex, D_i);
1039 HashSet<HeapRegionNode> nodesWithNewAlpha = new HashSet<HeapRegionNode>();
1040 HashSet<ReferenceEdge> edgesWithNewBeta = new HashSet<ReferenceEdge>();
1042 HashSet<ReferenceEdge> edgesReachable = new HashSet<ReferenceEdge>();
1043 HashSet<ReferenceEdge> edgesUpstream = new HashSet<ReferenceEdge>();
1045 Iterator lnArgItr = paramIndex2ln.entrySet().iterator();
1046 while( lnArgItr.hasNext() ) {
1047 Map.Entry me = (Map.Entry)lnArgItr.next();
1048 Integer index = (Integer) me.getKey();
1049 LabelNode lnArg_i = (LabelNode) me.getValue();
1051 // rewrite alpha for the nodes reachable from argument label i
1052 HashSet<HeapRegionNode> reachableNodes = new HashSet<HeapRegionNode>();
1053 HashSet<HeapRegionNode> todoNodes = new HashSet<HeapRegionNode>();
1055 // to find all reachable nodes, start with label referencees
1056 Iterator<ReferenceEdge> edgeArgItr = lnArg_i.iteratorToReferencees();
1057 while( edgeArgItr.hasNext() ) {
1058 ReferenceEdge edge = edgeArgItr.next();
1059 todoNodes.add(edge.getDst() );
1062 // then follow links until all reachable nodes have been found
1063 while( !todoNodes.isEmpty() ) {
1064 HeapRegionNode hrn = todoNodes.iterator().next();
1065 todoNodes.remove(hrn);
1066 reachableNodes.add(hrn);
1068 Iterator<ReferenceEdge> edgeItr = hrn.iteratorToReferencees();
1069 while( edgeItr.hasNext() ) {
1070 ReferenceEdge edge = edgeItr.next();
1072 if( !reachableNodes.contains(edge.getDst() ) ) {
1073 todoNodes.add(edge.getDst() );
1079 paramIndex2reachableCallerNodes.put(index, reachableNodes);
1081 // now iterate over reachable nodes to update their alpha, and
1082 // classify edges found as "argument reachable" or "upstream"
1083 Iterator<HeapRegionNode> hrnItr = reachableNodes.iterator();
1084 while( hrnItr.hasNext() ) {
1085 HeapRegionNode hrn = hrnItr.next();
1087 rewriteCallerReachability(index,
1090 paramIndex2rewriteH.get(index),
1091 paramIndex2rewrite_d,
1092 paramIndex2rewriteD,
1093 paramIndex2paramToken.get(index),
1094 paramToken2paramIndex,
1095 paramTokenPlus2paramIndex,
1099 nodesWithNewAlpha.add(hrn);
1101 // look at all incoming edges to the reachable nodes
1102 // and sort them as edges reachable from the argument
1103 // label node, or upstream edges
1104 Iterator<ReferenceEdge> edgeItr = hrn.iteratorToReferencers();
1105 while( edgeItr.hasNext() ) {
1106 ReferenceEdge edge = edgeItr.next();
1108 OwnershipNode on = edge.getSrc();
1110 if( on instanceof LabelNode ) {
1112 LabelNode ln0 = (LabelNode) on;
1113 if( ln0.equals(lnArg_i) ) {
1114 edgesReachable.add(edge);
1116 edgesUpstream.add(edge);
1121 HeapRegionNode hrn0 = (HeapRegionNode) on;
1122 if( reachableNodes.contains(hrn0) ) {
1123 edgesReachable.add(edge);
1125 edgesUpstream.add(edge);
1131 // update reachable edges
1132 Iterator<ReferenceEdge> edgeReachableItr = edgesReachable.iterator();
1133 while( edgeReachableItr.hasNext() ) {
1134 ReferenceEdge edgeReachable = edgeReachableItr.next();
1136 rewriteCallerReachability(index,
1139 paramIndex2rewriteJ.get(index),
1140 paramIndex2rewrite_d,
1141 paramIndex2rewriteD,
1142 paramIndex2paramToken.get(index),
1143 paramToken2paramIndex,
1144 paramTokenPlus2paramIndex,
1148 edgesWithNewBeta.add(edgeReachable);
1151 // update upstream edges
1152 Hashtable<ReferenceEdge, ChangeTupleSet> edgeUpstreamPlannedChanges =
1153 new Hashtable<ReferenceEdge, ChangeTupleSet>();
1155 Iterator<ReferenceEdge> edgeUpstreamItr = edgesUpstream.iterator();
1156 while( edgeUpstreamItr.hasNext() ) {
1157 ReferenceEdge edgeUpstream = edgeUpstreamItr.next();
1159 rewriteCallerReachability(index,
1162 paramIndex2rewriteK.get(index),
1163 paramIndex2rewrite_d,
1164 paramIndex2rewriteD,
1165 paramIndex2paramToken.get(index),
1166 paramToken2paramIndex,
1167 paramTokenPlus2paramIndex,
1169 edgeUpstreamPlannedChanges);
1171 edgesWithNewBeta.add(edgeUpstream);
1174 propagateTokensOverEdges(edgesUpstream,
1175 edgeUpstreamPlannedChanges,
1180 // commit changes to alpha and beta
1181 Iterator<HeapRegionNode> nodeItr = nodesWithNewAlpha.iterator();
1182 while( nodeItr.hasNext() ) {
1183 nodeItr.next().applyAlphaNew();
1186 Iterator<ReferenceEdge> edgeItr = edgesWithNewBeta.iterator();
1187 while( edgeItr.hasNext() ) {
1188 edgeItr.next().applyBetaNew();
1192 // verify the existence of allocation sites and their
1193 // shadows from the callee in the context of this caller graph
1194 // then map allocated nodes of callee onto the caller shadows
1196 Iterator<AllocationSite> asItr = ogCallee.allocationSites.iterator();
1197 while( asItr.hasNext() ) {
1198 AllocationSite allocSite = asItr.next();
1199 HeapRegionNode hrnSummary = getSummaryNode(allocSite);
1201 // assert that the shadow nodes have no reference edges
1202 // because they're brand new to the graph, or last time
1203 // they were used they should have been cleared of edges
1204 HeapRegionNode hrnShadowSummary = getShadowSummaryNode(allocSite);
1205 assert hrnShadowSummary.getNumReferencers() == 0;
1206 assert hrnShadowSummary.getNumReferencees() == 0;
1208 // then bring g_ij onto g'_ij and rewrite
1209 transferOnto(hrnSummary, hrnShadowSummary);
1211 HeapRegionNode hrnSummaryCallee = ogCallee.getSummaryNode(allocSite);
1212 hrnShadowSummary.setAlpha(toShadowTokens(ogCallee, hrnSummaryCallee.getAlpha() ) );
1214 // shadow nodes only are touched by a rewrite one time,
1215 // so rewrite and immediately commit--and they don't belong
1216 // to a particular parameter, so use a bogus param index
1217 // that pulls a self-rewrite out of H
1218 rewriteCallerReachability(bogusIndex,
1221 hrnShadowSummary.getAlpha(),
1222 paramIndex2rewrite_d,
1223 paramIndex2rewriteD,
1225 paramToken2paramIndex,
1226 paramTokenPlus2paramIndex,
1230 hrnShadowSummary.applyAlphaNew();
1233 for( int i = 0; i < allocSite.getAllocationDepth(); ++i ) {
1234 Integer idIth = allocSite.getIthOldest(i);
1235 assert id2hrn.containsKey(idIth);
1236 HeapRegionNode hrnIth = id2hrn.get(idIth);
1238 Integer idShadowIth = -(allocSite.getIthOldest(i));
1239 assert id2hrn.containsKey(idShadowIth);
1240 HeapRegionNode hrnIthShadow = id2hrn.get(idShadowIth);
1241 assert hrnIthShadow.getNumReferencers() == 0;
1242 assert hrnIthShadow.getNumReferencees() == 0;
1244 transferOnto(hrnIth, hrnIthShadow);
1246 assert ogCallee.id2hrn.containsKey(idIth);
1247 HeapRegionNode hrnIthCallee = ogCallee.id2hrn.get(idIth);
1248 hrnIthShadow.setAlpha(toShadowTokens(ogCallee, hrnIthCallee.getAlpha() ) );
1250 rewriteCallerReachability(bogusIndex,
1253 hrnIthShadow.getAlpha(),
1254 paramIndex2rewrite_d,
1255 paramIndex2rewriteD,
1257 paramToken2paramIndex,
1258 paramTokenPlus2paramIndex,
1262 hrnIthShadow.applyAlphaNew();
1267 // for every heap region->heap region edge in the
1268 // callee graph, create the matching edge or edges
1269 // in the caller graph
1270 Set sCallee = ogCallee.id2hrn.entrySet();
1271 Iterator iCallee = sCallee.iterator();
1272 while( iCallee.hasNext() ) {
1273 Map.Entry meCallee = (Map.Entry)iCallee.next();
1274 Integer idCallee = (Integer) meCallee.getKey();
1275 HeapRegionNode hrnCallee = (HeapRegionNode) meCallee.getValue();
1277 Iterator<ReferenceEdge> heapRegionsItrCallee = hrnCallee.iteratorToReferencees();
1278 while( heapRegionsItrCallee.hasNext() ) {
1279 ReferenceEdge edgeCallee = heapRegionsItrCallee.next();
1280 HeapRegionNode hrnChildCallee = edgeCallee.getDst();
1281 Integer idChildCallee = hrnChildCallee.getID();
1283 // only address this edge if it is not a special reflexive edge
1284 if( !edgeCallee.isInitialParamReflexive() ) {
1286 // now we know that in the callee method's ownership graph
1287 // there is a heap region->heap region reference edge given
1288 // by heap region pointers:
1289 // hrnCallee -> heapChildCallee
1291 // or by the ownership-graph independent ID's:
1292 // idCallee -> idChildCallee
1294 // make the edge with src and dst so beta info is
1295 // calculated once, then copy it for each new edge in caller
1296 ReferenceEdge edgeNewInCallerTemplate = new ReferenceEdge(null,
1298 edgeCallee.getFieldDesc(),
1300 toShadowTokens(ogCallee,
1301 edgeCallee.getBeta() )
1303 rewriteCallerReachability(bogusIndex,
1305 edgeNewInCallerTemplate,
1306 edgeNewInCallerTemplate.getBeta(),
1307 paramIndex2rewrite_d,
1308 paramIndex2rewriteD,
1310 paramToken2paramIndex,
1311 paramTokenPlus2paramIndex,
1315 edgeNewInCallerTemplate.applyBetaNew();
1318 // So now make a set of possible source heaps in the caller graph
1319 // and a set of destination heaps in the caller graph, and make
1320 // a reference edge in the caller for every possible (src,dst) pair
1321 HashSet<HeapRegionNode> possibleCallerSrcs =
1322 getHRNSetThatPossiblyMapToCalleeHRN(ogCallee,
1323 (HeapRegionNode) edgeCallee.getSrc(),
1324 paramIndex2reachableCallerNodes);
1326 HashSet<HeapRegionNode> possibleCallerDsts =
1327 getHRNSetThatPossiblyMapToCalleeHRN(ogCallee,
1328 edgeCallee.getDst(),
1329 paramIndex2reachableCallerNodes);
1332 // make every possible pair of {srcSet} -> {dstSet} edges in the caller
1333 Iterator srcItr = possibleCallerSrcs.iterator();
1334 while( srcItr.hasNext() ) {
1335 HeapRegionNode src = (HeapRegionNode) srcItr.next();
1337 if( !hasMatchingField(src, edgeCallee) ) {
1338 // prune this source node possibility
1342 Iterator dstItr = possibleCallerDsts.iterator();
1343 while( dstItr.hasNext() ) {
1344 HeapRegionNode dst = (HeapRegionNode) dstItr.next();
1346 if( !hasMatchingType(edgeCallee, dst) ) {
1351 // otherwise the caller src and dst pair can match the edge, so make it
1352 ReferenceEdge edgeNewInCaller = edgeNewInCallerTemplate.copy();
1353 edgeNewInCaller.setSrc(src);
1354 edgeNewInCaller.setDst(dst);
1356 ReferenceEdge edgeExisting = src.getReferenceTo(dst, edgeNewInCaller.getFieldDesc() );
1357 if( edgeExisting == null ) {
1358 // if this edge doesn't exist in the caller, create it
1359 addReferenceEdge(src, dst, edgeNewInCaller);
1361 // if it already exists, merge with it
1362 edgeExisting.setBeta(edgeExisting.getBeta().union(edgeNewInCaller.getBeta() ) );
1371 // return value may need to be assigned in caller
1372 TempDescriptor returnTemp = fc.getReturnTemp();
1373 if( returnTemp != null && !returnTemp.getType().isImmutable() ) {
1375 LabelNode lnLhsCaller = getLabelNodeFromTemp(returnTemp);
1376 clearReferenceEdgesFrom(lnLhsCaller, null, true);
1378 LabelNode lnReturnCallee = ogCallee.getLabelNodeFromTemp(tdReturn);
1379 Iterator<ReferenceEdge> edgeCalleeItr = lnReturnCallee.iteratorToReferencees();
1380 while( edgeCalleeItr.hasNext() ) {
1381 ReferenceEdge edgeCallee = edgeCalleeItr.next();
1383 ReferenceEdge edgeNewInCallerTemplate = new ReferenceEdge(null,
1385 edgeCallee.getFieldDesc(),
1387 toShadowTokens(ogCallee,
1388 edgeCallee.getBeta() )
1390 rewriteCallerReachability(bogusIndex,
1392 edgeNewInCallerTemplate,
1393 edgeNewInCallerTemplate.getBeta(),
1394 paramIndex2rewrite_d,
1395 paramIndex2rewriteD,
1397 paramToken2paramIndex,
1398 paramTokenPlus2paramIndex,
1402 edgeNewInCallerTemplate.applyBetaNew();
1405 HashSet<HeapRegionNode> assignCallerRhs =
1406 getHRNSetThatPossiblyMapToCalleeHRN(ogCallee,
1407 edgeCallee.getDst(),
1408 paramIndex2reachableCallerNodes);
1410 Iterator<HeapRegionNode> itrHrn = assignCallerRhs.iterator();
1411 while( itrHrn.hasNext() ) {
1412 HeapRegionNode hrnCaller = itrHrn.next();
1414 if( !hasMatchingType(edgeCallee, hrnCaller) ) {
1419 // otherwise caller node can match callee edge, so make it
1420 ReferenceEdge edgeNewInCaller = edgeNewInCallerTemplate.copy();
1421 edgeNewInCaller.setSrc(lnLhsCaller);
1422 edgeNewInCaller.setDst(hrnCaller);
1424 ReferenceEdge edgeExisting = lnLhsCaller.getReferenceTo(hrnCaller, edgeNewInCaller.getFieldDesc() );
1425 if( edgeExisting == null ) {
1427 // if this edge doesn't exist in the caller, create it
1428 addReferenceEdge(lnLhsCaller, hrnCaller, edgeNewInCaller);
1430 // if it already exists, merge with it
1431 edgeExisting.setBeta(edgeExisting.getBeta().union(edgeNewInCaller.getBeta() ) );
1438 // merge the shadow nodes of allocation sites back down to normal capacity
1439 Iterator<AllocationSite> allocItr = ogCallee.allocationSites.iterator();
1440 while( allocItr.hasNext() ) {
1441 AllocationSite as = allocItr.next();
1443 // first age each allocation site enough times to make room for the shadow nodes
1444 for( int i = 0; i < as.getAllocationDepth(); ++i ) {
1448 // then merge the shadow summary into the normal summary
1449 HeapRegionNode hrnSummary = getSummaryNode(as);
1450 assert hrnSummary != null;
1452 HeapRegionNode hrnSummaryShadow = getShadowSummaryNode(as);
1453 assert hrnSummaryShadow != null;
1455 mergeIntoSummary(hrnSummaryShadow, hrnSummary);
1457 // then clear off after merge
1458 clearReferenceEdgesFrom(hrnSummaryShadow, null, true);
1459 clearReferenceEdgesTo(hrnSummaryShadow, null, true);
1460 hrnSummaryShadow.setAlpha(new ReachabilitySet().makeCanonical() );
1462 // then transplant shadow nodes onto the now clean normal nodes
1463 for( int i = 0; i < as.getAllocationDepth(); ++i ) {
1465 Integer idIth = as.getIthOldest(i);
1466 HeapRegionNode hrnIth = id2hrn.get(idIth);
1468 Integer idIthShadow = as.getIthOldestShadow(i);
1469 HeapRegionNode hrnIthShadow = id2hrn.get(idIthShadow);
1471 transferOnto(hrnIthShadow, hrnIth);
1473 // clear off shadow nodes after transfer
1474 clearReferenceEdgesFrom(hrnIthShadow, null, true);
1475 clearReferenceEdgesTo(hrnIthShadow, null, true);
1476 hrnIthShadow.setAlpha(new ReachabilitySet().makeCanonical() );
1479 // finally, globally change shadow tokens into normal tokens
1480 Iterator itrAllLabelNodes = td2ln.entrySet().iterator();
1481 while( itrAllLabelNodes.hasNext() ) {
1482 Map.Entry me = (Map.Entry)itrAllLabelNodes.next();
1483 LabelNode ln = (LabelNode) me.getValue();
1485 Iterator<ReferenceEdge> itrEdges = ln.iteratorToReferencees();
1486 while( itrEdges.hasNext() ) {
1487 unshadowTokens(as, itrEdges.next() );
1491 Iterator itrAllHRNodes = id2hrn.entrySet().iterator();
1492 while( itrAllHRNodes.hasNext() ) {
1493 Map.Entry me = (Map.Entry)itrAllHRNodes.next();
1494 HeapRegionNode hrnToAge = (HeapRegionNode) me.getValue();
1496 unshadowTokens(as, hrnToAge);
1498 Iterator<ReferenceEdge> itrEdges = hrnToAge.iteratorToReferencees();
1499 while( itrEdges.hasNext() ) {
1500 unshadowTokens(as, itrEdges.next() );
1507 protected boolean hasMatchingField(HeapRegionNode src, ReferenceEdge edge) {
1509 // if no allocation site, then it's a match-everything region
1510 AllocationSite asSrc = src.getAllocationSite();
1511 if( asSrc == null ) {
1515 TypeDescriptor tdSrc = asSrc.getType();
1516 assert tdSrc != null;
1518 // if it's not a class, it doesn't have any fields to match
1519 if( !tdSrc.isClass() ) {
1523 Iterator fieldsSrcItr = tdSrc.getClassDesc().getFields();
1524 while( fieldsSrcItr.hasNext() ) {
1525 FieldDescriptor fd = (FieldDescriptor) fieldsSrcItr.next();
1526 if( fd == edge.getFieldDesc() ) {
1531 // otherwise it is a class with fields
1532 // but we didn't find a match
1537 protected boolean hasMatchingType(ReferenceEdge edge, HeapRegionNode dst) {
1539 // if the region has no type, matches everything
1540 AllocationSite asDst = dst.getAllocationSite();
1541 if( asDst == null ) {
1545 TypeDescriptor tdDst = asDst.getType();
1546 assert tdDst != null;
1548 // if the type is not a class don't match because
1549 // primitives are copied, no memory aliases
1550 ClassDescriptor cdDst = tdDst.getClassDesc();
1551 if( cdDst == null ) {
1555 // if the field is null, it matches everything
1556 FieldDescriptor fd = edge.getFieldDesc();
1560 TypeDescriptor tdFd = fd.getType();
1561 assert tdFd != null;
1563 return typeUtil.isSuperorType(tdFd, tdDst);
1568 protected void unshadowTokens(AllocationSite as, ReferenceEdge edge) {
1569 edge.setBeta(edge.getBeta().unshadowTokens(as) );
1572 protected void unshadowTokens(AllocationSite as, HeapRegionNode hrn) {
1573 hrn.setAlpha(hrn.getAlpha().unshadowTokens(as) );
1577 private ReachabilitySet toShadowTokens(OwnershipGraph ogCallee,
1578 ReachabilitySet rsIn) {
1580 ReachabilitySet rsOut = new ReachabilitySet(rsIn).makeCanonical();
1582 Iterator<AllocationSite> allocItr = ogCallee.allocationSites.iterator();
1583 while( allocItr.hasNext() ) {
1584 AllocationSite as = allocItr.next();
1586 rsOut = rsOut.toShadowTokens(as);
1589 return rsOut.makeCanonical();
1593 private void rewriteCallerReachability(Integer paramIndex,
1596 ReachabilitySet rules,
1597 Hashtable<Integer, ReachabilitySet> paramIndex2rewrite_d,
1598 Hashtable<Integer, ReachabilitySet> paramIndex2rewriteD,
1600 Hashtable<TokenTuple, Integer> paramToken2paramIndex,
1601 Hashtable<TokenTuple, Integer> paramTokenPlus2paramIndex,
1602 boolean makeChangeSet,
1603 Hashtable<ReferenceEdge, ChangeTupleSet> edgePlannedChanges) {
1604 assert(hrn == null && edge != null) ||
1605 (hrn != null && edge == null);
1607 assert rules != null;
1610 ReachabilitySet callerReachabilityCurrent;
1612 callerReachabilityCurrent = edge.getBeta();
1614 callerReachabilityCurrent = hrn.getAlpha();
1617 ReachabilitySet callerReachabilityNew = new ReachabilitySet().makeCanonical();
1619 // for initializing structures in this method
1620 TokenTupleSet ttsEmpty = new TokenTupleSet().makeCanonical();
1622 // use this to construct a change set if required; the idea is to
1623 // map every partially rewritten token tuple set to the set of
1624 // caller-context token tuple sets that were used to generate it
1625 Hashtable<TokenTupleSet, HashSet<TokenTupleSet> > rewritten2source =
1626 new Hashtable<TokenTupleSet, HashSet<TokenTupleSet> >();
1627 rewritten2source.put(ttsEmpty, new HashSet<TokenTupleSet>() );
1630 Iterator<TokenTupleSet> rulesItr = rules.iterator();
1631 while(rulesItr.hasNext()) {
1632 TokenTupleSet rule = rulesItr.next();
1634 ReachabilitySet rewrittenRule = new ReachabilitySet(ttsEmpty).makeCanonical();
1636 Iterator<TokenTuple> ruleItr = rule.iterator();
1637 while(ruleItr.hasNext()) {
1638 TokenTuple ttCallee = ruleItr.next();
1640 // compute the possibilities for rewriting this callee token
1641 ReachabilitySet ttCalleeRewrites = null;
1642 boolean callerSourceUsed = false;
1644 if( ttCallee.equals(p_i) ) {
1645 // replace the arity-one token of the current parameter with the reachability
1646 // information from the caller edge
1647 ttCalleeRewrites = callerReachabilityCurrent;
1648 callerSourceUsed = true;
1650 } else if( paramToken2paramIndex.containsKey(ttCallee) ) {
1652 Integer paramIndex_j = paramToken2paramIndex.get(ttCallee);
1653 assert paramIndex_j != null;
1654 ttCalleeRewrites = paramIndex2rewrite_d.get(paramIndex_j);
1655 assert ttCalleeRewrites != null;
1657 } else if( paramTokenPlus2paramIndex.containsKey(ttCallee) ) {
1659 Integer paramIndex_j = paramTokenPlus2paramIndex.get(ttCallee);
1660 assert paramIndex_j != null;
1661 ttCalleeRewrites = paramIndex2rewriteD.get(paramIndex_j);
1662 assert ttCalleeRewrites != null;
1665 // otherwise there's no need for a rewrite, just pass this one on
1666 TokenTupleSet ttsCaller = new TokenTupleSet(ttCallee).makeCanonical();
1667 ttCalleeRewrites = new ReachabilitySet(ttsCaller).makeCanonical();
1670 // branch every version of the working rewritten rule with
1671 // the possibilities for rewriting the current callee token
1672 ReachabilitySet rewrittenRuleWithTTCallee = new ReachabilitySet().makeCanonical();
1674 Iterator<TokenTupleSet> rewrittenRuleItr = rewrittenRule.iterator();
1675 while( rewrittenRuleItr.hasNext() ) {
1676 TokenTupleSet ttsRewritten = rewrittenRuleItr.next();
1678 Iterator<TokenTupleSet> ttCalleeRewritesItr = ttCalleeRewrites.iterator();
1679 while( ttCalleeRewritesItr.hasNext() ) {
1680 TokenTupleSet ttsBranch = ttCalleeRewritesItr.next();
1682 TokenTupleSet ttsRewrittenNext = ttsRewritten.unionUpArity(ttsBranch);
1684 if( makeChangeSet ) {
1685 // in order to keep the list of source token tuple sets
1686 // start with the sets used to make the partially rewritten
1687 // rule up to this point
1688 HashSet<TokenTupleSet> sourceSets = rewritten2source.get(ttsRewritten);
1689 assert sourceSets != null;
1691 // make a shallow copy for possible modification
1692 sourceSets = (HashSet<TokenTupleSet>)sourceSets.clone();
1694 // if we used something from the caller to rewrite it, remember
1695 if( callerSourceUsed ) {
1696 sourceSets.add(ttsBranch);
1699 // set mapping for the further rewritten rule
1700 rewritten2source.put(ttsRewrittenNext, sourceSets);
1703 rewrittenRuleWithTTCallee =
1704 rewrittenRuleWithTTCallee.union(ttsRewrittenNext);
1708 // now the rewritten rule's possibilities have been extended by
1709 // rewriting the current callee token, remember result
1710 rewrittenRule = rewrittenRuleWithTTCallee;
1713 // the rule has been entirely rewritten into the caller context
1714 // now, so add it to the new reachability information
1715 callerReachabilityNew =
1716 callerReachabilityNew.union(rewrittenRule);
1719 if( makeChangeSet ) {
1720 ChangeTupleSet callerChangeSet = new ChangeTupleSet().makeCanonical();
1722 // each possibility for the final reachability should have a set of
1723 // caller sources mapped to it, use to create the change set
1724 Iterator<TokenTupleSet> callerReachabilityItr = callerReachabilityNew.iterator();
1725 while( callerReachabilityItr.hasNext() ) {
1726 TokenTupleSet ttsRewrittenFinal = callerReachabilityItr.next();
1727 HashSet<TokenTupleSet> sourceSets = rewritten2source.get(ttsRewrittenFinal);
1728 assert sourceSets != null;
1730 Iterator<TokenTupleSet> sourceSetsItr = sourceSets.iterator();
1731 while( sourceSetsItr.hasNext() ) {
1732 TokenTupleSet ttsSource = sourceSetsItr.next();
1735 callerChangeSet.union(new ChangeTuple(ttsSource, ttsRewrittenFinal) );
1739 assert edgePlannedChanges != null;
1740 edgePlannedChanges.put(edge, callerChangeSet);
1744 edge.setBetaNew(edge.getBetaNew().union(callerReachabilityNew) );
1746 hrn.setAlphaNew(hrn.getAlphaNew().union(callerReachabilityNew) );
1752 private HashSet<HeapRegionNode>
1753 getHRNSetThatPossiblyMapToCalleeHRN(OwnershipGraph ogCallee,
1754 HeapRegionNode hrnCallee,
1755 Hashtable<Integer, HashSet<HeapRegionNode> > paramIndex2reachableCallerNodes
1758 HashSet<HeapRegionNode> possibleCallerHRNs = new HashSet<HeapRegionNode>();
1760 Integer paramIndexCallee = ogCallee.id2paramIndex.get(hrnCallee.getID() );
1762 if( paramIndexCallee == null ) {
1763 // this is a node allocated in the callee then and it has
1764 // exactly one shadow node in the caller to map to
1765 AllocationSite as = hrnCallee.getAllocationSite();
1768 int age = as.getAgeCategory(hrnCallee.getID() );
1769 assert age != AllocationSite.AGE_notInThisSite;
1772 if( age == AllocationSite.AGE_summary ) {
1773 idCaller = as.getSummaryShadow();
1774 } else if( age == AllocationSite.AGE_oldest ) {
1775 idCaller = as.getOldestShadow();
1777 assert age == AllocationSite.AGE_in_I;
1779 Integer I = as.getAge(hrnCallee.getID() );
1782 idCaller = as.getIthOldestShadow(I);
1785 assert id2hrn.containsKey(idCaller);
1786 HeapRegionNode hrnCaller = id2hrn.get(idCaller);
1787 possibleCallerHRNs.add(hrnCaller);
1790 // this is a node that was created to represent a parameter
1791 // so it maps to a whole mess of heap regions
1792 assert paramIndex2reachableCallerNodes.containsKey(paramIndexCallee);
1793 possibleCallerHRNs = paramIndex2reachableCallerNodes.get(paramIndexCallee);
1796 return possibleCallerHRNs;
1801 ////////////////////////////////////////////////////
1802 // in merge() and equals() methods the suffix A
1803 // represents the passed in graph and the suffix
1804 // B refers to the graph in this object
1805 // Merging means to take the incoming graph A and
1806 // merge it into B, so after the operation graph B
1807 // is the final result.
1808 ////////////////////////////////////////////////////
1809 public void merge(OwnershipGraph og) {
1815 mergeOwnershipNodes(og);
1816 mergeReferenceEdges(og);
1817 mergeId2paramIndex(og);
1818 mergeAllocationSites(og);
1822 protected void mergeOwnershipNodes(OwnershipGraph og) {
1823 Set sA = og.id2hrn.entrySet();
1824 Iterator iA = sA.iterator();
1825 while( iA.hasNext() ) {
1826 Map.Entry meA = (Map.Entry)iA.next();
1827 Integer idA = (Integer) meA.getKey();
1828 HeapRegionNode hrnA = (HeapRegionNode) meA.getValue();
1830 // if this graph doesn't have a node the
1831 // incoming graph has, allocate it
1832 if( !id2hrn.containsKey(idA) ) {
1833 HeapRegionNode hrnB = hrnA.copy();
1834 id2hrn.put(idA, hrnB);
1837 // otherwise this is a node present in both graphs
1838 // so make the new reachability set a union of the
1839 // nodes' reachability sets
1840 HeapRegionNode hrnB = id2hrn.get(idA);
1841 hrnB.setAlpha(hrnB.getAlpha().union(hrnA.getAlpha() ) );
1845 // now add any label nodes that are in graph B but
1847 sA = og.td2ln.entrySet();
1849 while( iA.hasNext() ) {
1850 Map.Entry meA = (Map.Entry)iA.next();
1851 TempDescriptor tdA = (TempDescriptor) meA.getKey();
1852 LabelNode lnA = (LabelNode) meA.getValue();
1854 // if the label doesn't exist in B, allocate and add it
1855 LabelNode lnB = getLabelNodeFromTemp(tdA);
1859 protected void mergeReferenceEdges(OwnershipGraph og) {
1862 Set sA = og.id2hrn.entrySet();
1863 Iterator iA = sA.iterator();
1864 while( iA.hasNext() ) {
1865 Map.Entry meA = (Map.Entry)iA.next();
1866 Integer idA = (Integer) meA.getKey();
1867 HeapRegionNode hrnA = (HeapRegionNode) meA.getValue();
1869 Iterator<ReferenceEdge> heapRegionsItrA = hrnA.iteratorToReferencees();
1870 while( heapRegionsItrA.hasNext() ) {
1871 ReferenceEdge edgeA = heapRegionsItrA.next();
1872 HeapRegionNode hrnChildA = edgeA.getDst();
1873 Integer idChildA = hrnChildA.getID();
1875 // at this point we know an edge in graph A exists
1876 // idA -> idChildA, does this exist in B?
1877 assert id2hrn.containsKey(idA);
1878 HeapRegionNode hrnB = id2hrn.get(idA);
1879 ReferenceEdge edgeToMerge = null;
1881 Iterator<ReferenceEdge> heapRegionsItrB = hrnB.iteratorToReferencees();
1882 while( heapRegionsItrB.hasNext() &&
1883 edgeToMerge == null ) {
1885 ReferenceEdge edgeB = heapRegionsItrB.next();
1886 HeapRegionNode hrnChildB = edgeB.getDst();
1887 Integer idChildB = hrnChildB.getID();
1889 // don't use the ReferenceEdge.equals() here because
1890 // we're talking about existence between graphs
1891 if( idChildB.equals(idChildA) &&
1892 edgeB.getFieldDesc() == edgeA.getFieldDesc() ) {
1893 edgeToMerge = edgeB;
1897 // if the edge from A was not found in B,
1899 if( edgeToMerge == null ) {
1900 assert id2hrn.containsKey(idChildA);
1901 HeapRegionNode hrnChildB = id2hrn.get(idChildA);
1902 edgeToMerge = edgeA.copy();
1903 edgeToMerge.setSrc(hrnB);
1904 edgeToMerge.setDst(hrnChildB);
1905 addReferenceEdge(hrnB, hrnChildB, edgeToMerge);
1907 // otherwise, the edge already existed in both graphs
1908 // so merge their reachability sets
1910 // just replace this beta set with the union
1911 assert edgeToMerge != null;
1912 edgeToMerge.setBeta(
1913 edgeToMerge.getBeta().union(edgeA.getBeta() )
1915 if( !edgeA.isInitialParamReflexive() ) {
1916 edgeToMerge.setIsInitialParamReflexive(false);
1922 // and then again with label nodes
1923 sA = og.td2ln.entrySet();
1925 while( iA.hasNext() ) {
1926 Map.Entry meA = (Map.Entry)iA.next();
1927 TempDescriptor tdA = (TempDescriptor) meA.getKey();
1928 LabelNode lnA = (LabelNode) meA.getValue();
1930 Iterator<ReferenceEdge> heapRegionsItrA = lnA.iteratorToReferencees();
1931 while( heapRegionsItrA.hasNext() ) {
1932 ReferenceEdge edgeA = heapRegionsItrA.next();
1933 HeapRegionNode hrnChildA = edgeA.getDst();
1934 Integer idChildA = hrnChildA.getID();
1936 // at this point we know an edge in graph A exists
1937 // tdA -> idChildA, does this exist in B?
1938 assert td2ln.containsKey(tdA);
1939 LabelNode lnB = td2ln.get(tdA);
1940 ReferenceEdge edgeToMerge = null;
1942 // labels never have edges with a field
1943 //assert edgeA.getFieldDesc() == null;
1945 Iterator<ReferenceEdge> heapRegionsItrB = lnB.iteratorToReferencees();
1946 while( heapRegionsItrB.hasNext() &&
1947 edgeToMerge == null ) {
1949 ReferenceEdge edgeB = heapRegionsItrB.next();
1950 HeapRegionNode hrnChildB = edgeB.getDst();
1951 Integer idChildB = hrnChildB.getID();
1953 // labels never have edges with a field
1954 //assert edgeB.getFieldDesc() == null;
1956 // don't use the ReferenceEdge.equals() here because
1957 // we're talking about existence between graphs
1958 if( idChildB.equals(idChildA) &&
1959 edgeB.getFieldDesc() == edgeA.getFieldDesc() ) {
1960 edgeToMerge = edgeB;
1964 // if the edge from A was not found in B,
1966 if( edgeToMerge == null ) {
1967 assert id2hrn.containsKey(idChildA);
1968 HeapRegionNode hrnChildB = id2hrn.get(idChildA);
1969 edgeToMerge = edgeA.copy();
1970 edgeToMerge.setSrc(lnB);
1971 edgeToMerge.setDst(hrnChildB);
1972 addReferenceEdge(lnB, hrnChildB, edgeToMerge);
1974 // otherwise, the edge already existed in both graphs
1975 // so merge their reachability sets
1977 // just replace this beta set with the union
1978 edgeToMerge.setBeta(
1979 edgeToMerge.getBeta().union(edgeA.getBeta() )
1981 if( !edgeA.isInitialParamReflexive() ) {
1982 edgeToMerge.setIsInitialParamReflexive(false);
1989 // you should only merge ownership graphs that have the
1990 // same number of parameters, or if one or both parameter
1991 // index tables are empty
1992 protected void mergeId2paramIndex(OwnershipGraph og) {
1993 if( id2paramIndex.size() == 0 ) {
1994 id2paramIndex = og.id2paramIndex;
1995 paramIndex2id = og.paramIndex2id;
1996 paramIndex2tdQ = og.paramIndex2tdQ;
2000 if( og.id2paramIndex.size() == 0 ) {
2004 assert id2paramIndex.size() == og.id2paramIndex.size();
2007 protected void mergeAllocationSites(OwnershipGraph og) {
2008 allocationSites.addAll(og.allocationSites);
2013 // it is necessary in the equals() member functions
2014 // to "check both ways" when comparing the data
2015 // structures of two graphs. For instance, if all
2016 // edges between heap region nodes in graph A are
2017 // present and equal in graph B it is not sufficient
2018 // to say the graphs are equal. Consider that there
2019 // may be edges in graph B that are not in graph A.
2020 // the only way to know that all edges in both graphs
2021 // are equally present is to iterate over both data
2022 // structures and compare against the other graph.
2023 public boolean equals(OwnershipGraph og) {
2029 if( !areHeapRegionNodesEqual(og) ) {
2033 if( !areLabelNodesEqual(og) ) {
2037 if( !areReferenceEdgesEqual(og) ) {
2041 if( !areId2paramIndexEqual(og) ) {
2045 // if everything is equal up to this point,
2046 // assert that allocationSites is also equal--
2047 // this data is redundant and kept for efficiency
2048 assert allocationSites.equals(og.allocationSites);
2053 protected boolean areHeapRegionNodesEqual(OwnershipGraph og) {
2055 if( !areallHRNinAalsoinBandequal(this, og) ) {
2059 if( !areallHRNinAalsoinBandequal(og, this) ) {
2066 static protected boolean areallHRNinAalsoinBandequal(OwnershipGraph ogA,
2067 OwnershipGraph ogB) {
2068 Set sA = ogA.id2hrn.entrySet();
2069 Iterator iA = sA.iterator();
2070 while( iA.hasNext() ) {
2071 Map.Entry meA = (Map.Entry)iA.next();
2072 Integer idA = (Integer) meA.getKey();
2073 HeapRegionNode hrnA = (HeapRegionNode) meA.getValue();
2075 if( !ogB.id2hrn.containsKey(idA) ) {
2079 HeapRegionNode hrnB = ogB.id2hrn.get(idA);
2080 if( !hrnA.equalsIncludingAlpha(hrnB) ) {
2089 protected boolean areLabelNodesEqual(OwnershipGraph og) {
2091 if( !areallLNinAalsoinBandequal(this, og) ) {
2095 if( !areallLNinAalsoinBandequal(og, this) ) {
2102 static protected boolean areallLNinAalsoinBandequal(OwnershipGraph ogA,
2103 OwnershipGraph ogB) {
2104 Set sA = ogA.td2ln.entrySet();
2105 Iterator iA = sA.iterator();
2106 while( iA.hasNext() ) {
2107 Map.Entry meA = (Map.Entry)iA.next();
2108 TempDescriptor tdA = (TempDescriptor) meA.getKey();
2110 if( !ogB.td2ln.containsKey(tdA) ) {
2119 protected boolean areReferenceEdgesEqual(OwnershipGraph og) {
2120 if( !areallREinAandBequal(this, og) ) {
2127 static protected boolean areallREinAandBequal(OwnershipGraph ogA,
2128 OwnershipGraph ogB) {
2130 // check all the heap region->heap region edges
2131 Set sA = ogA.id2hrn.entrySet();
2132 Iterator iA = sA.iterator();
2133 while( iA.hasNext() ) {
2134 Map.Entry meA = (Map.Entry)iA.next();
2135 Integer idA = (Integer) meA.getKey();
2136 HeapRegionNode hrnA = (HeapRegionNode) meA.getValue();
2138 // we should have already checked that the same
2139 // heap regions exist in both graphs
2140 assert ogB.id2hrn.containsKey(idA);
2142 if( !areallREfromAequaltoB(ogA, hrnA, ogB) ) {
2146 // then check every edge in B for presence in A, starting
2147 // from the same parent HeapRegionNode
2148 HeapRegionNode hrnB = ogB.id2hrn.get(idA);
2150 if( !areallREfromAequaltoB(ogB, hrnB, ogA) ) {
2155 // then check all the label->heap region edges
2156 sA = ogA.td2ln.entrySet();
2158 while( iA.hasNext() ) {
2159 Map.Entry meA = (Map.Entry)iA.next();
2160 TempDescriptor tdA = (TempDescriptor) meA.getKey();
2161 LabelNode lnA = (LabelNode) meA.getValue();
2163 // we should have already checked that the same
2164 // label nodes exist in both graphs
2165 assert ogB.td2ln.containsKey(tdA);
2167 if( !areallREfromAequaltoB(ogA, lnA, ogB) ) {
2171 // then check every edge in B for presence in A, starting
2172 // from the same parent LabelNode
2173 LabelNode lnB = ogB.td2ln.get(tdA);
2175 if( !areallREfromAequaltoB(ogB, lnB, ogA) ) {
2184 static protected boolean areallREfromAequaltoB(OwnershipGraph ogA,
2186 OwnershipGraph ogB) {
2188 Iterator<ReferenceEdge> itrA = onA.iteratorToReferencees();
2189 while( itrA.hasNext() ) {
2190 ReferenceEdge edgeA = itrA.next();
2191 HeapRegionNode hrnChildA = edgeA.getDst();
2192 Integer idChildA = hrnChildA.getID();
2194 assert ogB.id2hrn.containsKey(idChildA);
2196 // at this point we know an edge in graph A exists
2197 // onA -> idChildA, does this exact edge exist in B?
2198 boolean edgeFound = false;
2200 OwnershipNode onB = null;
2201 if( onA instanceof HeapRegionNode ) {
2202 HeapRegionNode hrnA = (HeapRegionNode) onA;
2203 onB = ogB.id2hrn.get(hrnA.getID() );
2205 LabelNode lnA = (LabelNode) onA;
2206 onB = ogB.td2ln.get(lnA.getTempDescriptor() );
2209 Iterator<ReferenceEdge> itrB = onB.iteratorToReferencees();
2210 while( itrB.hasNext() ) {
2211 ReferenceEdge edgeB = itrB.next();
2212 HeapRegionNode hrnChildB = edgeB.getDst();
2213 Integer idChildB = hrnChildB.getID();
2215 if( idChildA.equals(idChildB) &&
2216 edgeA.getFieldDesc() == edgeB.getFieldDesc() ) {
2218 // there is an edge in the right place with the right field,
2219 // but do they have the same attributes?
2220 if( edgeA.getBeta().equals(edgeB.getBeta() ) ) {
2238 protected boolean areId2paramIndexEqual(OwnershipGraph og) {
2239 return id2paramIndex.size() == og.id2paramIndex.size();
2243 public boolean hasPotentialAlias(Integer paramIndex1, Integer paramIndex2) {
2245 // get parameter's heap region
2246 assert paramIndex2id.containsKey(paramIndex1);
2247 Integer idParam1 = paramIndex2id.get(paramIndex1);
2249 assert id2hrn.containsKey(idParam1);
2250 HeapRegionNode hrnParam1 = id2hrn.get(idParam1);
2251 assert hrnParam1 != null;
2253 // get tokens for this parameter
2254 TokenTuple p1 = new TokenTuple(hrnParam1.getID(),
2256 TokenTuple.ARITY_ONE).makeCanonical();
2258 TokenTuple pPlus1 = new TokenTuple(hrnParam1.getID(),
2260 TokenTuple.ARITY_ONEORMORE).makeCanonical();
2262 TokenTuple pStar1 = new TokenTuple(hrnParam1.getID(),
2264 TokenTuple.ARITY_ZEROORMORE).makeCanonical();
2267 // get tokens for the other parameter
2268 assert paramIndex2id.containsKey(paramIndex2);
2269 Integer idParam2 = paramIndex2id.get(paramIndex2);
2271 assert id2hrn.containsKey(idParam2);
2272 HeapRegionNode hrnParam2 = id2hrn.get(idParam2);
2273 assert hrnParam2 != null;
2275 TokenTuple p2 = new TokenTuple(hrnParam2.getID(),
2277 TokenTuple.ARITY_ONE).makeCanonical();
2279 TokenTuple pPlus2 = new TokenTuple(hrnParam2.getID(),
2281 TokenTuple.ARITY_ONEORMORE).makeCanonical();
2283 TokenTuple pStar2 = new TokenTuple(hrnParam2.getID(),
2285 TokenTuple.ARITY_ZEROORMORE).makeCanonical();
2288 // get special label p_q for first parameter
2289 TempDescriptor tdParamQ1 = paramIndex2tdQ.get(paramIndex1);
2290 assert tdParamQ1 != null;
2291 LabelNode lnParamQ1 = td2ln.get(tdParamQ1);
2292 assert lnParamQ1 != null;
2294 // then get the edge from label q to parameter's hrn
2295 ReferenceEdge edgeSpecialQ1 = lnParamQ1.getReferenceTo(hrnParam1, null);
2296 assert edgeSpecialQ1 != null;
2298 // if the beta of this edge has tokens from both parameters in one
2299 // token tuple set, then there is a potential alias between them
2300 ReachabilitySet beta1 = edgeSpecialQ1.getBeta();
2301 assert beta1 != null;
2303 if( beta1.containsTupleSetWithBoth(p1, p2) ) {
2306 if( beta1.containsTupleSetWithBoth(pPlus1, p2) ) {
2309 if( beta1.containsTupleSetWithBoth(pStar1, p2) ) {
2312 if( beta1.containsTupleSetWithBoth(p1, pPlus2) ) {
2315 if( beta1.containsTupleSetWithBoth(pPlus1, pPlus2) ) {
2318 if( beta1.containsTupleSetWithBoth(pStar1, pPlus2) ) {
2321 if( beta1.containsTupleSetWithBoth(p1, pStar2) ) {
2324 if( beta1.containsTupleSetWithBoth(pPlus1, pStar2) ) {
2327 if( beta1.containsTupleSetWithBoth(pStar1, pStar2) ) {
2335 public boolean hasPotentialAlias(Integer paramIndex, AllocationSite as) {
2337 // get parameter's heap region
2338 assert paramIndex2id.containsKey(paramIndex);
2339 Integer idParam = paramIndex2id.get(paramIndex);
2341 assert id2hrn.containsKey(idParam);
2342 HeapRegionNode hrnParam = id2hrn.get(idParam);
2343 assert hrnParam != null;
2345 // get tokens for this parameter
2346 TokenTuple p = new TokenTuple(hrnParam.getID(),
2348 TokenTuple.ARITY_ONE).makeCanonical();
2350 TokenTuple pPlus = new TokenTuple(hrnParam.getID(),
2352 TokenTuple.ARITY_ONEORMORE).makeCanonical();
2354 TokenTuple pStar = new TokenTuple(hrnParam.getID(),
2356 TokenTuple.ARITY_ZEROORMORE).makeCanonical();
2358 // get special label p_q
2359 TempDescriptor tdParamQ = paramIndex2tdQ.get(paramIndex);
2360 assert tdParamQ != null;
2361 LabelNode lnParamQ = td2ln.get(tdParamQ);
2362 assert lnParamQ != null;
2364 // then get the edge from label q to parameter's hrn
2365 ReferenceEdge edgeSpecialQ = lnParamQ.getReferenceTo(hrnParam, null);
2366 assert edgeSpecialQ != null;
2368 // look through this beta set for potential aliases
2369 ReachabilitySet beta = edgeSpecialQ.getBeta();
2370 assert beta != null;
2373 // get tokens for summary node
2374 TokenTuple gs = new TokenTuple(as.getSummary(),
2376 TokenTuple.ARITY_ONE).makeCanonical();
2378 TokenTuple gsPlus = new TokenTuple(as.getSummary(),
2380 TokenTuple.ARITY_ONEORMORE).makeCanonical();
2382 TokenTuple gsStar = new TokenTuple(as.getSummary(),
2384 TokenTuple.ARITY_ZEROORMORE).makeCanonical();
2387 if( beta.containsTupleSetWithBoth(p, gs) ) {
2390 if( beta.containsTupleSetWithBoth(pPlus, gs) ) {
2393 if( beta.containsTupleSetWithBoth(pStar, gs) ) {
2396 if( beta.containsTupleSetWithBoth(p, gsPlus) ) {
2399 if( beta.containsTupleSetWithBoth(pPlus, gsPlus) ) {
2402 if( beta.containsTupleSetWithBoth(pStar, gsPlus) ) {
2405 if( beta.containsTupleSetWithBoth(p, gsStar) ) {
2408 if( beta.containsTupleSetWithBoth(pPlus, gsStar) ) {
2411 if( beta.containsTupleSetWithBoth(pStar, gsStar) ) {
2415 // check for other nodes
2416 for( int i = 0; i < as.getAllocationDepth(); ++i ) {
2418 // the other nodes of an allocation site are single, no plus
2419 TokenTuple gi = new TokenTuple(as.getIthOldest(i),
2421 TokenTuple.ARITY_ONE).makeCanonical();
2423 TokenTuple giStar = new TokenTuple(as.getIthOldest(i),
2425 TokenTuple.ARITY_ZEROORMORE).makeCanonical();
2427 if( beta.containsTupleSetWithBoth(p, gi) ) {
2430 if( beta.containsTupleSetWithBoth(pPlus, gi) ) {
2433 if( beta.containsTupleSetWithBoth(pStar, gi) ) {
2436 if( beta.containsTupleSetWithBoth(p, giStar) ) {
2439 if( beta.containsTupleSetWithBoth(pPlus, giStar) ) {
2442 if( beta.containsTupleSetWithBoth(pStar, giStar) ) {
2451 public boolean hasPotentialAlias(AllocationSite as1, AllocationSite as2) {
2453 // get tokens for summary nodes
2454 TokenTuple gs1 = new TokenTuple(as1.getSummary(),
2456 TokenTuple.ARITY_ONE).makeCanonical();
2458 TokenTuple gsPlus1 = new TokenTuple(as1.getSummary(),
2460 TokenTuple.ARITY_ONEORMORE).makeCanonical();
2462 TokenTuple gsStar1 = new TokenTuple(as1.getSummary(),
2464 TokenTuple.ARITY_ZEROORMORE).makeCanonical();
2466 // get summary node's alpha
2467 Integer idSum1 = as1.getSummary();
2468 assert id2hrn.containsKey(idSum1);
2469 HeapRegionNode hrnSum1 = id2hrn.get(idSum1);
2470 assert hrnSum1 != null;
2471 ReachabilitySet alphaSum1 = hrnSum1.getAlpha();
2472 assert alphaSum1 != null;
2475 // and for the other one
2476 TokenTuple gs2 = new TokenTuple(as2.getSummary(),
2478 TokenTuple.ARITY_ONE).makeCanonical();
2480 TokenTuple gsPlus2 = new TokenTuple(as2.getSummary(),
2482 TokenTuple.ARITY_ONEORMORE).makeCanonical();
2484 TokenTuple gsStar2 = new TokenTuple(as2.getSummary(),
2486 TokenTuple.ARITY_ZEROORMORE).makeCanonical();
2488 // get summary node's alpha
2489 Integer idSum2 = as2.getSummary();
2490 assert id2hrn.containsKey(idSum2);
2491 HeapRegionNode hrnSum2 = id2hrn.get(idSum2);
2492 assert hrnSum2 != null;
2493 ReachabilitySet alphaSum2 = hrnSum2.getAlpha();
2494 assert alphaSum2 != null;
2496 // does either one report reachability from the other tokens?
2497 if( alphaSum1.containsTuple(gsPlus2) ) {
2500 if( alphaSum1.containsTuple(gsStar2) ) {
2503 if( alphaSum2.containsTuple(gsPlus1) ) {
2506 if( alphaSum2.containsTuple(gsStar1) ) {
2510 // only check ONE token if they are different sites
2512 if( alphaSum1.containsTuple(gs2) ) {
2515 if( alphaSum2.containsTuple(gs1) ) {
2521 // check sum2 against alloc1 nodes
2522 for( int i = 0; i < as1.getAllocationDepth(); ++i ) {
2523 Integer idI1 = as1.getIthOldest(i);
2524 assert id2hrn.containsKey(idI1);
2525 HeapRegionNode hrnI1 = id2hrn.get(idI1);
2526 assert hrnI1 != null;
2527 ReachabilitySet alphaI1 = hrnI1.getAlpha();
2528 assert alphaI1 != null;
2530 // the other nodes of an allocation site are single, no stars
2531 TokenTuple gi1 = new TokenTuple(as1.getIthOldest(i),
2533 TokenTuple.ARITY_ONE).makeCanonical();
2535 TokenTuple giStar1 = new TokenTuple(as1.getIthOldest(i),
2537 TokenTuple.ARITY_ZEROORMORE).makeCanonical();
2539 if( alphaSum2.containsTuple(gi1) ) {
2542 if( alphaSum2.containsTuple(giStar1) ) {
2545 if( alphaI1.containsTuple(gs2) ) {
2548 if( alphaI1.containsTuple(gsPlus2) ) {
2551 if( alphaI1.containsTuple(gsStar2) ) {
2556 // check sum1 against alloc2 nodes
2557 for( int i = 0; i < as2.getAllocationDepth(); ++i ) {
2558 Integer idI2 = as2.getIthOldest(i);
2559 assert id2hrn.containsKey(idI2);
2560 HeapRegionNode hrnI2 = id2hrn.get(idI2);
2561 assert hrnI2 != null;
2562 ReachabilitySet alphaI2 = hrnI2.getAlpha();
2563 assert alphaI2 != null;
2565 TokenTuple gi2 = new TokenTuple(as2.getIthOldest(i),
2567 TokenTuple.ARITY_ONE).makeCanonical();
2569 TokenTuple giStar2 = new TokenTuple(as2.getIthOldest(i),
2571 TokenTuple.ARITY_ZEROORMORE).makeCanonical();
2573 if( alphaSum1.containsTuple(gi2) ) {
2576 if( alphaSum1.containsTuple(giStar2) ) {
2579 if( alphaI2.containsTuple(gs1) ) {
2582 if( alphaI2.containsTuple(gsPlus1) ) {
2585 if( alphaI2.containsTuple(gsStar1) ) {
2589 // while we're at it, do an inner loop for alloc2 vs alloc1 nodes
2590 for( int j = 0; j < as1.getAllocationDepth(); ++j ) {
2591 Integer idI1 = as1.getIthOldest(j);
2593 // if these are the same site, don't look for the same token, no alias.
2594 // different tokens of the same site could alias together though
2595 if( idI1 == idI2 ) {
2599 HeapRegionNode hrnI1 = id2hrn.get(idI1);
2600 ReachabilitySet alphaI1 = hrnI1.getAlpha();
2601 TokenTuple gi1 = new TokenTuple(as1.getIthOldest(j),
2603 TokenTuple.ARITY_ONE).makeCanonical();
2605 TokenTuple giStar1 = new TokenTuple(as1.getIthOldest(j),
2607 TokenTuple.ARITY_ZEROORMORE).makeCanonical();
2609 if( alphaI2.containsTuple(gi1) ) {
2612 if( alphaI2.containsTuple(giStar1) ) {
2615 if( alphaI1.containsTuple(gi2) ) {
2618 if( alphaI1.containsTuple(giStar2) ) {
2628 // for writing ownership graphs to dot files
2629 public void writeGraph(Descriptor methodDesc,
2631 boolean writeLabels,
2632 boolean labelSelect,
2633 boolean pruneGarbage,
2634 boolean writeReferencers,
2635 boolean writeParamMappings
2636 ) throws java.io.IOException {
2638 methodDesc.getSymbol() +
2639 methodDesc.getNum() +
2649 public void writeGraph(Descriptor methodDesc,
2650 boolean writeLabels,
2651 boolean labelSelect,
2652 boolean pruneGarbage,
2653 boolean writeReferencers,
2654 boolean writeParamMappings
2655 ) throws java.io.IOException {
2657 writeGraph(methodDesc+"COMPLETE",
2666 public void writeGraph(Descriptor methodDesc,
2668 boolean writeLabels,
2669 boolean labelSelect,
2670 boolean pruneGarbage,
2671 boolean writeReferencers,
2672 boolean writeParamMappings
2673 ) throws java.io.IOException {
2675 writeGraph(methodDesc+"COMPLETE"+String.format("%05d", numUpdate),
2684 public void writeGraph(String graphName,
2685 boolean writeLabels,
2686 boolean labelSelect,
2687 boolean pruneGarbage,
2688 boolean writeReferencers,
2689 boolean writeParamMappings
2690 ) throws java.io.IOException {
2692 // remove all non-word characters from the graph name so
2693 // the filename and identifier in dot don't cause errors
2694 graphName = graphName.replaceAll("[\\W]", "");
2696 BufferedWriter bw = new BufferedWriter(new FileWriter(graphName+".dot") );
2697 bw.write("digraph "+graphName+" {\n");
2699 HashSet<HeapRegionNode> visited = new HashSet<HeapRegionNode>();
2701 // then visit every heap region node
2702 Set s = id2hrn.entrySet();
2703 Iterator i = s.iterator();
2704 while( i.hasNext() ) {
2705 Map.Entry me = (Map.Entry)i.next();
2706 HeapRegionNode hrn = (HeapRegionNode) me.getValue();
2707 if( !pruneGarbage ||
2709 hrn.getDescription().startsWith("param")
2712 if( !visited.contains(hrn) ) {
2713 traverseHeapRegionNodes(VISIT_HRN_WRITE_FULL,
2723 bw.write(" graphTitle[label=\""+graphName+"\",shape=box];\n");
2725 if( writeParamMappings ) {
2726 Set df = paramIndex2id.entrySet();
2727 Iterator ih = df.iterator();
2728 while( ih.hasNext() ) {
2729 Map.Entry meh = (Map.Entry)ih.next();
2730 Integer pi = (Integer) meh.getKey();
2731 Integer id = (Integer) meh.getValue();
2732 bw.write(" pindex"+pi+"[label=\""+pi+" to "+id+"\",shape=box];\n");
2736 // then visit every label node, useful for debugging
2738 s = td2ln.entrySet();
2740 while( i.hasNext() ) {
2741 Map.Entry me = (Map.Entry)i.next();
2742 LabelNode ln = (LabelNode) me.getValue();
2745 String labelStr = ln.getTempDescriptorString();
2746 if( labelStr.startsWith("___temp") ||
2747 labelStr.startsWith("___dst") ||
2748 labelStr.startsWith("___srctmp") ||
2749 labelStr.startsWith("___neverused") ) {
2754 //bw.write(" "+ln.toString() + ";\n");
2756 Iterator<ReferenceEdge> heapRegionsItr = ln.iteratorToReferencees();
2757 while( heapRegionsItr.hasNext() ) {
2758 ReferenceEdge edge = heapRegionsItr.next();
2759 HeapRegionNode hrn = edge.getDst();
2761 if( pruneGarbage && !visited.contains(hrn) ) {
2762 traverseHeapRegionNodes(VISIT_HRN_WRITE_FULL,
2770 bw.write(" " + ln.toString() +
2771 " -> " + hrn.toString() +
2772 "[label=\"" + edge.toGraphEdgeString() +
2783 protected void traverseHeapRegionNodes(int mode,
2787 HashSet<HeapRegionNode> visited,
2788 boolean writeReferencers
2789 ) throws java.io.IOException {
2791 if( visited.contains(hrn) ) {
2797 case VISIT_HRN_WRITE_FULL:
2799 String attributes = "[";
2801 if( hrn.isSingleObject() ) {
2802 attributes += "shape=box";
2804 attributes += "shape=Msquare";
2807 if( hrn.isFlagged() ) {
2808 attributes += ",style=filled,fillcolor=lightgrey";
2811 attributes += ",label=\"ID" +
2814 hrn.getDescription() +
2816 hrn.getAlphaString() +
2819 bw.write(" " + hrn.toString() + attributes + ";\n");
2824 // useful for debugging
2825 if( writeReferencers ) {
2826 OwnershipNode onRef = null;
2827 Iterator refItr = hrn.iteratorToReferencers();
2828 while( refItr.hasNext() ) {
2829 onRef = (OwnershipNode) refItr.next();
2832 case VISIT_HRN_WRITE_FULL:
2833 bw.write(" " + hrn.toString() +
2834 " -> " + onRef.toString() +
2835 "[color=lightgray];\n");
2841 Iterator<ReferenceEdge> childRegionsItr = hrn.iteratorToReferencees();
2842 while( childRegionsItr.hasNext() ) {
2843 ReferenceEdge edge = childRegionsItr.next();
2844 HeapRegionNode hrnChild = edge.getDst();
2847 case VISIT_HRN_WRITE_FULL:
2848 bw.write(" " + hrn.toString() +
2849 " -> " + hrnChild.toString() +
2850 "[label=\"" + edge.toGraphEdgeString() +
2855 traverseHeapRegionNodes(mode,