1 package Analysis.Disjoint;
5 import Util.UtilAlgorithms;
9 public class ReachGraph {
11 // use to disable improvements for comparison
12 protected static final boolean DISABLE_STRONG_UPDATES = false;
13 protected static final boolean DISABLE_GLOBAL_SWEEP = false;
15 // a special out-of-scope temp
16 protected static final TempDescriptor tdReturn = new TempDescriptor( "_Return___" );
18 // predicate constants
19 public static final ExistPred predTrue = ExistPred.factory(); // if no args, true
20 public static final ExistPredSet predsEmpty = ExistPredSet.factory();
21 public static final ExistPredSet predsTrue = ExistPredSet.factory( predTrue );
23 // some frequently used reachability constants
24 protected static final ReachState rstateEmpty = ReachState.factory();
25 protected static final ReachSet rsetEmpty = ReachSet.factory();
26 protected static final ReachSet rsetWithEmptyState = Canonical.changePredsTo( ReachSet.factory( rstateEmpty ),
29 // from DisjointAnalysis for convenience
30 protected static int allocationDepth = -1;
31 protected static TypeUtil typeUtil = null;
32 protected static State state = null;
35 // variable and heap region nodes indexed by unique ID
36 public Hashtable<Integer, HeapRegionNode> id2hrn;
37 public Hashtable<TempDescriptor, VariableNode > td2vn;
39 // convenient set of alloc sites for all heap regions
40 // present in the graph without having to search
41 public Set<AllocSite> allocSites;
43 // set of inaccessible variables for current program statement
44 // with respect to stall-site analysis
45 public Set<TempDescriptor> inaccessibleVars;
49 id2hrn = new Hashtable<Integer, HeapRegionNode>();
50 td2vn = new Hashtable<TempDescriptor, VariableNode >();
51 allocSites = new HashSet<AllocSite>();
52 inaccessibleVars = new HashSet<TempDescriptor>();
56 // temp descriptors are globally unique and map to
57 // exactly one variable node, easy
58 protected VariableNode getVariableNodeFromTemp( TempDescriptor td ) {
61 if( !td2vn.containsKey( td ) ) {
62 td2vn.put( td, new VariableNode( td ) );
65 return td2vn.get( td );
68 //This method is created for client modules to access the Reachgraph
69 //after the analysis is done and no modifications are to be made.
70 public VariableNode getVariableNodeNoMutation( TempDescriptor td ) {
73 if( !td2vn.containsKey( td ) ) {
77 return td2vn.get( td );
80 public boolean hasVariable( TempDescriptor td ) {
81 return td2vn.containsKey( td );
85 // this suite of methods can be used to assert a
86 // very important property of ReachGraph objects:
87 // some element, HeapRegionNode, RefEdge etc.
88 // should be referenced by at most ONE ReachGraph!!
89 // If a heap region or edge or variable should be
90 // in another graph, make a new object with
91 // equivalent properties for a new graph
92 public boolean belongsToThis( RefSrcNode rsn ) {
93 if( rsn instanceof VariableNode ) {
94 VariableNode vn = (VariableNode) rsn;
95 return this.td2vn.get( vn.getTempDescriptor() ) == vn;
97 HeapRegionNode hrn = (HeapRegionNode) rsn;
98 return this.id2hrn.get( hrn.getID() ) == hrn;
105 // the reason for this method is to have the option
106 // of creating new heap regions with specific IDs, or
107 // duplicating heap regions with specific IDs (especially
108 // in the merge() operation) or to create new heap
109 // regions with a new unique ID
110 protected HeapRegionNode
111 createNewHeapRegionNode( Integer id,
112 boolean isSingleObject,
113 boolean isNewSummary,
114 boolean isOutOfContext,
123 TypeDescriptor typeToUse = null;
124 if( allocSite != null ) {
125 typeToUse = allocSite.getType();
126 allocSites.add( allocSite );
131 boolean markForAnalysis = false;
132 if( allocSite != null && allocSite.isFlagged() ) {
133 markForAnalysis = true;
136 if( allocSite == null ) {
137 assert !markForAnalysis;
139 } else if( markForAnalysis != allocSite.isFlagged() ) {
145 id = DisjointAnalysis.generateUniqueHeapRegionNodeID();
148 if( inherent == null ) {
149 if( markForAnalysis ) {
151 Canonical.changePredsTo(
154 ReachTuple.factory( id,
156 ReachTuple.ARITY_ONE,
157 false // out-of-context
164 inherent = rsetWithEmptyState;
168 if( alpha == null ) {
172 assert preds != null;
174 HeapRegionNode hrn = new HeapRegionNode( id,
185 id2hrn.put( id, hrn );
191 ////////////////////////////////////////////////
193 // Low-level referencee and referencer methods
195 // These methods provide the lowest level for
196 // creating references between reachability nodes
197 // and handling the details of maintaining both
198 // list of referencers and referencees.
200 ////////////////////////////////////////////////
201 protected void addRefEdge( RefSrcNode referencer,
202 HeapRegionNode referencee,
204 assert referencer != null;
205 assert referencee != null;
207 assert edge.getSrc() == referencer;
208 assert edge.getDst() == referencee;
209 assert belongsToThis( referencer );
210 assert belongsToThis( referencee );
212 // edges are getting added twice to graphs now, the
213 // kind that should have abstract facts merged--use
214 // this check to prevent that
215 assert referencer.getReferenceTo( referencee,
220 referencer.addReferencee( edge );
221 referencee.addReferencer( edge );
224 protected void removeRefEdge( RefEdge e ) {
225 removeRefEdge( e.getSrc(),
231 protected void removeRefEdge( RefSrcNode referencer,
232 HeapRegionNode referencee,
235 assert referencer != null;
236 assert referencee != null;
238 RefEdge edge = referencer.getReferenceTo( referencee,
242 assert edge == referencee.getReferenceFrom( referencer,
246 referencer.removeReferencee( edge );
247 referencee.removeReferencer( edge );
250 // return whether at least one edge was removed
251 protected boolean clearRefEdgesFrom( RefSrcNode referencer,
254 boolean removeAll ) {
255 assert referencer != null;
257 boolean atLeastOneEdgeRemoved = false;
259 // get a copy of the set to iterate over, otherwise
260 // we will be trying to take apart the set as we
261 // are iterating over it, which won't work
262 Iterator<RefEdge> i = referencer.iteratorToReferenceesClone();
263 while( i.hasNext() ) {
264 RefEdge edge = i.next();
267 (edge.typeEquals( type ) && edge.fieldEquals( field ))
270 HeapRegionNode referencee = edge.getDst();
272 removeRefEdge( referencer,
277 atLeastOneEdgeRemoved = true;
281 return atLeastOneEdgeRemoved;
284 protected void clearRefEdgesTo( HeapRegionNode referencee,
287 boolean removeAll ) {
288 assert referencee != null;
290 // get a copy of the set to iterate over, otherwise
291 // we will be trying to take apart the set as we
292 // are iterating over it, which won't work
293 Iterator<RefEdge> i = referencee.iteratorToReferencersClone();
294 while( i.hasNext() ) {
295 RefEdge edge = i.next();
298 (edge.typeEquals( type ) && edge.fieldEquals( field ))
301 RefSrcNode referencer = edge.getSrc();
303 removeRefEdge( referencer,
311 protected void clearNonVarRefEdgesTo( HeapRegionNode referencee ) {
312 assert referencee != null;
314 // get a copy of the set to iterate over, otherwise
315 // we will be trying to take apart the set as we
316 // are iterating over it, which won't work
317 Iterator<RefEdge> i = referencee.iteratorToReferencersClone();
318 while( i.hasNext() ) {
319 RefEdge edge = i.next();
320 RefSrcNode referencer = edge.getSrc();
321 if( !(referencer instanceof VariableNode) ) {
322 removeRefEdge( referencer,
330 // this is a common operation in many transfer functions: we want
331 // to add an edge, but if there is already such an edge we should
332 // merge the properties of the existing and the new edges
333 protected void addEdgeOrMergeWithExisting( RefEdge edgeNew ) {
335 RefSrcNode src = edgeNew.getSrc();
336 assert belongsToThis( src );
338 HeapRegionNode dst = edgeNew.getDst();
339 assert belongsToThis( dst );
341 // look to see if an edge with same field exists
342 // and merge with it, otherwise just add the edge
343 RefEdge edgeExisting = src.getReferenceTo( dst,
348 if( edgeExisting != null ) {
349 edgeExisting.setBeta(
350 Canonical.unionORpreds( edgeExisting.getBeta(),
354 edgeExisting.setPreds(
355 Canonical.join( edgeExisting.getPreds(),
359 edgeExisting.setTaints(
360 Canonical.unionORpreds( edgeExisting.getTaints(),
366 addRefEdge( src, dst, edgeNew );
372 ////////////////////////////////////////////////////
374 // Assignment Operation Methods
376 // These methods are high-level operations for
377 // modeling program assignment statements using
378 // the low-level reference create/remove methods
381 ////////////////////////////////////////////////////
383 public void assignTempXEqualToTempY( TempDescriptor x,
385 assignTempXEqualToCastedTempY( x, y, null );
389 public void assignTempXEqualToCastedTempY( TempDescriptor x,
391 TypeDescriptor tdCast ) {
393 VariableNode lnX = getVariableNodeFromTemp( x );
394 VariableNode lnY = getVariableNodeFromTemp( y );
396 clearRefEdgesFrom( lnX, null, null, true );
398 // note it is possible that the types of temps in the
399 // flat node to analyze will reveal that some typed
400 // edges in the reachability graph are impossible
401 Set<RefEdge> impossibleEdges = new HashSet<RefEdge>();
403 Iterator<RefEdge> itrYhrn = lnY.iteratorToReferencees();
404 while( itrYhrn.hasNext() ) {
405 RefEdge edgeY = itrYhrn.next();
406 HeapRegionNode referencee = edgeY.getDst();
407 RefEdge edgeNew = edgeY.copy();
409 if( !isSuperiorType( x.getType(), edgeY.getType() ) ) {
410 impossibleEdges.add( edgeY );
414 edgeNew.setSrc( lnX );
416 if( tdCast == null ) {
417 edgeNew.setType( mostSpecificType( y.getType(),
423 edgeNew.setType( mostSpecificType( y.getType(),
425 referencee.getType(),
431 edgeNew.setField( null );
433 addRefEdge( lnX, referencee, edgeNew );
436 Iterator<RefEdge> itrImp = impossibleEdges.iterator();
437 while( itrImp.hasNext() ) {
438 RefEdge edgeImp = itrImp.next();
439 removeRefEdge( edgeImp );
444 public void assignTempXEqualToTempYFieldF( TempDescriptor x,
446 FieldDescriptor f ) {
447 VariableNode lnX = getVariableNodeFromTemp( x );
448 VariableNode lnY = getVariableNodeFromTemp( y );
450 clearRefEdgesFrom( lnX, null, null, true );
452 // note it is possible that the types of temps in the
453 // flat node to analyze will reveal that some typed
454 // edges in the reachability graph are impossible
455 Set<RefEdge> impossibleEdges = new HashSet<RefEdge>();
457 Iterator<RefEdge> itrYhrn = lnY.iteratorToReferencees();
458 while( itrYhrn.hasNext() ) {
459 RefEdge edgeY = itrYhrn.next();
460 HeapRegionNode hrnY = edgeY.getDst();
461 ReachSet betaY = edgeY.getBeta();
463 Iterator<RefEdge> itrHrnFhrn = hrnY.iteratorToReferencees();
465 while( itrHrnFhrn.hasNext() ) {
466 RefEdge edgeHrn = itrHrnFhrn.next();
467 HeapRegionNode hrnHrn = edgeHrn.getDst();
468 ReachSet betaHrn = edgeHrn.getBeta();
470 // prune edges that are not a matching field
471 if( edgeHrn.getType() != null &&
472 !edgeHrn.getField().equals( f.getSymbol() )
477 // check for impossible edges
478 if( !isSuperiorType( x.getType(), edgeHrn.getType() ) ) {
479 impossibleEdges.add( edgeHrn );
483 TypeDescriptor tdNewEdge =
484 mostSpecificType( edgeHrn.getType(),
488 RefEdge edgeNew = new RefEdge( lnX,
492 Canonical.intersection( betaY, betaHrn ),
494 Canonical.unionORpreds(edgeHrn.getTaints(),edgeY.getTaints())
497 addEdgeOrMergeWithExisting( edgeNew );
501 Iterator<RefEdge> itrImp = impossibleEdges.iterator();
502 while( itrImp.hasNext() ) {
503 RefEdge edgeImp = itrImp.next();
504 removeRefEdge( edgeImp );
507 // anytime you might remove edges between heap regions
508 // you must global sweep to clean up broken reachability
509 if( !impossibleEdges.isEmpty() ) {
510 if( !DISABLE_GLOBAL_SWEEP ) {
518 // return whether a strong update was actually effected
519 public boolean assignTempXFieldFEqualToTempY( TempDescriptor x,
523 VariableNode lnX = getVariableNodeFromTemp( x );
524 VariableNode lnY = getVariableNodeFromTemp( y );
526 HashSet<HeapRegionNode> nodesWithNewAlpha = new HashSet<HeapRegionNode>();
527 HashSet<RefEdge> edgesWithNewBeta = new HashSet<RefEdge>();
529 // note it is possible that the types of temps in the
530 // flat node to analyze will reveal that some typed
531 // edges in the reachability graph are impossible
532 Set<RefEdge> impossibleEdges = new HashSet<RefEdge>();
534 // first look for possible strong updates and remove those edges
535 boolean strongUpdateCond = false;
536 boolean edgeRemovedByStrongUpdate = false;
538 Iterator<RefEdge> itrXhrn = lnX.iteratorToReferencees();
539 while( itrXhrn.hasNext() ) {
540 RefEdge edgeX = itrXhrn.next();
541 HeapRegionNode hrnX = edgeX.getDst();
543 // we can do a strong update here if one of two cases holds
545 f != DisjointAnalysis.getArrayField( f.getType() ) &&
546 ( (hrnX.getNumReferencers() == 1) || // case 1
547 (hrnX.isSingleObject() && lnX.getNumReferencees() == 1) // case 2
550 if( !DISABLE_STRONG_UPDATES ) {
551 strongUpdateCond = true;
554 clearRefEdgesFrom( hrnX,
559 edgeRemovedByStrongUpdate = true;
565 // then do all token propagation
566 itrXhrn = lnX.iteratorToReferencees();
567 while( itrXhrn.hasNext() ) {
568 RefEdge edgeX = itrXhrn.next();
569 HeapRegionNode hrnX = edgeX.getDst();
570 ReachSet betaX = edgeX.getBeta();
571 ReachSet R = Canonical.intersection( hrnX.getAlpha(),
575 Iterator<RefEdge> itrYhrn = lnY.iteratorToReferencees();
576 while( itrYhrn.hasNext() ) {
577 RefEdge edgeY = itrYhrn.next();
578 HeapRegionNode hrnY = edgeY.getDst();
579 ReachSet O = edgeY.getBeta();
581 // check for impossible edges
582 if( !isSuperiorType( f.getType(), edgeY.getType() ) ) {
583 impossibleEdges.add( edgeY );
587 // propagate tokens over nodes starting from hrnSrc, and it will
588 // take care of propagating back up edges from any touched nodes
589 ChangeSet Cy = Canonical.unionUpArityToChangeSet( O, R );
590 propagateTokensOverNodes( hrnY, Cy, nodesWithNewAlpha, edgesWithNewBeta );
592 // then propagate back just up the edges from hrn
593 ChangeSet Cx = Canonical.unionUpArityToChangeSet( R, O );
594 HashSet<RefEdge> todoEdges = new HashSet<RefEdge>();
596 Hashtable<RefEdge, ChangeSet> edgePlannedChanges =
597 new Hashtable<RefEdge, ChangeSet>();
599 Iterator<RefEdge> referItr = hrnX.iteratorToReferencers();
600 while( referItr.hasNext() ) {
601 RefEdge edgeUpstream = referItr.next();
602 todoEdges.add( edgeUpstream );
603 edgePlannedChanges.put( edgeUpstream, Cx );
606 propagateTokensOverEdges( todoEdges,
613 // apply the updates to reachability
614 Iterator<HeapRegionNode> nodeItr = nodesWithNewAlpha.iterator();
615 while( nodeItr.hasNext() ) {
616 nodeItr.next().applyAlphaNew();
619 Iterator<RefEdge> edgeItr = edgesWithNewBeta.iterator();
620 while( edgeItr.hasNext() ) {
621 edgeItr.next().applyBetaNew();
625 // then go back through and add the new edges
626 itrXhrn = lnX.iteratorToReferencees();
627 while( itrXhrn.hasNext() ) {
628 RefEdge edgeX = itrXhrn.next();
629 HeapRegionNode hrnX = edgeX.getDst();
631 Iterator<RefEdge> itrYhrn = lnY.iteratorToReferencees();
632 while( itrYhrn.hasNext() ) {
633 RefEdge edgeY = itrYhrn.next();
634 HeapRegionNode hrnY = edgeY.getDst();
636 // skip impossible edges here, we already marked them
637 // when computing reachability propagations above
638 if( !isSuperiorType( f.getType(), edgeY.getType() ) ) {
642 // prepare the new reference edge hrnX.f -> hrnY
643 TypeDescriptor tdNewEdge =
644 mostSpecificType( y.getType(),
654 Canonical.changePredsTo(
655 Canonical.pruneBy( edgeY.getBeta(),
664 addEdgeOrMergeWithExisting( edgeNew );
668 Iterator<RefEdge> itrImp = impossibleEdges.iterator();
669 while( itrImp.hasNext() ) {
670 RefEdge edgeImp = itrImp.next();
671 removeRefEdge( edgeImp );
674 // if there was a strong update, make sure to improve
675 // reachability with a global sweep
676 if( edgeRemovedByStrongUpdate || !impossibleEdges.isEmpty() ) {
677 if( !DISABLE_GLOBAL_SWEEP ) {
682 return edgeRemovedByStrongUpdate;
686 public void assignReturnEqualToTemp( TempDescriptor x ) {
688 VariableNode lnR = getVariableNodeFromTemp( tdReturn );
689 VariableNode lnX = getVariableNodeFromTemp( x );
691 clearRefEdgesFrom( lnR, null, null, true );
693 Iterator<RefEdge> itrXhrn = lnX.iteratorToReferencees();
694 while( itrXhrn.hasNext() ) {
695 RefEdge edgeX = itrXhrn.next();
696 HeapRegionNode referencee = edgeX.getDst();
697 RefEdge edgeNew = edgeX.copy();
698 edgeNew.setSrc( lnR );
699 edgeNew.setTaints( Canonical.changePredsTo( edgeNew.getTaints(),
704 addRefEdge( lnR, referencee, edgeNew );
709 public void assignTempEqualToNewAlloc( TempDescriptor x,
716 // after the age operation the newest (or zero-ith oldest)
717 // node associated with the allocation site should have
718 // no references to it as if it were a newly allocated
720 Integer idNewest = as.getIthOldest( 0 );
721 HeapRegionNode hrnNewest = id2hrn.get( idNewest );
722 assert hrnNewest != null;
724 VariableNode lnX = getVariableNodeFromTemp( x );
725 clearRefEdgesFrom( lnX, null, null, true );
727 // make a new reference to allocated node
728 TypeDescriptor type = as.getType();
731 new RefEdge( lnX, // source
735 hrnNewest.getAlpha(), // beta
736 predsTrue, // predicates
737 TaintSet.factory() // taints
740 addRefEdge( lnX, hrnNewest, edgeNew );
744 // use the allocation site (unique to entire analysis) to
745 // locate the heap region nodes in this reachability graph
746 // that should be aged. The process models the allocation
747 // of new objects and collects all the oldest allocations
748 // in a summary node to allow for a finite analysis
750 // There is an additional property of this method. After
751 // running it on a particular reachability graph (many graphs
752 // may have heap regions related to the same allocation site)
753 // the heap region node objects in this reachability graph will be
754 // allocated. Therefore, after aging a graph for an allocation
755 // site, attempts to retrieve the heap region nodes using the
756 // integer id's contained in the allocation site should always
757 // return non-null heap regions.
758 public void age( AllocSite as ) {
760 // keep track of allocation sites that are represented
761 // in this graph for efficiency with other operations
762 allocSites.add( as );
764 // if there is a k-th oldest node, it merges into
766 Integer idK = as.getOldest();
767 if( id2hrn.containsKey( idK ) ) {
768 HeapRegionNode hrnK = id2hrn.get( idK );
770 // retrieve the summary node, or make it
772 HeapRegionNode hrnSummary = getSummaryNode( as, false );
774 mergeIntoSummary( hrnK, hrnSummary );
777 // move down the line of heap region nodes
778 // clobbering the ith and transferring all references
779 // to and from i-1 to node i.
780 for( int i = allocationDepth - 1; i > 0; --i ) {
782 // only do the transfer if the i-1 node exists
783 Integer idImin1th = as.getIthOldest( i - 1 );
784 if( id2hrn.containsKey( idImin1th ) ) {
785 HeapRegionNode hrnImin1 = id2hrn.get( idImin1th );
786 if( hrnImin1.isWiped() ) {
787 // there is no info on this node, just skip
791 // either retrieve or make target of transfer
792 HeapRegionNode hrnI = getIthNode( as, i, false );
794 transferOnto( hrnImin1, hrnI );
799 // as stated above, the newest node should have had its
800 // references moved over to the second oldest, so we wipe newest
801 // in preparation for being the new object to assign something to
802 HeapRegionNode hrn0 = getIthNode( as, 0, false );
803 wipeOut( hrn0, true );
805 // now tokens in reachability sets need to "age" also
806 Iterator itrAllVariableNodes = td2vn.entrySet().iterator();
807 while( itrAllVariableNodes.hasNext() ) {
808 Map.Entry me = (Map.Entry) itrAllVariableNodes.next();
809 VariableNode ln = (VariableNode) me.getValue();
811 Iterator<RefEdge> itrEdges = ln.iteratorToReferencees();
812 while( itrEdges.hasNext() ) {
813 ageTuplesFrom( as, itrEdges.next() );
817 Iterator itrAllHRNodes = id2hrn.entrySet().iterator();
818 while( itrAllHRNodes.hasNext() ) {
819 Map.Entry me = (Map.Entry) itrAllHRNodes.next();
820 HeapRegionNode hrnToAge = (HeapRegionNode) me.getValue();
822 ageTuplesFrom( as, hrnToAge );
824 Iterator<RefEdge> itrEdges = hrnToAge.iteratorToReferencees();
825 while( itrEdges.hasNext() ) {
826 ageTuplesFrom( as, itrEdges.next() );
831 // after tokens have been aged, reset newest node's reachability
832 // and a brand new node has a "true" predicate
833 hrn0.setAlpha( hrn0.getInherent() );
834 hrn0.setPreds( predsTrue );
838 // either retrieve or create the needed heap region node
839 protected HeapRegionNode getSummaryNode( AllocSite as,
844 idSummary = as.getSummaryShadow();
846 idSummary = as.getSummary();
849 HeapRegionNode hrnSummary = id2hrn.get( idSummary );
851 if( hrnSummary == null ) {
853 String strDesc = as.toStringForDOT()+"\\nsummary";
856 createNewHeapRegionNode( idSummary, // id or null to generate a new one
857 false, // single object?
859 false, // out-of-context?
860 as.getType(), // type
861 as, // allocation site
862 null, // inherent reach
863 null, // current reach
864 predsEmpty, // predicates
865 strDesc // description
872 // either retrieve or create the needed heap region node
873 protected HeapRegionNode getIthNode( AllocSite as,
879 idIth = as.getIthOldestShadow( i );
881 idIth = as.getIthOldest( i );
884 HeapRegionNode hrnIth = id2hrn.get( idIth );
886 if( hrnIth == null ) {
888 String strDesc = as.toStringForDOT()+"\\n"+i+" oldest";
890 hrnIth = createNewHeapRegionNode( idIth, // id or null to generate a new one
891 true, // single object?
893 false, // out-of-context?
894 as.getType(), // type
895 as, // allocation site
896 null, // inherent reach
897 null, // current reach
898 predsEmpty, // predicates
899 strDesc // description
907 protected void mergeIntoSummary( HeapRegionNode hrn,
908 HeapRegionNode hrnSummary ) {
909 assert hrnSummary.isNewSummary();
911 // assert that these nodes belong to THIS graph
912 assert belongsToThis( hrn );
913 assert belongsToThis( hrnSummary );
915 assert hrn != hrnSummary;
917 // transfer references _from_ hrn over to hrnSummary
918 Iterator<RefEdge> itrReferencee = hrn.iteratorToReferencees();
919 while( itrReferencee.hasNext() ) {
920 RefEdge edge = itrReferencee.next();
921 RefEdge edgeMerged = edge.copy();
922 edgeMerged.setSrc( hrnSummary );
924 HeapRegionNode hrnReferencee = edge.getDst();
925 RefEdge edgeSummary =
926 hrnSummary.getReferenceTo( hrnReferencee,
931 if( edgeSummary == null ) {
932 // the merge is trivial, nothing to be done
933 addRefEdge( hrnSummary, hrnReferencee, edgeMerged );
936 // otherwise an edge from the referencer to hrnSummary exists already
937 // and the edge referencer->hrn should be merged with it
939 Canonical.unionORpreds( edgeMerged.getBeta(),
940 edgeSummary.getBeta()
943 edgeSummary.setPreds(
944 Canonical.join( edgeMerged.getPreds(),
945 edgeSummary.getPreds()
951 // next transfer references _to_ hrn over to hrnSummary
952 Iterator<RefEdge> itrReferencer = hrn.iteratorToReferencers();
953 while( itrReferencer.hasNext() ) {
954 RefEdge edge = itrReferencer.next();
955 RefEdge edgeMerged = edge.copy();
956 edgeMerged.setDst( hrnSummary );
958 RefSrcNode onReferencer = edge.getSrc();
959 RefEdge edgeSummary =
960 onReferencer.getReferenceTo( hrnSummary,
965 if( edgeSummary == null ) {
966 // the merge is trivial, nothing to be done
967 addRefEdge( onReferencer, hrnSummary, edgeMerged );
970 // otherwise an edge from the referencer to alpha_S exists already
971 // and the edge referencer->alpha_K should be merged with it
973 Canonical.unionORpreds( edgeMerged.getBeta(),
974 edgeSummary.getBeta()
977 edgeSummary.setPreds(
978 Canonical.join( edgeMerged.getPreds(),
979 edgeSummary.getPreds()
985 // then merge hrn reachability into hrnSummary
987 Canonical.unionORpreds( hrnSummary.getAlpha(),
993 Canonical.join( hrnSummary.getPreds(),
998 // and afterward, this node is gone
999 wipeOut( hrn, true );
1003 protected void transferOnto( HeapRegionNode hrnA,
1004 HeapRegionNode hrnB ) {
1006 assert belongsToThis( hrnA );
1007 assert belongsToThis( hrnB );
1008 assert hrnA != hrnB;
1010 // clear references in and out of node b?
1011 assert hrnB.isWiped();
1013 // copy each: (edge in and out of A) to B
1014 Iterator<RefEdge> itrReferencee = hrnA.iteratorToReferencees();
1015 while( itrReferencee.hasNext() ) {
1016 RefEdge edge = itrReferencee.next();
1017 HeapRegionNode hrnReferencee = edge.getDst();
1018 RefEdge edgeNew = edge.copy();
1019 edgeNew.setSrc( hrnB );
1020 edgeNew.setDst( hrnReferencee );
1022 addRefEdge( hrnB, hrnReferencee, edgeNew );
1025 Iterator<RefEdge> itrReferencer = hrnA.iteratorToReferencers();
1026 while( itrReferencer.hasNext() ) {
1027 RefEdge edge = itrReferencer.next();
1028 RefSrcNode rsnReferencer = edge.getSrc();
1029 RefEdge edgeNew = edge.copy();
1030 edgeNew.setSrc( rsnReferencer );
1031 edgeNew.setDst( hrnB );
1033 addRefEdge( rsnReferencer, hrnB, edgeNew );
1036 // replace hrnB reachability and preds with hrnA's
1037 hrnB.setAlpha( hrnA.getAlpha() );
1038 hrnB.setPreds( hrnA.getPreds() );
1040 // after transfer, wipe out source
1041 wipeOut( hrnA, true );
1045 // the purpose of this method is to conceptually "wipe out"
1046 // a heap region from the graph--purposefully not called REMOVE
1047 // because the node is still hanging around in the graph, just
1048 // not mechanically connected or have any reach or predicate
1049 // information on it anymore--lots of ops can use this
1050 protected void wipeOut( HeapRegionNode hrn,
1051 boolean wipeVariableReferences ) {
1053 assert belongsToThis( hrn );
1055 clearRefEdgesFrom( hrn, null, null, true );
1057 if( wipeVariableReferences ) {
1058 clearRefEdgesTo( hrn, null, null, true );
1060 clearNonVarRefEdgesTo( hrn );
1063 hrn.setAlpha( rsetEmpty );
1064 hrn.setPreds( predsEmpty );
1068 protected void ageTuplesFrom( AllocSite as, RefEdge edge ) {
1070 Canonical.ageTuplesFrom( edge.getBeta(),
1076 protected void ageTuplesFrom( AllocSite as, HeapRegionNode hrn ) {
1078 Canonical.ageTuplesFrom( hrn.getAlpha(),
1086 protected void propagateTokensOverNodes( HeapRegionNode nPrime,
1088 HashSet<HeapRegionNode> nodesWithNewAlpha,
1089 HashSet<RefEdge> edgesWithNewBeta ) {
1091 HashSet<HeapRegionNode> todoNodes
1092 = new HashSet<HeapRegionNode>();
1093 todoNodes.add( nPrime );
1095 HashSet<RefEdge> todoEdges
1096 = new HashSet<RefEdge>();
1098 Hashtable<HeapRegionNode, ChangeSet> nodePlannedChanges
1099 = new Hashtable<HeapRegionNode, ChangeSet>();
1100 nodePlannedChanges.put( nPrime, c0 );
1102 Hashtable<RefEdge, ChangeSet> edgePlannedChanges
1103 = new Hashtable<RefEdge, ChangeSet>();
1105 // first propagate change sets everywhere they can go
1106 while( !todoNodes.isEmpty() ) {
1107 HeapRegionNode n = todoNodes.iterator().next();
1108 ChangeSet C = nodePlannedChanges.get( n );
1110 Iterator<RefEdge> referItr = n.iteratorToReferencers();
1111 while( referItr.hasNext() ) {
1112 RefEdge edge = referItr.next();
1113 todoEdges.add( edge );
1115 if( !edgePlannedChanges.containsKey( edge ) ) {
1116 edgePlannedChanges.put( edge,
1121 edgePlannedChanges.put( edge,
1122 Canonical.union( edgePlannedChanges.get( edge ),
1128 Iterator<RefEdge> refeeItr = n.iteratorToReferencees();
1129 while( refeeItr.hasNext() ) {
1130 RefEdge edgeF = refeeItr.next();
1131 HeapRegionNode m = edgeF.getDst();
1133 ChangeSet changesToPass = ChangeSet.factory();
1135 Iterator<ChangeTuple> itrCprime = C.iterator();
1136 while( itrCprime.hasNext() ) {
1137 ChangeTuple c = itrCprime.next();
1138 if( edgeF.getBeta().containsIgnorePreds( c.getStateToMatch() )
1141 changesToPass = Canonical.add( changesToPass, c );
1145 if( !changesToPass.isEmpty() ) {
1146 if( !nodePlannedChanges.containsKey( m ) ) {
1147 nodePlannedChanges.put( m, ChangeSet.factory() );
1150 ChangeSet currentChanges = nodePlannedChanges.get( m );
1152 if( !changesToPass.isSubset( currentChanges ) ) {
1154 nodePlannedChanges.put( m,
1155 Canonical.union( currentChanges,
1164 todoNodes.remove( n );
1167 // then apply all of the changes for each node at once
1168 Iterator itrMap = nodePlannedChanges.entrySet().iterator();
1169 while( itrMap.hasNext() ) {
1170 Map.Entry me = (Map.Entry) itrMap.next();
1171 HeapRegionNode n = (HeapRegionNode) me.getKey();
1172 ChangeSet C = (ChangeSet) me.getValue();
1174 // this propagation step is with respect to one change,
1175 // so we capture the full change from the old alpha:
1176 ReachSet localDelta = Canonical.applyChangeSet( n.getAlpha(),
1180 // but this propagation may be only one of many concurrent
1181 // possible changes, so keep a running union with the node's
1182 // partially updated new alpha set
1183 n.setAlphaNew( Canonical.unionORpreds( n.getAlphaNew(),
1188 nodesWithNewAlpha.add( n );
1191 propagateTokensOverEdges( todoEdges,
1198 protected void propagateTokensOverEdges( HashSet <RefEdge> todoEdges,
1199 Hashtable<RefEdge, ChangeSet> edgePlannedChanges,
1200 HashSet <RefEdge> edgesWithNewBeta ) {
1202 // first propagate all change tuples everywhere they can go
1203 while( !todoEdges.isEmpty() ) {
1204 RefEdge edgeE = todoEdges.iterator().next();
1205 todoEdges.remove( edgeE );
1207 if( !edgePlannedChanges.containsKey( edgeE ) ) {
1208 edgePlannedChanges.put( edgeE,
1213 ChangeSet C = edgePlannedChanges.get( edgeE );
1215 ChangeSet changesToPass = ChangeSet.factory();
1217 Iterator<ChangeTuple> itrC = C.iterator();
1218 while( itrC.hasNext() ) {
1219 ChangeTuple c = itrC.next();
1220 if( edgeE.getBeta().containsIgnorePreds( c.getStateToMatch() )
1223 changesToPass = Canonical.add( changesToPass, c );
1227 RefSrcNode rsn = edgeE.getSrc();
1229 if( !changesToPass.isEmpty() && rsn instanceof HeapRegionNode ) {
1230 HeapRegionNode n = (HeapRegionNode) rsn;
1232 Iterator<RefEdge> referItr = n.iteratorToReferencers();
1233 while( referItr.hasNext() ) {
1234 RefEdge edgeF = referItr.next();
1236 if( !edgePlannedChanges.containsKey( edgeF ) ) {
1237 edgePlannedChanges.put( edgeF,
1242 ChangeSet currentChanges = edgePlannedChanges.get( edgeF );
1244 if( !changesToPass.isSubset( currentChanges ) ) {
1245 todoEdges.add( edgeF );
1246 edgePlannedChanges.put( edgeF,
1247 Canonical.union( currentChanges,
1256 // then apply all of the changes for each edge at once
1257 Iterator itrMap = edgePlannedChanges.entrySet().iterator();
1258 while( itrMap.hasNext() ) {
1259 Map.Entry me = (Map.Entry) itrMap.next();
1260 RefEdge e = (RefEdge) me.getKey();
1261 ChangeSet C = (ChangeSet) me.getValue();
1263 // this propagation step is with respect to one change,
1264 // so we capture the full change from the old beta:
1265 ReachSet localDelta =
1266 Canonical.applyChangeSet( e.getBeta(),
1271 // but this propagation may be only one of many concurrent
1272 // possible changes, so keep a running union with the edge's
1273 // partially updated new beta set
1274 e.setBetaNew( Canonical.unionORpreds( e.getBetaNew(),
1279 edgesWithNewBeta.add( e );
1284 public void taintInSetVars( FlatSESEEnterNode sese ) {
1286 Iterator<TempDescriptor> isvItr = sese.getInVarSet().iterator();
1287 while( isvItr.hasNext() ) {
1288 TempDescriptor isv = isvItr.next();
1290 // use this where defined flatnode to support RCR/DFJ
1291 FlatNode whereDefined = null;
1293 whereDefined = sese;
1296 // in-set var taints should NOT propagate back into callers
1297 // so give it FALSE(EMPTY) predicates
1307 public void taintStallSite( FlatNode stallSite,
1308 TempDescriptor var ) {
1310 // use this where defined flatnode to support RCR/DFJ
1311 FlatNode whereDefined = null;
1313 whereDefined = stallSite;
1316 // stall site taint should propagate back into callers
1317 // so give it TRUE predicates
1326 protected void taintTemp( FlatSESEEnterNode sese,
1329 FlatNode whereDefined,
1333 VariableNode vn = getVariableNodeFromTemp( var );
1335 Iterator<RefEdge> reItr = vn.iteratorToReferencees();
1336 while( reItr.hasNext() ) {
1337 RefEdge re = reItr.next();
1339 Taint taint = Taint.factory( sese,
1342 re.getDst().getAllocSite(),
1347 re.setTaints( Canonical.add( re.getTaints(),
1354 public void removeInContextTaints( FlatSESEEnterNode sese ) {
1356 Iterator meItr = id2hrn.entrySet().iterator();
1357 while( meItr.hasNext() ) {
1358 Map.Entry me = (Map.Entry) meItr.next();
1359 Integer id = (Integer) me.getKey();
1360 HeapRegionNode hrn = (HeapRegionNode) me.getValue();
1362 Iterator<RefEdge> reItr = hrn.iteratorToReferencers();
1363 while( reItr.hasNext() ) {
1364 RefEdge re = reItr.next();
1366 re.setTaints( Canonical.removeInContextTaints( re.getTaints(),
1374 public void removeAllStallSiteTaints() {
1376 Iterator meItr = id2hrn.entrySet().iterator();
1377 while( meItr.hasNext() ) {
1378 Map.Entry me = (Map.Entry) meItr.next();
1379 Integer id = (Integer) me.getKey();
1380 HeapRegionNode hrn = (HeapRegionNode) me.getValue();
1382 Iterator<RefEdge> reItr = hrn.iteratorToReferencers();
1383 while( reItr.hasNext() ) {
1384 RefEdge re = reItr.next();
1386 re.setTaints( Canonical.removeStallSiteTaints( re.getTaints()
1394 // used in makeCalleeView below to decide if there is
1395 // already an appropriate out-of-context edge in a callee
1396 // view graph for merging, or null if a new one will be added
1398 getOutOfContextReferenceTo( HeapRegionNode hrn,
1399 TypeDescriptor srcType,
1400 TypeDescriptor refType,
1402 assert belongsToThis( hrn );
1404 HeapRegionNode hrnInContext = id2hrn.get( hrn.getID() );
1405 if( hrnInContext == null ) {
1409 Iterator<RefEdge> refItr = hrnInContext.iteratorToReferencers();
1410 while( refItr.hasNext() ) {
1411 RefEdge re = refItr.next();
1413 assert belongsToThis( re.getSrc() );
1414 assert belongsToThis( re.getDst() );
1416 if( !(re.getSrc() instanceof HeapRegionNode) ) {
1420 HeapRegionNode hrnSrc = (HeapRegionNode) re.getSrc();
1421 if( !hrnSrc.isOutOfContext() ) {
1425 if( srcType == null ) {
1426 if( hrnSrc.getType() != null ) {
1430 if( !srcType.equals( hrnSrc.getType() ) ) {
1435 if( !re.typeEquals( refType ) ) {
1439 if( !re.fieldEquals( refField ) ) {
1443 // tada! We found it!
1450 // used below to convert a ReachSet to its callee-context
1451 // equivalent with respect to allocation sites in this graph
1452 protected ReachSet toCalleeContext( ReachSet rs,
1453 ExistPredSet predsNodeOrEdge,
1454 Set<HrnIdOoc> oocHrnIdOoc2callee
1456 ReachSet out = ReachSet.factory();
1458 Iterator<ReachState> itr = rs.iterator();
1459 while( itr.hasNext() ) {
1460 ReachState stateCaller = itr.next();
1462 ReachState stateCallee = stateCaller;
1464 Iterator<AllocSite> asItr = allocSites.iterator();
1465 while( asItr.hasNext() ) {
1466 AllocSite as = asItr.next();
1468 ReachState stateNew = ReachState.factory();
1469 Iterator<ReachTuple> rtItr = stateCallee.iterator();
1470 while( rtItr.hasNext() ) {
1471 ReachTuple rt = rtItr.next();
1473 // only translate this tuple if it is
1474 // in the out-callee-context bag
1475 HrnIdOoc hio = new HrnIdOoc( rt.getHrnID(),
1478 if( !oocHrnIdOoc2callee.contains( hio ) ) {
1479 stateNew = Canonical.addUpArity( stateNew, rt );
1483 int age = as.getAgeCategory( rt.getHrnID() );
1485 // this is the current mapping, where 0, 1, 2S were allocated
1486 // in the current context, 0?, 1? and 2S? were allocated in a
1487 // previous context, and we're translating to a future context
1499 if( age == AllocSite.AGE_notInThisSite ) {
1500 // things not from the site just go back in
1501 stateNew = Canonical.addUpArity( stateNew, rt );
1503 } else if( age == AllocSite.AGE_summary ||
1507 stateNew = Canonical.addUpArity( stateNew,
1508 ReachTuple.factory( as.getSummary(),
1511 true // out-of-context
1516 // otherwise everything else just goes to an out-of-context
1517 // version, everything else the same
1518 Integer I = as.getAge( rt.getHrnID() );
1521 assert !rt.isMultiObject();
1523 stateNew = Canonical.addUpArity( stateNew,
1524 ReachTuple.factory( rt.getHrnID(),
1525 rt.isMultiObject(), // multi
1527 true // out-of-context
1533 stateCallee = stateNew;
1536 // make a predicate of the caller graph element
1537 // and the caller state we just converted
1538 ExistPredSet predsWithState = ExistPredSet.factory();
1540 Iterator<ExistPred> predItr = predsNodeOrEdge.iterator();
1541 while( predItr.hasNext() ) {
1542 ExistPred predNodeOrEdge = predItr.next();
1545 Canonical.add( predsWithState,
1546 ExistPred.factory( predNodeOrEdge.n_hrnID,
1547 predNodeOrEdge.e_tdSrc,
1548 predNodeOrEdge.e_hrnSrcID,
1549 predNodeOrEdge.e_hrnDstID,
1550 predNodeOrEdge.e_type,
1551 predNodeOrEdge.e_field,
1554 predNodeOrEdge.e_srcOutCalleeContext,
1555 predNodeOrEdge.e_srcOutCallerContext
1560 stateCallee = Canonical.changePredsTo( stateCallee,
1563 out = Canonical.add( out,
1567 assert out.isCanonical();
1571 // used below to convert a ReachSet to its caller-context
1572 // equivalent with respect to allocation sites in this graph
1574 toCallerContext( ReachSet rs,
1575 Hashtable<ReachState, ExistPredSet> calleeStatesSatisfied
1577 ReachSet out = ReachSet.factory();
1579 // when the mapping is null it means there were no
1580 // predicates satisfied
1581 if( calleeStatesSatisfied == null ) {
1585 Iterator<ReachState> itr = rs.iterator();
1586 while( itr.hasNext() ) {
1587 ReachState stateCallee = itr.next();
1589 if( calleeStatesSatisfied.containsKey( stateCallee ) ) {
1591 // starting from one callee state...
1592 ReachSet rsCaller = ReachSet.factory( stateCallee );
1594 // possibly branch it into many states, which any
1595 // allocation site might do, so lots of derived states
1596 Iterator<AllocSite> asItr = allocSites.iterator();
1597 while( asItr.hasNext() ) {
1598 AllocSite as = asItr.next();
1599 rsCaller = Canonical.toCallerContext( rsCaller, as );
1602 // then before adding each derived, now caller-context
1603 // states to the output, attach the appropriate pred
1604 // based on the source callee state
1605 Iterator<ReachState> stateItr = rsCaller.iterator();
1606 while( stateItr.hasNext() ) {
1607 ReachState stateCaller = stateItr.next();
1608 stateCaller = Canonical.attach( stateCaller,
1609 calleeStatesSatisfied.get( stateCallee )
1611 out = Canonical.add( out,
1618 assert out.isCanonical();
1623 // used below to convert a ReachSet to an equivalent
1624 // version with shadow IDs merged into unshadowed IDs
1625 protected ReachSet unshadow( ReachSet rs ) {
1627 Iterator<AllocSite> asItr = allocSites.iterator();
1628 while( asItr.hasNext() ) {
1629 AllocSite as = asItr.next();
1630 out = Canonical.unshadow( out, as );
1632 assert out.isCanonical();
1637 // convert a caller taint set into a callee taint set
1639 toCalleeContext( TaintSet ts,
1640 ExistPredSet predsEdge ) {
1642 TaintSet out = TaintSet.factory();
1644 // the idea is easy, the taint identifier itself doesn't
1645 // change at all, but the predicates should be tautology:
1646 // start with the preds passed in from the caller edge
1647 // that host the taints, and alter them to have the taint
1648 // added, just becoming more specific than edge predicate alone
1650 Iterator<Taint> itr = ts.iterator();
1651 while( itr.hasNext() ) {
1652 Taint tCaller = itr.next();
1654 ExistPredSet predsWithTaint = ExistPredSet.factory();
1656 Iterator<ExistPred> predItr = predsEdge.iterator();
1657 while( predItr.hasNext() ) {
1658 ExistPred predEdge = predItr.next();
1661 Canonical.add( predsWithTaint,
1662 ExistPred.factory( predEdge.e_tdSrc,
1663 predEdge.e_hrnSrcID,
1664 predEdge.e_hrnDstID,
1669 predEdge.e_srcOutCalleeContext,
1670 predEdge.e_srcOutCallerContext
1675 Taint tCallee = Canonical.changePredsTo( tCaller,
1678 out = Canonical.add( out,
1683 assert out.isCanonical();
1688 // used below to convert a TaintSet to its caller-context
1689 // equivalent, just eliminate Taints with bad preds
1691 toCallerContext( TaintSet ts,
1692 Hashtable<Taint, ExistPredSet> calleeTaintsSatisfied
1695 TaintSet out = TaintSet.factory();
1697 // when the mapping is null it means there were no
1698 // predicates satisfied
1699 if( calleeTaintsSatisfied == null ) {
1703 Iterator<Taint> itr = ts.iterator();
1704 while( itr.hasNext() ) {
1705 Taint tCallee = itr.next();
1707 if( calleeTaintsSatisfied.containsKey( tCallee ) ) {
1710 Canonical.attach( Taint.factory( tCallee.sese,
1715 ExistPredSet.factory() ),
1716 calleeTaintsSatisfied.get( tCallee )
1718 out = Canonical.add( out,
1724 assert out.isCanonical();
1731 // use this method to make a new reach graph that is
1732 // what heap the FlatMethod callee from the FlatCall
1733 // would start with reaching from its arguments in
1736 makeCalleeView( FlatCall fc,
1737 FlatMethod fmCallee,
1738 Set<Integer> callerNodeIDsCopiedToCallee,
1739 boolean writeDebugDOTs
1743 // first traverse this context to find nodes and edges
1744 // that will be callee-reachable
1745 Set<HeapRegionNode> reachableCallerNodes =
1746 new HashSet<HeapRegionNode>();
1748 // caller edges between callee-reachable nodes
1749 Set<RefEdge> reachableCallerEdges =
1750 new HashSet<RefEdge>();
1752 // caller edges from arg vars, and the matching param index
1753 // because these become a special edge in callee
1754 Hashtable<RefEdge, Integer> reachableCallerArgEdges2paramIndex =
1755 new Hashtable<RefEdge, Integer>();
1757 // caller edges from local vars or callee-unreachable nodes
1758 // (out-of-context sources) to callee-reachable nodes
1759 Set<RefEdge> oocCallerEdges =
1760 new HashSet<RefEdge>();
1763 for( int i = 0; i < fmCallee.numParameters(); ++i ) {
1765 TempDescriptor tdArg = fc.getArgMatchingParamIndex( fmCallee, i );
1766 VariableNode vnArgCaller = this.getVariableNodeFromTemp( tdArg );
1768 Set<RefSrcNode> toVisitInCaller = new HashSet<RefSrcNode>();
1769 Set<RefSrcNode> visitedInCaller = new HashSet<RefSrcNode>();
1771 toVisitInCaller.add( vnArgCaller );
1773 while( !toVisitInCaller.isEmpty() ) {
1774 RefSrcNode rsnCaller = toVisitInCaller.iterator().next();
1775 toVisitInCaller.remove( rsnCaller );
1776 visitedInCaller.add( rsnCaller );
1778 Iterator<RefEdge> itrRefEdges = rsnCaller.iteratorToReferencees();
1779 while( itrRefEdges.hasNext() ) {
1780 RefEdge reCaller = itrRefEdges.next();
1781 HeapRegionNode hrnCaller = reCaller.getDst();
1783 callerNodeIDsCopiedToCallee.add( hrnCaller.getID() );
1784 reachableCallerNodes.add( hrnCaller );
1786 if( reCaller.getSrc() instanceof HeapRegionNode ) {
1787 reachableCallerEdges.add( reCaller );
1789 if( rsnCaller.equals( vnArgCaller ) ) {
1790 reachableCallerArgEdges2paramIndex.put( reCaller, i );
1792 oocCallerEdges.add( reCaller );
1796 if( !visitedInCaller.contains( hrnCaller ) ) {
1797 toVisitInCaller.add( hrnCaller );
1800 } // end edge iteration
1801 } // end visiting heap nodes in caller
1802 } // end iterating over parameters as starting points
1805 // now collect out-of-callee-context IDs and
1806 // map them to whether the ID is out of the caller
1808 Set<HrnIdOoc> oocHrnIdOoc2callee = new HashSet<HrnIdOoc>();
1810 Iterator<Integer> itrInContext =
1811 callerNodeIDsCopiedToCallee.iterator();
1812 while( itrInContext.hasNext() ) {
1813 Integer hrnID = itrInContext.next();
1814 HeapRegionNode hrnCallerAndInContext = id2hrn.get( hrnID );
1816 Iterator<RefEdge> itrMightCross =
1817 hrnCallerAndInContext.iteratorToReferencers();
1818 while( itrMightCross.hasNext() ) {
1819 RefEdge edgeMightCross = itrMightCross.next();
1821 RefSrcNode rsnCallerAndOutContext =
1822 edgeMightCross.getSrc();
1824 if( rsnCallerAndOutContext instanceof VariableNode ) {
1825 // variables do not have out-of-context reach states,
1827 oocCallerEdges.add( edgeMightCross );
1831 HeapRegionNode hrnCallerAndOutContext =
1832 (HeapRegionNode) rsnCallerAndOutContext;
1834 // is this source node out-of-context?
1835 if( callerNodeIDsCopiedToCallee.contains( hrnCallerAndOutContext.getID() ) ) {
1836 // no, skip this edge
1841 oocCallerEdges.add( edgeMightCross );
1843 // add all reach tuples on the node to list
1844 // of things that are out-of-context: insight
1845 // if this node is reachable from someting that WAS
1846 // in-context, then this node should already be in-context
1847 Iterator<ReachState> stateItr = hrnCallerAndOutContext.getAlpha().iterator();
1848 while( stateItr.hasNext() ) {
1849 ReachState state = stateItr.next();
1851 Iterator<ReachTuple> rtItr = state.iterator();
1852 while( rtItr.hasNext() ) {
1853 ReachTuple rt = rtItr.next();
1855 oocHrnIdOoc2callee.add( new HrnIdOoc( rt.getHrnID(),
1864 // the callee view is a new graph: DON'T MODIFY *THIS* graph
1865 ReachGraph rg = new ReachGraph();
1867 // add nodes to callee graph
1868 Iterator<HeapRegionNode> hrnItr = reachableCallerNodes.iterator();
1869 while( hrnItr.hasNext() ) {
1870 HeapRegionNode hrnCaller = hrnItr.next();
1872 assert callerNodeIDsCopiedToCallee.contains( hrnCaller.getID() );
1873 assert !rg.id2hrn.containsKey( hrnCaller.getID() );
1875 ExistPred pred = ExistPred.factory( hrnCaller.getID(), null );
1876 ExistPredSet preds = ExistPredSet.factory( pred );
1878 rg.createNewHeapRegionNode( hrnCaller.getID(),
1879 hrnCaller.isSingleObject(),
1880 hrnCaller.isNewSummary(),
1881 false, // out-of-context?
1882 hrnCaller.getType(),
1883 hrnCaller.getAllocSite(),
1884 toCalleeContext( hrnCaller.getInherent(),
1888 toCalleeContext( hrnCaller.getAlpha(),
1893 hrnCaller.getDescription()
1897 // add param edges to callee graph
1899 reachableCallerArgEdges2paramIndex.entrySet().iterator();
1900 while( argEdges.hasNext() ) {
1901 Map.Entry me = (Map.Entry) argEdges.next();
1902 RefEdge reArg = (RefEdge) me.getKey();
1903 Integer index = (Integer) me.getValue();
1905 VariableNode vnCaller = (VariableNode) reArg.getSrc();
1906 TempDescriptor argCaller = vnCaller.getTempDescriptor();
1908 TempDescriptor paramCallee = fmCallee.getParameter( index );
1909 VariableNode vnCallee = rg.getVariableNodeFromTemp( paramCallee );
1911 HeapRegionNode hrnDstCaller = reArg.getDst();
1912 HeapRegionNode hrnDstCallee = rg.id2hrn.get( hrnDstCaller.getID() );
1913 assert hrnDstCallee != null;
1916 ExistPred.factory( argCaller,
1918 hrnDstCallee.getID(),
1923 true, // out-of-callee-context
1924 false // out-of-caller-context
1927 ExistPredSet preds =
1928 ExistPredSet.factory( pred );
1931 new RefEdge( vnCallee,
1935 toCalleeContext( reArg.getBeta(),
1940 toCalleeContext( reArg.getTaints(),
1944 rg.addRefEdge( vnCallee,
1950 // add in-context edges to callee graph
1951 Iterator<RefEdge> reItr = reachableCallerEdges.iterator();
1952 while( reItr.hasNext() ) {
1953 RefEdge reCaller = reItr.next();
1954 RefSrcNode rsnCaller = reCaller.getSrc();
1955 assert rsnCaller instanceof HeapRegionNode;
1956 HeapRegionNode hrnSrcCaller = (HeapRegionNode) rsnCaller;
1957 HeapRegionNode hrnDstCaller = reCaller.getDst();
1959 HeapRegionNode hrnSrcCallee = rg.id2hrn.get( hrnSrcCaller.getID() );
1960 HeapRegionNode hrnDstCallee = rg.id2hrn.get( hrnDstCaller.getID() );
1961 assert hrnSrcCallee != null;
1962 assert hrnDstCallee != null;
1965 ExistPred.factory( null,
1966 hrnSrcCallee.getID(),
1967 hrnDstCallee.getID(),
1969 reCaller.getField(),
1972 false, // out-of-callee-context
1973 false // out-of-caller-context
1976 ExistPredSet preds =
1977 ExistPredSet.factory( pred );
1980 new RefEdge( hrnSrcCallee,
1983 reCaller.getField(),
1984 toCalleeContext( reCaller.getBeta(),
1989 toCalleeContext( reCaller.getTaints(),
1993 rg.addRefEdge( hrnSrcCallee,
1999 // add out-of-context edges to callee graph
2000 reItr = oocCallerEdges.iterator();
2001 while( reItr.hasNext() ) {
2002 RefEdge reCaller = reItr.next();
2003 RefSrcNode rsnCaller = reCaller.getSrc();
2004 HeapRegionNode hrnDstCaller = reCaller.getDst();
2005 HeapRegionNode hrnDstCallee = rg.id2hrn.get( hrnDstCaller.getID() );
2006 assert hrnDstCallee != null;
2008 TypeDescriptor oocNodeType;
2010 TempDescriptor oocPredSrcTemp = null;
2011 Integer oocPredSrcID = null;
2012 boolean outOfCalleeContext;
2013 boolean outOfCallerContext;
2015 if( rsnCaller instanceof VariableNode ) {
2016 VariableNode vnCaller = (VariableNode) rsnCaller;
2018 oocReach = rsetEmpty;
2019 oocPredSrcTemp = vnCaller.getTempDescriptor();
2020 outOfCalleeContext = true;
2021 outOfCallerContext = false;
2024 HeapRegionNode hrnSrcCaller = (HeapRegionNode) rsnCaller;
2025 assert !callerNodeIDsCopiedToCallee.contains( hrnSrcCaller.getID() );
2026 oocNodeType = hrnSrcCaller.getType();
2027 oocReach = hrnSrcCaller.getAlpha();
2028 oocPredSrcID = hrnSrcCaller.getID();
2029 if( hrnSrcCaller.isOutOfContext() ) {
2030 outOfCalleeContext = false;
2031 outOfCallerContext = true;
2033 outOfCalleeContext = true;
2034 outOfCallerContext = false;
2039 ExistPred.factory( oocPredSrcTemp,
2041 hrnDstCallee.getID(),
2043 reCaller.getField(),
2050 ExistPredSet preds =
2051 ExistPredSet.factory( pred );
2053 RefEdge oocEdgeExisting =
2054 rg.getOutOfContextReferenceTo( hrnDstCallee,
2060 if( oocEdgeExisting == null ) {
2061 // for consistency, map one out-of-context "identifier"
2062 // to one heap region node id, otherwise no convergence
2063 String oocid = "oocid"+
2065 hrnDstCallee.getIDString()+
2068 reCaller.getField();
2070 Integer oocHrnID = oocid2hrnid.get( oocid );
2072 HeapRegionNode hrnCalleeAndOutContext;
2074 if( oocHrnID == null ) {
2076 hrnCalleeAndOutContext =
2077 rg.createNewHeapRegionNode( null, // ID
2078 false, // single object?
2079 false, // new summary?
2080 true, // out-of-context?
2082 null, // alloc site, shouldn't be used
2083 toCalleeContext( oocReach,
2087 toCalleeContext( oocReach,
2095 oocid2hrnid.put( oocid, hrnCalleeAndOutContext.getID() );
2099 // the mapping already exists, so see if node is there
2100 hrnCalleeAndOutContext = rg.id2hrn.get( oocHrnID );
2102 if( hrnCalleeAndOutContext == null ) {
2104 hrnCalleeAndOutContext =
2105 rg.createNewHeapRegionNode( oocHrnID, // ID
2106 false, // single object?
2107 false, // new summary?
2108 true, // out-of-context?
2110 null, // alloc site, shouldn't be used
2111 toCalleeContext( oocReach,
2115 toCalleeContext( oocReach,
2124 // otherwise it is there, so merge reachability
2125 hrnCalleeAndOutContext.setAlpha( Canonical.unionORpreds( hrnCalleeAndOutContext.getAlpha(),
2126 toCalleeContext( oocReach,
2135 assert hrnCalleeAndOutContext.reachHasOnlyOOC();
2137 rg.addRefEdge( hrnCalleeAndOutContext,
2139 new RefEdge( hrnCalleeAndOutContext,
2142 reCaller.getField(),
2143 toCalleeContext( reCaller.getBeta(),
2148 toCalleeContext( reCaller.getTaints(),
2154 // the out-of-context edge already exists
2155 oocEdgeExisting.setBeta( Canonical.unionORpreds( oocEdgeExisting.getBeta(),
2156 toCalleeContext( reCaller.getBeta(),
2163 oocEdgeExisting.setPreds( Canonical.join( oocEdgeExisting.getPreds(),
2168 oocEdgeExisting.setTaints( Canonical.unionORpreds( oocEdgeExisting.getTaints(),
2169 toCalleeContext( reCaller.getTaints(),
2175 HeapRegionNode hrnCalleeAndOutContext =
2176 (HeapRegionNode) oocEdgeExisting.getSrc();
2177 hrnCalleeAndOutContext.setAlpha( Canonical.unionORpreds( hrnCalleeAndOutContext.getAlpha(),
2178 toCalleeContext( oocReach,
2185 assert hrnCalleeAndOutContext.reachHasOnlyOOC();
2190 if( writeDebugDOTs ) {
2191 debugGraphPrefix = String.format( "call%03d", debugCallSiteVisitCounter );
2192 rg.writeGraph( debugGraphPrefix+"calleeview",
2193 resolveMethodDebugDOTwriteLabels,
2194 resolveMethodDebugDOTselectTemps,
2195 resolveMethodDebugDOTpruneGarbage,
2196 resolveMethodDebugDOThideReach,
2197 resolveMethodDebugDOThideSubsetReach,
2198 resolveMethodDebugDOThidePreds,
2199 resolveMethodDebugDOThideEdgeTaints );
2205 private static Hashtable<String, Integer> oocid2hrnid =
2206 new Hashtable<String, Integer>();
2209 // useful since many graphs writes in the method call debug code
2210 private static boolean resolveMethodDebugDOTwriteLabels = true;
2211 private static boolean resolveMethodDebugDOTselectTemps = true;
2212 private static boolean resolveMethodDebugDOTpruneGarbage = true;
2213 private static boolean resolveMethodDebugDOThideReach = false;
2214 private static boolean resolveMethodDebugDOThideSubsetReach = false;
2215 private static boolean resolveMethodDebugDOThidePreds = true;
2216 private static boolean resolveMethodDebugDOThideEdgeTaints = true;
2218 static String debugGraphPrefix;
2219 static int debugCallSiteVisitCounter;
2220 static int debugCallSiteVisitStartCapture;
2221 static int debugCallSiteNumVisitsToCapture;
2222 static boolean debugCallSiteStopAfter;
2226 resolveMethodCall( FlatCall fc,
2227 FlatMethod fmCallee,
2228 ReachGraph rgCallee,
2229 Set<Integer> callerNodeIDsCopiedToCallee,
2230 boolean writeDebugDOTs
2233 if( writeDebugDOTs ) {
2235 System.out.println( " Writing out visit "+
2236 debugCallSiteVisitCounter+
2237 " to debug call site" );
2239 debugGraphPrefix = String.format( "call%03d",
2240 debugCallSiteVisitCounter );
2242 rgCallee.writeGraph( debugGraphPrefix+"callee",
2243 resolveMethodDebugDOTwriteLabels,
2244 resolveMethodDebugDOTselectTemps,
2245 resolveMethodDebugDOTpruneGarbage,
2246 resolveMethodDebugDOThideReach,
2247 resolveMethodDebugDOThideSubsetReach,
2248 resolveMethodDebugDOThidePreds,
2249 resolveMethodDebugDOThideEdgeTaints );
2251 writeGraph( debugGraphPrefix+"caller00In",
2252 resolveMethodDebugDOTwriteLabels,
2253 resolveMethodDebugDOTselectTemps,
2254 resolveMethodDebugDOTpruneGarbage,
2255 resolveMethodDebugDOThideReach,
2256 resolveMethodDebugDOThideSubsetReach,
2257 resolveMethodDebugDOThidePreds,
2258 resolveMethodDebugDOThideEdgeTaints,
2259 callerNodeIDsCopiedToCallee );
2264 // method call transfer function steps:
2265 // 1. Use current callee-reachable heap (CRH) to test callee
2266 // predicates and mark what will be coming in.
2267 // 2. Wipe CRH out of caller.
2268 // 3. Transplant marked callee parts in:
2269 // a) bring in nodes
2270 // b) bring in callee -> callee edges
2271 // c) resolve out-of-context -> callee edges
2272 // d) assign return value
2273 // 4. Collapse shadow nodes down
2274 // 5. Global sweep it.
2277 // 1. mark what callee elements have satisfied predicates
2278 Hashtable<HeapRegionNode, ExistPredSet> calleeNodesSatisfied =
2279 new Hashtable<HeapRegionNode, ExistPredSet>();
2281 Hashtable<RefEdge, ExistPredSet> calleeEdgesSatisfied =
2282 new Hashtable<RefEdge, ExistPredSet>();
2284 Hashtable< HeapRegionNode, Hashtable<ReachState, ExistPredSet> >
2285 calleeNode2calleeStatesSatisfied =
2286 new Hashtable< HeapRegionNode, Hashtable<ReachState, ExistPredSet> >();
2288 Hashtable< RefEdge, Hashtable<ReachState, ExistPredSet> >
2289 calleeEdge2calleeStatesSatisfied =
2290 new Hashtable< RefEdge, Hashtable<ReachState, ExistPredSet> >();
2292 Hashtable< RefEdge, Hashtable<Taint, ExistPredSet> >
2293 calleeEdge2calleeTaintsSatisfied =
2294 new Hashtable< RefEdge, Hashtable<Taint, ExistPredSet> >();
2296 Hashtable< RefEdge, Set<RefSrcNode> > calleeEdges2oocCallerSrcMatches =
2297 new Hashtable< RefEdge, Set<RefSrcNode> >();
2300 Iterator meItr = rgCallee.id2hrn.entrySet().iterator();
2301 while( meItr.hasNext() ) {
2302 Map.Entry me = (Map.Entry) meItr.next();
2303 Integer id = (Integer) me.getKey();
2304 HeapRegionNode hrnCallee = (HeapRegionNode) me.getValue();
2306 // if a callee element's predicates are satisfied then a set
2307 // of CALLER predicates is returned: they are the predicates
2308 // that the callee element moved into the caller context
2309 // should have, and it is inefficient to find this again later
2310 ExistPredSet predsIfSatis =
2311 hrnCallee.getPreds().isSatisfiedBy( this,
2312 callerNodeIDsCopiedToCallee
2315 if( predsIfSatis != null ) {
2316 calleeNodesSatisfied.put( hrnCallee, predsIfSatis );
2318 // otherwise don't bother looking at edges to this node
2322 // since the node is coming over, find out which reach
2323 // states on it should come over, too
2324 assert calleeNode2calleeStatesSatisfied.get( hrnCallee ) == null;
2326 Iterator<ReachState> stateItr = hrnCallee.getAlpha().iterator();
2327 while( stateItr.hasNext() ) {
2328 ReachState stateCallee = stateItr.next();
2331 stateCallee.getPreds().isSatisfiedBy( this,
2332 callerNodeIDsCopiedToCallee
2334 if( predsIfSatis != null ) {
2336 Hashtable<ReachState, ExistPredSet> calleeStatesSatisfied =
2337 calleeNode2calleeStatesSatisfied.get( hrnCallee );
2339 if( calleeStatesSatisfied == null ) {
2340 calleeStatesSatisfied =
2341 new Hashtable<ReachState, ExistPredSet>();
2343 calleeNode2calleeStatesSatisfied.put( hrnCallee, calleeStatesSatisfied );
2346 calleeStatesSatisfied.put( stateCallee, predsIfSatis );
2350 // then look at edges to the node
2351 Iterator<RefEdge> reItr = hrnCallee.iteratorToReferencers();
2352 while( reItr.hasNext() ) {
2353 RefEdge reCallee = reItr.next();
2354 RefSrcNode rsnCallee = reCallee.getSrc();
2356 // (caller local variables to in-context heap regions)
2357 // have an (out-of-context heap region -> in-context heap region)
2358 // abstraction in the callEE, so its true we never need to
2359 // look at a (var node -> heap region) edge in callee to bring
2360 // those over for the call site transfer, except for the special
2361 // case of *RETURN var* -> heap region edges.
2362 // What about (param var->heap region)
2363 // edges in callee? They are dealt with below this loop.
2365 if( rsnCallee instanceof VariableNode ) {
2367 // looking for the return-value variable only
2368 VariableNode vnCallee = (VariableNode) rsnCallee;
2369 if( vnCallee.getTempDescriptor() != tdReturn ) {
2373 TempDescriptor returnTemp = fc.getReturnTemp();
2374 if( returnTemp == null ||
2375 !DisjointAnalysis.shouldAnalysisTrack( returnTemp.getType() )
2380 // note that the assignment of the return value is to a
2381 // variable in the caller which is out-of-context with
2382 // respect to the callee
2383 VariableNode vnLhsCaller = getVariableNodeFromTemp( returnTemp );
2384 Set<RefSrcNode> rsnCallers = new HashSet<RefSrcNode>();
2385 rsnCallers.add( vnLhsCaller );
2386 calleeEdges2oocCallerSrcMatches.put( reCallee, rsnCallers );
2390 // for HeapRegionNode callee sources...
2392 // first see if the source is out-of-context, and only
2393 // proceed with this edge if we find some caller-context
2395 HeapRegionNode hrnSrcCallee = (HeapRegionNode) rsnCallee;
2396 boolean matchedOutOfContext = false;
2398 if( !hrnSrcCallee.isOutOfContext() ) {
2401 hrnSrcCallee.getPreds().isSatisfiedBy( this,
2402 callerNodeIDsCopiedToCallee
2404 if( predsIfSatis != null ) {
2405 calleeNodesSatisfied.put( hrnSrcCallee, predsIfSatis );
2407 // otherwise forget this edge
2412 // hrnSrcCallee is out-of-context
2414 assert !calleeEdges2oocCallerSrcMatches.containsKey( reCallee );
2416 Set<RefSrcNode> rsnCallers = new HashSet<RefSrcNode>();
2418 // is the target node in the caller?
2419 HeapRegionNode hrnDstCaller = this.id2hrn.get( hrnCallee.getID() );
2420 if( hrnDstCaller == null ) {
2424 Iterator<RefEdge> reDstItr = hrnDstCaller.iteratorToReferencers();
2425 while( reDstItr.hasNext() ) {
2426 // the edge and field (either possibly null) must match
2427 RefEdge reCaller = reDstItr.next();
2429 if( !reCaller.typeEquals ( reCallee.getType() ) ||
2430 !reCaller.fieldEquals( reCallee.getField() )
2435 RefSrcNode rsnCaller = reCaller.getSrc();
2436 if( rsnCaller instanceof VariableNode ) {
2438 // a variable node matches an OOC region with null type
2439 if( hrnSrcCallee.getType() != null ) {
2444 // otherwise types should match
2445 HeapRegionNode hrnCallerSrc = (HeapRegionNode) rsnCaller;
2446 if( hrnSrcCallee.getType() == null ) {
2447 if( hrnCallerSrc.getType() != null ) {
2451 if( !hrnSrcCallee.getType().equals( hrnCallerSrc.getType() ) ) {
2457 rsnCallers.add( rsnCaller );
2458 matchedOutOfContext = true;
2461 if( !rsnCallers.isEmpty() ) {
2462 calleeEdges2oocCallerSrcMatches.put( reCallee, rsnCallers );
2466 if( hrnSrcCallee.isOutOfContext() &&
2467 !matchedOutOfContext ) {
2474 reCallee.getPreds().isSatisfiedBy( this,
2475 callerNodeIDsCopiedToCallee
2478 if( predsIfSatis != null ) {
2479 calleeEdgesSatisfied.put( reCallee, predsIfSatis );
2481 // since the edge is coming over, find out which reach
2482 // states on it should come over, too
2483 assert calleeEdge2calleeStatesSatisfied.get( reCallee ) == null;
2485 stateItr = reCallee.getBeta().iterator();
2486 while( stateItr.hasNext() ) {
2487 ReachState stateCallee = stateItr.next();
2490 stateCallee.getPreds().isSatisfiedBy( this,
2491 callerNodeIDsCopiedToCallee
2493 if( predsIfSatis != null ) {
2495 Hashtable<ReachState, ExistPredSet> calleeStatesSatisfied =
2496 calleeEdge2calleeStatesSatisfied.get( reCallee );
2498 if( calleeStatesSatisfied == null ) {
2499 calleeStatesSatisfied =
2500 new Hashtable<ReachState, ExistPredSet>();
2502 calleeEdge2calleeStatesSatisfied.put( reCallee, calleeStatesSatisfied );
2505 calleeStatesSatisfied.put( stateCallee, predsIfSatis );
2509 // since the edge is coming over, find out which taints
2510 // on it should come over, too
2511 assert calleeEdge2calleeTaintsSatisfied.get( reCallee ) == null;
2513 Iterator<Taint> tItr = reCallee.getTaints().iterator();
2514 while( tItr.hasNext() ) {
2515 Taint tCallee = tItr.next();
2518 tCallee.getPreds().isSatisfiedBy( this,
2519 callerNodeIDsCopiedToCallee
2521 if( predsIfSatis != null ) {
2523 Hashtable<Taint, ExistPredSet> calleeTaintsSatisfied =
2524 calleeEdge2calleeTaintsSatisfied.get( reCallee );
2526 if( calleeTaintsSatisfied == null ) {
2527 calleeTaintsSatisfied =
2528 new Hashtable<Taint, ExistPredSet>();
2530 calleeEdge2calleeTaintsSatisfied.put( reCallee, calleeTaintsSatisfied );
2533 calleeTaintsSatisfied.put( tCallee, predsIfSatis );
2540 if( writeDebugDOTs ) {
2541 writeGraph( debugGraphPrefix+"caller20BeforeWipe",
2542 resolveMethodDebugDOTwriteLabels,
2543 resolveMethodDebugDOTselectTemps,
2544 resolveMethodDebugDOTpruneGarbage,
2545 resolveMethodDebugDOThideReach,
2546 resolveMethodDebugDOThideSubsetReach,
2547 resolveMethodDebugDOThidePreds,
2548 resolveMethodDebugDOThideEdgeTaints );
2552 // 2. predicates tested, ok to wipe out caller part
2553 Iterator<Integer> hrnItr = callerNodeIDsCopiedToCallee.iterator();
2554 while( hrnItr.hasNext() ) {
2555 Integer hrnID = hrnItr.next();
2556 HeapRegionNode hrnCaller = id2hrn.get( hrnID );
2557 assert hrnCaller != null;
2559 // when clearing off nodes, also eliminate variable
2561 wipeOut( hrnCaller, true );
2564 // if we are assigning the return value to something, clobber now
2565 // as part of the wipe
2566 TempDescriptor returnTemp = fc.getReturnTemp();
2567 if( returnTemp != null &&
2568 DisjointAnalysis.shouldAnalysisTrack( returnTemp.getType() )
2571 VariableNode vnLhsCaller = getVariableNodeFromTemp( returnTemp );
2572 clearRefEdgesFrom( vnLhsCaller, null, null, true );
2578 if( writeDebugDOTs ) {
2579 writeGraph( debugGraphPrefix+"caller30BeforeAddingNodes",
2580 resolveMethodDebugDOTwriteLabels,
2581 resolveMethodDebugDOTselectTemps,
2582 resolveMethodDebugDOTpruneGarbage,
2583 resolveMethodDebugDOThideReach,
2584 resolveMethodDebugDOThideSubsetReach,
2585 resolveMethodDebugDOThidePreds,
2586 resolveMethodDebugDOThideEdgeTaints );
2592 // 3. callee elements with satisfied preds come in, note that
2593 // the mapping of elements satisfied to preds is like this:
2594 // A callee element EE has preds EEp that are satisfied by
2595 // some caller element ER. We bring EE into the caller
2596 // context as ERee with the preds of ER, namely ERp, which
2597 // in the following algorithm is the value in the mapping
2600 Iterator satisItr = calleeNodesSatisfied.entrySet().iterator();
2601 while( satisItr.hasNext() ) {
2602 Map.Entry me = (Map.Entry) satisItr.next();
2603 HeapRegionNode hrnCallee = (HeapRegionNode) me.getKey();
2604 ExistPredSet preds = (ExistPredSet) me.getValue();
2606 // TODO: I think its true that the current implementation uses
2607 // the type of the OOC region and the predicates OF THE EDGE from
2608 // it to link everything up in caller context, so that's why we're
2609 // skipping this... maybe that's a sillier way to do it?
2610 if( hrnCallee.isOutOfContext() ) {
2614 AllocSite as = hrnCallee.getAllocSite();
2615 allocSites.add( as );
2617 Integer hrnIDshadow = as.getShadowIDfromID( hrnCallee.getID() );
2619 HeapRegionNode hrnCaller = id2hrn.get( hrnIDshadow );
2620 if( hrnCaller == null ) {
2622 createNewHeapRegionNode( hrnIDshadow, // id or null to generate a new one
2623 hrnCallee.isSingleObject(), // single object?
2624 hrnCallee.isNewSummary(), // summary?
2625 false, // out-of-context?
2626 hrnCallee.getType(), // type
2627 hrnCallee.getAllocSite(), // allocation site
2628 toCallerContext( hrnCallee.getInherent(),
2629 calleeNode2calleeStatesSatisfied.get( hrnCallee ) ), // inherent reach
2630 null, // current reach
2631 predsEmpty, // predicates
2632 hrnCallee.getDescription() // description
2635 assert hrnCaller.isWiped();
2638 hrnCaller.setAlpha( toCallerContext( hrnCallee.getAlpha(),
2639 calleeNode2calleeStatesSatisfied.get( hrnCallee )
2643 hrnCaller.setPreds( preds );
2650 if( writeDebugDOTs ) {
2651 writeGraph( debugGraphPrefix+"caller31BeforeAddingEdges",
2652 resolveMethodDebugDOTwriteLabels,
2653 resolveMethodDebugDOTselectTemps,
2654 resolveMethodDebugDOTpruneGarbage,
2655 resolveMethodDebugDOThideReach,
2656 resolveMethodDebugDOThideSubsetReach,
2657 resolveMethodDebugDOThidePreds,
2658 resolveMethodDebugDOThideEdgeTaints );
2662 // set these up during the next procedure so after
2663 // the caller has all of its nodes and edges put
2664 // back together we can propagate the callee's
2665 // reach changes backwards into the caller graph
2666 HashSet<RefEdge> edgesForPropagation = new HashSet<RefEdge>();
2668 Hashtable<RefEdge, ChangeSet> edgePlannedChanges =
2669 new Hashtable<RefEdge, ChangeSet>();
2672 // 3.b) callee -> callee edges AND out-of-context -> callee
2673 // which includes return temp -> callee edges now, too
2674 satisItr = calleeEdgesSatisfied.entrySet().iterator();
2675 while( satisItr.hasNext() ) {
2676 Map.Entry me = (Map.Entry) satisItr.next();
2677 RefEdge reCallee = (RefEdge) me.getKey();
2678 ExistPredSet preds = (ExistPredSet) me.getValue();
2680 HeapRegionNode hrnDstCallee = reCallee.getDst();
2681 AllocSite asDst = hrnDstCallee.getAllocSite();
2682 allocSites.add( asDst );
2684 Integer hrnIDDstShadow =
2685 asDst.getShadowIDfromID( hrnDstCallee.getID() );
2687 HeapRegionNode hrnDstCaller = id2hrn.get( hrnIDDstShadow );
2688 assert hrnDstCaller != null;
2691 RefSrcNode rsnCallee = reCallee.getSrc();
2693 Set<RefSrcNode> rsnCallers =
2694 new HashSet<RefSrcNode>();
2696 Set<RefSrcNode> oocCallers =
2697 calleeEdges2oocCallerSrcMatches.get( reCallee );
2699 if( rsnCallee instanceof HeapRegionNode ) {
2700 HeapRegionNode hrnCalleeSrc = (HeapRegionNode) rsnCallee;
2701 if( hrnCalleeSrc.isOutOfContext() ) {
2702 assert oocCallers != null;
2707 if( oocCallers == null ) {
2708 // there are no out-of-context matches, so it's
2709 // either a param/arg var or one in-context heap region
2710 if( rsnCallee instanceof VariableNode ) {
2711 // variable -> node in the callee should only
2712 // come into the caller if its from a param var
2713 VariableNode vnCallee = (VariableNode) rsnCallee;
2714 TempDescriptor tdParam = vnCallee.getTempDescriptor();
2715 TempDescriptor tdArg = fc.getArgMatchingParam( fmCallee,
2717 if( tdArg == null ) {
2718 // this means the variable isn't a parameter, its local
2719 // to the callee so we ignore it in call site transfer
2720 // shouldn't this NEVER HAPPEN?
2724 rsnCallers.add( this.getVariableNodeFromTemp( tdArg ) );
2727 // otherwise source is in context, one region
2729 HeapRegionNode hrnSrcCallee = (HeapRegionNode) rsnCallee;
2731 // translate an in-context node to shadow
2732 AllocSite asSrc = hrnSrcCallee.getAllocSite();
2733 allocSites.add( asSrc );
2735 Integer hrnIDSrcShadow =
2736 asSrc.getShadowIDfromID( hrnSrcCallee.getID() );
2738 HeapRegionNode hrnSrcCallerShadow =
2739 this.id2hrn.get( hrnIDSrcShadow );
2741 assert hrnSrcCallerShadow != null;
2743 rsnCallers.add( hrnSrcCallerShadow );
2747 // otherwise we have a set of out-of-context srcs
2748 // that should NOT be translated to shadow nodes
2749 assert !oocCallers.isEmpty();
2750 rsnCallers.addAll( oocCallers );
2753 // now make all caller edges we've identified from
2754 // this callee edge with a satisfied predicate
2755 assert !rsnCallers.isEmpty();
2756 Iterator<RefSrcNode> rsnItr = rsnCallers.iterator();
2757 while( rsnItr.hasNext() ) {
2758 RefSrcNode rsnCaller = rsnItr.next();
2760 RefEdge reCaller = new RefEdge( rsnCaller,
2763 reCallee.getField(),
2764 toCallerContext( reCallee.getBeta(),
2765 calleeEdge2calleeStatesSatisfied.get( reCallee ) ),
2767 toCallerContext( reCallee.getTaints(),
2768 calleeEdge2calleeTaintsSatisfied.get( reCallee ) )
2771 ChangeSet cs = ChangeSet.factory();
2772 Iterator<ReachState> rsItr = reCaller.getBeta().iterator();
2773 while( rsItr.hasNext() ) {
2774 ReachState state = rsItr.next();
2775 ExistPredSet predsPreCallee = state.getPreds();
2777 if( state.isEmpty() ) {
2781 Iterator<ExistPred> predItr = predsPreCallee.iterator();
2782 while( predItr.hasNext() ) {
2783 ExistPred pred = predItr.next();
2784 ReachState old = pred.ne_state;
2790 cs = Canonical.add( cs,
2791 ChangeTuple.factory( old,
2798 // we're just going to use the convenient "merge-if-exists"
2799 // edge call below, but still take a separate look if there
2800 // is an existing caller edge to build change sets properly
2801 if( !cs.isEmpty() ) {
2802 RefEdge edgeExisting = rsnCaller.getReferenceTo( hrnDstCaller,
2806 if( edgeExisting != null ) {
2807 ChangeSet csExisting = edgePlannedChanges.get( edgeExisting );
2808 if( csExisting == null ) {
2809 csExisting = ChangeSet.factory();
2811 edgePlannedChanges.put( edgeExisting,
2812 Canonical.union( csExisting,
2817 edgesForPropagation.add( reCaller );
2818 assert !edgePlannedChanges.containsKey( reCaller );
2819 edgePlannedChanges.put( reCaller, cs );
2823 // then add new caller edge or merge
2824 addEdgeOrMergeWithExisting( reCaller );
2832 if( writeDebugDOTs ) {
2833 writeGraph( debugGraphPrefix+"caller38propagateReach",
2834 resolveMethodDebugDOTwriteLabels,
2835 resolveMethodDebugDOTselectTemps,
2836 resolveMethodDebugDOTpruneGarbage,
2837 resolveMethodDebugDOThideReach,
2838 resolveMethodDebugDOThideSubsetReach,
2839 resolveMethodDebugDOThidePreds,
2840 resolveMethodDebugDOThideEdgeTaints );
2843 // propagate callee reachability changes to the rest
2844 // of the caller graph edges
2845 HashSet<RefEdge> edgesUpdated = new HashSet<RefEdge>();
2847 propagateTokensOverEdges( edgesForPropagation, // source edges
2848 edgePlannedChanges, // map src edge to change set
2849 edgesUpdated ); // list of updated edges
2851 // commit beta' (beta<-betaNew)
2852 Iterator<RefEdge> edgeItr = edgesUpdated.iterator();
2853 while( edgeItr.hasNext() ) {
2854 edgeItr.next().applyBetaNew();
2863 if( writeDebugDOTs ) {
2864 writeGraph( debugGraphPrefix+"caller40BeforeShadowMerge",
2865 resolveMethodDebugDOTwriteLabels,
2866 resolveMethodDebugDOTselectTemps,
2867 resolveMethodDebugDOTpruneGarbage,
2868 resolveMethodDebugDOThideReach,
2869 resolveMethodDebugDOThideSubsetReach,
2870 resolveMethodDebugDOThidePreds,
2871 resolveMethodDebugDOThideEdgeTaints );
2875 // 4) merge shadow nodes so alloc sites are back to k
2876 Iterator<AllocSite> asItr = rgCallee.allocSites.iterator();
2877 while( asItr.hasNext() ) {
2878 // for each allocation site do the following to merge
2879 // shadow nodes (newest from callee) with any existing
2880 // look for the newest normal and newest shadow "slot"
2881 // not being used, transfer normal to shadow. Keep
2882 // doing this until there are no more normal nodes, or
2883 // no empty shadow slots: then merge all remaining normal
2884 // nodes into the shadow summary. Finally, convert all
2885 // shadow to their normal versions.
2886 AllocSite as = asItr.next();
2889 while( ageNorm < allocationDepth &&
2890 ageShad < allocationDepth ) {
2892 // first, are there any normal nodes left?
2893 Integer idNorm = as.getIthOldest( ageNorm );
2894 HeapRegionNode hrnNorm = id2hrn.get( idNorm );
2895 if( hrnNorm == null ) {
2896 // no, this age of normal node not in the caller graph
2901 // yes, a normal node exists, is there an empty shadow
2902 // "slot" to transfer it onto?
2903 HeapRegionNode hrnShad = getIthNode( as, ageShad, true );
2904 if( !hrnShad.isWiped() ) {
2905 // no, this age of shadow node is not empty
2910 // yes, this shadow node is empty
2911 transferOnto( hrnNorm, hrnShad );
2916 // now, while there are still normal nodes but no shadow
2917 // slots, merge normal nodes into the shadow summary
2918 while( ageNorm < allocationDepth ) {
2920 // first, are there any normal nodes left?
2921 Integer idNorm = as.getIthOldest( ageNorm );
2922 HeapRegionNode hrnNorm = id2hrn.get( idNorm );
2923 if( hrnNorm == null ) {
2924 // no, this age of normal node not in the caller graph
2929 // yes, a normal node exists, so get the shadow summary
2930 HeapRegionNode summShad = getSummaryNode( as, true );
2931 mergeIntoSummary( hrnNorm, summShad );
2935 // if there is a normal summary, merge it into shadow summary
2936 Integer idNorm = as.getSummary();
2937 HeapRegionNode summNorm = id2hrn.get( idNorm );
2938 if( summNorm != null ) {
2939 HeapRegionNode summShad = getSummaryNode( as, true );
2940 mergeIntoSummary( summNorm, summShad );
2943 // finally, flip all existing shadow nodes onto the normal
2944 for( int i = 0; i < allocationDepth; ++i ) {
2945 Integer idShad = as.getIthOldestShadow( i );
2946 HeapRegionNode hrnShad = id2hrn.get( idShad );
2947 if( hrnShad != null ) {
2949 HeapRegionNode hrnNorm = getIthNode( as, i, false );
2950 assert hrnNorm.isWiped();
2951 transferOnto( hrnShad, hrnNorm );
2955 Integer idShad = as.getSummaryShadow();
2956 HeapRegionNode summShad = id2hrn.get( idShad );
2957 if( summShad != null ) {
2958 summNorm = getSummaryNode( as, false );
2959 transferOnto( summShad, summNorm );
2968 if( writeDebugDOTs ) {
2969 writeGraph( debugGraphPrefix+"caller45BeforeUnshadow",
2970 resolveMethodDebugDOTwriteLabels,
2971 resolveMethodDebugDOTselectTemps,
2972 resolveMethodDebugDOTpruneGarbage,
2973 resolveMethodDebugDOThideReach,
2974 resolveMethodDebugDOThideSubsetReach,
2975 resolveMethodDebugDOThidePreds,
2976 resolveMethodDebugDOThideEdgeTaints );
2980 Iterator itrAllHRNodes = id2hrn.entrySet().iterator();
2981 while( itrAllHRNodes.hasNext() ) {
2982 Map.Entry me = (Map.Entry) itrAllHRNodes.next();
2983 HeapRegionNode hrn = (HeapRegionNode) me.getValue();
2985 hrn.setAlpha( unshadow( hrn.getAlpha() ) );
2987 Iterator<RefEdge> itrEdges = hrn.iteratorToReferencers();
2988 while( itrEdges.hasNext() ) {
2989 RefEdge re = itrEdges.next();
2990 re.setBeta( unshadow( re.getBeta() ) );
2997 if( writeDebugDOTs ) {
2998 writeGraph( debugGraphPrefix+"caller50BeforeGlobalSweep",
2999 resolveMethodDebugDOTwriteLabels,
3000 resolveMethodDebugDOTselectTemps,
3001 resolveMethodDebugDOTpruneGarbage,
3002 resolveMethodDebugDOThideReach,
3003 resolveMethodDebugDOThideSubsetReach,
3004 resolveMethodDebugDOThidePreds,
3005 resolveMethodDebugDOThideEdgeTaints );
3010 if( !DISABLE_GLOBAL_SWEEP ) {
3015 if( writeDebugDOTs ) {
3016 writeGraph( debugGraphPrefix+"caller90AfterTransfer",
3017 resolveMethodDebugDOTwriteLabels,
3018 resolveMethodDebugDOTselectTemps,
3019 resolveMethodDebugDOTpruneGarbage,
3020 resolveMethodDebugDOThideReach,
3021 resolveMethodDebugDOThideSubsetReach,
3022 resolveMethodDebugDOThidePreds,
3023 resolveMethodDebugDOThideEdgeTaints );
3029 ////////////////////////////////////////////////////
3031 // Abstract garbage collection simply removes
3032 // heap region nodes that are not mechanically
3033 // reachable from a root set. This step is
3034 // essential for testing node and edge existence
3035 // predicates efficiently
3037 ////////////////////////////////////////////////////
3038 public void abstractGarbageCollect( Set<TempDescriptor> liveSet ) {
3040 // calculate a root set, will be different for Java
3041 // version of analysis versus Bamboo version
3042 Set<RefSrcNode> toVisit = new HashSet<RefSrcNode>();
3044 // visit every variable in graph while building root
3045 // set, and do iterating on a copy, so we can remove
3046 // dead variables while we're at this
3047 Iterator makeCopyItr = td2vn.entrySet().iterator();
3048 Set entrysCopy = new HashSet();
3049 while( makeCopyItr.hasNext() ) {
3050 entrysCopy.add( makeCopyItr.next() );
3053 Iterator eItr = entrysCopy.iterator();
3054 while( eItr.hasNext() ) {
3055 Map.Entry me = (Map.Entry) eItr.next();
3056 TempDescriptor td = (TempDescriptor) me.getKey();
3057 VariableNode vn = (VariableNode) me.getValue();
3059 if( liveSet.contains( td ) ) {
3063 // dead var, remove completely from graph
3065 clearRefEdgesFrom( vn, null, null, true );
3069 // everything visited in a traversal is
3070 // considered abstractly live
3071 Set<RefSrcNode> visited = new HashSet<RefSrcNode>();
3073 while( !toVisit.isEmpty() ) {
3074 RefSrcNode rsn = toVisit.iterator().next();
3075 toVisit.remove( rsn );
3078 Iterator<RefEdge> hrnItr = rsn.iteratorToReferencees();
3079 while( hrnItr.hasNext() ) {
3080 RefEdge edge = hrnItr.next();
3081 HeapRegionNode hrn = edge.getDst();
3083 if( !visited.contains( hrn ) ) {
3089 // get a copy of the set to iterate over because
3090 // we're going to monkey with the graph when we
3091 // identify a garbage node
3092 Set<HeapRegionNode> hrnAllPrior = new HashSet<HeapRegionNode>();
3093 Iterator<HeapRegionNode> hrnItr = id2hrn.values().iterator();
3094 while( hrnItr.hasNext() ) {
3095 hrnAllPrior.add( hrnItr.next() );
3098 Iterator<HeapRegionNode> hrnAllItr = hrnAllPrior.iterator();
3099 while( hrnAllItr.hasNext() ) {
3100 HeapRegionNode hrn = hrnAllItr.next();
3102 if( !visited.contains( hrn ) ) {
3104 // heap region nodes are compared across ReachGraph
3105 // objects by their integer ID, so when discarding
3106 // garbage nodes we must also discard entries in
3107 // the ID -> heap region hashtable.
3108 id2hrn.remove( hrn.getID() );
3110 // RefEdge objects are two-way linked between
3111 // nodes, so when a node is identified as garbage,
3112 // actively clear references to and from it so
3113 // live nodes won't have dangling RefEdge's
3114 wipeOut( hrn, true );
3116 // if we just removed the last node from an allocation
3117 // site, it should be taken out of the ReachGraph's list
3118 AllocSite as = hrn.getAllocSite();
3119 if( !hasNodesOf( as ) ) {
3120 allocSites.remove( as );
3126 protected boolean hasNodesOf( AllocSite as ) {
3127 if( id2hrn.containsKey( as.getSummary() ) ) {
3131 for( int i = 0; i < allocationDepth; ++i ) {
3132 if( id2hrn.containsKey( as.getIthOldest( i ) ) ) {
3140 ////////////////////////////////////////////////////
3142 // This global sweep is an optional step to prune
3143 // reachability sets that are not internally
3144 // consistent with the global graph. It should be
3145 // invoked after strong updates or method calls.
3147 ////////////////////////////////////////////////////
3148 public void globalSweep() {
3150 // boldB is part of the phase 1 sweep
3151 // it has an in-context table and an out-of-context table
3152 Hashtable< Integer, Hashtable<RefEdge, ReachSet> > boldBic =
3153 new Hashtable< Integer, Hashtable<RefEdge, ReachSet> >();
3155 Hashtable< Integer, Hashtable<RefEdge, ReachSet> > boldBooc =
3156 new Hashtable< Integer, Hashtable<RefEdge, ReachSet> >();
3158 // visit every heap region to initialize alphaNew and betaNew,
3159 // and make a map of every hrnID to the source nodes it should
3160 // propagate forward from. In-context flagged hrnID's propagate
3161 // from only the in-context node they name, but out-of-context
3162 // ID's may propagate from several out-of-context nodes
3163 Hashtable< Integer, Set<HeapRegionNode> > icID2srcs =
3164 new Hashtable< Integer, Set<HeapRegionNode> >();
3166 Hashtable< Integer, Set<HeapRegionNode> > oocID2srcs =
3167 new Hashtable< Integer, Set<HeapRegionNode> >();
3170 Iterator itrHrns = id2hrn.entrySet().iterator();
3171 while( itrHrns.hasNext() ) {
3172 Map.Entry me = (Map.Entry) itrHrns.next();
3173 Integer hrnID = (Integer) me.getKey();
3174 HeapRegionNode hrn = (HeapRegionNode) me.getValue();
3176 // assert that this node and incoming edges have clean alphaNew
3177 // and betaNew sets, respectively
3178 assert rsetEmpty.equals( hrn.getAlphaNew() );
3180 Iterator<RefEdge> itrRers = hrn.iteratorToReferencers();
3181 while( itrRers.hasNext() ) {
3182 RefEdge edge = itrRers.next();
3183 assert rsetEmpty.equals( edge.getBetaNew() );
3186 // make a mapping of IDs to heap regions they propagate from
3187 if( hrn.isFlagged() ) {
3188 assert !hrn.isOutOfContext();
3189 assert !icID2srcs.containsKey( hrn.getID() );
3191 // in-context flagged node IDs simply propagate from the
3193 Set<HeapRegionNode> srcs = new HashSet<HeapRegionNode>();
3195 icID2srcs.put( hrn.getID(), srcs );
3198 if( hrn.isOutOfContext() ) {
3199 assert !hrn.isFlagged();
3201 // the reachability states on an out-of-context
3202 // node are not really important (combinations of
3203 // IDs or arity)--what matters is that the states
3204 // specify which nodes this out-of-context node
3205 // stands in for. For example, if the state [17?, 19*]
3206 // appears on the ooc node, it may serve as a source
3207 // for node 17? and a source for node 19.
3208 Iterator<ReachState> stateItr = hrn.getAlpha().iterator();
3209 while( stateItr.hasNext() ) {
3210 ReachState state = stateItr.next();
3212 Iterator<ReachTuple> rtItr = state.iterator();
3213 while( rtItr.hasNext() ) {
3214 ReachTuple rt = rtItr.next();
3215 assert rt.isOutOfContext();
3217 Set<HeapRegionNode> srcs = oocID2srcs.get( rt.getHrnID() );
3218 if( srcs == null ) {
3219 srcs = new HashSet<HeapRegionNode>();
3222 oocID2srcs.put( rt.getHrnID(), srcs );
3228 // calculate boldB for all hrnIDs identified by the above
3229 // node traversal, propagating from every source
3230 while( !icID2srcs.isEmpty() || !oocID2srcs.isEmpty() ) {
3233 Set<HeapRegionNode> srcs;
3236 if( !icID2srcs.isEmpty() ) {
3237 Map.Entry me = (Map.Entry) icID2srcs.entrySet().iterator().next();
3238 hrnID = (Integer) me.getKey();
3239 srcs = (Set<HeapRegionNode>) me.getValue();
3241 icID2srcs.remove( hrnID );
3244 assert !oocID2srcs.isEmpty();
3246 Map.Entry me = (Map.Entry) oocID2srcs.entrySet().iterator().next();
3247 hrnID = (Integer) me.getKey();
3248 srcs = (Set<HeapRegionNode>) me.getValue();
3250 oocID2srcs.remove( hrnID );
3254 Hashtable<RefEdge, ReachSet> boldB_f =
3255 new Hashtable<RefEdge, ReachSet>();
3257 Set<RefEdge> workSetEdges = new HashSet<RefEdge>();
3259 Iterator<HeapRegionNode> hrnItr = srcs.iterator();
3260 while( hrnItr.hasNext() ) {
3261 HeapRegionNode hrn = hrnItr.next();
3263 assert workSetEdges.isEmpty();
3265 // initial boldB_f constraints
3266 Iterator<RefEdge> itrRees = hrn.iteratorToReferencees();
3267 while( itrRees.hasNext() ) {
3268 RefEdge edge = itrRees.next();
3270 assert !boldB_f.containsKey( edge );
3271 boldB_f.put( edge, edge.getBeta() );
3273 assert !workSetEdges.contains( edge );
3274 workSetEdges.add( edge );
3277 // enforce the boldB_f constraint at edges until we reach a fixed point
3278 while( !workSetEdges.isEmpty() ) {
3279 RefEdge edge = workSetEdges.iterator().next();
3280 workSetEdges.remove( edge );
3282 Iterator<RefEdge> itrPrime = edge.getDst().iteratorToReferencees();
3283 while( itrPrime.hasNext() ) {
3284 RefEdge edgePrime = itrPrime.next();
3286 ReachSet prevResult = boldB_f.get( edgePrime );
3287 ReachSet intersection = Canonical.intersection( boldB_f.get( edge ),
3291 if( prevResult == null ||
3292 Canonical.unionORpreds( prevResult,
3293 intersection ).size()
3297 if( prevResult == null ) {
3298 boldB_f.put( edgePrime,
3299 Canonical.unionORpreds( edgePrime.getBeta(),
3304 boldB_f.put( edgePrime,
3305 Canonical.unionORpreds( prevResult,
3310 workSetEdges.add( edgePrime );
3317 boldBic.put( hrnID, boldB_f );
3319 boldBooc.put( hrnID, boldB_f );
3324 // use boldB to prune hrnIDs from alpha states that are impossible
3325 // and propagate the differences backwards across edges
3326 HashSet<RefEdge> edgesForPropagation = new HashSet<RefEdge>();
3328 Hashtable<RefEdge, ChangeSet> edgePlannedChanges =
3329 new Hashtable<RefEdge, ChangeSet>();
3332 itrHrns = id2hrn.entrySet().iterator();
3333 while( itrHrns.hasNext() ) {
3334 Map.Entry me = (Map.Entry) itrHrns.next();
3335 Integer hrnID = (Integer) me.getKey();
3336 HeapRegionNode hrn = (HeapRegionNode) me.getValue();
3338 // out-of-context nodes don't participate in the
3339 // global sweep, they serve as sources for the pass
3341 if( hrn.isOutOfContext() ) {
3345 // the inherent states of a region are the exception
3346 // to removal as the global sweep prunes
3347 ReachTuple rtException = ReachTuple.factory( hrnID,
3348 !hrn.isSingleObject(),
3349 ReachTuple.ARITY_ONE,
3350 false // out-of-context
3353 ChangeSet cts = ChangeSet.factory();
3355 // mark hrnIDs for removal
3356 Iterator<ReachState> stateItr = hrn.getAlpha().iterator();
3357 while( stateItr.hasNext() ) {
3358 ReachState stateOld = stateItr.next();
3360 ReachState markedHrnIDs = ReachState.factory();
3362 Iterator<ReachTuple> rtItr = stateOld.iterator();
3363 while( rtItr.hasNext() ) {
3364 ReachTuple rtOld = rtItr.next();
3366 // never remove the inherent hrnID from a flagged region
3367 // because it is trivially satisfied
3368 if( hrn.isFlagged() ) {
3369 if( rtOld == rtException ) {
3374 // does boldB allow this hrnID?
3375 boolean foundState = false;
3376 Iterator<RefEdge> incidentEdgeItr = hrn.iteratorToReferencers();
3377 while( incidentEdgeItr.hasNext() ) {
3378 RefEdge incidentEdge = incidentEdgeItr.next();
3380 Hashtable<RefEdge, ReachSet> B;
3381 if( rtOld.isOutOfContext() ) {
3382 B = boldBooc.get( rtOld.getHrnID() );
3385 if( !id2hrn.containsKey( rtOld.getHrnID() ) ) {
3386 // let symbols not in the graph get pruned
3390 B = boldBic.get( rtOld.getHrnID() );
3394 ReachSet boldB_rtOld_incident = B.get( incidentEdge );
3395 if( boldB_rtOld_incident != null &&
3396 boldB_rtOld_incident.containsIgnorePreds( stateOld ) != null
3404 markedHrnIDs = Canonical.addUpArity( markedHrnIDs, rtOld );
3408 // if there is nothing marked, just move on
3409 if( markedHrnIDs.isEmpty() ) {
3410 hrn.setAlphaNew( Canonical.add( hrn.getAlphaNew(),
3417 // remove all marked hrnIDs and establish a change set that should
3418 // propagate backwards over edges from this node
3419 ReachState statePruned = ReachState.factory();
3420 rtItr = stateOld.iterator();
3421 while( rtItr.hasNext() ) {
3422 ReachTuple rtOld = rtItr.next();
3424 if( !markedHrnIDs.containsTuple( rtOld ) ) {
3425 statePruned = Canonical.addUpArity( statePruned, rtOld );
3428 assert !stateOld.equals( statePruned );
3430 hrn.setAlphaNew( Canonical.add( hrn.getAlphaNew(),
3434 ChangeTuple ct = ChangeTuple.factory( stateOld,
3437 cts = Canonical.add( cts, ct );
3440 // throw change tuple set on all incident edges
3441 if( !cts.isEmpty() ) {
3442 Iterator<RefEdge> incidentEdgeItr = hrn.iteratorToReferencers();
3443 while( incidentEdgeItr.hasNext() ) {
3444 RefEdge incidentEdge = incidentEdgeItr.next();
3446 edgesForPropagation.add( incidentEdge );
3448 if( edgePlannedChanges.get( incidentEdge ) == null ) {
3449 edgePlannedChanges.put( incidentEdge, cts );
3451 edgePlannedChanges.put(
3453 Canonical.union( edgePlannedChanges.get( incidentEdge ),
3462 HashSet<RefEdge> edgesUpdated = new HashSet<RefEdge>();
3464 propagateTokensOverEdges( edgesForPropagation,
3468 // at the end of the 1st phase reference edges have
3469 // beta, betaNew that correspond to beta and betaR
3471 // commit beta<-betaNew, so beta=betaR and betaNew
3472 // will represent the beta' calculation in 2nd phase
3474 // commit alpha<-alphaNew because it won't change
3475 HashSet<RefEdge> res = new HashSet<RefEdge>();
3477 Iterator<HeapRegionNode> nodeItr = id2hrn.values().iterator();
3478 while( nodeItr.hasNext() ) {
3479 HeapRegionNode hrn = nodeItr.next();
3481 // as mentioned above, out-of-context nodes only serve
3482 // as sources of reach states for the sweep, not part
3484 if( hrn.isOutOfContext() ) {
3485 assert hrn.getAlphaNew().equals( rsetEmpty );
3487 hrn.applyAlphaNew();
3490 Iterator<RefEdge> itrRes = hrn.iteratorToReferencers();
3491 while( itrRes.hasNext() ) {
3492 res.add( itrRes.next() );
3498 Iterator<RefEdge> edgeItr = res.iterator();
3499 while( edgeItr.hasNext() ) {
3500 RefEdge edge = edgeItr.next();
3501 HeapRegionNode hrn = edge.getDst();
3503 // commit results of last phase
3504 if( edgesUpdated.contains( edge ) ) {
3505 edge.applyBetaNew();
3508 // compute intial condition of 2nd phase
3509 edge.setBetaNew( Canonical.intersection( edge.getBeta(),
3515 // every edge in the graph is the initial workset
3516 Set<RefEdge> edgeWorkSet = (Set) res.clone();
3517 while( !edgeWorkSet.isEmpty() ) {
3518 RefEdge edgePrime = edgeWorkSet.iterator().next();
3519 edgeWorkSet.remove( edgePrime );
3521 RefSrcNode rsn = edgePrime.getSrc();
3522 if( !(rsn instanceof HeapRegionNode) ) {
3525 HeapRegionNode hrn = (HeapRegionNode) rsn;
3527 Iterator<RefEdge> itrEdge = hrn.iteratorToReferencers();
3528 while( itrEdge.hasNext() ) {
3529 RefEdge edge = itrEdge.next();
3531 ReachSet prevResult = edge.getBetaNew();
3532 assert prevResult != null;
3534 ReachSet intersection =
3535 Canonical.intersection( edge.getBeta(),
3536 edgePrime.getBetaNew()
3539 if( Canonical.unionORpreds( prevResult,
3546 Canonical.unionORpreds( prevResult,
3550 edgeWorkSet.add( edge );
3555 // commit beta' (beta<-betaNew)
3556 edgeItr = res.iterator();
3557 while( edgeItr.hasNext() ) {
3558 edgeItr.next().applyBetaNew();
3563 // a useful assertion for debugging:
3564 // every in-context tuple on any edge or
3565 // any node should name a node that is
3566 // part of the graph
3567 public boolean inContextTuplesInGraph() {
3569 Iterator hrnItr = id2hrn.entrySet().iterator();
3570 while( hrnItr.hasNext() ) {
3571 Map.Entry me = (Map.Entry) hrnItr.next();
3572 HeapRegionNode hrn = (HeapRegionNode) me.getValue();
3575 Iterator<ReachState> stateItr = hrn.getAlpha().iterator();
3576 while( stateItr.hasNext() ) {
3577 ReachState state = stateItr.next();
3579 Iterator<ReachTuple> rtItr = state.iterator();
3580 while( rtItr.hasNext() ) {
3581 ReachTuple rt = rtItr.next();
3583 if( !rt.isOutOfContext() ) {
3584 if( !id2hrn.containsKey( rt.getHrnID() ) ) {
3585 System.out.println( rt.getHrnID()+" is missing" );
3593 Iterator<RefEdge> edgeItr = hrn.iteratorToReferencers();
3594 while( edgeItr.hasNext() ) {
3595 RefEdge edge = edgeItr.next();
3597 Iterator<ReachState> stateItr = edge.getBeta().iterator();
3598 while( stateItr.hasNext() ) {
3599 ReachState state = stateItr.next();
3601 Iterator<ReachTuple> rtItr = state.iterator();
3602 while( rtItr.hasNext() ) {
3603 ReachTuple rt = rtItr.next();
3605 if( !rt.isOutOfContext() ) {
3606 if( !id2hrn.containsKey( rt.getHrnID() ) ) {
3607 System.out.println( rt.getHrnID()+" is missing" );
3620 // another useful assertion for debugging
3621 public boolean noEmptyReachSetsInGraph() {
3623 Iterator hrnItr = id2hrn.entrySet().iterator();
3624 while( hrnItr.hasNext() ) {
3625 Map.Entry me = (Map.Entry) hrnItr.next();
3626 HeapRegionNode hrn = (HeapRegionNode) me.getValue();
3628 if( !hrn.isOutOfContext() &&
3630 hrn.getAlpha().isEmpty()
3632 System.out.println( "!!! "+hrn+" has an empty ReachSet !!!" );
3636 Iterator<RefEdge> edgeItr = hrn.iteratorToReferencers();
3637 while( edgeItr.hasNext() ) {
3638 RefEdge edge = edgeItr.next();
3640 if( edge.getBeta().isEmpty() ) {
3641 System.out.println( "!!! "+edge+" has an empty ReachSet !!!" );
3651 public boolean everyReachStateWTrue() {
3653 Iterator hrnItr = id2hrn.entrySet().iterator();
3654 while( hrnItr.hasNext() ) {
3655 Map.Entry me = (Map.Entry) hrnItr.next();
3656 HeapRegionNode hrn = (HeapRegionNode) me.getValue();
3659 Iterator<ReachState> stateItr = hrn.getAlpha().iterator();
3660 while( stateItr.hasNext() ) {
3661 ReachState state = stateItr.next();
3663 if( !state.getPreds().equals( predsTrue ) ) {
3669 Iterator<RefEdge> edgeItr = hrn.iteratorToReferencers();
3670 while( edgeItr.hasNext() ) {
3671 RefEdge edge = edgeItr.next();
3673 Iterator<ReachState> stateItr = edge.getBeta().iterator();
3674 while( stateItr.hasNext() ) {
3675 ReachState state = stateItr.next();
3677 if( !state.getPreds().equals( predsTrue ) ) {
3690 ////////////////////////////////////////////////////
3691 // in merge() and equals() methods the suffix A
3692 // represents the passed in graph and the suffix
3693 // B refers to the graph in this object
3694 // Merging means to take the incoming graph A and
3695 // merge it into B, so after the operation graph B
3696 // is the final result.
3697 ////////////////////////////////////////////////////
3698 protected void merge( ReachGraph rg ) {
3705 mergeRefEdges ( rg );
3706 mergeAllocSites ( rg );
3707 mergeInaccessibleVars( rg );
3710 protected void mergeNodes( ReachGraph rg ) {
3712 // start with heap region nodes
3713 Set sA = rg.id2hrn.entrySet();
3714 Iterator iA = sA.iterator();
3715 while( iA.hasNext() ) {
3716 Map.Entry meA = (Map.Entry) iA.next();
3717 Integer idA = (Integer) meA.getKey();
3718 HeapRegionNode hrnA = (HeapRegionNode) meA.getValue();
3720 // if this graph doesn't have a node the
3721 // incoming graph has, allocate it
3722 if( !id2hrn.containsKey( idA ) ) {
3723 HeapRegionNode hrnB = hrnA.copy();
3724 id2hrn.put( idA, hrnB );
3727 // otherwise this is a node present in both graphs
3728 // so make the new reachability set a union of the
3729 // nodes' reachability sets
3730 HeapRegionNode hrnB = id2hrn.get( idA );
3731 hrnB.setAlpha( Canonical.unionORpreds( hrnB.getAlpha(),
3736 hrnB.setPreds( Canonical.join( hrnB.getPreds(),
3743 if( !hrnA.equals( hrnB ) ) {
3744 rg.writeGraph( "graphA" );
3745 this.writeGraph( "graphB" );
3746 throw new Error( "flagged not matching" );
3754 // now add any variable nodes that are in graph B but
3756 sA = rg.td2vn.entrySet();
3758 while( iA.hasNext() ) {
3759 Map.Entry meA = (Map.Entry) iA.next();
3760 TempDescriptor tdA = (TempDescriptor) meA.getKey();
3761 VariableNode lnA = (VariableNode) meA.getValue();
3763 // if the variable doesn't exist in B, allocate and add it
3764 VariableNode lnB = getVariableNodeFromTemp( tdA );
3768 protected void mergeRefEdges( ReachGraph rg ) {
3770 // between heap regions
3771 Set sA = rg.id2hrn.entrySet();
3772 Iterator iA = sA.iterator();
3773 while( iA.hasNext() ) {
3774 Map.Entry meA = (Map.Entry) iA.next();
3775 Integer idA = (Integer) meA.getKey();
3776 HeapRegionNode hrnA = (HeapRegionNode) meA.getValue();
3778 Iterator<RefEdge> heapRegionsItrA = hrnA.iteratorToReferencees();
3779 while( heapRegionsItrA.hasNext() ) {
3780 RefEdge edgeA = heapRegionsItrA.next();
3781 HeapRegionNode hrnChildA = edgeA.getDst();
3782 Integer idChildA = hrnChildA.getID();
3784 // at this point we know an edge in graph A exists
3785 // idA -> idChildA, does this exist in B?
3786 assert id2hrn.containsKey( idA );
3787 HeapRegionNode hrnB = id2hrn.get( idA );
3788 RefEdge edgeToMerge = null;
3790 Iterator<RefEdge> heapRegionsItrB = hrnB.iteratorToReferencees();
3791 while( heapRegionsItrB.hasNext() &&
3792 edgeToMerge == null ) {
3794 RefEdge edgeB = heapRegionsItrB.next();
3795 HeapRegionNode hrnChildB = edgeB.getDst();
3796 Integer idChildB = hrnChildB.getID();
3798 // don't use the RefEdge.equals() here because
3799 // we're talking about existence between graphs,
3800 // not intragraph equal
3801 if( idChildB.equals( idChildA ) &&
3802 edgeB.typeAndFieldEquals( edgeA ) ) {
3804 edgeToMerge = edgeB;
3808 // if the edge from A was not found in B,
3810 if( edgeToMerge == null ) {
3811 assert id2hrn.containsKey( idChildA );
3812 HeapRegionNode hrnChildB = id2hrn.get( idChildA );
3813 edgeToMerge = edgeA.copy();
3814 edgeToMerge.setSrc( hrnB );
3815 edgeToMerge.setDst( hrnChildB );
3816 addRefEdge( hrnB, hrnChildB, edgeToMerge );
3818 // otherwise, the edge already existed in both graphs
3819 // so merge their reachability sets
3821 // just replace this beta set with the union
3822 assert edgeToMerge != null;
3823 edgeToMerge.setBeta(
3824 Canonical.unionORpreds( edgeToMerge.getBeta(),
3828 edgeToMerge.setPreds(
3829 Canonical.join( edgeToMerge.getPreds(),
3833 edgeToMerge.setTaints(
3834 Canonical.union( edgeToMerge.getTaints(),
3842 // and then again from variable nodes
3843 sA = rg.td2vn.entrySet();
3845 while( iA.hasNext() ) {
3846 Map.Entry meA = (Map.Entry) iA.next();
3847 TempDescriptor tdA = (TempDescriptor) meA.getKey();
3848 VariableNode vnA = (VariableNode) meA.getValue();
3850 Iterator<RefEdge> heapRegionsItrA = vnA.iteratorToReferencees();
3851 while( heapRegionsItrA.hasNext() ) {
3852 RefEdge edgeA = heapRegionsItrA.next();
3853 HeapRegionNode hrnChildA = edgeA.getDst();
3854 Integer idChildA = hrnChildA.getID();
3856 // at this point we know an edge in graph A exists
3857 // tdA -> idChildA, does this exist in B?
3858 assert td2vn.containsKey( tdA );
3859 VariableNode vnB = td2vn.get( tdA );
3860 RefEdge edgeToMerge = null;
3862 Iterator<RefEdge> heapRegionsItrB = vnB.iteratorToReferencees();
3863 while( heapRegionsItrB.hasNext() &&
3864 edgeToMerge == null ) {
3866 RefEdge edgeB = heapRegionsItrB.next();
3867 HeapRegionNode hrnChildB = edgeB.getDst();
3868 Integer idChildB = hrnChildB.getID();
3870 // don't use the RefEdge.equals() here because
3871 // we're talking about existence between graphs
3872 if( idChildB.equals( idChildA ) &&
3873 edgeB.typeAndFieldEquals( edgeA ) ) {
3875 edgeToMerge = edgeB;
3879 // if the edge from A was not found in B,
3881 if( edgeToMerge == null ) {
3882 assert id2hrn.containsKey( idChildA );
3883 HeapRegionNode hrnChildB = id2hrn.get( idChildA );
3884 edgeToMerge = edgeA.copy();
3885 edgeToMerge.setSrc( vnB );
3886 edgeToMerge.setDst( hrnChildB );
3887 addRefEdge( vnB, hrnChildB, edgeToMerge );
3889 // otherwise, the edge already existed in both graphs
3890 // so merge their reachability sets
3892 // just replace this beta set with the union
3893 edgeToMerge.setBeta( Canonical.unionORpreds( edgeToMerge.getBeta(),
3897 edgeToMerge.setPreds( Canonical.join( edgeToMerge.getPreds(),
3901 edgeToMerge.setTaints(
3902 Canonical.union( edgeToMerge.getTaints(),
3911 protected void mergeAllocSites( ReachGraph rg ) {
3912 allocSites.addAll( rg.allocSites );
3915 protected void mergeInaccessibleVars( ReachGraph rg ){
3916 inaccessibleVars.addAll(rg.inaccessibleVars);
3921 static boolean dbgEquals = false;
3924 // it is necessary in the equals() member functions
3925 // to "check both ways" when comparing the data
3926 // structures of two graphs. For instance, if all
3927 // edges between heap region nodes in graph A are
3928 // present and equal in graph B it is not sufficient
3929 // to say the graphs are equal. Consider that there
3930 // may be edges in graph B that are not in graph A.
3931 // the only way to know that all edges in both graphs
3932 // are equally present is to iterate over both data
3933 // structures and compare against the other graph.
3934 public boolean equals( ReachGraph rg ) {
3938 System.out.println( "rg is null" );
3943 if( !areHeapRegionNodesEqual( rg ) ) {
3945 System.out.println( "hrn not equal" );
3950 if( !areVariableNodesEqual( rg ) ) {
3952 System.out.println( "vars not equal" );
3957 if( !areRefEdgesEqual( rg ) ) {
3959 System.out.println( "edges not equal" );
3964 if( !inaccessibleVars.equals(rg.inaccessibleVars) ){
3968 // if everything is equal up to this point,
3969 // assert that allocSites is also equal--
3970 // this data is redundant but kept for efficiency
3971 assert allocSites.equals( rg.allocSites );
3977 protected boolean areHeapRegionNodesEqual( ReachGraph rg ) {
3979 if( !areallHRNinAalsoinBandequal( this, rg ) ) {
3983 if( !areallHRNinAalsoinBandequal( rg, this ) ) {
3990 static protected boolean areallHRNinAalsoinBandequal( ReachGraph rgA,
3992 Set sA = rgA.id2hrn.entrySet();
3993 Iterator iA = sA.iterator();
3994 while( iA.hasNext() ) {
3995 Map.Entry meA = (Map.Entry) iA.next();
3996 Integer idA = (Integer) meA.getKey();
3997 HeapRegionNode hrnA = (HeapRegionNode) meA.getValue();
3999 if( !rgB.id2hrn.containsKey( idA ) ) {
4003 HeapRegionNode hrnB = rgB.id2hrn.get( idA );
4004 if( !hrnA.equalsIncludingAlphaAndPreds( hrnB ) ) {
4012 protected boolean areVariableNodesEqual( ReachGraph rg ) {
4014 if( !areallVNinAalsoinBandequal( this, rg ) ) {
4018 if( !areallVNinAalsoinBandequal( rg, this ) ) {
4025 static protected boolean areallVNinAalsoinBandequal( ReachGraph rgA,
4027 Set sA = rgA.td2vn.entrySet();
4028 Iterator iA = sA.iterator();
4029 while( iA.hasNext() ) {
4030 Map.Entry meA = (Map.Entry) iA.next();
4031 TempDescriptor tdA = (TempDescriptor) meA.getKey();
4033 if( !rgB.td2vn.containsKey( tdA ) ) {
4042 protected boolean areRefEdgesEqual( ReachGraph rg ) {
4043 if( !areallREinAandBequal( this, rg ) ) {
4047 if( !areallREinAandBequal( rg, this ) ) {
4054 static protected boolean areallREinAandBequal( ReachGraph rgA,
4057 // check all the heap region->heap region edges
4058 Set sA = rgA.id2hrn.entrySet();
4059 Iterator iA = sA.iterator();
4060 while( iA.hasNext() ) {
4061 Map.Entry meA = (Map.Entry) iA.next();
4062 Integer idA = (Integer) meA.getKey();
4063 HeapRegionNode hrnA = (HeapRegionNode) meA.getValue();
4065 // we should have already checked that the same
4066 // heap regions exist in both graphs
4067 assert rgB.id2hrn.containsKey( idA );
4069 if( !areallREfromAequaltoB( rgA, hrnA, rgB ) ) {
4073 // then check every edge in B for presence in A, starting
4074 // from the same parent HeapRegionNode
4075 HeapRegionNode hrnB = rgB.id2hrn.get( idA );
4077 if( !areallREfromAequaltoB( rgB, hrnB, rgA ) ) {
4082 // then check all the variable->heap region edges
4083 sA = rgA.td2vn.entrySet();
4085 while( iA.hasNext() ) {
4086 Map.Entry meA = (Map.Entry) iA.next();
4087 TempDescriptor tdA = (TempDescriptor) meA.getKey();
4088 VariableNode vnA = (VariableNode) meA.getValue();
4090 // we should have already checked that the same
4091 // label nodes exist in both graphs
4092 assert rgB.td2vn.containsKey( tdA );
4094 if( !areallREfromAequaltoB( rgA, vnA, rgB ) ) {
4098 // then check every edge in B for presence in A, starting
4099 // from the same parent VariableNode
4100 VariableNode vnB = rgB.td2vn.get( tdA );
4102 if( !areallREfromAequaltoB( rgB, vnB, rgA ) ) {
4111 static protected boolean areallREfromAequaltoB( ReachGraph rgA,
4115 Iterator<RefEdge> itrA = rnA.iteratorToReferencees();
4116 while( itrA.hasNext() ) {
4117 RefEdge edgeA = itrA.next();
4118 HeapRegionNode hrnChildA = edgeA.getDst();
4119 Integer idChildA = hrnChildA.getID();
4121 assert rgB.id2hrn.containsKey( idChildA );
4123 // at this point we know an edge in graph A exists
4124 // rnA -> idChildA, does this exact edge exist in B?
4125 boolean edgeFound = false;
4127 RefSrcNode rnB = null;
4128 if( rnA instanceof HeapRegionNode ) {
4129 HeapRegionNode hrnA = (HeapRegionNode) rnA;
4130 rnB = rgB.id2hrn.get( hrnA.getID() );
4132 VariableNode vnA = (VariableNode) rnA;
4133 rnB = rgB.td2vn.get( vnA.getTempDescriptor() );
4136 Iterator<RefEdge> itrB = rnB.iteratorToReferencees();
4137 while( itrB.hasNext() ) {
4138 RefEdge edgeB = itrB.next();
4139 HeapRegionNode hrnChildB = edgeB.getDst();
4140 Integer idChildB = hrnChildB.getID();
4142 if( idChildA.equals( idChildB ) &&
4143 edgeA.typeAndFieldEquals( edgeB ) ) {
4145 // there is an edge in the right place with the right field,
4146 // but do they have the same attributes?
4147 if( edgeA.getBeta().equals( edgeB.getBeta() ) &&
4148 edgeA.equalsPreds( edgeB )
4164 // can be used to assert monotonicity
4165 static public boolean isNoSmallerThan( ReachGraph rgA,
4168 //System.out.println( "*** Asking if A is no smaller than B ***" );
4171 Iterator iA = rgA.id2hrn.entrySet().iterator();
4172 while( iA.hasNext() ) {
4173 Map.Entry meA = (Map.Entry) iA.next();
4174 Integer idA = (Integer) meA.getKey();
4175 HeapRegionNode hrnA = (HeapRegionNode) meA.getValue();
4177 if( !rgB.id2hrn.containsKey( idA ) ) {
4178 System.out.println( " regions smaller" );
4182 //HeapRegionNode hrnB = rgB.id2hrn.get( idA );
4183 /* NOT EQUALS, NO SMALLER THAN!
4184 if( !hrnA.equalsIncludingAlphaAndPreds( hrnB ) ) {
4185 System.out.println( " regions smaller" );
4191 // this works just fine, no smaller than
4192 if( !areallVNinAalsoinBandequal( rgA, rgB ) ) {
4193 System.out.println( " vars smaller:" );
4194 System.out.println( " A:"+rgA.td2vn.keySet() );
4195 System.out.println( " B:"+rgB.td2vn.keySet() );
4200 iA = rgA.id2hrn.entrySet().iterator();
4201 while( iA.hasNext() ) {
4202 Map.Entry meA = (Map.Entry) iA.next();
4203 Integer idA = (Integer) meA.getKey();
4204 HeapRegionNode hrnA = (HeapRegionNode) meA.getValue();
4206 Iterator<RefEdge> reItr = hrnA.iteratorToReferencers();
4207 while( reItr.hasNext() ) {
4208 RefEdge edgeA = reItr.next();
4209 RefSrcNode rsnA = edgeA.getSrc();
4211 // we already checked that nodes were present
4212 HeapRegionNode hrnB = rgB.id2hrn.get( hrnA.getID() );
4213 assert hrnB != null;
4216 if( rsnA instanceof VariableNode ) {
4217 VariableNode vnA = (VariableNode) rsnA;
4218 rsnB = rgB.td2vn.get( vnA.getTempDescriptor() );
4221 HeapRegionNode hrnSrcA = (HeapRegionNode) rsnA;
4222 rsnB = rgB.id2hrn.get( hrnSrcA.getID() );
4224 assert rsnB != null;
4226 RefEdge edgeB = rsnB.getReferenceTo( hrnB,
4230 if( edgeB == null ) {
4231 System.out.println( " edges smaller:" );
4235 // REMEMBER, IS NO SMALLER THAN
4237 System.out.println( " edges smaller" );
4253 // this analysis no longer has the "match anything"
4254 // type which was represented by null
4255 protected TypeDescriptor mostSpecificType( TypeDescriptor td1,
4256 TypeDescriptor td2 ) {
4260 if( td1.isNull() ) {
4263 if( td2.isNull() ) {
4266 return typeUtil.mostSpecific( td1, td2 );
4269 protected TypeDescriptor mostSpecificType( TypeDescriptor td1,
4271 TypeDescriptor td3 ) {
4273 return mostSpecificType( td1,
4274 mostSpecificType( td2, td3 )
4278 protected TypeDescriptor mostSpecificType( TypeDescriptor td1,
4281 TypeDescriptor td4 ) {
4283 return mostSpecificType( mostSpecificType( td1, td2 ),
4284 mostSpecificType( td3, td4 )
4288 protected boolean isSuperiorType( TypeDescriptor possibleSuper,
4289 TypeDescriptor possibleChild ) {
4290 assert possibleSuper != null;
4291 assert possibleChild != null;
4293 if( possibleSuper.isNull() ||
4294 possibleChild.isNull() ) {
4298 return typeUtil.isSuperorType( possibleSuper, possibleChild );
4302 protected boolean hasMatchingField( HeapRegionNode src,
4305 TypeDescriptor tdSrc = src.getType();
4306 assert tdSrc != null;
4308 if( tdSrc.isArray() ) {
4309 TypeDescriptor td = edge.getType();
4312 TypeDescriptor tdSrcDeref = tdSrc.dereference();
4313 assert tdSrcDeref != null;
4315 if( !typeUtil.isSuperorType( tdSrcDeref, td ) ) {
4319 return edge.getField().equals( DisjointAnalysis.arrayElementFieldName );
4322 // if it's not a class, it doesn't have any fields to match
4323 if( !tdSrc.isClass() ) {
4327 ClassDescriptor cd = tdSrc.getClassDesc();
4328 while( cd != null ) {
4329 Iterator fieldItr = cd.getFields();
4331 while( fieldItr.hasNext() ) {
4332 FieldDescriptor fd = (FieldDescriptor) fieldItr.next();
4334 if( fd.getType().equals( edge.getType() ) &&
4335 fd.getSymbol().equals( edge.getField() ) ) {
4340 cd = cd.getSuperDesc();
4343 // otherwise it is a class with fields
4344 // but we didn't find a match
4348 protected boolean hasMatchingType( RefEdge edge,
4349 HeapRegionNode dst ) {
4351 // if the region has no type, matches everything
4352 TypeDescriptor tdDst = dst.getType();
4353 assert tdDst != null;
4355 // if the type is not a class or an array, don't
4356 // match because primitives are copied, no aliases
4357 ClassDescriptor cdDst = tdDst.getClassDesc();
4358 if( cdDst == null && !tdDst.isArray() ) {
4362 // if the edge type is null, it matches everything
4363 TypeDescriptor tdEdge = edge.getType();
4364 assert tdEdge != null;
4366 return typeUtil.isSuperorType( tdEdge, tdDst );
4371 // the default signature for quick-and-dirty debugging
4372 public void writeGraph( String graphName ) {
4373 writeGraph( graphName,
4374 true, // write labels
4375 true, // label select
4376 true, // prune garbage
4377 false, // hide reachability
4378 true, // hide subset reachability
4379 true, // hide predicates
4380 false, // hide edge taints
4381 null // in-context boundary
4385 public void writeGraph( String graphName,
4386 boolean writeLabels,
4387 boolean labelSelect,
4388 boolean pruneGarbage,
4389 boolean hideReachability,
4390 boolean hideSubsetReachability,
4391 boolean hidePredicates,
4392 boolean hideEdgeTaints
4394 writeGraph( graphName,
4399 hideSubsetReachability,
4405 public void writeGraph( String graphName,
4406 boolean writeLabels,
4407 boolean labelSelect,
4408 boolean pruneGarbage,
4409 boolean hideReachability,
4410 boolean hideSubsetReachability,
4411 boolean hidePredicates,
4412 boolean hideEdgeTaints,
4413 Set<Integer> callerNodeIDsCopiedToCallee
4416 // remove all non-word characters from the graph name so
4417 // the filename and identifier in dot don't cause errors
4418 graphName = graphName.replaceAll( "[\\W]", "" );
4421 new BufferedWriter( new FileWriter( graphName+".dot" ) );
4423 bw.write( "digraph "+graphName+" {\n" );
4426 // this is an optional step to form the callee-reachable
4427 // "cut-out" into a DOT cluster for visualization
4428 if( callerNodeIDsCopiedToCallee != null ) {
4430 bw.write( " subgraph cluster0 {\n" );
4431 bw.write( " color=blue;\n" );
4433 Iterator i = id2hrn.entrySet().iterator();
4434 while( i.hasNext() ) {
4435 Map.Entry me = (Map.Entry) i.next();
4436 HeapRegionNode hrn = (HeapRegionNode) me.getValue();
4438 if( callerNodeIDsCopiedToCallee.contains( hrn.getID() ) ) {
4441 hrn.toStringDOT( hideReachability,
4442 hideSubsetReachability,
4452 Set<HeapRegionNode> visited = new HashSet<HeapRegionNode>();
4454 // then visit every heap region node
4455 Iterator i = id2hrn.entrySet().iterator();
4456 while( i.hasNext() ) {
4457 Map.Entry me = (Map.Entry) i.next();
4458 HeapRegionNode hrn = (HeapRegionNode) me.getValue();
4460 // only visit nodes worth writing out--for instance
4461 // not every node at an allocation is referenced
4462 // (think of it as garbage-collected), etc.
4463 if( !pruneGarbage ||
4464 hrn.isOutOfContext() ||
4465 (hrn.isFlagged() && hrn.getID() > 0 && !hrn.isWiped()) // a non-shadow flagged node
4468 if( !visited.contains( hrn ) ) {
4469 traverseHeapRegionNodes( hrn,
4474 hideSubsetReachability,
4477 callerNodeIDsCopiedToCallee );
4482 bw.write( " graphTitle[label=\""+graphName+"\",shape=box];\n" );
4485 // then visit every label node, useful for debugging
4487 i = td2vn.entrySet().iterator();
4488 while( i.hasNext() ) {
4489 Map.Entry me = (Map.Entry) i.next();
4490 VariableNode vn = (VariableNode) me.getValue();
4493 String labelStr = vn.getTempDescriptorString();
4494 if( labelStr.startsWith( "___temp" ) ||
4495 labelStr.startsWith( "___dst" ) ||
4496 labelStr.startsWith( "___srctmp" ) ||
4497 labelStr.startsWith( "___neverused" )
4503 Iterator<RefEdge> heapRegionsItr = vn.iteratorToReferencees();
4504 while( heapRegionsItr.hasNext() ) {
4505 RefEdge edge = heapRegionsItr.next();
4506 HeapRegionNode hrn = edge.getDst();
4508 if( !visited.contains( hrn ) ) {
4509 traverseHeapRegionNodes( hrn,
4514 hideSubsetReachability,
4517 callerNodeIDsCopiedToCallee );
4520 bw.write( " "+vn.toString()+
4521 " -> "+hrn.toString()+
4522 edge.toStringDOT( hideReachability,
4523 hideSubsetReachability,
4535 } catch( IOException e ) {
4536 throw new Error( "Error writing out DOT graph "+graphName );
4541 traverseHeapRegionNodes( HeapRegionNode hrn,
4544 Set<HeapRegionNode> visited,
4545 boolean hideReachability,
4546 boolean hideSubsetReachability,
4547 boolean hidePredicates,
4548 boolean hideEdgeTaints,
4549 Set<Integer> callerNodeIDsCopiedToCallee
4550 ) throws java.io.IOException {
4552 if( visited.contains( hrn ) ) {
4557 // if we're drawing the callee-view subgraph, only
4558 // write out the node info if it hasn't already been
4560 if( callerNodeIDsCopiedToCallee == null ||
4561 !callerNodeIDsCopiedToCallee.contains( hrn.getID() )
4565 hrn.toStringDOT( hideReachability,
4566 hideSubsetReachability,
4571 Iterator<RefEdge> childRegionsItr = hrn.iteratorToReferencees();
4572 while( childRegionsItr.hasNext() ) {
4573 RefEdge edge = childRegionsItr.next();
4574 HeapRegionNode hrnChild = edge.getDst();
4576 if( callerNodeIDsCopiedToCallee != null &&
4577 (edge.getSrc() instanceof HeapRegionNode) ) {
4578 HeapRegionNode hrnSrc = (HeapRegionNode) edge.getSrc();
4579 if( callerNodeIDsCopiedToCallee.contains( hrnSrc.getID() ) &&
4580 callerNodeIDsCopiedToCallee.contains( edge.getDst().getID() )
4582 bw.write( " "+hrn.toString()+
4583 " -> "+hrnChild.toString()+
4584 edge.toStringDOT( hideReachability,
4585 hideSubsetReachability,
4590 } else if( !callerNodeIDsCopiedToCallee.contains( hrnSrc.getID() ) &&
4591 callerNodeIDsCopiedToCallee.contains( edge.getDst().getID() )
4593 bw.write( " "+hrn.toString()+
4594 " -> "+hrnChild.toString()+
4595 edge.toStringDOT( hideReachability,
4596 hideSubsetReachability,
4599 ",color=blue,style=dashed" )+
4602 bw.write( " "+hrn.toString()+
4603 " -> "+hrnChild.toString()+
4604 edge.toStringDOT( hideReachability,
4605 hideSubsetReachability,
4612 bw.write( " "+hrn.toString()+
4613 " -> "+hrnChild.toString()+
4614 edge.toStringDOT( hideReachability,
4615 hideSubsetReachability,
4622 traverseHeapRegionNodes( hrnChild,
4627 hideSubsetReachability,
4630 callerNodeIDsCopiedToCallee );
4639 // return the set of heap regions from the given allocation
4640 // site, if any, that exist in this graph
4641 protected Set<HeapRegionNode> getAnyExisting( AllocSite as ) {
4643 Set<HeapRegionNode> out = new HashSet<HeapRegionNode>();
4645 Integer idSum = as.getSummary();
4646 if( id2hrn.containsKey( idSum ) ) {
4647 out.add( id2hrn.get( idSum ) );
4650 for( int i = 0; i < as.getAllocationDepth(); ++i ) {
4651 Integer idI = as.getIthOldest( i );
4652 if( id2hrn.containsKey( idI ) ) {
4653 out.add( id2hrn.get( idI ) );
4660 // return the set of reach tuples (NOT A REACH STATE! JUST A SET!)
4661 // from the given allocation site, if any, from regions for that
4662 // site that exist in this graph
4663 protected Set<ReachTuple> getAnyExisting( AllocSite as,
4664 boolean includeARITY_ZEROORMORE,
4665 boolean includeARITY_ONE ) {
4667 Set<ReachTuple> out = new HashSet<ReachTuple>();
4669 Integer idSum = as.getSummary();
4670 if( id2hrn.containsKey( idSum ) ) {
4672 HeapRegionNode hrn = id2hrn.get( idSum );
4673 assert !hrn.isOutOfContext();
4675 if( !includeARITY_ZEROORMORE ) {
4676 out.add( ReachTuple.factory( hrn.getID(),
4677 true, // multi-obj region
4678 ReachTuple.ARITY_ZEROORMORE,
4683 if( includeARITY_ONE ) {
4684 out.add( ReachTuple.factory( hrn.getID(),
4685 true, // multi-object region
4686 ReachTuple.ARITY_ONE,
4692 if( !includeARITY_ONE ) {
4693 // no need to do the single-object regions that
4694 // only have an ARITY ONE possible
4698 for( int i = 0; i < as.getAllocationDepth(); ++i ) {
4700 Integer idI = as.getIthOldest( i );
4701 if( id2hrn.containsKey( idI ) ) {
4703 HeapRegionNode hrn = id2hrn.get( idI );
4704 assert !hrn.isOutOfContext();
4706 out.add( ReachTuple.factory( hrn.getID(),
4707 false, // multi-object region
4708 ReachTuple.ARITY_ONE,
4718 // if an object allocated at the target site may be
4719 // reachable from both an object from root1 and an
4720 // object allocated at root2, return TRUE
4721 public boolean mayBothReachTarget( AllocSite asRoot1,
4723 AllocSite asTarget ) {
4725 // consider all heap regions of the target and look
4726 // for a reach state that indicates regions of root1
4727 // and root2 might be able to reach same object
4728 Set<HeapRegionNode> hrnSetTarget = getAnyExisting( asTarget );
4730 // get relevant reach tuples, include ARITY_ZEROORMORE and ARITY_ONE
4731 Set<ReachTuple> rtSet1 = getAnyExisting( asRoot1, true, true );
4732 Set<ReachTuple> rtSet2 = getAnyExisting( asRoot2, true, true );
4734 Iterator<HeapRegionNode> hrnItr = hrnSetTarget.iterator();
4735 while( hrnItr.hasNext() ) {
4736 HeapRegionNode hrn = hrnItr.next();
4738 Iterator<ReachTuple> rtItr1 = rtSet1.iterator();
4739 while( rtItr1.hasNext() ) {
4740 ReachTuple rt1 = rtItr1.next();
4742 Iterator<ReachTuple> rtItr2 = rtSet2.iterator();
4743 while( rtItr2.hasNext() ) {
4744 ReachTuple rt2 = rtItr2.next();
4746 if( !hrn.getAlpha().getStatesWithBoth( rt1, rt2 ).isEmpty() ) {
4756 // similar to the method above, return TRUE if ever
4757 // more than one object from the root allocation site
4758 // may reach an object from the target site
4759 public boolean mayManyReachTarget( AllocSite asRoot,
4760 AllocSite asTarget ) {
4762 // consider all heap regions of the target and look
4763 // for a reach state that multiple objects of root
4764 // might be able to reach the same object
4765 Set<HeapRegionNode> hrnSetTarget = getAnyExisting( asTarget );
4767 // get relevant reach tuples
4768 Set<ReachTuple> rtSetZOM = getAnyExisting( asRoot, true, false );
4769 Set<ReachTuple> rtSetONE = getAnyExisting( asRoot, false, true );
4771 Iterator<HeapRegionNode> hrnItr = hrnSetTarget.iterator();
4772 while( hrnItr.hasNext() ) {
4773 HeapRegionNode hrn = hrnItr.next();
4775 // if any ZERORMORE tuples are here, TRUE
4776 Iterator<ReachTuple> rtItr = rtSetZOM.iterator();
4777 while( rtItr.hasNext() ) {
4778 ReachTuple rtZOM = rtItr.next();
4780 if( hrn.getAlpha().containsTuple( rtZOM ) ) {
4785 // otherwise, look for any pair of ONE tuples
4786 Iterator<ReachTuple> rtItr1 = rtSetONE.iterator();
4787 while( rtItr1.hasNext() ) {
4788 ReachTuple rt1 = rtItr1.next();
4790 Iterator<ReachTuple> rtItr2 = rtSetONE.iterator();
4791 while( rtItr2.hasNext() ) {
4792 ReachTuple rt2 = rtItr2.next();
4798 if( !hrn.getAlpha().getStatesWithBoth( rt1, rt2 ).isEmpty() ) {
4812 public Set<HeapRegionNode> findCommonReachableNodes( ReachSet proofOfSharing ) {
4814 Set<HeapRegionNode> exhibitProofState =
4815 new HashSet<HeapRegionNode>();
4817 Iterator hrnItr = id2hrn.entrySet().iterator();
4818 while( hrnItr.hasNext() ) {
4819 Map.Entry me = (Map.Entry) hrnItr.next();
4820 HeapRegionNode hrn = (HeapRegionNode) me.getValue();
4822 ReachSet intersection =
4823 Canonical.intersection( proofOfSharing,
4826 if( !intersection.isEmpty() ) {
4827 assert !hrn.isOutOfContext();
4828 exhibitProofState.add( hrn );
4832 return exhibitProofState;
4836 public Set<HeapRegionNode> mayReachSharedObjects(HeapRegionNode hrn1,
4837 HeapRegionNode hrn2) {
4838 assert hrn1 != null;
4839 assert hrn2 != null;
4841 assert !hrn1.isOutOfContext();
4842 assert !hrn2.isOutOfContext();
4844 assert belongsToThis( hrn1 );
4845 assert belongsToThis( hrn2 );
4847 assert !hrn1.getID().equals( hrn2.getID() );
4850 // then get the various tokens for these heap regions
4852 ReachTuple.factory( hrn1.getID(),
4853 !hrn1.isSingleObject(), // multi?
4854 ReachTuple.ARITY_ONE,
4857 ReachTuple h1star = null;
4858 if( !hrn1.isSingleObject() ) {
4860 ReachTuple.factory( hrn1.getID(),
4861 !hrn1.isSingleObject(),
4862 ReachTuple.ARITY_ZEROORMORE,
4867 ReachTuple.factory( hrn2.getID(),
4868 !hrn2.isSingleObject(),
4869 ReachTuple.ARITY_ONE,
4872 ReachTuple h2star = null;
4873 if( !hrn2.isSingleObject() ) {
4875 ReachTuple.factory( hrn2.getID(),
4876 !hrn2.isSingleObject(),
4877 ReachTuple.ARITY_ZEROORMORE,
4881 // then get the merged beta of all out-going edges from these heap
4884 ReachSet beta1 = ReachSet.factory();
4885 Iterator<RefEdge> itrEdge = hrn1.iteratorToReferencees();
4886 while (itrEdge.hasNext()) {
4887 RefEdge edge = itrEdge.next();
4888 beta1 = Canonical.unionORpreds(beta1, edge.getBeta());
4891 ReachSet beta2 = ReachSet.factory();
4892 itrEdge = hrn2.iteratorToReferencees();
4893 while (itrEdge.hasNext()) {
4894 RefEdge edge = itrEdge.next();
4895 beta2 = Canonical.unionORpreds(beta2, edge.getBeta());
4898 ReachSet proofOfSharing = ReachSet.factory();
4901 Canonical.unionORpreds( proofOfSharing,
4902 beta1.getStatesWithBoth( h1, h2 )
4905 Canonical.unionORpreds( proofOfSharing,
4906 beta2.getStatesWithBoth( h1, h2 )
4909 if( !hrn1.isSingleObject() ) {
4911 Canonical.unionORpreds( proofOfSharing,
4912 beta1.getStatesWithBoth( h1star, h2 )
4915 Canonical.unionORpreds( proofOfSharing,
4916 beta2.getStatesWithBoth( h1star, h2 )
4920 if( !hrn2.isSingleObject() ) {
4922 Canonical.unionORpreds( proofOfSharing,
4923 beta1.getStatesWithBoth( h1, h2star )
4926 Canonical.unionORpreds( proofOfSharing,
4927 beta2.getStatesWithBoth( h1, h2star )
4931 if( !hrn1.isSingleObject() &&
4932 !hrn2.isSingleObject()
4935 Canonical.unionORpreds( proofOfSharing,
4936 beta1.getStatesWithBoth( h1star, h2star )
4939 Canonical.unionORpreds( proofOfSharing,
4940 beta2.getStatesWithBoth( h1star, h2star )
4944 Set<HeapRegionNode> common = new HashSet<HeapRegionNode>();
4945 if( !proofOfSharing.isEmpty() ) {
4946 common = findCommonReachableNodes( proofOfSharing );
4947 if( !DISABLE_STRONG_UPDATES &&
4948 !DISABLE_GLOBAL_SWEEP
4950 assert !common.isEmpty();
4957 // this version of the above method checks whether there is sharing
4958 // among the objects in a summary node
4959 public Set<HeapRegionNode> mayReachSharedObjects(HeapRegionNode hrn) {
4961 assert hrn.isNewSummary();
4962 assert !hrn.isOutOfContext();
4963 assert belongsToThis( hrn );
4966 ReachTuple.factory( hrn.getID(),
4968 ReachTuple.ARITY_ZEROORMORE,
4971 // then get the merged beta of all out-going edges from
4974 ReachSet beta = ReachSet.factory();
4975 Iterator<RefEdge> itrEdge = hrn.iteratorToReferencees();
4976 while (itrEdge.hasNext()) {
4977 RefEdge edge = itrEdge.next();
4978 beta = Canonical.unionORpreds(beta, edge.getBeta());
4981 ReachSet proofOfSharing = ReachSet.factory();
4984 Canonical.unionORpreds( proofOfSharing,
4985 beta.getStatesWithBoth( hstar, hstar )
4988 Set<HeapRegionNode> common = new HashSet<HeapRegionNode>();
4989 if( !proofOfSharing.isEmpty() ) {
4990 common = findCommonReachableNodes( proofOfSharing );
4991 if( !DISABLE_STRONG_UPDATES &&
4992 !DISABLE_GLOBAL_SWEEP
4994 assert !common.isEmpty();
5002 public Set<HeapRegionNode> mayReachSharedObjects(FlatMethod fm,
5003 Integer paramIndex1,
5004 Integer paramIndex2) {
5006 // get parameter's heap regions
5007 TempDescriptor paramTemp1 = fm.getParameter(paramIndex1.intValue());
5008 assert this.hasVariable( paramTemp1 );
5009 VariableNode paramVar1 = getVariableNodeFromTemp(paramTemp1);
5012 if( !(paramVar1.getNumReferencees() == 1) ) {
5013 System.out.println( "\n fm="+fm+"\n param="+paramTemp1 );
5014 writeGraph( "whatup" );
5018 assert paramVar1.getNumReferencees() == 1;
5019 RefEdge paramEdge1 = paramVar1.iteratorToReferencees().next();
5020 HeapRegionNode hrnParam1 = paramEdge1.getDst();
5022 TempDescriptor paramTemp2 = fm.getParameter(paramIndex2.intValue());
5023 assert this.hasVariable( paramTemp2 );
5024 VariableNode paramVar2 = getVariableNodeFromTemp(paramTemp2);
5026 if( !(paramVar2.getNumReferencees() == 1) ) {
5027 System.out.println( "\n fm="+fm+"\n param="+paramTemp2 );
5028 writeGraph( "whatup" );
5031 assert paramVar2.getNumReferencees() == 1;
5032 RefEdge paramEdge2 = paramVar2.iteratorToReferencees().next();
5033 HeapRegionNode hrnParam2 = paramEdge2.getDst();
5035 Set<HeapRegionNode> common = new HashSet<HeapRegionNode>();
5036 common.addAll(mayReachSharedObjects(hrnParam1, hrnParam2));
5041 public Set<HeapRegionNode> mayReachSharedObjects(FlatMethod fm,
5045 // get parameter's heap regions
5046 TempDescriptor paramTemp = fm.getParameter(paramIndex.intValue());
5047 assert this.hasVariable( paramTemp );
5048 VariableNode paramVar = getVariableNodeFromTemp(paramTemp);
5049 assert paramVar.getNumReferencees() == 1;
5050 RefEdge paramEdge = paramVar.iteratorToReferencees().next();
5051 HeapRegionNode hrnParam = paramEdge.getDst();
5054 HeapRegionNode hrnSummary=null;
5055 if(id2hrn.containsKey(as.getSummary())){
5056 // if summary node doesn't exist, ignore this case
5057 hrnSummary = id2hrn.get(as.getSummary());
5058 assert hrnSummary != null;
5061 Set<HeapRegionNode> common = new HashSet<HeapRegionNode>();
5062 if(hrnSummary!=null){
5063 common.addAll( mayReachSharedObjects(hrnParam, hrnSummary) );
5066 // check for other nodes
5067 for (int i = 0; i < as.getAllocationDepth(); ++i) {
5069 assert id2hrn.containsKey(as.getIthOldest(i));
5070 HeapRegionNode hrnIthOldest = id2hrn.get(as.getIthOldest(i));
5071 assert hrnIthOldest != null;
5073 common.addAll(mayReachSharedObjects(hrnParam, hrnIthOldest));
5080 public Set<HeapRegionNode> mayReachSharedObjects(AllocSite as1,
5083 // get summary node 1's alpha
5084 Integer idSum1 = as1.getSummary();
5085 HeapRegionNode hrnSum1=null;
5086 if(id2hrn.containsKey(idSum1)){
5087 hrnSum1 = id2hrn.get(idSum1);
5090 // get summary node 2's alpha
5091 Integer idSum2 = as2.getSummary();
5092 HeapRegionNode hrnSum2=null;
5093 if(id2hrn.containsKey(idSum2)){
5094 hrnSum2 = id2hrn.get(idSum2);
5097 Set<HeapRegionNode> common = new HashSet<HeapRegionNode>();
5098 if(hrnSum1!=null && hrnSum2!=null && hrnSum1!=hrnSum2){
5099 common.addAll(mayReachSharedObjects(hrnSum1, hrnSum2));
5103 // ask if objects from this summary share among each other
5104 common.addAll(mayReachSharedObjects(hrnSum1));
5107 // check sum2 against alloc1 nodes
5109 for (int i = 0; i < as1.getAllocationDepth(); ++i) {
5110 Integer idI1 = as1.getIthOldest(i);
5111 assert id2hrn.containsKey(idI1);
5112 HeapRegionNode hrnI1 = id2hrn.get(idI1);
5113 assert hrnI1 != null;
5114 common.addAll(mayReachSharedObjects(hrnI1, hrnSum2));
5117 // also ask if objects from this summary share among each other
5118 common.addAll(mayReachSharedObjects(hrnSum2));
5121 // check sum1 against alloc2 nodes
5122 for (int i = 0; i < as2.getAllocationDepth(); ++i) {
5123 Integer idI2 = as2.getIthOldest(i);
5124 assert id2hrn.containsKey(idI2);
5125 HeapRegionNode hrnI2 = id2hrn.get(idI2);
5126 assert hrnI2 != null;
5129 common.addAll(mayReachSharedObjects(hrnSum1, hrnI2));
5132 // while we're at it, do an inner loop for alloc2 vs alloc1 nodes
5133 for (int j = 0; j < as1.getAllocationDepth(); ++j) {
5134 Integer idI1 = as1.getIthOldest(j);
5136 // if these are the same site, don't look for the same token, no
5138 // different tokens of the same site could alias together though
5139 if (idI1.equals(idI2)) {
5143 HeapRegionNode hrnI1 = id2hrn.get(idI1);
5145 common.addAll(mayReachSharedObjects(hrnI1, hrnI2));
5152 public void makeInaccessible( Set<TempDescriptor> vars ) {
5153 inaccessibleVars.addAll( vars );
5156 public void makeInaccessible( TempDescriptor td ) {
5157 inaccessibleVars.add( td );
5160 public void makeAccessible( TempDescriptor td ) {
5161 inaccessibleVars.remove( td );
5164 public boolean isAccessible(TempDescriptor td) {
5165 return !inaccessibleVars.contains(td);
5168 public Set<TempDescriptor> getInaccessibleVars() {
5169 return inaccessibleVars;