1 package Analysis.Disjoint;
5 import Util.UtilAlgorithms;
9 public class ReachGraph {
11 // use to disable improvements for comparison
12 protected static final boolean DISABLE_STRONG_UPDATES = false;
13 protected static final boolean DISABLE_GLOBAL_SWEEP = false;
15 // a special out-of-scope temp
16 protected static final TempDescriptor tdReturn = new TempDescriptor( "_Return___" );
18 // predicate constants
19 public static final ExistPred predTrue = ExistPred.factory(); // if no args, true
20 public static final ExistPredSet predsEmpty = ExistPredSet.factory();
21 public static final ExistPredSet predsTrue = ExistPredSet.factory( predTrue );
23 // some frequently used reachability constants
24 protected static final ReachState rstateEmpty = ReachState.factory();
25 protected static final ReachSet rsetEmpty = ReachSet.factory();
26 protected static final ReachSet rsetWithEmptyState = Canonical.changePredsTo( ReachSet.factory( rstateEmpty ),
29 // from DisjointAnalysis for convenience
30 protected static int allocationDepth = -1;
31 protected static TypeUtil typeUtil = null;
34 // variable and heap region nodes indexed by unique ID
35 public Hashtable<Integer, HeapRegionNode> id2hrn;
36 public Hashtable<TempDescriptor, VariableNode > td2vn;
38 // convenient set of alloc sites for all heap regions
39 // present in the graph without having to search
40 public Set<AllocSite> allocSites;
42 // set of inaccessible variables for current program statement
43 // with respect to stall-site analysis
44 public Set<TempDescriptor> inaccessibleVars;
48 id2hrn = new Hashtable<Integer, HeapRegionNode>();
49 td2vn = new Hashtable<TempDescriptor, VariableNode >();
50 allocSites = new HashSet<AllocSite>();
51 inaccessibleVars = new HashSet<TempDescriptor>();
55 // temp descriptors are globally unique and map to
56 // exactly one variable node, easy
57 protected VariableNode getVariableNodeFromTemp( TempDescriptor td ) {
60 if( !td2vn.containsKey( td ) ) {
61 td2vn.put( td, new VariableNode( td ) );
64 return td2vn.get( td );
67 //This method is created for client modules to access the Reachgraph
68 //after the analysis is done and no modifications are to be made.
69 public VariableNode getVariableNodeNoMutation( TempDescriptor td ) {
72 if( !td2vn.containsKey( td ) ) {
76 return td2vn.get( td );
79 public boolean hasVariable( TempDescriptor td ) {
80 return td2vn.containsKey( td );
84 // this suite of methods can be used to assert a
85 // very important property of ReachGraph objects:
86 // some element, HeapRegionNode, RefEdge etc.
87 // should be referenced by at most ONE ReachGraph!!
88 // If a heap region or edge or variable should be
89 // in another graph, make a new object with
90 // equivalent properties for a new graph
91 public boolean belongsToThis( RefSrcNode rsn ) {
92 if( rsn instanceof VariableNode ) {
93 VariableNode vn = (VariableNode) rsn;
94 return this.td2vn.get( vn.getTempDescriptor() ) == vn;
96 HeapRegionNode hrn = (HeapRegionNode) rsn;
97 return this.id2hrn.get( hrn.getID() ) == hrn;
104 // the reason for this method is to have the option
105 // of creating new heap regions with specific IDs, or
106 // duplicating heap regions with specific IDs (especially
107 // in the merge() operation) or to create new heap
108 // regions with a new unique ID
109 protected HeapRegionNode
110 createNewHeapRegionNode( Integer id,
111 boolean isSingleObject,
112 boolean isNewSummary,
113 boolean isOutOfContext,
122 TypeDescriptor typeToUse = null;
123 if( allocSite != null ) {
124 typeToUse = allocSite.getType();
125 allocSites.add( allocSite );
130 boolean markForAnalysis = false;
131 if( allocSite != null && allocSite.isFlagged() ) {
132 markForAnalysis = true;
135 if( allocSite == null ) {
136 assert !markForAnalysis;
138 } else if( markForAnalysis != allocSite.isFlagged() ) {
144 id = DisjointAnalysis.generateUniqueHeapRegionNodeID();
147 if( inherent == null ) {
148 if( markForAnalysis ) {
150 Canonical.changePredsTo(
153 ReachTuple.factory( id,
155 ReachTuple.ARITY_ONE,
156 false // out-of-context
163 inherent = rsetWithEmptyState;
167 if( alpha == null ) {
171 assert preds != null;
173 HeapRegionNode hrn = new HeapRegionNode( id,
184 id2hrn.put( id, hrn );
190 ////////////////////////////////////////////////
192 // Low-level referencee and referencer methods
194 // These methods provide the lowest level for
195 // creating references between reachability nodes
196 // and handling the details of maintaining both
197 // list of referencers and referencees.
199 ////////////////////////////////////////////////
200 protected void addRefEdge( RefSrcNode referencer,
201 HeapRegionNode referencee,
203 assert referencer != null;
204 assert referencee != null;
206 assert edge.getSrc() == referencer;
207 assert edge.getDst() == referencee;
208 assert belongsToThis( referencer );
209 assert belongsToThis( referencee );
211 // edges are getting added twice to graphs now, the
212 // kind that should have abstract facts merged--use
213 // this check to prevent that
214 assert referencer.getReferenceTo( referencee,
219 referencer.addReferencee( edge );
220 referencee.addReferencer( edge );
223 protected void removeRefEdge( RefEdge e ) {
224 removeRefEdge( e.getSrc(),
230 protected void removeRefEdge( RefSrcNode referencer,
231 HeapRegionNode referencee,
234 assert referencer != null;
235 assert referencee != null;
237 RefEdge edge = referencer.getReferenceTo( referencee,
241 assert edge == referencee.getReferenceFrom( referencer,
245 referencer.removeReferencee( edge );
246 referencee.removeReferencer( edge );
249 // return whether at least one edge was removed
250 protected boolean clearRefEdgesFrom( RefSrcNode referencer,
253 boolean removeAll ) {
254 assert referencer != null;
256 boolean atLeastOneEdgeRemoved = false;
258 // get a copy of the set to iterate over, otherwise
259 // we will be trying to take apart the set as we
260 // are iterating over it, which won't work
261 Iterator<RefEdge> i = referencer.iteratorToReferenceesClone();
262 while( i.hasNext() ) {
263 RefEdge edge = i.next();
266 (edge.typeEquals( type ) && edge.fieldEquals( field ))
269 HeapRegionNode referencee = edge.getDst();
271 removeRefEdge( referencer,
276 atLeastOneEdgeRemoved = true;
280 return atLeastOneEdgeRemoved;
283 protected void clearRefEdgesTo( HeapRegionNode referencee,
286 boolean removeAll ) {
287 assert referencee != null;
289 // get a copy of the set to iterate over, otherwise
290 // we will be trying to take apart the set as we
291 // are iterating over it, which won't work
292 Iterator<RefEdge> i = referencee.iteratorToReferencersClone();
293 while( i.hasNext() ) {
294 RefEdge edge = i.next();
297 (edge.typeEquals( type ) && edge.fieldEquals( field ))
300 RefSrcNode referencer = edge.getSrc();
302 removeRefEdge( referencer,
310 protected void clearNonVarRefEdgesTo( HeapRegionNode referencee ) {
311 assert referencee != null;
313 // get a copy of the set to iterate over, otherwise
314 // we will be trying to take apart the set as we
315 // are iterating over it, which won't work
316 Iterator<RefEdge> i = referencee.iteratorToReferencersClone();
317 while( i.hasNext() ) {
318 RefEdge edge = i.next();
319 RefSrcNode referencer = edge.getSrc();
320 if( !(referencer instanceof VariableNode) ) {
321 removeRefEdge( referencer,
329 // this is a common operation in many transfer functions: we want
330 // to add an edge, but if there is already such an edge we should
331 // merge the properties of the existing and the new edges
332 protected void addEdgeOrMergeWithExisting( RefEdge edgeNew ) {
334 RefSrcNode src = edgeNew.getSrc();
335 assert belongsToThis( src );
337 HeapRegionNode dst = edgeNew.getDst();
338 assert belongsToThis( dst );
340 // look to see if an edge with same field exists
341 // and merge with it, otherwise just add the edge
342 RefEdge edgeExisting = src.getReferenceTo( dst,
347 if( edgeExisting != null ) {
348 edgeExisting.setBeta(
349 Canonical.unionORpreds( edgeExisting.getBeta(),
353 edgeExisting.setPreds(
354 Canonical.join( edgeExisting.getPreds(),
358 edgeExisting.setTaints(
359 Canonical.unionORpreds( edgeExisting.getTaints(),
365 addRefEdge( src, dst, edgeNew );
371 ////////////////////////////////////////////////////
373 // Assignment Operation Methods
375 // These methods are high-level operations for
376 // modeling program assignment statements using
377 // the low-level reference create/remove methods
380 ////////////////////////////////////////////////////
382 public void assignTempXEqualToTempY( TempDescriptor x,
384 assignTempXEqualToCastedTempY( x, y, null );
388 public void assignTempXEqualToCastedTempY( TempDescriptor x,
390 TypeDescriptor tdCast ) {
392 VariableNode lnX = getVariableNodeFromTemp( x );
393 VariableNode lnY = getVariableNodeFromTemp( y );
395 clearRefEdgesFrom( lnX, null, null, true );
397 // note it is possible that the types of temps in the
398 // flat node to analyze will reveal that some typed
399 // edges in the reachability graph are impossible
400 Set<RefEdge> impossibleEdges = new HashSet<RefEdge>();
402 Iterator<RefEdge> itrYhrn = lnY.iteratorToReferencees();
403 while( itrYhrn.hasNext() ) {
404 RefEdge edgeY = itrYhrn.next();
405 HeapRegionNode referencee = edgeY.getDst();
406 RefEdge edgeNew = edgeY.copy();
408 if( !isSuperiorType( x.getType(), edgeY.getType() ) ) {
409 impossibleEdges.add( edgeY );
413 edgeNew.setSrc( lnX );
415 if( tdCast == null ) {
416 edgeNew.setType( mostSpecificType( y.getType(),
422 edgeNew.setType( mostSpecificType( y.getType(),
424 referencee.getType(),
430 edgeNew.setField( null );
432 addRefEdge( lnX, referencee, edgeNew );
435 Iterator<RefEdge> itrImp = impossibleEdges.iterator();
436 while( itrImp.hasNext() ) {
437 RefEdge edgeImp = itrImp.next();
438 removeRefEdge( edgeImp );
443 public void assignTempXEqualToTempYFieldF( TempDescriptor x,
445 FieldDescriptor f ) {
446 VariableNode lnX = getVariableNodeFromTemp( x );
447 VariableNode lnY = getVariableNodeFromTemp( y );
449 clearRefEdgesFrom( lnX, null, null, true );
451 // note it is possible that the types of temps in the
452 // flat node to analyze will reveal that some typed
453 // edges in the reachability graph are impossible
454 Set<RefEdge> impossibleEdges = new HashSet<RefEdge>();
456 Iterator<RefEdge> itrYhrn = lnY.iteratorToReferencees();
457 while( itrYhrn.hasNext() ) {
458 RefEdge edgeY = itrYhrn.next();
459 HeapRegionNode hrnY = edgeY.getDst();
460 ReachSet betaY = edgeY.getBeta();
462 Iterator<RefEdge> itrHrnFhrn = hrnY.iteratorToReferencees();
464 while( itrHrnFhrn.hasNext() ) {
465 RefEdge edgeHrn = itrHrnFhrn.next();
466 HeapRegionNode hrnHrn = edgeHrn.getDst();
467 ReachSet betaHrn = edgeHrn.getBeta();
469 // prune edges that are not a matching field
470 if( edgeHrn.getType() != null &&
471 !edgeHrn.getField().equals( f.getSymbol() )
476 // check for impossible edges
477 if( !isSuperiorType( x.getType(), edgeHrn.getType() ) ) {
478 impossibleEdges.add( edgeHrn );
482 TypeDescriptor tdNewEdge =
483 mostSpecificType( edgeHrn.getType(),
487 RefEdge edgeNew = new RefEdge( lnX,
491 Canonical.intersection( betaY, betaHrn ),
496 addEdgeOrMergeWithExisting( edgeNew );
500 Iterator<RefEdge> itrImp = impossibleEdges.iterator();
501 while( itrImp.hasNext() ) {
502 RefEdge edgeImp = itrImp.next();
503 removeRefEdge( edgeImp );
506 // anytime you might remove edges between heap regions
507 // you must global sweep to clean up broken reachability
508 if( !impossibleEdges.isEmpty() ) {
509 if( !DISABLE_GLOBAL_SWEEP ) {
517 // return whether a strong update was actually effected
518 public boolean assignTempXFieldFEqualToTempY( TempDescriptor x,
522 VariableNode lnX = getVariableNodeFromTemp( x );
523 VariableNode lnY = getVariableNodeFromTemp( y );
525 HashSet<HeapRegionNode> nodesWithNewAlpha = new HashSet<HeapRegionNode>();
526 HashSet<RefEdge> edgesWithNewBeta = new HashSet<RefEdge>();
528 // note it is possible that the types of temps in the
529 // flat node to analyze will reveal that some typed
530 // edges in the reachability graph are impossible
531 Set<RefEdge> impossibleEdges = new HashSet<RefEdge>();
533 // first look for possible strong updates and remove those edges
534 boolean strongUpdateCond = false;
535 boolean edgeRemovedByStrongUpdate = false;
537 Iterator<RefEdge> itrXhrn = lnX.iteratorToReferencees();
538 while( itrXhrn.hasNext() ) {
539 RefEdge edgeX = itrXhrn.next();
540 HeapRegionNode hrnX = edgeX.getDst();
542 // we can do a strong update here if one of two cases holds
544 f != DisjointAnalysis.getArrayField( f.getType() ) &&
545 ( (hrnX.getNumReferencers() == 1) || // case 1
546 (hrnX.isSingleObject() && lnX.getNumReferencees() == 1) // case 2
549 if( !DISABLE_STRONG_UPDATES ) {
550 strongUpdateCond = true;
553 clearRefEdgesFrom( hrnX,
558 edgeRemovedByStrongUpdate = true;
564 // then do all token propagation
565 itrXhrn = lnX.iteratorToReferencees();
566 while( itrXhrn.hasNext() ) {
567 RefEdge edgeX = itrXhrn.next();
568 HeapRegionNode hrnX = edgeX.getDst();
569 ReachSet betaX = edgeX.getBeta();
570 ReachSet R = Canonical.intersection( hrnX.getAlpha(),
574 Iterator<RefEdge> itrYhrn = lnY.iteratorToReferencees();
575 while( itrYhrn.hasNext() ) {
576 RefEdge edgeY = itrYhrn.next();
577 HeapRegionNode hrnY = edgeY.getDst();
578 ReachSet O = edgeY.getBeta();
580 // check for impossible edges
581 if( !isSuperiorType( f.getType(), edgeY.getType() ) ) {
582 impossibleEdges.add( edgeY );
586 // propagate tokens over nodes starting from hrnSrc, and it will
587 // take care of propagating back up edges from any touched nodes
588 ChangeSet Cy = Canonical.unionUpArityToChangeSet( O, R );
589 propagateTokensOverNodes( hrnY, Cy, nodesWithNewAlpha, edgesWithNewBeta );
591 // then propagate back just up the edges from hrn
592 ChangeSet Cx = Canonical.unionUpArityToChangeSet( R, O );
593 HashSet<RefEdge> todoEdges = new HashSet<RefEdge>();
595 Hashtable<RefEdge, ChangeSet> edgePlannedChanges =
596 new Hashtable<RefEdge, ChangeSet>();
598 Iterator<RefEdge> referItr = hrnX.iteratorToReferencers();
599 while( referItr.hasNext() ) {
600 RefEdge edgeUpstream = referItr.next();
601 todoEdges.add( edgeUpstream );
602 edgePlannedChanges.put( edgeUpstream, Cx );
605 propagateTokensOverEdges( todoEdges,
612 // apply the updates to reachability
613 Iterator<HeapRegionNode> nodeItr = nodesWithNewAlpha.iterator();
614 while( nodeItr.hasNext() ) {
615 nodeItr.next().applyAlphaNew();
618 Iterator<RefEdge> edgeItr = edgesWithNewBeta.iterator();
619 while( edgeItr.hasNext() ) {
620 edgeItr.next().applyBetaNew();
624 // then go back through and add the new edges
625 itrXhrn = lnX.iteratorToReferencees();
626 while( itrXhrn.hasNext() ) {
627 RefEdge edgeX = itrXhrn.next();
628 HeapRegionNode hrnX = edgeX.getDst();
630 Iterator<RefEdge> itrYhrn = lnY.iteratorToReferencees();
631 while( itrYhrn.hasNext() ) {
632 RefEdge edgeY = itrYhrn.next();
633 HeapRegionNode hrnY = edgeY.getDst();
635 // skip impossible edges here, we already marked them
636 // when computing reachability propagations above
637 if( !isSuperiorType( f.getType(), edgeY.getType() ) ) {
641 // prepare the new reference edge hrnX.f -> hrnY
642 TypeDescriptor tdNewEdge =
643 mostSpecificType( y.getType(),
653 Canonical.changePredsTo(
654 Canonical.pruneBy( edgeY.getBeta(),
663 addEdgeOrMergeWithExisting( edgeNew );
667 Iterator<RefEdge> itrImp = impossibleEdges.iterator();
668 while( itrImp.hasNext() ) {
669 RefEdge edgeImp = itrImp.next();
670 removeRefEdge( edgeImp );
673 // if there was a strong update, make sure to improve
674 // reachability with a global sweep
675 if( edgeRemovedByStrongUpdate || !impossibleEdges.isEmpty() ) {
676 if( !DISABLE_GLOBAL_SWEEP ) {
681 return edgeRemovedByStrongUpdate;
685 public void assignReturnEqualToTemp( TempDescriptor x ) {
687 VariableNode lnR = getVariableNodeFromTemp( tdReturn );
688 VariableNode lnX = getVariableNodeFromTemp( x );
690 clearRefEdgesFrom( lnR, null, null, true );
692 Iterator<RefEdge> itrXhrn = lnX.iteratorToReferencees();
693 while( itrXhrn.hasNext() ) {
694 RefEdge edgeX = itrXhrn.next();
695 HeapRegionNode referencee = edgeX.getDst();
696 RefEdge edgeNew = edgeX.copy();
697 edgeNew.setSrc( lnR );
698 edgeNew.setTaints( Canonical.changePredsTo( edgeNew.getTaints(),
703 addRefEdge( lnR, referencee, edgeNew );
708 public void assignTempEqualToNewAlloc( TempDescriptor x,
715 // after the age operation the newest (or zero-ith oldest)
716 // node associated with the allocation site should have
717 // no references to it as if it were a newly allocated
719 Integer idNewest = as.getIthOldest( 0 );
720 HeapRegionNode hrnNewest = id2hrn.get( idNewest );
721 assert hrnNewest != null;
723 VariableNode lnX = getVariableNodeFromTemp( x );
724 clearRefEdgesFrom( lnX, null, null, true );
726 // make a new reference to allocated node
727 TypeDescriptor type = as.getType();
730 new RefEdge( lnX, // source
734 hrnNewest.getAlpha(), // beta
735 predsTrue, // predicates
736 TaintSet.factory() // taints
739 addRefEdge( lnX, hrnNewest, edgeNew );
743 // use the allocation site (unique to entire analysis) to
744 // locate the heap region nodes in this reachability graph
745 // that should be aged. The process models the allocation
746 // of new objects and collects all the oldest allocations
747 // in a summary node to allow for a finite analysis
749 // There is an additional property of this method. After
750 // running it on a particular reachability graph (many graphs
751 // may have heap regions related to the same allocation site)
752 // the heap region node objects in this reachability graph will be
753 // allocated. Therefore, after aging a graph for an allocation
754 // site, attempts to retrieve the heap region nodes using the
755 // integer id's contained in the allocation site should always
756 // return non-null heap regions.
757 public void age( AllocSite as ) {
759 // keep track of allocation sites that are represented
760 // in this graph for efficiency with other operations
761 allocSites.add( as );
763 // if there is a k-th oldest node, it merges into
765 Integer idK = as.getOldest();
766 if( id2hrn.containsKey( idK ) ) {
767 HeapRegionNode hrnK = id2hrn.get( idK );
769 // retrieve the summary node, or make it
771 HeapRegionNode hrnSummary = getSummaryNode( as, false );
773 mergeIntoSummary( hrnK, hrnSummary );
776 // move down the line of heap region nodes
777 // clobbering the ith and transferring all references
778 // to and from i-1 to node i.
779 for( int i = allocationDepth - 1; i > 0; --i ) {
781 // only do the transfer if the i-1 node exists
782 Integer idImin1th = as.getIthOldest( i - 1 );
783 if( id2hrn.containsKey( idImin1th ) ) {
784 HeapRegionNode hrnImin1 = id2hrn.get( idImin1th );
785 if( hrnImin1.isWiped() ) {
786 // there is no info on this node, just skip
790 // either retrieve or make target of transfer
791 HeapRegionNode hrnI = getIthNode( as, i, false );
793 transferOnto( hrnImin1, hrnI );
798 // as stated above, the newest node should have had its
799 // references moved over to the second oldest, so we wipe newest
800 // in preparation for being the new object to assign something to
801 HeapRegionNode hrn0 = getIthNode( as, 0, false );
802 wipeOut( hrn0, true );
804 // now tokens in reachability sets need to "age" also
805 Iterator itrAllVariableNodes = td2vn.entrySet().iterator();
806 while( itrAllVariableNodes.hasNext() ) {
807 Map.Entry me = (Map.Entry) itrAllVariableNodes.next();
808 VariableNode ln = (VariableNode) me.getValue();
810 Iterator<RefEdge> itrEdges = ln.iteratorToReferencees();
811 while( itrEdges.hasNext() ) {
812 ageTuplesFrom( as, itrEdges.next() );
816 Iterator itrAllHRNodes = id2hrn.entrySet().iterator();
817 while( itrAllHRNodes.hasNext() ) {
818 Map.Entry me = (Map.Entry) itrAllHRNodes.next();
819 HeapRegionNode hrnToAge = (HeapRegionNode) me.getValue();
821 ageTuplesFrom( as, hrnToAge );
823 Iterator<RefEdge> itrEdges = hrnToAge.iteratorToReferencees();
824 while( itrEdges.hasNext() ) {
825 ageTuplesFrom( as, itrEdges.next() );
830 // after tokens have been aged, reset newest node's reachability
831 // and a brand new node has a "true" predicate
832 hrn0.setAlpha( hrn0.getInherent() );
833 hrn0.setPreds( predsTrue );
837 // either retrieve or create the needed heap region node
838 protected HeapRegionNode getSummaryNode( AllocSite as,
843 idSummary = as.getSummaryShadow();
845 idSummary = as.getSummary();
848 HeapRegionNode hrnSummary = id2hrn.get( idSummary );
850 if( hrnSummary == null ) {
852 String strDesc = as.toStringForDOT()+"\\nsummary";
855 createNewHeapRegionNode( idSummary, // id or null to generate a new one
856 false, // single object?
858 false, // out-of-context?
859 as.getType(), // type
860 as, // allocation site
861 null, // inherent reach
862 null, // current reach
863 predsEmpty, // predicates
864 strDesc // description
871 // either retrieve or create the needed heap region node
872 protected HeapRegionNode getIthNode( AllocSite as,
878 idIth = as.getIthOldestShadow( i );
880 idIth = as.getIthOldest( i );
883 HeapRegionNode hrnIth = id2hrn.get( idIth );
885 if( hrnIth == null ) {
887 String strDesc = as.toStringForDOT()+"\\n"+i+" oldest";
889 hrnIth = createNewHeapRegionNode( idIth, // id or null to generate a new one
890 true, // single object?
892 false, // out-of-context?
893 as.getType(), // type
894 as, // allocation site
895 null, // inherent reach
896 null, // current reach
897 predsEmpty, // predicates
898 strDesc // description
906 protected void mergeIntoSummary( HeapRegionNode hrn,
907 HeapRegionNode hrnSummary ) {
908 assert hrnSummary.isNewSummary();
910 // assert that these nodes belong to THIS graph
911 assert belongsToThis( hrn );
912 assert belongsToThis( hrnSummary );
914 assert hrn != hrnSummary;
916 // transfer references _from_ hrn over to hrnSummary
917 Iterator<RefEdge> itrReferencee = hrn.iteratorToReferencees();
918 while( itrReferencee.hasNext() ) {
919 RefEdge edge = itrReferencee.next();
920 RefEdge edgeMerged = edge.copy();
921 edgeMerged.setSrc( hrnSummary );
923 HeapRegionNode hrnReferencee = edge.getDst();
924 RefEdge edgeSummary =
925 hrnSummary.getReferenceTo( hrnReferencee,
930 if( edgeSummary == null ) {
931 // the merge is trivial, nothing to be done
932 addRefEdge( hrnSummary, hrnReferencee, edgeMerged );
935 // otherwise an edge from the referencer to hrnSummary exists already
936 // and the edge referencer->hrn should be merged with it
938 Canonical.unionORpreds( edgeMerged.getBeta(),
939 edgeSummary.getBeta()
942 edgeSummary.setPreds(
943 Canonical.join( edgeMerged.getPreds(),
944 edgeSummary.getPreds()
950 // next transfer references _to_ hrn over to hrnSummary
951 Iterator<RefEdge> itrReferencer = hrn.iteratorToReferencers();
952 while( itrReferencer.hasNext() ) {
953 RefEdge edge = itrReferencer.next();
954 RefEdge edgeMerged = edge.copy();
955 edgeMerged.setDst( hrnSummary );
957 RefSrcNode onReferencer = edge.getSrc();
958 RefEdge edgeSummary =
959 onReferencer.getReferenceTo( hrnSummary,
964 if( edgeSummary == null ) {
965 // the merge is trivial, nothing to be done
966 addRefEdge( onReferencer, hrnSummary, edgeMerged );
969 // otherwise an edge from the referencer to alpha_S exists already
970 // and the edge referencer->alpha_K should be merged with it
972 Canonical.unionORpreds( edgeMerged.getBeta(),
973 edgeSummary.getBeta()
976 edgeSummary.setPreds(
977 Canonical.join( edgeMerged.getPreds(),
978 edgeSummary.getPreds()
984 // then merge hrn reachability into hrnSummary
986 Canonical.unionORpreds( hrnSummary.getAlpha(),
992 Canonical.join( hrnSummary.getPreds(),
997 // and afterward, this node is gone
998 wipeOut( hrn, true );
1002 protected void transferOnto( HeapRegionNode hrnA,
1003 HeapRegionNode hrnB ) {
1005 assert belongsToThis( hrnA );
1006 assert belongsToThis( hrnB );
1007 assert hrnA != hrnB;
1009 // clear references in and out of node b?
1010 assert hrnB.isWiped();
1012 // copy each: (edge in and out of A) to B
1013 Iterator<RefEdge> itrReferencee = hrnA.iteratorToReferencees();
1014 while( itrReferencee.hasNext() ) {
1015 RefEdge edge = itrReferencee.next();
1016 HeapRegionNode hrnReferencee = edge.getDst();
1017 RefEdge edgeNew = edge.copy();
1018 edgeNew.setSrc( hrnB );
1019 edgeNew.setDst( hrnReferencee );
1021 addRefEdge( hrnB, hrnReferencee, edgeNew );
1024 Iterator<RefEdge> itrReferencer = hrnA.iteratorToReferencers();
1025 while( itrReferencer.hasNext() ) {
1026 RefEdge edge = itrReferencer.next();
1027 RefSrcNode rsnReferencer = edge.getSrc();
1028 RefEdge edgeNew = edge.copy();
1029 edgeNew.setSrc( rsnReferencer );
1030 edgeNew.setDst( hrnB );
1032 addRefEdge( rsnReferencer, hrnB, edgeNew );
1035 // replace hrnB reachability and preds with hrnA's
1036 hrnB.setAlpha( hrnA.getAlpha() );
1037 hrnB.setPreds( hrnA.getPreds() );
1039 // after transfer, wipe out source
1040 wipeOut( hrnA, true );
1044 // the purpose of this method is to conceptually "wipe out"
1045 // a heap region from the graph--purposefully not called REMOVE
1046 // because the node is still hanging around in the graph, just
1047 // not mechanically connected or have any reach or predicate
1048 // information on it anymore--lots of ops can use this
1049 protected void wipeOut( HeapRegionNode hrn,
1050 boolean wipeVariableReferences ) {
1052 assert belongsToThis( hrn );
1054 clearRefEdgesFrom( hrn, null, null, true );
1056 if( wipeVariableReferences ) {
1057 clearRefEdgesTo( hrn, null, null, true );
1059 clearNonVarRefEdgesTo( hrn );
1062 hrn.setAlpha( rsetEmpty );
1063 hrn.setPreds( predsEmpty );
1067 protected void ageTuplesFrom( AllocSite as, RefEdge edge ) {
1069 Canonical.ageTuplesFrom( edge.getBeta(),
1075 protected void ageTuplesFrom( AllocSite as, HeapRegionNode hrn ) {
1077 Canonical.ageTuplesFrom( hrn.getAlpha(),
1085 protected void propagateTokensOverNodes( HeapRegionNode nPrime,
1087 HashSet<HeapRegionNode> nodesWithNewAlpha,
1088 HashSet<RefEdge> edgesWithNewBeta ) {
1090 HashSet<HeapRegionNode> todoNodes
1091 = new HashSet<HeapRegionNode>();
1092 todoNodes.add( nPrime );
1094 HashSet<RefEdge> todoEdges
1095 = new HashSet<RefEdge>();
1097 Hashtable<HeapRegionNode, ChangeSet> nodePlannedChanges
1098 = new Hashtable<HeapRegionNode, ChangeSet>();
1099 nodePlannedChanges.put( nPrime, c0 );
1101 Hashtable<RefEdge, ChangeSet> edgePlannedChanges
1102 = new Hashtable<RefEdge, ChangeSet>();
1104 // first propagate change sets everywhere they can go
1105 while( !todoNodes.isEmpty() ) {
1106 HeapRegionNode n = todoNodes.iterator().next();
1107 ChangeSet C = nodePlannedChanges.get( n );
1109 Iterator<RefEdge> referItr = n.iteratorToReferencers();
1110 while( referItr.hasNext() ) {
1111 RefEdge edge = referItr.next();
1112 todoEdges.add( edge );
1114 if( !edgePlannedChanges.containsKey( edge ) ) {
1115 edgePlannedChanges.put( edge,
1120 edgePlannedChanges.put( edge,
1121 Canonical.union( edgePlannedChanges.get( edge ),
1127 Iterator<RefEdge> refeeItr = n.iteratorToReferencees();
1128 while( refeeItr.hasNext() ) {
1129 RefEdge edgeF = refeeItr.next();
1130 HeapRegionNode m = edgeF.getDst();
1132 ChangeSet changesToPass = ChangeSet.factory();
1134 Iterator<ChangeTuple> itrCprime = C.iterator();
1135 while( itrCprime.hasNext() ) {
1136 ChangeTuple c = itrCprime.next();
1137 if( edgeF.getBeta().containsIgnorePreds( c.getStateToMatch() )
1140 changesToPass = Canonical.add( changesToPass, c );
1144 if( !changesToPass.isEmpty() ) {
1145 if( !nodePlannedChanges.containsKey( m ) ) {
1146 nodePlannedChanges.put( m, ChangeSet.factory() );
1149 ChangeSet currentChanges = nodePlannedChanges.get( m );
1151 if( !changesToPass.isSubset( currentChanges ) ) {
1153 nodePlannedChanges.put( m,
1154 Canonical.union( currentChanges,
1163 todoNodes.remove( n );
1166 // then apply all of the changes for each node at once
1167 Iterator itrMap = nodePlannedChanges.entrySet().iterator();
1168 while( itrMap.hasNext() ) {
1169 Map.Entry me = (Map.Entry) itrMap.next();
1170 HeapRegionNode n = (HeapRegionNode) me.getKey();
1171 ChangeSet C = (ChangeSet) me.getValue();
1173 // this propagation step is with respect to one change,
1174 // so we capture the full change from the old alpha:
1175 ReachSet localDelta = Canonical.applyChangeSet( n.getAlpha(),
1179 // but this propagation may be only one of many concurrent
1180 // possible changes, so keep a running union with the node's
1181 // partially updated new alpha set
1182 n.setAlphaNew( Canonical.unionORpreds( n.getAlphaNew(),
1187 nodesWithNewAlpha.add( n );
1190 propagateTokensOverEdges( todoEdges,
1197 protected void propagateTokensOverEdges( HashSet <RefEdge> todoEdges,
1198 Hashtable<RefEdge, ChangeSet> edgePlannedChanges,
1199 HashSet <RefEdge> edgesWithNewBeta ) {
1201 // first propagate all change tuples everywhere they can go
1202 while( !todoEdges.isEmpty() ) {
1203 RefEdge edgeE = todoEdges.iterator().next();
1204 todoEdges.remove( edgeE );
1206 if( !edgePlannedChanges.containsKey( edgeE ) ) {
1207 edgePlannedChanges.put( edgeE,
1212 ChangeSet C = edgePlannedChanges.get( edgeE );
1214 ChangeSet changesToPass = ChangeSet.factory();
1216 Iterator<ChangeTuple> itrC = C.iterator();
1217 while( itrC.hasNext() ) {
1218 ChangeTuple c = itrC.next();
1219 if( edgeE.getBeta().containsIgnorePreds( c.getStateToMatch() )
1222 changesToPass = Canonical.add( changesToPass, c );
1226 RefSrcNode rsn = edgeE.getSrc();
1228 if( !changesToPass.isEmpty() && rsn instanceof HeapRegionNode ) {
1229 HeapRegionNode n = (HeapRegionNode) rsn;
1231 Iterator<RefEdge> referItr = n.iteratorToReferencers();
1232 while( referItr.hasNext() ) {
1233 RefEdge edgeF = referItr.next();
1235 if( !edgePlannedChanges.containsKey( edgeF ) ) {
1236 edgePlannedChanges.put( edgeF,
1241 ChangeSet currentChanges = edgePlannedChanges.get( edgeF );
1243 if( !changesToPass.isSubset( currentChanges ) ) {
1244 todoEdges.add( edgeF );
1245 edgePlannedChanges.put( edgeF,
1246 Canonical.union( currentChanges,
1255 // then apply all of the changes for each edge at once
1256 Iterator itrMap = edgePlannedChanges.entrySet().iterator();
1257 while( itrMap.hasNext() ) {
1258 Map.Entry me = (Map.Entry) itrMap.next();
1259 RefEdge e = (RefEdge) me.getKey();
1260 ChangeSet C = (ChangeSet) me.getValue();
1262 // this propagation step is with respect to one change,
1263 // so we capture the full change from the old beta:
1264 ReachSet localDelta =
1265 Canonical.applyChangeSet( e.getBeta(),
1270 // but this propagation may be only one of many concurrent
1271 // possible changes, so keep a running union with the edge's
1272 // partially updated new beta set
1273 e.setBetaNew( Canonical.unionORpreds( e.getBetaNew(),
1278 edgesWithNewBeta.add( e );
1283 public void taintInSetVars( FlatSESEEnterNode sese ) {
1284 if( sese.getIsCallerSESEplaceholder() ) {
1288 Iterator<TempDescriptor> isvItr = sese.getInVarSet().iterator();
1289 while( isvItr.hasNext() ) {
1290 TempDescriptor isv = isvItr.next();
1292 // in-set var taints should NOT propagate back into callers
1293 // so give it FALSE(EMPTY) predicates
1300 System.out.println("taint "+isv+" for "+sese);
1301 writeGraph("taint");
1305 public void taintStallSite( FlatNode stallSite,
1306 TempDescriptor var ) {
1308 // stall site taint should propagate back into callers
1309 // so give it TRUE predicates
1317 protected void taintTemp( FlatSESEEnterNode sese,
1323 VariableNode vn = getVariableNodeFromTemp( var );
1325 Iterator<RefEdge> reItr = vn.iteratorToReferencees();
1326 while( reItr.hasNext() ) {
1327 RefEdge re = reItr.next();
1329 Taint taint = Taint.factory( sese,
1332 re.getDst().getAllocSite(),
1336 re.setTaints( Canonical.add( re.getTaints(),
1343 public void removeInContextTaints( FlatSESEEnterNode sese ) {
1344 if( sese.getIsCallerSESEplaceholder() ) {
1348 Iterator meItr = id2hrn.entrySet().iterator();
1349 while( meItr.hasNext() ) {
1350 Map.Entry me = (Map.Entry) meItr.next();
1351 Integer id = (Integer) me.getKey();
1352 HeapRegionNode hrn = (HeapRegionNode) me.getValue();
1354 Iterator<RefEdge> reItr = hrn.iteratorToReferencers();
1355 while( reItr.hasNext() ) {
1356 RefEdge re = reItr.next();
1358 re.setTaints( Canonical.removeInContextTaints( re.getTaints(),
1366 public void removeAllStallSiteTaints() {
1368 Iterator meItr = id2hrn.entrySet().iterator();
1369 while( meItr.hasNext() ) {
1370 Map.Entry me = (Map.Entry) meItr.next();
1371 Integer id = (Integer) me.getKey();
1372 HeapRegionNode hrn = (HeapRegionNode) me.getValue();
1374 Iterator<RefEdge> reItr = hrn.iteratorToReferencers();
1375 while( reItr.hasNext() ) {
1376 RefEdge re = reItr.next();
1378 re.setTaints( Canonical.removeStallSiteTaints( re.getTaints()
1386 // used in makeCalleeView below to decide if there is
1387 // already an appropriate out-of-context edge in a callee
1388 // view graph for merging, or null if a new one will be added
1390 getOutOfContextReferenceTo( HeapRegionNode hrn,
1391 TypeDescriptor srcType,
1392 TypeDescriptor refType,
1394 assert belongsToThis( hrn );
1396 HeapRegionNode hrnInContext = id2hrn.get( hrn.getID() );
1397 if( hrnInContext == null ) {
1401 Iterator<RefEdge> refItr = hrnInContext.iteratorToReferencers();
1402 while( refItr.hasNext() ) {
1403 RefEdge re = refItr.next();
1405 assert belongsToThis( re.getSrc() );
1406 assert belongsToThis( re.getDst() );
1408 if( !(re.getSrc() instanceof HeapRegionNode) ) {
1412 HeapRegionNode hrnSrc = (HeapRegionNode) re.getSrc();
1413 if( !hrnSrc.isOutOfContext() ) {
1417 if( srcType == null ) {
1418 if( hrnSrc.getType() != null ) {
1422 if( !srcType.equals( hrnSrc.getType() ) ) {
1427 if( !re.typeEquals( refType ) ) {
1431 if( !re.fieldEquals( refField ) ) {
1435 // tada! We found it!
1442 // used below to convert a ReachSet to its callee-context
1443 // equivalent with respect to allocation sites in this graph
1444 protected ReachSet toCalleeContext( ReachSet rs,
1445 ExistPredSet predsNodeOrEdge,
1446 Set<HrnIdOoc> oocHrnIdOoc2callee
1448 ReachSet out = ReachSet.factory();
1450 Iterator<ReachState> itr = rs.iterator();
1451 while( itr.hasNext() ) {
1452 ReachState stateCaller = itr.next();
1454 ReachState stateCallee = stateCaller;
1456 Iterator<AllocSite> asItr = allocSites.iterator();
1457 while( asItr.hasNext() ) {
1458 AllocSite as = asItr.next();
1460 ReachState stateNew = ReachState.factory();
1461 Iterator<ReachTuple> rtItr = stateCallee.iterator();
1462 while( rtItr.hasNext() ) {
1463 ReachTuple rt = rtItr.next();
1465 // only translate this tuple if it is
1466 // in the out-callee-context bag
1467 HrnIdOoc hio = new HrnIdOoc( rt.getHrnID(),
1470 if( !oocHrnIdOoc2callee.contains( hio ) ) {
1471 stateNew = Canonical.addUpArity( stateNew, rt );
1475 int age = as.getAgeCategory( rt.getHrnID() );
1477 // this is the current mapping, where 0, 1, 2S were allocated
1478 // in the current context, 0?, 1? and 2S? were allocated in a
1479 // previous context, and we're translating to a future context
1491 if( age == AllocSite.AGE_notInThisSite ) {
1492 // things not from the site just go back in
1493 stateNew = Canonical.addUpArity( stateNew, rt );
1495 } else if( age == AllocSite.AGE_summary ||
1499 stateNew = Canonical.addUpArity( stateNew,
1500 ReachTuple.factory( as.getSummary(),
1503 true // out-of-context
1508 // otherwise everything else just goes to an out-of-context
1509 // version, everything else the same
1510 Integer I = as.getAge( rt.getHrnID() );
1513 assert !rt.isMultiObject();
1515 stateNew = Canonical.addUpArity( stateNew,
1516 ReachTuple.factory( rt.getHrnID(),
1517 rt.isMultiObject(), // multi
1519 true // out-of-context
1525 stateCallee = stateNew;
1528 // make a predicate of the caller graph element
1529 // and the caller state we just converted
1530 ExistPredSet predsWithState = ExistPredSet.factory();
1532 Iterator<ExistPred> predItr = predsNodeOrEdge.iterator();
1533 while( predItr.hasNext() ) {
1534 ExistPred predNodeOrEdge = predItr.next();
1537 Canonical.add( predsWithState,
1538 ExistPred.factory( predNodeOrEdge.n_hrnID,
1539 predNodeOrEdge.e_tdSrc,
1540 predNodeOrEdge.e_hrnSrcID,
1541 predNodeOrEdge.e_hrnDstID,
1542 predNodeOrEdge.e_type,
1543 predNodeOrEdge.e_field,
1546 predNodeOrEdge.e_srcOutCalleeContext,
1547 predNodeOrEdge.e_srcOutCallerContext
1552 stateCallee = Canonical.changePredsTo( stateCallee,
1555 out = Canonical.add( out,
1559 assert out.isCanonical();
1563 // used below to convert a ReachSet to its caller-context
1564 // equivalent with respect to allocation sites in this graph
1566 toCallerContext( ReachSet rs,
1567 Hashtable<ReachState, ExistPredSet> calleeStatesSatisfied
1569 ReachSet out = ReachSet.factory();
1571 // when the mapping is null it means there were no
1572 // predicates satisfied
1573 if( calleeStatesSatisfied == null ) {
1577 Iterator<ReachState> itr = rs.iterator();
1578 while( itr.hasNext() ) {
1579 ReachState stateCallee = itr.next();
1581 if( calleeStatesSatisfied.containsKey( stateCallee ) ) {
1583 // starting from one callee state...
1584 ReachSet rsCaller = ReachSet.factory( stateCallee );
1586 // possibly branch it into many states, which any
1587 // allocation site might do, so lots of derived states
1588 Iterator<AllocSite> asItr = allocSites.iterator();
1589 while( asItr.hasNext() ) {
1590 AllocSite as = asItr.next();
1591 rsCaller = Canonical.toCallerContext( rsCaller, as );
1594 // then before adding each derived, now caller-context
1595 // states to the output, attach the appropriate pred
1596 // based on the source callee state
1597 Iterator<ReachState> stateItr = rsCaller.iterator();
1598 while( stateItr.hasNext() ) {
1599 ReachState stateCaller = stateItr.next();
1600 stateCaller = Canonical.attach( stateCaller,
1601 calleeStatesSatisfied.get( stateCallee )
1603 out = Canonical.add( out,
1610 assert out.isCanonical();
1615 // used below to convert a ReachSet to an equivalent
1616 // version with shadow IDs merged into unshadowed IDs
1617 protected ReachSet unshadow( ReachSet rs ) {
1619 Iterator<AllocSite> asItr = allocSites.iterator();
1620 while( asItr.hasNext() ) {
1621 AllocSite as = asItr.next();
1622 out = Canonical.unshadow( out, as );
1624 assert out.isCanonical();
1629 // convert a caller taint set into a callee taint set
1631 toCalleeContext( TaintSet ts,
1632 ExistPredSet predsEdge ) {
1634 TaintSet out = TaintSet.factory();
1636 // the idea is easy, the taint identifier itself doesn't
1637 // change at all, but the predicates should be tautology:
1638 // start with the preds passed in from the caller edge
1639 // that host the taints, and alter them to have the taint
1640 // added, just becoming more specific than edge predicate alone
1642 Iterator<Taint> itr = ts.iterator();
1643 while( itr.hasNext() ) {
1644 Taint tCaller = itr.next();
1646 ExistPredSet predsWithTaint = ExistPredSet.factory();
1648 Iterator<ExistPred> predItr = predsEdge.iterator();
1649 while( predItr.hasNext() ) {
1650 ExistPred predEdge = predItr.next();
1653 Canonical.add( predsWithTaint,
1654 ExistPred.factory( predEdge.e_tdSrc,
1655 predEdge.e_hrnSrcID,
1656 predEdge.e_hrnDstID,
1661 predEdge.e_srcOutCalleeContext,
1662 predEdge.e_srcOutCallerContext
1667 Taint tCallee = Canonical.changePredsTo( tCaller,
1670 out = Canonical.add( out,
1675 assert out.isCanonical();
1680 // used below to convert a TaintSet to its caller-context
1681 // equivalent, just eliminate Taints with bad preds
1683 toCallerContext( TaintSet ts,
1684 Hashtable<Taint, ExistPredSet> calleeTaintsSatisfied
1687 TaintSet out = TaintSet.factory();
1689 // when the mapping is null it means there were no
1690 // predicates satisfied
1691 if( calleeTaintsSatisfied == null ) {
1695 Iterator<Taint> itr = ts.iterator();
1696 while( itr.hasNext() ) {
1697 Taint tCallee = itr.next();
1699 if( calleeTaintsSatisfied.containsKey( tCallee ) ) {
1702 Canonical.attach( Taint.factory( tCallee.sese,
1706 ExistPredSet.factory() ),
1707 calleeTaintsSatisfied.get( tCallee )
1709 out = Canonical.add( out,
1715 assert out.isCanonical();
1722 // use this method to make a new reach graph that is
1723 // what heap the FlatMethod callee from the FlatCall
1724 // would start with reaching from its arguments in
1727 makeCalleeView( FlatCall fc,
1728 FlatMethod fmCallee,
1729 Set<Integer> callerNodeIDsCopiedToCallee,
1730 boolean writeDebugDOTs
1734 // first traverse this context to find nodes and edges
1735 // that will be callee-reachable
1736 Set<HeapRegionNode> reachableCallerNodes =
1737 new HashSet<HeapRegionNode>();
1739 // caller edges between callee-reachable nodes
1740 Set<RefEdge> reachableCallerEdges =
1741 new HashSet<RefEdge>();
1743 // caller edges from arg vars, and the matching param index
1744 // because these become a special edge in callee
1745 Hashtable<RefEdge, Integer> reachableCallerArgEdges2paramIndex =
1746 new Hashtable<RefEdge, Integer>();
1748 // caller edges from local vars or callee-unreachable nodes
1749 // (out-of-context sources) to callee-reachable nodes
1750 Set<RefEdge> oocCallerEdges =
1751 new HashSet<RefEdge>();
1754 for( int i = 0; i < fmCallee.numParameters(); ++i ) {
1756 TempDescriptor tdArg = fc.getArgMatchingParamIndex( fmCallee, i );
1757 VariableNode vnArgCaller = this.getVariableNodeFromTemp( tdArg );
1759 Set<RefSrcNode> toVisitInCaller = new HashSet<RefSrcNode>();
1760 Set<RefSrcNode> visitedInCaller = new HashSet<RefSrcNode>();
1762 toVisitInCaller.add( vnArgCaller );
1764 while( !toVisitInCaller.isEmpty() ) {
1765 RefSrcNode rsnCaller = toVisitInCaller.iterator().next();
1766 toVisitInCaller.remove( rsnCaller );
1767 visitedInCaller.add( rsnCaller );
1769 Iterator<RefEdge> itrRefEdges = rsnCaller.iteratorToReferencees();
1770 while( itrRefEdges.hasNext() ) {
1771 RefEdge reCaller = itrRefEdges.next();
1772 HeapRegionNode hrnCaller = reCaller.getDst();
1774 callerNodeIDsCopiedToCallee.add( hrnCaller.getID() );
1775 reachableCallerNodes.add( hrnCaller );
1777 if( reCaller.getSrc() instanceof HeapRegionNode ) {
1778 reachableCallerEdges.add( reCaller );
1780 if( rsnCaller.equals( vnArgCaller ) ) {
1781 reachableCallerArgEdges2paramIndex.put( reCaller, i );
1783 oocCallerEdges.add( reCaller );
1787 if( !visitedInCaller.contains( hrnCaller ) ) {
1788 toVisitInCaller.add( hrnCaller );
1791 } // end edge iteration
1792 } // end visiting heap nodes in caller
1793 } // end iterating over parameters as starting points
1796 // now collect out-of-callee-context IDs and
1797 // map them to whether the ID is out of the caller
1799 Set<HrnIdOoc> oocHrnIdOoc2callee = new HashSet<HrnIdOoc>();
1801 Iterator<Integer> itrInContext =
1802 callerNodeIDsCopiedToCallee.iterator();
1803 while( itrInContext.hasNext() ) {
1804 Integer hrnID = itrInContext.next();
1805 HeapRegionNode hrnCallerAndInContext = id2hrn.get( hrnID );
1807 Iterator<RefEdge> itrMightCross =
1808 hrnCallerAndInContext.iteratorToReferencers();
1809 while( itrMightCross.hasNext() ) {
1810 RefEdge edgeMightCross = itrMightCross.next();
1812 RefSrcNode rsnCallerAndOutContext =
1813 edgeMightCross.getSrc();
1815 if( rsnCallerAndOutContext instanceof VariableNode ) {
1816 // variables do not have out-of-context reach states,
1818 oocCallerEdges.add( edgeMightCross );
1822 HeapRegionNode hrnCallerAndOutContext =
1823 (HeapRegionNode) rsnCallerAndOutContext;
1825 // is this source node out-of-context?
1826 if( callerNodeIDsCopiedToCallee.contains( hrnCallerAndOutContext.getID() ) ) {
1827 // no, skip this edge
1832 oocCallerEdges.add( edgeMightCross );
1834 // add all reach tuples on the node to list
1835 // of things that are out-of-context: insight
1836 // if this node is reachable from someting that WAS
1837 // in-context, then this node should already be in-context
1838 Iterator<ReachState> stateItr = hrnCallerAndOutContext.getAlpha().iterator();
1839 while( stateItr.hasNext() ) {
1840 ReachState state = stateItr.next();
1842 Iterator<ReachTuple> rtItr = state.iterator();
1843 while( rtItr.hasNext() ) {
1844 ReachTuple rt = rtItr.next();
1846 oocHrnIdOoc2callee.add( new HrnIdOoc( rt.getHrnID(),
1855 // the callee view is a new graph: DON'T MODIFY *THIS* graph
1856 ReachGraph rg = new ReachGraph();
1858 // add nodes to callee graph
1859 Iterator<HeapRegionNode> hrnItr = reachableCallerNodes.iterator();
1860 while( hrnItr.hasNext() ) {
1861 HeapRegionNode hrnCaller = hrnItr.next();
1863 assert callerNodeIDsCopiedToCallee.contains( hrnCaller.getID() );
1864 assert !rg.id2hrn.containsKey( hrnCaller.getID() );
1866 ExistPred pred = ExistPred.factory( hrnCaller.getID(), null );
1867 ExistPredSet preds = ExistPredSet.factory( pred );
1869 rg.createNewHeapRegionNode( hrnCaller.getID(),
1870 hrnCaller.isSingleObject(),
1871 hrnCaller.isNewSummary(),
1872 false, // out-of-context?
1873 hrnCaller.getType(),
1874 hrnCaller.getAllocSite(),
1875 toCalleeContext( hrnCaller.getInherent(),
1879 toCalleeContext( hrnCaller.getAlpha(),
1884 hrnCaller.getDescription()
1888 // add param edges to callee graph
1890 reachableCallerArgEdges2paramIndex.entrySet().iterator();
1891 while( argEdges.hasNext() ) {
1892 Map.Entry me = (Map.Entry) argEdges.next();
1893 RefEdge reArg = (RefEdge) me.getKey();
1894 Integer index = (Integer) me.getValue();
1896 VariableNode vnCaller = (VariableNode) reArg.getSrc();
1897 TempDescriptor argCaller = vnCaller.getTempDescriptor();
1899 TempDescriptor paramCallee = fmCallee.getParameter( index );
1900 VariableNode vnCallee = rg.getVariableNodeFromTemp( paramCallee );
1902 HeapRegionNode hrnDstCaller = reArg.getDst();
1903 HeapRegionNode hrnDstCallee = rg.id2hrn.get( hrnDstCaller.getID() );
1904 assert hrnDstCallee != null;
1907 ExistPred.factory( argCaller,
1909 hrnDstCallee.getID(),
1914 true, // out-of-callee-context
1915 false // out-of-caller-context
1918 ExistPredSet preds =
1919 ExistPredSet.factory( pred );
1922 new RefEdge( vnCallee,
1926 toCalleeContext( reArg.getBeta(),
1931 toCalleeContext( reArg.getTaints(),
1935 rg.addRefEdge( vnCallee,
1941 // add in-context edges to callee graph
1942 Iterator<RefEdge> reItr = reachableCallerEdges.iterator();
1943 while( reItr.hasNext() ) {
1944 RefEdge reCaller = reItr.next();
1945 RefSrcNode rsnCaller = reCaller.getSrc();
1946 assert rsnCaller instanceof HeapRegionNode;
1947 HeapRegionNode hrnSrcCaller = (HeapRegionNode) rsnCaller;
1948 HeapRegionNode hrnDstCaller = reCaller.getDst();
1950 HeapRegionNode hrnSrcCallee = rg.id2hrn.get( hrnSrcCaller.getID() );
1951 HeapRegionNode hrnDstCallee = rg.id2hrn.get( hrnDstCaller.getID() );
1952 assert hrnSrcCallee != null;
1953 assert hrnDstCallee != null;
1956 ExistPred.factory( null,
1957 hrnSrcCallee.getID(),
1958 hrnDstCallee.getID(),
1960 reCaller.getField(),
1963 false, // out-of-callee-context
1964 false // out-of-caller-context
1967 ExistPredSet preds =
1968 ExistPredSet.factory( pred );
1971 new RefEdge( hrnSrcCallee,
1974 reCaller.getField(),
1975 toCalleeContext( reCaller.getBeta(),
1980 toCalleeContext( reCaller.getTaints(),
1984 rg.addRefEdge( hrnSrcCallee,
1990 // add out-of-context edges to callee graph
1991 reItr = oocCallerEdges.iterator();
1992 while( reItr.hasNext() ) {
1993 RefEdge reCaller = reItr.next();
1994 RefSrcNode rsnCaller = reCaller.getSrc();
1995 HeapRegionNode hrnDstCaller = reCaller.getDst();
1996 HeapRegionNode hrnDstCallee = rg.id2hrn.get( hrnDstCaller.getID() );
1997 assert hrnDstCallee != null;
1999 TypeDescriptor oocNodeType;
2001 TempDescriptor oocPredSrcTemp = null;
2002 Integer oocPredSrcID = null;
2003 boolean outOfCalleeContext;
2004 boolean outOfCallerContext;
2006 if( rsnCaller instanceof VariableNode ) {
2007 VariableNode vnCaller = (VariableNode) rsnCaller;
2009 oocReach = rsetEmpty;
2010 oocPredSrcTemp = vnCaller.getTempDescriptor();
2011 outOfCalleeContext = true;
2012 outOfCallerContext = false;
2015 HeapRegionNode hrnSrcCaller = (HeapRegionNode) rsnCaller;
2016 assert !callerNodeIDsCopiedToCallee.contains( hrnSrcCaller.getID() );
2017 oocNodeType = hrnSrcCaller.getType();
2018 oocReach = hrnSrcCaller.getAlpha();
2019 oocPredSrcID = hrnSrcCaller.getID();
2020 if( hrnSrcCaller.isOutOfContext() ) {
2021 outOfCalleeContext = false;
2022 outOfCallerContext = true;
2024 outOfCalleeContext = true;
2025 outOfCallerContext = false;
2030 ExistPred.factory( oocPredSrcTemp,
2032 hrnDstCallee.getID(),
2034 reCaller.getField(),
2041 ExistPredSet preds =
2042 ExistPredSet.factory( pred );
2044 RefEdge oocEdgeExisting =
2045 rg.getOutOfContextReferenceTo( hrnDstCallee,
2051 if( oocEdgeExisting == null ) {
2052 // for consistency, map one out-of-context "identifier"
2053 // to one heap region node id, otherwise no convergence
2054 String oocid = "oocid"+
2056 hrnDstCallee.getIDString()+
2059 reCaller.getField();
2061 Integer oocHrnID = oocid2hrnid.get( oocid );
2063 HeapRegionNode hrnCalleeAndOutContext;
2065 if( oocHrnID == null ) {
2067 hrnCalleeAndOutContext =
2068 rg.createNewHeapRegionNode( null, // ID
2069 false, // single object?
2070 false, // new summary?
2071 true, // out-of-context?
2073 null, // alloc site, shouldn't be used
2074 toCalleeContext( oocReach,
2078 toCalleeContext( oocReach,
2086 oocid2hrnid.put( oocid, hrnCalleeAndOutContext.getID() );
2090 // the mapping already exists, so see if node is there
2091 hrnCalleeAndOutContext = rg.id2hrn.get( oocHrnID );
2093 if( hrnCalleeAndOutContext == null ) {
2095 hrnCalleeAndOutContext =
2096 rg.createNewHeapRegionNode( oocHrnID, // ID
2097 false, // single object?
2098 false, // new summary?
2099 true, // out-of-context?
2101 null, // alloc site, shouldn't be used
2102 toCalleeContext( oocReach,
2106 toCalleeContext( oocReach,
2115 // otherwise it is there, so merge reachability
2116 hrnCalleeAndOutContext.setAlpha( Canonical.unionORpreds( hrnCalleeAndOutContext.getAlpha(),
2117 toCalleeContext( oocReach,
2126 assert hrnCalleeAndOutContext.reachHasOnlyOOC();
2128 rg.addRefEdge( hrnCalleeAndOutContext,
2130 new RefEdge( hrnCalleeAndOutContext,
2133 reCaller.getField(),
2134 toCalleeContext( reCaller.getBeta(),
2139 toCalleeContext( reCaller.getTaints(),
2145 // the out-of-context edge already exists
2146 oocEdgeExisting.setBeta( Canonical.unionORpreds( oocEdgeExisting.getBeta(),
2147 toCalleeContext( reCaller.getBeta(),
2154 oocEdgeExisting.setPreds( Canonical.join( oocEdgeExisting.getPreds(),
2159 oocEdgeExisting.setTaints( Canonical.unionORpreds( oocEdgeExisting.getTaints(),
2160 toCalleeContext( reCaller.getTaints(),
2166 HeapRegionNode hrnCalleeAndOutContext =
2167 (HeapRegionNode) oocEdgeExisting.getSrc();
2168 hrnCalleeAndOutContext.setAlpha( Canonical.unionORpreds( hrnCalleeAndOutContext.getAlpha(),
2169 toCalleeContext( oocReach,
2176 assert hrnCalleeAndOutContext.reachHasOnlyOOC();
2181 if( writeDebugDOTs ) {
2182 debugGraphPrefix = String.format( "call%03d", debugCallSiteVisitCounter );
2183 rg.writeGraph( debugGraphPrefix+"calleeview",
2184 resolveMethodDebugDOTwriteLabels,
2185 resolveMethodDebugDOTselectTemps,
2186 resolveMethodDebugDOTpruneGarbage,
2187 resolveMethodDebugDOThideReach,
2188 resolveMethodDebugDOThideSubsetReach,
2189 resolveMethodDebugDOThidePreds,
2190 resolveMethodDebugDOThideEdgeTaints );
2196 private static Hashtable<String, Integer> oocid2hrnid =
2197 new Hashtable<String, Integer>();
2200 // useful since many graphs writes in the method call debug code
2201 private static boolean resolveMethodDebugDOTwriteLabels = true;
2202 private static boolean resolveMethodDebugDOTselectTemps = true;
2203 private static boolean resolveMethodDebugDOTpruneGarbage = true;
2204 private static boolean resolveMethodDebugDOThideReach = true;
2205 private static boolean resolveMethodDebugDOThideSubsetReach = true;
2206 private static boolean resolveMethodDebugDOThidePreds = true;
2207 private static boolean resolveMethodDebugDOThideEdgeTaints = false;
2209 static String debugGraphPrefix;
2210 static int debugCallSiteVisitCounter;
2211 static int debugCallSiteVisitStartCapture;
2212 static int debugCallSiteNumVisitsToCapture;
2213 static boolean debugCallSiteStopAfter;
2217 resolveMethodCall( FlatCall fc,
2218 FlatMethod fmCallee,
2219 ReachGraph rgCallee,
2220 Set<Integer> callerNodeIDsCopiedToCallee,
2221 boolean writeDebugDOTs
2224 if( writeDebugDOTs ) {
2225 System.out.println( " Writing out visit "+
2226 debugCallSiteVisitCounter+
2227 " to debug call site" );
2229 debugGraphPrefix = String.format( "call%03d",
2230 debugCallSiteVisitCounter );
2232 rgCallee.writeGraph( debugGraphPrefix+"callee",
2233 resolveMethodDebugDOTwriteLabels,
2234 resolveMethodDebugDOTselectTemps,
2235 resolveMethodDebugDOTpruneGarbage,
2236 resolveMethodDebugDOThideReach,
2237 resolveMethodDebugDOThideSubsetReach,
2238 resolveMethodDebugDOThidePreds,
2239 resolveMethodDebugDOThideEdgeTaints );
2241 writeGraph( debugGraphPrefix+"caller00In",
2242 resolveMethodDebugDOTwriteLabels,
2243 resolveMethodDebugDOTselectTemps,
2244 resolveMethodDebugDOTpruneGarbage,
2245 resolveMethodDebugDOThideReach,
2246 resolveMethodDebugDOThideSubsetReach,
2247 resolveMethodDebugDOThidePreds,
2248 resolveMethodDebugDOThideEdgeTaints,
2249 callerNodeIDsCopiedToCallee );
2254 // method call transfer function steps:
2255 // 1. Use current callee-reachable heap (CRH) to test callee
2256 // predicates and mark what will be coming in.
2257 // 2. Wipe CRH out of caller.
2258 // 3. Transplant marked callee parts in:
2259 // a) bring in nodes
2260 // b) bring in callee -> callee edges
2261 // c) resolve out-of-context -> callee edges
2262 // d) assign return value
2263 // 4. Collapse shadow nodes down
2264 // 5. Global sweep it.
2267 // 1. mark what callee elements have satisfied predicates
2268 Hashtable<HeapRegionNode, ExistPredSet> calleeNodesSatisfied =
2269 new Hashtable<HeapRegionNode, ExistPredSet>();
2271 Hashtable<RefEdge, ExistPredSet> calleeEdgesSatisfied =
2272 new Hashtable<RefEdge, ExistPredSet>();
2274 Hashtable< HeapRegionNode, Hashtable<ReachState, ExistPredSet> >
2275 calleeNode2calleeStatesSatisfied =
2276 new Hashtable< HeapRegionNode, Hashtable<ReachState, ExistPredSet> >();
2278 Hashtable< RefEdge, Hashtable<ReachState, ExistPredSet> >
2279 calleeEdge2calleeStatesSatisfied =
2280 new Hashtable< RefEdge, Hashtable<ReachState, ExistPredSet> >();
2282 Hashtable< RefEdge, Hashtable<Taint, ExistPredSet> >
2283 calleeEdge2calleeTaintsSatisfied =
2284 new Hashtable< RefEdge, Hashtable<Taint, ExistPredSet> >();
2286 Hashtable< RefEdge, Set<RefSrcNode> > calleeEdges2oocCallerSrcMatches =
2287 new Hashtable< RefEdge, Set<RefSrcNode> >();
2290 Iterator meItr = rgCallee.id2hrn.entrySet().iterator();
2291 while( meItr.hasNext() ) {
2292 Map.Entry me = (Map.Entry) meItr.next();
2293 Integer id = (Integer) me.getKey();
2294 HeapRegionNode hrnCallee = (HeapRegionNode) me.getValue();
2296 // if a callee element's predicates are satisfied then a set
2297 // of CALLER predicates is returned: they are the predicates
2298 // that the callee element moved into the caller context
2299 // should have, and it is inefficient to find this again later
2300 ExistPredSet predsIfSatis =
2301 hrnCallee.getPreds().isSatisfiedBy( this,
2302 callerNodeIDsCopiedToCallee
2305 if( predsIfSatis != null ) {
2306 calleeNodesSatisfied.put( hrnCallee, predsIfSatis );
2308 // otherwise don't bother looking at edges to this node
2312 // since the node is coming over, find out which reach
2313 // states on it should come over, too
2314 assert calleeNode2calleeStatesSatisfied.get( hrnCallee ) == null;
2316 Iterator<ReachState> stateItr = hrnCallee.getAlpha().iterator();
2317 while( stateItr.hasNext() ) {
2318 ReachState stateCallee = stateItr.next();
2321 stateCallee.getPreds().isSatisfiedBy( this,
2322 callerNodeIDsCopiedToCallee
2324 if( predsIfSatis != null ) {
2326 Hashtable<ReachState, ExistPredSet> calleeStatesSatisfied =
2327 calleeNode2calleeStatesSatisfied.get( hrnCallee );
2329 if( calleeStatesSatisfied == null ) {
2330 calleeStatesSatisfied =
2331 new Hashtable<ReachState, ExistPredSet>();
2333 calleeNode2calleeStatesSatisfied.put( hrnCallee, calleeStatesSatisfied );
2336 calleeStatesSatisfied.put( stateCallee, predsIfSatis );
2340 // then look at edges to the node
2341 Iterator<RefEdge> reItr = hrnCallee.iteratorToReferencers();
2342 while( reItr.hasNext() ) {
2343 RefEdge reCallee = reItr.next();
2344 RefSrcNode rsnCallee = reCallee.getSrc();
2346 // (caller local variables to in-context heap regions)
2347 // have an (out-of-context heap region -> in-context heap region)
2348 // abstraction in the callEE, so its true we never need to
2349 // look at a (var node -> heap region) edge in callee to bring
2350 // those over for the call site transfer, except for the special
2351 // case of *RETURN var* -> heap region edges.
2352 // What about (param var->heap region)
2353 // edges in callee? They are dealt with below this loop.
2355 if( rsnCallee instanceof VariableNode ) {
2357 // looking for the return-value variable only
2358 VariableNode vnCallee = (VariableNode) rsnCallee;
2359 if( vnCallee.getTempDescriptor() != tdReturn ) {
2363 TempDescriptor returnTemp = fc.getReturnTemp();
2364 if( returnTemp == null ||
2365 !DisjointAnalysis.shouldAnalysisTrack( returnTemp.getType() )
2370 // note that the assignment of the return value is to a
2371 // variable in the caller which is out-of-context with
2372 // respect to the callee
2373 VariableNode vnLhsCaller = getVariableNodeFromTemp( returnTemp );
2374 Set<RefSrcNode> rsnCallers = new HashSet<RefSrcNode>();
2375 rsnCallers.add( vnLhsCaller );
2376 calleeEdges2oocCallerSrcMatches.put( reCallee, rsnCallers );
2380 // for HeapRegionNode callee sources...
2382 // first see if the source is out-of-context, and only
2383 // proceed with this edge if we find some caller-context
2385 HeapRegionNode hrnSrcCallee = (HeapRegionNode) rsnCallee;
2386 boolean matchedOutOfContext = false;
2388 if( !hrnSrcCallee.isOutOfContext() ) {
2391 hrnSrcCallee.getPreds().isSatisfiedBy( this,
2392 callerNodeIDsCopiedToCallee
2394 if( predsIfSatis != null ) {
2395 calleeNodesSatisfied.put( hrnSrcCallee, predsIfSatis );
2397 // otherwise forget this edge
2402 // hrnSrcCallee is out-of-context
2404 assert !calleeEdges2oocCallerSrcMatches.containsKey( reCallee );
2406 Set<RefSrcNode> rsnCallers = new HashSet<RefSrcNode>();
2408 // is the target node in the caller?
2409 HeapRegionNode hrnDstCaller = this.id2hrn.get( hrnCallee.getID() );
2410 if( hrnDstCaller == null ) {
2414 Iterator<RefEdge> reDstItr = hrnDstCaller.iteratorToReferencers();
2415 while( reDstItr.hasNext() ) {
2416 // the edge and field (either possibly null) must match
2417 RefEdge reCaller = reDstItr.next();
2419 if( !reCaller.typeEquals ( reCallee.getType() ) ||
2420 !reCaller.fieldEquals( reCallee.getField() )
2425 RefSrcNode rsnCaller = reCaller.getSrc();
2426 if( rsnCaller instanceof VariableNode ) {
2428 // a variable node matches an OOC region with null type
2429 if( hrnSrcCallee.getType() != null ) {
2434 // otherwise types should match
2435 HeapRegionNode hrnCallerSrc = (HeapRegionNode) rsnCaller;
2436 if( hrnSrcCallee.getType() == null ) {
2437 if( hrnCallerSrc.getType() != null ) {
2441 if( !hrnSrcCallee.getType().equals( hrnCallerSrc.getType() ) ) {
2447 rsnCallers.add( rsnCaller );
2448 matchedOutOfContext = true;
2451 if( !rsnCallers.isEmpty() ) {
2452 calleeEdges2oocCallerSrcMatches.put( reCallee, rsnCallers );
2456 if( hrnSrcCallee.isOutOfContext() &&
2457 !matchedOutOfContext ) {
2464 reCallee.getPreds().isSatisfiedBy( this,
2465 callerNodeIDsCopiedToCallee
2468 if( predsIfSatis != null ) {
2469 calleeEdgesSatisfied.put( reCallee, predsIfSatis );
2471 // since the edge is coming over, find out which reach
2472 // states on it should come over, too
2473 assert calleeEdge2calleeStatesSatisfied.get( reCallee ) == null;
2475 stateItr = reCallee.getBeta().iterator();
2476 while( stateItr.hasNext() ) {
2477 ReachState stateCallee = stateItr.next();
2480 stateCallee.getPreds().isSatisfiedBy( this,
2481 callerNodeIDsCopiedToCallee
2483 if( predsIfSatis != null ) {
2485 Hashtable<ReachState, ExistPredSet> calleeStatesSatisfied =
2486 calleeEdge2calleeStatesSatisfied.get( reCallee );
2488 if( calleeStatesSatisfied == null ) {
2489 calleeStatesSatisfied =
2490 new Hashtable<ReachState, ExistPredSet>();
2492 calleeEdge2calleeStatesSatisfied.put( reCallee, calleeStatesSatisfied );
2495 calleeStatesSatisfied.put( stateCallee, predsIfSatis );
2499 // since the edge is coming over, find out which taints
2500 // on it should come over, too
2501 assert calleeEdge2calleeTaintsSatisfied.get( reCallee ) == null;
2503 Iterator<Taint> tItr = reCallee.getTaints().iterator();
2504 while( tItr.hasNext() ) {
2505 Taint tCallee = tItr.next();
2508 tCallee.getPreds().isSatisfiedBy( this,
2509 callerNodeIDsCopiedToCallee
2511 if( predsIfSatis != null ) {
2513 Hashtable<Taint, ExistPredSet> calleeTaintsSatisfied =
2514 calleeEdge2calleeTaintsSatisfied.get( reCallee );
2516 if( calleeTaintsSatisfied == null ) {
2517 calleeTaintsSatisfied =
2518 new Hashtable<Taint, ExistPredSet>();
2520 calleeEdge2calleeTaintsSatisfied.put( reCallee, calleeTaintsSatisfied );
2523 calleeTaintsSatisfied.put( tCallee, predsIfSatis );
2530 if( writeDebugDOTs ) {
2531 writeGraph( debugGraphPrefix+"caller20BeforeWipe",
2532 resolveMethodDebugDOTwriteLabels,
2533 resolveMethodDebugDOTselectTemps,
2534 resolveMethodDebugDOTpruneGarbage,
2535 resolveMethodDebugDOThideReach,
2536 resolveMethodDebugDOThideSubsetReach,
2537 resolveMethodDebugDOThidePreds,
2538 resolveMethodDebugDOThideEdgeTaints );
2542 // 2. predicates tested, ok to wipe out caller part
2543 Iterator<Integer> hrnItr = callerNodeIDsCopiedToCallee.iterator();
2544 while( hrnItr.hasNext() ) {
2545 Integer hrnID = hrnItr.next();
2546 HeapRegionNode hrnCaller = id2hrn.get( hrnID );
2547 assert hrnCaller != null;
2549 // when clearing off nodes, also eliminate variable
2551 wipeOut( hrnCaller, true );
2554 // if we are assigning the return value to something, clobber now
2555 // as part of the wipe
2556 TempDescriptor returnTemp = fc.getReturnTemp();
2557 if( returnTemp != null &&
2558 DisjointAnalysis.shouldAnalysisTrack( returnTemp.getType() )
2561 VariableNode vnLhsCaller = getVariableNodeFromTemp( returnTemp );
2562 clearRefEdgesFrom( vnLhsCaller, null, null, true );
2568 if( writeDebugDOTs ) {
2569 writeGraph( debugGraphPrefix+"caller30BeforeAddingNodes",
2570 resolveMethodDebugDOTwriteLabels,
2571 resolveMethodDebugDOTselectTemps,
2572 resolveMethodDebugDOTpruneGarbage,
2573 resolveMethodDebugDOThideReach,
2574 resolveMethodDebugDOThideSubsetReach,
2575 resolveMethodDebugDOThidePreds,
2576 resolveMethodDebugDOThideEdgeTaints );
2582 // 3. callee elements with satisfied preds come in, note that
2583 // the mapping of elements satisfied to preds is like this:
2584 // A callee element EE has preds EEp that are satisfied by
2585 // some caller element ER. We bring EE into the caller
2586 // context as ERee with the preds of ER, namely ERp, which
2587 // in the following algorithm is the value in the mapping
2590 Iterator satisItr = calleeNodesSatisfied.entrySet().iterator();
2591 while( satisItr.hasNext() ) {
2592 Map.Entry me = (Map.Entry) satisItr.next();
2593 HeapRegionNode hrnCallee = (HeapRegionNode) me.getKey();
2594 ExistPredSet preds = (ExistPredSet) me.getValue();
2596 // TODO: I think its true that the current implementation uses
2597 // the type of the OOC region and the predicates OF THE EDGE from
2598 // it to link everything up in caller context, so that's why we're
2599 // skipping this... maybe that's a sillier way to do it?
2600 if( hrnCallee.isOutOfContext() ) {
2604 AllocSite as = hrnCallee.getAllocSite();
2605 allocSites.add( as );
2607 Integer hrnIDshadow = as.getShadowIDfromID( hrnCallee.getID() );
2609 HeapRegionNode hrnCaller = id2hrn.get( hrnIDshadow );
2610 if( hrnCaller == null ) {
2612 createNewHeapRegionNode( hrnIDshadow, // id or null to generate a new one
2613 hrnCallee.isSingleObject(), // single object?
2614 hrnCallee.isNewSummary(), // summary?
2615 false, // out-of-context?
2616 hrnCallee.getType(), // type
2617 hrnCallee.getAllocSite(), // allocation site
2618 toCallerContext( hrnCallee.getInherent(),
2619 calleeNode2calleeStatesSatisfied.get( hrnCallee ) ), // inherent reach
2620 null, // current reach
2621 predsEmpty, // predicates
2622 hrnCallee.getDescription() // description
2625 assert hrnCaller.isWiped();
2628 hrnCaller.setAlpha( toCallerContext( hrnCallee.getAlpha(),
2629 calleeNode2calleeStatesSatisfied.get( hrnCallee )
2633 hrnCaller.setPreds( preds );
2640 if( writeDebugDOTs ) {
2641 writeGraph( debugGraphPrefix+"caller31BeforeAddingEdges",
2642 resolveMethodDebugDOTwriteLabels,
2643 resolveMethodDebugDOTselectTemps,
2644 resolveMethodDebugDOTpruneGarbage,
2645 resolveMethodDebugDOThideReach,
2646 resolveMethodDebugDOThideSubsetReach,
2647 resolveMethodDebugDOThidePreds,
2648 resolveMethodDebugDOThideEdgeTaints );
2652 // set these up during the next procedure so after
2653 // the caller has all of its nodes and edges put
2654 // back together we can propagate the callee's
2655 // reach changes backwards into the caller graph
2656 HashSet<RefEdge> edgesForPropagation = new HashSet<RefEdge>();
2658 Hashtable<RefEdge, ChangeSet> edgePlannedChanges =
2659 new Hashtable<RefEdge, ChangeSet>();
2662 // 3.b) callee -> callee edges AND out-of-context -> callee
2663 // which includes return temp -> callee edges now, too
2664 satisItr = calleeEdgesSatisfied.entrySet().iterator();
2665 while( satisItr.hasNext() ) {
2666 Map.Entry me = (Map.Entry) satisItr.next();
2667 RefEdge reCallee = (RefEdge) me.getKey();
2668 ExistPredSet preds = (ExistPredSet) me.getValue();
2670 HeapRegionNode hrnDstCallee = reCallee.getDst();
2671 AllocSite asDst = hrnDstCallee.getAllocSite();
2672 allocSites.add( asDst );
2674 Integer hrnIDDstShadow =
2675 asDst.getShadowIDfromID( hrnDstCallee.getID() );
2677 HeapRegionNode hrnDstCaller = id2hrn.get( hrnIDDstShadow );
2678 assert hrnDstCaller != null;
2681 RefSrcNode rsnCallee = reCallee.getSrc();
2683 Set<RefSrcNode> rsnCallers =
2684 new HashSet<RefSrcNode>();
2686 Set<RefSrcNode> oocCallers =
2687 calleeEdges2oocCallerSrcMatches.get( reCallee );
2689 if( rsnCallee instanceof HeapRegionNode ) {
2690 HeapRegionNode hrnCalleeSrc = (HeapRegionNode) rsnCallee;
2691 if( hrnCalleeSrc.isOutOfContext() ) {
2692 assert oocCallers != null;
2697 if( oocCallers == null ) {
2698 // there are no out-of-context matches, so it's
2699 // either a param/arg var or one in-context heap region
2700 if( rsnCallee instanceof VariableNode ) {
2701 // variable -> node in the callee should only
2702 // come into the caller if its from a param var
2703 VariableNode vnCallee = (VariableNode) rsnCallee;
2704 TempDescriptor tdParam = vnCallee.getTempDescriptor();
2705 TempDescriptor tdArg = fc.getArgMatchingParam( fmCallee,
2707 if( tdArg == null ) {
2708 // this means the variable isn't a parameter, its local
2709 // to the callee so we ignore it in call site transfer
2710 // shouldn't this NEVER HAPPEN?
2714 rsnCallers.add( this.getVariableNodeFromTemp( tdArg ) );
2717 // otherwise source is in context, one region
2719 HeapRegionNode hrnSrcCallee = (HeapRegionNode) rsnCallee;
2721 // translate an in-context node to shadow
2722 AllocSite asSrc = hrnSrcCallee.getAllocSite();
2723 allocSites.add( asSrc );
2725 Integer hrnIDSrcShadow =
2726 asSrc.getShadowIDfromID( hrnSrcCallee.getID() );
2728 HeapRegionNode hrnSrcCallerShadow =
2729 this.id2hrn.get( hrnIDSrcShadow );
2731 assert hrnSrcCallerShadow != null;
2733 rsnCallers.add( hrnSrcCallerShadow );
2737 // otherwise we have a set of out-of-context srcs
2738 // that should NOT be translated to shadow nodes
2739 assert !oocCallers.isEmpty();
2740 rsnCallers.addAll( oocCallers );
2743 // now make all caller edges we've identified from
2744 // this callee edge with a satisfied predicate
2745 assert !rsnCallers.isEmpty();
2746 Iterator<RefSrcNode> rsnItr = rsnCallers.iterator();
2747 while( rsnItr.hasNext() ) {
2748 RefSrcNode rsnCaller = rsnItr.next();
2750 RefEdge reCaller = new RefEdge( rsnCaller,
2753 reCallee.getField(),
2754 toCallerContext( reCallee.getBeta(),
2755 calleeEdge2calleeStatesSatisfied.get( reCallee ) ),
2757 toCallerContext( reCallee.getTaints(),
2758 calleeEdge2calleeTaintsSatisfied.get( reCallee ) )
2761 ChangeSet cs = ChangeSet.factory();
2762 Iterator<ReachState> rsItr = reCaller.getBeta().iterator();
2763 while( rsItr.hasNext() ) {
2764 ReachState state = rsItr.next();
2765 ExistPredSet predsPreCallee = state.getPreds();
2767 if( state.isEmpty() ) {
2771 Iterator<ExistPred> predItr = predsPreCallee.iterator();
2772 while( predItr.hasNext() ) {
2773 ExistPred pred = predItr.next();
2774 ReachState old = pred.ne_state;
2780 cs = Canonical.add( cs,
2781 ChangeTuple.factory( old,
2788 // we're just going to use the convenient "merge-if-exists"
2789 // edge call below, but still take a separate look if there
2790 // is an existing caller edge to build change sets properly
2791 if( !cs.isEmpty() ) {
2792 RefEdge edgeExisting = rsnCaller.getReferenceTo( hrnDstCaller,
2796 if( edgeExisting != null ) {
2797 ChangeSet csExisting = edgePlannedChanges.get( edgeExisting );
2798 if( csExisting == null ) {
2799 csExisting = ChangeSet.factory();
2801 edgePlannedChanges.put( edgeExisting,
2802 Canonical.union( csExisting,
2807 edgesForPropagation.add( reCaller );
2808 assert !edgePlannedChanges.containsKey( reCaller );
2809 edgePlannedChanges.put( reCaller, cs );
2813 // then add new caller edge or merge
2814 addEdgeOrMergeWithExisting( reCaller );
2822 if( writeDebugDOTs ) {
2823 writeGraph( debugGraphPrefix+"caller38propagateReach",
2824 resolveMethodDebugDOTwriteLabels,
2825 resolveMethodDebugDOTselectTemps,
2826 resolveMethodDebugDOTpruneGarbage,
2827 resolveMethodDebugDOThideReach,
2828 resolveMethodDebugDOThideSubsetReach,
2829 resolveMethodDebugDOThidePreds,
2830 resolveMethodDebugDOThideEdgeTaints );
2833 // propagate callee reachability changes to the rest
2834 // of the caller graph edges
2835 HashSet<RefEdge> edgesUpdated = new HashSet<RefEdge>();
2837 propagateTokensOverEdges( edgesForPropagation, // source edges
2838 edgePlannedChanges, // map src edge to change set
2839 edgesUpdated ); // list of updated edges
2841 // commit beta' (beta<-betaNew)
2842 Iterator<RefEdge> edgeItr = edgesUpdated.iterator();
2843 while( edgeItr.hasNext() ) {
2844 edgeItr.next().applyBetaNew();
2853 if( writeDebugDOTs ) {
2854 writeGraph( debugGraphPrefix+"caller40BeforeShadowMerge",
2855 resolveMethodDebugDOTwriteLabels,
2856 resolveMethodDebugDOTselectTemps,
2857 resolveMethodDebugDOTpruneGarbage,
2858 resolveMethodDebugDOThideReach,
2859 resolveMethodDebugDOThideSubsetReach,
2860 resolveMethodDebugDOThidePreds,
2861 resolveMethodDebugDOThideEdgeTaints );
2865 // 4) merge shadow nodes so alloc sites are back to k
2866 Iterator<AllocSite> asItr = rgCallee.allocSites.iterator();
2867 while( asItr.hasNext() ) {
2868 // for each allocation site do the following to merge
2869 // shadow nodes (newest from callee) with any existing
2870 // look for the newest normal and newest shadow "slot"
2871 // not being used, transfer normal to shadow. Keep
2872 // doing this until there are no more normal nodes, or
2873 // no empty shadow slots: then merge all remaining normal
2874 // nodes into the shadow summary. Finally, convert all
2875 // shadow to their normal versions.
2876 AllocSite as = asItr.next();
2879 while( ageNorm < allocationDepth &&
2880 ageShad < allocationDepth ) {
2882 // first, are there any normal nodes left?
2883 Integer idNorm = as.getIthOldest( ageNorm );
2884 HeapRegionNode hrnNorm = id2hrn.get( idNorm );
2885 if( hrnNorm == null ) {
2886 // no, this age of normal node not in the caller graph
2891 // yes, a normal node exists, is there an empty shadow
2892 // "slot" to transfer it onto?
2893 HeapRegionNode hrnShad = getIthNode( as, ageShad, true );
2894 if( !hrnShad.isWiped() ) {
2895 // no, this age of shadow node is not empty
2900 // yes, this shadow node is empty
2901 transferOnto( hrnNorm, hrnShad );
2906 // now, while there are still normal nodes but no shadow
2907 // slots, merge normal nodes into the shadow summary
2908 while( ageNorm < allocationDepth ) {
2910 // first, are there any normal nodes left?
2911 Integer idNorm = as.getIthOldest( ageNorm );
2912 HeapRegionNode hrnNorm = id2hrn.get( idNorm );
2913 if( hrnNorm == null ) {
2914 // no, this age of normal node not in the caller graph
2919 // yes, a normal node exists, so get the shadow summary
2920 HeapRegionNode summShad = getSummaryNode( as, true );
2921 mergeIntoSummary( hrnNorm, summShad );
2925 // if there is a normal summary, merge it into shadow summary
2926 Integer idNorm = as.getSummary();
2927 HeapRegionNode summNorm = id2hrn.get( idNorm );
2928 if( summNorm != null ) {
2929 HeapRegionNode summShad = getSummaryNode( as, true );
2930 mergeIntoSummary( summNorm, summShad );
2933 // finally, flip all existing shadow nodes onto the normal
2934 for( int i = 0; i < allocationDepth; ++i ) {
2935 Integer idShad = as.getIthOldestShadow( i );
2936 HeapRegionNode hrnShad = id2hrn.get( idShad );
2937 if( hrnShad != null ) {
2939 HeapRegionNode hrnNorm = getIthNode( as, i, false );
2940 assert hrnNorm.isWiped();
2941 transferOnto( hrnShad, hrnNorm );
2945 Integer idShad = as.getSummaryShadow();
2946 HeapRegionNode summShad = id2hrn.get( idShad );
2947 if( summShad != null ) {
2948 summNorm = getSummaryNode( as, false );
2949 transferOnto( summShad, summNorm );
2958 if( writeDebugDOTs ) {
2959 writeGraph( debugGraphPrefix+"caller45BeforeUnshadow",
2960 resolveMethodDebugDOTwriteLabels,
2961 resolveMethodDebugDOTselectTemps,
2962 resolveMethodDebugDOTpruneGarbage,
2963 resolveMethodDebugDOThideReach,
2964 resolveMethodDebugDOThideSubsetReach,
2965 resolveMethodDebugDOThidePreds,
2966 resolveMethodDebugDOThideEdgeTaints );
2970 Iterator itrAllHRNodes = id2hrn.entrySet().iterator();
2971 while( itrAllHRNodes.hasNext() ) {
2972 Map.Entry me = (Map.Entry) itrAllHRNodes.next();
2973 HeapRegionNode hrn = (HeapRegionNode) me.getValue();
2975 hrn.setAlpha( unshadow( hrn.getAlpha() ) );
2977 Iterator<RefEdge> itrEdges = hrn.iteratorToReferencers();
2978 while( itrEdges.hasNext() ) {
2979 RefEdge re = itrEdges.next();
2980 re.setBeta( unshadow( re.getBeta() ) );
2987 if( writeDebugDOTs ) {
2988 writeGraph( debugGraphPrefix+"caller50BeforeGlobalSweep",
2989 resolveMethodDebugDOTwriteLabels,
2990 resolveMethodDebugDOTselectTemps,
2991 resolveMethodDebugDOTpruneGarbage,
2992 resolveMethodDebugDOThideReach,
2993 resolveMethodDebugDOThideSubsetReach,
2994 resolveMethodDebugDOThidePreds,
2995 resolveMethodDebugDOThideEdgeTaints );
3000 if( !DISABLE_GLOBAL_SWEEP ) {
3005 if( writeDebugDOTs ) {
3006 writeGraph( debugGraphPrefix+"caller90AfterTransfer",
3007 resolveMethodDebugDOTwriteLabels,
3008 resolveMethodDebugDOTselectTemps,
3009 resolveMethodDebugDOTpruneGarbage,
3010 resolveMethodDebugDOThideReach,
3011 resolveMethodDebugDOThideSubsetReach,
3012 resolveMethodDebugDOThidePreds,
3013 resolveMethodDebugDOThideEdgeTaints );
3019 ////////////////////////////////////////////////////
3021 // Abstract garbage collection simply removes
3022 // heap region nodes that are not mechanically
3023 // reachable from a root set. This step is
3024 // essential for testing node and edge existence
3025 // predicates efficiently
3027 ////////////////////////////////////////////////////
3028 public void abstractGarbageCollect( Set<TempDescriptor> liveSet ) {
3030 // calculate a root set, will be different for Java
3031 // version of analysis versus Bamboo version
3032 Set<RefSrcNode> toVisit = new HashSet<RefSrcNode>();
3034 // visit every variable in graph while building root
3035 // set, and do iterating on a copy, so we can remove
3036 // dead variables while we're at this
3037 Iterator makeCopyItr = td2vn.entrySet().iterator();
3038 Set entrysCopy = new HashSet();
3039 while( makeCopyItr.hasNext() ) {
3040 entrysCopy.add( makeCopyItr.next() );
3043 Iterator eItr = entrysCopy.iterator();
3044 while( eItr.hasNext() ) {
3045 Map.Entry me = (Map.Entry) eItr.next();
3046 TempDescriptor td = (TempDescriptor) me.getKey();
3047 VariableNode vn = (VariableNode) me.getValue();
3049 if( liveSet.contains( td ) ) {
3053 // dead var, remove completely from graph
3055 clearRefEdgesFrom( vn, null, null, true );
3059 // everything visited in a traversal is
3060 // considered abstractly live
3061 Set<RefSrcNode> visited = new HashSet<RefSrcNode>();
3063 while( !toVisit.isEmpty() ) {
3064 RefSrcNode rsn = toVisit.iterator().next();
3065 toVisit.remove( rsn );
3068 Iterator<RefEdge> hrnItr = rsn.iteratorToReferencees();
3069 while( hrnItr.hasNext() ) {
3070 RefEdge edge = hrnItr.next();
3071 HeapRegionNode hrn = edge.getDst();
3073 if( !visited.contains( hrn ) ) {
3079 // get a copy of the set to iterate over because
3080 // we're going to monkey with the graph when we
3081 // identify a garbage node
3082 Set<HeapRegionNode> hrnAllPrior = new HashSet<HeapRegionNode>();
3083 Iterator<HeapRegionNode> hrnItr = id2hrn.values().iterator();
3084 while( hrnItr.hasNext() ) {
3085 hrnAllPrior.add( hrnItr.next() );
3088 Iterator<HeapRegionNode> hrnAllItr = hrnAllPrior.iterator();
3089 while( hrnAllItr.hasNext() ) {
3090 HeapRegionNode hrn = hrnAllItr.next();
3092 if( !visited.contains( hrn ) ) {
3094 // heap region nodes are compared across ReachGraph
3095 // objects by their integer ID, so when discarding
3096 // garbage nodes we must also discard entries in
3097 // the ID -> heap region hashtable.
3098 id2hrn.remove( hrn.getID() );
3100 // RefEdge objects are two-way linked between
3101 // nodes, so when a node is identified as garbage,
3102 // actively clear references to and from it so
3103 // live nodes won't have dangling RefEdge's
3104 wipeOut( hrn, true );
3106 // if we just removed the last node from an allocation
3107 // site, it should be taken out of the ReachGraph's list
3108 AllocSite as = hrn.getAllocSite();
3109 if( !hasNodesOf( as ) ) {
3110 allocSites.remove( as );
3116 protected boolean hasNodesOf( AllocSite as ) {
3117 if( id2hrn.containsKey( as.getSummary() ) ) {
3121 for( int i = 0; i < allocationDepth; ++i ) {
3122 if( id2hrn.containsKey( as.getIthOldest( i ) ) ) {
3130 ////////////////////////////////////////////////////
3132 // This global sweep is an optional step to prune
3133 // reachability sets that are not internally
3134 // consistent with the global graph. It should be
3135 // invoked after strong updates or method calls.
3137 ////////////////////////////////////////////////////
3138 public void globalSweep() {
3140 // boldB is part of the phase 1 sweep
3141 // it has an in-context table and an out-of-context table
3142 Hashtable< Integer, Hashtable<RefEdge, ReachSet> > boldBic =
3143 new Hashtable< Integer, Hashtable<RefEdge, ReachSet> >();
3145 Hashtable< Integer, Hashtable<RefEdge, ReachSet> > boldBooc =
3146 new Hashtable< Integer, Hashtable<RefEdge, ReachSet> >();
3148 // visit every heap region to initialize alphaNew and betaNew,
3149 // and make a map of every hrnID to the source nodes it should
3150 // propagate forward from. In-context flagged hrnID's propagate
3151 // from only the in-context node they name, but out-of-context
3152 // ID's may propagate from several out-of-context nodes
3153 Hashtable< Integer, Set<HeapRegionNode> > icID2srcs =
3154 new Hashtable< Integer, Set<HeapRegionNode> >();
3156 Hashtable< Integer, Set<HeapRegionNode> > oocID2srcs =
3157 new Hashtable< Integer, Set<HeapRegionNode> >();
3160 Iterator itrHrns = id2hrn.entrySet().iterator();
3161 while( itrHrns.hasNext() ) {
3162 Map.Entry me = (Map.Entry) itrHrns.next();
3163 Integer hrnID = (Integer) me.getKey();
3164 HeapRegionNode hrn = (HeapRegionNode) me.getValue();
3166 // assert that this node and incoming edges have clean alphaNew
3167 // and betaNew sets, respectively
3168 assert rsetEmpty.equals( hrn.getAlphaNew() );
3170 Iterator<RefEdge> itrRers = hrn.iteratorToReferencers();
3171 while( itrRers.hasNext() ) {
3172 RefEdge edge = itrRers.next();
3173 assert rsetEmpty.equals( edge.getBetaNew() );
3176 // make a mapping of IDs to heap regions they propagate from
3177 if( hrn.isFlagged() ) {
3178 assert !hrn.isOutOfContext();
3179 assert !icID2srcs.containsKey( hrn.getID() );
3181 // in-context flagged node IDs simply propagate from the
3183 Set<HeapRegionNode> srcs = new HashSet<HeapRegionNode>();
3185 icID2srcs.put( hrn.getID(), srcs );
3188 if( hrn.isOutOfContext() ) {
3189 assert !hrn.isFlagged();
3191 // the reachability states on an out-of-context
3192 // node are not really important (combinations of
3193 // IDs or arity)--what matters is that the states
3194 // specify which nodes this out-of-context node
3195 // stands in for. For example, if the state [17?, 19*]
3196 // appears on the ooc node, it may serve as a source
3197 // for node 17? and a source for node 19.
3198 Iterator<ReachState> stateItr = hrn.getAlpha().iterator();
3199 while( stateItr.hasNext() ) {
3200 ReachState state = stateItr.next();
3202 Iterator<ReachTuple> rtItr = state.iterator();
3203 while( rtItr.hasNext() ) {
3204 ReachTuple rt = rtItr.next();
3205 assert rt.isOutOfContext();
3207 Set<HeapRegionNode> srcs = oocID2srcs.get( rt.getHrnID() );
3208 if( srcs == null ) {
3209 srcs = new HashSet<HeapRegionNode>();
3212 oocID2srcs.put( rt.getHrnID(), srcs );
3218 // calculate boldB for all hrnIDs identified by the above
3219 // node traversal, propagating from every source
3220 while( !icID2srcs.isEmpty() || !oocID2srcs.isEmpty() ) {
3223 Set<HeapRegionNode> srcs;
3226 if( !icID2srcs.isEmpty() ) {
3227 Map.Entry me = (Map.Entry) icID2srcs.entrySet().iterator().next();
3228 hrnID = (Integer) me.getKey();
3229 srcs = (Set<HeapRegionNode>) me.getValue();
3231 icID2srcs.remove( hrnID );
3234 assert !oocID2srcs.isEmpty();
3236 Map.Entry me = (Map.Entry) oocID2srcs.entrySet().iterator().next();
3237 hrnID = (Integer) me.getKey();
3238 srcs = (Set<HeapRegionNode>) me.getValue();
3240 oocID2srcs.remove( hrnID );
3244 Hashtable<RefEdge, ReachSet> boldB_f =
3245 new Hashtable<RefEdge, ReachSet>();
3247 Set<RefEdge> workSetEdges = new HashSet<RefEdge>();
3249 Iterator<HeapRegionNode> hrnItr = srcs.iterator();
3250 while( hrnItr.hasNext() ) {
3251 HeapRegionNode hrn = hrnItr.next();
3253 assert workSetEdges.isEmpty();
3255 // initial boldB_f constraints
3256 Iterator<RefEdge> itrRees = hrn.iteratorToReferencees();
3257 while( itrRees.hasNext() ) {
3258 RefEdge edge = itrRees.next();
3260 assert !boldB_f.containsKey( edge );
3261 boldB_f.put( edge, edge.getBeta() );
3263 assert !workSetEdges.contains( edge );
3264 workSetEdges.add( edge );
3267 // enforce the boldB_f constraint at edges until we reach a fixed point
3268 while( !workSetEdges.isEmpty() ) {
3269 RefEdge edge = workSetEdges.iterator().next();
3270 workSetEdges.remove( edge );
3272 Iterator<RefEdge> itrPrime = edge.getDst().iteratorToReferencees();
3273 while( itrPrime.hasNext() ) {
3274 RefEdge edgePrime = itrPrime.next();
3276 ReachSet prevResult = boldB_f.get( edgePrime );
3277 ReachSet intersection = Canonical.intersection( boldB_f.get( edge ),
3281 if( prevResult == null ||
3282 Canonical.unionORpreds( prevResult,
3283 intersection ).size()
3287 if( prevResult == null ) {
3288 boldB_f.put( edgePrime,
3289 Canonical.unionORpreds( edgePrime.getBeta(),
3294 boldB_f.put( edgePrime,
3295 Canonical.unionORpreds( prevResult,
3300 workSetEdges.add( edgePrime );
3307 boldBic.put( hrnID, boldB_f );
3309 boldBooc.put( hrnID, boldB_f );
3314 // use boldB to prune hrnIDs from alpha states that are impossible
3315 // and propagate the differences backwards across edges
3316 HashSet<RefEdge> edgesForPropagation = new HashSet<RefEdge>();
3318 Hashtable<RefEdge, ChangeSet> edgePlannedChanges =
3319 new Hashtable<RefEdge, ChangeSet>();
3322 itrHrns = id2hrn.entrySet().iterator();
3323 while( itrHrns.hasNext() ) {
3324 Map.Entry me = (Map.Entry) itrHrns.next();
3325 Integer hrnID = (Integer) me.getKey();
3326 HeapRegionNode hrn = (HeapRegionNode) me.getValue();
3328 // out-of-context nodes don't participate in the
3329 // global sweep, they serve as sources for the pass
3331 if( hrn.isOutOfContext() ) {
3335 // the inherent states of a region are the exception
3336 // to removal as the global sweep prunes
3337 ReachTuple rtException = ReachTuple.factory( hrnID,
3338 !hrn.isSingleObject(),
3339 ReachTuple.ARITY_ONE,
3340 false // out-of-context
3343 ChangeSet cts = ChangeSet.factory();
3345 // mark hrnIDs for removal
3346 Iterator<ReachState> stateItr = hrn.getAlpha().iterator();
3347 while( stateItr.hasNext() ) {
3348 ReachState stateOld = stateItr.next();
3350 ReachState markedHrnIDs = ReachState.factory();
3352 Iterator<ReachTuple> rtItr = stateOld.iterator();
3353 while( rtItr.hasNext() ) {
3354 ReachTuple rtOld = rtItr.next();
3356 // never remove the inherent hrnID from a flagged region
3357 // because it is trivially satisfied
3358 if( hrn.isFlagged() ) {
3359 if( rtOld == rtException ) {
3364 // does boldB allow this hrnID?
3365 boolean foundState = false;
3366 Iterator<RefEdge> incidentEdgeItr = hrn.iteratorToReferencers();
3367 while( incidentEdgeItr.hasNext() ) {
3368 RefEdge incidentEdge = incidentEdgeItr.next();
3370 Hashtable<RefEdge, ReachSet> B;
3371 if( rtOld.isOutOfContext() ) {
3372 B = boldBooc.get( rtOld.getHrnID() );
3375 if( !id2hrn.containsKey( rtOld.getHrnID() ) ) {
3376 // let symbols not in the graph get pruned
3380 B = boldBic.get( rtOld.getHrnID() );
3384 ReachSet boldB_rtOld_incident = B.get( incidentEdge );
3385 if( boldB_rtOld_incident != null &&
3386 boldB_rtOld_incident.containsIgnorePreds( stateOld ) != null
3394 markedHrnIDs = Canonical.addUpArity( markedHrnIDs, rtOld );
3398 // if there is nothing marked, just move on
3399 if( markedHrnIDs.isEmpty() ) {
3400 hrn.setAlphaNew( Canonical.add( hrn.getAlphaNew(),
3407 // remove all marked hrnIDs and establish a change set that should
3408 // propagate backwards over edges from this node
3409 ReachState statePruned = ReachState.factory();
3410 rtItr = stateOld.iterator();
3411 while( rtItr.hasNext() ) {
3412 ReachTuple rtOld = rtItr.next();
3414 if( !markedHrnIDs.containsTuple( rtOld ) ) {
3415 statePruned = Canonical.addUpArity( statePruned, rtOld );
3418 assert !stateOld.equals( statePruned );
3420 hrn.setAlphaNew( Canonical.add( hrn.getAlphaNew(),
3424 ChangeTuple ct = ChangeTuple.factory( stateOld,
3427 cts = Canonical.add( cts, ct );
3430 // throw change tuple set on all incident edges
3431 if( !cts.isEmpty() ) {
3432 Iterator<RefEdge> incidentEdgeItr = hrn.iteratorToReferencers();
3433 while( incidentEdgeItr.hasNext() ) {
3434 RefEdge incidentEdge = incidentEdgeItr.next();
3436 edgesForPropagation.add( incidentEdge );
3438 if( edgePlannedChanges.get( incidentEdge ) == null ) {
3439 edgePlannedChanges.put( incidentEdge, cts );
3441 edgePlannedChanges.put(
3443 Canonical.union( edgePlannedChanges.get( incidentEdge ),
3452 HashSet<RefEdge> edgesUpdated = new HashSet<RefEdge>();
3454 propagateTokensOverEdges( edgesForPropagation,
3458 // at the end of the 1st phase reference edges have
3459 // beta, betaNew that correspond to beta and betaR
3461 // commit beta<-betaNew, so beta=betaR and betaNew
3462 // will represent the beta' calculation in 2nd phase
3464 // commit alpha<-alphaNew because it won't change
3465 HashSet<RefEdge> res = new HashSet<RefEdge>();
3467 Iterator<HeapRegionNode> nodeItr = id2hrn.values().iterator();
3468 while( nodeItr.hasNext() ) {
3469 HeapRegionNode hrn = nodeItr.next();
3471 // as mentioned above, out-of-context nodes only serve
3472 // as sources of reach states for the sweep, not part
3474 if( hrn.isOutOfContext() ) {
3475 assert hrn.getAlphaNew().equals( rsetEmpty );
3477 hrn.applyAlphaNew();
3480 Iterator<RefEdge> itrRes = hrn.iteratorToReferencers();
3481 while( itrRes.hasNext() ) {
3482 res.add( itrRes.next() );
3488 Iterator<RefEdge> edgeItr = res.iterator();
3489 while( edgeItr.hasNext() ) {
3490 RefEdge edge = edgeItr.next();
3491 HeapRegionNode hrn = edge.getDst();
3493 // commit results of last phase
3494 if( edgesUpdated.contains( edge ) ) {
3495 edge.applyBetaNew();
3498 // compute intial condition of 2nd phase
3499 edge.setBetaNew( Canonical.intersection( edge.getBeta(),
3505 // every edge in the graph is the initial workset
3506 Set<RefEdge> edgeWorkSet = (Set) res.clone();
3507 while( !edgeWorkSet.isEmpty() ) {
3508 RefEdge edgePrime = edgeWorkSet.iterator().next();
3509 edgeWorkSet.remove( edgePrime );
3511 RefSrcNode rsn = edgePrime.getSrc();
3512 if( !(rsn instanceof HeapRegionNode) ) {
3515 HeapRegionNode hrn = (HeapRegionNode) rsn;
3517 Iterator<RefEdge> itrEdge = hrn.iteratorToReferencers();
3518 while( itrEdge.hasNext() ) {
3519 RefEdge edge = itrEdge.next();
3521 ReachSet prevResult = edge.getBetaNew();
3522 assert prevResult != null;
3524 ReachSet intersection =
3525 Canonical.intersection( edge.getBeta(),
3526 edgePrime.getBetaNew()
3529 if( Canonical.unionORpreds( prevResult,
3536 Canonical.unionORpreds( prevResult,
3540 edgeWorkSet.add( edge );
3545 // commit beta' (beta<-betaNew)
3546 edgeItr = res.iterator();
3547 while( edgeItr.hasNext() ) {
3548 edgeItr.next().applyBetaNew();
3553 // a useful assertion for debugging:
3554 // every in-context tuple on any edge or
3555 // any node should name a node that is
3556 // part of the graph
3557 public boolean inContextTuplesInGraph() {
3559 Iterator hrnItr = id2hrn.entrySet().iterator();
3560 while( hrnItr.hasNext() ) {
3561 Map.Entry me = (Map.Entry) hrnItr.next();
3562 HeapRegionNode hrn = (HeapRegionNode) me.getValue();
3565 Iterator<ReachState> stateItr = hrn.getAlpha().iterator();
3566 while( stateItr.hasNext() ) {
3567 ReachState state = stateItr.next();
3569 Iterator<ReachTuple> rtItr = state.iterator();
3570 while( rtItr.hasNext() ) {
3571 ReachTuple rt = rtItr.next();
3573 if( !rt.isOutOfContext() ) {
3574 if( !id2hrn.containsKey( rt.getHrnID() ) ) {
3575 System.out.println( rt.getHrnID()+" is missing" );
3583 Iterator<RefEdge> edgeItr = hrn.iteratorToReferencers();
3584 while( edgeItr.hasNext() ) {
3585 RefEdge edge = edgeItr.next();
3587 Iterator<ReachState> stateItr = edge.getBeta().iterator();
3588 while( stateItr.hasNext() ) {
3589 ReachState state = stateItr.next();
3591 Iterator<ReachTuple> rtItr = state.iterator();
3592 while( rtItr.hasNext() ) {
3593 ReachTuple rt = rtItr.next();
3595 if( !rt.isOutOfContext() ) {
3596 if( !id2hrn.containsKey( rt.getHrnID() ) ) {
3597 System.out.println( rt.getHrnID()+" is missing" );
3610 // another useful assertion for debugging
3611 public boolean noEmptyReachSetsInGraph() {
3613 Iterator hrnItr = id2hrn.entrySet().iterator();
3614 while( hrnItr.hasNext() ) {
3615 Map.Entry me = (Map.Entry) hrnItr.next();
3616 HeapRegionNode hrn = (HeapRegionNode) me.getValue();
3618 if( !hrn.isOutOfContext() &&
3620 hrn.getAlpha().isEmpty()
3622 System.out.println( "!!! "+hrn+" has an empty ReachSet !!!" );
3626 Iterator<RefEdge> edgeItr = hrn.iteratorToReferencers();
3627 while( edgeItr.hasNext() ) {
3628 RefEdge edge = edgeItr.next();
3630 if( edge.getBeta().isEmpty() ) {
3631 System.out.println( "!!! "+edge+" has an empty ReachSet !!!" );
3641 public boolean everyReachStateWTrue() {
3643 Iterator hrnItr = id2hrn.entrySet().iterator();
3644 while( hrnItr.hasNext() ) {
3645 Map.Entry me = (Map.Entry) hrnItr.next();
3646 HeapRegionNode hrn = (HeapRegionNode) me.getValue();
3649 Iterator<ReachState> stateItr = hrn.getAlpha().iterator();
3650 while( stateItr.hasNext() ) {
3651 ReachState state = stateItr.next();
3653 if( !state.getPreds().equals( predsTrue ) ) {
3659 Iterator<RefEdge> edgeItr = hrn.iteratorToReferencers();
3660 while( edgeItr.hasNext() ) {
3661 RefEdge edge = edgeItr.next();
3663 Iterator<ReachState> stateItr = edge.getBeta().iterator();
3664 while( stateItr.hasNext() ) {
3665 ReachState state = stateItr.next();
3667 if( !state.getPreds().equals( predsTrue ) ) {
3680 ////////////////////////////////////////////////////
3681 // in merge() and equals() methods the suffix A
3682 // represents the passed in graph and the suffix
3683 // B refers to the graph in this object
3684 // Merging means to take the incoming graph A and
3685 // merge it into B, so after the operation graph B
3686 // is the final result.
3687 ////////////////////////////////////////////////////
3688 protected void merge( ReachGraph rg ) {
3695 mergeRefEdges ( rg );
3696 mergeAllocSites ( rg );
3697 mergeInaccessibleVars( rg );
3700 protected void mergeNodes( ReachGraph rg ) {
3702 // start with heap region nodes
3703 Set sA = rg.id2hrn.entrySet();
3704 Iterator iA = sA.iterator();
3705 while( iA.hasNext() ) {
3706 Map.Entry meA = (Map.Entry) iA.next();
3707 Integer idA = (Integer) meA.getKey();
3708 HeapRegionNode hrnA = (HeapRegionNode) meA.getValue();
3710 // if this graph doesn't have a node the
3711 // incoming graph has, allocate it
3712 if( !id2hrn.containsKey( idA ) ) {
3713 HeapRegionNode hrnB = hrnA.copy();
3714 id2hrn.put( idA, hrnB );
3717 // otherwise this is a node present in both graphs
3718 // so make the new reachability set a union of the
3719 // nodes' reachability sets
3720 HeapRegionNode hrnB = id2hrn.get( idA );
3721 hrnB.setAlpha( Canonical.unionORpreds( hrnB.getAlpha(),
3726 hrnB.setPreds( Canonical.join( hrnB.getPreds(),
3733 if( !hrnA.equals( hrnB ) ) {
3734 rg.writeGraph( "graphA" );
3735 this.writeGraph( "graphB" );
3736 throw new Error( "flagged not matching" );
3744 // now add any variable nodes that are in graph B but
3746 sA = rg.td2vn.entrySet();
3748 while( iA.hasNext() ) {
3749 Map.Entry meA = (Map.Entry) iA.next();
3750 TempDescriptor tdA = (TempDescriptor) meA.getKey();
3751 VariableNode lnA = (VariableNode) meA.getValue();
3753 // if the variable doesn't exist in B, allocate and add it
3754 VariableNode lnB = getVariableNodeFromTemp( tdA );
3758 protected void mergeRefEdges( ReachGraph rg ) {
3760 // between heap regions
3761 Set sA = rg.id2hrn.entrySet();
3762 Iterator iA = sA.iterator();
3763 while( iA.hasNext() ) {
3764 Map.Entry meA = (Map.Entry) iA.next();
3765 Integer idA = (Integer) meA.getKey();
3766 HeapRegionNode hrnA = (HeapRegionNode) meA.getValue();
3768 Iterator<RefEdge> heapRegionsItrA = hrnA.iteratorToReferencees();
3769 while( heapRegionsItrA.hasNext() ) {
3770 RefEdge edgeA = heapRegionsItrA.next();
3771 HeapRegionNode hrnChildA = edgeA.getDst();
3772 Integer idChildA = hrnChildA.getID();
3774 // at this point we know an edge in graph A exists
3775 // idA -> idChildA, does this exist in B?
3776 assert id2hrn.containsKey( idA );
3777 HeapRegionNode hrnB = id2hrn.get( idA );
3778 RefEdge edgeToMerge = null;
3780 Iterator<RefEdge> heapRegionsItrB = hrnB.iteratorToReferencees();
3781 while( heapRegionsItrB.hasNext() &&
3782 edgeToMerge == null ) {
3784 RefEdge edgeB = heapRegionsItrB.next();
3785 HeapRegionNode hrnChildB = edgeB.getDst();
3786 Integer idChildB = hrnChildB.getID();
3788 // don't use the RefEdge.equals() here because
3789 // we're talking about existence between graphs,
3790 // not intragraph equal
3791 if( idChildB.equals( idChildA ) &&
3792 edgeB.typeAndFieldEquals( edgeA ) ) {
3794 edgeToMerge = edgeB;
3798 // if the edge from A was not found in B,
3800 if( edgeToMerge == null ) {
3801 assert id2hrn.containsKey( idChildA );
3802 HeapRegionNode hrnChildB = id2hrn.get( idChildA );
3803 edgeToMerge = edgeA.copy();
3804 edgeToMerge.setSrc( hrnB );
3805 edgeToMerge.setDst( hrnChildB );
3806 addRefEdge( hrnB, hrnChildB, edgeToMerge );
3808 // otherwise, the edge already existed in both graphs
3809 // so merge their reachability sets
3811 // just replace this beta set with the union
3812 assert edgeToMerge != null;
3813 edgeToMerge.setBeta(
3814 Canonical.unionORpreds( edgeToMerge.getBeta(),
3818 edgeToMerge.setPreds(
3819 Canonical.join( edgeToMerge.getPreds(),
3823 edgeToMerge.setTaints(
3824 Canonical.union( edgeToMerge.getTaints(),
3832 // and then again from variable nodes
3833 sA = rg.td2vn.entrySet();
3835 while( iA.hasNext() ) {
3836 Map.Entry meA = (Map.Entry) iA.next();
3837 TempDescriptor tdA = (TempDescriptor) meA.getKey();
3838 VariableNode vnA = (VariableNode) meA.getValue();
3840 Iterator<RefEdge> heapRegionsItrA = vnA.iteratorToReferencees();
3841 while( heapRegionsItrA.hasNext() ) {
3842 RefEdge edgeA = heapRegionsItrA.next();
3843 HeapRegionNode hrnChildA = edgeA.getDst();
3844 Integer idChildA = hrnChildA.getID();
3846 // at this point we know an edge in graph A exists
3847 // tdA -> idChildA, does this exist in B?
3848 assert td2vn.containsKey( tdA );
3849 VariableNode vnB = td2vn.get( tdA );
3850 RefEdge edgeToMerge = null;
3852 Iterator<RefEdge> heapRegionsItrB = vnB.iteratorToReferencees();
3853 while( heapRegionsItrB.hasNext() &&
3854 edgeToMerge == null ) {
3856 RefEdge edgeB = heapRegionsItrB.next();
3857 HeapRegionNode hrnChildB = edgeB.getDst();
3858 Integer idChildB = hrnChildB.getID();
3860 // don't use the RefEdge.equals() here because
3861 // we're talking about existence between graphs
3862 if( idChildB.equals( idChildA ) &&
3863 edgeB.typeAndFieldEquals( edgeA ) ) {
3865 edgeToMerge = edgeB;
3869 // if the edge from A was not found in B,
3871 if( edgeToMerge == null ) {
3872 assert id2hrn.containsKey( idChildA );
3873 HeapRegionNode hrnChildB = id2hrn.get( idChildA );
3874 edgeToMerge = edgeA.copy();
3875 edgeToMerge.setSrc( vnB );
3876 edgeToMerge.setDst( hrnChildB );
3877 addRefEdge( vnB, hrnChildB, edgeToMerge );
3879 // otherwise, the edge already existed in both graphs
3880 // so merge their reachability sets
3882 // just replace this beta set with the union
3883 edgeToMerge.setBeta( Canonical.unionORpreds( edgeToMerge.getBeta(),
3887 edgeToMerge.setPreds( Canonical.join( edgeToMerge.getPreds(),
3891 edgeToMerge.setTaints(
3892 Canonical.union( edgeToMerge.getTaints(),
3901 protected void mergeAllocSites( ReachGraph rg ) {
3902 allocSites.addAll( rg.allocSites );
3905 protected void mergeInaccessibleVars( ReachGraph rg ){
3906 inaccessibleVars.addAll(rg.inaccessibleVars);
3911 static boolean dbgEquals = false;
3914 // it is necessary in the equals() member functions
3915 // to "check both ways" when comparing the data
3916 // structures of two graphs. For instance, if all
3917 // edges between heap region nodes in graph A are
3918 // present and equal in graph B it is not sufficient
3919 // to say the graphs are equal. Consider that there
3920 // may be edges in graph B that are not in graph A.
3921 // the only way to know that all edges in both graphs
3922 // are equally present is to iterate over both data
3923 // structures and compare against the other graph.
3924 public boolean equals( ReachGraph rg ) {
3928 System.out.println( "rg is null" );
3933 if( !areHeapRegionNodesEqual( rg ) ) {
3935 System.out.println( "hrn not equal" );
3940 if( !areVariableNodesEqual( rg ) ) {
3942 System.out.println( "vars not equal" );
3947 if( !areRefEdgesEqual( rg ) ) {
3949 System.out.println( "edges not equal" );
3954 if( !inaccessibleVars.equals(rg.inaccessibleVars) ){
3958 // if everything is equal up to this point,
3959 // assert that allocSites is also equal--
3960 // this data is redundant but kept for efficiency
3961 assert allocSites.equals( rg.allocSites );
3967 protected boolean areHeapRegionNodesEqual( ReachGraph rg ) {
3969 if( !areallHRNinAalsoinBandequal( this, rg ) ) {
3973 if( !areallHRNinAalsoinBandequal( rg, this ) ) {
3980 static protected boolean areallHRNinAalsoinBandequal( ReachGraph rgA,
3982 Set sA = rgA.id2hrn.entrySet();
3983 Iterator iA = sA.iterator();
3984 while( iA.hasNext() ) {
3985 Map.Entry meA = (Map.Entry) iA.next();
3986 Integer idA = (Integer) meA.getKey();
3987 HeapRegionNode hrnA = (HeapRegionNode) meA.getValue();
3989 if( !rgB.id2hrn.containsKey( idA ) ) {
3993 HeapRegionNode hrnB = rgB.id2hrn.get( idA );
3994 if( !hrnA.equalsIncludingAlphaAndPreds( hrnB ) ) {
4002 protected boolean areVariableNodesEqual( ReachGraph rg ) {
4004 if( !areallVNinAalsoinBandequal( this, rg ) ) {
4008 if( !areallVNinAalsoinBandequal( rg, this ) ) {
4015 static protected boolean areallVNinAalsoinBandequal( ReachGraph rgA,
4017 Set sA = rgA.td2vn.entrySet();
4018 Iterator iA = sA.iterator();
4019 while( iA.hasNext() ) {
4020 Map.Entry meA = (Map.Entry) iA.next();
4021 TempDescriptor tdA = (TempDescriptor) meA.getKey();
4023 if( !rgB.td2vn.containsKey( tdA ) ) {
4032 protected boolean areRefEdgesEqual( ReachGraph rg ) {
4033 if( !areallREinAandBequal( this, rg ) ) {
4037 if( !areallREinAandBequal( rg, this ) ) {
4044 static protected boolean areallREinAandBequal( ReachGraph rgA,
4047 // check all the heap region->heap region edges
4048 Set sA = rgA.id2hrn.entrySet();
4049 Iterator iA = sA.iterator();
4050 while( iA.hasNext() ) {
4051 Map.Entry meA = (Map.Entry) iA.next();
4052 Integer idA = (Integer) meA.getKey();
4053 HeapRegionNode hrnA = (HeapRegionNode) meA.getValue();
4055 // we should have already checked that the same
4056 // heap regions exist in both graphs
4057 assert rgB.id2hrn.containsKey( idA );
4059 if( !areallREfromAequaltoB( rgA, hrnA, rgB ) ) {
4063 // then check every edge in B for presence in A, starting
4064 // from the same parent HeapRegionNode
4065 HeapRegionNode hrnB = rgB.id2hrn.get( idA );
4067 if( !areallREfromAequaltoB( rgB, hrnB, rgA ) ) {
4072 // then check all the variable->heap region edges
4073 sA = rgA.td2vn.entrySet();
4075 while( iA.hasNext() ) {
4076 Map.Entry meA = (Map.Entry) iA.next();
4077 TempDescriptor tdA = (TempDescriptor) meA.getKey();
4078 VariableNode vnA = (VariableNode) meA.getValue();
4080 // we should have already checked that the same
4081 // label nodes exist in both graphs
4082 assert rgB.td2vn.containsKey( tdA );
4084 if( !areallREfromAequaltoB( rgA, vnA, rgB ) ) {
4088 // then check every edge in B for presence in A, starting
4089 // from the same parent VariableNode
4090 VariableNode vnB = rgB.td2vn.get( tdA );
4092 if( !areallREfromAequaltoB( rgB, vnB, rgA ) ) {
4101 static protected boolean areallREfromAequaltoB( ReachGraph rgA,
4105 Iterator<RefEdge> itrA = rnA.iteratorToReferencees();
4106 while( itrA.hasNext() ) {
4107 RefEdge edgeA = itrA.next();
4108 HeapRegionNode hrnChildA = edgeA.getDst();
4109 Integer idChildA = hrnChildA.getID();
4111 assert rgB.id2hrn.containsKey( idChildA );
4113 // at this point we know an edge in graph A exists
4114 // rnA -> idChildA, does this exact edge exist in B?
4115 boolean edgeFound = false;
4117 RefSrcNode rnB = null;
4118 if( rnA instanceof HeapRegionNode ) {
4119 HeapRegionNode hrnA = (HeapRegionNode) rnA;
4120 rnB = rgB.id2hrn.get( hrnA.getID() );
4122 VariableNode vnA = (VariableNode) rnA;
4123 rnB = rgB.td2vn.get( vnA.getTempDescriptor() );
4126 Iterator<RefEdge> itrB = rnB.iteratorToReferencees();
4127 while( itrB.hasNext() ) {
4128 RefEdge edgeB = itrB.next();
4129 HeapRegionNode hrnChildB = edgeB.getDst();
4130 Integer idChildB = hrnChildB.getID();
4132 if( idChildA.equals( idChildB ) &&
4133 edgeA.typeAndFieldEquals( edgeB ) ) {
4135 // there is an edge in the right place with the right field,
4136 // but do they have the same attributes?
4137 if( edgeA.getBeta().equals( edgeB.getBeta() ) &&
4138 edgeA.equalsPreds( edgeB )
4154 // can be used to assert monotonicity
4155 static public boolean isNoSmallerThan( ReachGraph rgA,
4158 //System.out.println( "*** Asking if A is no smaller than B ***" );
4161 Iterator iA = rgA.id2hrn.entrySet().iterator();
4162 while( iA.hasNext() ) {
4163 Map.Entry meA = (Map.Entry) iA.next();
4164 Integer idA = (Integer) meA.getKey();
4165 HeapRegionNode hrnA = (HeapRegionNode) meA.getValue();
4167 if( !rgB.id2hrn.containsKey( idA ) ) {
4168 System.out.println( " regions smaller" );
4172 //HeapRegionNode hrnB = rgB.id2hrn.get( idA );
4173 /* NOT EQUALS, NO SMALLER THAN!
4174 if( !hrnA.equalsIncludingAlphaAndPreds( hrnB ) ) {
4175 System.out.println( " regions smaller" );
4181 // this works just fine, no smaller than
4182 if( !areallVNinAalsoinBandequal( rgA, rgB ) ) {
4183 System.out.println( " vars smaller:" );
4184 System.out.println( " A:"+rgA.td2vn.keySet() );
4185 System.out.println( " B:"+rgB.td2vn.keySet() );
4190 iA = rgA.id2hrn.entrySet().iterator();
4191 while( iA.hasNext() ) {
4192 Map.Entry meA = (Map.Entry) iA.next();
4193 Integer idA = (Integer) meA.getKey();
4194 HeapRegionNode hrnA = (HeapRegionNode) meA.getValue();
4196 Iterator<RefEdge> reItr = hrnA.iteratorToReferencers();
4197 while( reItr.hasNext() ) {
4198 RefEdge edgeA = reItr.next();
4199 RefSrcNode rsnA = edgeA.getSrc();
4201 // we already checked that nodes were present
4202 HeapRegionNode hrnB = rgB.id2hrn.get( hrnA.getID() );
4203 assert hrnB != null;
4206 if( rsnA instanceof VariableNode ) {
4207 VariableNode vnA = (VariableNode) rsnA;
4208 rsnB = rgB.td2vn.get( vnA.getTempDescriptor() );
4211 HeapRegionNode hrnSrcA = (HeapRegionNode) rsnA;
4212 rsnB = rgB.id2hrn.get( hrnSrcA.getID() );
4214 assert rsnB != null;
4216 RefEdge edgeB = rsnB.getReferenceTo( hrnB,
4220 if( edgeB == null ) {
4221 System.out.println( " edges smaller:" );
4225 // REMEMBER, IS NO SMALLER THAN
4227 System.out.println( " edges smaller" );
4243 // this analysis no longer has the "match anything"
4244 // type which was represented by null
4245 protected TypeDescriptor mostSpecificType( TypeDescriptor td1,
4246 TypeDescriptor td2 ) {
4250 if( td1.isNull() ) {
4253 if( td2.isNull() ) {
4256 return typeUtil.mostSpecific( td1, td2 );
4259 protected TypeDescriptor mostSpecificType( TypeDescriptor td1,
4261 TypeDescriptor td3 ) {
4263 return mostSpecificType( td1,
4264 mostSpecificType( td2, td3 )
4268 protected TypeDescriptor mostSpecificType( TypeDescriptor td1,
4271 TypeDescriptor td4 ) {
4273 return mostSpecificType( mostSpecificType( td1, td2 ),
4274 mostSpecificType( td3, td4 )
4278 protected boolean isSuperiorType( TypeDescriptor possibleSuper,
4279 TypeDescriptor possibleChild ) {
4280 assert possibleSuper != null;
4281 assert possibleChild != null;
4283 if( possibleSuper.isNull() ||
4284 possibleChild.isNull() ) {
4288 return typeUtil.isSuperorType( possibleSuper, possibleChild );
4292 protected boolean hasMatchingField( HeapRegionNode src,
4295 TypeDescriptor tdSrc = src.getType();
4296 assert tdSrc != null;
4298 if( tdSrc.isArray() ) {
4299 TypeDescriptor td = edge.getType();
4302 TypeDescriptor tdSrcDeref = tdSrc.dereference();
4303 assert tdSrcDeref != null;
4305 if( !typeUtil.isSuperorType( tdSrcDeref, td ) ) {
4309 return edge.getField().equals( DisjointAnalysis.arrayElementFieldName );
4312 // if it's not a class, it doesn't have any fields to match
4313 if( !tdSrc.isClass() ) {
4317 ClassDescriptor cd = tdSrc.getClassDesc();
4318 while( cd != null ) {
4319 Iterator fieldItr = cd.getFields();
4321 while( fieldItr.hasNext() ) {
4322 FieldDescriptor fd = (FieldDescriptor) fieldItr.next();
4324 if( fd.getType().equals( edge.getType() ) &&
4325 fd.getSymbol().equals( edge.getField() ) ) {
4330 cd = cd.getSuperDesc();
4333 // otherwise it is a class with fields
4334 // but we didn't find a match
4338 protected boolean hasMatchingType( RefEdge edge,
4339 HeapRegionNode dst ) {
4341 // if the region has no type, matches everything
4342 TypeDescriptor tdDst = dst.getType();
4343 assert tdDst != null;
4345 // if the type is not a class or an array, don't
4346 // match because primitives are copied, no aliases
4347 ClassDescriptor cdDst = tdDst.getClassDesc();
4348 if( cdDst == null && !tdDst.isArray() ) {
4352 // if the edge type is null, it matches everything
4353 TypeDescriptor tdEdge = edge.getType();
4354 assert tdEdge != null;
4356 return typeUtil.isSuperorType( tdEdge, tdDst );
4361 // the default signature for quick-and-dirty debugging
4362 public void writeGraph( String graphName ) {
4363 writeGraph( graphName,
4364 true, // write labels
4365 true, // label select
4366 true, // prune garbage
4367 false, // hide reachability
4368 true, // hide subset reachability
4369 true, // hide predicates
4370 false, // hide edge taints
4371 null // in-context boundary
4375 public void writeGraph( String graphName,
4376 boolean writeLabels,
4377 boolean labelSelect,
4378 boolean pruneGarbage,
4379 boolean hideReachability,
4380 boolean hideSubsetReachability,
4381 boolean hidePredicates,
4382 boolean hideEdgeTaints
4384 writeGraph( graphName,
4389 hideSubsetReachability,
4395 public void writeGraph( String graphName,
4396 boolean writeLabels,
4397 boolean labelSelect,
4398 boolean pruneGarbage,
4399 boolean hideReachability,
4400 boolean hideSubsetReachability,
4401 boolean hidePredicates,
4402 boolean hideEdgeTaints,
4403 Set<Integer> callerNodeIDsCopiedToCallee
4407 // remove all non-word characters from the graph name so
4408 // the filename and identifier in dot don't cause errors
4409 graphName = graphName.replaceAll( "[\\W]", "" );
4412 new BufferedWriter( new FileWriter( graphName+".dot" ) );
4414 bw.write( "digraph "+graphName+" {\n" );
4417 // this is an optional step to form the callee-reachable
4418 // "cut-out" into a DOT cluster for visualization
4419 if( callerNodeIDsCopiedToCallee != null ) {
4421 bw.write( " subgraph cluster0 {\n" );
4422 bw.write( " color=blue;\n" );
4424 Iterator i = id2hrn.entrySet().iterator();
4425 while( i.hasNext() ) {
4426 Map.Entry me = (Map.Entry) i.next();
4427 HeapRegionNode hrn = (HeapRegionNode) me.getValue();
4429 if( callerNodeIDsCopiedToCallee.contains( hrn.getID() ) ) {
4432 hrn.toStringDOT( hideReachability,
4433 hideSubsetReachability,
4443 Set<HeapRegionNode> visited = new HashSet<HeapRegionNode>();
4445 // then visit every heap region node
4446 Iterator i = id2hrn.entrySet().iterator();
4447 while( i.hasNext() ) {
4448 Map.Entry me = (Map.Entry) i.next();
4449 HeapRegionNode hrn = (HeapRegionNode) me.getValue();
4451 // only visit nodes worth writing out--for instance
4452 // not every node at an allocation is referenced
4453 // (think of it as garbage-collected), etc.
4454 if( !pruneGarbage ||
4455 hrn.isOutOfContext() ||
4456 (hrn.isFlagged() && hrn.getID() > 0 && !hrn.isWiped()) // a non-shadow flagged node
4459 if( !visited.contains( hrn ) ) {
4460 traverseHeapRegionNodes( hrn,
4465 hideSubsetReachability,
4468 callerNodeIDsCopiedToCallee );
4473 bw.write( " graphTitle[label=\""+graphName+"\",shape=box];\n" );
4476 // then visit every label node, useful for debugging
4478 i = td2vn.entrySet().iterator();
4479 while( i.hasNext() ) {
4480 Map.Entry me = (Map.Entry) i.next();
4481 VariableNode vn = (VariableNode) me.getValue();
4484 String labelStr = vn.getTempDescriptorString();
4485 if( labelStr.startsWith( "___temp" ) ||
4486 labelStr.startsWith( "___dst" ) ||
4487 labelStr.startsWith( "___srctmp" ) ||
4488 labelStr.startsWith( "___neverused" )
4494 Iterator<RefEdge> heapRegionsItr = vn.iteratorToReferencees();
4495 while( heapRegionsItr.hasNext() ) {
4496 RefEdge edge = heapRegionsItr.next();
4497 HeapRegionNode hrn = edge.getDst();
4499 if( !visited.contains( hrn ) ) {
4500 traverseHeapRegionNodes( hrn,
4505 hideSubsetReachability,
4508 callerNodeIDsCopiedToCallee );
4511 bw.write( " "+vn.toString()+
4512 " -> "+hrn.toString()+
4513 edge.toStringDOT( hideReachability,
4514 hideSubsetReachability,
4526 } catch( IOException e ) {
4527 throw new Error( "Error writing out DOT graph "+graphName );
4532 traverseHeapRegionNodes( HeapRegionNode hrn,
4535 Set<HeapRegionNode> visited,
4536 boolean hideReachability,
4537 boolean hideSubsetReachability,
4538 boolean hidePredicates,
4539 boolean hideEdgeTaints,
4540 Set<Integer> callerNodeIDsCopiedToCallee
4541 ) throws java.io.IOException {
4543 if( visited.contains( hrn ) ) {
4548 // if we're drawing the callee-view subgraph, only
4549 // write out the node info if it hasn't already been
4551 if( callerNodeIDsCopiedToCallee == null ||
4552 !callerNodeIDsCopiedToCallee.contains( hrn.getID() )
4556 hrn.toStringDOT( hideReachability,
4557 hideSubsetReachability,
4562 Iterator<RefEdge> childRegionsItr = hrn.iteratorToReferencees();
4563 while( childRegionsItr.hasNext() ) {
4564 RefEdge edge = childRegionsItr.next();
4565 HeapRegionNode hrnChild = edge.getDst();
4567 if( callerNodeIDsCopiedToCallee != null &&
4568 (edge.getSrc() instanceof HeapRegionNode) ) {
4569 HeapRegionNode hrnSrc = (HeapRegionNode) edge.getSrc();
4570 if( callerNodeIDsCopiedToCallee.contains( hrnSrc.getID() ) &&
4571 callerNodeIDsCopiedToCallee.contains( edge.getDst().getID() )
4573 bw.write( " "+hrn.toString()+
4574 " -> "+hrnChild.toString()+
4575 edge.toStringDOT( hideReachability,
4576 hideSubsetReachability,
4581 } else if( !callerNodeIDsCopiedToCallee.contains( hrnSrc.getID() ) &&
4582 callerNodeIDsCopiedToCallee.contains( edge.getDst().getID() )
4584 bw.write( " "+hrn.toString()+
4585 " -> "+hrnChild.toString()+
4586 edge.toStringDOT( hideReachability,
4587 hideSubsetReachability,
4590 ",color=blue,style=dashed" )+
4593 bw.write( " "+hrn.toString()+
4594 " -> "+hrnChild.toString()+
4595 edge.toStringDOT( hideReachability,
4596 hideSubsetReachability,
4603 bw.write( " "+hrn.toString()+
4604 " -> "+hrnChild.toString()+
4605 edge.toStringDOT( hideReachability,
4606 hideSubsetReachability,
4613 traverseHeapRegionNodes( hrnChild,
4618 hideSubsetReachability,
4621 callerNodeIDsCopiedToCallee );
4630 // return the set of heap regions from the given allocation
4631 // site, if any, that exist in this graph
4632 protected Set<HeapRegionNode> getAnyExisting( AllocSite as ) {
4634 Set<HeapRegionNode> out = new HashSet<HeapRegionNode>();
4636 Integer idSum = as.getSummary();
4637 if( id2hrn.containsKey( idSum ) ) {
4638 out.add( id2hrn.get( idSum ) );
4641 for( int i = 0; i < as.getAllocationDepth(); ++i ) {
4642 Integer idI = as.getIthOldest( i );
4643 if( id2hrn.containsKey( idI ) ) {
4644 out.add( id2hrn.get( idI ) );
4651 // return the set of reach tuples (NOT A REACH STATE! JUST A SET!)
4652 // from the given allocation site, if any, from regions for that
4653 // site that exist in this graph
4654 protected Set<ReachTuple> getAnyExisting( AllocSite as,
4655 boolean includeARITY_ZEROORMORE,
4656 boolean includeARITY_ONE ) {
4658 Set<ReachTuple> out = new HashSet<ReachTuple>();
4660 Integer idSum = as.getSummary();
4661 if( id2hrn.containsKey( idSum ) ) {
4663 HeapRegionNode hrn = id2hrn.get( idSum );
4664 assert !hrn.isOutOfContext();
4666 if( !includeARITY_ZEROORMORE ) {
4667 out.add( ReachTuple.factory( hrn.getID(),
4668 true, // multi-obj region
4669 ReachTuple.ARITY_ZEROORMORE,
4674 if( includeARITY_ONE ) {
4675 out.add( ReachTuple.factory( hrn.getID(),
4676 true, // multi-object region
4677 ReachTuple.ARITY_ONE,
4683 if( !includeARITY_ONE ) {
4684 // no need to do the single-object regions that
4685 // only have an ARITY ONE possible
4689 for( int i = 0; i < as.getAllocationDepth(); ++i ) {
4691 Integer idI = as.getIthOldest( i );
4692 if( id2hrn.containsKey( idI ) ) {
4694 HeapRegionNode hrn = id2hrn.get( idI );
4695 assert !hrn.isOutOfContext();
4697 out.add( ReachTuple.factory( hrn.getID(),
4698 false, // multi-object region
4699 ReachTuple.ARITY_ONE,
4709 // if an object allocated at the target site may be
4710 // reachable from both an object from root1 and an
4711 // object allocated at root2, return TRUE
4712 public boolean mayBothReachTarget( AllocSite asRoot1,
4714 AllocSite asTarget ) {
4716 // consider all heap regions of the target and look
4717 // for a reach state that indicates regions of root1
4718 // and root2 might be able to reach same object
4719 Set<HeapRegionNode> hrnSetTarget = getAnyExisting( asTarget );
4721 // get relevant reach tuples, include ARITY_ZEROORMORE and ARITY_ONE
4722 Set<ReachTuple> rtSet1 = getAnyExisting( asRoot1, true, true );
4723 Set<ReachTuple> rtSet2 = getAnyExisting( asRoot2, true, true );
4725 Iterator<HeapRegionNode> hrnItr = hrnSetTarget.iterator();
4726 while( hrnItr.hasNext() ) {
4727 HeapRegionNode hrn = hrnItr.next();
4729 Iterator<ReachTuple> rtItr1 = rtSet1.iterator();
4730 while( rtItr1.hasNext() ) {
4731 ReachTuple rt1 = rtItr1.next();
4733 Iterator<ReachTuple> rtItr2 = rtSet2.iterator();
4734 while( rtItr2.hasNext() ) {
4735 ReachTuple rt2 = rtItr2.next();
4737 if( !hrn.getAlpha().getStatesWithBoth( rt1, rt2 ).isEmpty() ) {
4747 // similar to the method above, return TRUE if ever
4748 // more than one object from the root allocation site
4749 // may reach an object from the target site
4750 public boolean mayManyReachTarget( AllocSite asRoot,
4751 AllocSite asTarget ) {
4753 // consider all heap regions of the target and look
4754 // for a reach state that multiple objects of root
4755 // might be able to reach the same object
4756 Set<HeapRegionNode> hrnSetTarget = getAnyExisting( asTarget );
4758 // get relevant reach tuples
4759 Set<ReachTuple> rtSetZOM = getAnyExisting( asRoot, true, false );
4760 Set<ReachTuple> rtSetONE = getAnyExisting( asRoot, false, true );
4762 Iterator<HeapRegionNode> hrnItr = hrnSetTarget.iterator();
4763 while( hrnItr.hasNext() ) {
4764 HeapRegionNode hrn = hrnItr.next();
4766 // if any ZERORMORE tuples are here, TRUE
4767 Iterator<ReachTuple> rtItr = rtSetZOM.iterator();
4768 while( rtItr.hasNext() ) {
4769 ReachTuple rtZOM = rtItr.next();
4771 if( hrn.getAlpha().containsTuple( rtZOM ) ) {
4776 // otherwise, look for any pair of ONE tuples
4777 Iterator<ReachTuple> rtItr1 = rtSetONE.iterator();
4778 while( rtItr1.hasNext() ) {
4779 ReachTuple rt1 = rtItr1.next();
4781 Iterator<ReachTuple> rtItr2 = rtSetONE.iterator();
4782 while( rtItr2.hasNext() ) {
4783 ReachTuple rt2 = rtItr2.next();
4789 if( !hrn.getAlpha().getStatesWithBoth( rt1, rt2 ).isEmpty() ) {
4803 public Set<HeapRegionNode> findCommonReachableNodes( ReachSet proofOfSharing ) {
4805 Set<HeapRegionNode> exhibitProofState =
4806 new HashSet<HeapRegionNode>();
4808 Iterator hrnItr = id2hrn.entrySet().iterator();
4809 while( hrnItr.hasNext() ) {
4810 Map.Entry me = (Map.Entry) hrnItr.next();
4811 HeapRegionNode hrn = (HeapRegionNode) me.getValue();
4813 ReachSet intersection =
4814 Canonical.intersection( proofOfSharing,
4817 if( !intersection.isEmpty() ) {
4818 assert !hrn.isOutOfContext();
4819 exhibitProofState.add( hrn );
4823 return exhibitProofState;
4827 public Set<HeapRegionNode> mayReachSharedObjects(HeapRegionNode hrn1,
4828 HeapRegionNode hrn2) {
4829 assert hrn1 != null;
4830 assert hrn2 != null;
4832 assert !hrn1.isOutOfContext();
4833 assert !hrn2.isOutOfContext();
4835 assert belongsToThis( hrn1 );
4836 assert belongsToThis( hrn2 );
4838 assert !hrn1.getID().equals( hrn2.getID() );
4841 // then get the various tokens for these heap regions
4843 ReachTuple.factory( hrn1.getID(),
4844 !hrn1.isSingleObject(), // multi?
4845 ReachTuple.ARITY_ONE,
4848 ReachTuple h1star = null;
4849 if( !hrn1.isSingleObject() ) {
4851 ReachTuple.factory( hrn1.getID(),
4852 !hrn1.isSingleObject(),
4853 ReachTuple.ARITY_ZEROORMORE,
4858 ReachTuple.factory( hrn2.getID(),
4859 !hrn2.isSingleObject(),
4860 ReachTuple.ARITY_ONE,
4863 ReachTuple h2star = null;
4864 if( !hrn2.isSingleObject() ) {
4866 ReachTuple.factory( hrn2.getID(),
4867 !hrn2.isSingleObject(),
4868 ReachTuple.ARITY_ZEROORMORE,
4872 // then get the merged beta of all out-going edges from these heap
4875 ReachSet beta1 = ReachSet.factory();
4876 Iterator<RefEdge> itrEdge = hrn1.iteratorToReferencees();
4877 while (itrEdge.hasNext()) {
4878 RefEdge edge = itrEdge.next();
4879 beta1 = Canonical.unionORpreds(beta1, edge.getBeta());
4882 ReachSet beta2 = ReachSet.factory();
4883 itrEdge = hrn2.iteratorToReferencees();
4884 while (itrEdge.hasNext()) {
4885 RefEdge edge = itrEdge.next();
4886 beta2 = Canonical.unionORpreds(beta2, edge.getBeta());
4889 ReachSet proofOfSharing = ReachSet.factory();
4892 Canonical.unionORpreds( proofOfSharing,
4893 beta1.getStatesWithBoth( h1, h2 )
4896 Canonical.unionORpreds( proofOfSharing,
4897 beta2.getStatesWithBoth( h1, h2 )
4900 if( !hrn1.isSingleObject() ) {
4902 Canonical.unionORpreds( proofOfSharing,
4903 beta1.getStatesWithBoth( h1star, h2 )
4906 Canonical.unionORpreds( proofOfSharing,
4907 beta2.getStatesWithBoth( h1star, h2 )
4911 if( !hrn2.isSingleObject() ) {
4913 Canonical.unionORpreds( proofOfSharing,
4914 beta1.getStatesWithBoth( h1, h2star )
4917 Canonical.unionORpreds( proofOfSharing,
4918 beta2.getStatesWithBoth( h1, h2star )
4922 if( !hrn1.isSingleObject() &&
4923 !hrn2.isSingleObject()
4926 Canonical.unionORpreds( proofOfSharing,
4927 beta1.getStatesWithBoth( h1star, h2star )
4930 Canonical.unionORpreds( proofOfSharing,
4931 beta2.getStatesWithBoth( h1star, h2star )
4935 Set<HeapRegionNode> common = new HashSet<HeapRegionNode>();
4936 if( !proofOfSharing.isEmpty() ) {
4937 common = findCommonReachableNodes( proofOfSharing );
4938 if( !DISABLE_STRONG_UPDATES &&
4939 !DISABLE_GLOBAL_SWEEP
4941 assert !common.isEmpty();
4948 // this version of the above method checks whether there is sharing
4949 // among the objects in a summary node
4950 public Set<HeapRegionNode> mayReachSharedObjects(HeapRegionNode hrn) {
4952 assert hrn.isNewSummary();
4953 assert !hrn.isOutOfContext();
4954 assert belongsToThis( hrn );
4957 ReachTuple.factory( hrn.getID(),
4959 ReachTuple.ARITY_ZEROORMORE,
4962 // then get the merged beta of all out-going edges from
4965 ReachSet beta = ReachSet.factory();
4966 Iterator<RefEdge> itrEdge = hrn.iteratorToReferencees();
4967 while (itrEdge.hasNext()) {
4968 RefEdge edge = itrEdge.next();
4969 beta = Canonical.unionORpreds(beta, edge.getBeta());
4972 ReachSet proofOfSharing = ReachSet.factory();
4975 Canonical.unionORpreds( proofOfSharing,
4976 beta.getStatesWithBoth( hstar, hstar )
4979 Set<HeapRegionNode> common = new HashSet<HeapRegionNode>();
4980 if( !proofOfSharing.isEmpty() ) {
4981 common = findCommonReachableNodes( proofOfSharing );
4982 if( !DISABLE_STRONG_UPDATES &&
4983 !DISABLE_GLOBAL_SWEEP
4985 assert !common.isEmpty();
4993 public Set<HeapRegionNode> mayReachSharedObjects(FlatMethod fm,
4994 Integer paramIndex1,
4995 Integer paramIndex2) {
4997 // get parameter's heap regions
4998 TempDescriptor paramTemp1 = fm.getParameter(paramIndex1.intValue());
4999 assert this.hasVariable( paramTemp1 );
5000 VariableNode paramVar1 = getVariableNodeFromTemp(paramTemp1);
5003 if( !(paramVar1.getNumReferencees() == 1) ) {
5004 System.out.println( "\n fm="+fm+"\n param="+paramTemp1 );
5005 writeGraph( "whatup" );
5009 assert paramVar1.getNumReferencees() == 1;
5010 RefEdge paramEdge1 = paramVar1.iteratorToReferencees().next();
5011 HeapRegionNode hrnParam1 = paramEdge1.getDst();
5013 TempDescriptor paramTemp2 = fm.getParameter(paramIndex2.intValue());
5014 assert this.hasVariable( paramTemp2 );
5015 VariableNode paramVar2 = getVariableNodeFromTemp(paramTemp2);
5017 if( !(paramVar2.getNumReferencees() == 1) ) {
5018 System.out.println( "\n fm="+fm+"\n param="+paramTemp2 );
5019 writeGraph( "whatup" );
5022 assert paramVar2.getNumReferencees() == 1;
5023 RefEdge paramEdge2 = paramVar2.iteratorToReferencees().next();
5024 HeapRegionNode hrnParam2 = paramEdge2.getDst();
5026 Set<HeapRegionNode> common = new HashSet<HeapRegionNode>();
5027 common.addAll(mayReachSharedObjects(hrnParam1, hrnParam2));
5032 public Set<HeapRegionNode> mayReachSharedObjects(FlatMethod fm,
5036 // get parameter's heap regions
5037 TempDescriptor paramTemp = fm.getParameter(paramIndex.intValue());
5038 assert this.hasVariable( paramTemp );
5039 VariableNode paramVar = getVariableNodeFromTemp(paramTemp);
5040 assert paramVar.getNumReferencees() == 1;
5041 RefEdge paramEdge = paramVar.iteratorToReferencees().next();
5042 HeapRegionNode hrnParam = paramEdge.getDst();
5045 HeapRegionNode hrnSummary=null;
5046 if(id2hrn.containsKey(as.getSummary())){
5047 // if summary node doesn't exist, ignore this case
5048 hrnSummary = id2hrn.get(as.getSummary());
5049 assert hrnSummary != null;
5052 Set<HeapRegionNode> common = new HashSet<HeapRegionNode>();
5053 if(hrnSummary!=null){
5054 common.addAll( mayReachSharedObjects(hrnParam, hrnSummary) );
5057 // check for other nodes
5058 for (int i = 0; i < as.getAllocationDepth(); ++i) {
5060 assert id2hrn.containsKey(as.getIthOldest(i));
5061 HeapRegionNode hrnIthOldest = id2hrn.get(as.getIthOldest(i));
5062 assert hrnIthOldest != null;
5064 common.addAll(mayReachSharedObjects(hrnParam, hrnIthOldest));
5071 public Set<HeapRegionNode> mayReachSharedObjects(AllocSite as1,
5074 // get summary node 1's alpha
5075 Integer idSum1 = as1.getSummary();
5076 HeapRegionNode hrnSum1=null;
5077 if(id2hrn.containsKey(idSum1)){
5078 hrnSum1 = id2hrn.get(idSum1);
5081 // get summary node 2's alpha
5082 Integer idSum2 = as2.getSummary();
5083 HeapRegionNode hrnSum2=null;
5084 if(id2hrn.containsKey(idSum2)){
5085 hrnSum2 = id2hrn.get(idSum2);
5088 Set<HeapRegionNode> common = new HashSet<HeapRegionNode>();
5089 if(hrnSum1!=null && hrnSum2!=null && hrnSum1!=hrnSum2){
5090 common.addAll(mayReachSharedObjects(hrnSum1, hrnSum2));
5094 // ask if objects from this summary share among each other
5095 common.addAll(mayReachSharedObjects(hrnSum1));
5098 // check sum2 against alloc1 nodes
5100 for (int i = 0; i < as1.getAllocationDepth(); ++i) {
5101 Integer idI1 = as1.getIthOldest(i);
5102 assert id2hrn.containsKey(idI1);
5103 HeapRegionNode hrnI1 = id2hrn.get(idI1);
5104 assert hrnI1 != null;
5105 common.addAll(mayReachSharedObjects(hrnI1, hrnSum2));
5108 // also ask if objects from this summary share among each other
5109 common.addAll(mayReachSharedObjects(hrnSum2));
5112 // check sum1 against alloc2 nodes
5113 for (int i = 0; i < as2.getAllocationDepth(); ++i) {
5114 Integer idI2 = as2.getIthOldest(i);
5115 assert id2hrn.containsKey(idI2);
5116 HeapRegionNode hrnI2 = id2hrn.get(idI2);
5117 assert hrnI2 != null;
5120 common.addAll(mayReachSharedObjects(hrnSum1, hrnI2));
5123 // while we're at it, do an inner loop for alloc2 vs alloc1 nodes
5124 for (int j = 0; j < as1.getAllocationDepth(); ++j) {
5125 Integer idI1 = as1.getIthOldest(j);
5127 // if these are the same site, don't look for the same token, no
5129 // different tokens of the same site could alias together though
5130 if (idI1.equals(idI2)) {
5134 HeapRegionNode hrnI1 = id2hrn.get(idI1);
5136 common.addAll(mayReachSharedObjects(hrnI1, hrnI2));
5143 public void makeInaccessible( Set<TempDescriptor> vars ) {
5144 inaccessibleVars.addAll( vars );
5147 public void makeInaccessible( TempDescriptor td ) {
5148 inaccessibleVars.add( td );
5151 public void makeAccessible( TempDescriptor td ) {
5152 inaccessibleVars.remove( td );
5155 public boolean isAccessible(TempDescriptor td) {
5156 return !inaccessibleVars.contains(td);
5159 public Set<TempDescriptor> getInaccessibleVars() {
5160 return inaccessibleVars;