1 package Analysis.Disjoint;
5 import Util.UtilAlgorithms;
9 public class ReachGraph {
11 // use to disable improvements for comparison
12 protected static final boolean DISABLE_STRONG_UPDATES = false;
13 protected static final boolean DISABLE_GLOBAL_SWEEP = false;
15 // a special out-of-scope temp
16 protected static final TempDescriptor tdReturn = new TempDescriptor("_Return___");
18 // predicate constants
19 public static final ExistPred predTrue = ExistPred.factory(); // if no args, true
20 public static final ExistPredSet predsEmpty = ExistPredSet.factory();
21 public static final ExistPredSet predsTrue = ExistPredSet.factory(predTrue);
23 // some frequently used reachability constants
24 protected static final ReachState rstateEmpty = ReachState.factory();
25 protected static final ReachSet rsetEmpty = ReachSet.factory();
26 protected static final ReachSet rsetWithEmptyState = Canonical.changePredsTo(ReachSet.factory(rstateEmpty),
29 // from DisjointAnalysis for convenience
30 protected static int allocationDepth = -1;
31 protected static TypeUtil typeUtil = null;
32 protected static State state = null;
35 // variable and heap region nodes indexed by unique ID
36 public Hashtable<Integer, HeapRegionNode> id2hrn;
37 public Hashtable<TempDescriptor, VariableNode > td2vn;
39 // convenient set of alloc sites for all heap regions
40 // present in the graph without having to search
41 public Set<AllocSite> allocSites;
43 // set of inaccessible variables for current program statement
44 // with respect to stall-site analysis
45 public Set<TempDescriptor> inaccessibleVars;
49 id2hrn = new Hashtable<Integer, HeapRegionNode>();
50 td2vn = new Hashtable<TempDescriptor, VariableNode >();
51 allocSites = new HashSet<AllocSite>();
52 inaccessibleVars = new HashSet<TempDescriptor>();
56 // temp descriptors are globally unique and map to
57 // exactly one variable node, easy
58 protected VariableNode getVariableNodeFromTemp(TempDescriptor td) {
61 if( !td2vn.containsKey(td) ) {
62 td2vn.put(td, new VariableNode(td) );
68 //This method is created for client modules to access the Reachgraph
69 //after the analysis is done and no modifications are to be made.
70 public VariableNode getVariableNodeNoMutation(TempDescriptor td) {
73 if( !td2vn.containsKey(td) ) {
80 public boolean hasVariable(TempDescriptor td) {
81 return td2vn.containsKey(td);
85 // this suite of methods can be used to assert a
86 // very important property of ReachGraph objects:
87 // some element, HeapRegionNode, RefEdge etc.
88 // should be referenced by at most ONE ReachGraph!!
89 // If a heap region or edge or variable should be
90 // in another graph, make a new object with
91 // equivalent properties for a new graph
92 public boolean belongsToThis(RefSrcNode rsn) {
93 if( rsn instanceof VariableNode ) {
94 VariableNode vn = (VariableNode) rsn;
95 return this.td2vn.get(vn.getTempDescriptor() ) == vn;
97 HeapRegionNode hrn = (HeapRegionNode) rsn;
98 return this.id2hrn.get(hrn.getID() ) == hrn;
105 // the reason for this method is to have the option
106 // of creating new heap regions with specific IDs, or
107 // duplicating heap regions with specific IDs (especially
108 // in the merge() operation) or to create new heap
109 // regions with a new unique ID
110 protected HeapRegionNode
111 createNewHeapRegionNode(Integer id,
112 boolean isSingleObject,
113 boolean isNewSummary,
114 boolean isOutOfContext,
123 TypeDescriptor typeToUse = null;
124 if( allocSite != null ) {
125 typeToUse = allocSite.getType();
126 allocSites.add(allocSite);
131 boolean markForAnalysis = false;
132 if( allocSite != null && allocSite.isFlagged() ) {
133 markForAnalysis = true;
136 if( allocSite == null ) {
137 assert !markForAnalysis;
139 } else if( markForAnalysis != allocSite.isFlagged() ) {
145 id = DisjointAnalysis.generateUniqueHeapRegionNodeID();
148 if( inherent == null ) {
149 if( markForAnalysis ) {
151 Canonical.changePredsTo(
154 ReachTuple.factory(id,
156 ReachTuple.ARITY_ONE,
157 false // out-of-context
164 inherent = rsetWithEmptyState;
168 if( alpha == null ) {
172 assert preds != null;
174 HeapRegionNode hrn = new HeapRegionNode(id,
191 ////////////////////////////////////////////////
193 // Low-level referencee and referencer methods
195 // These methods provide the lowest level for
196 // creating references between reachability nodes
197 // and handling the details of maintaining both
198 // list of referencers and referencees.
200 ////////////////////////////////////////////////
201 protected void addRefEdge(RefSrcNode referencer,
202 HeapRegionNode referencee,
204 assert referencer != null;
205 assert referencee != null;
207 assert edge.getSrc() == referencer;
208 assert edge.getDst() == referencee;
209 assert belongsToThis(referencer);
210 assert belongsToThis(referencee);
212 // edges are getting added twice to graphs now, the
213 // kind that should have abstract facts merged--use
214 // this check to prevent that
215 assert referencer.getReferenceTo(referencee,
220 referencer.addReferencee(edge);
221 referencee.addReferencer(edge);
224 protected void removeRefEdge(RefEdge e) {
225 removeRefEdge(e.getSrc(),
231 protected void removeRefEdge(RefSrcNode referencer,
232 HeapRegionNode referencee,
235 assert referencer != null;
236 assert referencee != null;
238 RefEdge edge = referencer.getReferenceTo(referencee,
242 assert edge == referencee.getReferenceFrom(referencer,
246 referencer.removeReferencee(edge);
247 referencee.removeReferencer(edge);
250 // return whether at least one edge was removed
251 protected boolean clearRefEdgesFrom(RefSrcNode referencer,
255 assert referencer != null;
257 boolean atLeastOneEdgeRemoved = false;
259 // get a copy of the set to iterate over, otherwise
260 // we will be trying to take apart the set as we
261 // are iterating over it, which won't work
262 Iterator<RefEdge> i = referencer.iteratorToReferenceesClone();
263 while( i.hasNext() ) {
264 RefEdge edge = i.next();
267 (edge.typeEquals(type) && edge.fieldEquals(field))
270 HeapRegionNode referencee = edge.getDst();
272 removeRefEdge(referencer,
277 atLeastOneEdgeRemoved = true;
281 return atLeastOneEdgeRemoved;
284 protected void clearRefEdgesTo(HeapRegionNode referencee,
288 assert referencee != null;
290 // get a copy of the set to iterate over, otherwise
291 // we will be trying to take apart the set as we
292 // are iterating over it, which won't work
293 Iterator<RefEdge> i = referencee.iteratorToReferencersClone();
294 while( i.hasNext() ) {
295 RefEdge edge = i.next();
298 (edge.typeEquals(type) && edge.fieldEquals(field))
301 RefSrcNode referencer = edge.getSrc();
303 removeRefEdge(referencer,
311 protected void clearNonVarRefEdgesTo(HeapRegionNode referencee) {
312 assert referencee != null;
314 // get a copy of the set to iterate over, otherwise
315 // we will be trying to take apart the set as we
316 // are iterating over it, which won't work
317 Iterator<RefEdge> i = referencee.iteratorToReferencersClone();
318 while( i.hasNext() ) {
319 RefEdge edge = i.next();
320 RefSrcNode referencer = edge.getSrc();
321 if( !(referencer instanceof VariableNode) ) {
322 removeRefEdge(referencer,
330 // this is a common operation in many transfer functions: we want
331 // to add an edge, but if there is already such an edge we should
332 // merge the properties of the existing and the new edges
333 protected void addEdgeOrMergeWithExisting(RefEdge edgeNew) {
335 RefSrcNode src = edgeNew.getSrc();
336 assert belongsToThis(src);
338 HeapRegionNode dst = edgeNew.getDst();
339 assert belongsToThis(dst);
341 // look to see if an edge with same field exists
342 // and merge with it, otherwise just add the edge
343 RefEdge edgeExisting = src.getReferenceTo(dst,
348 if( edgeExisting != null ) {
349 edgeExisting.setBeta(
350 Canonical.unionORpreds(edgeExisting.getBeta(),
354 edgeExisting.setPreds(
355 Canonical.join(edgeExisting.getPreds(),
359 edgeExisting.setTaints(
360 Canonical.unionORpreds(edgeExisting.getTaints(),
366 addRefEdge(src, dst, edgeNew);
372 ////////////////////////////////////////////////////
374 // Assignment Operation Methods
376 // These methods are high-level operations for
377 // modeling program assignment statements using
378 // the low-level reference create/remove methods
381 ////////////////////////////////////////////////////
383 public void assignTempXEqualToTempY(TempDescriptor x,
385 assignTempXEqualToCastedTempY(x, y, null);
389 public void assignTempXEqualToCastedTempY(TempDescriptor x,
391 TypeDescriptor tdCast) {
393 VariableNode lnX = getVariableNodeFromTemp(x);
394 VariableNode lnY = getVariableNodeFromTemp(y);
396 clearRefEdgesFrom(lnX, null, null, true);
398 // note it is possible that the types of temps in the
399 // flat node to analyze will reveal that some typed
400 // edges in the reachability graph are impossible
401 Set<RefEdge> impossibleEdges = new HashSet<RefEdge>();
403 Iterator<RefEdge> itrYhrn = lnY.iteratorToReferencees();
404 while( itrYhrn.hasNext() ) {
405 RefEdge edgeY = itrYhrn.next();
406 HeapRegionNode referencee = edgeY.getDst();
407 RefEdge edgeNew = edgeY.copy();
409 if( !isSuperiorType(x.getType(), edgeY.getType() ) ) {
410 impossibleEdges.add(edgeY);
416 if( tdCast == null ) {
417 edgeNew.setType(mostSpecificType(y.getType(),
423 edgeNew.setType(mostSpecificType(y.getType(),
425 referencee.getType(),
431 edgeNew.setField(null);
433 addRefEdge(lnX, referencee, edgeNew);
436 Iterator<RefEdge> itrImp = impossibleEdges.iterator();
437 while( itrImp.hasNext() ) {
438 RefEdge edgeImp = itrImp.next();
439 removeRefEdge(edgeImp);
444 public void assignTempXEqualToTempYFieldF(TempDescriptor x,
447 FlatNode currentProgramPoint
450 VariableNode lnX = getVariableNodeFromTemp(x);
451 VariableNode lnY = getVariableNodeFromTemp(y);
453 clearRefEdgesFrom(lnX, null, null, true);
455 // note it is possible that the types of temps in the
456 // flat node to analyze will reveal that some typed
457 // edges in the reachability graph are impossible
458 Set<RefEdge> impossibleEdges = new HashSet<RefEdge>();
460 Iterator<RefEdge> itrYhrn = lnY.iteratorToReferencees();
461 while( itrYhrn.hasNext() ) {
462 RefEdge edgeY = itrYhrn.next();
463 HeapRegionNode hrnY = edgeY.getDst();
464 ReachSet betaY = edgeY.getBeta();
466 Iterator<RefEdge> itrHrnFhrn = hrnY.iteratorToReferencees();
468 while( itrHrnFhrn.hasNext() ) {
469 RefEdge edgeHrn = itrHrnFhrn.next();
470 HeapRegionNode hrnHrn = edgeHrn.getDst();
471 ReachSet betaHrn = edgeHrn.getBeta();
473 // prune edges that are not a matching field
474 if( edgeHrn.getType() != null &&
475 !edgeHrn.getField().equals(f.getSymbol() )
480 // check for impossible edges
481 if( !isSuperiorType(x.getType(), edgeHrn.getType() ) ) {
482 impossibleEdges.add(edgeHrn);
486 TypeDescriptor tdNewEdge =
487 mostSpecificType(edgeHrn.getType(),
491 TaintSet taints = Canonical.unionORpreds(edgeHrn.getTaints(),
495 // the DFJ way to generate taints changes for field statements
496 taints = Canonical.changeWhereDefined(taints,
497 currentProgramPoint);
500 RefEdge edgeNew = new RefEdge(lnX,
504 Canonical.intersection(betaY, betaHrn),
509 addEdgeOrMergeWithExisting(edgeNew);
513 Iterator<RefEdge> itrImp = impossibleEdges.iterator();
514 while( itrImp.hasNext() ) {
515 RefEdge edgeImp = itrImp.next();
516 removeRefEdge(edgeImp);
519 // anytime you might remove edges between heap regions
520 // you must global sweep to clean up broken reachability
521 if( !impossibleEdges.isEmpty() ) {
522 if( !DISABLE_GLOBAL_SWEEP ) {
530 // return whether a strong update was actually effected
531 public boolean assignTempXFieldFEqualToTempY(TempDescriptor x,
534 FlatNode currentProgramPoint
537 VariableNode lnX = getVariableNodeFromTemp(x);
538 VariableNode lnY = getVariableNodeFromTemp(y);
540 HashSet<HeapRegionNode> nodesWithNewAlpha = new HashSet<HeapRegionNode>();
541 HashSet<RefEdge> edgesWithNewBeta = new HashSet<RefEdge>();
543 // note it is possible that the types of temps in the
544 // flat node to analyze will reveal that some typed
545 // edges in the reachability graph are impossible
546 Set<RefEdge> impossibleEdges = new HashSet<RefEdge>();
548 // first look for possible strong updates and remove those edges
549 boolean strongUpdateCond = false;
550 boolean edgeRemovedByStrongUpdate = false;
552 Iterator<RefEdge> itrXhrn = lnX.iteratorToReferencees();
553 while( itrXhrn.hasNext() ) {
554 RefEdge edgeX = itrXhrn.next();
555 HeapRegionNode hrnX = edgeX.getDst();
557 // we can do a strong update here if one of two cases holds
559 f != DisjointAnalysis.getArrayField(f.getType() ) &&
560 ( (hrnX.getNumReferencers() == 1) || // case 1
561 (hrnX.isSingleObject() && lnX.getNumReferencees() == 1) // case 2
564 if( !DISABLE_STRONG_UPDATES ) {
565 strongUpdateCond = true;
568 clearRefEdgesFrom(hrnX,
573 edgeRemovedByStrongUpdate = true;
579 // then do all token propagation
580 itrXhrn = lnX.iteratorToReferencees();
581 while( itrXhrn.hasNext() ) {
582 RefEdge edgeX = itrXhrn.next();
583 HeapRegionNode hrnX = edgeX.getDst();
584 ReachSet betaX = edgeX.getBeta();
585 ReachSet R = Canonical.intersection(hrnX.getAlpha(),
589 Iterator<RefEdge> itrYhrn = lnY.iteratorToReferencees();
590 while( itrYhrn.hasNext() ) {
591 RefEdge edgeY = itrYhrn.next();
592 HeapRegionNode hrnY = edgeY.getDst();
593 ReachSet O = edgeY.getBeta();
595 // check for impossible edges
596 if( !isSuperiorType(f.getType(), edgeY.getType() ) ) {
597 impossibleEdges.add(edgeY);
601 // propagate tokens over nodes starting from hrnSrc, and it will
602 // take care of propagating back up edges from any touched nodes
603 ChangeSet Cy = Canonical.unionUpArityToChangeSet(O, R);
604 propagateTokensOverNodes(hrnY, Cy, nodesWithNewAlpha, edgesWithNewBeta);
606 // then propagate back just up the edges from hrn
607 ChangeSet Cx = Canonical.unionUpArityToChangeSet(R, O);
608 HashSet<RefEdge> todoEdges = new HashSet<RefEdge>();
610 Hashtable<RefEdge, ChangeSet> edgePlannedChanges =
611 new Hashtable<RefEdge, ChangeSet>();
613 Iterator<RefEdge> referItr = hrnX.iteratorToReferencers();
614 while( referItr.hasNext() ) {
615 RefEdge edgeUpstream = referItr.next();
616 todoEdges.add(edgeUpstream);
617 edgePlannedChanges.put(edgeUpstream, Cx);
620 propagateTokensOverEdges(todoEdges,
627 // apply the updates to reachability
628 Iterator<HeapRegionNode> nodeItr = nodesWithNewAlpha.iterator();
629 while( nodeItr.hasNext() ) {
630 nodeItr.next().applyAlphaNew();
633 Iterator<RefEdge> edgeItr = edgesWithNewBeta.iterator();
634 while( edgeItr.hasNext() ) {
635 edgeItr.next().applyBetaNew();
639 // then go back through and add the new edges
640 itrXhrn = lnX.iteratorToReferencees();
641 while( itrXhrn.hasNext() ) {
642 RefEdge edgeX = itrXhrn.next();
643 HeapRegionNode hrnX = edgeX.getDst();
645 Iterator<RefEdge> itrYhrn = lnY.iteratorToReferencees();
646 while( itrYhrn.hasNext() ) {
647 RefEdge edgeY = itrYhrn.next();
648 HeapRegionNode hrnY = edgeY.getDst();
650 // skip impossible edges here, we already marked them
651 // when computing reachability propagations above
652 if( !isSuperiorType(f.getType(), edgeY.getType() ) ) {
656 // prepare the new reference edge hrnX.f -> hrnY
657 TypeDescriptor tdNewEdge =
658 mostSpecificType(y.getType(),
663 TaintSet taints = edgeY.getTaints();
666 // the DFJ way to generate taints changes for field statements
667 taints = Canonical.changeWhereDefined(taints,
668 currentProgramPoint);
676 Canonical.changePredsTo(
677 Canonical.pruneBy(edgeY.getBeta(),
686 addEdgeOrMergeWithExisting(edgeNew);
690 Iterator<RefEdge> itrImp = impossibleEdges.iterator();
691 while( itrImp.hasNext() ) {
692 RefEdge edgeImp = itrImp.next();
693 removeRefEdge(edgeImp);
696 // if there was a strong update, make sure to improve
697 // reachability with a global sweep
698 if( edgeRemovedByStrongUpdate || !impossibleEdges.isEmpty() ) {
699 if( !DISABLE_GLOBAL_SWEEP ) {
704 return edgeRemovedByStrongUpdate;
708 public void assignReturnEqualToTemp(TempDescriptor x) {
710 VariableNode lnR = getVariableNodeFromTemp(tdReturn);
711 VariableNode lnX = getVariableNodeFromTemp(x);
713 clearRefEdgesFrom(lnR, null, null, true);
715 Iterator<RefEdge> itrXhrn = lnX.iteratorToReferencees();
716 while( itrXhrn.hasNext() ) {
717 RefEdge edgeX = itrXhrn.next();
718 HeapRegionNode referencee = edgeX.getDst();
719 RefEdge edgeNew = edgeX.copy();
721 edgeNew.setTaints(Canonical.changePredsTo(edgeNew.getTaints(),
726 addRefEdge(lnR, referencee, edgeNew);
731 public void assignTempEqualToNewAlloc(TempDescriptor x,
738 // after the age operation the newest (or zero-ith oldest)
739 // node associated with the allocation site should have
740 // no references to it as if it were a newly allocated
742 Integer idNewest = as.getIthOldest(0);
743 HeapRegionNode hrnNewest = id2hrn.get(idNewest);
744 assert hrnNewest != null;
746 VariableNode lnX = getVariableNodeFromTemp(x);
747 clearRefEdgesFrom(lnX, null, null, true);
749 // make a new reference to allocated node
750 TypeDescriptor type = as.getType();
753 new RefEdge(lnX, // source
757 hrnNewest.getAlpha(), // beta
758 predsTrue, // predicates
759 TaintSet.factory() // taints
762 addRefEdge(lnX, hrnNewest, edgeNew);
766 // use the allocation site (unique to entire analysis) to
767 // locate the heap region nodes in this reachability graph
768 // that should be aged. The process models the allocation
769 // of new objects and collects all the oldest allocations
770 // in a summary node to allow for a finite analysis
772 // There is an additional property of this method. After
773 // running it on a particular reachability graph (many graphs
774 // may have heap regions related to the same allocation site)
775 // the heap region node objects in this reachability graph will be
776 // allocated. Therefore, after aging a graph for an allocation
777 // site, attempts to retrieve the heap region nodes using the
778 // integer id's contained in the allocation site should always
779 // return non-null heap regions.
780 public void age(AllocSite as) {
782 // keep track of allocation sites that are represented
783 // in this graph for efficiency with other operations
786 // if there is a k-th oldest node, it merges into
788 Integer idK = as.getOldest();
789 if( id2hrn.containsKey(idK) ) {
790 HeapRegionNode hrnK = id2hrn.get(idK);
792 // retrieve the summary node, or make it
794 HeapRegionNode hrnSummary = getSummaryNode(as, false);
796 mergeIntoSummary(hrnK, hrnSummary);
799 // move down the line of heap region nodes
800 // clobbering the ith and transferring all references
801 // to and from i-1 to node i.
802 for( int i = allocationDepth - 1; i > 0; --i ) {
804 // only do the transfer if the i-1 node exists
805 Integer idImin1th = as.getIthOldest(i - 1);
806 if( id2hrn.containsKey(idImin1th) ) {
807 HeapRegionNode hrnImin1 = id2hrn.get(idImin1th);
808 if( hrnImin1.isWiped() ) {
809 // there is no info on this node, just skip
813 // either retrieve or make target of transfer
814 HeapRegionNode hrnI = getIthNode(as, i, false);
816 transferOnto(hrnImin1, hrnI);
821 // as stated above, the newest node should have had its
822 // references moved over to the second oldest, so we wipe newest
823 // in preparation for being the new object to assign something to
824 HeapRegionNode hrn0 = getIthNode(as, 0, false);
827 // now tokens in reachability sets need to "age" also
828 Iterator itrAllHRNodes = id2hrn.entrySet().iterator();
829 while( itrAllHRNodes.hasNext() ) {
830 Map.Entry me = (Map.Entry)itrAllHRNodes.next();
831 HeapRegionNode hrnToAge = (HeapRegionNode) me.getValue();
833 ageTuplesFrom(as, hrnToAge);
835 Iterator<RefEdge> itrEdges = hrnToAge.iteratorToReferencers();
836 while( itrEdges.hasNext() ) {
837 ageTuplesFrom(as, itrEdges.next() );
842 // after tokens have been aged, reset newest node's reachability
843 // and a brand new node has a "true" predicate
844 hrn0.setAlpha(hrn0.getInherent() );
845 hrn0.setPreds(predsTrue);
849 // either retrieve or create the needed heap region node
850 protected HeapRegionNode getSummaryNode(AllocSite as,
855 idSummary = as.getSummaryShadow();
857 idSummary = as.getSummary();
860 HeapRegionNode hrnSummary = id2hrn.get(idSummary);
862 if( hrnSummary == null ) {
864 String strDesc = as.toStringForDOT()+"\\nsummary";
867 createNewHeapRegionNode(idSummary, // id or null to generate a new one
868 false, // single object?
870 false, // out-of-context?
871 as.getType(), // type
872 as, // allocation site
873 null, // inherent reach
874 null, // current reach
875 predsEmpty, // predicates
876 strDesc // description
883 // either retrieve or create the needed heap region node
884 protected HeapRegionNode getIthNode(AllocSite as,
890 idIth = as.getIthOldestShadow(i);
892 idIth = as.getIthOldest(i);
895 HeapRegionNode hrnIth = id2hrn.get(idIth);
897 if( hrnIth == null ) {
899 String strDesc = as.toStringForDOT()+"\\n"+i+" oldest";
901 hrnIth = createNewHeapRegionNode(idIth, // id or null to generate a new one
902 true, // single object?
904 false, // out-of-context?
905 as.getType(), // type
906 as, // allocation site
907 null, // inherent reach
908 null, // current reach
909 predsEmpty, // predicates
910 strDesc // description
918 protected void mergeIntoSummary(HeapRegionNode hrn,
919 HeapRegionNode hrnSummary) {
920 assert hrnSummary.isNewSummary();
922 // assert that these nodes belong to THIS graph
923 assert belongsToThis(hrn);
924 assert belongsToThis(hrnSummary);
926 assert hrn != hrnSummary;
928 // transfer references _from_ hrn over to hrnSummary
929 Iterator<RefEdge> itrReferencee = hrn.iteratorToReferencees();
930 while( itrReferencee.hasNext() ) {
931 RefEdge edge = itrReferencee.next();
932 RefEdge edgeMerged = edge.copy();
933 edgeMerged.setSrc(hrnSummary);
935 HeapRegionNode hrnReferencee = edge.getDst();
936 RefEdge edgeSummary =
937 hrnSummary.getReferenceTo(hrnReferencee,
942 if( edgeSummary == null ) {
943 // the merge is trivial, nothing to be done
944 addRefEdge(hrnSummary, hrnReferencee, edgeMerged);
947 // otherwise an edge from the referencer to hrnSummary exists already
948 // and the edge referencer->hrn should be merged with it
950 Canonical.unionORpreds(edgeMerged.getBeta(),
951 edgeSummary.getBeta()
954 edgeSummary.setPreds(
955 Canonical.join(edgeMerged.getPreds(),
956 edgeSummary.getPreds()
962 // next transfer references _to_ hrn over to hrnSummary
963 Iterator<RefEdge> itrReferencer = hrn.iteratorToReferencers();
964 while( itrReferencer.hasNext() ) {
965 RefEdge edge = itrReferencer.next();
966 RefEdge edgeMerged = edge.copy();
967 edgeMerged.setDst(hrnSummary);
969 RefSrcNode onReferencer = edge.getSrc();
970 RefEdge edgeSummary =
971 onReferencer.getReferenceTo(hrnSummary,
976 if( edgeSummary == null ) {
977 // the merge is trivial, nothing to be done
978 addRefEdge(onReferencer, hrnSummary, edgeMerged);
981 // otherwise an edge from the referencer to alpha_S exists already
982 // and the edge referencer->alpha_K should be merged with it
984 Canonical.unionORpreds(edgeMerged.getBeta(),
985 edgeSummary.getBeta()
988 edgeSummary.setPreds(
989 Canonical.join(edgeMerged.getPreds(),
990 edgeSummary.getPreds()
996 // then merge hrn reachability into hrnSummary
998 Canonical.unionORpreds(hrnSummary.getAlpha(),
1003 hrnSummary.setPreds(
1004 Canonical.join(hrnSummary.getPreds(),
1009 // and afterward, this node is gone
1014 protected void transferOnto(HeapRegionNode hrnA,
1015 HeapRegionNode hrnB) {
1017 assert belongsToThis(hrnA);
1018 assert belongsToThis(hrnB);
1019 assert hrnA != hrnB;
1021 // clear references in and out of node b?
1022 assert hrnB.isWiped();
1024 // copy each: (edge in and out of A) to B
1025 Iterator<RefEdge> itrReferencee = hrnA.iteratorToReferencees();
1026 while( itrReferencee.hasNext() ) {
1027 RefEdge edge = itrReferencee.next();
1028 HeapRegionNode hrnReferencee = edge.getDst();
1029 RefEdge edgeNew = edge.copy();
1030 edgeNew.setSrc(hrnB);
1031 edgeNew.setDst(hrnReferencee);
1033 addRefEdge(hrnB, hrnReferencee, edgeNew);
1036 Iterator<RefEdge> itrReferencer = hrnA.iteratorToReferencers();
1037 while( itrReferencer.hasNext() ) {
1038 RefEdge edge = itrReferencer.next();
1039 RefSrcNode rsnReferencer = edge.getSrc();
1040 RefEdge edgeNew = edge.copy();
1041 edgeNew.setSrc(rsnReferencer);
1042 edgeNew.setDst(hrnB);
1044 addRefEdge(rsnReferencer, hrnB, edgeNew);
1047 // replace hrnB reachability and preds with hrnA's
1048 hrnB.setAlpha(hrnA.getAlpha() );
1049 hrnB.setPreds(hrnA.getPreds() );
1051 // after transfer, wipe out source
1052 wipeOut(hrnA, true);
1056 // the purpose of this method is to conceptually "wipe out"
1057 // a heap region from the graph--purposefully not called REMOVE
1058 // because the node is still hanging around in the graph, just
1059 // not mechanically connected or have any reach or predicate
1060 // information on it anymore--lots of ops can use this
1061 protected void wipeOut(HeapRegionNode hrn,
1062 boolean wipeVariableReferences) {
1064 assert belongsToThis(hrn);
1066 clearRefEdgesFrom(hrn, null, null, true);
1068 if( wipeVariableReferences ) {
1069 clearRefEdgesTo(hrn, null, null, true);
1071 clearNonVarRefEdgesTo(hrn);
1074 hrn.setAlpha(rsetEmpty);
1075 hrn.setPreds(predsEmpty);
1079 protected void ageTuplesFrom(AllocSite as, RefEdge edge) {
1081 Canonical.ageTuplesFrom(edge.getBeta(),
1087 protected void ageTuplesFrom(AllocSite as, HeapRegionNode hrn) {
1089 Canonical.ageTuplesFrom(hrn.getAlpha(),
1097 protected void propagateTokensOverNodes(HeapRegionNode nPrime,
1099 HashSet<HeapRegionNode> nodesWithNewAlpha,
1100 HashSet<RefEdge> edgesWithNewBeta) {
1102 HashSet<HeapRegionNode> todoNodes
1103 = new HashSet<HeapRegionNode>();
1104 todoNodes.add(nPrime);
1106 HashSet<RefEdge> todoEdges
1107 = new HashSet<RefEdge>();
1109 Hashtable<HeapRegionNode, ChangeSet> nodePlannedChanges
1110 = new Hashtable<HeapRegionNode, ChangeSet>();
1111 nodePlannedChanges.put(nPrime, c0);
1113 Hashtable<RefEdge, ChangeSet> edgePlannedChanges
1114 = new Hashtable<RefEdge, ChangeSet>();
1116 // first propagate change sets everywhere they can go
1117 while( !todoNodes.isEmpty() ) {
1118 HeapRegionNode n = todoNodes.iterator().next();
1119 ChangeSet C = nodePlannedChanges.get(n);
1121 Iterator<RefEdge> referItr = n.iteratorToReferencers();
1122 while( referItr.hasNext() ) {
1123 RefEdge edge = referItr.next();
1124 todoEdges.add(edge);
1126 if( !edgePlannedChanges.containsKey(edge) ) {
1127 edgePlannedChanges.put(edge,
1132 edgePlannedChanges.put(edge,
1133 Canonical.union(edgePlannedChanges.get(edge),
1139 Iterator<RefEdge> refeeItr = n.iteratorToReferencees();
1140 while( refeeItr.hasNext() ) {
1141 RefEdge edgeF = refeeItr.next();
1142 HeapRegionNode m = edgeF.getDst();
1144 ChangeSet changesToPass = ChangeSet.factory();
1146 Iterator<ChangeTuple> itrCprime = C.iterator();
1147 while( itrCprime.hasNext() ) {
1148 ChangeTuple c = itrCprime.next();
1149 if( edgeF.getBeta().containsIgnorePreds(c.getStateToMatch() )
1152 changesToPass = Canonical.add(changesToPass, c);
1156 if( !changesToPass.isEmpty() ) {
1157 if( !nodePlannedChanges.containsKey(m) ) {
1158 nodePlannedChanges.put(m, ChangeSet.factory() );
1161 ChangeSet currentChanges = nodePlannedChanges.get(m);
1163 if( !changesToPass.isSubset(currentChanges) ) {
1165 nodePlannedChanges.put(m,
1166 Canonical.union(currentChanges,
1175 todoNodes.remove(n);
1178 // then apply all of the changes for each node at once
1179 Iterator itrMap = nodePlannedChanges.entrySet().iterator();
1180 while( itrMap.hasNext() ) {
1181 Map.Entry me = (Map.Entry)itrMap.next();
1182 HeapRegionNode n = (HeapRegionNode) me.getKey();
1183 ChangeSet C = (ChangeSet) me.getValue();
1185 // this propagation step is with respect to one change,
1186 // so we capture the full change from the old alpha:
1187 ReachSet localDelta = Canonical.applyChangeSet(n.getAlpha(),
1191 // but this propagation may be only one of many concurrent
1192 // possible changes, so keep a running union with the node's
1193 // partially updated new alpha set
1194 n.setAlphaNew(Canonical.unionORpreds(n.getAlphaNew(),
1199 nodesWithNewAlpha.add(n);
1202 propagateTokensOverEdges(todoEdges,
1209 protected void propagateTokensOverEdges(HashSet <RefEdge> todoEdges,
1210 Hashtable<RefEdge, ChangeSet> edgePlannedChanges,
1211 HashSet <RefEdge> edgesWithNewBeta) {
1213 // first propagate all change tuples everywhere they can go
1214 while( !todoEdges.isEmpty() ) {
1215 RefEdge edgeE = todoEdges.iterator().next();
1216 todoEdges.remove(edgeE);
1218 if( !edgePlannedChanges.containsKey(edgeE) ) {
1219 edgePlannedChanges.put(edgeE,
1224 ChangeSet C = edgePlannedChanges.get(edgeE);
1226 ChangeSet changesToPass = ChangeSet.factory();
1228 Iterator<ChangeTuple> itrC = C.iterator();
1229 while( itrC.hasNext() ) {
1230 ChangeTuple c = itrC.next();
1231 if( edgeE.getBeta().containsIgnorePreds(c.getStateToMatch() )
1234 changesToPass = Canonical.add(changesToPass, c);
1238 RefSrcNode rsn = edgeE.getSrc();
1240 if( !changesToPass.isEmpty() && rsn instanceof HeapRegionNode ) {
1241 HeapRegionNode n = (HeapRegionNode) rsn;
1243 Iterator<RefEdge> referItr = n.iteratorToReferencers();
1244 while( referItr.hasNext() ) {
1245 RefEdge edgeF = referItr.next();
1247 if( !edgePlannedChanges.containsKey(edgeF) ) {
1248 edgePlannedChanges.put(edgeF,
1253 ChangeSet currentChanges = edgePlannedChanges.get(edgeF);
1255 if( !changesToPass.isSubset(currentChanges) ) {
1256 todoEdges.add(edgeF);
1257 edgePlannedChanges.put(edgeF,
1258 Canonical.union(currentChanges,
1267 // then apply all of the changes for each edge at once
1268 Iterator itrMap = edgePlannedChanges.entrySet().iterator();
1269 while( itrMap.hasNext() ) {
1270 Map.Entry me = (Map.Entry)itrMap.next();
1271 RefEdge e = (RefEdge) me.getKey();
1272 ChangeSet C = (ChangeSet) me.getValue();
1274 // this propagation step is with respect to one change,
1275 // so we capture the full change from the old beta:
1276 ReachSet localDelta =
1277 Canonical.applyChangeSet(e.getBeta(),
1282 // but this propagation may be only one of many concurrent
1283 // possible changes, so keep a running union with the edge's
1284 // partially updated new beta set
1285 e.setBetaNew(Canonical.unionORpreds(e.getBetaNew(),
1290 edgesWithNewBeta.add(e);
1295 public void taintInSetVars(FlatSESEEnterNode sese) {
1297 Iterator<TempDescriptor> isvItr = sese.getInVarSet().iterator();
1298 while( isvItr.hasNext() ) {
1299 TempDescriptor isv = isvItr.next();
1301 // use this where defined flatnode to support RCR/DFJ
1302 FlatNode whereDefined = null;
1304 whereDefined = sese;
1307 // in-set var taints should NOT propagate back into callers
1308 // so give it FALSE(EMPTY) predicates
1318 public void taintStallSite(FlatNode stallSite,
1319 TempDescriptor var) {
1321 // use this where defined flatnode to support RCR/DFJ
1322 FlatNode whereDefined = null;
1324 whereDefined = stallSite;
1327 // stall site taint should propagate back into callers
1328 // so give it TRUE predicates
1337 protected void taintTemp(FlatSESEEnterNode sese,
1340 FlatNode whereDefined,
1344 VariableNode vn = getVariableNodeFromTemp(var);
1346 Iterator<RefEdge> reItr = vn.iteratorToReferencees();
1347 while( reItr.hasNext() ) {
1348 RefEdge re = reItr.next();
1350 Taint taint = Taint.factory(sese,
1353 re.getDst().getAllocSite(),
1358 re.setTaints(Canonical.add(re.getTaints(),
1365 public void removeInContextTaints(FlatSESEEnterNode sese) {
1367 Iterator meItr = id2hrn.entrySet().iterator();
1368 while( meItr.hasNext() ) {
1369 Map.Entry me = (Map.Entry)meItr.next();
1370 Integer id = (Integer) me.getKey();
1371 HeapRegionNode hrn = (HeapRegionNode) me.getValue();
1373 Iterator<RefEdge> reItr = hrn.iteratorToReferencers();
1374 while( reItr.hasNext() ) {
1375 RefEdge re = reItr.next();
1377 re.setTaints(Canonical.removeInContextTaints(re.getTaints(),
1385 public void removeAllStallSiteTaints() {
1387 Iterator meItr = id2hrn.entrySet().iterator();
1388 while( meItr.hasNext() ) {
1389 Map.Entry me = (Map.Entry)meItr.next();
1390 Integer id = (Integer) me.getKey();
1391 HeapRegionNode hrn = (HeapRegionNode) me.getValue();
1393 Iterator<RefEdge> reItr = hrn.iteratorToReferencers();
1394 while( reItr.hasNext() ) {
1395 RefEdge re = reItr.next();
1397 re.setTaints(Canonical.removeStallSiteTaints(re.getTaints()
1405 // used in makeCalleeView below to decide if there is
1406 // already an appropriate out-of-context edge in a callee
1407 // view graph for merging, or null if a new one will be added
1409 getOutOfContextReferenceTo(HeapRegionNode hrn,
1410 TypeDescriptor srcType,
1411 TypeDescriptor refType,
1413 assert belongsToThis(hrn);
1415 HeapRegionNode hrnInContext = id2hrn.get(hrn.getID() );
1416 if( hrnInContext == null ) {
1420 Iterator<RefEdge> refItr = hrnInContext.iteratorToReferencers();
1421 while( refItr.hasNext() ) {
1422 RefEdge re = refItr.next();
1424 assert belongsToThis(re.getSrc() );
1425 assert belongsToThis(re.getDst() );
1427 if( !(re.getSrc() instanceof HeapRegionNode) ) {
1431 HeapRegionNode hrnSrc = (HeapRegionNode) re.getSrc();
1432 if( !hrnSrc.isOutOfContext() ) {
1436 if( srcType == null ) {
1437 if( hrnSrc.getType() != null ) {
1441 if( !srcType.equals(hrnSrc.getType() ) ) {
1446 if( !re.typeEquals(refType) ) {
1450 if( !re.fieldEquals(refField) ) {
1454 // tada! We found it!
1461 // used below to convert a ReachSet to its callee-context
1462 // equivalent with respect to allocation sites in this graph
1463 protected ReachSet toCalleeContext(ReachSet rs,
1464 ExistPredSet predsNodeOrEdge,
1465 Set<HrnIdOoc> oocHrnIdOoc2callee
1467 ReachSet out = ReachSet.factory();
1469 Iterator<ReachState> itr = rs.iterator();
1470 while( itr.hasNext() ) {
1471 ReachState stateCaller = itr.next();
1473 ReachState stateCallee = stateCaller;
1475 Iterator<AllocSite> asItr = allocSites.iterator();
1476 while( asItr.hasNext() ) {
1477 AllocSite as = asItr.next();
1479 ReachState stateNew = ReachState.factory();
1480 Iterator<ReachTuple> rtItr = stateCallee.iterator();
1481 while( rtItr.hasNext() ) {
1482 ReachTuple rt = rtItr.next();
1484 // only translate this tuple if it is
1485 // in the out-callee-context bag
1486 HrnIdOoc hio = new HrnIdOoc(rt.getHrnID(),
1489 if( !oocHrnIdOoc2callee.contains(hio) ) {
1490 stateNew = Canonical.addUpArity(stateNew, rt);
1494 int age = as.getAgeCategory(rt.getHrnID() );
1496 // this is the current mapping, where 0, 1, 2S were allocated
1497 // in the current context, 0?, 1? and 2S? were allocated in a
1498 // previous context, and we're translating to a future context
1510 if( age == AllocSite.AGE_notInThisSite ) {
1511 // things not from the site just go back in
1512 stateNew = Canonical.addUpArity(stateNew, rt);
1514 } else if( age == AllocSite.AGE_summary ||
1518 stateNew = Canonical.addUpArity(stateNew,
1519 ReachTuple.factory(as.getSummary(),
1522 true // out-of-context
1527 // otherwise everything else just goes to an out-of-context
1528 // version, everything else the same
1529 Integer I = as.getAge(rt.getHrnID() );
1532 assert !rt.isMultiObject();
1534 stateNew = Canonical.addUpArity(stateNew,
1535 ReachTuple.factory(rt.getHrnID(),
1536 rt.isMultiObject(), // multi
1538 true // out-of-context
1544 stateCallee = stateNew;
1547 // make a predicate of the caller graph element
1548 // and the caller state we just converted
1549 ExistPredSet predsWithState = ExistPredSet.factory();
1551 Iterator<ExistPred> predItr = predsNodeOrEdge.iterator();
1552 while( predItr.hasNext() ) {
1553 ExistPred predNodeOrEdge = predItr.next();
1556 Canonical.add(predsWithState,
1557 ExistPred.factory(predNodeOrEdge.n_hrnID,
1558 predNodeOrEdge.e_tdSrc,
1559 predNodeOrEdge.e_hrnSrcID,
1560 predNodeOrEdge.e_hrnDstID,
1561 predNodeOrEdge.e_type,
1562 predNodeOrEdge.e_field,
1565 predNodeOrEdge.e_srcOutCalleeContext,
1566 predNodeOrEdge.e_srcOutCallerContext
1571 stateCallee = Canonical.changePredsTo(stateCallee,
1574 out = Canonical.add(out,
1578 assert out.isCanonical();
1582 // used below to convert a ReachSet to its caller-context
1583 // equivalent with respect to allocation sites in this graph
1585 toCallerContext(ReachSet rs,
1586 Hashtable<ReachState, ExistPredSet> calleeStatesSatisfied
1588 ReachSet out = ReachSet.factory();
1590 // when the mapping is null it means there were no
1591 // predicates satisfied
1592 if( calleeStatesSatisfied == null ) {
1596 Iterator<ReachState> itr = rs.iterator();
1597 while( itr.hasNext() ) {
1598 ReachState stateCallee = itr.next();
1600 if( calleeStatesSatisfied.containsKey(stateCallee) ) {
1602 // starting from one callee state...
1603 ReachSet rsCaller = ReachSet.factory(stateCallee);
1605 // possibly branch it into many states, which any
1606 // allocation site might do, so lots of derived states
1607 Iterator<AllocSite> asItr = allocSites.iterator();
1608 while( asItr.hasNext() ) {
1609 AllocSite as = asItr.next();
1610 rsCaller = Canonical.toCallerContext(rsCaller, as);
1613 // then before adding each derived, now caller-context
1614 // states to the output, attach the appropriate pred
1615 // based on the source callee state
1616 Iterator<ReachState> stateItr = rsCaller.iterator();
1617 while( stateItr.hasNext() ) {
1618 ReachState stateCaller = stateItr.next();
1619 stateCaller = Canonical.attach(stateCaller,
1620 calleeStatesSatisfied.get(stateCallee)
1622 out = Canonical.add(out,
1629 assert out.isCanonical();
1634 // used below to convert a ReachSet to an equivalent
1635 // version with shadow IDs merged into unshadowed IDs
1636 protected ReachSet unshadow(ReachSet rs) {
1638 Iterator<AllocSite> asItr = allocSites.iterator();
1639 while( asItr.hasNext() ) {
1640 AllocSite as = asItr.next();
1641 out = Canonical.unshadow(out, as);
1643 assert out.isCanonical();
1648 // convert a caller taint set into a callee taint set
1650 toCalleeContext(TaintSet ts,
1651 ExistPredSet predsEdge) {
1653 TaintSet out = TaintSet.factory();
1655 // the idea is easy, the taint identifier itself doesn't
1656 // change at all, but the predicates should be tautology:
1657 // start with the preds passed in from the caller edge
1658 // that host the taints, and alter them to have the taint
1659 // added, just becoming more specific than edge predicate alone
1661 Iterator<Taint> itr = ts.iterator();
1662 while( itr.hasNext() ) {
1663 Taint tCaller = itr.next();
1665 ExistPredSet predsWithTaint = ExistPredSet.factory();
1667 Iterator<ExistPred> predItr = predsEdge.iterator();
1668 while( predItr.hasNext() ) {
1669 ExistPred predEdge = predItr.next();
1672 Canonical.add(predsWithTaint,
1673 ExistPred.factory(predEdge.e_tdSrc,
1674 predEdge.e_hrnSrcID,
1675 predEdge.e_hrnDstID,
1680 predEdge.e_srcOutCalleeContext,
1681 predEdge.e_srcOutCallerContext
1686 Taint tCallee = Canonical.changePredsTo(tCaller,
1689 out = Canonical.add(out,
1694 assert out.isCanonical();
1699 // used below to convert a TaintSet to its caller-context
1700 // equivalent, just eliminate Taints with bad preds
1702 toCallerContext(TaintSet ts,
1703 Hashtable<Taint, ExistPredSet> calleeTaintsSatisfied
1706 TaintSet out = TaintSet.factory();
1708 // when the mapping is null it means there were no
1709 // predicates satisfied
1710 if( calleeTaintsSatisfied == null ) {
1714 Iterator<Taint> itr = ts.iterator();
1715 while( itr.hasNext() ) {
1716 Taint tCallee = itr.next();
1718 if( calleeTaintsSatisfied.containsKey(tCallee) ) {
1721 Canonical.attach(Taint.factory(tCallee.sese,
1726 ExistPredSet.factory() ),
1727 calleeTaintsSatisfied.get(tCallee)
1729 out = Canonical.add(out,
1735 assert out.isCanonical();
1742 // use this method to make a new reach graph that is
1743 // what heap the FlatMethod callee from the FlatCall
1744 // would start with reaching from its arguments in
1747 makeCalleeView(FlatCall fc,
1748 FlatMethod fmCallee,
1749 Set<Integer> callerNodeIDsCopiedToCallee,
1750 boolean writeDebugDOTs
1754 // first traverse this context to find nodes and edges
1755 // that will be callee-reachable
1756 Set<HeapRegionNode> reachableCallerNodes =
1757 new HashSet<HeapRegionNode>();
1759 // caller edges between callee-reachable nodes
1760 Set<RefEdge> reachableCallerEdges =
1761 new HashSet<RefEdge>();
1763 // caller edges from arg vars, and the matching param index
1764 // because these become a special edge in callee
1765 Hashtable<RefEdge, Integer> reachableCallerArgEdges2paramIndex =
1766 new Hashtable<RefEdge, Integer>();
1768 // caller edges from local vars or callee-unreachable nodes
1769 // (out-of-context sources) to callee-reachable nodes
1770 Set<RefEdge> oocCallerEdges =
1771 new HashSet<RefEdge>();
1774 for( int i = 0; i < fmCallee.numParameters(); ++i ) {
1776 TempDescriptor tdArg = fc.getArgMatchingParamIndex(fmCallee, i);
1777 VariableNode vnArgCaller = this.getVariableNodeFromTemp(tdArg);
1779 Set<RefSrcNode> toVisitInCaller = new HashSet<RefSrcNode>();
1780 Set<RefSrcNode> visitedInCaller = new HashSet<RefSrcNode>();
1782 toVisitInCaller.add(vnArgCaller);
1784 while( !toVisitInCaller.isEmpty() ) {
1785 RefSrcNode rsnCaller = toVisitInCaller.iterator().next();
1786 toVisitInCaller.remove(rsnCaller);
1787 visitedInCaller.add(rsnCaller);
1789 Iterator<RefEdge> itrRefEdges = rsnCaller.iteratorToReferencees();
1790 while( itrRefEdges.hasNext() ) {
1791 RefEdge reCaller = itrRefEdges.next();
1792 HeapRegionNode hrnCaller = reCaller.getDst();
1794 callerNodeIDsCopiedToCallee.add(hrnCaller.getID() );
1795 reachableCallerNodes.add(hrnCaller);
1797 if( reCaller.getSrc() instanceof HeapRegionNode ) {
1798 reachableCallerEdges.add(reCaller);
1800 if( rsnCaller.equals(vnArgCaller) ) {
1801 reachableCallerArgEdges2paramIndex.put(reCaller, i);
1803 oocCallerEdges.add(reCaller);
1807 if( !visitedInCaller.contains(hrnCaller) ) {
1808 toVisitInCaller.add(hrnCaller);
1811 } // end edge iteration
1812 } // end visiting heap nodes in caller
1813 } // end iterating over parameters as starting points
1816 // now collect out-of-callee-context IDs and
1817 // map them to whether the ID is out of the caller
1819 Set<HrnIdOoc> oocHrnIdOoc2callee = new HashSet<HrnIdOoc>();
1821 Iterator<Integer> itrInContext =
1822 callerNodeIDsCopiedToCallee.iterator();
1823 while( itrInContext.hasNext() ) {
1824 Integer hrnID = itrInContext.next();
1825 HeapRegionNode hrnCallerAndInContext = id2hrn.get(hrnID);
1827 Iterator<RefEdge> itrMightCross =
1828 hrnCallerAndInContext.iteratorToReferencers();
1829 while( itrMightCross.hasNext() ) {
1830 RefEdge edgeMightCross = itrMightCross.next();
1832 RefSrcNode rsnCallerAndOutContext =
1833 edgeMightCross.getSrc();
1835 if( rsnCallerAndOutContext instanceof VariableNode ) {
1836 // variables do not have out-of-context reach states,
1838 oocCallerEdges.add(edgeMightCross);
1842 HeapRegionNode hrnCallerAndOutContext =
1843 (HeapRegionNode) rsnCallerAndOutContext;
1845 // is this source node out-of-context?
1846 if( callerNodeIDsCopiedToCallee.contains(hrnCallerAndOutContext.getID() ) ) {
1847 // no, skip this edge
1852 oocCallerEdges.add(edgeMightCross);
1854 // add all reach tuples on the node to list
1855 // of things that are out-of-context: insight
1856 // if this node is reachable from someting that WAS
1857 // in-context, then this node should already be in-context
1858 Iterator<ReachState> stateItr = hrnCallerAndOutContext.getAlpha().iterator();
1859 while( stateItr.hasNext() ) {
1860 ReachState state = stateItr.next();
1862 Iterator<ReachTuple> rtItr = state.iterator();
1863 while( rtItr.hasNext() ) {
1864 ReachTuple rt = rtItr.next();
1866 oocHrnIdOoc2callee.add(new HrnIdOoc(rt.getHrnID(),
1875 // the callee view is a new graph: DON'T MODIFY *THIS* graph
1876 ReachGraph rg = new ReachGraph();
1878 // add nodes to callee graph
1879 Iterator<HeapRegionNode> hrnItr = reachableCallerNodes.iterator();
1880 while( hrnItr.hasNext() ) {
1881 HeapRegionNode hrnCaller = hrnItr.next();
1883 assert callerNodeIDsCopiedToCallee.contains(hrnCaller.getID() );
1884 assert !rg.id2hrn.containsKey(hrnCaller.getID() );
1886 ExistPred pred = ExistPred.factory(hrnCaller.getID(), null);
1887 ExistPredSet preds = ExistPredSet.factory(pred);
1889 rg.createNewHeapRegionNode(hrnCaller.getID(),
1890 hrnCaller.isSingleObject(),
1891 hrnCaller.isNewSummary(),
1892 false, // out-of-context?
1893 hrnCaller.getType(),
1894 hrnCaller.getAllocSite(),
1895 toCalleeContext(hrnCaller.getInherent(),
1899 toCalleeContext(hrnCaller.getAlpha(),
1904 hrnCaller.getDescription()
1908 // add param edges to callee graph
1910 reachableCallerArgEdges2paramIndex.entrySet().iterator();
1911 while( argEdges.hasNext() ) {
1912 Map.Entry me = (Map.Entry)argEdges.next();
1913 RefEdge reArg = (RefEdge) me.getKey();
1914 Integer index = (Integer) me.getValue();
1916 VariableNode vnCaller = (VariableNode) reArg.getSrc();
1917 TempDescriptor argCaller = vnCaller.getTempDescriptor();
1919 TempDescriptor paramCallee = fmCallee.getParameter(index);
1920 VariableNode vnCallee = rg.getVariableNodeFromTemp(paramCallee);
1922 HeapRegionNode hrnDstCaller = reArg.getDst();
1923 HeapRegionNode hrnDstCallee = rg.id2hrn.get(hrnDstCaller.getID() );
1924 assert hrnDstCallee != null;
1927 ExistPred.factory(argCaller,
1929 hrnDstCallee.getID(),
1934 true, // out-of-callee-context
1935 false // out-of-caller-context
1938 ExistPredSet preds =
1939 ExistPredSet.factory(pred);
1942 new RefEdge(vnCallee,
1946 toCalleeContext(reArg.getBeta(),
1951 toCalleeContext(reArg.getTaints(),
1955 rg.addRefEdge(vnCallee,
1961 // add in-context edges to callee graph
1962 Iterator<RefEdge> reItr = reachableCallerEdges.iterator();
1963 while( reItr.hasNext() ) {
1964 RefEdge reCaller = reItr.next();
1965 RefSrcNode rsnCaller = reCaller.getSrc();
1966 assert rsnCaller instanceof HeapRegionNode;
1967 HeapRegionNode hrnSrcCaller = (HeapRegionNode) rsnCaller;
1968 HeapRegionNode hrnDstCaller = reCaller.getDst();
1970 HeapRegionNode hrnSrcCallee = rg.id2hrn.get(hrnSrcCaller.getID() );
1971 HeapRegionNode hrnDstCallee = rg.id2hrn.get(hrnDstCaller.getID() );
1972 assert hrnSrcCallee != null;
1973 assert hrnDstCallee != null;
1976 ExistPred.factory(null,
1977 hrnSrcCallee.getID(),
1978 hrnDstCallee.getID(),
1980 reCaller.getField(),
1983 false, // out-of-callee-context
1984 false // out-of-caller-context
1987 ExistPredSet preds =
1988 ExistPredSet.factory(pred);
1991 new RefEdge(hrnSrcCallee,
1994 reCaller.getField(),
1995 toCalleeContext(reCaller.getBeta(),
2000 toCalleeContext(reCaller.getTaints(),
2004 rg.addRefEdge(hrnSrcCallee,
2010 // add out-of-context edges to callee graph
2011 reItr = oocCallerEdges.iterator();
2012 while( reItr.hasNext() ) {
2013 RefEdge reCaller = reItr.next();
2014 RefSrcNode rsnCaller = reCaller.getSrc();
2015 HeapRegionNode hrnDstCaller = reCaller.getDst();
2016 HeapRegionNode hrnDstCallee = rg.id2hrn.get(hrnDstCaller.getID() );
2017 assert hrnDstCallee != null;
2019 TypeDescriptor oocNodeType;
2021 TempDescriptor oocPredSrcTemp = null;
2022 Integer oocPredSrcID = null;
2023 boolean outOfCalleeContext;
2024 boolean outOfCallerContext;
2026 if( rsnCaller instanceof VariableNode ) {
2027 VariableNode vnCaller = (VariableNode) rsnCaller;
2029 oocReach = rsetEmpty;
2030 oocPredSrcTemp = vnCaller.getTempDescriptor();
2031 outOfCalleeContext = true;
2032 outOfCallerContext = false;
2035 HeapRegionNode hrnSrcCaller = (HeapRegionNode) rsnCaller;
2036 assert !callerNodeIDsCopiedToCallee.contains(hrnSrcCaller.getID() );
2037 oocNodeType = hrnSrcCaller.getType();
2038 oocReach = hrnSrcCaller.getAlpha();
2039 oocPredSrcID = hrnSrcCaller.getID();
2040 if( hrnSrcCaller.isOutOfContext() ) {
2041 outOfCalleeContext = false;
2042 outOfCallerContext = true;
2044 outOfCalleeContext = true;
2045 outOfCallerContext = false;
2050 ExistPred.factory(oocPredSrcTemp,
2052 hrnDstCallee.getID(),
2054 reCaller.getField(),
2061 ExistPredSet preds =
2062 ExistPredSet.factory(pred);
2064 RefEdge oocEdgeExisting =
2065 rg.getOutOfContextReferenceTo(hrnDstCallee,
2071 if( oocEdgeExisting == null ) {
2072 // for consistency, map one out-of-context "identifier"
2073 // to one heap region node id, otherwise no convergence
2074 String oocid = "oocid"+
2076 hrnDstCallee.getIDString()+
2079 reCaller.getField();
2081 Integer oocHrnID = oocid2hrnid.get(oocid);
2083 HeapRegionNode hrnCalleeAndOutContext;
2085 if( oocHrnID == null ) {
2087 hrnCalleeAndOutContext =
2088 rg.createNewHeapRegionNode(null, // ID
2089 false, // single object?
2090 false, // new summary?
2091 true, // out-of-context?
2093 null, // alloc site, shouldn't be used
2094 toCalleeContext(oocReach,
2098 toCalleeContext(oocReach,
2106 oocid2hrnid.put(oocid, hrnCalleeAndOutContext.getID() );
2110 // the mapping already exists, so see if node is there
2111 hrnCalleeAndOutContext = rg.id2hrn.get(oocHrnID);
2113 if( hrnCalleeAndOutContext == null ) {
2115 hrnCalleeAndOutContext =
2116 rg.createNewHeapRegionNode(oocHrnID, // ID
2117 false, // single object?
2118 false, // new summary?
2119 true, // out-of-context?
2121 null, // alloc site, shouldn't be used
2122 toCalleeContext(oocReach,
2126 toCalleeContext(oocReach,
2135 // otherwise it is there, so merge reachability
2136 hrnCalleeAndOutContext.setAlpha(Canonical.unionORpreds(hrnCalleeAndOutContext.getAlpha(),
2137 toCalleeContext(oocReach,
2146 assert hrnCalleeAndOutContext.reachHasOnlyOOC();
2148 rg.addRefEdge(hrnCalleeAndOutContext,
2150 new RefEdge(hrnCalleeAndOutContext,
2153 reCaller.getField(),
2154 toCalleeContext(reCaller.getBeta(),
2159 toCalleeContext(reCaller.getTaints(),
2165 // the out-of-context edge already exists
2166 oocEdgeExisting.setBeta(Canonical.unionORpreds(oocEdgeExisting.getBeta(),
2167 toCalleeContext(reCaller.getBeta(),
2174 oocEdgeExisting.setPreds(Canonical.join(oocEdgeExisting.getPreds(),
2179 oocEdgeExisting.setTaints(Canonical.unionORpreds(oocEdgeExisting.getTaints(),
2180 toCalleeContext(reCaller.getTaints(),
2186 HeapRegionNode hrnCalleeAndOutContext =
2187 (HeapRegionNode) oocEdgeExisting.getSrc();
2188 hrnCalleeAndOutContext.setAlpha(Canonical.unionORpreds(hrnCalleeAndOutContext.getAlpha(),
2189 toCalleeContext(oocReach,
2196 assert hrnCalleeAndOutContext.reachHasOnlyOOC();
2201 if( writeDebugDOTs ) {
2202 debugGraphPrefix = String.format("call%03d", debugCallSiteVisitCounter);
2203 rg.writeGraph(debugGraphPrefix+"calleeview",
2204 resolveMethodDebugDOTwriteLabels,
2205 resolveMethodDebugDOTselectTemps,
2206 resolveMethodDebugDOTpruneGarbage,
2207 resolveMethodDebugDOThideReach,
2208 resolveMethodDebugDOThideSubsetReach,
2209 resolveMethodDebugDOThidePreds,
2210 resolveMethodDebugDOThideEdgeTaints);
2216 private static Hashtable<String, Integer> oocid2hrnid =
2217 new Hashtable<String, Integer>();
2220 // useful since many graphs writes in the method call debug code
2221 private static boolean resolveMethodDebugDOTwriteLabels = true;
2222 private static boolean resolveMethodDebugDOTselectTemps = true;
2223 private static boolean resolveMethodDebugDOTpruneGarbage = true;
2224 private static boolean resolveMethodDebugDOThideReach = false;
2225 private static boolean resolveMethodDebugDOThideSubsetReach = false;
2226 private static boolean resolveMethodDebugDOThidePreds = true;
2227 private static boolean resolveMethodDebugDOThideEdgeTaints = true;
2229 static String debugGraphPrefix;
2230 static int debugCallSiteVisitCounter;
2231 static int debugCallSiteVisitStartCapture;
2232 static int debugCallSiteNumVisitsToCapture;
2233 static boolean debugCallSiteStopAfter;
2237 resolveMethodCall(FlatCall fc,
2238 FlatMethod fmCallee,
2239 ReachGraph rgCallee,
2240 Set<Integer> callerNodeIDsCopiedToCallee,
2241 boolean writeDebugDOTs
2244 if( writeDebugDOTs ) {
2246 System.out.println(" Writing out visit "+
2247 debugCallSiteVisitCounter+
2248 " to debug call site");
2250 debugGraphPrefix = String.format("call%03d",
2251 debugCallSiteVisitCounter);
2253 rgCallee.writeGraph(debugGraphPrefix+"callee",
2254 resolveMethodDebugDOTwriteLabels,
2255 resolveMethodDebugDOTselectTemps,
2256 resolveMethodDebugDOTpruneGarbage,
2257 resolveMethodDebugDOThideReach,
2258 resolveMethodDebugDOThideSubsetReach,
2259 resolveMethodDebugDOThidePreds,
2260 resolveMethodDebugDOThideEdgeTaints);
2262 writeGraph(debugGraphPrefix+"caller00In",
2263 resolveMethodDebugDOTwriteLabels,
2264 resolveMethodDebugDOTselectTemps,
2265 resolveMethodDebugDOTpruneGarbage,
2266 resolveMethodDebugDOThideReach,
2267 resolveMethodDebugDOThideSubsetReach,
2268 resolveMethodDebugDOThidePreds,
2269 resolveMethodDebugDOThideEdgeTaints,
2270 callerNodeIDsCopiedToCallee);
2275 // method call transfer function steps:
2276 // 1. Use current callee-reachable heap (CRH) to test callee
2277 // predicates and mark what will be coming in.
2278 // 2. Wipe CRH out of caller.
2279 // 3. Transplant marked callee parts in:
2280 // a) bring in nodes
2281 // b) bring in callee -> callee edges
2282 // c) resolve out-of-context -> callee edges
2283 // d) assign return value
2284 // 4. Collapse shadow nodes down
2285 // 5. Global sweep it.
2288 // 1. mark what callee elements have satisfied predicates
2289 Hashtable<HeapRegionNode, ExistPredSet> calleeNodesSatisfied =
2290 new Hashtable<HeapRegionNode, ExistPredSet>();
2292 Hashtable<RefEdge, ExistPredSet> calleeEdgesSatisfied =
2293 new Hashtable<RefEdge, ExistPredSet>();
2295 Hashtable< HeapRegionNode, Hashtable<ReachState, ExistPredSet> >
2296 calleeNode2calleeStatesSatisfied =
2297 new Hashtable< HeapRegionNode, Hashtable<ReachState, ExistPredSet> >();
2299 Hashtable< RefEdge, Hashtable<ReachState, ExistPredSet> >
2300 calleeEdge2calleeStatesSatisfied =
2301 new Hashtable< RefEdge, Hashtable<ReachState, ExistPredSet> >();
2303 Hashtable< RefEdge, Hashtable<Taint, ExistPredSet> >
2304 calleeEdge2calleeTaintsSatisfied =
2305 new Hashtable< RefEdge, Hashtable<Taint, ExistPredSet> >();
2307 Hashtable< RefEdge, Set<RefSrcNode> > calleeEdges2oocCallerSrcMatches =
2308 new Hashtable< RefEdge, Set<RefSrcNode> >();
2311 Iterator meItr = rgCallee.id2hrn.entrySet().iterator();
2312 while( meItr.hasNext() ) {
2313 Map.Entry me = (Map.Entry)meItr.next();
2314 Integer id = (Integer) me.getKey();
2315 HeapRegionNode hrnCallee = (HeapRegionNode) me.getValue();
2317 // if a callee element's predicates are satisfied then a set
2318 // of CALLER predicates is returned: they are the predicates
2319 // that the callee element moved into the caller context
2320 // should have, and it is inefficient to find this again later
2321 ExistPredSet predsIfSatis =
2322 hrnCallee.getPreds().isSatisfiedBy(this,
2323 callerNodeIDsCopiedToCallee
2326 if( predsIfSatis != null ) {
2327 calleeNodesSatisfied.put(hrnCallee, predsIfSatis);
2329 // otherwise don't bother looking at edges to this node
2333 // since the node is coming over, find out which reach
2334 // states on it should come over, too
2335 assert calleeNode2calleeStatesSatisfied.get(hrnCallee) == null;
2337 Iterator<ReachState> stateItr = hrnCallee.getAlpha().iterator();
2338 while( stateItr.hasNext() ) {
2339 ReachState stateCallee = stateItr.next();
2342 stateCallee.getPreds().isSatisfiedBy(this,
2343 callerNodeIDsCopiedToCallee
2345 if( predsIfSatis != null ) {
2347 Hashtable<ReachState, ExistPredSet> calleeStatesSatisfied =
2348 calleeNode2calleeStatesSatisfied.get(hrnCallee);
2350 if( calleeStatesSatisfied == null ) {
2351 calleeStatesSatisfied =
2352 new Hashtable<ReachState, ExistPredSet>();
2354 calleeNode2calleeStatesSatisfied.put(hrnCallee, calleeStatesSatisfied);
2357 calleeStatesSatisfied.put(stateCallee, predsIfSatis);
2361 // then look at edges to the node
2362 Iterator<RefEdge> reItr = hrnCallee.iteratorToReferencers();
2363 while( reItr.hasNext() ) {
2364 RefEdge reCallee = reItr.next();
2365 RefSrcNode rsnCallee = reCallee.getSrc();
2367 // (caller local variables to in-context heap regions)
2368 // have an (out-of-context heap region -> in-context heap region)
2369 // abstraction in the callEE, so its true we never need to
2370 // look at a (var node -> heap region) edge in callee to bring
2371 // those over for the call site transfer, except for the special
2372 // case of *RETURN var* -> heap region edges.
2373 // What about (param var->heap region)
2374 // edges in callee? They are dealt with below this loop.
2376 if( rsnCallee instanceof VariableNode ) {
2378 // looking for the return-value variable only
2379 VariableNode vnCallee = (VariableNode) rsnCallee;
2380 if( vnCallee.getTempDescriptor() != tdReturn ) {
2384 TempDescriptor returnTemp = fc.getReturnTemp();
2385 if( returnTemp == null ||
2386 !DisjointAnalysis.shouldAnalysisTrack(returnTemp.getType() )
2391 // note that the assignment of the return value is to a
2392 // variable in the caller which is out-of-context with
2393 // respect to the callee
2394 VariableNode vnLhsCaller = getVariableNodeFromTemp(returnTemp);
2395 Set<RefSrcNode> rsnCallers = new HashSet<RefSrcNode>();
2396 rsnCallers.add(vnLhsCaller);
2397 calleeEdges2oocCallerSrcMatches.put(reCallee, rsnCallers);
2401 // for HeapRegionNode callee sources...
2403 // first see if the source is out-of-context, and only
2404 // proceed with this edge if we find some caller-context
2406 HeapRegionNode hrnSrcCallee = (HeapRegionNode) rsnCallee;
2407 boolean matchedOutOfContext = false;
2409 if( !hrnSrcCallee.isOutOfContext() ) {
2412 hrnSrcCallee.getPreds().isSatisfiedBy(this,
2413 callerNodeIDsCopiedToCallee
2415 if( predsIfSatis != null ) {
2416 calleeNodesSatisfied.put(hrnSrcCallee, predsIfSatis);
2418 // otherwise forget this edge
2423 // hrnSrcCallee is out-of-context
2425 assert !calleeEdges2oocCallerSrcMatches.containsKey(reCallee);
2427 Set<RefSrcNode> rsnCallers = new HashSet<RefSrcNode>();
2429 // is the target node in the caller?
2430 HeapRegionNode hrnDstCaller = this.id2hrn.get(hrnCallee.getID() );
2431 if( hrnDstCaller == null ) {
2435 Iterator<RefEdge> reDstItr = hrnDstCaller.iteratorToReferencers();
2436 while( reDstItr.hasNext() ) {
2437 // the edge and field (either possibly null) must match
2438 RefEdge reCaller = reDstItr.next();
2440 if( !reCaller.typeEquals(reCallee.getType() ) ||
2441 !reCaller.fieldEquals(reCallee.getField() )
2446 RefSrcNode rsnCaller = reCaller.getSrc();
2447 if( rsnCaller instanceof VariableNode ) {
2449 // a variable node matches an OOC region with null type
2450 if( hrnSrcCallee.getType() != null ) {
2455 // otherwise types should match
2456 HeapRegionNode hrnCallerSrc = (HeapRegionNode) rsnCaller;
2457 if( hrnSrcCallee.getType() == null ) {
2458 if( hrnCallerSrc.getType() != null ) {
2462 if( !hrnSrcCallee.getType().equals(hrnCallerSrc.getType() ) ) {
2468 rsnCallers.add(rsnCaller);
2469 matchedOutOfContext = true;
2472 if( !rsnCallers.isEmpty() ) {
2473 calleeEdges2oocCallerSrcMatches.put(reCallee, rsnCallers);
2477 if( hrnSrcCallee.isOutOfContext() &&
2478 !matchedOutOfContext ) {
2485 reCallee.getPreds().isSatisfiedBy(this,
2486 callerNodeIDsCopiedToCallee
2489 if( predsIfSatis != null ) {
2490 calleeEdgesSatisfied.put(reCallee, predsIfSatis);
2492 // since the edge is coming over, find out which reach
2493 // states on it should come over, too
2494 assert calleeEdge2calleeStatesSatisfied.get(reCallee) == null;
2496 stateItr = reCallee.getBeta().iterator();
2497 while( stateItr.hasNext() ) {
2498 ReachState stateCallee = stateItr.next();
2501 stateCallee.getPreds().isSatisfiedBy(this,
2502 callerNodeIDsCopiedToCallee
2504 if( predsIfSatis != null ) {
2506 Hashtable<ReachState, ExistPredSet> calleeStatesSatisfied =
2507 calleeEdge2calleeStatesSatisfied.get(reCallee);
2509 if( calleeStatesSatisfied == null ) {
2510 calleeStatesSatisfied =
2511 new Hashtable<ReachState, ExistPredSet>();
2513 calleeEdge2calleeStatesSatisfied.put(reCallee, calleeStatesSatisfied);
2516 calleeStatesSatisfied.put(stateCallee, predsIfSatis);
2520 // since the edge is coming over, find out which taints
2521 // on it should come over, too
2522 assert calleeEdge2calleeTaintsSatisfied.get(reCallee) == null;
2524 Iterator<Taint> tItr = reCallee.getTaints().iterator();
2525 while( tItr.hasNext() ) {
2526 Taint tCallee = tItr.next();
2529 tCallee.getPreds().isSatisfiedBy(this,
2530 callerNodeIDsCopiedToCallee
2532 if( predsIfSatis != null ) {
2534 Hashtable<Taint, ExistPredSet> calleeTaintsSatisfied =
2535 calleeEdge2calleeTaintsSatisfied.get(reCallee);
2537 if( calleeTaintsSatisfied == null ) {
2538 calleeTaintsSatisfied =
2539 new Hashtable<Taint, ExistPredSet>();
2541 calleeEdge2calleeTaintsSatisfied.put(reCallee, calleeTaintsSatisfied);
2544 calleeTaintsSatisfied.put(tCallee, predsIfSatis);
2551 if( writeDebugDOTs ) {
2552 writeGraph(debugGraphPrefix+"caller20BeforeWipe",
2553 resolveMethodDebugDOTwriteLabels,
2554 resolveMethodDebugDOTselectTemps,
2555 resolveMethodDebugDOTpruneGarbage,
2556 resolveMethodDebugDOThideReach,
2557 resolveMethodDebugDOThideSubsetReach,
2558 resolveMethodDebugDOThidePreds,
2559 resolveMethodDebugDOThideEdgeTaints);
2563 // 2. predicates tested, ok to wipe out caller part
2564 Iterator<Integer> hrnItr = callerNodeIDsCopiedToCallee.iterator();
2565 while( hrnItr.hasNext() ) {
2566 Integer hrnID = hrnItr.next();
2567 HeapRegionNode hrnCaller = id2hrn.get(hrnID);
2568 assert hrnCaller != null;
2570 // when clearing off nodes, also eliminate variable
2572 wipeOut(hrnCaller, true);
2575 // if we are assigning the return value to something, clobber now
2576 // as part of the wipe
2577 TempDescriptor returnTemp = fc.getReturnTemp();
2578 if( returnTemp != null &&
2579 DisjointAnalysis.shouldAnalysisTrack(returnTemp.getType() )
2582 VariableNode vnLhsCaller = getVariableNodeFromTemp(returnTemp);
2583 clearRefEdgesFrom(vnLhsCaller, null, null, true);
2589 if( writeDebugDOTs ) {
2590 writeGraph(debugGraphPrefix+"caller30BeforeAddingNodes",
2591 resolveMethodDebugDOTwriteLabels,
2592 resolveMethodDebugDOTselectTemps,
2593 resolveMethodDebugDOTpruneGarbage,
2594 resolveMethodDebugDOThideReach,
2595 resolveMethodDebugDOThideSubsetReach,
2596 resolveMethodDebugDOThidePreds,
2597 resolveMethodDebugDOThideEdgeTaints);
2603 // 3. callee elements with satisfied preds come in, note that
2604 // the mapping of elements satisfied to preds is like this:
2605 // A callee element EE has preds EEp that are satisfied by
2606 // some caller element ER. We bring EE into the caller
2607 // context as ERee with the preds of ER, namely ERp, which
2608 // in the following algorithm is the value in the mapping
2611 Iterator satisItr = calleeNodesSatisfied.entrySet().iterator();
2612 while( satisItr.hasNext() ) {
2613 Map.Entry me = (Map.Entry)satisItr.next();
2614 HeapRegionNode hrnCallee = (HeapRegionNode) me.getKey();
2615 ExistPredSet preds = (ExistPredSet) me.getValue();
2617 // TODO: I think its true that the current implementation uses
2618 // the type of the OOC region and the predicates OF THE EDGE from
2619 // it to link everything up in caller context, so that's why we're
2620 // skipping this... maybe that's a sillier way to do it?
2621 if( hrnCallee.isOutOfContext() ) {
2625 AllocSite as = hrnCallee.getAllocSite();
2628 Integer hrnIDshadow = as.getShadowIDfromID(hrnCallee.getID() );
2630 HeapRegionNode hrnCaller = id2hrn.get(hrnIDshadow);
2631 if( hrnCaller == null ) {
2633 createNewHeapRegionNode(hrnIDshadow, // id or null to generate a new one
2634 hrnCallee.isSingleObject(), // single object?
2635 hrnCallee.isNewSummary(), // summary?
2636 false, // out-of-context?
2637 hrnCallee.getType(), // type
2638 hrnCallee.getAllocSite(), // allocation site
2639 toCallerContext(hrnCallee.getInherent(),
2640 calleeNode2calleeStatesSatisfied.get(hrnCallee) ), // inherent reach
2641 null, // current reach
2642 predsEmpty, // predicates
2643 hrnCallee.getDescription() // description
2646 assert hrnCaller.isWiped();
2649 hrnCaller.setAlpha(toCallerContext(hrnCallee.getAlpha(),
2650 calleeNode2calleeStatesSatisfied.get(hrnCallee)
2654 hrnCaller.setPreds(preds);
2661 if( writeDebugDOTs ) {
2662 writeGraph(debugGraphPrefix+"caller31BeforeAddingEdges",
2663 resolveMethodDebugDOTwriteLabels,
2664 resolveMethodDebugDOTselectTemps,
2665 resolveMethodDebugDOTpruneGarbage,
2666 resolveMethodDebugDOThideReach,
2667 resolveMethodDebugDOThideSubsetReach,
2668 resolveMethodDebugDOThidePreds,
2669 resolveMethodDebugDOThideEdgeTaints);
2673 // set these up during the next procedure so after
2674 // the caller has all of its nodes and edges put
2675 // back together we can propagate the callee's
2676 // reach changes backwards into the caller graph
2677 HashSet<RefEdge> edgesForPropagation = new HashSet<RefEdge>();
2679 Hashtable<RefEdge, ChangeSet> edgePlannedChanges =
2680 new Hashtable<RefEdge, ChangeSet>();
2683 // 3.b) callee -> callee edges AND out-of-context -> callee
2684 // which includes return temp -> callee edges now, too
2685 satisItr = calleeEdgesSatisfied.entrySet().iterator();
2686 while( satisItr.hasNext() ) {
2687 Map.Entry me = (Map.Entry)satisItr.next();
2688 RefEdge reCallee = (RefEdge) me.getKey();
2689 ExistPredSet preds = (ExistPredSet) me.getValue();
2691 HeapRegionNode hrnDstCallee = reCallee.getDst();
2692 AllocSite asDst = hrnDstCallee.getAllocSite();
2693 allocSites.add(asDst);
2695 Integer hrnIDDstShadow =
2696 asDst.getShadowIDfromID(hrnDstCallee.getID() );
2698 HeapRegionNode hrnDstCaller = id2hrn.get(hrnIDDstShadow);
2699 assert hrnDstCaller != null;
2702 RefSrcNode rsnCallee = reCallee.getSrc();
2704 Set<RefSrcNode> rsnCallers =
2705 new HashSet<RefSrcNode>();
2707 Set<RefSrcNode> oocCallers =
2708 calleeEdges2oocCallerSrcMatches.get(reCallee);
2710 if( rsnCallee instanceof HeapRegionNode ) {
2711 HeapRegionNode hrnCalleeSrc = (HeapRegionNode) rsnCallee;
2712 if( hrnCalleeSrc.isOutOfContext() ) {
2713 assert oocCallers != null;
2718 if( oocCallers == null ) {
2719 // there are no out-of-context matches, so it's
2720 // either a param/arg var or one in-context heap region
2721 if( rsnCallee instanceof VariableNode ) {
2722 // variable -> node in the callee should only
2723 // come into the caller if its from a param var
2724 VariableNode vnCallee = (VariableNode) rsnCallee;
2725 TempDescriptor tdParam = vnCallee.getTempDescriptor();
2726 TempDescriptor tdArg = fc.getArgMatchingParam(fmCallee,
2728 if( tdArg == null ) {
2729 // this means the variable isn't a parameter, its local
2730 // to the callee so we ignore it in call site transfer
2731 // shouldn't this NEVER HAPPEN?
2735 rsnCallers.add(this.getVariableNodeFromTemp(tdArg) );
2738 // otherwise source is in context, one region
2740 HeapRegionNode hrnSrcCallee = (HeapRegionNode) rsnCallee;
2742 // translate an in-context node to shadow
2743 AllocSite asSrc = hrnSrcCallee.getAllocSite();
2744 allocSites.add(asSrc);
2746 Integer hrnIDSrcShadow =
2747 asSrc.getShadowIDfromID(hrnSrcCallee.getID() );
2749 HeapRegionNode hrnSrcCallerShadow =
2750 this.id2hrn.get(hrnIDSrcShadow);
2752 assert hrnSrcCallerShadow != null;
2754 rsnCallers.add(hrnSrcCallerShadow);
2758 // otherwise we have a set of out-of-context srcs
2759 // that should NOT be translated to shadow nodes
2760 assert !oocCallers.isEmpty();
2761 rsnCallers.addAll(oocCallers);
2764 // now make all caller edges we've identified from
2765 // this callee edge with a satisfied predicate
2766 assert !rsnCallers.isEmpty();
2767 Iterator<RefSrcNode> rsnItr = rsnCallers.iterator();
2768 while( rsnItr.hasNext() ) {
2769 RefSrcNode rsnCaller = rsnItr.next();
2771 RefEdge reCaller = new RefEdge(rsnCaller,
2774 reCallee.getField(),
2775 toCallerContext(reCallee.getBeta(),
2776 calleeEdge2calleeStatesSatisfied.get(reCallee) ),
2778 toCallerContext(reCallee.getTaints(),
2779 calleeEdge2calleeTaintsSatisfied.get(reCallee) )
2782 ChangeSet cs = ChangeSet.factory();
2783 Iterator<ReachState> rsItr = reCaller.getBeta().iterator();
2784 while( rsItr.hasNext() ) {
2785 ReachState state = rsItr.next();
2786 ExistPredSet predsPreCallee = state.getPreds();
2788 if( state.isEmpty() ) {
2792 Iterator<ExistPred> predItr = predsPreCallee.iterator();
2793 while( predItr.hasNext() ) {
2794 ExistPred pred = predItr.next();
2795 ReachState old = pred.ne_state;
2801 cs = Canonical.add(cs,
2802 ChangeTuple.factory(old,
2809 // we're just going to use the convenient "merge-if-exists"
2810 // edge call below, but still take a separate look if there
2811 // is an existing caller edge to build change sets properly
2812 if( !cs.isEmpty() ) {
2813 RefEdge edgeExisting = rsnCaller.getReferenceTo(hrnDstCaller,
2817 if( edgeExisting != null ) {
2818 ChangeSet csExisting = edgePlannedChanges.get(edgeExisting);
2819 if( csExisting == null ) {
2820 csExisting = ChangeSet.factory();
2822 edgePlannedChanges.put(edgeExisting,
2823 Canonical.union(csExisting,
2828 edgesForPropagation.add(reCaller);
2829 assert !edgePlannedChanges.containsKey(reCaller);
2830 edgePlannedChanges.put(reCaller, cs);
2834 // then add new caller edge or merge
2835 addEdgeOrMergeWithExisting(reCaller);
2843 if( writeDebugDOTs ) {
2844 writeGraph(debugGraphPrefix+"caller38propagateReach",
2845 resolveMethodDebugDOTwriteLabels,
2846 resolveMethodDebugDOTselectTemps,
2847 resolveMethodDebugDOTpruneGarbage,
2848 resolveMethodDebugDOThideReach,
2849 resolveMethodDebugDOThideSubsetReach,
2850 resolveMethodDebugDOThidePreds,
2851 resolveMethodDebugDOThideEdgeTaints);
2854 // propagate callee reachability changes to the rest
2855 // of the caller graph edges
2856 HashSet<RefEdge> edgesUpdated = new HashSet<RefEdge>();
2858 propagateTokensOverEdges(edgesForPropagation, // source edges
2859 edgePlannedChanges, // map src edge to change set
2860 edgesUpdated); // list of updated edges
2862 // commit beta' (beta<-betaNew)
2863 Iterator<RefEdge> edgeItr = edgesUpdated.iterator();
2864 while( edgeItr.hasNext() ) {
2865 edgeItr.next().applyBetaNew();
2874 if( writeDebugDOTs ) {
2875 writeGraph(debugGraphPrefix+"caller40BeforeShadowMerge",
2876 resolveMethodDebugDOTwriteLabels,
2877 resolveMethodDebugDOTselectTemps,
2878 resolveMethodDebugDOTpruneGarbage,
2879 resolveMethodDebugDOThideReach,
2880 resolveMethodDebugDOThideSubsetReach,
2881 resolveMethodDebugDOThidePreds,
2882 resolveMethodDebugDOThideEdgeTaints);
2886 // 4) merge shadow nodes so alloc sites are back to k
2887 Iterator<AllocSite> asItr = rgCallee.allocSites.iterator();
2888 while( asItr.hasNext() ) {
2889 // for each allocation site do the following to merge
2890 // shadow nodes (newest from callee) with any existing
2891 // look for the newest normal and newest shadow "slot"
2892 // not being used, transfer normal to shadow. Keep
2893 // doing this until there are no more normal nodes, or
2894 // no empty shadow slots: then merge all remaining normal
2895 // nodes into the shadow summary. Finally, convert all
2896 // shadow to their normal versions.
2897 AllocSite as = asItr.next();
2901 while( ageNorm < allocationDepth &&
2902 ageShad < allocationDepth ) {
2904 // first, are there any normal nodes left?
2905 Integer idNorm = as.getIthOldest(ageNorm);
2906 HeapRegionNode hrnNorm = id2hrn.get(idNorm);
2907 if( hrnNorm == null ) {
2908 // no, this age of normal node not in the caller graph
2913 // yes, a normal node exists, is there an empty shadow
2914 // "slot" to transfer it onto?
2915 HeapRegionNode hrnShad = getIthNode(as, ageShad, true);
2916 if( !hrnShad.isWiped() ) {
2917 // no, this age of shadow node is not empty
2922 // yes, this shadow node is empty
2923 transferOnto(hrnNorm, hrnShad);
2928 // now, while there are still normal nodes but no shadow
2929 // slots, merge normal nodes into the shadow summary
2930 while( ageNorm < allocationDepth ) {
2932 // first, are there any normal nodes left?
2933 Integer idNorm = as.getIthOldest(ageNorm);
2934 HeapRegionNode hrnNorm = id2hrn.get(idNorm);
2935 if( hrnNorm == null ) {
2936 // no, this age of normal node not in the caller graph
2941 // yes, a normal node exists, so get the shadow summary
2942 HeapRegionNode summShad = getSummaryNode(as, true);
2943 mergeIntoSummary(hrnNorm, summShad);
2945 // now tokens in reachability sets need to age also
2946 Iterator itrAllHRNodes = id2hrn.entrySet().iterator();
2947 while( itrAllHRNodes.hasNext() ) {
2948 Map.Entry me = (Map.Entry)itrAllHRNodes.next();
2949 HeapRegionNode hrnToAge = (HeapRegionNode) me.getValue();
2951 ageTuplesFrom(as, hrnToAge);
2953 Iterator<RefEdge> itrEdges = hrnToAge.iteratorToReferencers();
2954 while( itrEdges.hasNext() ) {
2955 ageTuplesFrom(as, itrEdges.next() );
2962 // if there is a normal summary, merge it into shadow summary
2963 Integer idNorm = as.getSummary();
2964 HeapRegionNode summNorm = id2hrn.get(idNorm);
2965 if( summNorm != null ) {
2966 HeapRegionNode summShad = getSummaryNode(as, true);
2967 mergeIntoSummary(summNorm, summShad);
2970 // finally, flip all existing shadow nodes onto the normal
2971 for( int i = 0; i < allocationDepth; ++i ) {
2972 Integer idShad = as.getIthOldestShadow(i);
2973 HeapRegionNode hrnShad = id2hrn.get(idShad);
2974 if( hrnShad != null ) {
2976 HeapRegionNode hrnNorm = getIthNode(as, i, false);
2977 assert hrnNorm.isWiped();
2978 transferOnto(hrnShad, hrnNorm);
2982 Integer idShad = as.getSummaryShadow();
2983 HeapRegionNode summShad = id2hrn.get(idShad);
2984 if( summShad != null ) {
2985 summNorm = getSummaryNode(as, false);
2986 transferOnto(summShad, summNorm);
2995 if( writeDebugDOTs ) {
2996 writeGraph(debugGraphPrefix+"caller45BeforeUnshadow",
2997 resolveMethodDebugDOTwriteLabels,
2998 resolveMethodDebugDOTselectTemps,
2999 resolveMethodDebugDOTpruneGarbage,
3000 resolveMethodDebugDOThideReach,
3001 resolveMethodDebugDOThideSubsetReach,
3002 resolveMethodDebugDOThidePreds,
3003 resolveMethodDebugDOThideEdgeTaints);
3007 Iterator itrAllHRNodes = id2hrn.entrySet().iterator();
3008 while( itrAllHRNodes.hasNext() ) {
3009 Map.Entry me = (Map.Entry)itrAllHRNodes.next();
3010 HeapRegionNode hrn = (HeapRegionNode) me.getValue();
3012 hrn.setAlpha(unshadow(hrn.getAlpha() ) );
3014 Iterator<RefEdge> itrEdges = hrn.iteratorToReferencers();
3015 while( itrEdges.hasNext() ) {
3016 RefEdge re = itrEdges.next();
3017 re.setBeta(unshadow(re.getBeta() ) );
3024 if( writeDebugDOTs ) {
3025 writeGraph(debugGraphPrefix+"caller50BeforeGlobalSweep",
3026 resolveMethodDebugDOTwriteLabels,
3027 resolveMethodDebugDOTselectTemps,
3028 resolveMethodDebugDOTpruneGarbage,
3029 resolveMethodDebugDOThideReach,
3030 resolveMethodDebugDOThideSubsetReach,
3031 resolveMethodDebugDOThidePreds,
3032 resolveMethodDebugDOThideEdgeTaints);
3037 if( !DISABLE_GLOBAL_SWEEP ) {
3042 if( writeDebugDOTs ) {
3043 writeGraph(debugGraphPrefix+"caller90AfterTransfer",
3044 resolveMethodDebugDOTwriteLabels,
3045 resolveMethodDebugDOTselectTemps,
3046 resolveMethodDebugDOTpruneGarbage,
3047 resolveMethodDebugDOThideReach,
3048 resolveMethodDebugDOThideSubsetReach,
3049 resolveMethodDebugDOThidePreds,
3050 resolveMethodDebugDOThideEdgeTaints);
3056 ////////////////////////////////////////////////////
3058 // Abstract garbage collection simply removes
3059 // heap region nodes that are not mechanically
3060 // reachable from a root set. This step is
3061 // essential for testing node and edge existence
3062 // predicates efficiently
3064 ////////////////////////////////////////////////////
3065 public void abstractGarbageCollect(Set<TempDescriptor> liveSet) {
3067 // calculate a root set, will be different for Java
3068 // version of analysis versus Bamboo version
3069 Set<RefSrcNode> toVisit = new HashSet<RefSrcNode>();
3071 // visit every variable in graph while building root
3072 // set, and do iterating on a copy, so we can remove
3073 // dead variables while we're at this
3074 Iterator makeCopyItr = td2vn.entrySet().iterator();
3075 Set entrysCopy = new HashSet();
3076 while( makeCopyItr.hasNext() ) {
3077 entrysCopy.add(makeCopyItr.next() );
3080 Iterator eItr = entrysCopy.iterator();
3081 while( eItr.hasNext() ) {
3082 Map.Entry me = (Map.Entry)eItr.next();
3083 TempDescriptor td = (TempDescriptor) me.getKey();
3084 VariableNode vn = (VariableNode) me.getValue();
3086 if( liveSet.contains(td) ) {
3090 // dead var, remove completely from graph
3092 clearRefEdgesFrom(vn, null, null, true);
3096 // everything visited in a traversal is
3097 // considered abstractly live
3098 Set<RefSrcNode> visited = new HashSet<RefSrcNode>();
3100 while( !toVisit.isEmpty() ) {
3101 RefSrcNode rsn = toVisit.iterator().next();
3102 toVisit.remove(rsn);
3105 Iterator<RefEdge> hrnItr = rsn.iteratorToReferencees();
3106 while( hrnItr.hasNext() ) {
3107 RefEdge edge = hrnItr.next();
3108 HeapRegionNode hrn = edge.getDst();
3110 if( !visited.contains(hrn) ) {
3116 // get a copy of the set to iterate over because
3117 // we're going to monkey with the graph when we
3118 // identify a garbage node
3119 Set<HeapRegionNode> hrnAllPrior = new HashSet<HeapRegionNode>();
3120 Iterator<HeapRegionNode> hrnItr = id2hrn.values().iterator();
3121 while( hrnItr.hasNext() ) {
3122 hrnAllPrior.add(hrnItr.next() );
3125 Iterator<HeapRegionNode> hrnAllItr = hrnAllPrior.iterator();
3126 while( hrnAllItr.hasNext() ) {
3127 HeapRegionNode hrn = hrnAllItr.next();
3129 if( !visited.contains(hrn) ) {
3131 // heap region nodes are compared across ReachGraph
3132 // objects by their integer ID, so when discarding
3133 // garbage nodes we must also discard entries in
3134 // the ID -> heap region hashtable.
3135 id2hrn.remove(hrn.getID() );
3137 // RefEdge objects are two-way linked between
3138 // nodes, so when a node is identified as garbage,
3139 // actively clear references to and from it so
3140 // live nodes won't have dangling RefEdge's
3143 // if we just removed the last node from an allocation
3144 // site, it should be taken out of the ReachGraph's list
3145 AllocSite as = hrn.getAllocSite();
3146 if( !hasNodesOf(as) ) {
3147 allocSites.remove(as);
3153 protected boolean hasNodesOf(AllocSite as) {
3154 if( id2hrn.containsKey(as.getSummary() ) ) {
3158 for( int i = 0; i < allocationDepth; ++i ) {
3159 if( id2hrn.containsKey(as.getIthOldest(i) ) ) {
3167 ////////////////////////////////////////////////////
3169 // This global sweep is an optional step to prune
3170 // reachability sets that are not internally
3171 // consistent with the global graph. It should be
3172 // invoked after strong updates or method calls.
3174 ////////////////////////////////////////////////////
3175 public void globalSweep() {
3177 // boldB is part of the phase 1 sweep
3178 // it has an in-context table and an out-of-context table
3179 Hashtable< Integer, Hashtable<RefEdge, ReachSet> > boldBic =
3180 new Hashtable< Integer, Hashtable<RefEdge, ReachSet> >();
3182 Hashtable< Integer, Hashtable<RefEdge, ReachSet> > boldBooc =
3183 new Hashtable< Integer, Hashtable<RefEdge, ReachSet> >();
3185 // visit every heap region to initialize alphaNew and betaNew,
3186 // and make a map of every hrnID to the source nodes it should
3187 // propagate forward from. In-context flagged hrnID's propagate
3188 // from only the in-context node they name, but out-of-context
3189 // ID's may propagate from several out-of-context nodes
3190 Hashtable< Integer, Set<HeapRegionNode> > icID2srcs =
3191 new Hashtable< Integer, Set<HeapRegionNode> >();
3193 Hashtable< Integer, Set<HeapRegionNode> > oocID2srcs =
3194 new Hashtable< Integer, Set<HeapRegionNode> >();
3197 Iterator itrHrns = id2hrn.entrySet().iterator();
3198 while( itrHrns.hasNext() ) {
3199 Map.Entry me = (Map.Entry)itrHrns.next();
3200 Integer hrnID = (Integer) me.getKey();
3201 HeapRegionNode hrn = (HeapRegionNode) me.getValue();
3203 // assert that this node and incoming edges have clean alphaNew
3204 // and betaNew sets, respectively
3205 assert rsetEmpty.equals(hrn.getAlphaNew() );
3207 Iterator<RefEdge> itrRers = hrn.iteratorToReferencers();
3208 while( itrRers.hasNext() ) {
3209 RefEdge edge = itrRers.next();
3210 assert rsetEmpty.equals(edge.getBetaNew() );
3213 // make a mapping of IDs to heap regions they propagate from
3214 if( hrn.isFlagged() ) {
3215 assert !hrn.isOutOfContext();
3216 assert !icID2srcs.containsKey(hrn.getID() );
3218 // in-context flagged node IDs simply propagate from the
3220 Set<HeapRegionNode> srcs = new HashSet<HeapRegionNode>();
3222 icID2srcs.put(hrn.getID(), srcs);
3225 if( hrn.isOutOfContext() ) {
3226 assert !hrn.isFlagged();
3228 // the reachability states on an out-of-context
3229 // node are not really important (combinations of
3230 // IDs or arity)--what matters is that the states
3231 // specify which nodes this out-of-context node
3232 // stands in for. For example, if the state [17?, 19*]
3233 // appears on the ooc node, it may serve as a source
3234 // for node 17? and a source for node 19.
3235 Iterator<ReachState> stateItr = hrn.getAlpha().iterator();
3236 while( stateItr.hasNext() ) {
3237 ReachState state = stateItr.next();
3239 Iterator<ReachTuple> rtItr = state.iterator();
3240 while( rtItr.hasNext() ) {
3241 ReachTuple rt = rtItr.next();
3242 assert rt.isOutOfContext();
3244 Set<HeapRegionNode> srcs = oocID2srcs.get(rt.getHrnID() );
3245 if( srcs == null ) {
3246 srcs = new HashSet<HeapRegionNode>();
3249 oocID2srcs.put(rt.getHrnID(), srcs);
3255 // calculate boldB for all hrnIDs identified by the above
3256 // node traversal, propagating from every source
3257 while( !icID2srcs.isEmpty() || !oocID2srcs.isEmpty() ) {
3260 Set<HeapRegionNode> srcs;
3263 if( !icID2srcs.isEmpty() ) {
3264 Map.Entry me = (Map.Entry)icID2srcs.entrySet().iterator().next();
3265 hrnID = (Integer) me.getKey();
3266 srcs = (Set<HeapRegionNode>)me.getValue();
3268 icID2srcs.remove(hrnID);
3271 assert !oocID2srcs.isEmpty();
3273 Map.Entry me = (Map.Entry)oocID2srcs.entrySet().iterator().next();
3274 hrnID = (Integer) me.getKey();
3275 srcs = (Set<HeapRegionNode>)me.getValue();
3277 oocID2srcs.remove(hrnID);
3281 Hashtable<RefEdge, ReachSet> boldB_f =
3282 new Hashtable<RefEdge, ReachSet>();
3284 Set<RefEdge> workSetEdges = new HashSet<RefEdge>();
3286 Iterator<HeapRegionNode> hrnItr = srcs.iterator();
3287 while( hrnItr.hasNext() ) {
3288 HeapRegionNode hrn = hrnItr.next();
3290 assert workSetEdges.isEmpty();
3292 // initial boldB_f constraints
3293 Iterator<RefEdge> itrRees = hrn.iteratorToReferencees();
3294 while( itrRees.hasNext() ) {
3295 RefEdge edge = itrRees.next();
3297 assert !boldB_f.containsKey(edge);
3298 boldB_f.put(edge, edge.getBeta() );
3300 assert !workSetEdges.contains(edge);
3301 workSetEdges.add(edge);
3304 // enforce the boldB_f constraint at edges until we reach a fixed point
3305 while( !workSetEdges.isEmpty() ) {
3306 RefEdge edge = workSetEdges.iterator().next();
3307 workSetEdges.remove(edge);
3309 Iterator<RefEdge> itrPrime = edge.getDst().iteratorToReferencees();
3310 while( itrPrime.hasNext() ) {
3311 RefEdge edgePrime = itrPrime.next();
3313 ReachSet prevResult = boldB_f.get(edgePrime);
3314 ReachSet intersection = Canonical.intersection(boldB_f.get(edge),
3318 if( prevResult == null ||
3319 Canonical.unionORpreds(prevResult,
3320 intersection).size()
3324 if( prevResult == null ) {
3325 boldB_f.put(edgePrime,
3326 Canonical.unionORpreds(edgePrime.getBeta(),
3331 boldB_f.put(edgePrime,
3332 Canonical.unionORpreds(prevResult,
3337 workSetEdges.add(edgePrime);
3344 boldBic.put(hrnID, boldB_f);
3346 boldBooc.put(hrnID, boldB_f);
3351 // use boldB to prune hrnIDs from alpha states that are impossible
3352 // and propagate the differences backwards across edges
3353 HashSet<RefEdge> edgesForPropagation = new HashSet<RefEdge>();
3355 Hashtable<RefEdge, ChangeSet> edgePlannedChanges =
3356 new Hashtable<RefEdge, ChangeSet>();
3359 itrHrns = id2hrn.entrySet().iterator();
3360 while( itrHrns.hasNext() ) {
3361 Map.Entry me = (Map.Entry)itrHrns.next();
3362 Integer hrnID = (Integer) me.getKey();
3363 HeapRegionNode hrn = (HeapRegionNode) me.getValue();
3365 // out-of-context nodes don't participate in the
3366 // global sweep, they serve as sources for the pass
3368 if( hrn.isOutOfContext() ) {
3372 // the inherent states of a region are the exception
3373 // to removal as the global sweep prunes
3374 ReachTuple rtException = ReachTuple.factory(hrnID,
3375 !hrn.isSingleObject(),
3376 ReachTuple.ARITY_ONE,
3377 false // out-of-context
3380 ChangeSet cts = ChangeSet.factory();
3382 // mark hrnIDs for removal
3383 Iterator<ReachState> stateItr = hrn.getAlpha().iterator();
3384 while( stateItr.hasNext() ) {
3385 ReachState stateOld = stateItr.next();
3387 ReachState markedHrnIDs = ReachState.factory();
3389 Iterator<ReachTuple> rtItr = stateOld.iterator();
3390 while( rtItr.hasNext() ) {
3391 ReachTuple rtOld = rtItr.next();
3393 // never remove the inherent hrnID from a flagged region
3394 // because it is trivially satisfied
3395 if( hrn.isFlagged() ) {
3396 if( rtOld == rtException ) {
3401 // does boldB allow this hrnID?
3402 boolean foundState = false;
3403 Iterator<RefEdge> incidentEdgeItr = hrn.iteratorToReferencers();
3404 while( incidentEdgeItr.hasNext() ) {
3405 RefEdge incidentEdge = incidentEdgeItr.next();
3407 Hashtable<RefEdge, ReachSet> B;
3408 if( rtOld.isOutOfContext() ) {
3409 B = boldBooc.get(rtOld.getHrnID() );
3412 if( !id2hrn.containsKey(rtOld.getHrnID() ) ) {
3413 // let symbols not in the graph get pruned
3417 B = boldBic.get(rtOld.getHrnID() );
3421 ReachSet boldB_rtOld_incident = B.get(incidentEdge);
3422 if( boldB_rtOld_incident != null &&
3423 boldB_rtOld_incident.containsIgnorePreds(stateOld) != null
3431 markedHrnIDs = Canonical.addUpArity(markedHrnIDs, rtOld);
3435 // if there is nothing marked, just move on
3436 if( markedHrnIDs.isEmpty() ) {
3437 hrn.setAlphaNew(Canonical.add(hrn.getAlphaNew(),
3444 // remove all marked hrnIDs and establish a change set that should
3445 // propagate backwards over edges from this node
3446 ReachState statePruned = ReachState.factory();
3447 rtItr = stateOld.iterator();
3448 while( rtItr.hasNext() ) {
3449 ReachTuple rtOld = rtItr.next();
3451 if( !markedHrnIDs.containsTuple(rtOld) ) {
3452 statePruned = Canonical.addUpArity(statePruned, rtOld);
3455 assert !stateOld.equals(statePruned);
3457 hrn.setAlphaNew(Canonical.add(hrn.getAlphaNew(),
3461 ChangeTuple ct = ChangeTuple.factory(stateOld,
3464 cts = Canonical.add(cts, ct);
3467 // throw change tuple set on all incident edges
3468 if( !cts.isEmpty() ) {
3469 Iterator<RefEdge> incidentEdgeItr = hrn.iteratorToReferencers();
3470 while( incidentEdgeItr.hasNext() ) {
3471 RefEdge incidentEdge = incidentEdgeItr.next();
3473 edgesForPropagation.add(incidentEdge);
3475 if( edgePlannedChanges.get(incidentEdge) == null ) {
3476 edgePlannedChanges.put(incidentEdge, cts);
3478 edgePlannedChanges.put(
3480 Canonical.union(edgePlannedChanges.get(incidentEdge),
3489 HashSet<RefEdge> edgesUpdated = new HashSet<RefEdge>();
3491 propagateTokensOverEdges(edgesForPropagation,
3495 // at the end of the 1st phase reference edges have
3496 // beta, betaNew that correspond to beta and betaR
3498 // commit beta<-betaNew, so beta=betaR and betaNew
3499 // will represent the beta' calculation in 2nd phase
3501 // commit alpha<-alphaNew because it won't change
3502 HashSet<RefEdge> res = new HashSet<RefEdge>();
3504 Iterator<HeapRegionNode> nodeItr = id2hrn.values().iterator();
3505 while( nodeItr.hasNext() ) {
3506 HeapRegionNode hrn = nodeItr.next();
3508 // as mentioned above, out-of-context nodes only serve
3509 // as sources of reach states for the sweep, not part
3511 if( hrn.isOutOfContext() ) {
3512 assert hrn.getAlphaNew().equals(rsetEmpty);
3514 hrn.applyAlphaNew();
3517 Iterator<RefEdge> itrRes = hrn.iteratorToReferencers();
3518 while( itrRes.hasNext() ) {
3519 res.add(itrRes.next() );
3525 Iterator<RefEdge> edgeItr = res.iterator();
3526 while( edgeItr.hasNext() ) {
3527 RefEdge edge = edgeItr.next();
3528 HeapRegionNode hrn = edge.getDst();
3530 // commit results of last phase
3531 if( edgesUpdated.contains(edge) ) {
3532 edge.applyBetaNew();
3535 // compute intial condition of 2nd phase
3536 edge.setBetaNew(Canonical.intersection(edge.getBeta(),
3542 // every edge in the graph is the initial workset
3543 Set<RefEdge> edgeWorkSet = (Set) res.clone();
3544 while( !edgeWorkSet.isEmpty() ) {
3545 RefEdge edgePrime = edgeWorkSet.iterator().next();
3546 edgeWorkSet.remove(edgePrime);
3548 RefSrcNode rsn = edgePrime.getSrc();
3549 if( !(rsn instanceof HeapRegionNode) ) {
3552 HeapRegionNode hrn = (HeapRegionNode) rsn;
3554 Iterator<RefEdge> itrEdge = hrn.iteratorToReferencers();
3555 while( itrEdge.hasNext() ) {
3556 RefEdge edge = itrEdge.next();
3558 ReachSet prevResult = edge.getBetaNew();
3559 assert prevResult != null;
3561 ReachSet intersection =
3562 Canonical.intersection(edge.getBeta(),
3563 edgePrime.getBetaNew()
3566 if( Canonical.unionORpreds(prevResult,
3573 Canonical.unionORpreds(prevResult,
3577 edgeWorkSet.add(edge);
3582 // commit beta' (beta<-betaNew)
3583 edgeItr = res.iterator();
3584 while( edgeItr.hasNext() ) {
3585 edgeItr.next().applyBetaNew();
3590 // a useful assertion for debugging:
3591 // every in-context tuple on any edge or
3592 // any node should name a node that is
3593 // part of the graph
3594 public boolean inContextTuplesInGraph() {
3596 Iterator hrnItr = id2hrn.entrySet().iterator();
3597 while( hrnItr.hasNext() ) {
3598 Map.Entry me = (Map.Entry)hrnItr.next();
3599 HeapRegionNode hrn = (HeapRegionNode) me.getValue();
3602 Iterator<ReachState> stateItr = hrn.getAlpha().iterator();
3603 while( stateItr.hasNext() ) {
3604 ReachState state = stateItr.next();
3606 Iterator<ReachTuple> rtItr = state.iterator();
3607 while( rtItr.hasNext() ) {
3608 ReachTuple rt = rtItr.next();
3610 if( !rt.isOutOfContext() ) {
3611 if( !id2hrn.containsKey(rt.getHrnID() ) ) {
3612 System.out.println(rt.getHrnID()+" is missing");
3620 Iterator<RefEdge> edgeItr = hrn.iteratorToReferencers();
3621 while( edgeItr.hasNext() ) {
3622 RefEdge edge = edgeItr.next();
3624 Iterator<ReachState> stateItr = edge.getBeta().iterator();
3625 while( stateItr.hasNext() ) {
3626 ReachState state = stateItr.next();
3628 Iterator<ReachTuple> rtItr = state.iterator();
3629 while( rtItr.hasNext() ) {
3630 ReachTuple rt = rtItr.next();
3632 if( !rt.isOutOfContext() ) {
3633 if( !id2hrn.containsKey(rt.getHrnID() ) ) {
3634 System.out.println(rt.getHrnID()+" is missing");
3647 // another useful assertion for debugging
3648 public boolean noEmptyReachSetsInGraph() {
3650 Iterator hrnItr = id2hrn.entrySet().iterator();
3651 while( hrnItr.hasNext() ) {
3652 Map.Entry me = (Map.Entry)hrnItr.next();
3653 HeapRegionNode hrn = (HeapRegionNode) me.getValue();
3655 if( !hrn.isOutOfContext() &&
3657 hrn.getAlpha().isEmpty()
3659 System.out.println("!!! "+hrn+" has an empty ReachSet !!!");
3663 Iterator<RefEdge> edgeItr = hrn.iteratorToReferencers();
3664 while( edgeItr.hasNext() ) {
3665 RefEdge edge = edgeItr.next();
3667 if( edge.getBeta().isEmpty() ) {
3668 System.out.println("!!! "+edge+" has an empty ReachSet !!!");
3678 public boolean everyReachStateWTrue() {
3680 Iterator hrnItr = id2hrn.entrySet().iterator();
3681 while( hrnItr.hasNext() ) {
3682 Map.Entry me = (Map.Entry)hrnItr.next();
3683 HeapRegionNode hrn = (HeapRegionNode) me.getValue();
3686 Iterator<ReachState> stateItr = hrn.getAlpha().iterator();
3687 while( stateItr.hasNext() ) {
3688 ReachState state = stateItr.next();
3690 if( !state.getPreds().equals(predsTrue) ) {
3696 Iterator<RefEdge> edgeItr = hrn.iteratorToReferencers();
3697 while( edgeItr.hasNext() ) {
3698 RefEdge edge = edgeItr.next();
3700 Iterator<ReachState> stateItr = edge.getBeta().iterator();
3701 while( stateItr.hasNext() ) {
3702 ReachState state = stateItr.next();
3704 if( !state.getPreds().equals(predsTrue) ) {
3717 ////////////////////////////////////////////////////
3718 // in merge() and equals() methods the suffix A
3719 // represents the passed in graph and the suffix
3720 // B refers to the graph in this object
3721 // Merging means to take the incoming graph A and
3722 // merge it into B, so after the operation graph B
3723 // is the final result.
3724 ////////////////////////////////////////////////////
3725 protected void merge(ReachGraph rg) {
3733 mergeAllocSites(rg);
3734 mergeInaccessibleVars(rg);
3737 protected void mergeNodes(ReachGraph rg) {
3739 // start with heap region nodes
3740 Set sA = rg.id2hrn.entrySet();
3741 Iterator iA = sA.iterator();
3742 while( iA.hasNext() ) {
3743 Map.Entry meA = (Map.Entry)iA.next();
3744 Integer idA = (Integer) meA.getKey();
3745 HeapRegionNode hrnA = (HeapRegionNode) meA.getValue();
3747 // if this graph doesn't have a node the
3748 // incoming graph has, allocate it
3749 if( !id2hrn.containsKey(idA) ) {
3750 HeapRegionNode hrnB = hrnA.copy();
3751 id2hrn.put(idA, hrnB);
3754 // otherwise this is a node present in both graphs
3755 // so make the new reachability set a union of the
3756 // nodes' reachability sets
3757 HeapRegionNode hrnB = id2hrn.get(idA);
3758 hrnB.setAlpha(Canonical.unionORpreds(hrnB.getAlpha(),
3763 hrnB.setPreds(Canonical.join(hrnB.getPreds(),
3770 if( !hrnA.equals(hrnB) ) {
3771 rg.writeGraph("graphA");
3772 this.writeGraph("graphB");
3773 throw new Error("flagged not matching");
3781 // now add any variable nodes that are in graph B but
3783 sA = rg.td2vn.entrySet();
3785 while( iA.hasNext() ) {
3786 Map.Entry meA = (Map.Entry)iA.next();
3787 TempDescriptor tdA = (TempDescriptor) meA.getKey();
3788 VariableNode lnA = (VariableNode) meA.getValue();
3790 // if the variable doesn't exist in B, allocate and add it
3791 VariableNode lnB = getVariableNodeFromTemp(tdA);
3795 protected void mergeRefEdges(ReachGraph rg) {
3797 // between heap regions
3798 Set sA = rg.id2hrn.entrySet();
3799 Iterator iA = sA.iterator();
3800 while( iA.hasNext() ) {
3801 Map.Entry meA = (Map.Entry)iA.next();
3802 Integer idA = (Integer) meA.getKey();
3803 HeapRegionNode hrnA = (HeapRegionNode) meA.getValue();
3805 Iterator<RefEdge> heapRegionsItrA = hrnA.iteratorToReferencees();
3806 while( heapRegionsItrA.hasNext() ) {
3807 RefEdge edgeA = heapRegionsItrA.next();
3808 HeapRegionNode hrnChildA = edgeA.getDst();
3809 Integer idChildA = hrnChildA.getID();
3811 // at this point we know an edge in graph A exists
3812 // idA -> idChildA, does this exist in B?
3813 assert id2hrn.containsKey(idA);
3814 HeapRegionNode hrnB = id2hrn.get(idA);
3815 RefEdge edgeToMerge = null;
3817 Iterator<RefEdge> heapRegionsItrB = hrnB.iteratorToReferencees();
3818 while( heapRegionsItrB.hasNext() &&
3819 edgeToMerge == null ) {
3821 RefEdge edgeB = heapRegionsItrB.next();
3822 HeapRegionNode hrnChildB = edgeB.getDst();
3823 Integer idChildB = hrnChildB.getID();
3825 // don't use the RefEdge.equals() here because
3826 // we're talking about existence between graphs,
3827 // not intragraph equal
3828 if( idChildB.equals(idChildA) &&
3829 edgeB.typeAndFieldEquals(edgeA) ) {
3831 edgeToMerge = edgeB;
3835 // if the edge from A was not found in B,
3837 if( edgeToMerge == null ) {
3838 assert id2hrn.containsKey(idChildA);
3839 HeapRegionNode hrnChildB = id2hrn.get(idChildA);
3840 edgeToMerge = edgeA.copy();
3841 edgeToMerge.setSrc(hrnB);
3842 edgeToMerge.setDst(hrnChildB);
3843 addRefEdge(hrnB, hrnChildB, edgeToMerge);
3845 // otherwise, the edge already existed in both graphs
3846 // so merge their reachability sets
3848 // just replace this beta set with the union
3849 assert edgeToMerge != null;
3850 edgeToMerge.setBeta(
3851 Canonical.unionORpreds(edgeToMerge.getBeta(),
3855 edgeToMerge.setPreds(
3856 Canonical.join(edgeToMerge.getPreds(),
3860 edgeToMerge.setTaints(
3861 Canonical.union(edgeToMerge.getTaints(),
3869 // and then again from variable nodes
3870 sA = rg.td2vn.entrySet();
3872 while( iA.hasNext() ) {
3873 Map.Entry meA = (Map.Entry)iA.next();
3874 TempDescriptor tdA = (TempDescriptor) meA.getKey();
3875 VariableNode vnA = (VariableNode) meA.getValue();
3877 Iterator<RefEdge> heapRegionsItrA = vnA.iteratorToReferencees();
3878 while( heapRegionsItrA.hasNext() ) {
3879 RefEdge edgeA = heapRegionsItrA.next();
3880 HeapRegionNode hrnChildA = edgeA.getDst();
3881 Integer idChildA = hrnChildA.getID();
3883 // at this point we know an edge in graph A exists
3884 // tdA -> idChildA, does this exist in B?
3885 assert td2vn.containsKey(tdA);
3886 VariableNode vnB = td2vn.get(tdA);
3887 RefEdge edgeToMerge = null;
3889 Iterator<RefEdge> heapRegionsItrB = vnB.iteratorToReferencees();
3890 while( heapRegionsItrB.hasNext() &&
3891 edgeToMerge == null ) {
3893 RefEdge edgeB = heapRegionsItrB.next();
3894 HeapRegionNode hrnChildB = edgeB.getDst();
3895 Integer idChildB = hrnChildB.getID();
3897 // don't use the RefEdge.equals() here because
3898 // we're talking about existence between graphs
3899 if( idChildB.equals(idChildA) &&
3900 edgeB.typeAndFieldEquals(edgeA) ) {
3902 edgeToMerge = edgeB;
3906 // if the edge from A was not found in B,
3908 if( edgeToMerge == null ) {
3909 assert id2hrn.containsKey(idChildA);
3910 HeapRegionNode hrnChildB = id2hrn.get(idChildA);
3911 edgeToMerge = edgeA.copy();
3912 edgeToMerge.setSrc(vnB);
3913 edgeToMerge.setDst(hrnChildB);
3914 addRefEdge(vnB, hrnChildB, edgeToMerge);
3916 // otherwise, the edge already existed in both graphs
3917 // so merge their reachability sets
3919 // just replace this beta set with the union
3920 edgeToMerge.setBeta(Canonical.unionORpreds(edgeToMerge.getBeta(),
3924 edgeToMerge.setPreds(Canonical.join(edgeToMerge.getPreds(),
3928 edgeToMerge.setTaints(
3929 Canonical.union(edgeToMerge.getTaints(),
3938 protected void mergeAllocSites(ReachGraph rg) {
3939 allocSites.addAll(rg.allocSites);
3942 protected void mergeInaccessibleVars(ReachGraph rg) {
3943 inaccessibleVars.addAll(rg.inaccessibleVars);
3948 static boolean dbgEquals = false;
3951 // it is necessary in the equals() member functions
3952 // to "check both ways" when comparing the data
3953 // structures of two graphs. For instance, if all
3954 // edges between heap region nodes in graph A are
3955 // present and equal in graph B it is not sufficient
3956 // to say the graphs are equal. Consider that there
3957 // may be edges in graph B that are not in graph A.
3958 // the only way to know that all edges in both graphs
3959 // are equally present is to iterate over both data
3960 // structures and compare against the other graph.
3961 public boolean equals(ReachGraph rg) {
3965 System.out.println("rg is null");
3970 if( !areHeapRegionNodesEqual(rg) ) {
3972 System.out.println("hrn not equal");
3977 if( !areVariableNodesEqual(rg) ) {
3979 System.out.println("vars not equal");
3984 if( !areRefEdgesEqual(rg) ) {
3986 System.out.println("edges not equal");
3991 if( !inaccessibleVars.equals(rg.inaccessibleVars) ) {
3995 // if everything is equal up to this point,
3996 // assert that allocSites is also equal--
3997 // this data is redundant but kept for efficiency
3998 assert allocSites.equals(rg.allocSites);
4004 protected boolean areHeapRegionNodesEqual(ReachGraph rg) {
4006 if( !areallHRNinAalsoinBandequal(this, rg) ) {
4010 if( !areallHRNinAalsoinBandequal(rg, this) ) {
4017 static protected boolean areallHRNinAalsoinBandequal(ReachGraph rgA,
4019 Set sA = rgA.id2hrn.entrySet();
4020 Iterator iA = sA.iterator();
4021 while( iA.hasNext() ) {
4022 Map.Entry meA = (Map.Entry)iA.next();
4023 Integer idA = (Integer) meA.getKey();
4024 HeapRegionNode hrnA = (HeapRegionNode) meA.getValue();
4026 if( !rgB.id2hrn.containsKey(idA) ) {
4030 HeapRegionNode hrnB = rgB.id2hrn.get(idA);
4031 if( !hrnA.equalsIncludingAlphaAndPreds(hrnB) ) {
4039 protected boolean areVariableNodesEqual(ReachGraph rg) {
4041 if( !areallVNinAalsoinBandequal(this, rg) ) {
4045 if( !areallVNinAalsoinBandequal(rg, this) ) {
4052 static protected boolean areallVNinAalsoinBandequal(ReachGraph rgA,
4054 Set sA = rgA.td2vn.entrySet();
4055 Iterator iA = sA.iterator();
4056 while( iA.hasNext() ) {
4057 Map.Entry meA = (Map.Entry)iA.next();
4058 TempDescriptor tdA = (TempDescriptor) meA.getKey();
4060 if( !rgB.td2vn.containsKey(tdA) ) {
4069 protected boolean areRefEdgesEqual(ReachGraph rg) {
4070 if( !areallREinAandBequal(this, rg) ) {
4074 if( !areallREinAandBequal(rg, this) ) {
4081 static protected boolean areallREinAandBequal(ReachGraph rgA,
4084 // check all the heap region->heap region edges
4085 Set sA = rgA.id2hrn.entrySet();
4086 Iterator iA = sA.iterator();
4087 while( iA.hasNext() ) {
4088 Map.Entry meA = (Map.Entry)iA.next();
4089 Integer idA = (Integer) meA.getKey();
4090 HeapRegionNode hrnA = (HeapRegionNode) meA.getValue();
4092 // we should have already checked that the same
4093 // heap regions exist in both graphs
4094 assert rgB.id2hrn.containsKey(idA);
4096 if( !areallREfromAequaltoB(rgA, hrnA, rgB) ) {
4100 // then check every edge in B for presence in A, starting
4101 // from the same parent HeapRegionNode
4102 HeapRegionNode hrnB = rgB.id2hrn.get(idA);
4104 if( !areallREfromAequaltoB(rgB, hrnB, rgA) ) {
4109 // then check all the variable->heap region edges
4110 sA = rgA.td2vn.entrySet();
4112 while( iA.hasNext() ) {
4113 Map.Entry meA = (Map.Entry)iA.next();
4114 TempDescriptor tdA = (TempDescriptor) meA.getKey();
4115 VariableNode vnA = (VariableNode) meA.getValue();
4117 // we should have already checked that the same
4118 // label nodes exist in both graphs
4119 assert rgB.td2vn.containsKey(tdA);
4121 if( !areallREfromAequaltoB(rgA, vnA, rgB) ) {
4125 // then check every edge in B for presence in A, starting
4126 // from the same parent VariableNode
4127 VariableNode vnB = rgB.td2vn.get(tdA);
4129 if( !areallREfromAequaltoB(rgB, vnB, rgA) ) {
4138 static protected boolean areallREfromAequaltoB(ReachGraph rgA,
4142 Iterator<RefEdge> itrA = rnA.iteratorToReferencees();
4143 while( itrA.hasNext() ) {
4144 RefEdge edgeA = itrA.next();
4145 HeapRegionNode hrnChildA = edgeA.getDst();
4146 Integer idChildA = hrnChildA.getID();
4148 assert rgB.id2hrn.containsKey(idChildA);
4150 // at this point we know an edge in graph A exists
4151 // rnA -> idChildA, does this exact edge exist in B?
4152 boolean edgeFound = false;
4154 RefSrcNode rnB = null;
4155 if( rnA instanceof HeapRegionNode ) {
4156 HeapRegionNode hrnA = (HeapRegionNode) rnA;
4157 rnB = rgB.id2hrn.get(hrnA.getID() );
4159 VariableNode vnA = (VariableNode) rnA;
4160 rnB = rgB.td2vn.get(vnA.getTempDescriptor() );
4163 Iterator<RefEdge> itrB = rnB.iteratorToReferencees();
4164 while( itrB.hasNext() ) {
4165 RefEdge edgeB = itrB.next();
4166 HeapRegionNode hrnChildB = edgeB.getDst();
4167 Integer idChildB = hrnChildB.getID();
4169 if( idChildA.equals(idChildB) &&
4170 edgeA.typeAndFieldEquals(edgeB) ) {
4172 // there is an edge in the right place with the right field,
4173 // but do they have the same attributes?
4174 if( edgeA.getBeta().equals(edgeB.getBeta() ) &&
4175 edgeA.equalsPreds(edgeB)
4191 // can be used to assert monotonicity
4192 static public boolean isNoSmallerThan(ReachGraph rgA,
4195 //System.out.println( "*** Asking if A is no smaller than B ***" );
4198 Iterator iA = rgA.id2hrn.entrySet().iterator();
4199 while( iA.hasNext() ) {
4200 Map.Entry meA = (Map.Entry)iA.next();
4201 Integer idA = (Integer) meA.getKey();
4202 HeapRegionNode hrnA = (HeapRegionNode) meA.getValue();
4204 if( !rgB.id2hrn.containsKey(idA) ) {
4205 System.out.println(" regions smaller");
4209 //HeapRegionNode hrnB = rgB.id2hrn.get( idA );
4210 /* NOT EQUALS, NO SMALLER THAN!
4211 if( !hrnA.equalsIncludingAlphaAndPreds( hrnB ) ) {
4212 System.out.println( " regions smaller" );
4218 // this works just fine, no smaller than
4219 if( !areallVNinAalsoinBandequal(rgA, rgB) ) {
4220 System.out.println(" vars smaller:");
4221 System.out.println(" A:"+rgA.td2vn.keySet() );
4222 System.out.println(" B:"+rgB.td2vn.keySet() );
4227 iA = rgA.id2hrn.entrySet().iterator();
4228 while( iA.hasNext() ) {
4229 Map.Entry meA = (Map.Entry)iA.next();
4230 Integer idA = (Integer) meA.getKey();
4231 HeapRegionNode hrnA = (HeapRegionNode) meA.getValue();
4233 Iterator<RefEdge> reItr = hrnA.iteratorToReferencers();
4234 while( reItr.hasNext() ) {
4235 RefEdge edgeA = reItr.next();
4236 RefSrcNode rsnA = edgeA.getSrc();
4238 // we already checked that nodes were present
4239 HeapRegionNode hrnB = rgB.id2hrn.get(hrnA.getID() );
4240 assert hrnB != null;
4243 if( rsnA instanceof VariableNode ) {
4244 VariableNode vnA = (VariableNode) rsnA;
4245 rsnB = rgB.td2vn.get(vnA.getTempDescriptor() );
4248 HeapRegionNode hrnSrcA = (HeapRegionNode) rsnA;
4249 rsnB = rgB.id2hrn.get(hrnSrcA.getID() );
4251 assert rsnB != null;
4253 RefEdge edgeB = rsnB.getReferenceTo(hrnB,
4257 if( edgeB == null ) {
4258 System.out.println(" edges smaller:");
4262 // REMEMBER, IS NO SMALLER THAN
4264 System.out.println( " edges smaller" );
4280 // this analysis no longer has the "match anything"
4281 // type which was represented by null
4282 protected TypeDescriptor mostSpecificType(TypeDescriptor td1,
4283 TypeDescriptor td2) {
4287 if( td1.isNull() ) {
4290 if( td2.isNull() ) {
4293 return typeUtil.mostSpecific(td1, td2);
4296 protected TypeDescriptor mostSpecificType(TypeDescriptor td1,
4298 TypeDescriptor td3) {
4300 return mostSpecificType(td1,
4301 mostSpecificType(td2, td3)
4305 protected TypeDescriptor mostSpecificType(TypeDescriptor td1,
4308 TypeDescriptor td4) {
4310 return mostSpecificType(mostSpecificType(td1, td2),
4311 mostSpecificType(td3, td4)
4315 protected boolean isSuperiorType(TypeDescriptor possibleSuper,
4316 TypeDescriptor possibleChild) {
4317 assert possibleSuper != null;
4318 assert possibleChild != null;
4320 if( possibleSuper.isNull() ||
4321 possibleChild.isNull() ) {
4325 return typeUtil.isSuperorType(possibleSuper, possibleChild);
4329 protected boolean hasMatchingField(HeapRegionNode src,
4332 TypeDescriptor tdSrc = src.getType();
4333 assert tdSrc != null;
4335 if( tdSrc.isArray() ) {
4336 TypeDescriptor td = edge.getType();
4339 TypeDescriptor tdSrcDeref = tdSrc.dereference();
4340 assert tdSrcDeref != null;
4342 if( !typeUtil.isSuperorType(tdSrcDeref, td) ) {
4346 return edge.getField().equals(DisjointAnalysis.arrayElementFieldName);
4349 // if it's not a class, it doesn't have any fields to match
4350 if( !tdSrc.isClass() ) {
4354 ClassDescriptor cd = tdSrc.getClassDesc();
4355 while( cd != null ) {
4356 Iterator fieldItr = cd.getFields();
4358 while( fieldItr.hasNext() ) {
4359 FieldDescriptor fd = (FieldDescriptor) fieldItr.next();
4361 if( fd.getType().equals(edge.getType() ) &&
4362 fd.getSymbol().equals(edge.getField() ) ) {
4367 cd = cd.getSuperDesc();
4370 // otherwise it is a class with fields
4371 // but we didn't find a match
4375 protected boolean hasMatchingType(RefEdge edge,
4376 HeapRegionNode dst) {
4378 // if the region has no type, matches everything
4379 TypeDescriptor tdDst = dst.getType();
4380 assert tdDst != null;
4382 // if the type is not a class or an array, don't
4383 // match because primitives are copied, no aliases
4384 ClassDescriptor cdDst = tdDst.getClassDesc();
4385 if( cdDst == null && !tdDst.isArray() ) {
4389 // if the edge type is null, it matches everything
4390 TypeDescriptor tdEdge = edge.getType();
4391 assert tdEdge != null;
4393 return typeUtil.isSuperorType(tdEdge, tdDst);
4398 // the default signature for quick-and-dirty debugging
4399 public void writeGraph(String graphName) {
4400 writeGraph(graphName,
4401 true, // write labels
4402 true, // label select
4403 true, // prune garbage
4404 false, // hide reachability
4405 true, // hide subset reachability
4406 true, // hide predicates
4407 false, // hide edge taints
4408 null // in-context boundary
4412 public void writeGraph(String graphName,
4413 boolean writeLabels,
4414 boolean labelSelect,
4415 boolean pruneGarbage,
4416 boolean hideReachability,
4417 boolean hideSubsetReachability,
4418 boolean hidePredicates,
4419 boolean hideEdgeTaints
4421 writeGraph(graphName,
4426 hideSubsetReachability,
4432 public void writeGraph(String graphName,
4433 boolean writeLabels,
4434 boolean labelSelect,
4435 boolean pruneGarbage,
4436 boolean hideReachability,
4437 boolean hideSubsetReachability,
4438 boolean hidePredicates,
4439 boolean hideEdgeTaints,
4440 Set<Integer> callerNodeIDsCopiedToCallee
4443 // remove all non-word characters from the graph name so
4444 // the filename and identifier in dot don't cause errors
4445 graphName = graphName.replaceAll("[\\W]", "");
4448 new BufferedWriter(new FileWriter(graphName+".dot") );
4450 bw.write("digraph "+graphName+" {\n");
4453 // this is an optional step to form the callee-reachable
4454 // "cut-out" into a DOT cluster for visualization
4455 if( callerNodeIDsCopiedToCallee != null ) {
4457 bw.write(" subgraph cluster0 {\n");
4458 bw.write(" color=blue;\n");
4460 Iterator i = id2hrn.entrySet().iterator();
4461 while( i.hasNext() ) {
4462 Map.Entry me = (Map.Entry)i.next();
4463 HeapRegionNode hrn = (HeapRegionNode) me.getValue();
4465 if( callerNodeIDsCopiedToCallee.contains(hrn.getID() ) ) {
4468 hrn.toStringDOT(hideReachability,
4469 hideSubsetReachability,
4479 Set<HeapRegionNode> visited = new HashSet<HeapRegionNode>();
4481 // then visit every heap region node
4482 Iterator i = id2hrn.entrySet().iterator();
4483 while( i.hasNext() ) {
4484 Map.Entry me = (Map.Entry)i.next();
4485 HeapRegionNode hrn = (HeapRegionNode) me.getValue();
4487 // only visit nodes worth writing out--for instance
4488 // not every node at an allocation is referenced
4489 // (think of it as garbage-collected), etc.
4490 if( !pruneGarbage ||
4491 hrn.isOutOfContext() ||
4492 (hrn.isFlagged() && hrn.getID() > 0 && !hrn.isWiped()) // a non-shadow flagged node
4495 if( !visited.contains(hrn) ) {
4496 traverseHeapRegionNodes(hrn,
4501 hideSubsetReachability,
4504 callerNodeIDsCopiedToCallee);
4509 bw.write(" graphTitle[label=\""+graphName+"\",shape=box];\n");
4512 // then visit every label node, useful for debugging
4514 i = td2vn.entrySet().iterator();
4515 while( i.hasNext() ) {
4516 Map.Entry me = (Map.Entry)i.next();
4517 VariableNode vn = (VariableNode) me.getValue();
4520 String labelStr = vn.getTempDescriptorString();
4521 if( labelStr.startsWith("___temp") ||
4522 labelStr.startsWith("___dst") ||
4523 labelStr.startsWith("___srctmp") ||
4524 labelStr.startsWith("___neverused")
4530 Iterator<RefEdge> heapRegionsItr = vn.iteratorToReferencees();
4531 while( heapRegionsItr.hasNext() ) {
4532 RefEdge edge = heapRegionsItr.next();
4533 HeapRegionNode hrn = edge.getDst();
4535 if( !visited.contains(hrn) ) {
4536 traverseHeapRegionNodes(hrn,
4541 hideSubsetReachability,
4544 callerNodeIDsCopiedToCallee);
4547 bw.write(" "+vn.toString()+
4548 " -> "+hrn.toString()+
4549 edge.toStringDOT(hideReachability,
4550 hideSubsetReachability,
4562 } catch( IOException e ) {
4563 throw new Error("Error writing out DOT graph "+graphName);
4568 traverseHeapRegionNodes(HeapRegionNode hrn,
4571 Set<HeapRegionNode> visited,
4572 boolean hideReachability,
4573 boolean hideSubsetReachability,
4574 boolean hidePredicates,
4575 boolean hideEdgeTaints,
4576 Set<Integer> callerNodeIDsCopiedToCallee
4577 ) throws java.io.IOException {
4579 if( visited.contains(hrn) ) {
4584 // if we're drawing the callee-view subgraph, only
4585 // write out the node info if it hasn't already been
4587 if( callerNodeIDsCopiedToCallee == null ||
4588 !callerNodeIDsCopiedToCallee.contains(hrn.getID() )
4592 hrn.toStringDOT(hideReachability,
4593 hideSubsetReachability,
4598 Iterator<RefEdge> childRegionsItr = hrn.iteratorToReferencees();
4599 while( childRegionsItr.hasNext() ) {
4600 RefEdge edge = childRegionsItr.next();
4601 HeapRegionNode hrnChild = edge.getDst();
4603 if( callerNodeIDsCopiedToCallee != null &&
4604 (edge.getSrc() instanceof HeapRegionNode) ) {
4605 HeapRegionNode hrnSrc = (HeapRegionNode) edge.getSrc();
4606 if( callerNodeIDsCopiedToCallee.contains(hrnSrc.getID() ) &&
4607 callerNodeIDsCopiedToCallee.contains(edge.getDst().getID() )
4609 bw.write(" "+hrn.toString()+
4610 " -> "+hrnChild.toString()+
4611 edge.toStringDOT(hideReachability,
4612 hideSubsetReachability,
4617 } else if( !callerNodeIDsCopiedToCallee.contains(hrnSrc.getID() ) &&
4618 callerNodeIDsCopiedToCallee.contains(edge.getDst().getID() )
4620 bw.write(" "+hrn.toString()+
4621 " -> "+hrnChild.toString()+
4622 edge.toStringDOT(hideReachability,
4623 hideSubsetReachability,
4626 ",color=blue,style=dashed")+
4629 bw.write(" "+hrn.toString()+
4630 " -> "+hrnChild.toString()+
4631 edge.toStringDOT(hideReachability,
4632 hideSubsetReachability,
4639 bw.write(" "+hrn.toString()+
4640 " -> "+hrnChild.toString()+
4641 edge.toStringDOT(hideReachability,
4642 hideSubsetReachability,
4649 traverseHeapRegionNodes(hrnChild,
4654 hideSubsetReachability,
4657 callerNodeIDsCopiedToCallee);
4666 // return the set of heap regions from the given allocation
4667 // site, if any, that exist in this graph
4668 protected Set<HeapRegionNode> getAnyExisting(AllocSite as) {
4670 Set<HeapRegionNode> out = new HashSet<HeapRegionNode>();
4672 Integer idSum = as.getSummary();
4673 if( id2hrn.containsKey(idSum) ) {
4674 out.add(id2hrn.get(idSum) );
4677 for( int i = 0; i < as.getAllocationDepth(); ++i ) {
4678 Integer idI = as.getIthOldest(i);
4679 if( id2hrn.containsKey(idI) ) {
4680 out.add(id2hrn.get(idI) );
4687 // return the set of reach tuples (NOT A REACH STATE! JUST A SET!)
4688 // from the given allocation site, if any, from regions for that
4689 // site that exist in this graph
4690 protected Set<ReachTuple> getAnyExisting(AllocSite as,
4691 boolean includeARITY_ZEROORMORE,
4692 boolean includeARITY_ONE) {
4694 Set<ReachTuple> out = new HashSet<ReachTuple>();
4696 Integer idSum = as.getSummary();
4697 if( id2hrn.containsKey(idSum) ) {
4699 HeapRegionNode hrn = id2hrn.get(idSum);
4700 assert !hrn.isOutOfContext();
4702 if( !includeARITY_ZEROORMORE ) {
4703 out.add(ReachTuple.factory(hrn.getID(),
4704 true, // multi-obj region
4705 ReachTuple.ARITY_ZEROORMORE,
4710 if( includeARITY_ONE ) {
4711 out.add(ReachTuple.factory(hrn.getID(),
4712 true, // multi-object region
4713 ReachTuple.ARITY_ONE,
4719 if( !includeARITY_ONE ) {
4720 // no need to do the single-object regions that
4721 // only have an ARITY ONE possible
4725 for( int i = 0; i < as.getAllocationDepth(); ++i ) {
4727 Integer idI = as.getIthOldest(i);
4728 if( id2hrn.containsKey(idI) ) {
4730 HeapRegionNode hrn = id2hrn.get(idI);
4731 assert !hrn.isOutOfContext();
4733 out.add(ReachTuple.factory(hrn.getID(),
4734 false, // multi-object region
4735 ReachTuple.ARITY_ONE,
4745 // if an object allocated at the target site may be
4746 // reachable from both an object from root1 and an
4747 // object allocated at root2, return TRUE
4748 public boolean mayBothReachTarget(AllocSite asRoot1,
4750 AllocSite asTarget) {
4752 // consider all heap regions of the target and look
4753 // for a reach state that indicates regions of root1
4754 // and root2 might be able to reach same object
4755 Set<HeapRegionNode> hrnSetTarget = getAnyExisting(asTarget);
4757 // get relevant reach tuples, include ARITY_ZEROORMORE and ARITY_ONE
4758 Set<ReachTuple> rtSet1 = getAnyExisting(asRoot1, true, true);
4759 Set<ReachTuple> rtSet2 = getAnyExisting(asRoot2, true, true);
4761 Iterator<HeapRegionNode> hrnItr = hrnSetTarget.iterator();
4762 while( hrnItr.hasNext() ) {
4763 HeapRegionNode hrn = hrnItr.next();
4765 Iterator<ReachTuple> rtItr1 = rtSet1.iterator();
4766 while( rtItr1.hasNext() ) {
4767 ReachTuple rt1 = rtItr1.next();
4769 Iterator<ReachTuple> rtItr2 = rtSet2.iterator();
4770 while( rtItr2.hasNext() ) {
4771 ReachTuple rt2 = rtItr2.next();
4773 if( !hrn.getAlpha().getStatesWithBoth(rt1, rt2).isEmpty() ) {
4783 // similar to the method above, return TRUE if ever
4784 // more than one object from the root allocation site
4785 // may reach an object from the target site
4786 public boolean mayManyReachTarget(AllocSite asRoot,
4787 AllocSite asTarget) {
4789 // consider all heap regions of the target and look
4790 // for a reach state that multiple objects of root
4791 // might be able to reach the same object
4792 Set<HeapRegionNode> hrnSetTarget = getAnyExisting(asTarget);
4794 // get relevant reach tuples
4795 Set<ReachTuple> rtSetZOM = getAnyExisting(asRoot, true, false);
4796 Set<ReachTuple> rtSetONE = getAnyExisting(asRoot, false, true);
4798 Iterator<HeapRegionNode> hrnItr = hrnSetTarget.iterator();
4799 while( hrnItr.hasNext() ) {
4800 HeapRegionNode hrn = hrnItr.next();
4802 // if any ZERORMORE tuples are here, TRUE
4803 Iterator<ReachTuple> rtItr = rtSetZOM.iterator();
4804 while( rtItr.hasNext() ) {
4805 ReachTuple rtZOM = rtItr.next();
4807 if( hrn.getAlpha().containsTuple(rtZOM) ) {
4812 // otherwise, look for any pair of ONE tuples
4813 Iterator<ReachTuple> rtItr1 = rtSetONE.iterator();
4814 while( rtItr1.hasNext() ) {
4815 ReachTuple rt1 = rtItr1.next();
4817 Iterator<ReachTuple> rtItr2 = rtSetONE.iterator();
4818 while( rtItr2.hasNext() ) {
4819 ReachTuple rt2 = rtItr2.next();
4825 if( !hrn.getAlpha().getStatesWithBoth(rt1, rt2).isEmpty() ) {
4839 public Set<HeapRegionNode> findCommonReachableNodes(ReachSet proofOfSharing) {
4841 Set<HeapRegionNode> exhibitProofState =
4842 new HashSet<HeapRegionNode>();
4844 Iterator hrnItr = id2hrn.entrySet().iterator();
4845 while( hrnItr.hasNext() ) {
4846 Map.Entry me = (Map.Entry)hrnItr.next();
4847 HeapRegionNode hrn = (HeapRegionNode) me.getValue();
4849 ReachSet intersection =
4850 Canonical.intersection(proofOfSharing,
4853 if( !intersection.isEmpty() ) {
4854 assert !hrn.isOutOfContext();
4855 exhibitProofState.add(hrn);
4859 return exhibitProofState;
4863 public Set<HeapRegionNode> mayReachSharedObjects(HeapRegionNode hrn1,
4864 HeapRegionNode hrn2) {
4865 assert hrn1 != null;
4866 assert hrn2 != null;
4868 assert !hrn1.isOutOfContext();
4869 assert !hrn2.isOutOfContext();
4871 assert belongsToThis(hrn1);
4872 assert belongsToThis(hrn2);
4874 assert !hrn1.getID().equals(hrn2.getID() );
4877 // then get the various tokens for these heap regions
4879 ReachTuple.factory(hrn1.getID(),
4880 !hrn1.isSingleObject(), // multi?
4881 ReachTuple.ARITY_ONE,
4884 ReachTuple h1star = null;
4885 if( !hrn1.isSingleObject() ) {
4887 ReachTuple.factory(hrn1.getID(),
4888 !hrn1.isSingleObject(),
4889 ReachTuple.ARITY_ZEROORMORE,
4894 ReachTuple.factory(hrn2.getID(),
4895 !hrn2.isSingleObject(),
4896 ReachTuple.ARITY_ONE,
4899 ReachTuple h2star = null;
4900 if( !hrn2.isSingleObject() ) {
4902 ReachTuple.factory(hrn2.getID(),
4903 !hrn2.isSingleObject(),
4904 ReachTuple.ARITY_ZEROORMORE,
4908 // then get the merged beta of all out-going edges from these heap
4911 ReachSet beta1 = ReachSet.factory();
4912 Iterator<RefEdge> itrEdge = hrn1.iteratorToReferencees();
4913 while (itrEdge.hasNext()) {
4914 RefEdge edge = itrEdge.next();
4915 beta1 = Canonical.unionORpreds(beta1, edge.getBeta());
4918 ReachSet beta2 = ReachSet.factory();
4919 itrEdge = hrn2.iteratorToReferencees();
4920 while (itrEdge.hasNext()) {
4921 RefEdge edge = itrEdge.next();
4922 beta2 = Canonical.unionORpreds(beta2, edge.getBeta());
4925 ReachSet proofOfSharing = ReachSet.factory();
4928 Canonical.unionORpreds(proofOfSharing,
4929 beta1.getStatesWithBoth(h1, h2)
4932 Canonical.unionORpreds(proofOfSharing,
4933 beta2.getStatesWithBoth(h1, h2)
4936 if( !hrn1.isSingleObject() ) {
4938 Canonical.unionORpreds(proofOfSharing,
4939 beta1.getStatesWithBoth(h1star, h2)
4942 Canonical.unionORpreds(proofOfSharing,
4943 beta2.getStatesWithBoth(h1star, h2)
4947 if( !hrn2.isSingleObject() ) {
4949 Canonical.unionORpreds(proofOfSharing,
4950 beta1.getStatesWithBoth(h1, h2star)
4953 Canonical.unionORpreds(proofOfSharing,
4954 beta2.getStatesWithBoth(h1, h2star)
4958 if( !hrn1.isSingleObject() &&
4959 !hrn2.isSingleObject()
4962 Canonical.unionORpreds(proofOfSharing,
4963 beta1.getStatesWithBoth(h1star, h2star)
4966 Canonical.unionORpreds(proofOfSharing,
4967 beta2.getStatesWithBoth(h1star, h2star)
4971 Set<HeapRegionNode> common = new HashSet<HeapRegionNode>();
4972 if( !proofOfSharing.isEmpty() ) {
4973 common = findCommonReachableNodes(proofOfSharing);
4974 if( !DISABLE_STRONG_UPDATES &&
4975 !DISABLE_GLOBAL_SWEEP
4977 assert !common.isEmpty();
4984 // this version of the above method checks whether there is sharing
4985 // among the objects in a summary node
4986 public Set<HeapRegionNode> mayReachSharedObjects(HeapRegionNode hrn) {
4988 assert hrn.isNewSummary();
4989 assert !hrn.isOutOfContext();
4990 assert belongsToThis(hrn);
4993 ReachTuple.factory(hrn.getID(),
4995 ReachTuple.ARITY_ZEROORMORE,
4998 // then get the merged beta of all out-going edges from
5001 ReachSet beta = ReachSet.factory();
5002 Iterator<RefEdge> itrEdge = hrn.iteratorToReferencees();
5003 while (itrEdge.hasNext()) {
5004 RefEdge edge = itrEdge.next();
5005 beta = Canonical.unionORpreds(beta, edge.getBeta());
5008 ReachSet proofOfSharing = ReachSet.factory();
5011 Canonical.unionORpreds(proofOfSharing,
5012 beta.getStatesWithBoth(hstar, hstar)
5015 Set<HeapRegionNode> common = new HashSet<HeapRegionNode>();
5016 if( !proofOfSharing.isEmpty() ) {
5017 common = findCommonReachableNodes(proofOfSharing);
5018 if( !DISABLE_STRONG_UPDATES &&
5019 !DISABLE_GLOBAL_SWEEP
5021 assert !common.isEmpty();
5029 public Set<HeapRegionNode> mayReachSharedObjects(FlatMethod fm,
5030 Integer paramIndex1,
5031 Integer paramIndex2) {
5033 // get parameter's heap regions
5034 TempDescriptor paramTemp1 = fm.getParameter(paramIndex1.intValue());
5035 assert this.hasVariable(paramTemp1);
5036 VariableNode paramVar1 = getVariableNodeFromTemp(paramTemp1);
5039 if( !(paramVar1.getNumReferencees() == 1) ) {
5040 System.out.println("\n fm="+fm+"\n param="+paramTemp1);
5041 writeGraph("whatup");
5045 assert paramVar1.getNumReferencees() == 1;
5046 RefEdge paramEdge1 = paramVar1.iteratorToReferencees().next();
5047 HeapRegionNode hrnParam1 = paramEdge1.getDst();
5049 TempDescriptor paramTemp2 = fm.getParameter(paramIndex2.intValue());
5050 assert this.hasVariable(paramTemp2);
5051 VariableNode paramVar2 = getVariableNodeFromTemp(paramTemp2);
5053 if( !(paramVar2.getNumReferencees() == 1) ) {
5054 System.out.println("\n fm="+fm+"\n param="+paramTemp2);
5055 writeGraph("whatup");
5058 assert paramVar2.getNumReferencees() == 1;
5059 RefEdge paramEdge2 = paramVar2.iteratorToReferencees().next();
5060 HeapRegionNode hrnParam2 = paramEdge2.getDst();
5062 Set<HeapRegionNode> common = new HashSet<HeapRegionNode>();
5063 common.addAll(mayReachSharedObjects(hrnParam1, hrnParam2));
5068 public Set<HeapRegionNode> mayReachSharedObjects(FlatMethod fm,
5072 // get parameter's heap regions
5073 TempDescriptor paramTemp = fm.getParameter(paramIndex.intValue());
5074 assert this.hasVariable(paramTemp);
5075 VariableNode paramVar = getVariableNodeFromTemp(paramTemp);
5076 assert paramVar.getNumReferencees() == 1;
5077 RefEdge paramEdge = paramVar.iteratorToReferencees().next();
5078 HeapRegionNode hrnParam = paramEdge.getDst();
5081 HeapRegionNode hrnSummary=null;
5082 if(id2hrn.containsKey(as.getSummary())) {
5083 // if summary node doesn't exist, ignore this case
5084 hrnSummary = id2hrn.get(as.getSummary());
5085 assert hrnSummary != null;
5088 Set<HeapRegionNode> common = new HashSet<HeapRegionNode>();
5089 if(hrnSummary!=null) {
5090 common.addAll(mayReachSharedObjects(hrnParam, hrnSummary) );
5093 // check for other nodes
5094 for (int i = 0; i < as.getAllocationDepth(); ++i) {
5096 assert id2hrn.containsKey(as.getIthOldest(i));
5097 HeapRegionNode hrnIthOldest = id2hrn.get(as.getIthOldest(i));
5098 assert hrnIthOldest != null;
5100 common.addAll(mayReachSharedObjects(hrnParam, hrnIthOldest));
5107 public Set<HeapRegionNode> mayReachSharedObjects(AllocSite as1,
5110 // get summary node 1's alpha
5111 Integer idSum1 = as1.getSummary();
5112 HeapRegionNode hrnSum1=null;
5113 if(id2hrn.containsKey(idSum1)) {
5114 hrnSum1 = id2hrn.get(idSum1);
5117 // get summary node 2's alpha
5118 Integer idSum2 = as2.getSummary();
5119 HeapRegionNode hrnSum2=null;
5120 if(id2hrn.containsKey(idSum2)) {
5121 hrnSum2 = id2hrn.get(idSum2);
5124 Set<HeapRegionNode> common = new HashSet<HeapRegionNode>();
5125 if(hrnSum1!=null && hrnSum2!=null && hrnSum1!=hrnSum2) {
5126 common.addAll(mayReachSharedObjects(hrnSum1, hrnSum2));
5130 // ask if objects from this summary share among each other
5131 common.addAll(mayReachSharedObjects(hrnSum1));
5134 // check sum2 against alloc1 nodes
5136 for (int i = 0; i < as1.getAllocationDepth(); ++i) {
5137 Integer idI1 = as1.getIthOldest(i);
5138 assert id2hrn.containsKey(idI1);
5139 HeapRegionNode hrnI1 = id2hrn.get(idI1);
5140 assert hrnI1 != null;
5141 common.addAll(mayReachSharedObjects(hrnI1, hrnSum2));
5144 // also ask if objects from this summary share among each other
5145 common.addAll(mayReachSharedObjects(hrnSum2));
5148 // check sum1 against alloc2 nodes
5149 for (int i = 0; i < as2.getAllocationDepth(); ++i) {
5150 Integer idI2 = as2.getIthOldest(i);
5151 assert id2hrn.containsKey(idI2);
5152 HeapRegionNode hrnI2 = id2hrn.get(idI2);
5153 assert hrnI2 != null;
5156 common.addAll(mayReachSharedObjects(hrnSum1, hrnI2));
5159 // while we're at it, do an inner loop for alloc2 vs alloc1 nodes
5160 for (int j = 0; j < as1.getAllocationDepth(); ++j) {
5161 Integer idI1 = as1.getIthOldest(j);
5163 // if these are the same site, don't look for the same token, no
5165 // different tokens of the same site could alias together though
5166 if (idI1.equals(idI2)) {
5170 HeapRegionNode hrnI1 = id2hrn.get(idI1);
5172 common.addAll(mayReachSharedObjects(hrnI1, hrnI2));
5179 public void makeInaccessible(Set<TempDescriptor> vars) {
5180 inaccessibleVars.addAll(vars);
5183 public void makeInaccessible(TempDescriptor td) {
5184 inaccessibleVars.add(td);
5187 public void makeAccessible(TempDescriptor td) {
5188 inaccessibleVars.remove(td);
5191 public boolean isAccessible(TempDescriptor td) {
5192 return !inaccessibleVars.contains(td);
5195 public Set<TempDescriptor> getInaccessibleVars() {
5196 return inaccessibleVars;