1 package Analysis.Disjoint;
5 import Util.UtilAlgorithms;
9 public class ReachGraph {
11 // use to disable improvements for comparison
12 protected static final boolean DISABLE_STRONG_UPDATES = false;
13 protected static final boolean DISABLE_GLOBAL_SWEEP = false;
15 // a special out-of-scope temp
16 protected static final TempDescriptor tdReturn = new TempDescriptor( "_Return___" );
18 // predicate constants
19 public static final ExistPred predTrue = ExistPred.factory(); // if no args, true
20 public static final ExistPredSet predsEmpty = ExistPredSet.factory();
21 public static final ExistPredSet predsTrue = ExistPredSet.factory( predTrue );
23 // some frequently used reachability constants
24 protected static final ReachState rstateEmpty = ReachState.factory();
25 protected static final ReachSet rsetEmpty = ReachSet.factory();
26 protected static final ReachSet rsetWithEmptyState = Canonical.changePredsTo( ReachSet.factory( rstateEmpty ),
29 // from DisjointAnalysis for convenience
30 protected static int allocationDepth = -1;
31 protected static TypeUtil typeUtil = null;
34 // variable and heap region nodes indexed by unique ID
35 public Hashtable<Integer, HeapRegionNode> id2hrn;
36 public Hashtable<TempDescriptor, VariableNode > td2vn;
38 // convenient set of alloc sites for all heap regions
39 // present in the graph without having to search
40 public Set<AllocSite> allocSites;
42 // set of inaccessible variables for current program statement
43 // with respect to stall-site analysis
44 public Set<TempDescriptor> inaccessibleVars;
48 id2hrn = new Hashtable<Integer, HeapRegionNode>();
49 td2vn = new Hashtable<TempDescriptor, VariableNode >();
50 allocSites = new HashSet<AllocSite>();
51 inaccessibleVars = new HashSet<TempDescriptor>();
55 // temp descriptors are globally unique and map to
56 // exactly one variable node, easy
57 protected VariableNode getVariableNodeFromTemp( TempDescriptor td ) {
60 if( !td2vn.containsKey( td ) ) {
61 td2vn.put( td, new VariableNode( td ) );
64 return td2vn.get( td );
67 public boolean hasVariable( TempDescriptor td ) {
68 return td2vn.containsKey( td );
72 // this suite of methods can be used to assert a
73 // very important property of ReachGraph objects:
74 // some element, HeapRegionNode, RefEdge etc.
75 // should be referenced by at most ONE ReachGraph!!
76 // If a heap region or edge or variable should be
77 // in another graph, make a new object with
78 // equivalent properties for a new graph
79 public boolean belongsToThis( RefSrcNode rsn ) {
80 if( rsn instanceof VariableNode ) {
81 VariableNode vn = (VariableNode) rsn;
82 return this.td2vn.get( vn.getTempDescriptor() ) == vn;
84 HeapRegionNode hrn = (HeapRegionNode) rsn;
85 return this.id2hrn.get( hrn.getID() ) == hrn;
92 // the reason for this method is to have the option
93 // of creating new heap regions with specific IDs, or
94 // duplicating heap regions with specific IDs (especially
95 // in the merge() operation) or to create new heap
96 // regions with a new unique ID
97 protected HeapRegionNode
98 createNewHeapRegionNode( Integer id,
99 boolean isSingleObject,
100 boolean isNewSummary,
101 boolean isOutOfContext,
110 TypeDescriptor typeToUse = null;
111 if( allocSite != null ) {
112 typeToUse = allocSite.getType();
113 allocSites.add( allocSite );
118 boolean markForAnalysis = false;
119 if( allocSite != null && allocSite.isFlagged() ) {
120 markForAnalysis = true;
123 if( allocSite == null ) {
124 assert !markForAnalysis;
126 } else if( markForAnalysis != allocSite.isFlagged() ) {
132 id = DisjointAnalysis.generateUniqueHeapRegionNodeID();
135 if( inherent == null ) {
136 if( markForAnalysis ) {
138 Canonical.changePredsTo(
141 ReachTuple.factory( id,
143 ReachTuple.ARITY_ONE,
144 false // out-of-context
151 inherent = rsetWithEmptyState;
155 if( alpha == null ) {
159 assert preds != null;
161 HeapRegionNode hrn = new HeapRegionNode( id,
172 id2hrn.put( id, hrn );
178 ////////////////////////////////////////////////
180 // Low-level referencee and referencer methods
182 // These methods provide the lowest level for
183 // creating references between reachability nodes
184 // and handling the details of maintaining both
185 // list of referencers and referencees.
187 ////////////////////////////////////////////////
188 protected void addRefEdge( RefSrcNode referencer,
189 HeapRegionNode referencee,
191 assert referencer != null;
192 assert referencee != null;
194 assert edge.getSrc() == referencer;
195 assert edge.getDst() == referencee;
196 assert belongsToThis( referencer );
197 assert belongsToThis( referencee );
199 // edges are getting added twice to graphs now, the
200 // kind that should have abstract facts merged--use
201 // this check to prevent that
202 assert referencer.getReferenceTo( referencee,
207 referencer.addReferencee( edge );
208 referencee.addReferencer( edge );
211 protected void removeRefEdge( RefEdge e ) {
212 removeRefEdge( e.getSrc(),
218 protected void removeRefEdge( RefSrcNode referencer,
219 HeapRegionNode referencee,
222 assert referencer != null;
223 assert referencee != null;
225 RefEdge edge = referencer.getReferenceTo( referencee,
229 assert edge == referencee.getReferenceFrom( referencer,
233 referencer.removeReferencee( edge );
234 referencee.removeReferencer( edge );
238 // int oldTaint=edge.getTaintIdentifier();
239 // if(referencer instanceof HeapRegionNode){
240 // depropagateTaintIdentifier((HeapRegionNode)referencer,oldTaint,new HashSet<HeapRegionNode>());
246 // return whether at least one edge was removed
247 protected boolean clearRefEdgesFrom( RefSrcNode referencer,
250 boolean removeAll ) {
251 assert referencer != null;
253 boolean atLeastOneEdgeRemoved = false;
255 // get a copy of the set to iterate over, otherwise
256 // we will be trying to take apart the set as we
257 // are iterating over it, which won't work
258 Iterator<RefEdge> i = referencer.iteratorToReferenceesClone();
259 while( i.hasNext() ) {
260 RefEdge edge = i.next();
263 (edge.typeEquals( type ) && edge.fieldEquals( field ))
266 HeapRegionNode referencee = edge.getDst();
268 removeRefEdge( referencer,
273 atLeastOneEdgeRemoved = true;
277 return atLeastOneEdgeRemoved;
280 protected void clearRefEdgesTo( HeapRegionNode referencee,
283 boolean removeAll ) {
284 assert referencee != null;
286 // get a copy of the set to iterate over, otherwise
287 // we will be trying to take apart the set as we
288 // are iterating over it, which won't work
289 Iterator<RefEdge> i = referencee.iteratorToReferencersClone();
290 while( i.hasNext() ) {
291 RefEdge edge = i.next();
294 (edge.typeEquals( type ) && edge.fieldEquals( field ))
297 RefSrcNode referencer = edge.getSrc();
299 removeRefEdge( referencer,
307 protected void clearNonVarRefEdgesTo( HeapRegionNode referencee ) {
308 assert referencee != null;
310 // get a copy of the set to iterate over, otherwise
311 // we will be trying to take apart the set as we
312 // are iterating over it, which won't work
313 Iterator<RefEdge> i = referencee.iteratorToReferencersClone();
314 while( i.hasNext() ) {
315 RefEdge edge = i.next();
316 RefSrcNode referencer = edge.getSrc();
317 if( !(referencer instanceof VariableNode) ) {
318 removeRefEdge( referencer,
326 // this is a common operation in many transfer functions: we want
327 // to add an edge, but if there is already such an edge we should
328 // merge the properties of the existing and the new edges
329 protected void addEdgeOrMergeWithExisting( RefEdge edgeNew ) {
331 RefSrcNode src = edgeNew.getSrc();
332 assert belongsToThis( src );
334 HeapRegionNode dst = edgeNew.getDst();
335 assert belongsToThis( dst );
337 // look to see if an edge with same field exists
338 // and merge with it, otherwise just add the edge
339 RefEdge edgeExisting = src.getReferenceTo( dst,
344 if( edgeExisting != null ) {
345 edgeExisting.setBeta(
346 Canonical.unionORpreds( edgeExisting.getBeta(),
350 edgeExisting.setPreds(
351 Canonical.join( edgeExisting.getPreds(),
355 edgeExisting.setTaints(
356 Canonical.unionORpreds( edgeExisting.getTaints(),
362 addRefEdge( src, dst, edgeNew );
368 ////////////////////////////////////////////////////
370 // Assignment Operation Methods
372 // These methods are high-level operations for
373 // modeling program assignment statements using
374 // the low-level reference create/remove methods
377 ////////////////////////////////////////////////////
379 public void assignTempXEqualToTempY( TempDescriptor x,
381 assignTempXEqualToCastedTempY( x, y, null );
385 public void assignTempXEqualToCastedTempY( TempDescriptor x,
387 TypeDescriptor tdCast ) {
389 VariableNode lnX = getVariableNodeFromTemp( x );
390 VariableNode lnY = getVariableNodeFromTemp( y );
392 clearRefEdgesFrom( lnX, null, null, true );
394 // note it is possible that the types of temps in the
395 // flat node to analyze will reveal that some typed
396 // edges in the reachability graph are impossible
397 Set<RefEdge> impossibleEdges = new HashSet<RefEdge>();
399 Iterator<RefEdge> itrYhrn = lnY.iteratorToReferencees();
400 while( itrYhrn.hasNext() ) {
401 RefEdge edgeY = itrYhrn.next();
402 HeapRegionNode referencee = edgeY.getDst();
403 RefEdge edgeNew = edgeY.copy();
405 if( !isSuperiorType( x.getType(), edgeY.getType() ) ) {
406 impossibleEdges.add( edgeY );
410 edgeNew.setSrc( lnX );
412 if( tdCast == null ) {
413 edgeNew.setType( mostSpecificType( y.getType(),
419 edgeNew.setType( mostSpecificType( y.getType(),
421 referencee.getType(),
427 edgeNew.setField( null );
429 addRefEdge( lnX, referencee, edgeNew );
432 Iterator<RefEdge> itrImp = impossibleEdges.iterator();
433 while( itrImp.hasNext() ) {
434 RefEdge edgeImp = itrImp.next();
435 removeRefEdge( edgeImp );
440 public void assignTempXEqualToTempYFieldF( TempDescriptor x,
442 FieldDescriptor f ) {
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 hrnY = edgeY.getDst();
457 ReachSet betaY = edgeY.getBeta();
459 Iterator<RefEdge> itrHrnFhrn = hrnY.iteratorToReferencees();
460 while( itrHrnFhrn.hasNext() ) {
461 RefEdge edgeHrn = itrHrnFhrn.next();
462 HeapRegionNode hrnHrn = edgeHrn.getDst();
463 ReachSet betaHrn = edgeHrn.getBeta();
465 // prune edges that are not a matching field
466 if( edgeHrn.getType() != null &&
467 !edgeHrn.getField().equals( f.getSymbol() )
472 // check for impossible edges
473 if( !isSuperiorType( x.getType(), edgeHrn.getType() ) ) {
474 impossibleEdges.add( edgeHrn );
478 TypeDescriptor tdNewEdge =
479 mostSpecificType( edgeHrn.getType(),
483 RefEdge edgeNew = new RefEdge( lnX,
487 Canonical.intersection( betaY, betaHrn ),
492 addEdgeOrMergeWithExisting( edgeNew );
496 Iterator<RefEdge> itrImp = impossibleEdges.iterator();
497 while( itrImp.hasNext() ) {
498 RefEdge edgeImp = itrImp.next();
499 removeRefEdge( edgeImp );
502 // anytime you might remove edges between heap regions
503 // you must global sweep to clean up broken reachability
504 if( !impossibleEdges.isEmpty() ) {
505 if( !DISABLE_GLOBAL_SWEEP ) {
513 // return whether a strong update was actually effected
514 public boolean assignTempXFieldFEqualToTempY( TempDescriptor x,
518 VariableNode lnX = getVariableNodeFromTemp( x );
519 VariableNode lnY = getVariableNodeFromTemp( y );
521 HashSet<HeapRegionNode> nodesWithNewAlpha = new HashSet<HeapRegionNode>();
522 HashSet<RefEdge> edgesWithNewBeta = new HashSet<RefEdge>();
524 // note it is possible that the types of temps in the
525 // flat node to analyze will reveal that some typed
526 // edges in the reachability graph are impossible
527 Set<RefEdge> impossibleEdges = new HashSet<RefEdge>();
529 // first look for possible strong updates and remove those edges
530 boolean strongUpdateCond = false;
531 boolean edgeRemovedByStrongUpdate = false;
533 Iterator<RefEdge> itrXhrn = lnX.iteratorToReferencees();
534 while( itrXhrn.hasNext() ) {
535 RefEdge edgeX = itrXhrn.next();
536 HeapRegionNode hrnX = edgeX.getDst();
538 // we can do a strong update here if one of two cases holds
540 f != DisjointAnalysis.getArrayField( f.getType() ) &&
541 ( (hrnX.getNumReferencers() == 1) || // case 1
542 (hrnX.isSingleObject() && lnX.getNumReferencees() == 1) // case 2
545 if( !DISABLE_STRONG_UPDATES ) {
546 strongUpdateCond = true;
549 clearRefEdgesFrom( hrnX,
554 edgeRemovedByStrongUpdate = true;
560 // then do all token propagation
561 itrXhrn = lnX.iteratorToReferencees();
562 while( itrXhrn.hasNext() ) {
563 RefEdge edgeX = itrXhrn.next();
564 HeapRegionNode hrnX = edgeX.getDst();
565 ReachSet betaX = edgeX.getBeta();
566 ReachSet R = Canonical.intersection( hrnX.getAlpha(),
570 Iterator<RefEdge> itrYhrn = lnY.iteratorToReferencees();
571 while( itrYhrn.hasNext() ) {
572 RefEdge edgeY = itrYhrn.next();
573 HeapRegionNode hrnY = edgeY.getDst();
574 ReachSet O = edgeY.getBeta();
576 // check for impossible edges
577 if( !isSuperiorType( f.getType(), edgeY.getType() ) ) {
578 impossibleEdges.add( edgeY );
582 // propagate tokens over nodes starting from hrnSrc, and it will
583 // take care of propagating back up edges from any touched nodes
584 ChangeSet Cy = Canonical.unionUpArityToChangeSet( O, R );
585 propagateTokensOverNodes( hrnY, Cy, nodesWithNewAlpha, edgesWithNewBeta );
587 // then propagate back just up the edges from hrn
588 ChangeSet Cx = Canonical.unionUpArityToChangeSet( R, O );
589 HashSet<RefEdge> todoEdges = new HashSet<RefEdge>();
591 Hashtable<RefEdge, ChangeSet> edgePlannedChanges =
592 new Hashtable<RefEdge, ChangeSet>();
594 Iterator<RefEdge> referItr = hrnX.iteratorToReferencers();
595 while( referItr.hasNext() ) {
596 RefEdge edgeUpstream = referItr.next();
597 todoEdges.add( edgeUpstream );
598 edgePlannedChanges.put( edgeUpstream, Cx );
601 propagateTokensOverEdges( todoEdges,
608 // apply the updates to reachability
609 Iterator<HeapRegionNode> nodeItr = nodesWithNewAlpha.iterator();
610 while( nodeItr.hasNext() ) {
611 nodeItr.next().applyAlphaNew();
614 Iterator<RefEdge> edgeItr = edgesWithNewBeta.iterator();
615 while( edgeItr.hasNext() ) {
616 edgeItr.next().applyBetaNew();
620 // then go back through and add the new edges
621 itrXhrn = lnX.iteratorToReferencees();
622 while( itrXhrn.hasNext() ) {
623 RefEdge edgeX = itrXhrn.next();
624 HeapRegionNode hrnX = edgeX.getDst();
626 Iterator<RefEdge> itrYhrn = lnY.iteratorToReferencees();
627 while( itrYhrn.hasNext() ) {
628 RefEdge edgeY = itrYhrn.next();
629 HeapRegionNode hrnY = edgeY.getDst();
631 // skip impossible edges here, we already marked them
632 // when computing reachability propagations above
633 if( !isSuperiorType( f.getType(), edgeY.getType() ) ) {
637 // prepare the new reference edge hrnX.f -> hrnY
638 TypeDescriptor tdNewEdge =
639 mostSpecificType( y.getType(),
649 Canonical.changePredsTo(
650 Canonical.pruneBy( edgeY.getBeta(),
656 Canonical.changePredsTo( edgeY.getTaints(),
660 addEdgeOrMergeWithExisting( edgeNew );
664 Iterator<RefEdge> itrImp = impossibleEdges.iterator();
665 while( itrImp.hasNext() ) {
666 RefEdge edgeImp = itrImp.next();
667 removeRefEdge( edgeImp );
670 // if there was a strong update, make sure to improve
671 // reachability with a global sweep
672 if( edgeRemovedByStrongUpdate || !impossibleEdges.isEmpty() ) {
673 if( !DISABLE_GLOBAL_SWEEP ) {
678 return edgeRemovedByStrongUpdate;
682 public void assignReturnEqualToTemp( TempDescriptor x ) {
684 VariableNode lnR = getVariableNodeFromTemp( tdReturn );
685 VariableNode lnX = getVariableNodeFromTemp( x );
687 clearRefEdgesFrom( lnR, null, null, true );
689 Iterator<RefEdge> itrXhrn = lnX.iteratorToReferencees();
690 while( itrXhrn.hasNext() ) {
691 RefEdge edgeX = itrXhrn.next();
692 HeapRegionNode referencee = edgeX.getDst();
693 RefEdge edgeNew = edgeX.copy();
694 edgeNew.setSrc( lnR );
695 edgeNew.setTaints( Canonical.changePredsTo( edgeNew.getTaints(),
700 addRefEdge( lnR, referencee, edgeNew );
705 public void assignTempEqualToNewAlloc( TempDescriptor x,
712 // after the age operation the newest (or zero-ith oldest)
713 // node associated with the allocation site should have
714 // no references to it as if it were a newly allocated
716 Integer idNewest = as.getIthOldest( 0 );
717 HeapRegionNode hrnNewest = id2hrn.get( idNewest );
718 assert hrnNewest != null;
720 VariableNode lnX = getVariableNodeFromTemp( x );
721 clearRefEdgesFrom( lnX, null, null, true );
723 // make a new reference to allocated node
724 TypeDescriptor type = as.getType();
727 new RefEdge( lnX, // source
731 hrnNewest.getAlpha(), // beta
732 predsTrue, // predicates
733 TaintSet.factory() // taints
736 addRefEdge( lnX, hrnNewest, edgeNew );
740 // use the allocation site (unique to entire analysis) to
741 // locate the heap region nodes in this reachability graph
742 // that should be aged. The process models the allocation
743 // of new objects and collects all the oldest allocations
744 // in a summary node to allow for a finite analysis
746 // There is an additional property of this method. After
747 // running it on a particular reachability graph (many graphs
748 // may have heap regions related to the same allocation site)
749 // the heap region node objects in this reachability graph will be
750 // allocated. Therefore, after aging a graph for an allocation
751 // site, attempts to retrieve the heap region nodes using the
752 // integer id's contained in the allocation site should always
753 // return non-null heap regions.
754 public void age( AllocSite as ) {
756 // keep track of allocation sites that are represented
757 // in this graph for efficiency with other operations
758 allocSites.add( as );
760 // if there is a k-th oldest node, it merges into
762 Integer idK = as.getOldest();
763 if( id2hrn.containsKey( idK ) ) {
764 HeapRegionNode hrnK = id2hrn.get( idK );
766 // retrieve the summary node, or make it
768 HeapRegionNode hrnSummary = getSummaryNode( as, false );
770 mergeIntoSummary( hrnK, hrnSummary );
773 // move down the line of heap region nodes
774 // clobbering the ith and transferring all references
775 // to and from i-1 to node i.
776 for( int i = allocationDepth - 1; i > 0; --i ) {
778 // only do the transfer if the i-1 node exists
779 Integer idImin1th = as.getIthOldest( i - 1 );
780 if( id2hrn.containsKey( idImin1th ) ) {
781 HeapRegionNode hrnImin1 = id2hrn.get( idImin1th );
782 if( hrnImin1.isWiped() ) {
783 // there is no info on this node, just skip
787 // either retrieve or make target of transfer
788 HeapRegionNode hrnI = getIthNode( as, i, false );
790 transferOnto( hrnImin1, hrnI );
795 // as stated above, the newest node should have had its
796 // references moved over to the second oldest, so we wipe newest
797 // in preparation for being the new object to assign something to
798 HeapRegionNode hrn0 = getIthNode( as, 0, false );
799 wipeOut( hrn0, true );
801 // now tokens in reachability sets need to "age" also
802 Iterator itrAllVariableNodes = td2vn.entrySet().iterator();
803 while( itrAllVariableNodes.hasNext() ) {
804 Map.Entry me = (Map.Entry) itrAllVariableNodes.next();
805 VariableNode ln = (VariableNode) me.getValue();
807 Iterator<RefEdge> itrEdges = ln.iteratorToReferencees();
808 while( itrEdges.hasNext() ) {
809 ageTuplesFrom( as, itrEdges.next() );
813 Iterator itrAllHRNodes = id2hrn.entrySet().iterator();
814 while( itrAllHRNodes.hasNext() ) {
815 Map.Entry me = (Map.Entry) itrAllHRNodes.next();
816 HeapRegionNode hrnToAge = (HeapRegionNode) me.getValue();
818 ageTuplesFrom( as, hrnToAge );
820 Iterator<RefEdge> itrEdges = hrnToAge.iteratorToReferencees();
821 while( itrEdges.hasNext() ) {
822 ageTuplesFrom( as, itrEdges.next() );
827 // after tokens have been aged, reset newest node's reachability
828 // and a brand new node has a "true" predicate
829 hrn0.setAlpha( hrn0.getInherent() );
830 hrn0.setPreds( predsTrue );
834 // either retrieve or create the needed heap region node
835 protected HeapRegionNode getSummaryNode( AllocSite as,
840 idSummary = as.getSummaryShadow();
842 idSummary = as.getSummary();
845 HeapRegionNode hrnSummary = id2hrn.get( idSummary );
847 if( hrnSummary == null ) {
849 String strDesc = as.toStringForDOT()+"\\nsummary";
852 createNewHeapRegionNode( idSummary, // id or null to generate a new one
853 false, // single object?
855 false, // out-of-context?
856 as.getType(), // type
857 as, // allocation site
858 null, // inherent reach
859 null, // current reach
860 predsEmpty, // predicates
861 strDesc // description
868 // either retrieve or create the needed heap region node
869 protected HeapRegionNode getIthNode( AllocSite as,
875 idIth = as.getIthOldestShadow( i );
877 idIth = as.getIthOldest( i );
880 HeapRegionNode hrnIth = id2hrn.get( idIth );
882 if( hrnIth == null ) {
884 String strDesc = as.toStringForDOT()+"\\n"+i+" oldest";
886 hrnIth = createNewHeapRegionNode( idIth, // id or null to generate a new one
887 true, // single object?
889 false, // out-of-context?
890 as.getType(), // type
891 as, // allocation site
892 null, // inherent reach
893 null, // current reach
894 predsEmpty, // predicates
895 strDesc // description
903 protected void mergeIntoSummary( HeapRegionNode hrn,
904 HeapRegionNode hrnSummary ) {
905 assert hrnSummary.isNewSummary();
907 // assert that these nodes belong to THIS graph
908 assert belongsToThis( hrn );
909 assert belongsToThis( hrnSummary );
911 assert hrn != hrnSummary;
913 // transfer references _from_ hrn over to hrnSummary
914 Iterator<RefEdge> itrReferencee = hrn.iteratorToReferencees();
915 while( itrReferencee.hasNext() ) {
916 RefEdge edge = itrReferencee.next();
917 RefEdge edgeMerged = edge.copy();
918 edgeMerged.setSrc( hrnSummary );
920 HeapRegionNode hrnReferencee = edge.getDst();
921 RefEdge edgeSummary =
922 hrnSummary.getReferenceTo( hrnReferencee,
927 if( edgeSummary == null ) {
928 // the merge is trivial, nothing to be done
929 addRefEdge( hrnSummary, hrnReferencee, edgeMerged );
932 // otherwise an edge from the referencer to hrnSummary exists already
933 // and the edge referencer->hrn should be merged with it
935 Canonical.unionORpreds( edgeMerged.getBeta(),
936 edgeSummary.getBeta()
939 edgeSummary.setPreds(
940 Canonical.join( edgeMerged.getPreds(),
941 edgeSummary.getPreds()
947 // next transfer references _to_ hrn over to hrnSummary
948 Iterator<RefEdge> itrReferencer = hrn.iteratorToReferencers();
949 while( itrReferencer.hasNext() ) {
950 RefEdge edge = itrReferencer.next();
951 RefEdge edgeMerged = edge.copy();
952 edgeMerged.setDst( hrnSummary );
954 RefSrcNode onReferencer = edge.getSrc();
955 RefEdge edgeSummary =
956 onReferencer.getReferenceTo( hrnSummary,
961 if( edgeSummary == null ) {
962 // the merge is trivial, nothing to be done
963 addRefEdge( onReferencer, hrnSummary, edgeMerged );
966 // otherwise an edge from the referencer to alpha_S exists already
967 // and the edge referencer->alpha_K should be merged with it
969 Canonical.unionORpreds( edgeMerged.getBeta(),
970 edgeSummary.getBeta()
973 edgeSummary.setPreds(
974 Canonical.join( edgeMerged.getPreds(),
975 edgeSummary.getPreds()
981 // then merge hrn reachability into hrnSummary
983 Canonical.unionORpreds( hrnSummary.getAlpha(),
989 Canonical.join( hrnSummary.getPreds(),
994 // and afterward, this node is gone
995 wipeOut( hrn, true );
999 protected void transferOnto( HeapRegionNode hrnA,
1000 HeapRegionNode hrnB ) {
1002 assert belongsToThis( hrnA );
1003 assert belongsToThis( hrnB );
1004 assert hrnA != hrnB;
1006 // clear references in and out of node b?
1007 assert hrnB.isWiped();
1009 // copy each: (edge in and out of A) to B
1010 Iterator<RefEdge> itrReferencee = hrnA.iteratorToReferencees();
1011 while( itrReferencee.hasNext() ) {
1012 RefEdge edge = itrReferencee.next();
1013 HeapRegionNode hrnReferencee = edge.getDst();
1014 RefEdge edgeNew = edge.copy();
1015 edgeNew.setSrc( hrnB );
1016 edgeNew.setDst( hrnReferencee );
1018 addRefEdge( hrnB, hrnReferencee, edgeNew );
1021 Iterator<RefEdge> itrReferencer = hrnA.iteratorToReferencers();
1022 while( itrReferencer.hasNext() ) {
1023 RefEdge edge = itrReferencer.next();
1024 RefSrcNode rsnReferencer = edge.getSrc();
1025 RefEdge edgeNew = edge.copy();
1026 edgeNew.setSrc( rsnReferencer );
1027 edgeNew.setDst( hrnB );
1029 addRefEdge( rsnReferencer, hrnB, edgeNew );
1032 // replace hrnB reachability and preds with hrnA's
1033 hrnB.setAlpha( hrnA.getAlpha() );
1034 hrnB.setPreds( hrnA.getPreds() );
1036 // after transfer, wipe out source
1037 wipeOut( hrnA, true );
1041 // the purpose of this method is to conceptually "wipe out"
1042 // a heap region from the graph--purposefully not called REMOVE
1043 // because the node is still hanging around in the graph, just
1044 // not mechanically connected or have any reach or predicate
1045 // information on it anymore--lots of ops can use this
1046 protected void wipeOut( HeapRegionNode hrn,
1047 boolean wipeVariableReferences ) {
1049 assert belongsToThis( hrn );
1051 clearRefEdgesFrom( hrn, null, null, true );
1053 if( wipeVariableReferences ) {
1054 clearRefEdgesTo( hrn, null, null, true );
1056 clearNonVarRefEdgesTo( hrn );
1059 hrn.setAlpha( rsetEmpty );
1060 hrn.setPreds( predsEmpty );
1064 protected void ageTuplesFrom( AllocSite as, RefEdge edge ) {
1066 Canonical.ageTuplesFrom( edge.getBeta(),
1072 protected void ageTuplesFrom( AllocSite as, HeapRegionNode hrn ) {
1074 Canonical.ageTuplesFrom( hrn.getAlpha(),
1082 protected void propagateTokensOverNodes( HeapRegionNode nPrime,
1084 HashSet<HeapRegionNode> nodesWithNewAlpha,
1085 HashSet<RefEdge> edgesWithNewBeta ) {
1087 HashSet<HeapRegionNode> todoNodes
1088 = new HashSet<HeapRegionNode>();
1089 todoNodes.add( nPrime );
1091 HashSet<RefEdge> todoEdges
1092 = new HashSet<RefEdge>();
1094 Hashtable<HeapRegionNode, ChangeSet> nodePlannedChanges
1095 = new Hashtable<HeapRegionNode, ChangeSet>();
1096 nodePlannedChanges.put( nPrime, c0 );
1098 Hashtable<RefEdge, ChangeSet> edgePlannedChanges
1099 = new Hashtable<RefEdge, ChangeSet>();
1101 // first propagate change sets everywhere they can go
1102 while( !todoNodes.isEmpty() ) {
1103 HeapRegionNode n = todoNodes.iterator().next();
1104 ChangeSet C = nodePlannedChanges.get( n );
1106 Iterator<RefEdge> referItr = n.iteratorToReferencers();
1107 while( referItr.hasNext() ) {
1108 RefEdge edge = referItr.next();
1109 todoEdges.add( edge );
1111 if( !edgePlannedChanges.containsKey( edge ) ) {
1112 edgePlannedChanges.put( edge,
1117 edgePlannedChanges.put( edge,
1118 Canonical.union( edgePlannedChanges.get( edge ),
1124 Iterator<RefEdge> refeeItr = n.iteratorToReferencees();
1125 while( refeeItr.hasNext() ) {
1126 RefEdge edgeF = refeeItr.next();
1127 HeapRegionNode m = edgeF.getDst();
1129 ChangeSet changesToPass = ChangeSet.factory();
1131 Iterator<ChangeTuple> itrCprime = C.iterator();
1132 while( itrCprime.hasNext() ) {
1133 ChangeTuple c = itrCprime.next();
1134 if( edgeF.getBeta().containsIgnorePreds( c.getStateToMatch() )
1137 changesToPass = Canonical.add( changesToPass, c );
1141 if( !changesToPass.isEmpty() ) {
1142 if( !nodePlannedChanges.containsKey( m ) ) {
1143 nodePlannedChanges.put( m, ChangeSet.factory() );
1146 ChangeSet currentChanges = nodePlannedChanges.get( m );
1148 if( !changesToPass.isSubset( currentChanges ) ) {
1150 nodePlannedChanges.put( m,
1151 Canonical.union( currentChanges,
1160 todoNodes.remove( n );
1163 // then apply all of the changes for each node at once
1164 Iterator itrMap = nodePlannedChanges.entrySet().iterator();
1165 while( itrMap.hasNext() ) {
1166 Map.Entry me = (Map.Entry) itrMap.next();
1167 HeapRegionNode n = (HeapRegionNode) me.getKey();
1168 ChangeSet C = (ChangeSet) me.getValue();
1170 // this propagation step is with respect to one change,
1171 // so we capture the full change from the old alpha:
1172 ReachSet localDelta = Canonical.applyChangeSet( n.getAlpha(),
1176 // but this propagation may be only one of many concurrent
1177 // possible changes, so keep a running union with the node's
1178 // partially updated new alpha set
1179 n.setAlphaNew( Canonical.unionORpreds( n.getAlphaNew(),
1184 nodesWithNewAlpha.add( n );
1187 propagateTokensOverEdges( todoEdges,
1194 protected void propagateTokensOverEdges( HashSet <RefEdge> todoEdges,
1195 Hashtable<RefEdge, ChangeSet> edgePlannedChanges,
1196 HashSet <RefEdge> edgesWithNewBeta ) {
1198 // first propagate all change tuples everywhere they can go
1199 while( !todoEdges.isEmpty() ) {
1200 RefEdge edgeE = todoEdges.iterator().next();
1201 todoEdges.remove( edgeE );
1203 if( !edgePlannedChanges.containsKey( edgeE ) ) {
1204 edgePlannedChanges.put( edgeE,
1209 ChangeSet C = edgePlannedChanges.get( edgeE );
1211 ChangeSet changesToPass = ChangeSet.factory();
1213 Iterator<ChangeTuple> itrC = C.iterator();
1214 while( itrC.hasNext() ) {
1215 ChangeTuple c = itrC.next();
1216 if( edgeE.getBeta().containsIgnorePreds( c.getStateToMatch() )
1219 changesToPass = Canonical.add( changesToPass, c );
1223 RefSrcNode rsn = edgeE.getSrc();
1225 if( !changesToPass.isEmpty() && rsn instanceof HeapRegionNode ) {
1226 HeapRegionNode n = (HeapRegionNode) rsn;
1228 Iterator<RefEdge> referItr = n.iteratorToReferencers();
1229 while( referItr.hasNext() ) {
1230 RefEdge edgeF = referItr.next();
1232 if( !edgePlannedChanges.containsKey( edgeF ) ) {
1233 edgePlannedChanges.put( edgeF,
1238 ChangeSet currentChanges = edgePlannedChanges.get( edgeF );
1240 if( !changesToPass.isSubset( currentChanges ) ) {
1241 todoEdges.add( edgeF );
1242 edgePlannedChanges.put( edgeF,
1243 Canonical.union( currentChanges,
1252 // then apply all of the changes for each edge at once
1253 Iterator itrMap = edgePlannedChanges.entrySet().iterator();
1254 while( itrMap.hasNext() ) {
1255 Map.Entry me = (Map.Entry) itrMap.next();
1256 RefEdge e = (RefEdge) me.getKey();
1257 ChangeSet C = (ChangeSet) me.getValue();
1259 // this propagation step is with respect to one change,
1260 // so we capture the full change from the old beta:
1261 ReachSet localDelta =
1262 Canonical.applyChangeSet( e.getBeta(),
1267 // but this propagation may be only one of many concurrent
1268 // possible changes, so keep a running union with the edge's
1269 // partially updated new beta set
1270 e.setBetaNew( Canonical.unionORpreds( e.getBetaNew(),
1275 edgesWithNewBeta.add( e );
1280 public void taintInSetVars( FlatSESEEnterNode sese ) {
1281 if( sese.getIsCallerSESEplaceholder() ) {
1285 Iterator<TempDescriptor> isvItr = sese.getInVarSet().iterator();
1286 while( isvItr.hasNext() ) {
1287 TempDescriptor isv = isvItr.next();
1289 // in-set var taints should NOT propagate back into callers
1290 // so give it FALSE(EMPTY) predicates
1299 public void taintStallSite( FlatNode stallSite,
1300 TempDescriptor var ) {
1302 // stall site taint should propagate back into callers
1303 // so give it TRUE predicates
1311 protected void taintTemp( FlatSESEEnterNode sese,
1317 VariableNode vn = getVariableNodeFromTemp( var );
1319 Iterator<RefEdge> reItr = vn.iteratorToReferencees();
1320 while( reItr.hasNext() ) {
1321 RefEdge re = reItr.next();
1323 Taint taint = Taint.factory( sese,
1326 re.getDst().getAllocSite(),
1330 re.setTaints( Canonical.add( re.getTaints(),
1337 public void removeInContextTaints( FlatSESEEnterNode sese ) {
1338 if( sese.getIsCallerSESEplaceholder() ) {
1342 Iterator meItr = id2hrn.entrySet().iterator();
1343 while( meItr.hasNext() ) {
1344 Map.Entry me = (Map.Entry) meItr.next();
1345 Integer id = (Integer) me.getKey();
1346 HeapRegionNode hrn = (HeapRegionNode) me.getValue();
1348 Iterator<RefEdge> reItr = hrn.iteratorToReferencers();
1349 while( reItr.hasNext() ) {
1350 RefEdge re = reItr.next();
1352 re.setTaints( Canonical.removeTaintsBy( re.getTaints(),
1360 public void removeAllStallSiteTaints() {
1362 Iterator meItr = id2hrn.entrySet().iterator();
1363 while( meItr.hasNext() ) {
1364 Map.Entry me = (Map.Entry) meItr.next();
1365 Integer id = (Integer) me.getKey();
1366 HeapRegionNode hrn = (HeapRegionNode) me.getValue();
1368 Iterator<RefEdge> reItr = hrn.iteratorToReferencers();
1369 while( reItr.hasNext() ) {
1370 RefEdge re = reItr.next();
1372 re.setTaints( Canonical.removeStallSiteTaints( re.getTaints()
1380 // used in makeCalleeView below to decide if there is
1381 // already an appropriate out-of-context edge in a callee
1382 // view graph for merging, or null if a new one will be added
1384 getOutOfContextReferenceTo( HeapRegionNode hrn,
1385 TypeDescriptor srcType,
1386 TypeDescriptor refType,
1388 assert belongsToThis( hrn );
1390 HeapRegionNode hrnInContext = id2hrn.get( hrn.getID() );
1391 if( hrnInContext == null ) {
1395 Iterator<RefEdge> refItr = hrnInContext.iteratorToReferencers();
1396 while( refItr.hasNext() ) {
1397 RefEdge re = refItr.next();
1399 assert belongsToThis( re.getSrc() );
1400 assert belongsToThis( re.getDst() );
1402 if( !(re.getSrc() instanceof HeapRegionNode) ) {
1406 HeapRegionNode hrnSrc = (HeapRegionNode) re.getSrc();
1407 if( !hrnSrc.isOutOfContext() ) {
1411 if( srcType == null ) {
1412 if( hrnSrc.getType() != null ) {
1416 if( !srcType.equals( hrnSrc.getType() ) ) {
1421 if( !re.typeEquals( refType ) ) {
1425 if( !re.fieldEquals( refField ) ) {
1429 // tada! We found it!
1436 // used below to convert a ReachSet to its callee-context
1437 // equivalent with respect to allocation sites in this graph
1438 protected ReachSet toCalleeContext( ReachSet rs,
1439 ExistPredSet predsNodeOrEdge,
1440 Set<HrnIdOoc> oocHrnIdOoc2callee
1442 ReachSet out = ReachSet.factory();
1444 Iterator<ReachState> itr = rs.iterator();
1445 while( itr.hasNext() ) {
1446 ReachState stateCaller = itr.next();
1448 ReachState stateCallee = stateCaller;
1450 Iterator<AllocSite> asItr = allocSites.iterator();
1451 while( asItr.hasNext() ) {
1452 AllocSite as = asItr.next();
1454 ReachState stateNew = ReachState.factory();
1455 Iterator<ReachTuple> rtItr = stateCallee.iterator();
1456 while( rtItr.hasNext() ) {
1457 ReachTuple rt = rtItr.next();
1459 // only translate this tuple if it is
1460 // in the out-callee-context bag
1461 HrnIdOoc hio = new HrnIdOoc( rt.getHrnID(),
1464 if( !oocHrnIdOoc2callee.contains( hio ) ) {
1465 stateNew = Canonical.addUpArity( stateNew, rt );
1469 int age = as.getAgeCategory( rt.getHrnID() );
1471 // this is the current mapping, where 0, 1, 2S were allocated
1472 // in the current context, 0?, 1? and 2S? were allocated in a
1473 // previous context, and we're translating to a future context
1485 if( age == AllocSite.AGE_notInThisSite ) {
1486 // things not from the site just go back in
1487 stateNew = Canonical.addUpArity( stateNew, rt );
1489 } else if( age == AllocSite.AGE_summary ||
1493 stateNew = Canonical.addUpArity( stateNew,
1494 ReachTuple.factory( as.getSummary(),
1497 true // out-of-context
1502 // otherwise everything else just goes to an out-of-context
1503 // version, everything else the same
1504 Integer I = as.getAge( rt.getHrnID() );
1507 assert !rt.isMultiObject();
1509 stateNew = Canonical.addUpArity( stateNew,
1510 ReachTuple.factory( rt.getHrnID(),
1511 rt.isMultiObject(), // multi
1513 true // out-of-context
1519 stateCallee = stateNew;
1522 // make a predicate of the caller graph element
1523 // and the caller state we just converted
1524 ExistPredSet predsWithState = ExistPredSet.factory();
1526 Iterator<ExistPred> predItr = predsNodeOrEdge.iterator();
1527 while( predItr.hasNext() ) {
1528 ExistPred predNodeOrEdge = predItr.next();
1531 Canonical.add( predsWithState,
1532 ExistPred.factory( predNodeOrEdge.n_hrnID,
1533 predNodeOrEdge.e_tdSrc,
1534 predNodeOrEdge.e_hrnSrcID,
1535 predNodeOrEdge.e_hrnDstID,
1536 predNodeOrEdge.e_type,
1537 predNodeOrEdge.e_field,
1540 predNodeOrEdge.e_srcOutCalleeContext,
1541 predNodeOrEdge.e_srcOutCallerContext
1546 stateCallee = Canonical.changePredsTo( stateCallee,
1549 out = Canonical.add( out,
1553 assert out.isCanonical();
1557 // used below to convert a ReachSet to its caller-context
1558 // equivalent with respect to allocation sites in this graph
1560 toCallerContext( ReachSet rs,
1561 Hashtable<ReachState, ExistPredSet> calleeStatesSatisfied
1563 ReachSet out = ReachSet.factory();
1565 // when the mapping is null it means there were no
1566 // predicates satisfied
1567 if( calleeStatesSatisfied == null ) {
1571 Iterator<ReachState> itr = rs.iterator();
1572 while( itr.hasNext() ) {
1573 ReachState stateCallee = itr.next();
1575 if( calleeStatesSatisfied.containsKey( stateCallee ) ) {
1577 // starting from one callee state...
1578 ReachSet rsCaller = ReachSet.factory( stateCallee );
1580 // possibly branch it into many states, which any
1581 // allocation site might do, so lots of derived states
1582 Iterator<AllocSite> asItr = allocSites.iterator();
1583 while( asItr.hasNext() ) {
1584 AllocSite as = asItr.next();
1585 rsCaller = Canonical.toCallerContext( rsCaller, as );
1588 // then before adding each derived, now caller-context
1589 // states to the output, attach the appropriate pred
1590 // based on the source callee state
1591 Iterator<ReachState> stateItr = rsCaller.iterator();
1592 while( stateItr.hasNext() ) {
1593 ReachState stateCaller = stateItr.next();
1594 stateCaller = Canonical.attach( stateCaller,
1595 calleeStatesSatisfied.get( stateCallee )
1597 out = Canonical.add( out,
1604 assert out.isCanonical();
1609 // used below to convert a ReachSet to an equivalent
1610 // version with shadow IDs merged into unshadowed IDs
1611 protected ReachSet unshadow( ReachSet rs ) {
1613 Iterator<AllocSite> asItr = allocSites.iterator();
1614 while( asItr.hasNext() ) {
1615 AllocSite as = asItr.next();
1616 out = Canonical.unshadow( out, as );
1618 assert out.isCanonical();
1623 // convert a caller taint set into a callee taint set
1625 toCalleeContext( TaintSet ts,
1626 ExistPredSet predsEdge ) {
1628 TaintSet out = TaintSet.factory();
1630 // the idea is easy, the taint identifier itself doesn't
1631 // change at all, but the predicates should be tautology:
1632 // start with the preds passed in from the caller edge
1633 // that host the taints, and alter them to have the taint
1634 // added, just becoming more specific than edge predicate alone
1636 Iterator<Taint> itr = ts.iterator();
1637 while( itr.hasNext() ) {
1638 Taint tCaller = itr.next();
1640 ExistPredSet predsWithTaint = ExistPredSet.factory();
1642 Iterator<ExistPred> predItr = predsEdge.iterator();
1643 while( predItr.hasNext() ) {
1644 ExistPred predEdge = predItr.next();
1647 Canonical.add( predsWithTaint,
1648 ExistPred.factory( predEdge.e_tdSrc,
1649 predEdge.e_hrnSrcID,
1650 predEdge.e_hrnDstID,
1655 predEdge.e_srcOutCalleeContext,
1656 predEdge.e_srcOutCallerContext
1661 Taint tCallee = Canonical.changePredsTo( tCaller,
1664 out = Canonical.add( out,
1669 assert out.isCanonical();
1674 // used below to convert a TaintSet to its caller-context
1675 // equivalent, just eliminate Taints with bad preds
1677 toCallerContext( TaintSet ts,
1678 Hashtable<Taint, ExistPredSet> calleeTaintsSatisfied
1681 TaintSet out = TaintSet.factory();
1683 // when the mapping is null it means there were no
1684 // predicates satisfied
1685 if( calleeTaintsSatisfied == null ) {
1689 Iterator<Taint> itr = ts.iterator();
1690 while( itr.hasNext() ) {
1691 Taint tCallee = itr.next();
1693 if( calleeTaintsSatisfied.containsKey( tCallee ) ) {
1696 Canonical.attach( Taint.factory( tCallee.sese,
1700 ExistPredSet.factory() ),
1701 calleeTaintsSatisfied.get( tCallee )
1703 out = Canonical.add( out,
1709 assert out.isCanonical();
1716 // use this method to make a new reach graph that is
1717 // what heap the FlatMethod callee from the FlatCall
1718 // would start with reaching from its arguments in
1721 makeCalleeView( FlatCall fc,
1722 FlatMethod fmCallee,
1723 Set<Integer> callerNodeIDsCopiedToCallee,
1724 boolean writeDebugDOTs
1728 // first traverse this context to find nodes and edges
1729 // that will be callee-reachable
1730 Set<HeapRegionNode> reachableCallerNodes =
1731 new HashSet<HeapRegionNode>();
1733 // caller edges between callee-reachable nodes
1734 Set<RefEdge> reachableCallerEdges =
1735 new HashSet<RefEdge>();
1737 // caller edges from arg vars, and the matching param index
1738 // because these become a special edge in callee
1739 Hashtable<RefEdge, Integer> reachableCallerArgEdges2paramIndex =
1740 new Hashtable<RefEdge, Integer>();
1742 // caller edges from local vars or callee-unreachable nodes
1743 // (out-of-context sources) to callee-reachable nodes
1744 Set<RefEdge> oocCallerEdges =
1745 new HashSet<RefEdge>();
1748 for( int i = 0; i < fmCallee.numParameters(); ++i ) {
1750 TempDescriptor tdArg = fc.getArgMatchingParamIndex( fmCallee, i );
1751 VariableNode vnArgCaller = this.getVariableNodeFromTemp( tdArg );
1753 Set<RefSrcNode> toVisitInCaller = new HashSet<RefSrcNode>();
1754 Set<RefSrcNode> visitedInCaller = new HashSet<RefSrcNode>();
1756 toVisitInCaller.add( vnArgCaller );
1758 while( !toVisitInCaller.isEmpty() ) {
1759 RefSrcNode rsnCaller = toVisitInCaller.iterator().next();
1760 toVisitInCaller.remove( rsnCaller );
1761 visitedInCaller.add( rsnCaller );
1763 Iterator<RefEdge> itrRefEdges = rsnCaller.iteratorToReferencees();
1764 while( itrRefEdges.hasNext() ) {
1765 RefEdge reCaller = itrRefEdges.next();
1766 HeapRegionNode hrnCaller = reCaller.getDst();
1768 callerNodeIDsCopiedToCallee.add( hrnCaller.getID() );
1769 reachableCallerNodes.add( hrnCaller );
1771 if( reCaller.getSrc() instanceof HeapRegionNode ) {
1772 reachableCallerEdges.add( reCaller );
1774 if( rsnCaller.equals( vnArgCaller ) ) {
1775 reachableCallerArgEdges2paramIndex.put( reCaller, i );
1777 oocCallerEdges.add( reCaller );
1781 if( !visitedInCaller.contains( hrnCaller ) ) {
1782 toVisitInCaller.add( hrnCaller );
1785 } // end edge iteration
1786 } // end visiting heap nodes in caller
1787 } // end iterating over parameters as starting points
1790 // now collect out-of-callee-context IDs and
1791 // map them to whether the ID is out of the caller
1793 Set<HrnIdOoc> oocHrnIdOoc2callee = new HashSet<HrnIdOoc>();
1795 Iterator<Integer> itrInContext =
1796 callerNodeIDsCopiedToCallee.iterator();
1797 while( itrInContext.hasNext() ) {
1798 Integer hrnID = itrInContext.next();
1799 HeapRegionNode hrnCallerAndInContext = id2hrn.get( hrnID );
1801 Iterator<RefEdge> itrMightCross =
1802 hrnCallerAndInContext.iteratorToReferencers();
1803 while( itrMightCross.hasNext() ) {
1804 RefEdge edgeMightCross = itrMightCross.next();
1806 RefSrcNode rsnCallerAndOutContext =
1807 edgeMightCross.getSrc();
1809 if( rsnCallerAndOutContext instanceof VariableNode ) {
1810 // variables do not have out-of-context reach states,
1812 oocCallerEdges.add( edgeMightCross );
1816 HeapRegionNode hrnCallerAndOutContext =
1817 (HeapRegionNode) rsnCallerAndOutContext;
1819 // is this source node out-of-context?
1820 if( callerNodeIDsCopiedToCallee.contains( hrnCallerAndOutContext.getID() ) ) {
1821 // no, skip this edge
1826 oocCallerEdges.add( edgeMightCross );
1828 // add all reach tuples on the node to list
1829 // of things that are out-of-context: insight
1830 // if this node is reachable from someting that WAS
1831 // in-context, then this node should already be in-context
1832 Iterator<ReachState> stateItr = hrnCallerAndOutContext.getAlpha().iterator();
1833 while( stateItr.hasNext() ) {
1834 ReachState state = stateItr.next();
1836 Iterator<ReachTuple> rtItr = state.iterator();
1837 while( rtItr.hasNext() ) {
1838 ReachTuple rt = rtItr.next();
1840 oocHrnIdOoc2callee.add( new HrnIdOoc( rt.getHrnID(),
1849 // the callee view is a new graph: DON'T MODIFY *THIS* graph
1850 ReachGraph rg = new ReachGraph();
1852 // add nodes to callee graph
1853 Iterator<HeapRegionNode> hrnItr = reachableCallerNodes.iterator();
1854 while( hrnItr.hasNext() ) {
1855 HeapRegionNode hrnCaller = hrnItr.next();
1857 assert callerNodeIDsCopiedToCallee.contains( hrnCaller.getID() );
1858 assert !rg.id2hrn.containsKey( hrnCaller.getID() );
1860 ExistPred pred = ExistPred.factory( hrnCaller.getID(), null );
1861 ExistPredSet preds = ExistPredSet.factory( pred );
1863 rg.createNewHeapRegionNode( hrnCaller.getID(),
1864 hrnCaller.isSingleObject(),
1865 hrnCaller.isNewSummary(),
1866 false, // out-of-context?
1867 hrnCaller.getType(),
1868 hrnCaller.getAllocSite(),
1869 toCalleeContext( hrnCaller.getInherent(),
1873 toCalleeContext( hrnCaller.getAlpha(),
1878 hrnCaller.getDescription()
1882 // add param edges to callee graph
1884 reachableCallerArgEdges2paramIndex.entrySet().iterator();
1885 while( argEdges.hasNext() ) {
1886 Map.Entry me = (Map.Entry) argEdges.next();
1887 RefEdge reArg = (RefEdge) me.getKey();
1888 Integer index = (Integer) me.getValue();
1890 VariableNode vnCaller = (VariableNode) reArg.getSrc();
1891 TempDescriptor argCaller = vnCaller.getTempDescriptor();
1893 TempDescriptor paramCallee = fmCallee.getParameter( index );
1894 VariableNode vnCallee = rg.getVariableNodeFromTemp( paramCallee );
1896 HeapRegionNode hrnDstCaller = reArg.getDst();
1897 HeapRegionNode hrnDstCallee = rg.id2hrn.get( hrnDstCaller.getID() );
1898 assert hrnDstCallee != null;
1901 ExistPred.factory( argCaller,
1903 hrnDstCallee.getID(),
1908 true, // out-of-callee-context
1909 false // out-of-caller-context
1912 ExistPredSet preds =
1913 ExistPredSet.factory( pred );
1916 new RefEdge( vnCallee,
1920 toCalleeContext( reArg.getBeta(),
1925 toCalleeContext( reArg.getTaints(),
1929 rg.addRefEdge( vnCallee,
1935 // add in-context edges to callee graph
1936 Iterator<RefEdge> reItr = reachableCallerEdges.iterator();
1937 while( reItr.hasNext() ) {
1938 RefEdge reCaller = reItr.next();
1939 RefSrcNode rsnCaller = reCaller.getSrc();
1940 assert rsnCaller instanceof HeapRegionNode;
1941 HeapRegionNode hrnSrcCaller = (HeapRegionNode) rsnCaller;
1942 HeapRegionNode hrnDstCaller = reCaller.getDst();
1944 HeapRegionNode hrnSrcCallee = rg.id2hrn.get( hrnSrcCaller.getID() );
1945 HeapRegionNode hrnDstCallee = rg.id2hrn.get( hrnDstCaller.getID() );
1946 assert hrnSrcCallee != null;
1947 assert hrnDstCallee != null;
1950 ExistPred.factory( null,
1951 hrnSrcCallee.getID(),
1952 hrnDstCallee.getID(),
1954 reCaller.getField(),
1957 false, // out-of-callee-context
1958 false // out-of-caller-context
1961 ExistPredSet preds =
1962 ExistPredSet.factory( pred );
1965 new RefEdge( hrnSrcCallee,
1968 reCaller.getField(),
1969 toCalleeContext( reCaller.getBeta(),
1974 TaintSet.factory() // no taints for in-context edges
1977 rg.addRefEdge( hrnSrcCallee,
1983 // add out-of-context edges to callee graph
1984 reItr = oocCallerEdges.iterator();
1985 while( reItr.hasNext() ) {
1986 RefEdge reCaller = reItr.next();
1987 RefSrcNode rsnCaller = reCaller.getSrc();
1988 HeapRegionNode hrnDstCaller = reCaller.getDst();
1989 HeapRegionNode hrnDstCallee = rg.id2hrn.get( hrnDstCaller.getID() );
1990 assert hrnDstCallee != null;
1992 TypeDescriptor oocNodeType;
1994 TempDescriptor oocPredSrcTemp = null;
1995 Integer oocPredSrcID = null;
1996 boolean outOfCalleeContext;
1997 boolean outOfCallerContext;
1999 if( rsnCaller instanceof VariableNode ) {
2000 VariableNode vnCaller = (VariableNode) rsnCaller;
2002 oocReach = rsetEmpty;
2003 oocPredSrcTemp = vnCaller.getTempDescriptor();
2004 outOfCalleeContext = true;
2005 outOfCallerContext = false;
2008 HeapRegionNode hrnSrcCaller = (HeapRegionNode) rsnCaller;
2009 assert !callerNodeIDsCopiedToCallee.contains( hrnSrcCaller.getID() );
2010 oocNodeType = hrnSrcCaller.getType();
2011 oocReach = hrnSrcCaller.getAlpha();
2012 oocPredSrcID = hrnSrcCaller.getID();
2013 if( hrnSrcCaller.isOutOfContext() ) {
2014 outOfCalleeContext = false;
2015 outOfCallerContext = true;
2017 outOfCalleeContext = true;
2018 outOfCallerContext = false;
2023 ExistPred.factory( oocPredSrcTemp,
2025 hrnDstCallee.getID(),
2027 reCaller.getField(),
2034 ExistPredSet preds =
2035 ExistPredSet.factory( pred );
2037 RefEdge oocEdgeExisting =
2038 rg.getOutOfContextReferenceTo( hrnDstCallee,
2044 if( oocEdgeExisting == null ) {
2045 // for consistency, map one out-of-context "identifier"
2046 // to one heap region node id, otherwise no convergence
2047 String oocid = "oocid"+
2049 hrnDstCallee.getIDString()+
2052 reCaller.getField();
2054 Integer oocHrnID = oocid2hrnid.get( oocid );
2056 HeapRegionNode hrnCalleeAndOutContext;
2058 if( oocHrnID == null ) {
2060 hrnCalleeAndOutContext =
2061 rg.createNewHeapRegionNode( null, // ID
2062 false, // single object?
2063 false, // new summary?
2064 true, // out-of-context?
2066 null, // alloc site, shouldn't be used
2067 toCalleeContext( oocReach,
2071 toCalleeContext( oocReach,
2079 oocid2hrnid.put( oocid, hrnCalleeAndOutContext.getID() );
2083 // the mapping already exists, so see if node is there
2084 hrnCalleeAndOutContext = rg.id2hrn.get( oocHrnID );
2086 if( hrnCalleeAndOutContext == null ) {
2088 hrnCalleeAndOutContext =
2089 rg.createNewHeapRegionNode( oocHrnID, // ID
2090 false, // single object?
2091 false, // new summary?
2092 true, // out-of-context?
2094 null, // alloc site, shouldn't be used
2095 toCalleeContext( oocReach,
2099 toCalleeContext( oocReach,
2108 // otherwise it is there, so merge reachability
2109 hrnCalleeAndOutContext.setAlpha( Canonical.unionORpreds( hrnCalleeAndOutContext.getAlpha(),
2110 toCalleeContext( oocReach,
2119 assert hrnCalleeAndOutContext.reachHasOnlyOOC();
2121 rg.addRefEdge( hrnCalleeAndOutContext,
2123 new RefEdge( hrnCalleeAndOutContext,
2126 reCaller.getField(),
2127 toCalleeContext( reCaller.getBeta(),
2132 toCalleeContext( reCaller.getTaints(),
2138 // the out-of-context edge already exists
2139 oocEdgeExisting.setBeta( Canonical.unionORpreds( oocEdgeExisting.getBeta(),
2140 toCalleeContext( reCaller.getBeta(),
2147 oocEdgeExisting.setPreds( Canonical.join( oocEdgeExisting.getPreds(),
2152 oocEdgeExisting.setTaints( Canonical.unionORpreds( oocEdgeExisting.getTaints(),
2153 toCalleeContext( reCaller.getTaints(),
2159 HeapRegionNode hrnCalleeAndOutContext =
2160 (HeapRegionNode) oocEdgeExisting.getSrc();
2161 hrnCalleeAndOutContext.setAlpha( Canonical.unionORpreds( hrnCalleeAndOutContext.getAlpha(),
2162 toCalleeContext( oocReach,
2169 assert hrnCalleeAndOutContext.reachHasOnlyOOC();
2174 if( writeDebugDOTs ) {
2175 debugGraphPrefix = String.format( "call%03d", debugCallSiteVisitCounter );
2176 rg.writeGraph( debugGraphPrefix+"calleeview",
2177 resolveMethodDebugDOTwriteLabels,
2178 resolveMethodDebugDOTselectTemps,
2179 resolveMethodDebugDOTpruneGarbage,
2180 resolveMethodDebugDOThideReach,
2181 resolveMethodDebugDOThideSubsetReach,
2182 resolveMethodDebugDOThidePreds,
2183 resolveMethodDebugDOThideEdgeTaints );
2189 private static Hashtable<String, Integer> oocid2hrnid =
2190 new Hashtable<String, Integer>();
2193 // useful since many graphs writes in the method call debug code
2194 private static boolean resolveMethodDebugDOTwriteLabels = true;
2195 private static boolean resolveMethodDebugDOTselectTemps = true;
2196 private static boolean resolveMethodDebugDOTpruneGarbage = true;
2197 private static boolean resolveMethodDebugDOThideReach = true;
2198 private static boolean resolveMethodDebugDOThideSubsetReach = true;
2199 private static boolean resolveMethodDebugDOThidePreds = true;
2200 private static boolean resolveMethodDebugDOThideEdgeTaints = true;
2202 static String debugGraphPrefix;
2203 static int debugCallSiteVisitCounter;
2204 static int debugCallSiteVisitStartCapture;
2205 static int debugCallSiteNumVisitsToCapture;
2206 static boolean debugCallSiteStopAfter;
2210 resolveMethodCall( FlatCall fc,
2211 FlatMethod fmCallee,
2212 ReachGraph rgCallee,
2213 Set<Integer> callerNodeIDsCopiedToCallee,
2214 boolean writeDebugDOTs
2217 if( writeDebugDOTs ) {
2218 System.out.println( " Writing out visit "+
2219 debugCallSiteVisitCounter+
2220 " to debug call site" );
2222 debugGraphPrefix = String.format( "call%03d",
2223 debugCallSiteVisitCounter );
2225 rgCallee.writeGraph( debugGraphPrefix+"callee",
2226 resolveMethodDebugDOTwriteLabels,
2227 resolveMethodDebugDOTselectTemps,
2228 resolveMethodDebugDOTpruneGarbage,
2229 resolveMethodDebugDOThideReach,
2230 resolveMethodDebugDOThideSubsetReach,
2231 resolveMethodDebugDOThidePreds,
2232 resolveMethodDebugDOThideEdgeTaints );
2234 writeGraph( debugGraphPrefix+"caller00In",
2235 resolveMethodDebugDOTwriteLabels,
2236 resolveMethodDebugDOTselectTemps,
2237 resolveMethodDebugDOTpruneGarbage,
2238 resolveMethodDebugDOThideReach,
2239 resolveMethodDebugDOThideSubsetReach,
2240 resolveMethodDebugDOThidePreds,
2241 resolveMethodDebugDOThideEdgeTaints,
2242 callerNodeIDsCopiedToCallee );
2247 // method call transfer function steps:
2248 // 1. Use current callee-reachable heap (CRH) to test callee
2249 // predicates and mark what will be coming in.
2250 // 2. Wipe CRH out of caller.
2251 // 3. Transplant marked callee parts in:
2252 // a) bring in nodes
2253 // b) bring in callee -> callee edges
2254 // c) resolve out-of-context -> callee edges
2255 // d) assign return value
2256 // 4. Collapse shadow nodes down
2257 // 5. Global sweep it.
2260 // 1. mark what callee elements have satisfied predicates
2261 Hashtable<HeapRegionNode, ExistPredSet> calleeNodesSatisfied =
2262 new Hashtable<HeapRegionNode, ExistPredSet>();
2264 Hashtable<RefEdge, ExistPredSet> calleeEdgesSatisfied =
2265 new Hashtable<RefEdge, ExistPredSet>();
2267 Hashtable< HeapRegionNode, Hashtable<ReachState, ExistPredSet> >
2268 calleeNode2calleeStatesSatisfied =
2269 new Hashtable< HeapRegionNode, Hashtable<ReachState, ExistPredSet> >();
2271 Hashtable< RefEdge, Hashtable<ReachState, ExistPredSet> >
2272 calleeEdge2calleeStatesSatisfied =
2273 new Hashtable< RefEdge, Hashtable<ReachState, ExistPredSet> >();
2275 Hashtable< RefEdge, Hashtable<Taint, ExistPredSet> >
2276 calleeEdge2calleeTaintsSatisfied =
2277 new Hashtable< RefEdge, Hashtable<Taint, ExistPredSet> >();
2279 Hashtable< RefEdge, Set<RefSrcNode> > calleeEdges2oocCallerSrcMatches =
2280 new Hashtable< RefEdge, Set<RefSrcNode> >();
2283 Iterator meItr = rgCallee.id2hrn.entrySet().iterator();
2284 while( meItr.hasNext() ) {
2285 Map.Entry me = (Map.Entry) meItr.next();
2286 Integer id = (Integer) me.getKey();
2287 HeapRegionNode hrnCallee = (HeapRegionNode) me.getValue();
2289 // if a callee element's predicates are satisfied then a set
2290 // of CALLER predicates is returned: they are the predicates
2291 // that the callee element moved into the caller context
2292 // should have, and it is inefficient to find this again later
2293 ExistPredSet predsIfSatis =
2294 hrnCallee.getPreds().isSatisfiedBy( this,
2295 callerNodeIDsCopiedToCallee
2298 if( predsIfSatis != null ) {
2299 calleeNodesSatisfied.put( hrnCallee, predsIfSatis );
2301 // otherwise don't bother looking at edges to this node
2305 // since the node is coming over, find out which reach
2306 // states on it should come over, too
2307 assert calleeNode2calleeStatesSatisfied.get( hrnCallee ) == null;
2309 Iterator<ReachState> stateItr = hrnCallee.getAlpha().iterator();
2310 while( stateItr.hasNext() ) {
2311 ReachState stateCallee = stateItr.next();
2314 stateCallee.getPreds().isSatisfiedBy( this,
2315 callerNodeIDsCopiedToCallee
2317 if( predsIfSatis != null ) {
2319 Hashtable<ReachState, ExistPredSet> calleeStatesSatisfied =
2320 calleeNode2calleeStatesSatisfied.get( hrnCallee );
2322 if( calleeStatesSatisfied == null ) {
2323 calleeStatesSatisfied =
2324 new Hashtable<ReachState, ExistPredSet>();
2326 calleeNode2calleeStatesSatisfied.put( hrnCallee, calleeStatesSatisfied );
2329 calleeStatesSatisfied.put( stateCallee, predsIfSatis );
2333 // then look at edges to the node
2334 Iterator<RefEdge> reItr = hrnCallee.iteratorToReferencers();
2335 while( reItr.hasNext() ) {
2336 RefEdge reCallee = reItr.next();
2337 RefSrcNode rsnCallee = reCallee.getSrc();
2339 // (caller local variables to in-context heap regions)
2340 // have an (out-of-context heap region -> in-context heap region)
2341 // abstraction in the callEE, so its true we never need to
2342 // look at a (var node -> heap region) edge in callee to bring
2343 // those over for the call site transfer, except for the special
2344 // case of *RETURN var* -> heap region edges.
2345 // What about (param var->heap region)
2346 // edges in callee? They are dealt with below this loop.
2348 if( rsnCallee instanceof VariableNode ) {
2350 // looking for the return-value variable only
2351 VariableNode vnCallee = (VariableNode) rsnCallee;
2352 if( vnCallee.getTempDescriptor() != tdReturn ) {
2356 TempDescriptor returnTemp = fc.getReturnTemp();
2357 if( returnTemp == null ||
2358 !DisjointAnalysis.shouldAnalysisTrack( returnTemp.getType() )
2363 // note that the assignment of the return value is to a
2364 // variable in the caller which is out-of-context with
2365 // respect to the callee
2366 VariableNode vnLhsCaller = getVariableNodeFromTemp( returnTemp );
2367 Set<RefSrcNode> rsnCallers = new HashSet<RefSrcNode>();
2368 rsnCallers.add( vnLhsCaller );
2369 calleeEdges2oocCallerSrcMatches.put( reCallee, rsnCallers );
2373 // for HeapRegionNode callee sources...
2375 // first see if the source is out-of-context, and only
2376 // proceed with this edge if we find some caller-context
2378 HeapRegionNode hrnSrcCallee = (HeapRegionNode) rsnCallee;
2379 boolean matchedOutOfContext = false;
2381 if( !hrnSrcCallee.isOutOfContext() ) {
2384 hrnSrcCallee.getPreds().isSatisfiedBy( this,
2385 callerNodeIDsCopiedToCallee
2387 if( predsIfSatis != null ) {
2388 calleeNodesSatisfied.put( hrnSrcCallee, predsIfSatis );
2390 // otherwise forget this edge
2395 // hrnSrcCallee is out-of-context
2397 assert !calleeEdges2oocCallerSrcMatches.containsKey( reCallee );
2399 Set<RefSrcNode> rsnCallers = new HashSet<RefSrcNode>();
2401 // is the target node in the caller?
2402 HeapRegionNode hrnDstCaller = this.id2hrn.get( hrnCallee.getID() );
2403 if( hrnDstCaller == null ) {
2407 Iterator<RefEdge> reDstItr = hrnDstCaller.iteratorToReferencers();
2408 while( reDstItr.hasNext() ) {
2409 // the edge and field (either possibly null) must match
2410 RefEdge reCaller = reDstItr.next();
2412 if( !reCaller.typeEquals ( reCallee.getType() ) ||
2413 !reCaller.fieldEquals( reCallee.getField() )
2418 RefSrcNode rsnCaller = reCaller.getSrc();
2419 if( rsnCaller instanceof VariableNode ) {
2421 // a variable node matches an OOC region with null type
2422 if( hrnSrcCallee.getType() != null ) {
2427 // otherwise types should match
2428 HeapRegionNode hrnCallerSrc = (HeapRegionNode) rsnCaller;
2429 if( hrnSrcCallee.getType() == null ) {
2430 if( hrnCallerSrc.getType() != null ) {
2434 if( !hrnSrcCallee.getType().equals( hrnCallerSrc.getType() ) ) {
2440 rsnCallers.add( rsnCaller );
2441 matchedOutOfContext = true;
2444 if( !rsnCallers.isEmpty() ) {
2445 calleeEdges2oocCallerSrcMatches.put( reCallee, rsnCallers );
2449 if( hrnSrcCallee.isOutOfContext() &&
2450 !matchedOutOfContext ) {
2457 reCallee.getPreds().isSatisfiedBy( this,
2458 callerNodeIDsCopiedToCallee
2461 if( predsIfSatis != null ) {
2462 calleeEdgesSatisfied.put( reCallee, predsIfSatis );
2464 // since the edge is coming over, find out which reach
2465 // states on it should come over, too
2466 assert calleeEdge2calleeStatesSatisfied.get( reCallee ) == null;
2468 stateItr = reCallee.getBeta().iterator();
2469 while( stateItr.hasNext() ) {
2470 ReachState stateCallee = stateItr.next();
2473 stateCallee.getPreds().isSatisfiedBy( this,
2474 callerNodeIDsCopiedToCallee
2476 if( predsIfSatis != null ) {
2478 Hashtable<ReachState, ExistPredSet> calleeStatesSatisfied =
2479 calleeEdge2calleeStatesSatisfied.get( reCallee );
2481 if( calleeStatesSatisfied == null ) {
2482 calleeStatesSatisfied =
2483 new Hashtable<ReachState, ExistPredSet>();
2485 calleeEdge2calleeStatesSatisfied.put( reCallee, calleeStatesSatisfied );
2488 calleeStatesSatisfied.put( stateCallee, predsIfSatis );
2492 // since the edge is coming over, find out which taints
2493 // on it should come over, too
2494 assert calleeEdge2calleeTaintsSatisfied.get( reCallee ) == null;
2496 Iterator<Taint> tItr = reCallee.getTaints().iterator();
2497 while( tItr.hasNext() ) {
2498 Taint tCallee = tItr.next();
2501 tCallee.getPreds().isSatisfiedBy( this,
2502 callerNodeIDsCopiedToCallee
2504 if( predsIfSatis != null ) {
2506 Hashtable<Taint, ExistPredSet> calleeTaintsSatisfied =
2507 calleeEdge2calleeTaintsSatisfied.get( reCallee );
2509 if( calleeTaintsSatisfied == null ) {
2510 calleeTaintsSatisfied =
2511 new Hashtable<Taint, ExistPredSet>();
2513 calleeEdge2calleeTaintsSatisfied.put( reCallee, calleeTaintsSatisfied );
2516 calleeTaintsSatisfied.put( tCallee, predsIfSatis );
2523 if( writeDebugDOTs ) {
2524 writeGraph( debugGraphPrefix+"caller20BeforeWipe",
2525 resolveMethodDebugDOTwriteLabels,
2526 resolveMethodDebugDOTselectTemps,
2527 resolveMethodDebugDOTpruneGarbage,
2528 resolveMethodDebugDOThideReach,
2529 resolveMethodDebugDOThideSubsetReach,
2530 resolveMethodDebugDOThidePreds,
2531 resolveMethodDebugDOThideEdgeTaints );
2535 // 2. predicates tested, ok to wipe out caller part
2536 Iterator<Integer> hrnItr = callerNodeIDsCopiedToCallee.iterator();
2537 while( hrnItr.hasNext() ) {
2538 Integer hrnID = hrnItr.next();
2539 HeapRegionNode hrnCaller = id2hrn.get( hrnID );
2540 assert hrnCaller != null;
2542 // when clearing off nodes, also eliminate variable
2544 wipeOut( hrnCaller, true );
2547 // if we are assigning the return value to something, clobber now
2548 // as part of the wipe
2549 TempDescriptor returnTemp = fc.getReturnTemp();
2550 if( returnTemp != null &&
2551 DisjointAnalysis.shouldAnalysisTrack( returnTemp.getType() )
2554 VariableNode vnLhsCaller = getVariableNodeFromTemp( returnTemp );
2555 clearRefEdgesFrom( vnLhsCaller, null, null, true );
2561 if( writeDebugDOTs ) {
2562 writeGraph( debugGraphPrefix+"caller30BeforeAddingNodes",
2563 resolveMethodDebugDOTwriteLabels,
2564 resolveMethodDebugDOTselectTemps,
2565 resolveMethodDebugDOTpruneGarbage,
2566 resolveMethodDebugDOThideReach,
2567 resolveMethodDebugDOThideSubsetReach,
2568 resolveMethodDebugDOThidePreds,
2569 resolveMethodDebugDOThideEdgeTaints );
2575 // 3. callee elements with satisfied preds come in, note that
2576 // the mapping of elements satisfied to preds is like this:
2577 // A callee element EE has preds EEp that are satisfied by
2578 // some caller element ER. We bring EE into the caller
2579 // context as ERee with the preds of ER, namely ERp, which
2580 // in the following algorithm is the value in the mapping
2583 Iterator satisItr = calleeNodesSatisfied.entrySet().iterator();
2584 while( satisItr.hasNext() ) {
2585 Map.Entry me = (Map.Entry) satisItr.next();
2586 HeapRegionNode hrnCallee = (HeapRegionNode) me.getKey();
2587 ExistPredSet preds = (ExistPredSet) me.getValue();
2589 // TODO: I think its true that the current implementation uses
2590 // the type of the OOC region and the predicates OF THE EDGE from
2591 // it to link everything up in caller context, so that's why we're
2592 // skipping this... maybe that's a sillier way to do it?
2593 if( hrnCallee.isOutOfContext() ) {
2597 AllocSite as = hrnCallee.getAllocSite();
2598 allocSites.add( as );
2600 Integer hrnIDshadow = as.getShadowIDfromID( hrnCallee.getID() );
2602 HeapRegionNode hrnCaller = id2hrn.get( hrnIDshadow );
2603 if( hrnCaller == null ) {
2605 createNewHeapRegionNode( hrnIDshadow, // id or null to generate a new one
2606 hrnCallee.isSingleObject(), // single object?
2607 hrnCallee.isNewSummary(), // summary?
2608 false, // out-of-context?
2609 hrnCallee.getType(), // type
2610 hrnCallee.getAllocSite(), // allocation site
2611 toCallerContext( hrnCallee.getInherent(),
2612 calleeNode2calleeStatesSatisfied.get( hrnCallee ) ), // inherent reach
2613 null, // current reach
2614 predsEmpty, // predicates
2615 hrnCallee.getDescription() // description
2618 assert hrnCaller.isWiped();
2621 hrnCaller.setAlpha( toCallerContext( hrnCallee.getAlpha(),
2622 calleeNode2calleeStatesSatisfied.get( hrnCallee )
2626 hrnCaller.setPreds( preds );
2633 if( writeDebugDOTs ) {
2634 writeGraph( debugGraphPrefix+"caller31BeforeAddingEdges",
2635 resolveMethodDebugDOTwriteLabels,
2636 resolveMethodDebugDOTselectTemps,
2637 resolveMethodDebugDOTpruneGarbage,
2638 resolveMethodDebugDOThideReach,
2639 resolveMethodDebugDOThideSubsetReach,
2640 resolveMethodDebugDOThidePreds,
2641 resolveMethodDebugDOThideEdgeTaints );
2645 // set these up during the next procedure so after
2646 // the caller has all of its nodes and edges put
2647 // back together we can propagate the callee's
2648 // reach changes backwards into the caller graph
2649 HashSet<RefEdge> edgesForPropagation = new HashSet<RefEdge>();
2651 Hashtable<RefEdge, ChangeSet> edgePlannedChanges =
2652 new Hashtable<RefEdge, ChangeSet>();
2655 // 3.b) callee -> callee edges AND out-of-context -> callee
2656 // which includes return temp -> callee edges now, too
2657 satisItr = calleeEdgesSatisfied.entrySet().iterator();
2658 while( satisItr.hasNext() ) {
2659 Map.Entry me = (Map.Entry) satisItr.next();
2660 RefEdge reCallee = (RefEdge) me.getKey();
2661 ExistPredSet preds = (ExistPredSet) me.getValue();
2663 HeapRegionNode hrnDstCallee = reCallee.getDst();
2664 AllocSite asDst = hrnDstCallee.getAllocSite();
2665 allocSites.add( asDst );
2667 Integer hrnIDDstShadow =
2668 asDst.getShadowIDfromID( hrnDstCallee.getID() );
2670 HeapRegionNode hrnDstCaller = id2hrn.get( hrnIDDstShadow );
2671 assert hrnDstCaller != null;
2674 RefSrcNode rsnCallee = reCallee.getSrc();
2676 Set<RefSrcNode> rsnCallers =
2677 new HashSet<RefSrcNode>();
2679 Set<RefSrcNode> oocCallers =
2680 calleeEdges2oocCallerSrcMatches.get( reCallee );
2682 if( rsnCallee instanceof HeapRegionNode ) {
2683 HeapRegionNode hrnCalleeSrc = (HeapRegionNode) rsnCallee;
2684 if( hrnCalleeSrc.isOutOfContext() ) {
2685 assert oocCallers != null;
2690 if( oocCallers == null ) {
2691 // there are no out-of-context matches, so it's
2692 // either a param/arg var or one in-context heap region
2693 if( rsnCallee instanceof VariableNode ) {
2694 // variable -> node in the callee should only
2695 // come into the caller if its from a param var
2696 VariableNode vnCallee = (VariableNode) rsnCallee;
2697 TempDescriptor tdParam = vnCallee.getTempDescriptor();
2698 TempDescriptor tdArg = fc.getArgMatchingParam( fmCallee,
2700 if( tdArg == null ) {
2701 // this means the variable isn't a parameter, its local
2702 // to the callee so we ignore it in call site transfer
2703 // shouldn't this NEVER HAPPEN?
2707 rsnCallers.add( this.getVariableNodeFromTemp( tdArg ) );
2710 // otherwise source is in context, one region
2712 HeapRegionNode hrnSrcCallee = (HeapRegionNode) rsnCallee;
2714 // translate an in-context node to shadow
2715 AllocSite asSrc = hrnSrcCallee.getAllocSite();
2716 allocSites.add( asSrc );
2718 Integer hrnIDSrcShadow =
2719 asSrc.getShadowIDfromID( hrnSrcCallee.getID() );
2721 HeapRegionNode hrnSrcCallerShadow =
2722 this.id2hrn.get( hrnIDSrcShadow );
2724 assert hrnSrcCallerShadow != null;
2726 rsnCallers.add( hrnSrcCallerShadow );
2730 // otherwise we have a set of out-of-context srcs
2731 // that should NOT be translated to shadow nodes
2732 assert !oocCallers.isEmpty();
2733 rsnCallers.addAll( oocCallers );
2736 // now make all caller edges we've identified from
2737 // this callee edge with a satisfied predicate
2738 assert !rsnCallers.isEmpty();
2739 Iterator<RefSrcNode> rsnItr = rsnCallers.iterator();
2740 while( rsnItr.hasNext() ) {
2741 RefSrcNode rsnCaller = rsnItr.next();
2743 RefEdge reCaller = new RefEdge( rsnCaller,
2746 reCallee.getField(),
2747 toCallerContext( reCallee.getBeta(),
2748 calleeEdge2calleeStatesSatisfied.get( reCallee ) ),
2750 toCallerContext( reCallee.getTaints(),
2751 calleeEdge2calleeTaintsSatisfied.get( reCallee ) )
2754 ChangeSet cs = ChangeSet.factory();
2755 Iterator<ReachState> rsItr = reCaller.getBeta().iterator();
2756 while( rsItr.hasNext() ) {
2757 ReachState state = rsItr.next();
2758 ExistPredSet predsPreCallee = state.getPreds();
2760 if( state.isEmpty() ) {
2764 Iterator<ExistPred> predItr = predsPreCallee.iterator();
2765 while( predItr.hasNext() ) {
2766 ExistPred pred = predItr.next();
2767 ReachState old = pred.ne_state;
2773 cs = Canonical.add( cs,
2774 ChangeTuple.factory( old,
2781 // we're just going to use the convenient "merge-if-exists"
2782 // edge call below, but still take a separate look if there
2783 // is an existing caller edge to build change sets properly
2784 if( !cs.isEmpty() ) {
2785 RefEdge edgeExisting = rsnCaller.getReferenceTo( hrnDstCaller,
2789 if( edgeExisting != null ) {
2790 ChangeSet csExisting = edgePlannedChanges.get( edgeExisting );
2791 if( csExisting == null ) {
2792 csExisting = ChangeSet.factory();
2794 edgePlannedChanges.put( edgeExisting,
2795 Canonical.union( csExisting,
2800 edgesForPropagation.add( reCaller );
2801 assert !edgePlannedChanges.containsKey( reCaller );
2802 edgePlannedChanges.put( reCaller, cs );
2806 // then add new caller edge or merge
2807 addEdgeOrMergeWithExisting( reCaller );
2815 if( writeDebugDOTs ) {
2816 writeGraph( debugGraphPrefix+"caller38propagateReach",
2817 resolveMethodDebugDOTwriteLabels,
2818 resolveMethodDebugDOTselectTemps,
2819 resolveMethodDebugDOTpruneGarbage,
2820 resolveMethodDebugDOThideReach,
2821 resolveMethodDebugDOThideSubsetReach,
2822 resolveMethodDebugDOThidePreds,
2823 resolveMethodDebugDOThideEdgeTaints );
2826 // propagate callee reachability changes to the rest
2827 // of the caller graph edges
2828 HashSet<RefEdge> edgesUpdated = new HashSet<RefEdge>();
2830 propagateTokensOverEdges( edgesForPropagation, // source edges
2831 edgePlannedChanges, // map src edge to change set
2832 edgesUpdated ); // list of updated edges
2834 // commit beta' (beta<-betaNew)
2835 Iterator<RefEdge> edgeItr = edgesUpdated.iterator();
2836 while( edgeItr.hasNext() ) {
2837 edgeItr.next().applyBetaNew();
2846 if( writeDebugDOTs ) {
2847 writeGraph( debugGraphPrefix+"caller40BeforeShadowMerge",
2848 resolveMethodDebugDOTwriteLabels,
2849 resolveMethodDebugDOTselectTemps,
2850 resolveMethodDebugDOTpruneGarbage,
2851 resolveMethodDebugDOThideReach,
2852 resolveMethodDebugDOThideSubsetReach,
2853 resolveMethodDebugDOThidePreds,
2854 resolveMethodDebugDOThideEdgeTaints );
2858 // 4) merge shadow nodes so alloc sites are back to k
2859 Iterator<AllocSite> asItr = rgCallee.allocSites.iterator();
2860 while( asItr.hasNext() ) {
2861 // for each allocation site do the following to merge
2862 // shadow nodes (newest from callee) with any existing
2863 // look for the newest normal and newest shadow "slot"
2864 // not being used, transfer normal to shadow. Keep
2865 // doing this until there are no more normal nodes, or
2866 // no empty shadow slots: then merge all remaining normal
2867 // nodes into the shadow summary. Finally, convert all
2868 // shadow to their normal versions.
2869 AllocSite as = asItr.next();
2872 while( ageNorm < allocationDepth &&
2873 ageShad < allocationDepth ) {
2875 // first, are there any normal nodes left?
2876 Integer idNorm = as.getIthOldest( ageNorm );
2877 HeapRegionNode hrnNorm = id2hrn.get( idNorm );
2878 if( hrnNorm == null ) {
2879 // no, this age of normal node not in the caller graph
2884 // yes, a normal node exists, is there an empty shadow
2885 // "slot" to transfer it onto?
2886 HeapRegionNode hrnShad = getIthNode( as, ageShad, true );
2887 if( !hrnShad.isWiped() ) {
2888 // no, this age of shadow node is not empty
2893 // yes, this shadow node is empty
2894 transferOnto( hrnNorm, hrnShad );
2899 // now, while there are still normal nodes but no shadow
2900 // slots, merge normal nodes into the shadow summary
2901 while( ageNorm < allocationDepth ) {
2903 // first, are there any normal nodes left?
2904 Integer idNorm = as.getIthOldest( ageNorm );
2905 HeapRegionNode hrnNorm = id2hrn.get( idNorm );
2906 if( hrnNorm == null ) {
2907 // no, this age of normal node not in the caller graph
2912 // yes, a normal node exists, so get the shadow summary
2913 HeapRegionNode summShad = getSummaryNode( as, true );
2914 mergeIntoSummary( hrnNorm, summShad );
2918 // if there is a normal summary, merge it into shadow summary
2919 Integer idNorm = as.getSummary();
2920 HeapRegionNode summNorm = id2hrn.get( idNorm );
2921 if( summNorm != null ) {
2922 HeapRegionNode summShad = getSummaryNode( as, true );
2923 mergeIntoSummary( summNorm, summShad );
2926 // finally, flip all existing shadow nodes onto the normal
2927 for( int i = 0; i < allocationDepth; ++i ) {
2928 Integer idShad = as.getIthOldestShadow( i );
2929 HeapRegionNode hrnShad = id2hrn.get( idShad );
2930 if( hrnShad != null ) {
2932 HeapRegionNode hrnNorm = getIthNode( as, i, false );
2933 assert hrnNorm.isWiped();
2934 transferOnto( hrnShad, hrnNorm );
2938 Integer idShad = as.getSummaryShadow();
2939 HeapRegionNode summShad = id2hrn.get( idShad );
2940 if( summShad != null ) {
2941 summNorm = getSummaryNode( as, false );
2942 transferOnto( summShad, summNorm );
2951 if( writeDebugDOTs ) {
2952 writeGraph( debugGraphPrefix+"caller45BeforeUnshadow",
2953 resolveMethodDebugDOTwriteLabels,
2954 resolveMethodDebugDOTselectTemps,
2955 resolveMethodDebugDOTpruneGarbage,
2956 resolveMethodDebugDOThideReach,
2957 resolveMethodDebugDOThideSubsetReach,
2958 resolveMethodDebugDOThidePreds,
2959 resolveMethodDebugDOThideEdgeTaints );
2963 Iterator itrAllHRNodes = id2hrn.entrySet().iterator();
2964 while( itrAllHRNodes.hasNext() ) {
2965 Map.Entry me = (Map.Entry) itrAllHRNodes.next();
2966 HeapRegionNode hrn = (HeapRegionNode) me.getValue();
2968 hrn.setAlpha( unshadow( hrn.getAlpha() ) );
2970 Iterator<RefEdge> itrEdges = hrn.iteratorToReferencers();
2971 while( itrEdges.hasNext() ) {
2972 RefEdge re = itrEdges.next();
2973 re.setBeta( unshadow( re.getBeta() ) );
2980 if( writeDebugDOTs ) {
2981 writeGraph( debugGraphPrefix+"caller50BeforeGlobalSweep",
2982 resolveMethodDebugDOTwriteLabels,
2983 resolveMethodDebugDOTselectTemps,
2984 resolveMethodDebugDOTpruneGarbage,
2985 resolveMethodDebugDOThideReach,
2986 resolveMethodDebugDOThideSubsetReach,
2987 resolveMethodDebugDOThidePreds,
2988 resolveMethodDebugDOThideEdgeTaints );
2993 if( !DISABLE_GLOBAL_SWEEP ) {
2998 if( writeDebugDOTs ) {
2999 writeGraph( debugGraphPrefix+"caller90AfterTransfer",
3000 resolveMethodDebugDOTwriteLabels,
3001 resolveMethodDebugDOTselectTemps,
3002 resolveMethodDebugDOTpruneGarbage,
3003 resolveMethodDebugDOThideReach,
3004 resolveMethodDebugDOThideSubsetReach,
3005 resolveMethodDebugDOThidePreds,
3006 resolveMethodDebugDOThideEdgeTaints );
3012 ////////////////////////////////////////////////////
3014 // Abstract garbage collection simply removes
3015 // heap region nodes that are not mechanically
3016 // reachable from a root set. This step is
3017 // essential for testing node and edge existence
3018 // predicates efficiently
3020 ////////////////////////////////////////////////////
3021 public void abstractGarbageCollect( Set<TempDescriptor> liveSet ) {
3023 // calculate a root set, will be different for Java
3024 // version of analysis versus Bamboo version
3025 Set<RefSrcNode> toVisit = new HashSet<RefSrcNode>();
3027 // visit every variable in graph while building root
3028 // set, and do iterating on a copy, so we can remove
3029 // dead variables while we're at this
3030 Iterator makeCopyItr = td2vn.entrySet().iterator();
3031 Set entrysCopy = new HashSet();
3032 while( makeCopyItr.hasNext() ) {
3033 entrysCopy.add( makeCopyItr.next() );
3036 Iterator eItr = entrysCopy.iterator();
3037 while( eItr.hasNext() ) {
3038 Map.Entry me = (Map.Entry) eItr.next();
3039 TempDescriptor td = (TempDescriptor) me.getKey();
3040 VariableNode vn = (VariableNode) me.getValue();
3042 if( liveSet.contains( td ) ) {
3046 // dead var, remove completely from graph
3048 clearRefEdgesFrom( vn, null, null, true );
3052 // everything visited in a traversal is
3053 // considered abstractly live
3054 Set<RefSrcNode> visited = new HashSet<RefSrcNode>();
3056 while( !toVisit.isEmpty() ) {
3057 RefSrcNode rsn = toVisit.iterator().next();
3058 toVisit.remove( rsn );
3061 Iterator<RefEdge> hrnItr = rsn.iteratorToReferencees();
3062 while( hrnItr.hasNext() ) {
3063 RefEdge edge = hrnItr.next();
3064 HeapRegionNode hrn = edge.getDst();
3066 if( !visited.contains( hrn ) ) {
3072 // get a copy of the set to iterate over because
3073 // we're going to monkey with the graph when we
3074 // identify a garbage node
3075 Set<HeapRegionNode> hrnAllPrior = new HashSet<HeapRegionNode>();
3076 Iterator<HeapRegionNode> hrnItr = id2hrn.values().iterator();
3077 while( hrnItr.hasNext() ) {
3078 hrnAllPrior.add( hrnItr.next() );
3081 Iterator<HeapRegionNode> hrnAllItr = hrnAllPrior.iterator();
3082 while( hrnAllItr.hasNext() ) {
3083 HeapRegionNode hrn = hrnAllItr.next();
3085 if( !visited.contains( hrn ) ) {
3087 // heap region nodes are compared across ReachGraph
3088 // objects by their integer ID, so when discarding
3089 // garbage nodes we must also discard entries in
3090 // the ID -> heap region hashtable.
3091 id2hrn.remove( hrn.getID() );
3093 // RefEdge objects are two-way linked between
3094 // nodes, so when a node is identified as garbage,
3095 // actively clear references to and from it so
3096 // live nodes won't have dangling RefEdge's
3097 wipeOut( hrn, true );
3099 // if we just removed the last node from an allocation
3100 // site, it should be taken out of the ReachGraph's list
3101 AllocSite as = hrn.getAllocSite();
3102 if( !hasNodesOf( as ) ) {
3103 allocSites.remove( as );
3109 protected boolean hasNodesOf( AllocSite as ) {
3110 if( id2hrn.containsKey( as.getSummary() ) ) {
3114 for( int i = 0; i < allocationDepth; ++i ) {
3115 if( id2hrn.containsKey( as.getIthOldest( i ) ) ) {
3123 ////////////////////////////////////////////////////
3125 // This global sweep is an optional step to prune
3126 // reachability sets that are not internally
3127 // consistent with the global graph. It should be
3128 // invoked after strong updates or method calls.
3130 ////////////////////////////////////////////////////
3131 public void globalSweep() {
3133 // boldB is part of the phase 1 sweep
3134 // it has an in-context table and an out-of-context table
3135 Hashtable< Integer, Hashtable<RefEdge, ReachSet> > boldBic =
3136 new Hashtable< Integer, Hashtable<RefEdge, ReachSet> >();
3138 Hashtable< Integer, Hashtable<RefEdge, ReachSet> > boldBooc =
3139 new Hashtable< Integer, Hashtable<RefEdge, ReachSet> >();
3141 // visit every heap region to initialize alphaNew and betaNew,
3142 // and make a map of every hrnID to the source nodes it should
3143 // propagate forward from. In-context flagged hrnID's propagate
3144 // from only the in-context node they name, but out-of-context
3145 // ID's may propagate from several out-of-context nodes
3146 Hashtable< Integer, Set<HeapRegionNode> > icID2srcs =
3147 new Hashtable< Integer, Set<HeapRegionNode> >();
3149 Hashtable< Integer, Set<HeapRegionNode> > oocID2srcs =
3150 new Hashtable< Integer, Set<HeapRegionNode> >();
3153 Iterator itrHrns = id2hrn.entrySet().iterator();
3154 while( itrHrns.hasNext() ) {
3155 Map.Entry me = (Map.Entry) itrHrns.next();
3156 Integer hrnID = (Integer) me.getKey();
3157 HeapRegionNode hrn = (HeapRegionNode) me.getValue();
3159 // assert that this node and incoming edges have clean alphaNew
3160 // and betaNew sets, respectively
3161 assert rsetEmpty.equals( hrn.getAlphaNew() );
3163 Iterator<RefEdge> itrRers = hrn.iteratorToReferencers();
3164 while( itrRers.hasNext() ) {
3165 RefEdge edge = itrRers.next();
3166 assert rsetEmpty.equals( edge.getBetaNew() );
3169 // make a mapping of IDs to heap regions they propagate from
3170 if( hrn.isFlagged() ) {
3171 assert !hrn.isOutOfContext();
3172 assert !icID2srcs.containsKey( hrn.getID() );
3174 // in-context flagged node IDs simply propagate from the
3176 Set<HeapRegionNode> srcs = new HashSet<HeapRegionNode>();
3178 icID2srcs.put( hrn.getID(), srcs );
3181 if( hrn.isOutOfContext() ) {
3182 assert !hrn.isFlagged();
3184 // the reachability states on an out-of-context
3185 // node are not really important (combinations of
3186 // IDs or arity)--what matters is that the states
3187 // specify which nodes this out-of-context node
3188 // stands in for. For example, if the state [17?, 19*]
3189 // appears on the ooc node, it may serve as a source
3190 // for node 17? and a source for node 19.
3191 Iterator<ReachState> stateItr = hrn.getAlpha().iterator();
3192 while( stateItr.hasNext() ) {
3193 ReachState state = stateItr.next();
3195 Iterator<ReachTuple> rtItr = state.iterator();
3196 while( rtItr.hasNext() ) {
3197 ReachTuple rt = rtItr.next();
3198 assert rt.isOutOfContext();
3200 Set<HeapRegionNode> srcs = oocID2srcs.get( rt.getHrnID() );
3201 if( srcs == null ) {
3202 srcs = new HashSet<HeapRegionNode>();
3205 oocID2srcs.put( rt.getHrnID(), srcs );
3211 // calculate boldB for all hrnIDs identified by the above
3212 // node traversal, propagating from every source
3213 while( !icID2srcs.isEmpty() || !oocID2srcs.isEmpty() ) {
3216 Set<HeapRegionNode> srcs;
3219 if( !icID2srcs.isEmpty() ) {
3220 Map.Entry me = (Map.Entry) icID2srcs.entrySet().iterator().next();
3221 hrnID = (Integer) me.getKey();
3222 srcs = (Set<HeapRegionNode>) me.getValue();
3224 icID2srcs.remove( hrnID );
3227 assert !oocID2srcs.isEmpty();
3229 Map.Entry me = (Map.Entry) oocID2srcs.entrySet().iterator().next();
3230 hrnID = (Integer) me.getKey();
3231 srcs = (Set<HeapRegionNode>) me.getValue();
3233 oocID2srcs.remove( hrnID );
3237 Hashtable<RefEdge, ReachSet> boldB_f =
3238 new Hashtable<RefEdge, ReachSet>();
3240 Set<RefEdge> workSetEdges = new HashSet<RefEdge>();
3242 Iterator<HeapRegionNode> hrnItr = srcs.iterator();
3243 while( hrnItr.hasNext() ) {
3244 HeapRegionNode hrn = hrnItr.next();
3246 assert workSetEdges.isEmpty();
3248 // initial boldB_f constraints
3249 Iterator<RefEdge> itrRees = hrn.iteratorToReferencees();
3250 while( itrRees.hasNext() ) {
3251 RefEdge edge = itrRees.next();
3253 assert !boldB_f.containsKey( edge );
3254 boldB_f.put( edge, edge.getBeta() );
3256 assert !workSetEdges.contains( edge );
3257 workSetEdges.add( edge );
3260 // enforce the boldB_f constraint at edges until we reach a fixed point
3261 while( !workSetEdges.isEmpty() ) {
3262 RefEdge edge = workSetEdges.iterator().next();
3263 workSetEdges.remove( edge );
3265 Iterator<RefEdge> itrPrime = edge.getDst().iteratorToReferencees();
3266 while( itrPrime.hasNext() ) {
3267 RefEdge edgePrime = itrPrime.next();
3269 ReachSet prevResult = boldB_f.get( edgePrime );
3270 ReachSet intersection = Canonical.intersection( boldB_f.get( edge ),
3274 if( prevResult == null ||
3275 Canonical.unionORpreds( prevResult,
3276 intersection ).size()
3280 if( prevResult == null ) {
3281 boldB_f.put( edgePrime,
3282 Canonical.unionORpreds( edgePrime.getBeta(),
3287 boldB_f.put( edgePrime,
3288 Canonical.unionORpreds( prevResult,
3293 workSetEdges.add( edgePrime );
3300 boldBic.put( hrnID, boldB_f );
3302 boldBooc.put( hrnID, boldB_f );
3307 // use boldB to prune hrnIDs from alpha states that are impossible
3308 // and propagate the differences backwards across edges
3309 HashSet<RefEdge> edgesForPropagation = new HashSet<RefEdge>();
3311 Hashtable<RefEdge, ChangeSet> edgePlannedChanges =
3312 new Hashtable<RefEdge, ChangeSet>();
3315 itrHrns = id2hrn.entrySet().iterator();
3316 while( itrHrns.hasNext() ) {
3317 Map.Entry me = (Map.Entry) itrHrns.next();
3318 Integer hrnID = (Integer) me.getKey();
3319 HeapRegionNode hrn = (HeapRegionNode) me.getValue();
3321 // out-of-context nodes don't participate in the
3322 // global sweep, they serve as sources for the pass
3324 if( hrn.isOutOfContext() ) {
3328 // the inherent states of a region are the exception
3329 // to removal as the global sweep prunes
3330 ReachTuple rtException = ReachTuple.factory( hrnID,
3331 !hrn.isSingleObject(),
3332 ReachTuple.ARITY_ONE,
3333 false // out-of-context
3336 ChangeSet cts = ChangeSet.factory();
3338 // mark hrnIDs for removal
3339 Iterator<ReachState> stateItr = hrn.getAlpha().iterator();
3340 while( stateItr.hasNext() ) {
3341 ReachState stateOld = stateItr.next();
3343 ReachState markedHrnIDs = ReachState.factory();
3345 Iterator<ReachTuple> rtItr = stateOld.iterator();
3346 while( rtItr.hasNext() ) {
3347 ReachTuple rtOld = rtItr.next();
3349 // never remove the inherent hrnID from a flagged region
3350 // because it is trivially satisfied
3351 if( hrn.isFlagged() ) {
3352 if( rtOld == rtException ) {
3357 // does boldB allow this hrnID?
3358 boolean foundState = false;
3359 Iterator<RefEdge> incidentEdgeItr = hrn.iteratorToReferencers();
3360 while( incidentEdgeItr.hasNext() ) {
3361 RefEdge incidentEdge = incidentEdgeItr.next();
3363 Hashtable<RefEdge, ReachSet> B;
3364 if( rtOld.isOutOfContext() ) {
3365 B = boldBooc.get( rtOld.getHrnID() );
3368 if( !id2hrn.containsKey( rtOld.getHrnID() ) ) {
3369 // let symbols not in the graph get pruned
3373 B = boldBic.get( rtOld.getHrnID() );
3377 ReachSet boldB_rtOld_incident = B.get( incidentEdge );
3378 if( boldB_rtOld_incident != null &&
3379 boldB_rtOld_incident.containsIgnorePreds( stateOld ) != null
3387 markedHrnIDs = Canonical.addUpArity( markedHrnIDs, rtOld );
3391 // if there is nothing marked, just move on
3392 if( markedHrnIDs.isEmpty() ) {
3393 hrn.setAlphaNew( Canonical.add( hrn.getAlphaNew(),
3400 // remove all marked hrnIDs and establish a change set that should
3401 // propagate backwards over edges from this node
3402 ReachState statePruned = ReachState.factory();
3403 rtItr = stateOld.iterator();
3404 while( rtItr.hasNext() ) {
3405 ReachTuple rtOld = rtItr.next();
3407 if( !markedHrnIDs.containsTuple( rtOld ) ) {
3408 statePruned = Canonical.addUpArity( statePruned, rtOld );
3411 assert !stateOld.equals( statePruned );
3413 hrn.setAlphaNew( Canonical.add( hrn.getAlphaNew(),
3417 ChangeTuple ct = ChangeTuple.factory( stateOld,
3420 cts = Canonical.add( cts, ct );
3423 // throw change tuple set on all incident edges
3424 if( !cts.isEmpty() ) {
3425 Iterator<RefEdge> incidentEdgeItr = hrn.iteratorToReferencers();
3426 while( incidentEdgeItr.hasNext() ) {
3427 RefEdge incidentEdge = incidentEdgeItr.next();
3429 edgesForPropagation.add( incidentEdge );
3431 if( edgePlannedChanges.get( incidentEdge ) == null ) {
3432 edgePlannedChanges.put( incidentEdge, cts );
3434 edgePlannedChanges.put(
3436 Canonical.union( edgePlannedChanges.get( incidentEdge ),
3445 HashSet<RefEdge> edgesUpdated = new HashSet<RefEdge>();
3447 propagateTokensOverEdges( edgesForPropagation,
3451 // at the end of the 1st phase reference edges have
3452 // beta, betaNew that correspond to beta and betaR
3454 // commit beta<-betaNew, so beta=betaR and betaNew
3455 // will represent the beta' calculation in 2nd phase
3457 // commit alpha<-alphaNew because it won't change
3458 HashSet<RefEdge> res = new HashSet<RefEdge>();
3460 Iterator<HeapRegionNode> nodeItr = id2hrn.values().iterator();
3461 while( nodeItr.hasNext() ) {
3462 HeapRegionNode hrn = nodeItr.next();
3464 // as mentioned above, out-of-context nodes only serve
3465 // as sources of reach states for the sweep, not part
3467 if( hrn.isOutOfContext() ) {
3468 assert hrn.getAlphaNew().equals( rsetEmpty );
3470 hrn.applyAlphaNew();
3473 Iterator<RefEdge> itrRes = hrn.iteratorToReferencers();
3474 while( itrRes.hasNext() ) {
3475 res.add( itrRes.next() );
3481 Iterator<RefEdge> edgeItr = res.iterator();
3482 while( edgeItr.hasNext() ) {
3483 RefEdge edge = edgeItr.next();
3484 HeapRegionNode hrn = edge.getDst();
3486 // commit results of last phase
3487 if( edgesUpdated.contains( edge ) ) {
3488 edge.applyBetaNew();
3491 // compute intial condition of 2nd phase
3492 edge.setBetaNew( Canonical.intersection( edge.getBeta(),
3498 // every edge in the graph is the initial workset
3499 Set<RefEdge> edgeWorkSet = (Set) res.clone();
3500 while( !edgeWorkSet.isEmpty() ) {
3501 RefEdge edgePrime = edgeWorkSet.iterator().next();
3502 edgeWorkSet.remove( edgePrime );
3504 RefSrcNode rsn = edgePrime.getSrc();
3505 if( !(rsn instanceof HeapRegionNode) ) {
3508 HeapRegionNode hrn = (HeapRegionNode) rsn;
3510 Iterator<RefEdge> itrEdge = hrn.iteratorToReferencers();
3511 while( itrEdge.hasNext() ) {
3512 RefEdge edge = itrEdge.next();
3514 ReachSet prevResult = edge.getBetaNew();
3515 assert prevResult != null;
3517 ReachSet intersection =
3518 Canonical.intersection( edge.getBeta(),
3519 edgePrime.getBetaNew()
3522 if( Canonical.unionORpreds( prevResult,
3529 Canonical.unionORpreds( prevResult,
3533 edgeWorkSet.add( edge );
3538 // commit beta' (beta<-betaNew)
3539 edgeItr = res.iterator();
3540 while( edgeItr.hasNext() ) {
3541 edgeItr.next().applyBetaNew();
3546 // a useful assertion for debugging:
3547 // every in-context tuple on any edge or
3548 // any node should name a node that is
3549 // part of the graph
3550 public boolean inContextTuplesInGraph() {
3552 Iterator hrnItr = id2hrn.entrySet().iterator();
3553 while( hrnItr.hasNext() ) {
3554 Map.Entry me = (Map.Entry) hrnItr.next();
3555 HeapRegionNode hrn = (HeapRegionNode) me.getValue();
3558 Iterator<ReachState> stateItr = hrn.getAlpha().iterator();
3559 while( stateItr.hasNext() ) {
3560 ReachState state = stateItr.next();
3562 Iterator<ReachTuple> rtItr = state.iterator();
3563 while( rtItr.hasNext() ) {
3564 ReachTuple rt = rtItr.next();
3566 if( !rt.isOutOfContext() ) {
3567 if( !id2hrn.containsKey( rt.getHrnID() ) ) {
3568 System.out.println( rt.getHrnID()+" is missing" );
3576 Iterator<RefEdge> edgeItr = hrn.iteratorToReferencers();
3577 while( edgeItr.hasNext() ) {
3578 RefEdge edge = edgeItr.next();
3580 Iterator<ReachState> stateItr = edge.getBeta().iterator();
3581 while( stateItr.hasNext() ) {
3582 ReachState state = stateItr.next();
3584 Iterator<ReachTuple> rtItr = state.iterator();
3585 while( rtItr.hasNext() ) {
3586 ReachTuple rt = rtItr.next();
3588 if( !rt.isOutOfContext() ) {
3589 if( !id2hrn.containsKey( rt.getHrnID() ) ) {
3590 System.out.println( rt.getHrnID()+" is missing" );
3603 // another useful assertion for debugging
3604 public boolean noEmptyReachSetsInGraph() {
3606 Iterator hrnItr = id2hrn.entrySet().iterator();
3607 while( hrnItr.hasNext() ) {
3608 Map.Entry me = (Map.Entry) hrnItr.next();
3609 HeapRegionNode hrn = (HeapRegionNode) me.getValue();
3611 if( !hrn.isOutOfContext() &&
3613 hrn.getAlpha().isEmpty()
3615 System.out.println( "!!! "+hrn+" has an empty ReachSet !!!" );
3619 Iterator<RefEdge> edgeItr = hrn.iteratorToReferencers();
3620 while( edgeItr.hasNext() ) {
3621 RefEdge edge = edgeItr.next();
3623 if( edge.getBeta().isEmpty() ) {
3624 System.out.println( "!!! "+edge+" has an empty ReachSet !!!" );
3634 public boolean everyReachStateWTrue() {
3636 Iterator hrnItr = id2hrn.entrySet().iterator();
3637 while( hrnItr.hasNext() ) {
3638 Map.Entry me = (Map.Entry) hrnItr.next();
3639 HeapRegionNode hrn = (HeapRegionNode) me.getValue();
3642 Iterator<ReachState> stateItr = hrn.getAlpha().iterator();
3643 while( stateItr.hasNext() ) {
3644 ReachState state = stateItr.next();
3646 if( !state.getPreds().equals( predsTrue ) ) {
3652 Iterator<RefEdge> edgeItr = hrn.iteratorToReferencers();
3653 while( edgeItr.hasNext() ) {
3654 RefEdge edge = edgeItr.next();
3656 Iterator<ReachState> stateItr = edge.getBeta().iterator();
3657 while( stateItr.hasNext() ) {
3658 ReachState state = stateItr.next();
3660 if( !state.getPreds().equals( predsTrue ) ) {
3673 ////////////////////////////////////////////////////
3674 // in merge() and equals() methods the suffix A
3675 // represents the passed in graph and the suffix
3676 // B refers to the graph in this object
3677 // Merging means to take the incoming graph A and
3678 // merge it into B, so after the operation graph B
3679 // is the final result.
3680 ////////////////////////////////////////////////////
3681 protected void merge( ReachGraph rg ) {
3688 mergeRefEdges ( rg );
3689 mergeAllocSites ( rg );
3690 mergeInaccessibleVars( rg );
3693 protected void mergeNodes( ReachGraph rg ) {
3695 // start with heap region nodes
3696 Set sA = rg.id2hrn.entrySet();
3697 Iterator iA = sA.iterator();
3698 while( iA.hasNext() ) {
3699 Map.Entry meA = (Map.Entry) iA.next();
3700 Integer idA = (Integer) meA.getKey();
3701 HeapRegionNode hrnA = (HeapRegionNode) meA.getValue();
3703 // if this graph doesn't have a node the
3704 // incoming graph has, allocate it
3705 if( !id2hrn.containsKey( idA ) ) {
3706 HeapRegionNode hrnB = hrnA.copy();
3707 id2hrn.put( idA, hrnB );
3710 // otherwise this is a node present in both graphs
3711 // so make the new reachability set a union of the
3712 // nodes' reachability sets
3713 HeapRegionNode hrnB = id2hrn.get( idA );
3714 hrnB.setAlpha( Canonical.unionORpreds( hrnB.getAlpha(),
3719 hrnB.setPreds( Canonical.join( hrnB.getPreds(),
3726 if( !hrnA.equals( hrnB ) ) {
3727 rg.writeGraph( "graphA" );
3728 this.writeGraph( "graphB" );
3729 throw new Error( "flagged not matching" );
3737 // now add any variable nodes that are in graph B but
3739 sA = rg.td2vn.entrySet();
3741 while( iA.hasNext() ) {
3742 Map.Entry meA = (Map.Entry) iA.next();
3743 TempDescriptor tdA = (TempDescriptor) meA.getKey();
3744 VariableNode lnA = (VariableNode) meA.getValue();
3746 // if the variable doesn't exist in B, allocate and add it
3747 VariableNode lnB = getVariableNodeFromTemp( tdA );
3751 protected void mergeRefEdges( ReachGraph rg ) {
3753 // between heap regions
3754 Set sA = rg.id2hrn.entrySet();
3755 Iterator iA = sA.iterator();
3756 while( iA.hasNext() ) {
3757 Map.Entry meA = (Map.Entry) iA.next();
3758 Integer idA = (Integer) meA.getKey();
3759 HeapRegionNode hrnA = (HeapRegionNode) meA.getValue();
3761 Iterator<RefEdge> heapRegionsItrA = hrnA.iteratorToReferencees();
3762 while( heapRegionsItrA.hasNext() ) {
3763 RefEdge edgeA = heapRegionsItrA.next();
3764 HeapRegionNode hrnChildA = edgeA.getDst();
3765 Integer idChildA = hrnChildA.getID();
3767 // at this point we know an edge in graph A exists
3768 // idA -> idChildA, does this exist in B?
3769 assert id2hrn.containsKey( idA );
3770 HeapRegionNode hrnB = id2hrn.get( idA );
3771 RefEdge edgeToMerge = null;
3773 Iterator<RefEdge> heapRegionsItrB = hrnB.iteratorToReferencees();
3774 while( heapRegionsItrB.hasNext() &&
3775 edgeToMerge == null ) {
3777 RefEdge edgeB = heapRegionsItrB.next();
3778 HeapRegionNode hrnChildB = edgeB.getDst();
3779 Integer idChildB = hrnChildB.getID();
3781 // don't use the RefEdge.equals() here because
3782 // we're talking about existence between graphs,
3783 // not intragraph equal
3784 if( idChildB.equals( idChildA ) &&
3785 edgeB.typeAndFieldEquals( edgeA ) ) {
3787 edgeToMerge = edgeB;
3791 // if the edge from A was not found in B,
3793 if( edgeToMerge == null ) {
3794 assert id2hrn.containsKey( idChildA );
3795 HeapRegionNode hrnChildB = id2hrn.get( idChildA );
3796 edgeToMerge = edgeA.copy();
3797 edgeToMerge.setSrc( hrnB );
3798 edgeToMerge.setDst( hrnChildB );
3799 addRefEdge( hrnB, hrnChildB, edgeToMerge );
3801 // otherwise, the edge already existed in both graphs
3802 // so merge their reachability sets
3804 // just replace this beta set with the union
3805 assert edgeToMerge != null;
3806 edgeToMerge.setBeta(
3807 Canonical.unionORpreds( edgeToMerge.getBeta(),
3811 edgeToMerge.setPreds(
3812 Canonical.join( edgeToMerge.getPreds(),
3816 edgeToMerge.setTaints(
3817 Canonical.union( edgeToMerge.getTaints(),
3825 // and then again from variable nodes
3826 sA = rg.td2vn.entrySet();
3828 while( iA.hasNext() ) {
3829 Map.Entry meA = (Map.Entry) iA.next();
3830 TempDescriptor tdA = (TempDescriptor) meA.getKey();
3831 VariableNode vnA = (VariableNode) meA.getValue();
3833 Iterator<RefEdge> heapRegionsItrA = vnA.iteratorToReferencees();
3834 while( heapRegionsItrA.hasNext() ) {
3835 RefEdge edgeA = heapRegionsItrA.next();
3836 HeapRegionNode hrnChildA = edgeA.getDst();
3837 Integer idChildA = hrnChildA.getID();
3839 // at this point we know an edge in graph A exists
3840 // tdA -> idChildA, does this exist in B?
3841 assert td2vn.containsKey( tdA );
3842 VariableNode vnB = td2vn.get( tdA );
3843 RefEdge edgeToMerge = null;
3845 Iterator<RefEdge> heapRegionsItrB = vnB.iteratorToReferencees();
3846 while( heapRegionsItrB.hasNext() &&
3847 edgeToMerge == null ) {
3849 RefEdge edgeB = heapRegionsItrB.next();
3850 HeapRegionNode hrnChildB = edgeB.getDst();
3851 Integer idChildB = hrnChildB.getID();
3853 // don't use the RefEdge.equals() here because
3854 // we're talking about existence between graphs
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( vnB );
3869 edgeToMerge.setDst( hrnChildB );
3870 addRefEdge( vnB, 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 edgeToMerge.setBeta( Canonical.unionORpreds( edgeToMerge.getBeta(),
3880 edgeToMerge.setPreds( Canonical.join( edgeToMerge.getPreds(),
3884 edgeToMerge.setTaints(
3885 Canonical.union( edgeToMerge.getTaints(),
3894 protected void mergeAllocSites( ReachGraph rg ) {
3895 allocSites.addAll( rg.allocSites );
3898 protected void mergeInaccessibleVars( ReachGraph rg ){
3899 inaccessibleVars.addAll(rg.inaccessibleVars);
3904 static boolean dbgEquals = false;
3907 // it is necessary in the equals() member functions
3908 // to "check both ways" when comparing the data
3909 // structures of two graphs. For instance, if all
3910 // edges between heap region nodes in graph A are
3911 // present and equal in graph B it is not sufficient
3912 // to say the graphs are equal. Consider that there
3913 // may be edges in graph B that are not in graph A.
3914 // the only way to know that all edges in both graphs
3915 // are equally present is to iterate over both data
3916 // structures and compare against the other graph.
3917 public boolean equals( ReachGraph rg ) {
3921 System.out.println( "rg is null" );
3926 if( !areHeapRegionNodesEqual( rg ) ) {
3928 System.out.println( "hrn not equal" );
3933 if( !areVariableNodesEqual( rg ) ) {
3935 System.out.println( "vars not equal" );
3940 if( !areRefEdgesEqual( rg ) ) {
3942 System.out.println( "edges not equal" );
3947 if( !inaccessibleVars.equals(rg.inaccessibleVars) ){
3951 // if everything is equal up to this point,
3952 // assert that allocSites is also equal--
3953 // this data is redundant but kept for efficiency
3954 assert allocSites.equals( rg.allocSites );
3960 protected boolean areHeapRegionNodesEqual( ReachGraph rg ) {
3962 if( !areallHRNinAalsoinBandequal( this, rg ) ) {
3966 if( !areallHRNinAalsoinBandequal( rg, this ) ) {
3973 static protected boolean areallHRNinAalsoinBandequal( ReachGraph rgA,
3975 Set sA = rgA.id2hrn.entrySet();
3976 Iterator iA = sA.iterator();
3977 while( iA.hasNext() ) {
3978 Map.Entry meA = (Map.Entry) iA.next();
3979 Integer idA = (Integer) meA.getKey();
3980 HeapRegionNode hrnA = (HeapRegionNode) meA.getValue();
3982 if( !rgB.id2hrn.containsKey( idA ) ) {
3986 HeapRegionNode hrnB = rgB.id2hrn.get( idA );
3987 if( !hrnA.equalsIncludingAlphaAndPreds( hrnB ) ) {
3995 protected boolean areVariableNodesEqual( ReachGraph rg ) {
3997 if( !areallVNinAalsoinBandequal( this, rg ) ) {
4001 if( !areallVNinAalsoinBandequal( rg, this ) ) {
4008 static protected boolean areallVNinAalsoinBandequal( ReachGraph rgA,
4010 Set sA = rgA.td2vn.entrySet();
4011 Iterator iA = sA.iterator();
4012 while( iA.hasNext() ) {
4013 Map.Entry meA = (Map.Entry) iA.next();
4014 TempDescriptor tdA = (TempDescriptor) meA.getKey();
4016 if( !rgB.td2vn.containsKey( tdA ) ) {
4025 protected boolean areRefEdgesEqual( ReachGraph rg ) {
4026 if( !areallREinAandBequal( this, rg ) ) {
4030 if( !areallREinAandBequal( rg, this ) ) {
4037 static protected boolean areallREinAandBequal( ReachGraph rgA,
4040 // check all the heap region->heap region edges
4041 Set sA = rgA.id2hrn.entrySet();
4042 Iterator iA = sA.iterator();
4043 while( iA.hasNext() ) {
4044 Map.Entry meA = (Map.Entry) iA.next();
4045 Integer idA = (Integer) meA.getKey();
4046 HeapRegionNode hrnA = (HeapRegionNode) meA.getValue();
4048 // we should have already checked that the same
4049 // heap regions exist in both graphs
4050 assert rgB.id2hrn.containsKey( idA );
4052 if( !areallREfromAequaltoB( rgA, hrnA, rgB ) ) {
4056 // then check every edge in B for presence in A, starting
4057 // from the same parent HeapRegionNode
4058 HeapRegionNode hrnB = rgB.id2hrn.get( idA );
4060 if( !areallREfromAequaltoB( rgB, hrnB, rgA ) ) {
4065 // then check all the variable->heap region edges
4066 sA = rgA.td2vn.entrySet();
4068 while( iA.hasNext() ) {
4069 Map.Entry meA = (Map.Entry) iA.next();
4070 TempDescriptor tdA = (TempDescriptor) meA.getKey();
4071 VariableNode vnA = (VariableNode) meA.getValue();
4073 // we should have already checked that the same
4074 // label nodes exist in both graphs
4075 assert rgB.td2vn.containsKey( tdA );
4077 if( !areallREfromAequaltoB( rgA, vnA, rgB ) ) {
4081 // then check every edge in B for presence in A, starting
4082 // from the same parent VariableNode
4083 VariableNode vnB = rgB.td2vn.get( tdA );
4085 if( !areallREfromAequaltoB( rgB, vnB, rgA ) ) {
4094 static protected boolean areallREfromAequaltoB( ReachGraph rgA,
4098 Iterator<RefEdge> itrA = rnA.iteratorToReferencees();
4099 while( itrA.hasNext() ) {
4100 RefEdge edgeA = itrA.next();
4101 HeapRegionNode hrnChildA = edgeA.getDst();
4102 Integer idChildA = hrnChildA.getID();
4104 assert rgB.id2hrn.containsKey( idChildA );
4106 // at this point we know an edge in graph A exists
4107 // rnA -> idChildA, does this exact edge exist in B?
4108 boolean edgeFound = false;
4110 RefSrcNode rnB = null;
4111 if( rnA instanceof HeapRegionNode ) {
4112 HeapRegionNode hrnA = (HeapRegionNode) rnA;
4113 rnB = rgB.id2hrn.get( hrnA.getID() );
4115 VariableNode vnA = (VariableNode) rnA;
4116 rnB = rgB.td2vn.get( vnA.getTempDescriptor() );
4119 Iterator<RefEdge> itrB = rnB.iteratorToReferencees();
4120 while( itrB.hasNext() ) {
4121 RefEdge edgeB = itrB.next();
4122 HeapRegionNode hrnChildB = edgeB.getDst();
4123 Integer idChildB = hrnChildB.getID();
4125 if( idChildA.equals( idChildB ) &&
4126 edgeA.typeAndFieldEquals( edgeB ) ) {
4128 // there is an edge in the right place with the right field,
4129 // but do they have the same attributes?
4130 if( edgeA.getBeta().equals( edgeB.getBeta() ) &&
4131 edgeA.equalsPreds( edgeB )
4147 // can be used to assert monotonicity
4148 static public boolean isNoSmallerThan( ReachGraph rgA,
4151 //System.out.println( "*** Asking if A is no smaller than B ***" );
4154 Iterator iA = rgA.id2hrn.entrySet().iterator();
4155 while( iA.hasNext() ) {
4156 Map.Entry meA = (Map.Entry) iA.next();
4157 Integer idA = (Integer) meA.getKey();
4158 HeapRegionNode hrnA = (HeapRegionNode) meA.getValue();
4160 if( !rgB.id2hrn.containsKey( idA ) ) {
4161 System.out.println( " regions smaller" );
4165 //HeapRegionNode hrnB = rgB.id2hrn.get( idA );
4166 /* NOT EQUALS, NO SMALLER THAN!
4167 if( !hrnA.equalsIncludingAlphaAndPreds( hrnB ) ) {
4168 System.out.println( " regions smaller" );
4174 // this works just fine, no smaller than
4175 if( !areallVNinAalsoinBandequal( rgA, rgB ) ) {
4176 System.out.println( " vars smaller:" );
4177 System.out.println( " A:"+rgA.td2vn.keySet() );
4178 System.out.println( " B:"+rgB.td2vn.keySet() );
4183 iA = rgA.id2hrn.entrySet().iterator();
4184 while( iA.hasNext() ) {
4185 Map.Entry meA = (Map.Entry) iA.next();
4186 Integer idA = (Integer) meA.getKey();
4187 HeapRegionNode hrnA = (HeapRegionNode) meA.getValue();
4189 Iterator<RefEdge> reItr = hrnA.iteratorToReferencers();
4190 while( reItr.hasNext() ) {
4191 RefEdge edgeA = reItr.next();
4192 RefSrcNode rsnA = edgeA.getSrc();
4194 // we already checked that nodes were present
4195 HeapRegionNode hrnB = rgB.id2hrn.get( hrnA.getID() );
4196 assert hrnB != null;
4199 if( rsnA instanceof VariableNode ) {
4200 VariableNode vnA = (VariableNode) rsnA;
4201 rsnB = rgB.td2vn.get( vnA.getTempDescriptor() );
4204 HeapRegionNode hrnSrcA = (HeapRegionNode) rsnA;
4205 rsnB = rgB.id2hrn.get( hrnSrcA.getID() );
4207 assert rsnB != null;
4209 RefEdge edgeB = rsnB.getReferenceTo( hrnB,
4213 if( edgeB == null ) {
4214 System.out.println( " edges smaller:" );
4218 // REMEMBER, IS NO SMALLER THAN
4220 System.out.println( " edges smaller" );
4236 // this analysis no longer has the "match anything"
4237 // type which was represented by null
4238 protected TypeDescriptor mostSpecificType( TypeDescriptor td1,
4239 TypeDescriptor td2 ) {
4243 if( td1.isNull() ) {
4246 if( td2.isNull() ) {
4249 return typeUtil.mostSpecific( td1, td2 );
4252 protected TypeDescriptor mostSpecificType( TypeDescriptor td1,
4254 TypeDescriptor td3 ) {
4256 return mostSpecificType( td1,
4257 mostSpecificType( td2, td3 )
4261 protected TypeDescriptor mostSpecificType( TypeDescriptor td1,
4264 TypeDescriptor td4 ) {
4266 return mostSpecificType( mostSpecificType( td1, td2 ),
4267 mostSpecificType( td3, td4 )
4271 protected boolean isSuperiorType( TypeDescriptor possibleSuper,
4272 TypeDescriptor possibleChild ) {
4273 assert possibleSuper != null;
4274 assert possibleChild != null;
4276 if( possibleSuper.isNull() ||
4277 possibleChild.isNull() ) {
4281 return typeUtil.isSuperorType( possibleSuper, possibleChild );
4285 protected boolean hasMatchingField( HeapRegionNode src,
4288 TypeDescriptor tdSrc = src.getType();
4289 assert tdSrc != null;
4291 if( tdSrc.isArray() ) {
4292 TypeDescriptor td = edge.getType();
4295 TypeDescriptor tdSrcDeref = tdSrc.dereference();
4296 assert tdSrcDeref != null;
4298 if( !typeUtil.isSuperorType( tdSrcDeref, td ) ) {
4302 return edge.getField().equals( DisjointAnalysis.arrayElementFieldName );
4305 // if it's not a class, it doesn't have any fields to match
4306 if( !tdSrc.isClass() ) {
4310 ClassDescriptor cd = tdSrc.getClassDesc();
4311 while( cd != null ) {
4312 Iterator fieldItr = cd.getFields();
4314 while( fieldItr.hasNext() ) {
4315 FieldDescriptor fd = (FieldDescriptor) fieldItr.next();
4317 if( fd.getType().equals( edge.getType() ) &&
4318 fd.getSymbol().equals( edge.getField() ) ) {
4323 cd = cd.getSuperDesc();
4326 // otherwise it is a class with fields
4327 // but we didn't find a match
4331 protected boolean hasMatchingType( RefEdge edge,
4332 HeapRegionNode dst ) {
4334 // if the region has no type, matches everything
4335 TypeDescriptor tdDst = dst.getType();
4336 assert tdDst != null;
4338 // if the type is not a class or an array, don't
4339 // match because primitives are copied, no aliases
4340 ClassDescriptor cdDst = tdDst.getClassDesc();
4341 if( cdDst == null && !tdDst.isArray() ) {
4345 // if the edge type is null, it matches everything
4346 TypeDescriptor tdEdge = edge.getType();
4347 assert tdEdge != null;
4349 return typeUtil.isSuperorType( tdEdge, tdDst );
4354 // the default signature for quick-and-dirty debugging
4355 public void writeGraph( String graphName ) {
4356 writeGraph( graphName,
4357 true, // write labels
4358 true, // label select
4359 true, // prune garbage
4360 false, // hide reachability
4361 true, // hide subset reachability
4362 true, // hide predicates
4363 true, // hide edge taints
4364 null // in-context boundary
4368 public void writeGraph( String graphName,
4369 boolean writeLabels,
4370 boolean labelSelect,
4371 boolean pruneGarbage,
4372 boolean hideReachability,
4373 boolean hideSubsetReachability,
4374 boolean hidePredicates,
4375 boolean hideEdgeTaints
4377 writeGraph( graphName,
4382 hideSubsetReachability,
4388 public void writeGraph( String graphName,
4389 boolean writeLabels,
4390 boolean labelSelect,
4391 boolean pruneGarbage,
4392 boolean hideReachability,
4393 boolean hideSubsetReachability,
4394 boolean hidePredicates,
4395 boolean hideEdgeTaints,
4396 Set<Integer> callerNodeIDsCopiedToCallee
4400 // remove all non-word characters from the graph name so
4401 // the filename and identifier in dot don't cause errors
4402 graphName = graphName.replaceAll( "[\\W]", "" );
4405 new BufferedWriter( new FileWriter( graphName+".dot" ) );
4407 bw.write( "digraph "+graphName+" {\n" );
4410 // this is an optional step to form the callee-reachable
4411 // "cut-out" into a DOT cluster for visualization
4412 if( callerNodeIDsCopiedToCallee != null ) {
4414 bw.write( " subgraph cluster0 {\n" );
4415 bw.write( " color=blue;\n" );
4417 Iterator i = id2hrn.entrySet().iterator();
4418 while( i.hasNext() ) {
4419 Map.Entry me = (Map.Entry) i.next();
4420 HeapRegionNode hrn = (HeapRegionNode) me.getValue();
4422 if( callerNodeIDsCopiedToCallee.contains( hrn.getID() ) ) {
4425 hrn.toStringDOT( hideReachability,
4426 hideSubsetReachability,
4436 Set<HeapRegionNode> visited = new HashSet<HeapRegionNode>();
4438 // then visit every heap region node
4439 Iterator i = id2hrn.entrySet().iterator();
4440 while( i.hasNext() ) {
4441 Map.Entry me = (Map.Entry) i.next();
4442 HeapRegionNode hrn = (HeapRegionNode) me.getValue();
4444 // only visit nodes worth writing out--for instance
4445 // not every node at an allocation is referenced
4446 // (think of it as garbage-collected), etc.
4447 if( !pruneGarbage ||
4448 hrn.isOutOfContext() ||
4449 (hrn.isFlagged() && hrn.getID() > 0 && !hrn.isWiped()) // a non-shadow flagged node
4452 if( !visited.contains( hrn ) ) {
4453 traverseHeapRegionNodes( hrn,
4458 hideSubsetReachability,
4461 callerNodeIDsCopiedToCallee );
4466 bw.write( " graphTitle[label=\""+graphName+"\",shape=box];\n" );
4469 // then visit every label node, useful for debugging
4471 i = td2vn.entrySet().iterator();
4472 while( i.hasNext() ) {
4473 Map.Entry me = (Map.Entry) i.next();
4474 VariableNode vn = (VariableNode) me.getValue();
4477 String labelStr = vn.getTempDescriptorString();
4478 if( labelStr.startsWith( "___temp" ) ||
4479 labelStr.startsWith( "___dst" ) ||
4480 labelStr.startsWith( "___srctmp" ) ||
4481 labelStr.startsWith( "___neverused" )
4487 Iterator<RefEdge> heapRegionsItr = vn.iteratorToReferencees();
4488 while( heapRegionsItr.hasNext() ) {
4489 RefEdge edge = heapRegionsItr.next();
4490 HeapRegionNode hrn = edge.getDst();
4492 if( !visited.contains( hrn ) ) {
4493 traverseHeapRegionNodes( hrn,
4498 hideSubsetReachability,
4501 callerNodeIDsCopiedToCallee );
4504 bw.write( " "+vn.toString()+
4505 " -> "+hrn.toString()+
4506 edge.toStringDOT( hideReachability,
4507 hideSubsetReachability,
4519 } catch( IOException e ) {
4520 throw new Error( "Error writing out DOT graph "+graphName );
4525 traverseHeapRegionNodes( HeapRegionNode hrn,
4528 Set<HeapRegionNode> visited,
4529 boolean hideReachability,
4530 boolean hideSubsetReachability,
4531 boolean hidePredicates,
4532 boolean hideEdgeTaints,
4533 Set<Integer> callerNodeIDsCopiedToCallee
4534 ) throws java.io.IOException {
4536 if( visited.contains( hrn ) ) {
4541 // if we're drawing the callee-view subgraph, only
4542 // write out the node info if it hasn't already been
4544 if( callerNodeIDsCopiedToCallee == null ||
4545 !callerNodeIDsCopiedToCallee.contains( hrn.getID() )
4549 hrn.toStringDOT( hideReachability,
4550 hideSubsetReachability,
4555 Iterator<RefEdge> childRegionsItr = hrn.iteratorToReferencees();
4556 while( childRegionsItr.hasNext() ) {
4557 RefEdge edge = childRegionsItr.next();
4558 HeapRegionNode hrnChild = edge.getDst();
4560 if( callerNodeIDsCopiedToCallee != null &&
4561 (edge.getSrc() instanceof HeapRegionNode) ) {
4562 HeapRegionNode hrnSrc = (HeapRegionNode) edge.getSrc();
4563 if( callerNodeIDsCopiedToCallee.contains( hrnSrc.getID() ) &&
4564 callerNodeIDsCopiedToCallee.contains( edge.getDst().getID() )
4566 bw.write( " "+hrn.toString()+
4567 " -> "+hrnChild.toString()+
4568 edge.toStringDOT( hideReachability,
4569 hideSubsetReachability,
4574 } else if( !callerNodeIDsCopiedToCallee.contains( hrnSrc.getID() ) &&
4575 callerNodeIDsCopiedToCallee.contains( edge.getDst().getID() )
4577 bw.write( " "+hrn.toString()+
4578 " -> "+hrnChild.toString()+
4579 edge.toStringDOT( hideReachability,
4580 hideSubsetReachability,
4583 ",color=blue,style=dashed" )+
4586 bw.write( " "+hrn.toString()+
4587 " -> "+hrnChild.toString()+
4588 edge.toStringDOT( hideReachability,
4589 hideSubsetReachability,
4596 bw.write( " "+hrn.toString()+
4597 " -> "+hrnChild.toString()+
4598 edge.toStringDOT( hideReachability,
4599 hideSubsetReachability,
4606 traverseHeapRegionNodes( hrnChild,
4611 hideSubsetReachability,
4614 callerNodeIDsCopiedToCallee );
4623 // return the set of heap regions from the given allocation
4624 // site, if any, that exist in this graph
4625 protected Set<HeapRegionNode> getAnyExisting( AllocSite as ) {
4627 Set<HeapRegionNode> out = new HashSet<HeapRegionNode>();
4629 Integer idSum = as.getSummary();
4630 if( id2hrn.containsKey( idSum ) ) {
4631 out.add( id2hrn.get( idSum ) );
4634 for( int i = 0; i < as.getAllocationDepth(); ++i ) {
4635 Integer idI = as.getIthOldest( i );
4636 if( id2hrn.containsKey( idI ) ) {
4637 out.add( id2hrn.get( idI ) );
4644 // return the set of reach tuples (NOT A REACH STATE! JUST A SET!)
4645 // from the given allocation site, if any, from regions for that
4646 // site that exist in this graph
4647 protected Set<ReachTuple> getAnyExisting( AllocSite as,
4648 boolean includeARITY_ZEROORMORE,
4649 boolean includeARITY_ONE ) {
4651 Set<ReachTuple> out = new HashSet<ReachTuple>();
4653 Integer idSum = as.getSummary();
4654 if( id2hrn.containsKey( idSum ) ) {
4656 HeapRegionNode hrn = id2hrn.get( idSum );
4657 assert !hrn.isOutOfContext();
4659 if( !includeARITY_ZEROORMORE ) {
4660 out.add( ReachTuple.factory( hrn.getID(),
4661 true, // multi-obj region
4662 ReachTuple.ARITY_ZEROORMORE,
4667 if( includeARITY_ONE ) {
4668 out.add( ReachTuple.factory( hrn.getID(),
4669 true, // multi-object region
4670 ReachTuple.ARITY_ONE,
4676 if( !includeARITY_ONE ) {
4677 // no need to do the single-object regions that
4678 // only have an ARITY ONE possible
4682 for( int i = 0; i < as.getAllocationDepth(); ++i ) {
4684 Integer idI = as.getIthOldest( i );
4685 if( id2hrn.containsKey( idI ) ) {
4687 HeapRegionNode hrn = id2hrn.get( idI );
4688 assert !hrn.isOutOfContext();
4690 out.add( ReachTuple.factory( hrn.getID(),
4691 false, // multi-object region
4692 ReachTuple.ARITY_ONE,
4702 // if an object allocated at the target site may be
4703 // reachable from both an object from root1 and an
4704 // object allocated at root2, return TRUE
4705 public boolean mayBothReachTarget( AllocSite asRoot1,
4707 AllocSite asTarget ) {
4709 // consider all heap regions of the target and look
4710 // for a reach state that indicates regions of root1
4711 // and root2 might be able to reach same object
4712 Set<HeapRegionNode> hrnSetTarget = getAnyExisting( asTarget );
4714 // get relevant reach tuples, include ARITY_ZEROORMORE and ARITY_ONE
4715 Set<ReachTuple> rtSet1 = getAnyExisting( asRoot1, true, true );
4716 Set<ReachTuple> rtSet2 = getAnyExisting( asRoot2, true, true );
4718 Iterator<HeapRegionNode> hrnItr = hrnSetTarget.iterator();
4719 while( hrnItr.hasNext() ) {
4720 HeapRegionNode hrn = hrnItr.next();
4722 Iterator<ReachTuple> rtItr1 = rtSet1.iterator();
4723 while( rtItr1.hasNext() ) {
4724 ReachTuple rt1 = rtItr1.next();
4726 Iterator<ReachTuple> rtItr2 = rtSet2.iterator();
4727 while( rtItr2.hasNext() ) {
4728 ReachTuple rt2 = rtItr2.next();
4730 if( !hrn.getAlpha().getStatesWithBoth( rt1, rt2 ).isEmpty() ) {
4740 // similar to the method above, return TRUE if ever
4741 // more than one object from the root allocation site
4742 // may reach an object from the target site
4743 public boolean mayManyReachTarget( AllocSite asRoot,
4744 AllocSite asTarget ) {
4746 // consider all heap regions of the target and look
4747 // for a reach state that multiple objects of root
4748 // might be able to reach the same object
4749 Set<HeapRegionNode> hrnSetTarget = getAnyExisting( asTarget );
4751 // get relevant reach tuples
4752 Set<ReachTuple> rtSetZOM = getAnyExisting( asRoot, true, false );
4753 Set<ReachTuple> rtSetONE = getAnyExisting( asRoot, false, true );
4755 Iterator<HeapRegionNode> hrnItr = hrnSetTarget.iterator();
4756 while( hrnItr.hasNext() ) {
4757 HeapRegionNode hrn = hrnItr.next();
4759 // if any ZERORMORE tuples are here, TRUE
4760 Iterator<ReachTuple> rtItr = rtSetZOM.iterator();
4761 while( rtItr.hasNext() ) {
4762 ReachTuple rtZOM = rtItr.next();
4764 if( hrn.getAlpha().containsTuple( rtZOM ) ) {
4769 // otherwise, look for any pair of ONE tuples
4770 Iterator<ReachTuple> rtItr1 = rtSetONE.iterator();
4771 while( rtItr1.hasNext() ) {
4772 ReachTuple rt1 = rtItr1.next();
4774 Iterator<ReachTuple> rtItr2 = rtSetONE.iterator();
4775 while( rtItr2.hasNext() ) {
4776 ReachTuple rt2 = rtItr2.next();
4782 if( !hrn.getAlpha().getStatesWithBoth( rt1, rt2 ).isEmpty() ) {
4796 public Set<HeapRegionNode> findCommonReachableNodes( ReachSet proofOfSharing ) {
4798 Set<HeapRegionNode> exhibitProofState =
4799 new HashSet<HeapRegionNode>();
4801 Iterator hrnItr = id2hrn.entrySet().iterator();
4802 while( hrnItr.hasNext() ) {
4803 Map.Entry me = (Map.Entry) hrnItr.next();
4804 HeapRegionNode hrn = (HeapRegionNode) me.getValue();
4806 ReachSet intersection =
4807 Canonical.intersection( proofOfSharing,
4810 if( !intersection.isEmpty() ) {
4811 assert !hrn.isOutOfContext();
4812 exhibitProofState.add( hrn );
4816 return exhibitProofState;
4820 public Set<HeapRegionNode> mayReachSharedObjects(HeapRegionNode hrn1,
4821 HeapRegionNode hrn2) {
4822 assert hrn1 != null;
4823 assert hrn2 != null;
4825 assert !hrn1.isOutOfContext();
4826 assert !hrn2.isOutOfContext();
4828 assert belongsToThis( hrn1 );
4829 assert belongsToThis( hrn2 );
4831 assert !hrn1.getID().equals( hrn2.getID() );
4834 // then get the various tokens for these heap regions
4836 ReachTuple.factory( hrn1.getID(),
4837 !hrn1.isSingleObject(), // multi?
4838 ReachTuple.ARITY_ONE,
4841 ReachTuple h1star = null;
4842 if( !hrn1.isSingleObject() ) {
4844 ReachTuple.factory( hrn1.getID(),
4845 !hrn1.isSingleObject(),
4846 ReachTuple.ARITY_ZEROORMORE,
4851 ReachTuple.factory( hrn2.getID(),
4852 !hrn2.isSingleObject(),
4853 ReachTuple.ARITY_ONE,
4856 ReachTuple h2star = null;
4857 if( !hrn2.isSingleObject() ) {
4859 ReachTuple.factory( hrn2.getID(),
4860 !hrn2.isSingleObject(),
4861 ReachTuple.ARITY_ZEROORMORE,
4865 // then get the merged beta of all out-going edges from these heap
4868 ReachSet beta1 = ReachSet.factory();
4869 Iterator<RefEdge> itrEdge = hrn1.iteratorToReferencees();
4870 while (itrEdge.hasNext()) {
4871 RefEdge edge = itrEdge.next();
4872 beta1 = Canonical.unionORpreds(beta1, edge.getBeta());
4875 ReachSet beta2 = ReachSet.factory();
4876 itrEdge = hrn2.iteratorToReferencees();
4877 while (itrEdge.hasNext()) {
4878 RefEdge edge = itrEdge.next();
4879 beta2 = Canonical.unionORpreds(beta2, edge.getBeta());
4882 ReachSet proofOfSharing = ReachSet.factory();
4885 Canonical.unionORpreds( proofOfSharing,
4886 beta1.getStatesWithBoth( h1, h2 )
4889 Canonical.unionORpreds( proofOfSharing,
4890 beta2.getStatesWithBoth( h1, h2 )
4893 if( !hrn1.isSingleObject() ) {
4895 Canonical.unionORpreds( proofOfSharing,
4896 beta1.getStatesWithBoth( h1star, h2 )
4899 Canonical.unionORpreds( proofOfSharing,
4900 beta2.getStatesWithBoth( h1star, h2 )
4904 if( !hrn2.isSingleObject() ) {
4906 Canonical.unionORpreds( proofOfSharing,
4907 beta1.getStatesWithBoth( h1, h2star )
4910 Canonical.unionORpreds( proofOfSharing,
4911 beta2.getStatesWithBoth( h1, h2star )
4915 if( !hrn1.isSingleObject() &&
4916 !hrn2.isSingleObject()
4919 Canonical.unionORpreds( proofOfSharing,
4920 beta1.getStatesWithBoth( h1star, h2star )
4923 Canonical.unionORpreds( proofOfSharing,
4924 beta2.getStatesWithBoth( h1star, h2star )
4928 Set<HeapRegionNode> common = new HashSet<HeapRegionNode>();
4929 if( !proofOfSharing.isEmpty() ) {
4930 common = findCommonReachableNodes( proofOfSharing );
4931 if( !DISABLE_STRONG_UPDATES &&
4932 !DISABLE_GLOBAL_SWEEP
4934 assert !common.isEmpty();
4941 // this version of the above method checks whether there is sharing
4942 // among the objects in a summary node
4943 public Set<HeapRegionNode> mayReachSharedObjects(HeapRegionNode hrn) {
4945 assert hrn.isNewSummary();
4946 assert !hrn.isOutOfContext();
4947 assert belongsToThis( hrn );
4950 ReachTuple.factory( hrn.getID(),
4952 ReachTuple.ARITY_ZEROORMORE,
4955 // then get the merged beta of all out-going edges from
4958 ReachSet beta = ReachSet.factory();
4959 Iterator<RefEdge> itrEdge = hrn.iteratorToReferencees();
4960 while (itrEdge.hasNext()) {
4961 RefEdge edge = itrEdge.next();
4962 beta = Canonical.unionORpreds(beta, edge.getBeta());
4965 ReachSet proofOfSharing = ReachSet.factory();
4968 Canonical.unionORpreds( proofOfSharing,
4969 beta.getStatesWithBoth( hstar, hstar )
4972 Set<HeapRegionNode> common = new HashSet<HeapRegionNode>();
4973 if( !proofOfSharing.isEmpty() ) {
4974 common = findCommonReachableNodes( proofOfSharing );
4975 if( !DISABLE_STRONG_UPDATES &&
4976 !DISABLE_GLOBAL_SWEEP
4978 assert !common.isEmpty();
4986 public Set<HeapRegionNode> mayReachSharedObjects(FlatMethod fm,
4987 Integer paramIndex1,
4988 Integer paramIndex2) {
4990 // get parameter's heap regions
4991 TempDescriptor paramTemp1 = fm.getParameter(paramIndex1.intValue());
4992 assert this.hasVariable( paramTemp1 );
4993 VariableNode paramVar1 = getVariableNodeFromTemp(paramTemp1);
4996 if( !(paramVar1.getNumReferencees() == 1) ) {
4997 System.out.println( "\n fm="+fm+"\n param="+paramTemp1 );
4998 writeGraph( "whatup" );
5002 assert paramVar1.getNumReferencees() == 1;
5003 RefEdge paramEdge1 = paramVar1.iteratorToReferencees().next();
5004 HeapRegionNode hrnParam1 = paramEdge1.getDst();
5006 TempDescriptor paramTemp2 = fm.getParameter(paramIndex2.intValue());
5007 assert this.hasVariable( paramTemp2 );
5008 VariableNode paramVar2 = getVariableNodeFromTemp(paramTemp2);
5010 if( !(paramVar2.getNumReferencees() == 1) ) {
5011 System.out.println( "\n fm="+fm+"\n param="+paramTemp2 );
5012 writeGraph( "whatup" );
5015 assert paramVar2.getNumReferencees() == 1;
5016 RefEdge paramEdge2 = paramVar2.iteratorToReferencees().next();
5017 HeapRegionNode hrnParam2 = paramEdge2.getDst();
5019 Set<HeapRegionNode> common = new HashSet<HeapRegionNode>();
5020 common.addAll(mayReachSharedObjects(hrnParam1, hrnParam2));
5025 public Set<HeapRegionNode> mayReachSharedObjects(FlatMethod fm,
5029 // get parameter's heap regions
5030 TempDescriptor paramTemp = fm.getParameter(paramIndex.intValue());
5031 assert this.hasVariable( paramTemp );
5032 VariableNode paramVar = getVariableNodeFromTemp(paramTemp);
5033 assert paramVar.getNumReferencees() == 1;
5034 RefEdge paramEdge = paramVar.iteratorToReferencees().next();
5035 HeapRegionNode hrnParam = paramEdge.getDst();
5038 HeapRegionNode hrnSummary=null;
5039 if(id2hrn.containsKey(as.getSummary())){
5040 // if summary node doesn't exist, ignore this case
5041 hrnSummary = id2hrn.get(as.getSummary());
5042 assert hrnSummary != null;
5045 Set<HeapRegionNode> common = new HashSet<HeapRegionNode>();
5046 if(hrnSummary!=null){
5047 common.addAll( mayReachSharedObjects(hrnParam, hrnSummary) );
5050 // check for other nodes
5051 for (int i = 0; i < as.getAllocationDepth(); ++i) {
5053 assert id2hrn.containsKey(as.getIthOldest(i));
5054 HeapRegionNode hrnIthOldest = id2hrn.get(as.getIthOldest(i));
5055 assert hrnIthOldest != null;
5057 common.addAll(mayReachSharedObjects(hrnParam, hrnIthOldest));
5064 public Set<HeapRegionNode> mayReachSharedObjects(AllocSite as1,
5067 // get summary node 1's alpha
5068 Integer idSum1 = as1.getSummary();
5069 HeapRegionNode hrnSum1=null;
5070 if(id2hrn.containsKey(idSum1)){
5071 hrnSum1 = id2hrn.get(idSum1);
5074 // get summary node 2's alpha
5075 Integer idSum2 = as2.getSummary();
5076 HeapRegionNode hrnSum2=null;
5077 if(id2hrn.containsKey(idSum2)){
5078 hrnSum2 = id2hrn.get(idSum2);
5081 Set<HeapRegionNode> common = new HashSet<HeapRegionNode>();
5082 if(hrnSum1!=null && hrnSum2!=null && hrnSum1!=hrnSum2){
5083 common.addAll(mayReachSharedObjects(hrnSum1, hrnSum2));
5087 // ask if objects from this summary share among each other
5088 common.addAll(mayReachSharedObjects(hrnSum1));
5091 // check sum2 against alloc1 nodes
5093 for (int i = 0; i < as1.getAllocationDepth(); ++i) {
5094 Integer idI1 = as1.getIthOldest(i);
5095 assert id2hrn.containsKey(idI1);
5096 HeapRegionNode hrnI1 = id2hrn.get(idI1);
5097 assert hrnI1 != null;
5098 common.addAll(mayReachSharedObjects(hrnI1, hrnSum2));
5101 // also ask if objects from this summary share among each other
5102 common.addAll(mayReachSharedObjects(hrnSum2));
5105 // check sum1 against alloc2 nodes
5106 for (int i = 0; i < as2.getAllocationDepth(); ++i) {
5107 Integer idI2 = as2.getIthOldest(i);
5108 assert id2hrn.containsKey(idI2);
5109 HeapRegionNode hrnI2 = id2hrn.get(idI2);
5110 assert hrnI2 != null;
5113 common.addAll(mayReachSharedObjects(hrnSum1, hrnI2));
5116 // while we're at it, do an inner loop for alloc2 vs alloc1 nodes
5117 for (int j = 0; j < as1.getAllocationDepth(); ++j) {
5118 Integer idI1 = as1.getIthOldest(j);
5120 // if these are the same site, don't look for the same token, no
5122 // different tokens of the same site could alias together though
5123 if (idI1.equals(idI2)) {
5127 HeapRegionNode hrnI1 = id2hrn.get(idI1);
5129 common.addAll(mayReachSharedObjects(hrnI1, hrnI2));
5136 public void makeInaccessible( Set<TempDescriptor> vars ) {
5137 inaccessibleVars.addAll( vars );
5140 public void makeInaccessible( TempDescriptor td ) {
5141 inaccessibleVars.add( td );
5144 public void makeAccessible( TempDescriptor td ) {
5145 inaccessibleVars.remove( td );
5148 public boolean isAccessible(TempDescriptor td) {
5149 return !inaccessibleVars.contains(td);
5152 public Set<TempDescriptor> getInaccessibleVars() {
5153 return inaccessibleVars;