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 temps
16 protected static TempDescriptor tdReturn;
17 protected static TempDescriptor tdStrLiteralBytes;
19 public static void initOutOfScopeTemps() {
20 tdReturn = new TempDescriptor("_Return___");
23 new TempDescriptor("_strLiteralBytes___",
24 new TypeDescriptor(TypeDescriptor.CHAR).makeArray( state )
28 // predicate constants
29 public static final ExistPred predTrue = ExistPred.factory(); // if no args, true
30 public static final ExistPredSet predsEmpty = ExistPredSet.factory();
31 public static final ExistPredSet predsTrue = ExistPredSet.factory(predTrue);
33 // some frequently used reachability constants
34 protected static final ReachState rstateEmpty = ReachState.factory();
35 protected static final ReachSet rsetEmpty = ReachSet.factory();
36 protected static final ReachSet rsetWithEmptyState = Canonical.changePredsTo(ReachSet.factory(rstateEmpty),
39 // from DisjointAnalysis for convenience
40 protected static int allocationDepth = -1;
41 protected static TypeUtil typeUtil = null;
42 protected static State state = null;
45 // variable and heap region nodes indexed by unique ID
46 public Hashtable<Integer, HeapRegionNode> id2hrn;
47 public Hashtable<TempDescriptor, VariableNode > td2vn;
49 // convenient set of alloc sites for all heap regions
50 // present in the graph without having to search
51 public Set<AllocSite> allocSites;
53 // set of inaccessible variables for current program statement
54 // with respect to stall-site analysis
55 public Set<TempDescriptor> inaccessibleVars;
59 id2hrn = new Hashtable<Integer, HeapRegionNode>();
60 td2vn = new Hashtable<TempDescriptor, VariableNode >();
61 allocSites = new HashSet<AllocSite>();
62 inaccessibleVars = new HashSet<TempDescriptor>();
66 // temp descriptors are globally unique and map to
67 // exactly one variable node, easy
68 protected VariableNode getVariableNodeFromTemp(TempDescriptor td) {
71 if( !td2vn.containsKey(td) ) {
72 td2vn.put(td, new VariableNode(td) );
78 //This method is created for client modules to access the Reachgraph
79 //after the analysis is done and no modifications are to be made.
80 public VariableNode getVariableNodeNoMutation(TempDescriptor td) {
83 if( !td2vn.containsKey(td) ) {
90 public boolean hasVariable(TempDescriptor td) {
91 return td2vn.containsKey(td);
95 // this suite of methods can be used to assert a
96 // very important property of ReachGraph objects:
97 // some element, HeapRegionNode, RefEdge etc.
98 // should be referenced by at most ONE ReachGraph!!
99 // If a heap region or edge or variable should be
100 // in another graph, make a new object with
101 // equivalent properties for a new graph
102 public boolean belongsToThis(RefSrcNode rsn) {
103 if( rsn instanceof VariableNode ) {
104 VariableNode vn = (VariableNode) rsn;
105 return this.td2vn.get(vn.getTempDescriptor() ) == vn;
107 HeapRegionNode hrn = (HeapRegionNode) rsn;
108 return this.id2hrn.get(hrn.getID() ) == hrn;
115 // the reason for this method is to have the option
116 // of creating new heap regions with specific IDs, or
117 // duplicating heap regions with specific IDs (especially
118 // in the merge() operation) or to create new heap
119 // regions with a new unique ID
120 protected HeapRegionNode
121 createNewHeapRegionNode(Integer id,
122 boolean isSingleObject,
123 boolean isNewSummary,
124 boolean isOutOfContext,
133 TypeDescriptor typeToUse = null;
134 if( allocSite != null ) {
135 typeToUse = allocSite.getType();
136 allocSites.add(allocSite);
141 boolean markForAnalysis = false;
142 if( allocSite != null && allocSite.isFlagged() ) {
143 markForAnalysis = true;
146 if( allocSite == null ) {
147 assert !markForAnalysis;
149 } else if( markForAnalysis != allocSite.isFlagged() ) {
155 id = DisjointAnalysis.generateUniqueHeapRegionNodeID();
158 if( inherent == null ) {
159 if( markForAnalysis ) {
161 Canonical.changePredsTo(
164 ReachTuple.factory(id,
166 ReachTuple.ARITY_ONE,
167 false // out-of-context
174 inherent = rsetWithEmptyState;
178 if( alpha == null ) {
182 assert preds != null;
184 HeapRegionNode hrn = new HeapRegionNode(id,
201 ////////////////////////////////////////////////
203 // Low-level referencee and referencer methods
205 // These methods provide the lowest level for
206 // creating references between reachability nodes
207 // and handling the details of maintaining both
208 // list of referencers and referencees.
210 ////////////////////////////////////////////////
211 protected void addRefEdge(RefSrcNode referencer,
212 HeapRegionNode referencee,
214 assert referencer != null;
215 assert referencee != null;
217 assert edge.getSrc() == referencer;
218 assert edge.getDst() == referencee;
219 assert belongsToThis(referencer);
220 assert belongsToThis(referencee);
222 // edges are getting added twice to graphs now, the
223 // kind that should have abstract facts merged--use
224 // this check to prevent that
225 assert referencer.getReferenceTo(referencee,
230 referencer.addReferencee(edge);
231 referencee.addReferencer(edge);
234 protected void removeRefEdge(RefEdge e) {
235 removeRefEdge(e.getSrc(),
241 protected void removeRefEdge(RefSrcNode referencer,
242 HeapRegionNode referencee,
245 assert referencer != null;
246 assert referencee != null;
248 RefEdge edge = referencer.getReferenceTo(referencee,
252 assert edge == referencee.getReferenceFrom(referencer,
256 referencer.removeReferencee(edge);
257 referencee.removeReferencer(edge);
261 protected boolean clearRefEdgesFrom(RefSrcNode referencer,
265 return clearRefEdgesFrom( referencer, type, field, removeAll, null, null );
268 // return whether at least one edge was removed
269 protected boolean clearRefEdgesFrom(RefSrcNode referencer,
273 Set<EdgeKey> edgeKeysRemoved,
274 FieldDescriptor fd) {
275 assert referencer != null;
277 boolean atLeastOneEdgeRemoved = false;
279 // get a copy of the set to iterate over, otherwise
280 // we will be trying to take apart the set as we
281 // are iterating over it, which won't work
282 Iterator<RefEdge> i = referencer.iteratorToReferenceesClone();
283 while( i.hasNext() ) {
284 RefEdge edge = i.next();
287 (edge.typeEquals(type) && edge.fieldEquals(field))
290 HeapRegionNode referencee = edge.getDst();
292 if( edgeKeysRemoved != null ) {
294 assert referencer instanceof HeapRegionNode;
295 edgeKeysRemoved.add( new EdgeKey( ((HeapRegionNode)referencer).getID(),
301 removeRefEdge(referencer,
306 atLeastOneEdgeRemoved = true;
310 return atLeastOneEdgeRemoved;
313 protected void clearRefEdgesTo(HeapRegionNode referencee,
317 assert referencee != null;
319 // get a copy of the set to iterate over, otherwise
320 // we will be trying to take apart the set as we
321 // are iterating over it, which won't work
322 Iterator<RefEdge> i = referencee.iteratorToReferencersClone();
323 while( i.hasNext() ) {
324 RefEdge edge = i.next();
327 (edge.typeEquals(type) && edge.fieldEquals(field))
330 RefSrcNode referencer = edge.getSrc();
332 removeRefEdge(referencer,
340 protected void clearNonVarRefEdgesTo(HeapRegionNode referencee) {
341 assert referencee != null;
343 // get a copy of the set to iterate over, otherwise
344 // we will be trying to take apart the set as we
345 // are iterating over it, which won't work
346 Iterator<RefEdge> i = referencee.iteratorToReferencersClone();
347 while( i.hasNext() ) {
348 RefEdge edge = i.next();
349 RefSrcNode referencer = edge.getSrc();
350 if( !(referencer instanceof VariableNode) ) {
351 removeRefEdge(referencer,
359 // this is a common operation in many transfer functions: we want
360 // to add an edge, but if there is already such an edge we should
361 // merge the properties of the existing and the new edges
362 protected void addEdgeOrMergeWithExisting(RefEdge edgeNew) {
364 RefSrcNode src = edgeNew.getSrc();
365 assert belongsToThis(src);
367 HeapRegionNode dst = edgeNew.getDst();
368 assert belongsToThis(dst);
370 // look to see if an edge with same field exists
371 // and merge with it, otherwise just add the edge
372 RefEdge edgeExisting = src.getReferenceTo(dst,
377 if( edgeExisting != null ) {
378 edgeExisting.setBeta(
379 Canonical.unionORpreds(edgeExisting.getBeta(),
383 edgeExisting.setPreds(
384 Canonical.join(edgeExisting.getPreds(),
388 edgeExisting.setTaints(
389 Canonical.unionORpreds(edgeExisting.getTaints(),
395 addRefEdge(src, dst, edgeNew);
401 ////////////////////////////////////////////////////
403 // Assignment Operation Methods
405 // These methods are high-level operations for
406 // modeling program assignment statements using
407 // the low-level reference create/remove methods
410 ////////////////////////////////////////////////////
412 public void assignTempEqualToStringLiteral(TempDescriptor x,
413 AllocSite asStringLiteral,
414 AllocSite asStringLiteralBytes,
415 FieldDescriptor fdStringBytesField) {
416 // model this to get points-to information right for
417 // pointers to string literals, even though it doesn't affect
418 // reachability paths in the heap
419 assignTempEqualToNewAlloc( x,
422 assignTempEqualToNewAlloc( tdStrLiteralBytes,
423 asStringLiteralBytes );
425 assignTempXFieldFEqualToTempY( x,
433 public void assignTempXEqualToTempY(TempDescriptor x,
435 assignTempXEqualToCastedTempY(x, y, null);
439 public void assignTempXEqualToCastedTempY(TempDescriptor x,
441 TypeDescriptor tdCast) {
443 VariableNode lnX = getVariableNodeFromTemp(x);
444 VariableNode lnY = getVariableNodeFromTemp(y);
446 clearRefEdgesFrom(lnX, null, null, true);
448 // note it is possible that the types of temps in the
449 // flat node to analyze will reveal that some typed
450 // edges in the reachability graph are impossible
451 Set<RefEdge> impossibleEdges = new HashSet<RefEdge>();
453 Iterator<RefEdge> itrYhrn = lnY.iteratorToReferencees();
454 while( itrYhrn.hasNext() ) {
455 RefEdge edgeY = itrYhrn.next();
456 HeapRegionNode referencee = edgeY.getDst();
457 RefEdge edgeNew = edgeY.copy();
459 if( !isSuperiorType(x.getType(), edgeY.getType() ) ) {
460 impossibleEdges.add(edgeY);
466 if( tdCast == null ) {
467 edgeNew.setType(mostSpecificType(y.getType(),
473 edgeNew.setType(mostSpecificType(y.getType(),
475 referencee.getType(),
481 edgeNew.setField(null);
483 addRefEdge(lnX, referencee, edgeNew);
486 Iterator<RefEdge> itrImp = impossibleEdges.iterator();
487 while( itrImp.hasNext() ) {
488 RefEdge edgeImp = itrImp.next();
489 removeRefEdge(edgeImp);
494 public void assignTempXEqualToTempYFieldF(TempDescriptor x,
497 FlatNode currentProgramPoint
500 VariableNode lnX = getVariableNodeFromTemp(x);
501 VariableNode lnY = getVariableNodeFromTemp(y);
503 clearRefEdgesFrom(lnX, null, null, true);
505 // note it is possible that the types of temps in the
506 // flat node to analyze will reveal that some typed
507 // edges in the reachability graph are impossible
508 Set<RefEdge> impossibleEdges = new HashSet<RefEdge>();
510 Iterator<RefEdge> itrYhrn = lnY.iteratorToReferencees();
511 while( itrYhrn.hasNext() ) {
512 RefEdge edgeY = itrYhrn.next();
513 HeapRegionNode hrnY = edgeY.getDst();
514 ReachSet betaY = edgeY.getBeta();
516 Iterator<RefEdge> itrHrnFhrn = hrnY.iteratorToReferencees();
518 while( itrHrnFhrn.hasNext() ) {
519 RefEdge edgeHrn = itrHrnFhrn.next();
520 HeapRegionNode hrnHrn = edgeHrn.getDst();
521 ReachSet betaHrn = edgeHrn.getBeta();
523 // prune edges that are not a matching field
524 if( edgeHrn.getType() != null &&
525 !edgeHrn.getField().equals(f.getSymbol() )
530 // check for impossible edges
531 if( !isSuperiorType(x.getType(), edgeHrn.getType() ) ) {
532 impossibleEdges.add(edgeHrn);
536 TypeDescriptor tdNewEdge =
537 mostSpecificType(edgeHrn.getType(),
541 TaintSet taints = Canonical.unionORpreds(edgeHrn.getTaints(),
545 // the DFJ way to generate taints changes for field statements
546 taints = Canonical.changeWhereDefined(taints,
547 currentProgramPoint);
550 RefEdge edgeNew = new RefEdge(lnX,
554 Canonical.intersection(betaY, betaHrn),
559 addEdgeOrMergeWithExisting(edgeNew);
563 Iterator<RefEdge> itrImp = impossibleEdges.iterator();
564 while( itrImp.hasNext() ) {
565 RefEdge edgeImp = itrImp.next();
566 removeRefEdge(edgeImp);
569 // anytime you might remove edges between heap regions
570 // you must global sweep to clean up broken reachability
571 if( !impossibleEdges.isEmpty() ) {
572 if( !DISABLE_GLOBAL_SWEEP ) {
580 // return whether a strong update was actually effected
581 public boolean assignTempXFieldFEqualToTempY(TempDescriptor x,
584 FlatNode currentProgramPoint,
585 Set<EdgeKey> edgeKeysRemoved
588 VariableNode lnX = getVariableNodeFromTemp(x);
589 VariableNode lnY = getVariableNodeFromTemp(y);
591 HashSet<HeapRegionNode> nodesWithNewAlpha = new HashSet<HeapRegionNode>();
592 HashSet<RefEdge> edgesWithNewBeta = new HashSet<RefEdge>();
594 // note it is possible that the types of temps in the
595 // flat node to analyze will reveal that some typed
596 // edges in the reachability graph are impossible
597 Set<RefEdge> impossibleEdges = new HashSet<RefEdge>();
599 // first look for possible strong updates and remove those edges
600 boolean strongUpdateCond = false;
601 boolean edgeRemovedByStrongUpdate = false;
603 Iterator<RefEdge> itrXhrn = lnX.iteratorToReferencees();
604 while( itrXhrn.hasNext() ) {
605 RefEdge edgeX = itrXhrn.next();
606 HeapRegionNode hrnX = edgeX.getDst();
608 // we can do a strong update here if one of two cases holds
610 f != DisjointAnalysis.getArrayField(f.getType() ) &&
611 ( (hrnX.getNumReferencers() == 1) || // case 1
612 (hrnX.isSingleObject() && lnX.getNumReferencees() == 1) // case 2
615 if( !DISABLE_STRONG_UPDATES ) {
616 strongUpdateCond = true;
618 boolean atLeastOne = clearRefEdgesFrom(hrnX,
625 edgeRemovedByStrongUpdate = true;
631 // then do all token propagation
632 itrXhrn = lnX.iteratorToReferencees();
633 while( itrXhrn.hasNext() ) {
634 RefEdge edgeX = itrXhrn.next();
635 HeapRegionNode hrnX = edgeX.getDst();
636 ReachSet betaX = edgeX.getBeta();
637 ReachSet R = Canonical.intersection(hrnX.getAlpha(),
641 Iterator<RefEdge> itrYhrn = lnY.iteratorToReferencees();
642 while( itrYhrn.hasNext() ) {
643 RefEdge edgeY = itrYhrn.next();
644 HeapRegionNode hrnY = edgeY.getDst();
645 ReachSet O = edgeY.getBeta();
647 // check for impossible edges
648 if( !isSuperiorType(f.getType(), edgeY.getType() ) ) {
649 impossibleEdges.add(edgeY);
653 // propagate tokens over nodes starting from hrnSrc, and it will
654 // take care of propagating back up edges from any touched nodes
655 ChangeSet Cy = Canonical.unionUpArityToChangeSet(O, R);
656 propagateTokensOverNodes(hrnY, Cy, nodesWithNewAlpha, edgesWithNewBeta);
658 // then propagate back just up the edges from hrn
659 ChangeSet Cx = Canonical.unionUpArityToChangeSet(R, O);
660 HashSet<RefEdge> todoEdges = new HashSet<RefEdge>();
662 Hashtable<RefEdge, ChangeSet> edgePlannedChanges =
663 new Hashtable<RefEdge, ChangeSet>();
665 Iterator<RefEdge> referItr = hrnX.iteratorToReferencers();
666 while( referItr.hasNext() ) {
667 RefEdge edgeUpstream = referItr.next();
668 todoEdges.add(edgeUpstream);
669 edgePlannedChanges.put(edgeUpstream, Cx);
672 propagateTokensOverEdges(todoEdges,
679 // apply the updates to reachability
680 Iterator<HeapRegionNode> nodeItr = nodesWithNewAlpha.iterator();
681 while( nodeItr.hasNext() ) {
682 nodeItr.next().applyAlphaNew();
685 Iterator<RefEdge> edgeItr = edgesWithNewBeta.iterator();
686 while( edgeItr.hasNext() ) {
687 edgeItr.next().applyBetaNew();
691 // then go back through and add the new edges
692 itrXhrn = lnX.iteratorToReferencees();
693 while( itrXhrn.hasNext() ) {
694 RefEdge edgeX = itrXhrn.next();
695 HeapRegionNode hrnX = edgeX.getDst();
697 Iterator<RefEdge> itrYhrn = lnY.iteratorToReferencees();
698 while( itrYhrn.hasNext() ) {
699 RefEdge edgeY = itrYhrn.next();
700 HeapRegionNode hrnY = edgeY.getDst();
702 // skip impossible edges here, we already marked them
703 // when computing reachability propagations above
704 if( !isSuperiorType(f.getType(), edgeY.getType() ) ) {
708 // prepare the new reference edge hrnX.f -> hrnY
709 TypeDescriptor tdNewEdge =
710 mostSpecificType(y.getType(),
715 TaintSet taints = edgeY.getTaints();
718 // the DFJ way to generate taints changes for field statements
719 taints = Canonical.changeWhereDefined(taints,
720 currentProgramPoint);
728 Canonical.changePredsTo(
729 Canonical.pruneBy(edgeY.getBeta(),
738 addEdgeOrMergeWithExisting(edgeNew);
742 Iterator<RefEdge> itrImp = impossibleEdges.iterator();
743 while( itrImp.hasNext() ) {
744 RefEdge edgeImp = itrImp.next();
745 removeRefEdge(edgeImp);
748 // if there was a strong update, make sure to improve
749 // reachability with a global sweep
750 if( edgeRemovedByStrongUpdate || !impossibleEdges.isEmpty() ) {
751 if( !DISABLE_GLOBAL_SWEEP ) {
756 return edgeRemovedByStrongUpdate;
760 public void assignReturnEqualToTemp(TempDescriptor x) {
762 VariableNode lnR = getVariableNodeFromTemp(tdReturn);
763 VariableNode lnX = getVariableNodeFromTemp(x);
765 clearRefEdgesFrom(lnR, null, null, true);
767 Iterator<RefEdge> itrXhrn = lnX.iteratorToReferencees();
768 while( itrXhrn.hasNext() ) {
769 RefEdge edgeX = itrXhrn.next();
770 HeapRegionNode referencee = edgeX.getDst();
771 RefEdge edgeNew = edgeX.copy();
773 edgeNew.setTaints(Canonical.changePredsTo(edgeNew.getTaints(),
778 addRefEdge(lnR, referencee, edgeNew);
783 public void assignTempEqualToNewAlloc(TempDescriptor x,
790 // after the age operation the newest (or zero-ith oldest)
791 // node associated with the allocation site should have
792 // no references to it as if it were a newly allocated
794 Integer idNewest = as.getIthOldest(0);
795 HeapRegionNode hrnNewest = id2hrn.get(idNewest);
796 assert hrnNewest != null;
798 VariableNode lnX = getVariableNodeFromTemp(x);
799 clearRefEdgesFrom(lnX, null, null, true);
801 // make a new reference to allocated node
802 TypeDescriptor type = as.getType();
805 new RefEdge(lnX, // source
809 hrnNewest.getAlpha(), // beta
810 predsTrue, // predicates
811 TaintSet.factory() // taints
814 addRefEdge(lnX, hrnNewest, edgeNew);
818 // use the allocation site (unique to entire analysis) to
819 // locate the heap region nodes in this reachability graph
820 // that should be aged. The process models the allocation
821 // of new objects and collects all the oldest allocations
822 // in a summary node to allow for a finite analysis
824 // There is an additional property of this method. After
825 // running it on a particular reachability graph (many graphs
826 // may have heap regions related to the same allocation site)
827 // the heap region node objects in this reachability graph will be
828 // allocated. Therefore, after aging a graph for an allocation
829 // site, attempts to retrieve the heap region nodes using the
830 // integer id's contained in the allocation site should always
831 // return non-null heap regions.
832 public void age(AllocSite as) {
834 // keep track of allocation sites that are represented
835 // in this graph for efficiency with other operations
838 // if there is a k-th oldest node, it merges into
840 Integer idK = as.getOldest();
841 if( id2hrn.containsKey(idK) ) {
842 HeapRegionNode hrnK = id2hrn.get(idK);
844 // retrieve the summary node, or make it
846 HeapRegionNode hrnSummary = getSummaryNode(as, false);
848 mergeIntoSummary(hrnK, hrnSummary);
851 // move down the line of heap region nodes
852 // clobbering the ith and transferring all references
853 // to and from i-1 to node i.
854 for( int i = allocationDepth - 1; i > 0; --i ) {
856 // only do the transfer if the i-1 node exists
857 Integer idImin1th = as.getIthOldest(i - 1);
858 if( id2hrn.containsKey(idImin1th) ) {
859 HeapRegionNode hrnImin1 = id2hrn.get(idImin1th);
860 if( hrnImin1.isWiped() ) {
861 // there is no info on this node, just skip
865 // either retrieve or make target of transfer
866 HeapRegionNode hrnI = getIthNode(as, i, false);
868 transferOnto(hrnImin1, hrnI);
873 // as stated above, the newest node should have had its
874 // references moved over to the second oldest, so we wipe newest
875 // in preparation for being the new object to assign something to
876 HeapRegionNode hrn0 = getIthNode(as, 0, false);
879 // now tokens in reachability sets need to "age" also
880 Iterator itrAllHRNodes = id2hrn.entrySet().iterator();
881 while( itrAllHRNodes.hasNext() ) {
882 Map.Entry me = (Map.Entry)itrAllHRNodes.next();
883 HeapRegionNode hrnToAge = (HeapRegionNode) me.getValue();
885 ageTuplesFrom(as, hrnToAge);
887 Iterator<RefEdge> itrEdges = hrnToAge.iteratorToReferencers();
888 while( itrEdges.hasNext() ) {
889 ageTuplesFrom(as, itrEdges.next() );
894 // after tokens have been aged, reset newest node's reachability
895 // and a brand new node has a "true" predicate
896 hrn0.setAlpha( Canonical.changePredsTo( hrn0.getInherent(), predsTrue ) );
897 hrn0.setPreds( predsTrue);
901 // either retrieve or create the needed heap region node
902 protected HeapRegionNode getSummaryNode(AllocSite as,
907 idSummary = as.getSummaryShadow();
909 idSummary = as.getSummary();
912 HeapRegionNode hrnSummary = id2hrn.get(idSummary);
914 if( hrnSummary == null ) {
916 String strDesc = as.toStringForDOT()+"\\nsummary";
919 createNewHeapRegionNode(idSummary, // id or null to generate a new one
920 false, // single object?
922 false, // out-of-context?
923 as.getType(), // type
924 as, // allocation site
925 null, // inherent reach
926 null, // current reach
927 predsEmpty, // predicates
928 strDesc // description
935 // either retrieve or create the needed heap region node
936 protected HeapRegionNode getIthNode(AllocSite as,
942 idIth = as.getIthOldestShadow(i);
944 idIth = as.getIthOldest(i);
947 HeapRegionNode hrnIth = id2hrn.get(idIth);
949 if( hrnIth == null ) {
951 String strDesc = as.toStringForDOT()+"\\n"+i+" oldest";
953 hrnIth = createNewHeapRegionNode(idIth, // id or null to generate a new one
954 true, // single object?
956 false, // out-of-context?
957 as.getType(), // type
958 as, // allocation site
959 null, // inherent reach
960 null, // current reach
961 predsEmpty, // predicates
962 strDesc // description
970 protected void mergeIntoSummary(HeapRegionNode hrn,
971 HeapRegionNode hrnSummary) {
972 assert hrnSummary.isNewSummary();
974 // assert that these nodes belong to THIS graph
975 assert belongsToThis(hrn);
976 assert belongsToThis(hrnSummary);
978 assert hrn != hrnSummary;
980 // transfer references _from_ hrn over to hrnSummary
981 Iterator<RefEdge> itrReferencee = hrn.iteratorToReferencees();
982 while( itrReferencee.hasNext() ) {
983 RefEdge edge = itrReferencee.next();
984 RefEdge edgeMerged = edge.copy();
985 edgeMerged.setSrc(hrnSummary);
987 HeapRegionNode hrnReferencee = edge.getDst();
988 RefEdge edgeSummary =
989 hrnSummary.getReferenceTo(hrnReferencee,
994 if( edgeSummary == null ) {
995 // the merge is trivial, nothing to be done
996 addRefEdge(hrnSummary, hrnReferencee, edgeMerged);
999 // otherwise an edge from the referencer to hrnSummary exists already
1000 // and the edge referencer->hrn should be merged with it
1001 edgeSummary.setBeta(
1002 Canonical.unionORpreds(edgeMerged.getBeta(),
1003 edgeSummary.getBeta()
1006 edgeSummary.setPreds(
1007 Canonical.join(edgeMerged.getPreds(),
1008 edgeSummary.getPreds()
1014 // next transfer references _to_ hrn over to hrnSummary
1015 Iterator<RefEdge> itrReferencer = hrn.iteratorToReferencers();
1016 while( itrReferencer.hasNext() ) {
1017 RefEdge edge = itrReferencer.next();
1018 RefEdge edgeMerged = edge.copy();
1019 edgeMerged.setDst(hrnSummary);
1021 RefSrcNode onReferencer = edge.getSrc();
1022 RefEdge edgeSummary =
1023 onReferencer.getReferenceTo(hrnSummary,
1028 if( edgeSummary == null ) {
1029 // the merge is trivial, nothing to be done
1030 addRefEdge(onReferencer, hrnSummary, edgeMerged);
1033 // otherwise an edge from the referencer to alpha_S exists already
1034 // and the edge referencer->alpha_K should be merged with it
1035 edgeSummary.setBeta(
1036 Canonical.unionORpreds(edgeMerged.getBeta(),
1037 edgeSummary.getBeta()
1040 edgeSummary.setPreds(
1041 Canonical.join(edgeMerged.getPreds(),
1042 edgeSummary.getPreds()
1048 // then merge hrn reachability into hrnSummary
1049 hrnSummary.setAlpha(
1050 Canonical.unionORpreds(hrnSummary.getAlpha(),
1055 hrnSummary.setPreds(
1056 Canonical.join(hrnSummary.getPreds(),
1061 // and afterward, this node is gone
1066 protected void transferOnto(HeapRegionNode hrnA,
1067 HeapRegionNode hrnB) {
1069 assert belongsToThis(hrnA);
1070 assert belongsToThis(hrnB);
1071 assert hrnA != hrnB;
1073 // clear references in and out of node b?
1074 assert hrnB.isWiped();
1076 // copy each: (edge in and out of A) to B
1077 Iterator<RefEdge> itrReferencee = hrnA.iteratorToReferencees();
1078 while( itrReferencee.hasNext() ) {
1079 RefEdge edge = itrReferencee.next();
1080 HeapRegionNode hrnReferencee = edge.getDst();
1081 RefEdge edgeNew = edge.copy();
1082 edgeNew.setSrc(hrnB);
1083 edgeNew.setDst(hrnReferencee);
1085 addRefEdge(hrnB, hrnReferencee, edgeNew);
1088 Iterator<RefEdge> itrReferencer = hrnA.iteratorToReferencers();
1089 while( itrReferencer.hasNext() ) {
1090 RefEdge edge = itrReferencer.next();
1091 RefSrcNode rsnReferencer = edge.getSrc();
1092 RefEdge edgeNew = edge.copy();
1093 edgeNew.setSrc(rsnReferencer);
1094 edgeNew.setDst(hrnB);
1096 addRefEdge(rsnReferencer, hrnB, edgeNew);
1099 // replace hrnB reachability and preds with hrnA's
1100 hrnB.setAlpha(hrnA.getAlpha() );
1101 hrnB.setPreds(hrnA.getPreds() );
1103 // after transfer, wipe out source
1104 wipeOut(hrnA, true);
1108 // the purpose of this method is to conceptually "wipe out"
1109 // a heap region from the graph--purposefully not called REMOVE
1110 // because the node is still hanging around in the graph, just
1111 // not mechanically connected or have any reach or predicate
1112 // information on it anymore--lots of ops can use this
1113 protected void wipeOut(HeapRegionNode hrn,
1114 boolean wipeVariableReferences) {
1116 assert belongsToThis(hrn);
1118 clearRefEdgesFrom(hrn, null, null, true);
1120 if( wipeVariableReferences ) {
1121 clearRefEdgesTo(hrn, null, null, true);
1123 clearNonVarRefEdgesTo(hrn);
1126 hrn.setAlpha(rsetEmpty);
1127 hrn.setPreds(predsEmpty);
1131 protected void ageTuplesFrom(AllocSite as, RefEdge edge) {
1133 Canonical.ageTuplesFrom(edge.getBeta(),
1139 protected void ageTuplesFrom(AllocSite as, HeapRegionNode hrn) {
1141 Canonical.ageTuplesFrom(hrn.getAlpha(),
1149 protected void propagateTokensOverNodes(HeapRegionNode nPrime,
1151 HashSet<HeapRegionNode> nodesWithNewAlpha,
1152 HashSet<RefEdge> edgesWithNewBeta) {
1154 HashSet<HeapRegionNode> todoNodes
1155 = new HashSet<HeapRegionNode>();
1156 todoNodes.add(nPrime);
1158 HashSet<RefEdge> todoEdges
1159 = new HashSet<RefEdge>();
1161 Hashtable<HeapRegionNode, ChangeSet> nodePlannedChanges
1162 = new Hashtable<HeapRegionNode, ChangeSet>();
1163 nodePlannedChanges.put(nPrime, c0);
1165 Hashtable<RefEdge, ChangeSet> edgePlannedChanges
1166 = new Hashtable<RefEdge, ChangeSet>();
1168 // first propagate change sets everywhere they can go
1169 while( !todoNodes.isEmpty() ) {
1170 HeapRegionNode n = todoNodes.iterator().next();
1171 ChangeSet C = nodePlannedChanges.get(n);
1173 Iterator<RefEdge> referItr = n.iteratorToReferencers();
1174 while( referItr.hasNext() ) {
1175 RefEdge edge = referItr.next();
1176 todoEdges.add(edge);
1178 if( !edgePlannedChanges.containsKey(edge) ) {
1179 edgePlannedChanges.put(edge,
1184 edgePlannedChanges.put(edge,
1185 Canonical.union(edgePlannedChanges.get(edge),
1191 Iterator<RefEdge> refeeItr = n.iteratorToReferencees();
1192 while( refeeItr.hasNext() ) {
1193 RefEdge edgeF = refeeItr.next();
1194 HeapRegionNode m = edgeF.getDst();
1196 ChangeSet changesToPass = ChangeSet.factory();
1198 Iterator<ChangeTuple> itrCprime = C.iterator();
1199 while( itrCprime.hasNext() ) {
1200 ChangeTuple c = itrCprime.next();
1201 if( edgeF.getBeta().containsIgnorePreds(c.getStateToMatch() )
1204 changesToPass = Canonical.add(changesToPass, c);
1208 if( !changesToPass.isEmpty() ) {
1209 if( !nodePlannedChanges.containsKey(m) ) {
1210 nodePlannedChanges.put(m, ChangeSet.factory() );
1213 ChangeSet currentChanges = nodePlannedChanges.get(m);
1215 if( !changesToPass.isSubset(currentChanges) ) {
1217 nodePlannedChanges.put(m,
1218 Canonical.union(currentChanges,
1227 todoNodes.remove(n);
1230 // then apply all of the changes for each node at once
1231 Iterator itrMap = nodePlannedChanges.entrySet().iterator();
1232 while( itrMap.hasNext() ) {
1233 Map.Entry me = (Map.Entry)itrMap.next();
1234 HeapRegionNode n = (HeapRegionNode) me.getKey();
1235 ChangeSet C = (ChangeSet) me.getValue();
1237 // this propagation step is with respect to one change,
1238 // so we capture the full change from the old alpha:
1239 ReachSet localDelta = Canonical.applyChangeSet(n.getAlpha(),
1243 // but this propagation may be only one of many concurrent
1244 // possible changes, so keep a running union with the node's
1245 // partially updated new alpha set
1246 n.setAlphaNew(Canonical.unionORpreds(n.getAlphaNew(),
1251 nodesWithNewAlpha.add(n);
1254 propagateTokensOverEdges(todoEdges,
1261 protected void propagateTokensOverEdges(HashSet <RefEdge> todoEdges,
1262 Hashtable<RefEdge, ChangeSet> edgePlannedChanges,
1263 HashSet <RefEdge> edgesWithNewBeta) {
1265 // first propagate all change tuples everywhere they can go
1266 while( !todoEdges.isEmpty() ) {
1267 RefEdge edgeE = todoEdges.iterator().next();
1268 todoEdges.remove(edgeE);
1270 if( !edgePlannedChanges.containsKey(edgeE) ) {
1271 edgePlannedChanges.put(edgeE,
1276 ChangeSet C = edgePlannedChanges.get(edgeE);
1278 ChangeSet changesToPass = ChangeSet.factory();
1280 Iterator<ChangeTuple> itrC = C.iterator();
1281 while( itrC.hasNext() ) {
1282 ChangeTuple c = itrC.next();
1283 if( edgeE.getBeta().containsIgnorePreds(c.getStateToMatch() )
1286 changesToPass = Canonical.add(changesToPass, c);
1290 RefSrcNode rsn = edgeE.getSrc();
1292 if( !changesToPass.isEmpty() && rsn instanceof HeapRegionNode ) {
1293 HeapRegionNode n = (HeapRegionNode) rsn;
1295 Iterator<RefEdge> referItr = n.iteratorToReferencers();
1296 while( referItr.hasNext() ) {
1297 RefEdge edgeF = referItr.next();
1299 if( !edgePlannedChanges.containsKey(edgeF) ) {
1300 edgePlannedChanges.put(edgeF,
1305 ChangeSet currentChanges = edgePlannedChanges.get(edgeF);
1307 if( !changesToPass.isSubset(currentChanges) ) {
1308 todoEdges.add(edgeF);
1309 edgePlannedChanges.put(edgeF,
1310 Canonical.union(currentChanges,
1319 // then apply all of the changes for each edge at once
1320 Iterator itrMap = edgePlannedChanges.entrySet().iterator();
1321 while( itrMap.hasNext() ) {
1322 Map.Entry me = (Map.Entry)itrMap.next();
1323 RefEdge e = (RefEdge) me.getKey();
1324 ChangeSet C = (ChangeSet) me.getValue();
1326 // this propagation step is with respect to one change,
1327 // so we capture the full change from the old beta:
1328 ReachSet localDelta =
1329 Canonical.applyChangeSet(e.getBeta(),
1334 // but this propagation may be only one of many concurrent
1335 // possible changes, so keep a running union with the edge's
1336 // partially updated new beta set
1337 e.setBetaNew(Canonical.unionORpreds(e.getBetaNew(),
1342 edgesWithNewBeta.add(e);
1347 public void taintInSetVars(FlatSESEEnterNode sese) {
1349 Iterator<TempDescriptor> isvItr = sese.getInVarSet().iterator();
1350 while( isvItr.hasNext() ) {
1351 TempDescriptor isv = isvItr.next();
1353 // use this where defined flatnode to support RCR/DFJ
1354 FlatNode whereDefined = null;
1356 // in-set var taints should NOT propagate back into callers
1357 // so give it FALSE(EMPTY) predicates
1367 public void taintStallSite(FlatNode stallSite,
1368 TempDescriptor var) {
1370 // use this where defined flatnode to support RCR/DFJ
1371 FlatNode whereDefined = null;
1373 // stall site taint should propagate back into callers
1374 // so give it TRUE predicates
1383 protected void taintTemp(FlatSESEEnterNode sese,
1386 FlatNode whereDefined,
1390 VariableNode vn = getVariableNodeFromTemp(var);
1392 Iterator<RefEdge> reItr = vn.iteratorToReferencees();
1393 while( reItr.hasNext() ) {
1394 RefEdge re = reItr.next();
1396 Taint taint = Taint.factory(sese,
1399 re.getDst().getAllocSite(),
1404 re.setTaints(Canonical.add(re.getTaints(),
1411 public void removeInContextTaints(FlatSESEEnterNode sese) {
1413 Iterator meItr = id2hrn.entrySet().iterator();
1414 while( meItr.hasNext() ) {
1415 Map.Entry me = (Map.Entry)meItr.next();
1416 Integer id = (Integer) me.getKey();
1417 HeapRegionNode hrn = (HeapRegionNode) me.getValue();
1419 Iterator<RefEdge> reItr = hrn.iteratorToReferencers();
1420 while( reItr.hasNext() ) {
1421 RefEdge re = reItr.next();
1423 re.setTaints(Canonical.removeInContextTaints(re.getTaints(),
1431 public void removeAllStallSiteTaints() {
1433 Iterator meItr = id2hrn.entrySet().iterator();
1434 while( meItr.hasNext() ) {
1435 Map.Entry me = (Map.Entry)meItr.next();
1436 Integer id = (Integer) me.getKey();
1437 HeapRegionNode hrn = (HeapRegionNode) me.getValue();
1439 Iterator<RefEdge> reItr = hrn.iteratorToReferencers();
1440 while( reItr.hasNext() ) {
1441 RefEdge re = reItr.next();
1443 re.setTaints(Canonical.removeStallSiteTaints(re.getTaints()
1451 // used in makeCalleeView below to decide if there is
1452 // already an appropriate out-of-context edge in a callee
1453 // view graph for merging, or null if a new one will be added
1455 getOutOfContextReferenceTo(HeapRegionNode hrn,
1456 TypeDescriptor srcType,
1457 TypeDescriptor refType,
1459 assert belongsToThis(hrn);
1461 HeapRegionNode hrnInContext = id2hrn.get(hrn.getID() );
1462 if( hrnInContext == null ) {
1466 Iterator<RefEdge> refItr = hrnInContext.iteratorToReferencers();
1467 while( refItr.hasNext() ) {
1468 RefEdge re = refItr.next();
1470 assert belongsToThis(re.getSrc() );
1471 assert belongsToThis(re.getDst() );
1473 if( !(re.getSrc() instanceof HeapRegionNode) ) {
1477 HeapRegionNode hrnSrc = (HeapRegionNode) re.getSrc();
1478 if( !hrnSrc.isOutOfContext() ) {
1482 if( srcType == null ) {
1483 if( hrnSrc.getType() != null ) {
1487 if( !srcType.equals(hrnSrc.getType() ) ) {
1492 if( !re.typeEquals(refType) ) {
1496 if( !re.fieldEquals(refField) ) {
1500 // tada! We found it!
1507 // used below to convert a ReachSet to its callee-context
1508 // equivalent with respect to allocation sites in this graph
1509 protected ReachSet toCalleeContext(ReachSet rs,
1510 ExistPredSet predsNodeOrEdge,
1511 Set<HrnIdOoc> oocHrnIdOoc2callee
1513 ReachSet out = ReachSet.factory();
1515 Iterator<ReachState> itr = rs.iterator();
1516 while( itr.hasNext() ) {
1517 ReachState stateCaller = itr.next();
1519 ReachState stateCallee = stateCaller;
1521 Iterator<AllocSite> asItr = allocSites.iterator();
1522 while( asItr.hasNext() ) {
1523 AllocSite as = asItr.next();
1525 ReachState stateNew = ReachState.factory();
1526 Iterator<ReachTuple> rtItr = stateCallee.iterator();
1527 while( rtItr.hasNext() ) {
1528 ReachTuple rt = rtItr.next();
1530 // only translate this tuple if it is
1531 // in the out-callee-context bag
1532 HrnIdOoc hio = new HrnIdOoc(rt.getHrnID(),
1535 if( !oocHrnIdOoc2callee.contains(hio) ) {
1536 stateNew = Canonical.addUpArity(stateNew, rt);
1540 int age = as.getAgeCategory(rt.getHrnID() );
1542 // this is the current mapping, where 0, 1, 2S were allocated
1543 // in the current context, 0?, 1? and 2S? were allocated in a
1544 // previous context, and we're translating to a future context
1556 if( age == AllocSite.AGE_notInThisSite ) {
1557 // things not from the site just go back in
1558 stateNew = Canonical.addUpArity(stateNew, rt);
1560 } else if( age == AllocSite.AGE_summary ||
1564 stateNew = Canonical.addUpArity(stateNew,
1565 ReachTuple.factory(as.getSummary(),
1568 true // out-of-context
1573 // otherwise everything else just goes to an out-of-context
1574 // version, everything else the same
1575 Integer I = as.getAge(rt.getHrnID() );
1578 assert !rt.isMultiObject();
1580 stateNew = Canonical.addUpArity(stateNew,
1581 ReachTuple.factory(rt.getHrnID(),
1582 rt.isMultiObject(), // multi
1584 true // out-of-context
1590 stateCallee = stateNew;
1593 // make a predicate of the caller graph element
1594 // and the caller state we just converted
1595 ExistPredSet predsWithState = ExistPredSet.factory();
1597 Iterator<ExistPred> predItr = predsNodeOrEdge.iterator();
1598 while( predItr.hasNext() ) {
1599 ExistPred predNodeOrEdge = predItr.next();
1602 Canonical.add(predsWithState,
1603 ExistPred.factory(predNodeOrEdge.n_hrnID,
1604 predNodeOrEdge.e_tdSrc,
1605 predNodeOrEdge.e_hrnSrcID,
1606 predNodeOrEdge.e_hrnDstID,
1607 predNodeOrEdge.e_type,
1608 predNodeOrEdge.e_field,
1611 predNodeOrEdge.e_srcOutCalleeContext,
1612 predNodeOrEdge.e_srcOutCallerContext
1617 stateCallee = Canonical.changePredsTo(stateCallee,
1620 out = Canonical.add(out,
1624 assert out.isCanonical();
1628 // used below to convert a ReachSet to its caller-context
1629 // equivalent with respect to allocation sites in this graph
1631 toCallerContext(ReachSet rs,
1632 Hashtable<ReachState, ExistPredSet> calleeStatesSatisfied
1634 ReachSet out = ReachSet.factory();
1636 // when the mapping is null it means there were no
1637 // predicates satisfied
1638 if( calleeStatesSatisfied == null ) {
1642 Iterator<ReachState> itr = rs.iterator();
1643 while( itr.hasNext() ) {
1644 ReachState stateCallee = itr.next();
1646 if( calleeStatesSatisfied.containsKey(stateCallee) ) {
1648 // starting from one callee state...
1649 ReachSet rsCaller = ReachSet.factory(stateCallee);
1651 // possibly branch it into many states, which any
1652 // allocation site might do, so lots of derived states
1653 Iterator<AllocSite> asItr = allocSites.iterator();
1654 while( asItr.hasNext() ) {
1655 AllocSite as = asItr.next();
1656 rsCaller = Canonical.toCallerContext(rsCaller, as);
1659 // then before adding each derived, now caller-context
1660 // states to the output, attach the appropriate pred
1661 // based on the source callee state
1662 Iterator<ReachState> stateItr = rsCaller.iterator();
1663 while( stateItr.hasNext() ) {
1664 ReachState stateCaller = stateItr.next();
1665 stateCaller = Canonical.attach(stateCaller,
1666 calleeStatesSatisfied.get(stateCallee)
1668 out = Canonical.add(out,
1675 assert out.isCanonical();
1680 // used below to convert a ReachSet to an equivalent
1681 // version with shadow IDs merged into unshadowed IDs
1682 protected ReachSet unshadow(ReachSet rs) {
1684 Iterator<AllocSite> asItr = allocSites.iterator();
1685 while( asItr.hasNext() ) {
1686 AllocSite as = asItr.next();
1687 out = Canonical.unshadow(out, as);
1689 assert out.isCanonical();
1694 // convert a caller taint set into a callee taint set
1696 toCalleeContext(TaintSet ts,
1697 ExistPredSet predsEdge) {
1699 TaintSet out = TaintSet.factory();
1701 // the idea is easy, the taint identifier itself doesn't
1702 // change at all, but the predicates should be tautology:
1703 // start with the preds passed in from the caller edge
1704 // that host the taints, and alter them to have the taint
1705 // added, just becoming more specific than edge predicate alone
1707 Iterator<Taint> itr = ts.iterator();
1708 while( itr.hasNext() ) {
1709 Taint tCaller = itr.next();
1711 ExistPredSet predsWithTaint = ExistPredSet.factory();
1713 Iterator<ExistPred> predItr = predsEdge.iterator();
1714 while( predItr.hasNext() ) {
1715 ExistPred predEdge = predItr.next();
1718 Canonical.add(predsWithTaint,
1719 ExistPred.factory(predEdge.e_tdSrc,
1720 predEdge.e_hrnSrcID,
1721 predEdge.e_hrnDstID,
1726 predEdge.e_srcOutCalleeContext,
1727 predEdge.e_srcOutCallerContext
1732 Taint tCallee = Canonical.changePredsTo(tCaller,
1735 out = Canonical.add(out,
1740 assert out.isCanonical();
1745 // used below to convert a TaintSet to its caller-context
1746 // equivalent, just eliminate Taints with bad preds
1748 toCallerContext(TaintSet ts,
1749 Hashtable<Taint, ExistPredSet> calleeTaintsSatisfied
1752 TaintSet out = TaintSet.factory();
1754 // when the mapping is null it means there were no
1755 // predicates satisfied
1756 if( calleeTaintsSatisfied == null ) {
1760 Iterator<Taint> itr = ts.iterator();
1761 while( itr.hasNext() ) {
1762 Taint tCallee = itr.next();
1764 if( calleeTaintsSatisfied.containsKey(tCallee) ) {
1767 Canonical.attach(Taint.factory(tCallee.sese,
1772 ExistPredSet.factory() ),
1773 calleeTaintsSatisfied.get(tCallee)
1775 out = Canonical.add(out,
1781 assert out.isCanonical();
1788 // use this method to make a new reach graph that is
1789 // what heap the FlatMethod callee from the FlatCall
1790 // would start with reaching from its arguments in
1793 makeCalleeView(FlatCall fc,
1794 FlatMethod fmCallee,
1795 Set<Integer> callerNodeIDsCopiedToCallee,
1796 boolean writeDebugDOTs
1800 // first traverse this context to find nodes and edges
1801 // that will be callee-reachable
1802 Set<HeapRegionNode> reachableCallerNodes =
1803 new HashSet<HeapRegionNode>();
1805 // caller edges between callee-reachable nodes
1806 Set<RefEdge> reachableCallerEdges =
1807 new HashSet<RefEdge>();
1809 // caller edges from arg vars, and the matching param index
1810 // because these become a special edge in callee
1811 // NOTE! One argument may be passed in as more than one parameter,
1812 // so map to a set of parameter indices!
1813 Hashtable< RefEdge, Set<Integer> > reachableCallerArgEdges2paramIndices =
1814 new Hashtable< RefEdge, Set<Integer> >();
1816 // caller edges from local vars or callee-unreachable nodes
1817 // (out-of-context sources) to callee-reachable nodes
1818 Set<RefEdge> oocCallerEdges =
1819 new HashSet<RefEdge>();
1822 for( int i = 0; i < fmCallee.numParameters(); ++i ) {
1824 TempDescriptor tdArg = fc.getArgMatchingParamIndex(fmCallee, i);
1825 VariableNode vnArgCaller = this.getVariableNodeFromTemp(tdArg);
1827 Set<RefSrcNode> toVisitInCaller = new HashSet<RefSrcNode>();
1828 Set<RefSrcNode> visitedInCaller = new HashSet<RefSrcNode>();
1830 toVisitInCaller.add(vnArgCaller);
1832 while( !toVisitInCaller.isEmpty() ) {
1833 RefSrcNode rsnCaller = toVisitInCaller.iterator().next();
1834 toVisitInCaller.remove(rsnCaller);
1835 visitedInCaller.add(rsnCaller);
1837 Iterator<RefEdge> itrRefEdges = rsnCaller.iteratorToReferencees();
1838 while( itrRefEdges.hasNext() ) {
1839 RefEdge reCaller = itrRefEdges.next();
1840 HeapRegionNode hrnCaller = reCaller.getDst();
1842 callerNodeIDsCopiedToCallee.add(hrnCaller.getID() );
1843 reachableCallerNodes.add(hrnCaller);
1845 if( reCaller.getSrc() instanceof HeapRegionNode ) {
1846 reachableCallerEdges.add(reCaller);
1849 if( rsnCaller.equals(vnArgCaller) ) {
1850 Set<Integer> pIndices =
1851 reachableCallerArgEdges2paramIndices.get( reCaller );
1853 if( pIndices == null ) {
1854 pIndices = new HashSet<Integer>();
1855 reachableCallerArgEdges2paramIndices.put( reCaller, pIndices );
1860 oocCallerEdges.add(reCaller);
1864 if( !visitedInCaller.contains(hrnCaller) ) {
1865 toVisitInCaller.add(hrnCaller);
1868 } // end edge iteration
1869 } // end visiting heap nodes in caller
1870 } // end iterating over parameters as starting points
1874 // now collect out-of-callee-context IDs and
1875 // map them to whether the ID is out of the caller
1877 Set<HrnIdOoc> oocHrnIdOoc2callee = new HashSet<HrnIdOoc>();
1879 Iterator<Integer> itrInContext =
1880 callerNodeIDsCopiedToCallee.iterator();
1881 while( itrInContext.hasNext() ) {
1882 Integer hrnID = itrInContext.next();
1883 HeapRegionNode hrnCallerAndInContext = id2hrn.get(hrnID);
1885 Iterator<RefEdge> itrMightCross =
1886 hrnCallerAndInContext.iteratorToReferencers();
1887 while( itrMightCross.hasNext() ) {
1888 RefEdge edgeMightCross = itrMightCross.next();
1890 RefSrcNode rsnCallerAndOutContext =
1891 edgeMightCross.getSrc();
1893 if( rsnCallerAndOutContext instanceof VariableNode ) {
1894 // variables do not have out-of-context reach states,
1896 oocCallerEdges.add(edgeMightCross);
1900 HeapRegionNode hrnCallerAndOutContext =
1901 (HeapRegionNode) rsnCallerAndOutContext;
1903 // is this source node out-of-context?
1904 if( callerNodeIDsCopiedToCallee.contains(hrnCallerAndOutContext.getID() ) ) {
1905 // no, skip this edge
1910 oocCallerEdges.add(edgeMightCross);
1912 // add all reach tuples on the node to list
1913 // of things that are out-of-context: insight
1914 // if this node is reachable from someting that WAS
1915 // in-context, then this node should already be in-context
1916 Iterator<ReachState> stateItr = hrnCallerAndOutContext.getAlpha().iterator();
1917 while( stateItr.hasNext() ) {
1918 ReachState state = stateItr.next();
1920 Iterator<ReachTuple> rtItr = state.iterator();
1921 while( rtItr.hasNext() ) {
1922 ReachTuple rt = rtItr.next();
1924 oocHrnIdOoc2callee.add(new HrnIdOoc(rt.getHrnID(),
1933 // the callee view is a new graph: DON'T MODIFY *THIS* graph
1934 ReachGraph rg = new ReachGraph();
1936 // add nodes to callee graph
1937 Iterator<HeapRegionNode> hrnItr = reachableCallerNodes.iterator();
1938 while( hrnItr.hasNext() ) {
1939 HeapRegionNode hrnCaller = hrnItr.next();
1941 assert callerNodeIDsCopiedToCallee.contains(hrnCaller.getID() );
1942 assert !rg.id2hrn.containsKey(hrnCaller.getID() );
1944 ExistPred pred = ExistPred.factory(hrnCaller.getID(), null);
1945 ExistPredSet preds = ExistPredSet.factory(pred);
1947 rg.createNewHeapRegionNode(hrnCaller.getID(),
1948 hrnCaller.isSingleObject(),
1949 hrnCaller.isNewSummary(),
1950 false, // out-of-context?
1951 hrnCaller.getType(),
1952 hrnCaller.getAllocSite(),
1953 toCalleeContext(hrnCaller.getInherent(),
1957 toCalleeContext(hrnCaller.getAlpha(),
1962 hrnCaller.getDescription()
1966 // add param edges to callee graph
1968 reachableCallerArgEdges2paramIndices.entrySet().iterator();
1969 while( argEdges.hasNext() ) {
1970 Map.Entry me = (Map.Entry) argEdges.next();
1971 RefEdge reArg = (RefEdge) me.getKey();
1972 Set<Integer> pInxs = (Set<Integer>) me.getValue();
1974 VariableNode vnCaller = (VariableNode) reArg.getSrc();
1975 TempDescriptor argCaller = vnCaller.getTempDescriptor();
1977 HeapRegionNode hrnDstCaller = reArg.getDst();
1978 HeapRegionNode hrnDstCallee = rg.id2hrn.get(hrnDstCaller.getID() );
1979 assert hrnDstCallee != null;
1982 ExistPred.factory(argCaller,
1984 hrnDstCallee.getID(),
1989 true, // out-of-callee-context
1990 false // out-of-caller-context
1993 ExistPredSet preds =
1994 ExistPredSet.factory(pred);
1996 for( Integer index: pInxs ) {
1998 TempDescriptor paramCallee = fmCallee.getParameter(index);
1999 VariableNode vnCallee = rg.getVariableNodeFromTemp(paramCallee);
2002 new RefEdge(vnCallee,
2006 toCalleeContext(reArg.getBeta(),
2011 toCalleeContext(reArg.getTaints(),
2015 rg.addRefEdge(vnCallee,
2022 // add in-context edges to callee graph
2023 Iterator<RefEdge> reItr = reachableCallerEdges.iterator();
2024 while( reItr.hasNext() ) {
2025 RefEdge reCaller = reItr.next();
2026 RefSrcNode rsnCaller = reCaller.getSrc();
2027 assert rsnCaller instanceof HeapRegionNode;
2028 HeapRegionNode hrnSrcCaller = (HeapRegionNode) rsnCaller;
2029 HeapRegionNode hrnDstCaller = reCaller.getDst();
2031 HeapRegionNode hrnSrcCallee = rg.id2hrn.get(hrnSrcCaller.getID() );
2032 HeapRegionNode hrnDstCallee = rg.id2hrn.get(hrnDstCaller.getID() );
2033 assert hrnSrcCallee != null;
2034 assert hrnDstCallee != null;
2037 ExistPred.factory(null,
2038 hrnSrcCallee.getID(),
2039 hrnDstCallee.getID(),
2041 reCaller.getField(),
2044 false, // out-of-callee-context
2045 false // out-of-caller-context
2048 ExistPredSet preds =
2049 ExistPredSet.factory(pred);
2052 new RefEdge(hrnSrcCallee,
2055 reCaller.getField(),
2056 toCalleeContext(reCaller.getBeta(),
2061 toCalleeContext(reCaller.getTaints(),
2065 rg.addRefEdge(hrnSrcCallee,
2071 // add out-of-context edges to callee graph
2072 reItr = oocCallerEdges.iterator();
2073 while( reItr.hasNext() ) {
2074 RefEdge reCaller = reItr.next();
2075 RefSrcNode rsnCaller = reCaller.getSrc();
2076 HeapRegionNode hrnDstCaller = reCaller.getDst();
2077 HeapRegionNode hrnDstCallee = rg.id2hrn.get(hrnDstCaller.getID() );
2078 assert hrnDstCallee != null;
2080 TypeDescriptor oocNodeType;
2082 TempDescriptor oocPredSrcTemp = null;
2083 Integer oocPredSrcID = null;
2084 boolean outOfCalleeContext;
2085 boolean outOfCallerContext;
2087 if( rsnCaller instanceof VariableNode ) {
2088 VariableNode vnCaller = (VariableNode) rsnCaller;
2090 oocReach = rsetEmpty;
2091 oocPredSrcTemp = vnCaller.getTempDescriptor();
2092 outOfCalleeContext = true;
2093 outOfCallerContext = false;
2096 HeapRegionNode hrnSrcCaller = (HeapRegionNode) rsnCaller;
2097 assert !callerNodeIDsCopiedToCallee.contains(hrnSrcCaller.getID() );
2098 oocNodeType = hrnSrcCaller.getType();
2099 oocReach = hrnSrcCaller.getAlpha();
2100 oocPredSrcID = hrnSrcCaller.getID();
2101 if( hrnSrcCaller.isOutOfContext() ) {
2102 outOfCalleeContext = false;
2103 outOfCallerContext = true;
2105 outOfCalleeContext = true;
2106 outOfCallerContext = false;
2111 ExistPred.factory(oocPredSrcTemp,
2113 hrnDstCallee.getID(),
2115 reCaller.getField(),
2122 ExistPredSet preds =
2123 ExistPredSet.factory(pred);
2125 RefEdge oocEdgeExisting =
2126 rg.getOutOfContextReferenceTo(hrnDstCallee,
2132 if( oocEdgeExisting == null ) {
2133 // for consistency, map one out-of-context "identifier"
2134 // to one heap region node id, otherwise no convergence
2135 String oocid = "oocid"+
2137 hrnDstCallee.getIDString()+
2140 reCaller.getField();
2142 Integer oocHrnID = oocid2hrnid.get(oocid);
2144 HeapRegionNode hrnCalleeAndOutContext;
2146 if( oocHrnID == null ) {
2148 hrnCalleeAndOutContext =
2149 rg.createNewHeapRegionNode(null, // ID
2150 false, // single object?
2151 false, // new summary?
2152 true, // out-of-context?
2154 null, // alloc site, shouldn't be used
2155 toCalleeContext(oocReach,
2159 toCalleeContext(oocReach,
2167 oocid2hrnid.put(oocid, hrnCalleeAndOutContext.getID() );
2171 // the mapping already exists, so see if node is there
2172 hrnCalleeAndOutContext = rg.id2hrn.get(oocHrnID);
2174 if( hrnCalleeAndOutContext == null ) {
2176 hrnCalleeAndOutContext =
2177 rg.createNewHeapRegionNode(oocHrnID, // ID
2178 false, // single object?
2179 false, // new summary?
2180 true, // out-of-context?
2182 null, // alloc site, shouldn't be used
2183 toCalleeContext(oocReach,
2187 toCalleeContext(oocReach,
2196 // otherwise it is there, so merge reachability
2197 hrnCalleeAndOutContext.setAlpha(Canonical.unionORpreds(hrnCalleeAndOutContext.getAlpha(),
2198 toCalleeContext(oocReach,
2207 assert hrnCalleeAndOutContext.reachHasOnlyOOC();
2209 rg.addRefEdge(hrnCalleeAndOutContext,
2211 new RefEdge(hrnCalleeAndOutContext,
2214 reCaller.getField(),
2215 toCalleeContext(reCaller.getBeta(),
2220 toCalleeContext(reCaller.getTaints(),
2226 // the out-of-context edge already exists
2227 oocEdgeExisting.setBeta(Canonical.unionORpreds(oocEdgeExisting.getBeta(),
2228 toCalleeContext(reCaller.getBeta(),
2235 oocEdgeExisting.setPreds(Canonical.join(oocEdgeExisting.getPreds(),
2240 oocEdgeExisting.setTaints(Canonical.unionORpreds(oocEdgeExisting.getTaints(),
2241 toCalleeContext(reCaller.getTaints(),
2247 HeapRegionNode hrnCalleeAndOutContext =
2248 (HeapRegionNode) oocEdgeExisting.getSrc();
2249 hrnCalleeAndOutContext.setAlpha(Canonical.unionORpreds(hrnCalleeAndOutContext.getAlpha(),
2250 toCalleeContext(oocReach,
2257 assert hrnCalleeAndOutContext.reachHasOnlyOOC();
2262 if( writeDebugDOTs ) {
2263 debugGraphPrefix = String.format("call%03d", debugCallSiteVisitCounter);
2264 rg.writeGraph(debugGraphPrefix+"calleeview",
2265 resolveMethodDebugDOTwriteLabels,
2266 resolveMethodDebugDOTselectTemps,
2267 resolveMethodDebugDOTpruneGarbage,
2268 resolveMethodDebugDOThideReach,
2269 resolveMethodDebugDOThideSubsetReach,
2270 resolveMethodDebugDOThidePreds,
2271 resolveMethodDebugDOThideEdgeTaints);
2277 private static Hashtable<String, Integer> oocid2hrnid =
2278 new Hashtable<String, Integer>();
2281 private static boolean resolveMethodDebugDOTwriteLabels = true;
2282 private static boolean resolveMethodDebugDOTselectTemps = true;
2283 private static boolean resolveMethodDebugDOTpruneGarbage = true;
2284 private static boolean resolveMethodDebugDOThideReach = false;
2285 private static boolean resolveMethodDebugDOThideSubsetReach = true;
2286 private static boolean resolveMethodDebugDOThidePreds = false;
2287 private static boolean resolveMethodDebugDOThideEdgeTaints = true;
2289 static String debugGraphPrefix;
2290 static int debugCallSiteVisitCounter;
2291 static int debugCallSiteVisitStartCapture;
2292 static int debugCallSiteNumVisitsToCapture;
2293 static boolean debugCallSiteStopAfter;
2297 resolveMethodCall(FlatCall fc,
2298 FlatMethod fmCallee,
2299 ReachGraph rgCallee,
2300 Set<Integer> callerNodeIDsCopiedToCallee,
2301 boolean writeDebugDOTs
2304 if( writeDebugDOTs ) {
2306 System.out.println(" Writing out visit "+
2307 debugCallSiteVisitCounter+
2308 " to debug call site");
2310 debugGraphPrefix = String.format("call%03d",
2311 debugCallSiteVisitCounter);
2313 rgCallee.writeGraph(debugGraphPrefix+"callee",
2314 resolveMethodDebugDOTwriteLabels,
2315 resolveMethodDebugDOTselectTemps,
2316 resolveMethodDebugDOTpruneGarbage,
2317 resolveMethodDebugDOThideReach,
2318 resolveMethodDebugDOThideSubsetReach,
2319 resolveMethodDebugDOThidePreds,
2320 resolveMethodDebugDOThideEdgeTaints);
2322 writeGraph(debugGraphPrefix+"caller00In",
2323 resolveMethodDebugDOTwriteLabels,
2324 resolveMethodDebugDOTselectTemps,
2325 resolveMethodDebugDOTpruneGarbage,
2326 resolveMethodDebugDOThideReach,
2327 resolveMethodDebugDOThideSubsetReach,
2328 resolveMethodDebugDOThidePreds,
2329 resolveMethodDebugDOThideEdgeTaints,
2330 callerNodeIDsCopiedToCallee);
2335 // method call transfer function steps:
2336 // 1. Use current callee-reachable heap (CRH) to test callee
2337 // predicates and mark what will be coming in.
2338 // 2. Wipe CRH out of caller.
2339 // 3. Transplant marked callee parts in:
2340 // a) bring in nodes
2341 // b) bring in callee -> callee edges
2342 // c) resolve out-of-context -> callee edges
2343 // d) assign return value
2344 // 4. Collapse shadow nodes down
2345 // 5. Global sweep it.
2348 // 1. mark what callee elements have satisfied predicates
2349 Hashtable<HeapRegionNode, ExistPredSet> calleeNodesSatisfied =
2350 new Hashtable<HeapRegionNode, ExistPredSet>();
2352 Hashtable<RefEdge, ExistPredSet> calleeEdgesSatisfied =
2353 new Hashtable<RefEdge, ExistPredSet>();
2355 Hashtable< HeapRegionNode, Hashtable<ReachState, ExistPredSet> >
2356 calleeNode2calleeStatesSatisfied =
2357 new Hashtable< HeapRegionNode, Hashtable<ReachState, ExistPredSet> >();
2359 Hashtable< RefEdge, Hashtable<ReachState, ExistPredSet> >
2360 calleeEdge2calleeStatesSatisfied =
2361 new Hashtable< RefEdge, Hashtable<ReachState, ExistPredSet> >();
2363 Hashtable< RefEdge, Hashtable<Taint, ExistPredSet> >
2364 calleeEdge2calleeTaintsSatisfied =
2365 new Hashtable< RefEdge, Hashtable<Taint, ExistPredSet> >();
2367 Hashtable< RefEdge, Set<RefSrcNode> > calleeEdges2oocCallerSrcMatches =
2368 new Hashtable< RefEdge, Set<RefSrcNode> >();
2372 Iterator meItr = rgCallee.id2hrn.entrySet().iterator();
2373 while( meItr.hasNext() ) {
2374 Map.Entry me = (Map.Entry)meItr.next();
2375 Integer id = (Integer) me.getKey();
2376 HeapRegionNode hrnCallee = (HeapRegionNode) me.getValue();
2378 // if a callee element's predicates are satisfied then a set
2379 // of CALLER predicates is returned: they are the predicates
2380 // that the callee element moved into the caller context
2381 // should have, and it is inefficient to find this again later
2382 ExistPredSet predsIfSatis =
2383 hrnCallee.getPreds().isSatisfiedBy(this,
2384 callerNodeIDsCopiedToCallee,
2387 if( predsIfSatis != null ) {
2388 calleeNodesSatisfied.put(hrnCallee, predsIfSatis);
2390 // otherwise don't bother looking at edges to this node
2396 // since the node is coming over, find out which reach
2397 // states on it should come over, too
2398 assert calleeNode2calleeStatesSatisfied.get(hrnCallee) == null;
2400 Iterator<ReachState> stateItr = hrnCallee.getAlpha().iterator();
2401 while( stateItr.hasNext() ) {
2402 ReachState stateCallee = stateItr.next();
2405 stateCallee.getPreds().isSatisfiedBy(this,
2406 callerNodeIDsCopiedToCallee,
2408 if( predsIfSatis != null ) {
2410 Hashtable<ReachState, ExistPredSet> calleeStatesSatisfied =
2411 calleeNode2calleeStatesSatisfied.get(hrnCallee);
2413 if( calleeStatesSatisfied == null ) {
2414 calleeStatesSatisfied =
2415 new Hashtable<ReachState, ExistPredSet>();
2417 calleeNode2calleeStatesSatisfied.put(hrnCallee, calleeStatesSatisfied);
2420 calleeStatesSatisfied.put(stateCallee, predsIfSatis);
2424 // then look at edges to the node
2425 Iterator<RefEdge> reItr = hrnCallee.iteratorToReferencers();
2426 while( reItr.hasNext() ) {
2427 RefEdge reCallee = reItr.next();
2428 RefSrcNode rsnCallee = reCallee.getSrc();
2430 // (caller local variables to in-context heap regions)
2431 // have an (out-of-context heap region -> in-context heap region)
2432 // abstraction in the callEE, so its true we never need to
2433 // look at a (var node -> heap region) edge in callee to bring
2434 // those over for the call site transfer, except for the special
2435 // case of *RETURN var* -> heap region edges.
2436 // What about (param var->heap region)
2437 // edges in callee? They are dealt with below this loop.
2439 if( rsnCallee instanceof VariableNode ) {
2441 // looking for the return-value variable only
2442 VariableNode vnCallee = (VariableNode) rsnCallee;
2443 if( vnCallee.getTempDescriptor() != tdReturn ) {
2447 TempDescriptor returnTemp = fc.getReturnTemp();
2448 if( returnTemp == null ||
2449 !DisjointAnalysis.shouldAnalysisTrack(returnTemp.getType() )
2454 // note that the assignment of the return value is to a
2455 // variable in the caller which is out-of-context with
2456 // respect to the callee
2457 VariableNode vnLhsCaller = getVariableNodeFromTemp(returnTemp);
2458 Set<RefSrcNode> rsnCallers = new HashSet<RefSrcNode>();
2459 rsnCallers.add(vnLhsCaller);
2460 calleeEdges2oocCallerSrcMatches.put(reCallee, rsnCallers);
2464 // for HeapRegionNode callee sources...
2466 // first see if the source is out-of-context, and only
2467 // proceed with this edge if we find some caller-context
2469 HeapRegionNode hrnSrcCallee = (HeapRegionNode) rsnCallee;
2470 boolean matchedOutOfContext = false;
2472 if( !hrnSrcCallee.isOutOfContext() ) {
2475 hrnSrcCallee.getPreds().isSatisfiedBy(this,
2476 callerNodeIDsCopiedToCallee,
2478 if( predsIfSatis != null ) {
2479 calleeNodesSatisfied.put(hrnSrcCallee, predsIfSatis);
2481 // otherwise forget this edge
2486 // hrnSrcCallee is out-of-context
2487 assert !calleeEdges2oocCallerSrcMatches.containsKey(reCallee);
2489 Set<RefSrcNode> rsnCallers = new HashSet<RefSrcNode>();
2491 // use the isSatisfiedBy with a non-null callers set to capture
2492 // nodes in the caller that match the predicates
2493 reCallee.getPreds().isSatisfiedBy( this,
2494 callerNodeIDsCopiedToCallee,
2497 if( !rsnCallers.isEmpty() ) {
2498 matchedOutOfContext = true;
2499 calleeEdges2oocCallerSrcMatches.put(reCallee, rsnCallers);
2503 if( hrnSrcCallee.isOutOfContext() &&
2504 !matchedOutOfContext ) {
2511 reCallee.getPreds().isSatisfiedBy(this,
2512 callerNodeIDsCopiedToCallee,
2516 if( predsIfSatis != null ) {
2517 calleeEdgesSatisfied.put(reCallee, predsIfSatis);
2519 // since the edge is coming over, find out which reach
2520 // states on it should come over, too
2521 assert calleeEdge2calleeStatesSatisfied.get(reCallee) == null;
2523 stateItr = reCallee.getBeta().iterator();
2524 while( stateItr.hasNext() ) {
2525 ReachState stateCallee = stateItr.next();
2528 stateCallee.getPreds().isSatisfiedBy(this,
2529 callerNodeIDsCopiedToCallee,
2531 if( predsIfSatis != null ) {
2533 Hashtable<ReachState, ExistPredSet> calleeStatesSatisfied =
2534 calleeEdge2calleeStatesSatisfied.get(reCallee);
2536 if( calleeStatesSatisfied == null ) {
2537 calleeStatesSatisfied =
2538 new Hashtable<ReachState, ExistPredSet>();
2540 calleeEdge2calleeStatesSatisfied.put(reCallee, calleeStatesSatisfied);
2543 calleeStatesSatisfied.put(stateCallee, predsIfSatis);
2547 // since the edge is coming over, find out which taints
2548 // on it should come over, too
2549 assert calleeEdge2calleeTaintsSatisfied.get(reCallee) == null;
2551 Iterator<Taint> tItr = reCallee.getTaints().iterator();
2552 while( tItr.hasNext() ) {
2553 Taint tCallee = tItr.next();
2556 tCallee.getPreds().isSatisfiedBy(this,
2557 callerNodeIDsCopiedToCallee,
2559 if( predsIfSatis != null ) {
2561 Hashtable<Taint, ExistPredSet> calleeTaintsSatisfied =
2562 calleeEdge2calleeTaintsSatisfied.get(reCallee);
2564 if( calleeTaintsSatisfied == null ) {
2565 calleeTaintsSatisfied =
2566 new Hashtable<Taint, ExistPredSet>();
2568 calleeEdge2calleeTaintsSatisfied.put(reCallee, calleeTaintsSatisfied);
2571 calleeTaintsSatisfied.put(tCallee, predsIfSatis);
2578 if( writeDebugDOTs ) {
2579 writeGraph(debugGraphPrefix+"caller20BeforeWipe",
2580 resolveMethodDebugDOTwriteLabels,
2581 resolveMethodDebugDOTselectTemps,
2582 resolveMethodDebugDOTpruneGarbage,
2583 resolveMethodDebugDOThideReach,
2584 resolveMethodDebugDOThideSubsetReach,
2585 resolveMethodDebugDOThidePreds,
2586 resolveMethodDebugDOThideEdgeTaints);
2590 // 2. predicates tested, ok to wipe out caller part
2591 Iterator<Integer> hrnItr = callerNodeIDsCopiedToCallee.iterator();
2592 while( hrnItr.hasNext() ) {
2593 Integer hrnID = hrnItr.next();
2594 HeapRegionNode hrnCaller = id2hrn.get(hrnID);
2595 assert hrnCaller != null;
2597 // when clearing off nodes, also eliminate variable
2599 wipeOut(hrnCaller, true);
2602 // if we are assigning the return value to something, clobber now
2603 // as part of the wipe
2604 TempDescriptor returnTemp = fc.getReturnTemp();
2605 if( returnTemp != null &&
2606 DisjointAnalysis.shouldAnalysisTrack(returnTemp.getType() )
2609 VariableNode vnLhsCaller = getVariableNodeFromTemp(returnTemp);
2610 clearRefEdgesFrom(vnLhsCaller, null, null, true);
2616 if( writeDebugDOTs ) {
2617 writeGraph(debugGraphPrefix+"caller30BeforeAddingNodes",
2618 resolveMethodDebugDOTwriteLabels,
2619 resolveMethodDebugDOTselectTemps,
2620 resolveMethodDebugDOTpruneGarbage,
2621 resolveMethodDebugDOThideReach,
2622 resolveMethodDebugDOThideSubsetReach,
2623 resolveMethodDebugDOThidePreds,
2624 resolveMethodDebugDOThideEdgeTaints);
2630 // 3. callee elements with satisfied preds come in, note that
2631 // the mapping of elements satisfied to preds is like this:
2632 // A callee element EE has preds EEp that are satisfied by
2633 // some caller element ER. We bring EE into the caller
2634 // context as ERee with the preds of ER, namely ERp, which
2635 // in the following algorithm is the value in the mapping
2638 Iterator satisItr = calleeNodesSatisfied.entrySet().iterator();
2639 while( satisItr.hasNext() ) {
2640 Map.Entry me = (Map.Entry)satisItr.next();
2641 HeapRegionNode hrnCallee = (HeapRegionNode) me.getKey();
2642 ExistPredSet preds = (ExistPredSet) me.getValue();
2644 // TODO: I think its true that the current implementation uses
2645 // the type of the OOC region and the predicates OF THE EDGE from
2646 // it to link everything up in caller context, so that's why we're
2647 // skipping this... maybe that's a sillier way to do it?
2648 if( hrnCallee.isOutOfContext() ) {
2652 AllocSite as = hrnCallee.getAllocSite();
2655 Integer hrnIDshadow = as.getShadowIDfromID(hrnCallee.getID() );
2657 HeapRegionNode hrnCaller = id2hrn.get(hrnIDshadow);
2658 if( hrnCaller == null ) {
2660 createNewHeapRegionNode(hrnIDshadow, // id or null to generate a new one
2661 hrnCallee.isSingleObject(), // single object?
2662 hrnCallee.isNewSummary(), // summary?
2663 false, // out-of-context?
2664 hrnCallee.getType(), // type
2665 hrnCallee.getAllocSite(), // allocation site
2666 toCallerContext(hrnCallee.getInherent(),
2667 calleeNode2calleeStatesSatisfied.get(hrnCallee) ), // inherent reach
2668 null, // current reach
2669 predsEmpty, // predicates
2670 hrnCallee.getDescription() // description
2673 assert hrnCaller.isWiped();
2676 hrnCaller.setAlpha(toCallerContext(hrnCallee.getAlpha(),
2677 calleeNode2calleeStatesSatisfied.get(hrnCallee)
2681 hrnCaller.setPreds(preds);
2688 if( writeDebugDOTs ) {
2689 writeGraph(debugGraphPrefix+"caller31BeforeAddingEdges",
2690 resolveMethodDebugDOTwriteLabels,
2691 resolveMethodDebugDOTselectTemps,
2692 resolveMethodDebugDOTpruneGarbage,
2693 resolveMethodDebugDOThideReach,
2694 resolveMethodDebugDOThideSubsetReach,
2695 resolveMethodDebugDOThidePreds,
2696 resolveMethodDebugDOThideEdgeTaints);
2700 // set these up during the next procedure so after
2701 // the caller has all of its nodes and edges put
2702 // back together we can propagate the callee's
2703 // reach changes backwards into the caller graph
2704 HashSet<RefEdge> edgesForPropagation = new HashSet<RefEdge>();
2706 Hashtable<RefEdge, ChangeSet> edgePlannedChanges =
2707 new Hashtable<RefEdge, ChangeSet>();
2710 // 3.b) callee -> callee edges AND out-of-context -> callee
2711 // which includes return temp -> callee edges now, too
2712 satisItr = calleeEdgesSatisfied.entrySet().iterator();
2713 while( satisItr.hasNext() ) {
2714 Map.Entry me = (Map.Entry)satisItr.next();
2715 RefEdge reCallee = (RefEdge) me.getKey();
2716 ExistPredSet preds = (ExistPredSet) me.getValue();
2718 HeapRegionNode hrnDstCallee = reCallee.getDst();
2719 AllocSite asDst = hrnDstCallee.getAllocSite();
2720 allocSites.add(asDst);
2722 Integer hrnIDDstShadow =
2723 asDst.getShadowIDfromID(hrnDstCallee.getID() );
2725 HeapRegionNode hrnDstCaller = id2hrn.get(hrnIDDstShadow);
2726 assert hrnDstCaller != null;
2729 RefSrcNode rsnCallee = reCallee.getSrc();
2731 Set<RefSrcNode> rsnCallers =
2732 new HashSet<RefSrcNode>();
2734 Set<RefSrcNode> oocCallers =
2735 calleeEdges2oocCallerSrcMatches.get(reCallee);
2737 if( rsnCallee instanceof HeapRegionNode ) {
2738 HeapRegionNode hrnCalleeSrc = (HeapRegionNode) rsnCallee;
2739 if( hrnCalleeSrc.isOutOfContext() ) {
2740 assert oocCallers != null;
2745 if( oocCallers == null ) {
2746 // there are no out-of-context matches, so it's
2747 // either a param/arg var or one in-context heap region
2748 if( rsnCallee instanceof VariableNode ) {
2749 // variable -> node in the callee should only
2750 // come into the caller if its from a param var
2751 VariableNode vnCallee = (VariableNode) rsnCallee;
2752 TempDescriptor tdParam = vnCallee.getTempDescriptor();
2753 TempDescriptor tdArg = fc.getArgMatchingParam(fmCallee,
2755 if( tdArg == null ) {
2756 // this means the variable isn't a parameter, its local
2757 // to the callee so we ignore it in call site transfer
2758 // shouldn't this NEVER HAPPEN?
2762 rsnCallers.add(this.getVariableNodeFromTemp(tdArg) );
2765 // otherwise source is in context, one region
2767 HeapRegionNode hrnSrcCallee = (HeapRegionNode) rsnCallee;
2769 // translate an in-context node to shadow
2770 AllocSite asSrc = hrnSrcCallee.getAllocSite();
2771 allocSites.add(asSrc);
2773 Integer hrnIDSrcShadow =
2774 asSrc.getShadowIDfromID(hrnSrcCallee.getID() );
2776 HeapRegionNode hrnSrcCallerShadow =
2777 this.id2hrn.get(hrnIDSrcShadow);
2779 assert hrnSrcCallerShadow != null;
2781 rsnCallers.add(hrnSrcCallerShadow);
2785 // otherwise we have a set of out-of-context srcs
2786 // that should NOT be translated to shadow nodes
2787 assert !oocCallers.isEmpty();
2788 rsnCallers.addAll(oocCallers);
2791 // now make all caller edges we've identified from
2792 // this callee edge with a satisfied predicate
2793 assert !rsnCallers.isEmpty();
2794 Iterator<RefSrcNode> rsnItr = rsnCallers.iterator();
2795 while( rsnItr.hasNext() ) {
2796 RefSrcNode rsnCaller = rsnItr.next();
2798 RefEdge reCaller = new RefEdge(rsnCaller,
2801 reCallee.getField(),
2802 toCallerContext(reCallee.getBeta(),
2803 calleeEdge2calleeStatesSatisfied.get(reCallee) ),
2805 toCallerContext(reCallee.getTaints(),
2806 calleeEdge2calleeTaintsSatisfied.get(reCallee) )
2809 ChangeSet cs = ChangeSet.factory();
2810 Iterator<ReachState> rsItr = reCaller.getBeta().iterator();
2811 while( rsItr.hasNext() ) {
2812 ReachState state = rsItr.next();
2813 ExistPredSet predsPreCallee = state.getPreds();
2815 if( state.isEmpty() ) {
2819 Iterator<ExistPred> predItr = predsPreCallee.iterator();
2820 while( predItr.hasNext() ) {
2821 ExistPred pred = predItr.next();
2822 ReachState old = pred.ne_state;
2828 cs = Canonical.add(cs,
2829 ChangeTuple.factory(old,
2836 // we're just going to use the convenient "merge-if-exists"
2837 // edge call below, but still take a separate look if there
2838 // is an existing caller edge to build change sets properly
2839 if( !cs.isEmpty() ) {
2840 RefEdge edgeExisting = rsnCaller.getReferenceTo(hrnDstCaller,
2844 if( edgeExisting != null ) {
2845 ChangeSet csExisting = edgePlannedChanges.get(edgeExisting);
2846 if( csExisting == null ) {
2847 csExisting = ChangeSet.factory();
2849 edgePlannedChanges.put(edgeExisting,
2850 Canonical.union(csExisting,
2855 edgesForPropagation.add(reCaller);
2856 assert !edgePlannedChanges.containsKey(reCaller);
2857 edgePlannedChanges.put(reCaller, cs);
2861 // then add new caller edge or merge
2862 addEdgeOrMergeWithExisting(reCaller);
2870 if( writeDebugDOTs ) {
2871 writeGraph(debugGraphPrefix+"caller38propagateReach",
2872 resolveMethodDebugDOTwriteLabels,
2873 resolveMethodDebugDOTselectTemps,
2874 resolveMethodDebugDOTpruneGarbage,
2875 resolveMethodDebugDOThideReach,
2876 resolveMethodDebugDOThideSubsetReach,
2877 resolveMethodDebugDOThidePreds,
2878 resolveMethodDebugDOThideEdgeTaints);
2881 // propagate callee reachability changes to the rest
2882 // of the caller graph edges
2883 HashSet<RefEdge> edgesUpdated = new HashSet<RefEdge>();
2885 propagateTokensOverEdges(edgesForPropagation, // source edges
2886 edgePlannedChanges, // map src edge to change set
2887 edgesUpdated); // list of updated edges
2889 // commit beta' (beta<-betaNew)
2890 Iterator<RefEdge> edgeItr = edgesUpdated.iterator();
2891 while( edgeItr.hasNext() ) {
2892 edgeItr.next().applyBetaNew();
2901 if( writeDebugDOTs ) {
2902 writeGraph(debugGraphPrefix+"caller40BeforeShadowMerge",
2903 resolveMethodDebugDOTwriteLabels,
2904 resolveMethodDebugDOTselectTemps,
2905 resolveMethodDebugDOTpruneGarbage,
2906 resolveMethodDebugDOThideReach,
2907 resolveMethodDebugDOThideSubsetReach,
2908 resolveMethodDebugDOThidePreds,
2909 resolveMethodDebugDOThideEdgeTaints);
2913 // 4) merge shadow nodes so alloc sites are back to k
2914 Iterator<AllocSite> asItr = rgCallee.allocSites.iterator();
2915 while( asItr.hasNext() ) {
2916 // for each allocation site do the following to merge
2917 // shadow nodes (newest from callee) with any existing
2918 // look for the newest normal and newest shadow "slot"
2919 // not being used, transfer normal to shadow. Keep
2920 // doing this until there are no more normal nodes, or
2921 // no empty shadow slots: then merge all remaining normal
2922 // nodes into the shadow summary. Finally, convert all
2923 // shadow to their normal versions.
2924 AllocSite as = asItr.next();
2928 while( ageNorm < allocationDepth &&
2929 ageShad < allocationDepth ) {
2931 // first, are there any normal nodes left?
2932 Integer idNorm = as.getIthOldest(ageNorm);
2933 HeapRegionNode hrnNorm = id2hrn.get(idNorm);
2934 if( hrnNorm == null ) {
2935 // no, this age of normal node not in the caller graph
2940 // yes, a normal node exists, is there an empty shadow
2941 // "slot" to transfer it onto?
2942 HeapRegionNode hrnShad = getIthNode(as, ageShad, true);
2943 if( !hrnShad.isWiped() ) {
2944 // no, this age of shadow node is not empty
2949 // yes, this shadow node is empty
2950 transferOnto(hrnNorm, hrnShad);
2955 // now, while there are still normal nodes but no shadow
2956 // slots, merge normal nodes into the shadow summary
2957 while( ageNorm < allocationDepth ) {
2959 // first, are there any normal nodes left?
2960 Integer idNorm = as.getIthOldest(ageNorm);
2961 HeapRegionNode hrnNorm = id2hrn.get(idNorm);
2962 if( hrnNorm == null ) {
2963 // no, this age of normal node not in the caller graph
2968 // yes, a normal node exists, so get the shadow summary
2969 HeapRegionNode summShad = getSummaryNode(as, true);
2970 mergeIntoSummary(hrnNorm, summShad);
2972 // now tokens in reachability sets need to age also
2973 Iterator itrAllHRNodes = id2hrn.entrySet().iterator();
2974 while( itrAllHRNodes.hasNext() ) {
2975 Map.Entry me = (Map.Entry)itrAllHRNodes.next();
2976 HeapRegionNode hrnToAge = (HeapRegionNode) me.getValue();
2978 ageTuplesFrom(as, hrnToAge);
2980 Iterator<RefEdge> itrEdges = hrnToAge.iteratorToReferencers();
2981 while( itrEdges.hasNext() ) {
2982 ageTuplesFrom(as, itrEdges.next() );
2989 // if there is a normal summary, merge it into shadow summary
2990 Integer idNorm = as.getSummary();
2991 HeapRegionNode summNorm = id2hrn.get(idNorm);
2992 if( summNorm != null ) {
2993 HeapRegionNode summShad = getSummaryNode(as, true);
2994 mergeIntoSummary(summNorm, summShad);
2997 // finally, flip all existing shadow nodes onto the normal
2998 for( int i = 0; i < allocationDepth; ++i ) {
2999 Integer idShad = as.getIthOldestShadow(i);
3000 HeapRegionNode hrnShad = id2hrn.get(idShad);
3001 if( hrnShad != null ) {
3003 HeapRegionNode hrnNorm = getIthNode(as, i, false);
3004 assert hrnNorm.isWiped();
3005 transferOnto(hrnShad, hrnNorm);
3009 Integer idShad = as.getSummaryShadow();
3010 HeapRegionNode summShad = id2hrn.get(idShad);
3011 if( summShad != null ) {
3012 summNorm = getSummaryNode(as, false);
3013 transferOnto(summShad, summNorm);
3022 if( writeDebugDOTs ) {
3023 writeGraph(debugGraphPrefix+"caller45BeforeUnshadow",
3024 resolveMethodDebugDOTwriteLabels,
3025 resolveMethodDebugDOTselectTemps,
3026 resolveMethodDebugDOTpruneGarbage,
3027 resolveMethodDebugDOThideReach,
3028 resolveMethodDebugDOThideSubsetReach,
3029 resolveMethodDebugDOThidePreds,
3030 resolveMethodDebugDOThideEdgeTaints);
3034 Iterator itrAllHRNodes = id2hrn.entrySet().iterator();
3035 while( itrAllHRNodes.hasNext() ) {
3036 Map.Entry me = (Map.Entry)itrAllHRNodes.next();
3037 HeapRegionNode hrn = (HeapRegionNode) me.getValue();
3039 hrn.setAlpha(unshadow(hrn.getAlpha() ) );
3041 Iterator<RefEdge> itrEdges = hrn.iteratorToReferencers();
3042 while( itrEdges.hasNext() ) {
3043 RefEdge re = itrEdges.next();
3044 re.setBeta(unshadow(re.getBeta() ) );
3051 if( writeDebugDOTs ) {
3052 writeGraph(debugGraphPrefix+"caller50BeforeGlobalSweep",
3053 resolveMethodDebugDOTwriteLabels,
3054 resolveMethodDebugDOTselectTemps,
3055 resolveMethodDebugDOTpruneGarbage,
3056 resolveMethodDebugDOThideReach,
3057 resolveMethodDebugDOThideSubsetReach,
3058 resolveMethodDebugDOThidePreds,
3059 resolveMethodDebugDOThideEdgeTaints);
3064 if( !DISABLE_GLOBAL_SWEEP ) {
3069 if( writeDebugDOTs ) {
3070 writeGraph(debugGraphPrefix+"caller90AfterTransfer",
3071 resolveMethodDebugDOTwriteLabels,
3072 resolveMethodDebugDOTselectTemps,
3073 resolveMethodDebugDOTpruneGarbage,
3074 resolveMethodDebugDOThideReach,
3075 resolveMethodDebugDOThideSubsetReach,
3076 resolveMethodDebugDOThidePreds,
3077 resolveMethodDebugDOThideEdgeTaints);
3083 ////////////////////////////////////////////////////
3085 // Abstract garbage collection simply removes
3086 // heap region nodes that are not mechanically
3087 // reachable from a root set. This step is
3088 // essential for testing node and edge existence
3089 // predicates efficiently
3091 ////////////////////////////////////////////////////
3092 public void abstractGarbageCollect(Set<TempDescriptor> liveSet) {
3094 // calculate a root set, will be different for Java
3095 // version of analysis versus Bamboo version
3096 Set<RefSrcNode> toVisit = new HashSet<RefSrcNode>();
3098 // visit every variable in graph while building root
3099 // set, and do iterating on a copy, so we can remove
3100 // dead variables while we're at this
3101 Iterator makeCopyItr = td2vn.entrySet().iterator();
3102 Set entrysCopy = new HashSet();
3103 while( makeCopyItr.hasNext() ) {
3104 entrysCopy.add(makeCopyItr.next() );
3107 Iterator eItr = entrysCopy.iterator();
3108 while( eItr.hasNext() ) {
3109 Map.Entry me = (Map.Entry)eItr.next();
3110 TempDescriptor td = (TempDescriptor) me.getKey();
3111 VariableNode vn = (VariableNode) me.getValue();
3113 if( liveSet.contains(td) ) {
3117 // dead var, remove completely from graph
3119 clearRefEdgesFrom(vn, null, null, true);
3123 // everything visited in a traversal is
3124 // considered abstractly live
3125 Set<RefSrcNode> visited = new HashSet<RefSrcNode>();
3127 while( !toVisit.isEmpty() ) {
3128 RefSrcNode rsn = toVisit.iterator().next();
3129 toVisit.remove(rsn);
3132 Iterator<RefEdge> hrnItr = rsn.iteratorToReferencees();
3133 while( hrnItr.hasNext() ) {
3134 RefEdge edge = hrnItr.next();
3135 HeapRegionNode hrn = edge.getDst();
3137 if( !visited.contains(hrn) ) {
3143 // get a copy of the set to iterate over because
3144 // we're going to monkey with the graph when we
3145 // identify a garbage node
3146 Set<HeapRegionNode> hrnAllPrior = new HashSet<HeapRegionNode>();
3147 Iterator<HeapRegionNode> hrnItr = id2hrn.values().iterator();
3148 while( hrnItr.hasNext() ) {
3149 hrnAllPrior.add(hrnItr.next() );
3152 Iterator<HeapRegionNode> hrnAllItr = hrnAllPrior.iterator();
3153 while( hrnAllItr.hasNext() ) {
3154 HeapRegionNode hrn = hrnAllItr.next();
3156 if( !visited.contains(hrn) ) {
3158 // heap region nodes are compared across ReachGraph
3159 // objects by their integer ID, so when discarding
3160 // garbage nodes we must also discard entries in
3161 // the ID -> heap region hashtable.
3162 id2hrn.remove(hrn.getID() );
3164 // RefEdge objects are two-way linked between
3165 // nodes, so when a node is identified as garbage,
3166 // actively clear references to and from it so
3167 // live nodes won't have dangling RefEdge's
3170 // if we just removed the last node from an allocation
3171 // site, it should be taken out of the ReachGraph's list
3172 AllocSite as = hrn.getAllocSite();
3173 if( !hasNodesOf(as) ) {
3174 allocSites.remove(as);
3180 protected boolean hasNodesOf(AllocSite as) {
3181 if( id2hrn.containsKey(as.getSummary() ) ) {
3185 for( int i = 0; i < allocationDepth; ++i ) {
3186 if( id2hrn.containsKey(as.getIthOldest(i) ) ) {
3194 ////////////////////////////////////////////////////
3196 // This global sweep is an optional step to prune
3197 // reachability sets that are not internally
3198 // consistent with the global graph. It should be
3199 // invoked after strong updates or method calls.
3201 ////////////////////////////////////////////////////
3202 public void globalSweep() {
3204 // boldB is part of the phase 1 sweep
3205 // it has an in-context table and an out-of-context table
3206 Hashtable< Integer, Hashtable<RefEdge, ReachSet> > boldBic =
3207 new Hashtable< Integer, Hashtable<RefEdge, ReachSet> >();
3209 Hashtable< Integer, Hashtable<RefEdge, ReachSet> > boldBooc =
3210 new Hashtable< Integer, Hashtable<RefEdge, ReachSet> >();
3212 // visit every heap region to initialize alphaNew and betaNew,
3213 // and make a map of every hrnID to the source nodes it should
3214 // propagate forward from. In-context flagged hrnID's propagate
3215 // from only the in-context node they name, but out-of-context
3216 // ID's may propagate from several out-of-context nodes
3217 Hashtable< Integer, Set<HeapRegionNode> > icID2srcs =
3218 new Hashtable< Integer, Set<HeapRegionNode> >();
3220 Hashtable< Integer, Set<HeapRegionNode> > oocID2srcs =
3221 new Hashtable< Integer, Set<HeapRegionNode> >();
3224 Iterator itrHrns = id2hrn.entrySet().iterator();
3225 while( itrHrns.hasNext() ) {
3226 Map.Entry me = (Map.Entry)itrHrns.next();
3227 Integer hrnID = (Integer) me.getKey();
3228 HeapRegionNode hrn = (HeapRegionNode) me.getValue();
3230 // assert that this node and incoming edges have clean alphaNew
3231 // and betaNew sets, respectively
3232 assert rsetEmpty.equals(hrn.getAlphaNew() );
3234 Iterator<RefEdge> itrRers = hrn.iteratorToReferencers();
3235 while( itrRers.hasNext() ) {
3236 RefEdge edge = itrRers.next();
3237 assert rsetEmpty.equals(edge.getBetaNew() );
3240 // make a mapping of IDs to heap regions they propagate from
3241 if( hrn.isFlagged() ) {
3242 assert !hrn.isOutOfContext();
3243 assert !icID2srcs.containsKey(hrn.getID() );
3245 // in-context flagged node IDs simply propagate from the
3247 Set<HeapRegionNode> srcs = new HashSet<HeapRegionNode>();
3249 icID2srcs.put(hrn.getID(), srcs);
3252 if( hrn.isOutOfContext() ) {
3253 assert !hrn.isFlagged();
3255 // the reachability states on an out-of-context
3256 // node are not really important (combinations of
3257 // IDs or arity)--what matters is that the states
3258 // specify which nodes this out-of-context node
3259 // stands in for. For example, if the state [17?, 19*]
3260 // appears on the ooc node, it may serve as a source
3261 // for node 17? and a source for node 19.
3262 Iterator<ReachState> stateItr = hrn.getAlpha().iterator();
3263 while( stateItr.hasNext() ) {
3264 ReachState state = stateItr.next();
3266 Iterator<ReachTuple> rtItr = state.iterator();
3267 while( rtItr.hasNext() ) {
3268 ReachTuple rt = rtItr.next();
3269 assert rt.isOutOfContext();
3271 Set<HeapRegionNode> srcs = oocID2srcs.get(rt.getHrnID() );
3272 if( srcs == null ) {
3273 srcs = new HashSet<HeapRegionNode>();
3276 oocID2srcs.put(rt.getHrnID(), srcs);
3282 // calculate boldB for all hrnIDs identified by the above
3283 // node traversal, propagating from every source
3284 while( !icID2srcs.isEmpty() || !oocID2srcs.isEmpty() ) {
3287 Set<HeapRegionNode> srcs;
3290 if( !icID2srcs.isEmpty() ) {
3291 Map.Entry me = (Map.Entry)icID2srcs.entrySet().iterator().next();
3292 hrnID = (Integer) me.getKey();
3293 srcs = (Set<HeapRegionNode>)me.getValue();
3295 icID2srcs.remove(hrnID);
3298 assert !oocID2srcs.isEmpty();
3300 Map.Entry me = (Map.Entry)oocID2srcs.entrySet().iterator().next();
3301 hrnID = (Integer) me.getKey();
3302 srcs = (Set<HeapRegionNode>)me.getValue();
3304 oocID2srcs.remove(hrnID);
3308 Hashtable<RefEdge, ReachSet> boldB_f =
3309 new Hashtable<RefEdge, ReachSet>();
3311 Set<RefEdge> workSetEdges = new HashSet<RefEdge>();
3313 Iterator<HeapRegionNode> hrnItr = srcs.iterator();
3314 while( hrnItr.hasNext() ) {
3315 HeapRegionNode hrn = hrnItr.next();
3317 assert workSetEdges.isEmpty();
3319 // initial boldB_f constraints
3320 Iterator<RefEdge> itrRees = hrn.iteratorToReferencees();
3321 while( itrRees.hasNext() ) {
3322 RefEdge edge = itrRees.next();
3324 assert !boldB_f.containsKey(edge);
3325 boldB_f.put(edge, edge.getBeta() );
3327 assert !workSetEdges.contains(edge);
3328 workSetEdges.add(edge);
3331 // enforce the boldB_f constraint at edges until we reach a fixed point
3332 while( !workSetEdges.isEmpty() ) {
3333 RefEdge edge = workSetEdges.iterator().next();
3334 workSetEdges.remove(edge);
3336 Iterator<RefEdge> itrPrime = edge.getDst().iteratorToReferencees();
3337 while( itrPrime.hasNext() ) {
3338 RefEdge edgePrime = itrPrime.next();
3340 ReachSet prevResult = boldB_f.get(edgePrime);
3341 ReachSet intersection = Canonical.intersection(boldB_f.get(edge),
3345 if( prevResult == null ||
3346 Canonical.unionORpreds(prevResult,
3347 intersection).size()
3351 if( prevResult == null ) {
3352 boldB_f.put(edgePrime,
3353 Canonical.unionORpreds(edgePrime.getBeta(),
3358 boldB_f.put(edgePrime,
3359 Canonical.unionORpreds(prevResult,
3364 workSetEdges.add(edgePrime);
3371 boldBic.put(hrnID, boldB_f);
3373 boldBooc.put(hrnID, boldB_f);
3378 // use boldB to prune hrnIDs from alpha states that are impossible
3379 // and propagate the differences backwards across edges
3380 HashSet<RefEdge> edgesForPropagation = new HashSet<RefEdge>();
3382 Hashtable<RefEdge, ChangeSet> edgePlannedChanges =
3383 new Hashtable<RefEdge, ChangeSet>();
3386 itrHrns = id2hrn.entrySet().iterator();
3387 while( itrHrns.hasNext() ) {
3388 Map.Entry me = (Map.Entry)itrHrns.next();
3389 Integer hrnID = (Integer) me.getKey();
3390 HeapRegionNode hrn = (HeapRegionNode) me.getValue();
3392 // out-of-context nodes don't participate in the
3393 // global sweep, they serve as sources for the pass
3395 if( hrn.isOutOfContext() ) {
3399 // the inherent states of a region are the exception
3400 // to removal as the global sweep prunes
3401 ReachTuple rtException = ReachTuple.factory(hrnID,
3402 !hrn.isSingleObject(),
3403 ReachTuple.ARITY_ONE,
3404 false // out-of-context
3407 ChangeSet cts = ChangeSet.factory();
3409 // mark hrnIDs for removal
3410 Iterator<ReachState> stateItr = hrn.getAlpha().iterator();
3411 while( stateItr.hasNext() ) {
3412 ReachState stateOld = stateItr.next();
3414 ReachState markedHrnIDs = ReachState.factory();
3416 Iterator<ReachTuple> rtItr = stateOld.iterator();
3417 while( rtItr.hasNext() ) {
3418 ReachTuple rtOld = rtItr.next();
3420 // never remove the inherent hrnID from a flagged region
3421 // because it is trivially satisfied
3422 if( hrn.isFlagged() ) {
3423 if( rtOld == rtException ) {
3428 // does boldB allow this hrnID?
3429 boolean foundState = false;
3430 Iterator<RefEdge> incidentEdgeItr = hrn.iteratorToReferencers();
3431 while( incidentEdgeItr.hasNext() ) {
3432 RefEdge incidentEdge = incidentEdgeItr.next();
3434 Hashtable<RefEdge, ReachSet> B;
3435 if( rtOld.isOutOfContext() ) {
3436 B = boldBooc.get(rtOld.getHrnID() );
3439 if( !id2hrn.containsKey(rtOld.getHrnID() ) ) {
3440 // let symbols not in the graph get pruned
3444 B = boldBic.get(rtOld.getHrnID() );
3448 ReachSet boldB_rtOld_incident = B.get(incidentEdge);
3449 if( boldB_rtOld_incident != null &&
3450 boldB_rtOld_incident.containsIgnorePreds(stateOld) != null
3458 markedHrnIDs = Canonical.addUpArity(markedHrnIDs, rtOld);
3462 // if there is nothing marked, just move on
3463 if( markedHrnIDs.isEmpty() ) {
3464 hrn.setAlphaNew(Canonical.add(hrn.getAlphaNew(),
3471 // remove all marked hrnIDs and establish a change set that should
3472 // propagate backwards over edges from this node
3473 ReachState statePruned = ReachState.factory();
3474 rtItr = stateOld.iterator();
3475 while( rtItr.hasNext() ) {
3476 ReachTuple rtOld = rtItr.next();
3478 if( !markedHrnIDs.containsTuple(rtOld) ) {
3479 statePruned = Canonical.addUpArity(statePruned, rtOld);
3482 assert !stateOld.equals(statePruned);
3484 hrn.setAlphaNew(Canonical.add(hrn.getAlphaNew(),
3488 ChangeTuple ct = ChangeTuple.factory(stateOld,
3491 cts = Canonical.add(cts, ct);
3494 // throw change tuple set on all incident edges
3495 if( !cts.isEmpty() ) {
3496 Iterator<RefEdge> incidentEdgeItr = hrn.iteratorToReferencers();
3497 while( incidentEdgeItr.hasNext() ) {
3498 RefEdge incidentEdge = incidentEdgeItr.next();
3500 edgesForPropagation.add(incidentEdge);
3502 if( edgePlannedChanges.get(incidentEdge) == null ) {
3503 edgePlannedChanges.put(incidentEdge, cts);
3505 edgePlannedChanges.put(
3507 Canonical.union(edgePlannedChanges.get(incidentEdge),
3516 HashSet<RefEdge> edgesUpdated = new HashSet<RefEdge>();
3518 propagateTokensOverEdges(edgesForPropagation,
3522 // at the end of the 1st phase reference edges have
3523 // beta, betaNew that correspond to beta and betaR
3525 // commit beta<-betaNew, so beta=betaR and betaNew
3526 // will represent the beta' calculation in 2nd phase
3528 // commit alpha<-alphaNew because it won't change
3529 HashSet<RefEdge> res = new HashSet<RefEdge>();
3531 Iterator<HeapRegionNode> nodeItr = id2hrn.values().iterator();
3532 while( nodeItr.hasNext() ) {
3533 HeapRegionNode hrn = nodeItr.next();
3535 // as mentioned above, out-of-context nodes only serve
3536 // as sources of reach states for the sweep, not part
3538 if( hrn.isOutOfContext() ) {
3539 assert hrn.getAlphaNew().equals(rsetEmpty);
3541 hrn.applyAlphaNew();
3544 Iterator<RefEdge> itrRes = hrn.iteratorToReferencers();
3545 while( itrRes.hasNext() ) {
3546 res.add(itrRes.next() );
3552 Iterator<RefEdge> edgeItr = res.iterator();
3553 while( edgeItr.hasNext() ) {
3554 RefEdge edge = edgeItr.next();
3555 HeapRegionNode hrn = edge.getDst();
3557 // commit results of last phase
3558 if( edgesUpdated.contains(edge) ) {
3559 edge.applyBetaNew();
3562 // compute intial condition of 2nd phase
3563 edge.setBetaNew(Canonical.intersection(edge.getBeta(),
3569 // every edge in the graph is the initial workset
3570 Set<RefEdge> edgeWorkSet = (Set) res.clone();
3571 while( !edgeWorkSet.isEmpty() ) {
3572 RefEdge edgePrime = edgeWorkSet.iterator().next();
3573 edgeWorkSet.remove(edgePrime);
3575 RefSrcNode rsn = edgePrime.getSrc();
3576 if( !(rsn instanceof HeapRegionNode) ) {
3579 HeapRegionNode hrn = (HeapRegionNode) rsn;
3581 Iterator<RefEdge> itrEdge = hrn.iteratorToReferencers();
3582 while( itrEdge.hasNext() ) {
3583 RefEdge edge = itrEdge.next();
3585 ReachSet prevResult = edge.getBetaNew();
3586 assert prevResult != null;
3588 ReachSet intersection =
3589 Canonical.intersection(edge.getBeta(),
3590 edgePrime.getBetaNew()
3593 if( Canonical.unionORpreds(prevResult,
3600 Canonical.unionORpreds(prevResult,
3604 edgeWorkSet.add(edge);
3609 // commit beta' (beta<-betaNew)
3610 edgeItr = res.iterator();
3611 while( edgeItr.hasNext() ) {
3612 edgeItr.next().applyBetaNew();
3617 // a useful assertion for debugging:
3618 // every in-context tuple on any edge or
3619 // any node should name a node that is
3620 // part of the graph
3621 public boolean inContextTuplesInGraph() {
3623 Iterator hrnItr = id2hrn.entrySet().iterator();
3624 while( hrnItr.hasNext() ) {
3625 Map.Entry me = (Map.Entry)hrnItr.next();
3626 HeapRegionNode hrn = (HeapRegionNode) me.getValue();
3629 Iterator<ReachState> stateItr = hrn.getAlpha().iterator();
3630 while( stateItr.hasNext() ) {
3631 ReachState state = stateItr.next();
3633 Iterator<ReachTuple> rtItr = state.iterator();
3634 while( rtItr.hasNext() ) {
3635 ReachTuple rt = rtItr.next();
3637 if( !rt.isOutOfContext() ) {
3638 if( !id2hrn.containsKey(rt.getHrnID() ) ) {
3639 System.out.println(rt.getHrnID()+" is missing");
3647 Iterator<RefEdge> edgeItr = hrn.iteratorToReferencers();
3648 while( edgeItr.hasNext() ) {
3649 RefEdge edge = edgeItr.next();
3651 Iterator<ReachState> stateItr = edge.getBeta().iterator();
3652 while( stateItr.hasNext() ) {
3653 ReachState state = stateItr.next();
3655 Iterator<ReachTuple> rtItr = state.iterator();
3656 while( rtItr.hasNext() ) {
3657 ReachTuple rt = rtItr.next();
3659 if( !rt.isOutOfContext() ) {
3660 if( !id2hrn.containsKey(rt.getHrnID() ) ) {
3661 System.out.println(rt.getHrnID()+" is missing");
3674 // another useful assertion for debugging
3675 public boolean noEmptyReachSetsInGraph() {
3677 Iterator hrnItr = id2hrn.entrySet().iterator();
3678 while( hrnItr.hasNext() ) {
3679 Map.Entry me = (Map.Entry)hrnItr.next();
3680 HeapRegionNode hrn = (HeapRegionNode) me.getValue();
3682 if( !hrn.isOutOfContext() &&
3684 hrn.getAlpha().isEmpty()
3686 System.out.println("!!! "+hrn+" has an empty ReachSet !!!");
3690 Iterator<RefEdge> edgeItr = hrn.iteratorToReferencers();
3691 while( edgeItr.hasNext() ) {
3692 RefEdge edge = edgeItr.next();
3694 if( edge.getBeta().isEmpty() ) {
3695 System.out.println("!!! "+edge+" has an empty ReachSet !!!");
3705 public boolean everyReachStateWTrue() {
3707 Iterator hrnItr = id2hrn.entrySet().iterator();
3708 while( hrnItr.hasNext() ) {
3709 Map.Entry me = (Map.Entry)hrnItr.next();
3710 HeapRegionNode hrn = (HeapRegionNode) me.getValue();
3713 Iterator<ReachState> stateItr = hrn.getAlpha().iterator();
3714 while( stateItr.hasNext() ) {
3715 ReachState state = stateItr.next();
3717 if( !state.getPreds().equals(predsTrue) ) {
3723 Iterator<RefEdge> edgeItr = hrn.iteratorToReferencers();
3724 while( edgeItr.hasNext() ) {
3725 RefEdge edge = edgeItr.next();
3727 Iterator<ReachState> stateItr = edge.getBeta().iterator();
3728 while( stateItr.hasNext() ) {
3729 ReachState state = stateItr.next();
3731 if( !state.getPreds().equals(predsTrue) ) {
3744 ////////////////////////////////////////////////////
3745 // in merge() and equals() methods the suffix A
3746 // represents the passed in graph and the suffix
3747 // B refers to the graph in this object
3748 // Merging means to take the incoming graph A and
3749 // merge it into B, so after the operation graph B
3750 // is the final result.
3751 ////////////////////////////////////////////////////
3752 protected void merge(ReachGraph rg) {
3760 mergeAllocSites(rg);
3761 mergeInaccessibleVars(rg);
3764 protected void mergeNodes(ReachGraph rg) {
3766 // start with heap region nodes
3767 Set sA = rg.id2hrn.entrySet();
3768 Iterator iA = sA.iterator();
3769 while( iA.hasNext() ) {
3770 Map.Entry meA = (Map.Entry)iA.next();
3771 Integer idA = (Integer) meA.getKey();
3772 HeapRegionNode hrnA = (HeapRegionNode) meA.getValue();
3774 // if this graph doesn't have a node the
3775 // incoming graph has, allocate it
3776 if( !id2hrn.containsKey(idA) ) {
3777 HeapRegionNode hrnB = hrnA.copy();
3778 id2hrn.put(idA, hrnB);
3781 // otherwise this is a node present in both graphs
3782 // so make the new reachability set a union of the
3783 // nodes' reachability sets
3784 HeapRegionNode hrnB = id2hrn.get(idA);
3785 hrnB.setAlpha(Canonical.unionORpreds(hrnB.getAlpha(),
3790 hrnB.setPreds(Canonical.join(hrnB.getPreds(),
3797 if( !hrnA.equals(hrnB) ) {
3798 rg.writeGraph("graphA");
3799 this.writeGraph("graphB");
3800 throw new Error("flagged not matching");
3808 // now add any variable nodes that are in graph B but
3810 sA = rg.td2vn.entrySet();
3812 while( iA.hasNext() ) {
3813 Map.Entry meA = (Map.Entry)iA.next();
3814 TempDescriptor tdA = (TempDescriptor) meA.getKey();
3815 VariableNode lnA = (VariableNode) meA.getValue();
3817 // if the variable doesn't exist in B, allocate and add it
3818 VariableNode lnB = getVariableNodeFromTemp(tdA);
3822 protected void mergeRefEdges(ReachGraph rg) {
3824 // between heap regions
3825 Set sA = rg.id2hrn.entrySet();
3826 Iterator iA = sA.iterator();
3827 while( iA.hasNext() ) {
3828 Map.Entry meA = (Map.Entry)iA.next();
3829 Integer idA = (Integer) meA.getKey();
3830 HeapRegionNode hrnA = (HeapRegionNode) meA.getValue();
3832 Iterator<RefEdge> heapRegionsItrA = hrnA.iteratorToReferencees();
3833 while( heapRegionsItrA.hasNext() ) {
3834 RefEdge edgeA = heapRegionsItrA.next();
3835 HeapRegionNode hrnChildA = edgeA.getDst();
3836 Integer idChildA = hrnChildA.getID();
3838 // at this point we know an edge in graph A exists
3839 // idA -> idChildA, does this exist in B?
3840 assert id2hrn.containsKey(idA);
3841 HeapRegionNode hrnB = id2hrn.get(idA);
3842 RefEdge edgeToMerge = null;
3844 Iterator<RefEdge> heapRegionsItrB = hrnB.iteratorToReferencees();
3845 while( heapRegionsItrB.hasNext() &&
3846 edgeToMerge == null ) {
3848 RefEdge edgeB = heapRegionsItrB.next();
3849 HeapRegionNode hrnChildB = edgeB.getDst();
3850 Integer idChildB = hrnChildB.getID();
3852 // don't use the RefEdge.equals() here because
3853 // we're talking about existence between graphs,
3854 // not intragraph equal
3855 if( idChildB.equals(idChildA) &&
3856 edgeB.typeAndFieldEquals(edgeA) ) {
3858 edgeToMerge = edgeB;
3862 // if the edge from A was not found in B,
3864 if( edgeToMerge == null ) {
3865 assert id2hrn.containsKey(idChildA);
3866 HeapRegionNode hrnChildB = id2hrn.get(idChildA);
3867 edgeToMerge = edgeA.copy();
3868 edgeToMerge.setSrc(hrnB);
3869 edgeToMerge.setDst(hrnChildB);
3870 addRefEdge(hrnB, hrnChildB, edgeToMerge);
3872 // otherwise, the edge already existed in both graphs
3873 // so merge their reachability sets
3875 // just replace this beta set with the union
3876 assert edgeToMerge != null;
3877 edgeToMerge.setBeta(
3878 Canonical.unionORpreds(edgeToMerge.getBeta(),
3882 edgeToMerge.setPreds(
3883 Canonical.join(edgeToMerge.getPreds(),
3887 edgeToMerge.setTaints(
3888 Canonical.union(edgeToMerge.getTaints(),
3896 // and then again from variable nodes
3897 sA = rg.td2vn.entrySet();
3899 while( iA.hasNext() ) {
3900 Map.Entry meA = (Map.Entry)iA.next();
3901 TempDescriptor tdA = (TempDescriptor) meA.getKey();
3902 VariableNode vnA = (VariableNode) meA.getValue();
3904 Iterator<RefEdge> heapRegionsItrA = vnA.iteratorToReferencees();
3905 while( heapRegionsItrA.hasNext() ) {
3906 RefEdge edgeA = heapRegionsItrA.next();
3907 HeapRegionNode hrnChildA = edgeA.getDst();
3908 Integer idChildA = hrnChildA.getID();
3910 // at this point we know an edge in graph A exists
3911 // tdA -> idChildA, does this exist in B?
3912 assert td2vn.containsKey(tdA);
3913 VariableNode vnB = td2vn.get(tdA);
3914 RefEdge edgeToMerge = null;
3916 Iterator<RefEdge> heapRegionsItrB = vnB.iteratorToReferencees();
3917 while( heapRegionsItrB.hasNext() &&
3918 edgeToMerge == null ) {
3920 RefEdge edgeB = heapRegionsItrB.next();
3921 HeapRegionNode hrnChildB = edgeB.getDst();
3922 Integer idChildB = hrnChildB.getID();
3924 // don't use the RefEdge.equals() here because
3925 // we're talking about existence between graphs
3926 if( idChildB.equals(idChildA) &&
3927 edgeB.typeAndFieldEquals(edgeA) ) {
3929 edgeToMerge = edgeB;
3933 // if the edge from A was not found in B,
3935 if( edgeToMerge == null ) {
3936 assert id2hrn.containsKey(idChildA);
3937 HeapRegionNode hrnChildB = id2hrn.get(idChildA);
3938 edgeToMerge = edgeA.copy();
3939 edgeToMerge.setSrc(vnB);
3940 edgeToMerge.setDst(hrnChildB);
3941 addRefEdge(vnB, hrnChildB, edgeToMerge);
3943 // otherwise, the edge already existed in both graphs
3944 // so merge their reachability sets
3946 // just replace this beta set with the union
3947 edgeToMerge.setBeta(Canonical.unionORpreds(edgeToMerge.getBeta(),
3951 edgeToMerge.setPreds(Canonical.join(edgeToMerge.getPreds(),
3955 edgeToMerge.setTaints(
3956 Canonical.union(edgeToMerge.getTaints(),
3965 protected void mergeAllocSites(ReachGraph rg) {
3966 allocSites.addAll(rg.allocSites);
3969 protected void mergeInaccessibleVars(ReachGraph rg) {
3970 inaccessibleVars.addAll(rg.inaccessibleVars);
3975 static public boolean dbgEquals = false;
3978 // it is necessary in the equals() member functions
3979 // to "check both ways" when comparing the data
3980 // structures of two graphs. For instance, if all
3981 // edges between heap region nodes in graph A are
3982 // present and equal in graph B it is not sufficient
3983 // to say the graphs are equal. Consider that there
3984 // may be edges in graph B that are not in graph A.
3985 // the only way to know that all edges in both graphs
3986 // are equally present is to iterate over both data
3987 // structures and compare against the other graph.
3988 public boolean equals(ReachGraph rg) {
3992 System.out.println("rg is null");
3997 if( !areHeapRegionNodesEqual(rg) ) {
3999 System.out.println("hrn not equal");
4004 if( !areVariableNodesEqual(rg) ) {
4006 System.out.println("vars not equal");
4011 if( !areRefEdgesEqual(rg) ) {
4013 System.out.println("edges not equal");
4018 if( !inaccessibleVars.equals(rg.inaccessibleVars) ) {
4022 // if everything is equal up to this point,
4023 // assert that allocSites is also equal--
4024 // this data is redundant but kept for efficiency
4025 assert allocSites.equals(rg.allocSites);
4031 protected boolean areHeapRegionNodesEqual(ReachGraph rg) {
4033 if( !areallHRNinAalsoinBandequal(this, rg) ) {
4037 if( !areallHRNinAalsoinBandequal(rg, this) ) {
4044 static protected boolean areallHRNinAalsoinBandequal(ReachGraph rgA,
4046 Set sA = rgA.id2hrn.entrySet();
4047 Iterator iA = sA.iterator();
4048 while( iA.hasNext() ) {
4049 Map.Entry meA = (Map.Entry)iA.next();
4050 Integer idA = (Integer) meA.getKey();
4051 HeapRegionNode hrnA = (HeapRegionNode) meA.getValue();
4053 if( !rgB.id2hrn.containsKey(idA) ) {
4057 HeapRegionNode hrnB = rgB.id2hrn.get(idA);
4058 if( !hrnA.equalsIncludingAlphaAndPreds(hrnB) ) {
4066 protected boolean areVariableNodesEqual(ReachGraph rg) {
4068 if( !areallVNinAalsoinBandequal(this, rg) ) {
4072 if( !areallVNinAalsoinBandequal(rg, this) ) {
4079 static protected boolean areallVNinAalsoinBandequal(ReachGraph rgA,
4081 Set sA = rgA.td2vn.entrySet();
4082 Iterator iA = sA.iterator();
4083 while( iA.hasNext() ) {
4084 Map.Entry meA = (Map.Entry)iA.next();
4085 TempDescriptor tdA = (TempDescriptor) meA.getKey();
4087 if( !rgB.td2vn.containsKey(tdA) ) {
4096 protected boolean areRefEdgesEqual(ReachGraph rg) {
4097 if( !areallREinAandBequal(this, rg) ) {
4101 if( !areallREinAandBequal(rg, this) ) {
4108 static protected boolean areallREinAandBequal(ReachGraph rgA,
4111 // check all the heap region->heap region edges
4112 Set sA = rgA.id2hrn.entrySet();
4113 Iterator iA = sA.iterator();
4114 while( iA.hasNext() ) {
4115 Map.Entry meA = (Map.Entry)iA.next();
4116 Integer idA = (Integer) meA.getKey();
4117 HeapRegionNode hrnA = (HeapRegionNode) meA.getValue();
4119 // we should have already checked that the same
4120 // heap regions exist in both graphs
4121 assert rgB.id2hrn.containsKey(idA);
4123 if( !areallREfromAequaltoB(rgA, hrnA, rgB) ) {
4127 // then check every edge in B for presence in A, starting
4128 // from the same parent HeapRegionNode
4129 HeapRegionNode hrnB = rgB.id2hrn.get(idA);
4131 if( !areallREfromAequaltoB(rgB, hrnB, rgA) ) {
4136 // then check all the variable->heap region edges
4137 sA = rgA.td2vn.entrySet();
4139 while( iA.hasNext() ) {
4140 Map.Entry meA = (Map.Entry)iA.next();
4141 TempDescriptor tdA = (TempDescriptor) meA.getKey();
4142 VariableNode vnA = (VariableNode) meA.getValue();
4144 // we should have already checked that the same
4145 // label nodes exist in both graphs
4146 assert rgB.td2vn.containsKey(tdA);
4148 if( !areallREfromAequaltoB(rgA, vnA, rgB) ) {
4152 // then check every edge in B for presence in A, starting
4153 // from the same parent VariableNode
4154 VariableNode vnB = rgB.td2vn.get(tdA);
4156 if( !areallREfromAequaltoB(rgB, vnB, rgA) ) {
4165 static protected boolean areallREfromAequaltoB(ReachGraph rgA,
4169 Iterator<RefEdge> itrA = rnA.iteratorToReferencees();
4170 while( itrA.hasNext() ) {
4171 RefEdge edgeA = itrA.next();
4172 HeapRegionNode hrnChildA = edgeA.getDst();
4173 Integer idChildA = hrnChildA.getID();
4175 assert rgB.id2hrn.containsKey(idChildA);
4177 // at this point we know an edge in graph A exists
4178 // rnA -> idChildA, does this exact edge exist in B?
4179 boolean edgeFound = false;
4181 RefSrcNode rnB = null;
4182 if( rnA instanceof HeapRegionNode ) {
4183 HeapRegionNode hrnA = (HeapRegionNode) rnA;
4184 rnB = rgB.id2hrn.get(hrnA.getID() );
4186 VariableNode vnA = (VariableNode) rnA;
4187 rnB = rgB.td2vn.get(vnA.getTempDescriptor() );
4190 Iterator<RefEdge> itrB = rnB.iteratorToReferencees();
4191 while( itrB.hasNext() ) {
4192 RefEdge edgeB = itrB.next();
4193 HeapRegionNode hrnChildB = edgeB.getDst();
4194 Integer idChildB = hrnChildB.getID();
4196 if( idChildA.equals(idChildB) &&
4197 edgeA.typeAndFieldEquals(edgeB) ) {
4199 // there is an edge in the right place with the right field,
4200 // but do they have the same attributes?
4201 if( edgeA.equalsIncludingBetaPredsTaints( edgeB ) ) {
4216 // can be used to assert monotonicity
4217 static public boolean isNoSmallerThan(ReachGraph rgA,
4220 //System.out.println( "*** Asking if A is no smaller than B ***" );
4222 Iterator iA = rgA.id2hrn.entrySet().iterator();
4223 while( iA.hasNext() ) {
4224 Map.Entry meA = (Map.Entry)iA.next();
4225 Integer idA = (Integer) meA.getKey();
4226 HeapRegionNode hrnA = (HeapRegionNode) meA.getValue();
4228 if( !rgB.id2hrn.containsKey(idA) ) {
4229 System.out.println(" regions smaller");
4234 // this works just fine, no smaller than
4235 if( !areallVNinAalsoinBandequal(rgA, rgB) ) {
4236 System.out.println(" vars smaller:");
4237 System.out.println(" A:"+rgA.td2vn.keySet() );
4238 System.out.println(" B:"+rgB.td2vn.keySet() );
4243 iA = rgA.id2hrn.entrySet().iterator();
4244 while( iA.hasNext() ) {
4245 Map.Entry meA = (Map.Entry)iA.next();
4246 Integer idA = (Integer) meA.getKey();
4247 HeapRegionNode hrnA = (HeapRegionNode) meA.getValue();
4249 Iterator<RefEdge> reItr = hrnA.iteratorToReferencers();
4250 while( reItr.hasNext() ) {
4251 RefEdge edgeA = reItr.next();
4252 RefSrcNode rsnA = edgeA.getSrc();
4254 // we already checked that nodes were present
4255 HeapRegionNode hrnB = rgB.id2hrn.get(hrnA.getID() );
4256 assert hrnB != null;
4259 if( rsnA instanceof VariableNode ) {
4260 VariableNode vnA = (VariableNode) rsnA;
4261 rsnB = rgB.td2vn.get(vnA.getTempDescriptor() );
4264 HeapRegionNode hrnSrcA = (HeapRegionNode) rsnA;
4265 rsnB = rgB.id2hrn.get(hrnSrcA.getID() );
4267 assert rsnB != null;
4269 RefEdge edgeB = rsnB.getReferenceTo(hrnB,
4273 if( edgeB == null ) {
4274 System.out.println(" edges smaller:");
4288 // this analysis no longer has the "match anything"
4289 // type which was represented by null
4290 protected TypeDescriptor mostSpecificType(TypeDescriptor td1,
4291 TypeDescriptor td2) {
4295 if( td1.isNull() ) {
4298 if( td2.isNull() ) {
4301 return typeUtil.mostSpecific(td1, td2);
4304 protected TypeDescriptor mostSpecificType(TypeDescriptor td1,
4306 TypeDescriptor td3) {
4308 return mostSpecificType(td1,
4309 mostSpecificType(td2, td3)
4313 protected TypeDescriptor mostSpecificType(TypeDescriptor td1,
4316 TypeDescriptor td4) {
4318 return mostSpecificType(mostSpecificType(td1, td2),
4319 mostSpecificType(td3, td4)
4323 protected boolean isSuperiorType(TypeDescriptor possibleSuper,
4324 TypeDescriptor possibleChild) {
4325 assert possibleSuper != null;
4326 assert possibleChild != null;
4328 if( possibleSuper.isNull() ||
4329 possibleChild.isNull() ) {
4333 return typeUtil.isSuperorType(possibleSuper, possibleChild);
4337 protected boolean hasMatchingField(HeapRegionNode src,
4340 TypeDescriptor tdSrc = src.getType();
4341 assert tdSrc != null;
4343 if( tdSrc.isArray() ) {
4344 TypeDescriptor td = edge.getType();
4347 TypeDescriptor tdSrcDeref = tdSrc.dereference();
4348 assert tdSrcDeref != null;
4350 if( !typeUtil.isSuperorType(tdSrcDeref, td) ) {
4354 return edge.getField().equals(DisjointAnalysis.arrayElementFieldName);
4357 // if it's not a class, it doesn't have any fields to match
4358 if( !tdSrc.isClass() ) {
4362 ClassDescriptor cd = tdSrc.getClassDesc();
4363 while( cd != null ) {
4364 Iterator fieldItr = cd.getFields();
4366 while( fieldItr.hasNext() ) {
4367 FieldDescriptor fd = (FieldDescriptor) fieldItr.next();
4369 if( fd.getType().equals(edge.getType() ) &&
4370 fd.getSymbol().equals(edge.getField() ) ) {
4375 cd = cd.getSuperDesc();
4378 // otherwise it is a class with fields
4379 // but we didn't find a match
4383 protected boolean hasMatchingType(RefEdge edge,
4384 HeapRegionNode dst) {
4386 // if the region has no type, matches everything
4387 TypeDescriptor tdDst = dst.getType();
4388 assert tdDst != null;
4390 // if the type is not a class or an array, don't
4391 // match because primitives are copied, no aliases
4392 ClassDescriptor cdDst = tdDst.getClassDesc();
4393 if( cdDst == null && !tdDst.isArray() ) {
4397 // if the edge type is null, it matches everything
4398 TypeDescriptor tdEdge = edge.getType();
4399 assert tdEdge != null;
4401 return typeUtil.isSuperorType(tdEdge, tdDst);
4406 // the default signature for quick-and-dirty debugging
4407 public void writeGraph(String graphName) {
4408 writeGraph(graphName,
4409 true, // write labels
4410 true, // label select
4411 true, // prune garbage
4412 false, // hide reachability
4413 true, // hide subset reachability
4414 true, // hide predicates
4415 false, // hide edge taints
4416 null // in-context boundary
4420 public void writeGraph(String graphName,
4421 boolean writeLabels,
4422 boolean labelSelect,
4423 boolean pruneGarbage,
4424 boolean hideReachability,
4425 boolean hideSubsetReachability,
4426 boolean hidePredicates,
4427 boolean hideEdgeTaints
4429 writeGraph(graphName,
4434 hideSubsetReachability,
4440 public void writeGraph(String graphName,
4441 boolean writeLabels,
4442 boolean labelSelect,
4443 boolean pruneGarbage,
4444 boolean hideReachability,
4445 boolean hideSubsetReachability,
4446 boolean hidePredicates,
4447 boolean hideEdgeTaints,
4448 Set<Integer> callerNodeIDsCopiedToCallee
4451 // remove all non-word characters from the graph name so
4452 // the filename and identifier in dot don't cause errors
4453 // jjenista - also replace underscore '_' to prevent some
4454 // really, really long names from IHMS debugging
4455 graphName = graphName.replaceAll("[\\W_]", "");
4458 new BufferedWriter(new FileWriter(graphName+".dot") );
4460 bw.write("digraph "+graphName+" {\n");
4463 // this is an optional step to form the callee-reachable
4464 // "cut-out" into a DOT cluster for visualization
4465 if( callerNodeIDsCopiedToCallee != null ) {
4467 bw.write(" subgraph cluster0 {\n");
4468 bw.write(" color=blue;\n");
4470 Iterator i = id2hrn.entrySet().iterator();
4471 while( i.hasNext() ) {
4472 Map.Entry me = (Map.Entry)i.next();
4473 HeapRegionNode hrn = (HeapRegionNode) me.getValue();
4475 if( callerNodeIDsCopiedToCallee.contains(hrn.getID() ) ) {
4478 hrn.toStringDOT(hideReachability,
4479 hideSubsetReachability,
4489 Set<HeapRegionNode> visited = new HashSet<HeapRegionNode>();
4491 // then visit every heap region node
4492 Iterator i = id2hrn.entrySet().iterator();
4493 while( i.hasNext() ) {
4494 Map.Entry me = (Map.Entry)i.next();
4495 HeapRegionNode hrn = (HeapRegionNode) me.getValue();
4497 // only visit nodes worth writing out--for instance
4498 // not every node at an allocation is referenced
4499 // (think of it as garbage-collected), etc.
4500 if( !pruneGarbage ||
4501 hrn.isOutOfContext() ||
4502 (hrn.isFlagged() && hrn.getID() > 0 && !hrn.isWiped()) // a non-shadow flagged node
4505 if( !visited.contains(hrn) ) {
4506 traverseHeapRegionNodes(hrn,
4511 hideSubsetReachability,
4514 callerNodeIDsCopiedToCallee);
4519 bw.write(" graphTitle[label=\""+graphName+"\",shape=box];\n");
4522 // then visit every label node, useful for debugging
4524 i = td2vn.entrySet().iterator();
4525 while( i.hasNext() ) {
4526 Map.Entry me = (Map.Entry)i.next();
4527 VariableNode vn = (VariableNode) me.getValue();
4530 String labelStr = vn.getTempDescriptorString();
4531 if( labelStr.startsWith("___temp") ||
4532 labelStr.startsWith("___dst") ||
4533 labelStr.startsWith("___srctmp") ||
4534 labelStr.startsWith("___neverused")
4540 Iterator<RefEdge> heapRegionsItr = vn.iteratorToReferencees();
4541 while( heapRegionsItr.hasNext() ) {
4542 RefEdge edge = heapRegionsItr.next();
4543 HeapRegionNode hrn = edge.getDst();
4545 if( !visited.contains(hrn) ) {
4546 traverseHeapRegionNodes(hrn,
4551 hideSubsetReachability,
4554 callerNodeIDsCopiedToCallee);
4557 bw.write(" "+vn.toString()+
4558 " -> "+hrn.toString()+
4559 edge.toStringDOT(hideReachability,
4560 hideSubsetReachability,
4572 } catch( IOException e ) {
4573 throw new Error("Error writing out DOT graph "+graphName);
4578 traverseHeapRegionNodes(HeapRegionNode hrn,
4581 Set<HeapRegionNode> visited,
4582 boolean hideReachability,
4583 boolean hideSubsetReachability,
4584 boolean hidePredicates,
4585 boolean hideEdgeTaints,
4586 Set<Integer> callerNodeIDsCopiedToCallee
4587 ) throws java.io.IOException {
4589 if( visited.contains(hrn) ) {
4594 // if we're drawing the callee-view subgraph, only
4595 // write out the node info if it hasn't already been
4597 if( callerNodeIDsCopiedToCallee == null ||
4598 !callerNodeIDsCopiedToCallee.contains(hrn.getID() )
4602 hrn.toStringDOT(hideReachability,
4603 hideSubsetReachability,
4608 Iterator<RefEdge> childRegionsItr = hrn.iteratorToReferencees();
4609 while( childRegionsItr.hasNext() ) {
4610 RefEdge edge = childRegionsItr.next();
4611 HeapRegionNode hrnChild = edge.getDst();
4613 if( callerNodeIDsCopiedToCallee != null &&
4614 (edge.getSrc() instanceof HeapRegionNode) ) {
4615 HeapRegionNode hrnSrc = (HeapRegionNode) edge.getSrc();
4616 if( callerNodeIDsCopiedToCallee.contains(hrnSrc.getID() ) &&
4617 callerNodeIDsCopiedToCallee.contains(edge.getDst().getID() )
4619 bw.write(" "+hrn.toString()+
4620 " -> "+hrnChild.toString()+
4621 edge.toStringDOT(hideReachability,
4622 hideSubsetReachability,
4627 } else if( !callerNodeIDsCopiedToCallee.contains(hrnSrc.getID() ) &&
4628 callerNodeIDsCopiedToCallee.contains(edge.getDst().getID() )
4630 bw.write(" "+hrn.toString()+
4631 " -> "+hrnChild.toString()+
4632 edge.toStringDOT(hideReachability,
4633 hideSubsetReachability,
4636 ",color=blue,style=dashed")+
4639 bw.write(" "+hrn.toString()+
4640 " -> "+hrnChild.toString()+
4641 edge.toStringDOT(hideReachability,
4642 hideSubsetReachability,
4649 bw.write(" "+hrn.toString()+
4650 " -> "+hrnChild.toString()+
4651 edge.toStringDOT(hideReachability,
4652 hideSubsetReachability,
4659 traverseHeapRegionNodes(hrnChild,
4664 hideSubsetReachability,
4667 callerNodeIDsCopiedToCallee);
4676 // return the set of heap regions from the given allocation
4677 // site, if any, that exist in this graph
4678 protected Set<HeapRegionNode> getAnyExisting(AllocSite as) {
4680 Set<HeapRegionNode> out = new HashSet<HeapRegionNode>();
4682 Integer idSum = as.getSummary();
4683 if( id2hrn.containsKey(idSum) ) {
4684 out.add(id2hrn.get(idSum) );
4687 for( int i = 0; i < as.getAllocationDepth(); ++i ) {
4688 Integer idI = as.getIthOldest(i);
4689 if( id2hrn.containsKey(idI) ) {
4690 out.add(id2hrn.get(idI) );
4697 // return the set of reach tuples (NOT A REACH STATE! JUST A SET!)
4698 // from the given allocation site, if any, from regions for that
4699 // site that exist in this graph
4700 protected Set<ReachTuple> getAnyExisting(AllocSite as,
4701 boolean includeARITY_ZEROORMORE,
4702 boolean includeARITY_ONE) {
4704 Set<ReachTuple> out = new HashSet<ReachTuple>();
4706 Integer idSum = as.getSummary();
4707 if( id2hrn.containsKey(idSum) ) {
4709 HeapRegionNode hrn = id2hrn.get(idSum);
4710 assert !hrn.isOutOfContext();
4712 if( !includeARITY_ZEROORMORE ) {
4713 out.add(ReachTuple.factory(hrn.getID(),
4714 true, // multi-obj region
4715 ReachTuple.ARITY_ZEROORMORE,
4720 if( includeARITY_ONE ) {
4721 out.add(ReachTuple.factory(hrn.getID(),
4722 true, // multi-object region
4723 ReachTuple.ARITY_ONE,
4729 if( !includeARITY_ONE ) {
4730 // no need to do the single-object regions that
4731 // only have an ARITY ONE possible
4735 for( int i = 0; i < as.getAllocationDepth(); ++i ) {
4737 Integer idI = as.getIthOldest(i);
4738 if( id2hrn.containsKey(idI) ) {
4740 HeapRegionNode hrn = id2hrn.get(idI);
4741 assert !hrn.isOutOfContext();
4743 out.add(ReachTuple.factory(hrn.getID(),
4744 false, // multi-object region
4745 ReachTuple.ARITY_ONE,
4755 // if an object allocated at the target site may be
4756 // reachable from both an object from root1 and an
4757 // object allocated at root2, return TRUE
4758 public boolean mayBothReachTarget(AllocSite asRoot1,
4760 AllocSite asTarget) {
4762 // consider all heap regions of the target and look
4763 // for a reach state that indicates regions of root1
4764 // and root2 might be able to reach same object
4765 Set<HeapRegionNode> hrnSetTarget = getAnyExisting(asTarget);
4767 // get relevant reach tuples, include ARITY_ZEROORMORE and ARITY_ONE
4768 Set<ReachTuple> rtSet1 = getAnyExisting(asRoot1, true, true);
4769 Set<ReachTuple> rtSet2 = getAnyExisting(asRoot2, true, true);
4771 Iterator<HeapRegionNode> hrnItr = hrnSetTarget.iterator();
4772 while( hrnItr.hasNext() ) {
4773 HeapRegionNode hrn = hrnItr.next();
4775 Iterator<ReachTuple> rtItr1 = rtSet1.iterator();
4776 while( rtItr1.hasNext() ) {
4777 ReachTuple rt1 = rtItr1.next();
4779 Iterator<ReachTuple> rtItr2 = rtSet2.iterator();
4780 while( rtItr2.hasNext() ) {
4781 ReachTuple rt2 = rtItr2.next();
4783 if( !hrn.getAlpha().getStatesWithBoth(rt1, rt2).isEmpty() ) {
4793 // similar to the method above, return TRUE if ever
4794 // more than one object from the root allocation site
4795 // may reach an object from the target site
4796 public boolean mayManyReachTarget(AllocSite asRoot,
4797 AllocSite asTarget) {
4799 // consider all heap regions of the target and look
4800 // for a reach state that multiple objects of root
4801 // might be able to reach the same object
4802 Set<HeapRegionNode> hrnSetTarget = getAnyExisting(asTarget);
4804 // get relevant reach tuples
4805 Set<ReachTuple> rtSetZOM = getAnyExisting(asRoot, true, false);
4806 Set<ReachTuple> rtSetONE = getAnyExisting(asRoot, false, true);
4808 Iterator<HeapRegionNode> hrnItr = hrnSetTarget.iterator();
4809 while( hrnItr.hasNext() ) {
4810 HeapRegionNode hrn = hrnItr.next();
4812 // if any ZERORMORE tuples are here, TRUE
4813 Iterator<ReachTuple> rtItr = rtSetZOM.iterator();
4814 while( rtItr.hasNext() ) {
4815 ReachTuple rtZOM = rtItr.next();
4817 if( hrn.getAlpha().containsTuple(rtZOM) ) {
4822 // otherwise, look for any pair of ONE tuples
4823 Iterator<ReachTuple> rtItr1 = rtSetONE.iterator();
4824 while( rtItr1.hasNext() ) {
4825 ReachTuple rt1 = rtItr1.next();
4827 Iterator<ReachTuple> rtItr2 = rtSetONE.iterator();
4828 while( rtItr2.hasNext() ) {
4829 ReachTuple rt2 = rtItr2.next();
4835 if( !hrn.getAlpha().getStatesWithBoth(rt1, rt2).isEmpty() ) {
4849 public Set<HeapRegionNode> findCommonReachableNodes(ReachSet proofOfSharing) {
4851 Set<HeapRegionNode> exhibitProofState =
4852 new HashSet<HeapRegionNode>();
4854 Iterator hrnItr = id2hrn.entrySet().iterator();
4855 while( hrnItr.hasNext() ) {
4856 Map.Entry me = (Map.Entry)hrnItr.next();
4857 HeapRegionNode hrn = (HeapRegionNode) me.getValue();
4859 ReachSet intersection =
4860 Canonical.intersection(proofOfSharing,
4863 if( !intersection.isEmpty() ) {
4864 assert !hrn.isOutOfContext();
4865 exhibitProofState.add(hrn);
4869 return exhibitProofState;
4873 public Set<HeapRegionNode> mayReachSharedObjects(HeapRegionNode hrn1,
4874 HeapRegionNode hrn2) {
4875 assert hrn1 != null;
4876 assert hrn2 != null;
4878 assert !hrn1.isOutOfContext();
4879 assert !hrn2.isOutOfContext();
4881 assert belongsToThis(hrn1);
4882 assert belongsToThis(hrn2);
4884 assert !hrn1.getID().equals(hrn2.getID() );
4887 // then get the various tokens for these heap regions
4889 ReachTuple.factory(hrn1.getID(),
4890 !hrn1.isSingleObject(), // multi?
4891 ReachTuple.ARITY_ONE,
4894 ReachTuple h1star = null;
4895 if( !hrn1.isSingleObject() ) {
4897 ReachTuple.factory(hrn1.getID(),
4898 !hrn1.isSingleObject(),
4899 ReachTuple.ARITY_ZEROORMORE,
4904 ReachTuple.factory(hrn2.getID(),
4905 !hrn2.isSingleObject(),
4906 ReachTuple.ARITY_ONE,
4909 ReachTuple h2star = null;
4910 if( !hrn2.isSingleObject() ) {
4912 ReachTuple.factory(hrn2.getID(),
4913 !hrn2.isSingleObject(),
4914 ReachTuple.ARITY_ZEROORMORE,
4918 // then get the merged beta of all out-going edges from these heap
4921 ReachSet beta1 = ReachSet.factory();
4922 Iterator<RefEdge> itrEdge = hrn1.iteratorToReferencees();
4923 while (itrEdge.hasNext()) {
4924 RefEdge edge = itrEdge.next();
4925 beta1 = Canonical.unionORpreds(beta1, edge.getBeta());
4928 ReachSet beta2 = ReachSet.factory();
4929 itrEdge = hrn2.iteratorToReferencees();
4930 while (itrEdge.hasNext()) {
4931 RefEdge edge = itrEdge.next();
4932 beta2 = Canonical.unionORpreds(beta2, edge.getBeta());
4935 ReachSet proofOfSharing = ReachSet.factory();
4938 Canonical.unionORpreds(proofOfSharing,
4939 beta1.getStatesWithBoth(h1, h2)
4942 Canonical.unionORpreds(proofOfSharing,
4943 beta2.getStatesWithBoth(h1, h2)
4946 if( !hrn1.isSingleObject() ) {
4948 Canonical.unionORpreds(proofOfSharing,
4949 beta1.getStatesWithBoth(h1star, h2)
4952 Canonical.unionORpreds(proofOfSharing,
4953 beta2.getStatesWithBoth(h1star, h2)
4957 if( !hrn2.isSingleObject() ) {
4959 Canonical.unionORpreds(proofOfSharing,
4960 beta1.getStatesWithBoth(h1, h2star)
4963 Canonical.unionORpreds(proofOfSharing,
4964 beta2.getStatesWithBoth(h1, h2star)
4968 if( !hrn1.isSingleObject() &&
4969 !hrn2.isSingleObject()
4972 Canonical.unionORpreds(proofOfSharing,
4973 beta1.getStatesWithBoth(h1star, h2star)
4976 Canonical.unionORpreds(proofOfSharing,
4977 beta2.getStatesWithBoth(h1star, h2star)
4981 Set<HeapRegionNode> common = new HashSet<HeapRegionNode>();
4982 if( !proofOfSharing.isEmpty() ) {
4983 common = findCommonReachableNodes(proofOfSharing);
4984 if( !DISABLE_STRONG_UPDATES &&
4985 !DISABLE_GLOBAL_SWEEP
4987 assert !common.isEmpty();
4994 // this version of the above method checks whether there is sharing
4995 // among the objects in a summary node
4996 public Set<HeapRegionNode> mayReachSharedObjects(HeapRegionNode hrn) {
4998 assert hrn.isNewSummary();
4999 assert !hrn.isOutOfContext();
5000 assert belongsToThis(hrn);
5003 ReachTuple.factory(hrn.getID(),
5005 ReachTuple.ARITY_ZEROORMORE,
5008 // then get the merged beta of all out-going edges from
5011 ReachSet beta = ReachSet.factory();
5012 Iterator<RefEdge> itrEdge = hrn.iteratorToReferencees();
5013 while (itrEdge.hasNext()) {
5014 RefEdge edge = itrEdge.next();
5015 beta = Canonical.unionORpreds(beta, edge.getBeta());
5018 ReachSet proofOfSharing = ReachSet.factory();
5021 Canonical.unionORpreds(proofOfSharing,
5022 beta.getStatesWithBoth(hstar, hstar)
5025 Set<HeapRegionNode> common = new HashSet<HeapRegionNode>();
5026 if( !proofOfSharing.isEmpty() ) {
5027 common = findCommonReachableNodes(proofOfSharing);
5028 if( !DISABLE_STRONG_UPDATES &&
5029 !DISABLE_GLOBAL_SWEEP
5031 assert !common.isEmpty();
5039 public Set<HeapRegionNode> mayReachSharedObjects(FlatMethod fm,
5040 Integer paramIndex1,
5041 Integer paramIndex2) {
5043 // get parameter's heap regions
5044 TempDescriptor paramTemp1 = fm.getParameter(paramIndex1.intValue());
5045 assert this.hasVariable(paramTemp1);
5046 VariableNode paramVar1 = getVariableNodeFromTemp(paramTemp1);
5049 if( !(paramVar1.getNumReferencees() == 1) ) {
5050 System.out.println("\n fm="+fm+"\n param="+paramTemp1);
5051 writeGraph("whatup");
5055 assert paramVar1.getNumReferencees() == 1;
5056 RefEdge paramEdge1 = paramVar1.iteratorToReferencees().next();
5057 HeapRegionNode hrnParam1 = paramEdge1.getDst();
5059 TempDescriptor paramTemp2 = fm.getParameter(paramIndex2.intValue());
5060 assert this.hasVariable(paramTemp2);
5061 VariableNode paramVar2 = getVariableNodeFromTemp(paramTemp2);
5063 if( !(paramVar2.getNumReferencees() == 1) ) {
5064 System.out.println("\n fm="+fm+"\n param="+paramTemp2);
5065 writeGraph("whatup");
5068 assert paramVar2.getNumReferencees() == 1;
5069 RefEdge paramEdge2 = paramVar2.iteratorToReferencees().next();
5070 HeapRegionNode hrnParam2 = paramEdge2.getDst();
5072 Set<HeapRegionNode> common = new HashSet<HeapRegionNode>();
5073 common.addAll(mayReachSharedObjects(hrnParam1, hrnParam2));
5078 public Set<HeapRegionNode> mayReachSharedObjects(FlatMethod fm,
5082 // get parameter's heap regions
5083 TempDescriptor paramTemp = fm.getParameter(paramIndex.intValue());
5084 assert this.hasVariable(paramTemp);
5085 VariableNode paramVar = getVariableNodeFromTemp(paramTemp);
5086 assert paramVar.getNumReferencees() == 1;
5087 RefEdge paramEdge = paramVar.iteratorToReferencees().next();
5088 HeapRegionNode hrnParam = paramEdge.getDst();
5091 HeapRegionNode hrnSummary=null;
5092 if(id2hrn.containsKey(as.getSummary())) {
5093 // if summary node doesn't exist, ignore this case
5094 hrnSummary = id2hrn.get(as.getSummary());
5095 assert hrnSummary != null;
5098 Set<HeapRegionNode> common = new HashSet<HeapRegionNode>();
5099 if(hrnSummary!=null) {
5100 common.addAll(mayReachSharedObjects(hrnParam, hrnSummary) );
5103 // check for other nodes
5104 for (int i = 0; i < as.getAllocationDepth(); ++i) {
5106 assert id2hrn.containsKey(as.getIthOldest(i));
5107 HeapRegionNode hrnIthOldest = id2hrn.get(as.getIthOldest(i));
5108 assert hrnIthOldest != null;
5110 common.addAll(mayReachSharedObjects(hrnParam, hrnIthOldest));
5117 public Set<HeapRegionNode> mayReachSharedObjects(AllocSite as1,
5120 // get summary node 1's alpha
5121 Integer idSum1 = as1.getSummary();
5122 HeapRegionNode hrnSum1=null;
5123 if(id2hrn.containsKey(idSum1)) {
5124 hrnSum1 = id2hrn.get(idSum1);
5127 // get summary node 2's alpha
5128 Integer idSum2 = as2.getSummary();
5129 HeapRegionNode hrnSum2=null;
5130 if(id2hrn.containsKey(idSum2)) {
5131 hrnSum2 = id2hrn.get(idSum2);
5134 Set<HeapRegionNode> common = new HashSet<HeapRegionNode>();
5135 if(hrnSum1!=null && hrnSum2!=null && hrnSum1!=hrnSum2) {
5136 common.addAll(mayReachSharedObjects(hrnSum1, hrnSum2));
5140 // ask if objects from this summary share among each other
5141 common.addAll(mayReachSharedObjects(hrnSum1));
5144 // check sum2 against alloc1 nodes
5146 for (int i = 0; i < as1.getAllocationDepth(); ++i) {
5147 Integer idI1 = as1.getIthOldest(i);
5148 assert id2hrn.containsKey(idI1);
5149 HeapRegionNode hrnI1 = id2hrn.get(idI1);
5150 assert hrnI1 != null;
5151 common.addAll(mayReachSharedObjects(hrnI1, hrnSum2));
5154 // also ask if objects from this summary share among each other
5155 common.addAll(mayReachSharedObjects(hrnSum2));
5158 // check sum1 against alloc2 nodes
5159 for (int i = 0; i < as2.getAllocationDepth(); ++i) {
5160 Integer idI2 = as2.getIthOldest(i);
5161 assert id2hrn.containsKey(idI2);
5162 HeapRegionNode hrnI2 = id2hrn.get(idI2);
5163 assert hrnI2 != null;
5166 common.addAll(mayReachSharedObjects(hrnSum1, hrnI2));
5169 // while we're at it, do an inner loop for alloc2 vs alloc1 nodes
5170 for (int j = 0; j < as1.getAllocationDepth(); ++j) {
5171 Integer idI1 = as1.getIthOldest(j);
5173 // if these are the same site, don't look for the same token, no
5175 // different tokens of the same site could alias together though
5176 if (idI1.equals(idI2)) {
5180 HeapRegionNode hrnI1 = id2hrn.get(idI1);
5182 common.addAll(mayReachSharedObjects(hrnI1, hrnI2));
5189 public void makeInaccessible(Set<TempDescriptor> vars) {
5190 inaccessibleVars.addAll(vars);
5193 public void makeInaccessible(TempDescriptor td) {
5194 inaccessibleVars.add(td);
5197 public void makeAccessible(TempDescriptor td) {
5198 inaccessibleVars.remove(td);
5201 public boolean isAccessible(TempDescriptor td) {
5202 return !inaccessibleVars.contains(td);
5205 public Set<TempDescriptor> getInaccessibleVars() {
5206 return inaccessibleVars;
5212 public Set<Alloc> canPointTo( TempDescriptor x ) {
5214 if( !DisjointAnalysis.shouldAnalysisTrack( x.getType() ) ) {
5215 // if we don't care to track it, return null which means
5216 // "a client of this result shouldn't care either"
5217 return HeapAnalysis.DONTCARE_PTR;
5220 Set<Alloc> out = new HashSet<Alloc>();
5222 VariableNode vn = getVariableNodeNoMutation( x );
5224 // the empty set means "can't point to anything"
5228 Iterator<RefEdge> edgeItr = vn.iteratorToReferencees();
5229 while( edgeItr.hasNext() ) {
5230 HeapRegionNode hrn = edgeItr.next().getDst();
5231 out.add( hrn.getAllocSite() );
5239 public Hashtable< Alloc, Set<Alloc> > canPointTo( TempDescriptor x,
5241 TypeDescriptor fieldType ) {
5243 if( !DisjointAnalysis.shouldAnalysisTrack( x.getType() ) ) {
5244 // if we don't care to track it, return null which means
5245 // "a client of this result shouldn't care either"
5246 return HeapAnalysis.DONTCARE_DREF;
5249 Hashtable< Alloc, Set<Alloc> > out = new Hashtable< Alloc, Set<Alloc> >();
5251 VariableNode vn = getVariableNodeNoMutation( x );
5253 // the empty table means "x can't point to anything"
5257 Iterator<RefEdge> edgeItr = vn.iteratorToReferencees();
5258 while( edgeItr.hasNext() ) {
5259 HeapRegionNode hrn = edgeItr.next().getDst();
5260 Alloc key = hrn.getAllocSite();
5262 if( !DisjointAnalysis.shouldAnalysisTrack( fieldType ) ) {
5263 // if we don't care to track it, put no entry which means
5264 // "a client of this result shouldn't care either"
5265 out.put( key, HeapAnalysis.DONTCARE_PTR );
5269 Set<Alloc> moreValues = new HashSet<Alloc>();
5270 Iterator<RefEdge> edgeItr2 = hrn.iteratorToReferencees();
5271 while( edgeItr2.hasNext() ) {
5272 RefEdge edge = edgeItr2.next();
5274 if( field.equals( edge.getField() ) ) {
5275 moreValues.add( edge.getDst().getAllocSite() );
5279 if( out.containsKey( key ) ) {
5280 out.get( key ).addAll( moreValues );
5282 out.put( key, moreValues );
5292 public TempDescriptor findVariableByName( String name ) {
5294 for( TempDescriptor td: td2vn.keySet() ) {
5295 if( td.getSymbol().contains( name ) ) {