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 HashSet<AllocSite> allocSites;
42 // set of accessible variables for current program statement
43 // if not contains, it is an inaccessible variable
44 public HashSet<TempDescriptor> accessibleVars;
47 id2hrn = new Hashtable<Integer, HeapRegionNode>();
48 td2vn = new Hashtable<TempDescriptor, VariableNode >();
49 allocSites = new HashSet<AllocSite>();
50 accessibleVars = new HashSet<TempDescriptor>();
54 // temp descriptors are globally unique and map to
55 // exactly one variable node, easy
56 protected VariableNode getVariableNodeFromTemp( TempDescriptor td ) {
59 if( !td2vn.containsKey( td ) ) {
60 td2vn.put( td, new VariableNode( td ) );
63 return td2vn.get( td );
66 public boolean hasVariable( TempDescriptor td ) {
67 return td2vn.containsKey( td );
71 // this suite of methods can be used to assert a
72 // very important property of ReachGraph objects:
73 // some element, HeapRegionNode, RefEdge etc.
74 // should be referenced by at most ONE ReachGraph!!
75 // If a heap region or edge or variable should be
76 // in another graph, make a new object with
77 // equivalent properties for a new graph
78 public boolean belongsToThis( RefSrcNode rsn ) {
79 if( rsn instanceof VariableNode ) {
80 VariableNode vn = (VariableNode) rsn;
81 return this.td2vn.get( vn.getTempDescriptor() ) == vn;
83 HeapRegionNode hrn = (HeapRegionNode) rsn;
84 return this.id2hrn.get( hrn.getID() ) == hrn;
91 // the reason for this method is to have the option
92 // of creating new heap regions with specific IDs, or
93 // duplicating heap regions with specific IDs (especially
94 // in the merge() operation) or to create new heap
95 // regions with a new unique ID
96 protected HeapRegionNode
97 createNewHeapRegionNode( Integer id,
98 boolean isSingleObject,
100 boolean isOutOfContext,
109 TypeDescriptor typeToUse = null;
110 if( allocSite != null ) {
111 typeToUse = allocSite.getType();
112 allocSites.add( allocSite );
117 boolean markForAnalysis = false;
118 if( allocSite != null && allocSite.isFlagged() ) {
119 markForAnalysis = true;
122 if( allocSite == null ) {
123 assert !markForAnalysis;
125 } else if( markForAnalysis != allocSite.isFlagged() ) {
131 id = DisjointAnalysis.generateUniqueHeapRegionNodeID();
134 if( inherent == null ) {
135 if( markForAnalysis ) {
137 Canonical.changePredsTo(
140 ReachTuple.factory( id,
142 ReachTuple.ARITY_ONE,
143 false // out-of-context
150 inherent = rsetWithEmptyState;
154 if( alpha == null ) {
158 assert preds != null;
160 HeapRegionNode hrn = new HeapRegionNode( id,
171 id2hrn.put( id, hrn );
177 ////////////////////////////////////////////////
179 // Low-level referencee and referencer methods
181 // These methods provide the lowest level for
182 // creating references between reachability nodes
183 // and handling the details of maintaining both
184 // list of referencers and referencees.
186 ////////////////////////////////////////////////
187 protected void addRefEdge( RefSrcNode referencer,
188 HeapRegionNode referencee,
190 assert referencer != null;
191 assert referencee != null;
193 assert edge.getSrc() == referencer;
194 assert edge.getDst() == referencee;
195 assert belongsToThis( referencer );
196 assert belongsToThis( referencee );
198 // edges are getting added twice to graphs now, the
199 // kind that should have abstract facts merged--use
200 // this check to prevent that
201 assert referencer.getReferenceTo( referencee,
206 referencer.addReferencee( edge );
207 referencee.addReferencer( edge );
210 protected void removeRefEdge( RefEdge e ) {
211 removeRefEdge( e.getSrc(),
217 protected void removeRefEdge( RefSrcNode referencer,
218 HeapRegionNode referencee,
221 assert referencer != null;
222 assert referencee != null;
224 RefEdge edge = referencer.getReferenceTo( referencee,
228 assert edge == referencee.getReferenceFrom( referencer,
232 referencer.removeReferencee( edge );
233 referencee.removeReferencer( edge );
237 // int oldTaint=edge.getTaintIdentifier();
238 // if(referencer instanceof HeapRegionNode){
239 // depropagateTaintIdentifier((HeapRegionNode)referencer,oldTaint,new HashSet<HeapRegionNode>());
245 // return whether at least one edge was removed
246 protected boolean clearRefEdgesFrom( RefSrcNode referencer,
249 boolean removeAll ) {
250 assert referencer != null;
252 boolean atLeastOneEdgeRemoved = false;
254 // get a copy of the set to iterate over, otherwise
255 // we will be trying to take apart the set as we
256 // are iterating over it, which won't work
257 Iterator<RefEdge> i = referencer.iteratorToReferenceesClone();
258 while( i.hasNext() ) {
259 RefEdge edge = i.next();
262 (edge.typeEquals( type ) && edge.fieldEquals( field ))
265 HeapRegionNode referencee = edge.getDst();
267 removeRefEdge( referencer,
272 atLeastOneEdgeRemoved = true;
276 return atLeastOneEdgeRemoved;
279 protected void clearRefEdgesTo( HeapRegionNode referencee,
282 boolean removeAll ) {
283 assert referencee != null;
285 // get a copy of the set to iterate over, otherwise
286 // we will be trying to take apart the set as we
287 // are iterating over it, which won't work
288 Iterator<RefEdge> i = referencee.iteratorToReferencersClone();
289 while( i.hasNext() ) {
290 RefEdge edge = i.next();
293 (edge.typeEquals( type ) && edge.fieldEquals( field ))
296 RefSrcNode referencer = edge.getSrc();
298 removeRefEdge( referencer,
306 protected void clearNonVarRefEdgesTo( HeapRegionNode referencee ) {
307 assert referencee != null;
309 // get a copy of the set to iterate over, otherwise
310 // we will be trying to take apart the set as we
311 // are iterating over it, which won't work
312 Iterator<RefEdge> i = referencee.iteratorToReferencersClone();
313 while( i.hasNext() ) {
314 RefEdge edge = i.next();
315 RefSrcNode referencer = edge.getSrc();
316 if( !(referencer instanceof VariableNode) ) {
317 removeRefEdge( referencer,
325 // this is a common operation in many transfer functions: we want
326 // to add an edge, but if there is already such an edge we should
327 // merge the properties of the existing and the new edges
328 protected void addEdgeOrMergeWithExisting( RefEdge edgeNew ) {
330 RefSrcNode src = edgeNew.getSrc();
331 assert belongsToThis( src );
333 HeapRegionNode dst = edgeNew.getDst();
334 assert belongsToThis( dst );
336 // look to see if an edge with same field exists
337 // and merge with it, otherwise just add the edge
338 RefEdge edgeExisting = src.getReferenceTo( dst,
343 if( edgeExisting != null ) {
344 edgeExisting.setBeta(
345 Canonical.unionORpreds( edgeExisting.getBeta(),
349 edgeExisting.setPreds(
350 Canonical.join( edgeExisting.getPreds(),
354 edgeExisting.setTaints(
355 Canonical.unionORpreds( edgeExisting.getTaints(),
361 addRefEdge( src, dst, edgeNew );
367 ////////////////////////////////////////////////////
369 // Assignment Operation Methods
371 // These methods are high-level operations for
372 // modeling program assignment statements using
373 // the low-level reference create/remove methods
376 ////////////////////////////////////////////////////
378 public void assignTempXEqualToTempY( TempDescriptor x,
380 assignTempXEqualToCastedTempY( x, y, null );
382 // x gets status of y
383 // if it is in region,
384 //if(accessibleVars.contains(y)){
385 // accessibleVars.add(x);
389 public void assignTempXEqualToCastedTempY( TempDescriptor x,
391 TypeDescriptor tdCast ) {
393 VariableNode lnX = getVariableNodeFromTemp( x );
394 VariableNode lnY = getVariableNodeFromTemp( y );
396 clearRefEdgesFrom( lnX, null, null, true );
398 // note it is possible that the types of temps in the
399 // flat node to analyze will reveal that some typed
400 // edges in the reachability graph are impossible
401 Set<RefEdge> impossibleEdges = new HashSet<RefEdge>();
403 Iterator<RefEdge> itrYhrn = lnY.iteratorToReferencees();
404 while( itrYhrn.hasNext() ) {
405 RefEdge edgeY = itrYhrn.next();
406 HeapRegionNode referencee = edgeY.getDst();
407 RefEdge edgeNew = edgeY.copy();
409 if( !isSuperiorType( x.getType(), edgeY.getType() ) ) {
410 impossibleEdges.add( edgeY );
414 edgeNew.setSrc( lnX );
416 if( tdCast == null ) {
417 edgeNew.setType( mostSpecificType( y.getType(),
423 edgeNew.setType( mostSpecificType( y.getType(),
425 referencee.getType(),
431 edgeNew.setField( null );
433 addRefEdge( lnX, referencee, edgeNew );
436 Iterator<RefEdge> itrImp = impossibleEdges.iterator();
437 while( itrImp.hasNext() ) {
438 RefEdge edgeImp = itrImp.next();
439 removeRefEdge( edgeImp );
444 public void assignTempXEqualToTempYFieldF( TempDescriptor x,
446 FieldDescriptor f ) {
447 VariableNode lnX = getVariableNodeFromTemp( x );
448 VariableNode lnY = getVariableNodeFromTemp( y );
450 clearRefEdgesFrom( lnX, null, null, true );
452 // note it is possible that the types of temps in the
453 // flat node to analyze will reveal that some typed
454 // edges in the reachability graph are impossible
455 Set<RefEdge> impossibleEdges = new HashSet<RefEdge>();
457 Iterator<RefEdge> itrYhrn = lnY.iteratorToReferencees();
458 while( itrYhrn.hasNext() ) {
459 RefEdge edgeY = itrYhrn.next();
460 HeapRegionNode hrnY = edgeY.getDst();
461 ReachSet betaY = edgeY.getBeta();
463 Iterator<RefEdge> itrHrnFhrn = hrnY.iteratorToReferencees();
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 ) {
514 // accessible status update
515 // if it is in region,
516 //accessibleVars.add(x);
517 //accessibleVars.add(y);
521 // return whether a strong update was actually effected
522 public boolean assignTempXFieldFEqualToTempY( TempDescriptor x,
526 VariableNode lnX = getVariableNodeFromTemp( x );
527 VariableNode lnY = getVariableNodeFromTemp( y );
529 HashSet<HeapRegionNode> nodesWithNewAlpha = new HashSet<HeapRegionNode>();
530 HashSet<RefEdge> edgesWithNewBeta = new HashSet<RefEdge>();
532 // note it is possible that the types of temps in the
533 // flat node to analyze will reveal that some typed
534 // edges in the reachability graph are impossible
535 Set<RefEdge> impossibleEdges = new HashSet<RefEdge>();
537 // first look for possible strong updates and remove those edges
538 boolean strongUpdateCond = false;
539 boolean edgeRemovedByStrongUpdate = false;
541 Iterator<RefEdge> itrXhrn = lnX.iteratorToReferencees();
542 while( itrXhrn.hasNext() ) {
543 RefEdge edgeX = itrXhrn.next();
544 HeapRegionNode hrnX = edgeX.getDst();
546 // we can do a strong update here if one of two cases holds
548 f != DisjointAnalysis.getArrayField( f.getType() ) &&
549 ( (hrnX.getNumReferencers() == 1) || // case 1
550 (hrnX.isSingleObject() && lnX.getNumReferencees() == 1) // case 2
553 if( !DISABLE_STRONG_UPDATES ) {
554 strongUpdateCond = true;
557 clearRefEdgesFrom( hrnX,
562 edgeRemovedByStrongUpdate = true;
568 // then do all token propagation
569 itrXhrn = lnX.iteratorToReferencees();
570 while( itrXhrn.hasNext() ) {
571 RefEdge edgeX = itrXhrn.next();
572 HeapRegionNode hrnX = edgeX.getDst();
573 ReachSet betaX = edgeX.getBeta();
574 ReachSet R = Canonical.intersection( hrnX.getAlpha(),
578 Iterator<RefEdge> itrYhrn = lnY.iteratorToReferencees();
579 while( itrYhrn.hasNext() ) {
580 RefEdge edgeY = itrYhrn.next();
581 HeapRegionNode hrnY = edgeY.getDst();
582 ReachSet O = edgeY.getBeta();
584 // check for impossible edges
585 if( !isSuperiorType( f.getType(), edgeY.getType() ) ) {
586 impossibleEdges.add( edgeY );
590 // propagate tokens over nodes starting from hrnSrc, and it will
591 // take care of propagating back up edges from any touched nodes
592 ChangeSet Cy = Canonical.unionUpArityToChangeSet( O, R );
593 propagateTokensOverNodes( hrnY, Cy, nodesWithNewAlpha, edgesWithNewBeta );
595 // then propagate back just up the edges from hrn
596 ChangeSet Cx = Canonical.unionUpArityToChangeSet( R, O );
597 HashSet<RefEdge> todoEdges = new HashSet<RefEdge>();
599 Hashtable<RefEdge, ChangeSet> edgePlannedChanges =
600 new Hashtable<RefEdge, ChangeSet>();
602 Iterator<RefEdge> referItr = hrnX.iteratorToReferencers();
603 while( referItr.hasNext() ) {
604 RefEdge edgeUpstream = referItr.next();
605 todoEdges.add( edgeUpstream );
606 edgePlannedChanges.put( edgeUpstream, Cx );
609 propagateTokensOverEdges( todoEdges,
616 // apply the updates to reachability
617 Iterator<HeapRegionNode> nodeItr = nodesWithNewAlpha.iterator();
618 while( nodeItr.hasNext() ) {
619 nodeItr.next().applyAlphaNew();
622 Iterator<RefEdge> edgeItr = edgesWithNewBeta.iterator();
623 while( edgeItr.hasNext() ) {
624 edgeItr.next().applyBetaNew();
628 // then go back through and add the new edges
629 itrXhrn = lnX.iteratorToReferencees();
630 while( itrXhrn.hasNext() ) {
631 RefEdge edgeX = itrXhrn.next();
632 HeapRegionNode hrnX = edgeX.getDst();
634 Iterator<RefEdge> itrYhrn = lnY.iteratorToReferencees();
635 while( itrYhrn.hasNext() ) {
636 RefEdge edgeY = itrYhrn.next();
637 HeapRegionNode hrnY = edgeY.getDst();
639 // skip impossible edges here, we already marked them
640 // when computing reachability propagations above
641 if( !isSuperiorType( f.getType(), edgeY.getType() ) ) {
645 // prepare the new reference edge hrnX.f -> hrnY
646 TypeDescriptor tdNewEdge =
647 mostSpecificType( y.getType(),
657 Canonical.changePredsTo(
658 Canonical.pruneBy( edgeY.getBeta(),
664 Canonical.changePredsTo( edgeY.getTaints(),
668 addEdgeOrMergeWithExisting( edgeNew );
672 Iterator<RefEdge> itrImp = impossibleEdges.iterator();
673 while( itrImp.hasNext() ) {
674 RefEdge edgeImp = itrImp.next();
675 removeRefEdge( edgeImp );
678 // if there was a strong update, make sure to improve
679 // reachability with a global sweep
680 if( edgeRemovedByStrongUpdate || !impossibleEdges.isEmpty() ) {
681 if( !DISABLE_GLOBAL_SWEEP ) {
687 // after x.y=f , stall x and y if they are not accessible
688 // also contribute write effects on stall site of x
689 // accessible status update
690 // if it is in region
691 //accessibleVars.add(x);
692 //accessibleVars.add(y);
694 return edgeRemovedByStrongUpdate;
698 public void assignReturnEqualToTemp( TempDescriptor x ) {
700 VariableNode lnR = getVariableNodeFromTemp( tdReturn );
701 VariableNode lnX = getVariableNodeFromTemp( x );
703 clearRefEdgesFrom( lnR, null, null, true );
705 Iterator<RefEdge> itrXhrn = lnX.iteratorToReferencees();
706 while( itrXhrn.hasNext() ) {
707 RefEdge edgeX = itrXhrn.next();
708 HeapRegionNode referencee = edgeX.getDst();
709 RefEdge edgeNew = edgeX.copy();
710 edgeNew.setSrc( lnR );
711 edgeNew.setTaints( Canonical.changePredsTo( edgeNew.getTaints(),
716 addRefEdge( lnR, referencee, edgeNew );
721 public void assignTempEqualToNewAlloc( TempDescriptor x,
728 // after the age operation the newest (or zero-ith oldest)
729 // node associated with the allocation site should have
730 // no references to it as if it were a newly allocated
732 Integer idNewest = as.getIthOldest( 0 );
733 HeapRegionNode hrnNewest = id2hrn.get( idNewest );
734 assert hrnNewest != null;
736 VariableNode lnX = getVariableNodeFromTemp( x );
737 clearRefEdgesFrom( lnX, null, null, true );
739 // make a new reference to allocated node
740 TypeDescriptor type = as.getType();
743 new RefEdge( lnX, // source
747 hrnNewest.getAlpha(), // beta
748 predsTrue, // predicates
749 TaintSet.factory() // taints
752 addRefEdge( lnX, hrnNewest, edgeNew );
754 // after x=new , x is accessible
755 // if (isInRegion()) {
756 //accessibleVars.add(x);
760 // use the allocation site (unique to entire analysis) to
761 // locate the heap region nodes in this reachability graph
762 // that should be aged. The process models the allocation
763 // of new objects and collects all the oldest allocations
764 // in a summary node to allow for a finite analysis
766 // There is an additional property of this method. After
767 // running it on a particular reachability graph (many graphs
768 // may have heap regions related to the same allocation site)
769 // the heap region node objects in this reachability graph will be
770 // allocated. Therefore, after aging a graph for an allocation
771 // site, attempts to retrieve the heap region nodes using the
772 // integer id's contained in the allocation site should always
773 // return non-null heap regions.
774 public void age( AllocSite as ) {
776 // keep track of allocation sites that are represented
777 // in this graph for efficiency with other operations
778 allocSites.add( as );
780 // if there is a k-th oldest node, it merges into
782 Integer idK = as.getOldest();
783 if( id2hrn.containsKey( idK ) ) {
784 HeapRegionNode hrnK = id2hrn.get( idK );
786 // retrieve the summary node, or make it
788 HeapRegionNode hrnSummary = getSummaryNode( as, false );
790 mergeIntoSummary( hrnK, hrnSummary );
793 // move down the line of heap region nodes
794 // clobbering the ith and transferring all references
795 // to and from i-1 to node i.
796 for( int i = allocationDepth - 1; i > 0; --i ) {
798 // only do the transfer if the i-1 node exists
799 Integer idImin1th = as.getIthOldest( i - 1 );
800 if( id2hrn.containsKey( idImin1th ) ) {
801 HeapRegionNode hrnImin1 = id2hrn.get( idImin1th );
802 if( hrnImin1.isWiped() ) {
803 // there is no info on this node, just skip
807 // either retrieve or make target of transfer
808 HeapRegionNode hrnI = getIthNode( as, i, false );
810 transferOnto( hrnImin1, hrnI );
815 // as stated above, the newest node should have had its
816 // references moved over to the second oldest, so we wipe newest
817 // in preparation for being the new object to assign something to
818 HeapRegionNode hrn0 = getIthNode( as, 0, false );
819 wipeOut( hrn0, true );
821 // now tokens in reachability sets need to "age" also
822 Iterator itrAllVariableNodes = td2vn.entrySet().iterator();
823 while( itrAllVariableNodes.hasNext() ) {
824 Map.Entry me = (Map.Entry) itrAllVariableNodes.next();
825 VariableNode ln = (VariableNode) me.getValue();
827 Iterator<RefEdge> itrEdges = ln.iteratorToReferencees();
828 while( itrEdges.hasNext() ) {
829 ageTuplesFrom( as, itrEdges.next() );
833 Iterator itrAllHRNodes = id2hrn.entrySet().iterator();
834 while( itrAllHRNodes.hasNext() ) {
835 Map.Entry me = (Map.Entry) itrAllHRNodes.next();
836 HeapRegionNode hrnToAge = (HeapRegionNode) me.getValue();
838 ageTuplesFrom( as, hrnToAge );
840 Iterator<RefEdge> itrEdges = hrnToAge.iteratorToReferencees();
841 while( itrEdges.hasNext() ) {
842 ageTuplesFrom( as, itrEdges.next() );
847 // after tokens have been aged, reset newest node's reachability
848 // and a brand new node has a "true" predicate
849 hrn0.setAlpha( hrn0.getInherent() );
850 hrn0.setPreds( predsTrue );
854 // either retrieve or create the needed heap region node
855 protected HeapRegionNode getSummaryNode( AllocSite as,
860 idSummary = as.getSummaryShadow();
862 idSummary = as.getSummary();
865 HeapRegionNode hrnSummary = id2hrn.get( idSummary );
867 if( hrnSummary == null ) {
869 String strDesc = as.toStringForDOT()+"\\nsummary";
872 createNewHeapRegionNode( idSummary, // id or null to generate a new one
873 false, // single object?
875 false, // out-of-context?
876 as.getType(), // type
877 as, // allocation site
878 null, // inherent reach
879 null, // current reach
880 predsEmpty, // predicates
881 strDesc // description
888 // either retrieve or create the needed heap region node
889 protected HeapRegionNode getIthNode( AllocSite as,
895 idIth = as.getIthOldestShadow( i );
897 idIth = as.getIthOldest( i );
900 HeapRegionNode hrnIth = id2hrn.get( idIth );
902 if( hrnIth == null ) {
904 String strDesc = as.toStringForDOT()+"\\n"+i+" oldest";
906 hrnIth = createNewHeapRegionNode( idIth, // id or null to generate a new one
907 true, // single object?
909 false, // out-of-context?
910 as.getType(), // type
911 as, // allocation site
912 null, // inherent reach
913 null, // current reach
914 predsEmpty, // predicates
915 strDesc // description
923 protected void mergeIntoSummary( HeapRegionNode hrn,
924 HeapRegionNode hrnSummary ) {
925 assert hrnSummary.isNewSummary();
927 // assert that these nodes belong to THIS graph
928 assert belongsToThis( hrn );
929 assert belongsToThis( hrnSummary );
931 assert hrn != hrnSummary;
933 // transfer references _from_ hrn over to hrnSummary
934 Iterator<RefEdge> itrReferencee = hrn.iteratorToReferencees();
935 while( itrReferencee.hasNext() ) {
936 RefEdge edge = itrReferencee.next();
937 RefEdge edgeMerged = edge.copy();
938 edgeMerged.setSrc( hrnSummary );
940 HeapRegionNode hrnReferencee = edge.getDst();
941 RefEdge edgeSummary =
942 hrnSummary.getReferenceTo( hrnReferencee,
947 if( edgeSummary == null ) {
948 // the merge is trivial, nothing to be done
949 addRefEdge( hrnSummary, hrnReferencee, edgeMerged );
952 // otherwise an edge from the referencer to hrnSummary exists already
953 // and the edge referencer->hrn should be merged with it
955 Canonical.unionORpreds( edgeMerged.getBeta(),
956 edgeSummary.getBeta()
959 edgeSummary.setPreds(
960 Canonical.join( edgeMerged.getPreds(),
961 edgeSummary.getPreds()
967 // next transfer references _to_ hrn over to hrnSummary
968 Iterator<RefEdge> itrReferencer = hrn.iteratorToReferencers();
969 while( itrReferencer.hasNext() ) {
970 RefEdge edge = itrReferencer.next();
971 RefEdge edgeMerged = edge.copy();
972 edgeMerged.setDst( hrnSummary );
974 RefSrcNode onReferencer = edge.getSrc();
975 RefEdge edgeSummary =
976 onReferencer.getReferenceTo( hrnSummary,
981 if( edgeSummary == null ) {
982 // the merge is trivial, nothing to be done
983 addRefEdge( onReferencer, hrnSummary, edgeMerged );
986 // otherwise an edge from the referencer to alpha_S exists already
987 // and the edge referencer->alpha_K should be merged with it
989 Canonical.unionORpreds( edgeMerged.getBeta(),
990 edgeSummary.getBeta()
993 edgeSummary.setPreds(
994 Canonical.join( edgeMerged.getPreds(),
995 edgeSummary.getPreds()
1001 // then merge hrn reachability into hrnSummary
1002 hrnSummary.setAlpha(
1003 Canonical.unionORpreds( hrnSummary.getAlpha(),
1008 hrnSummary.setPreds(
1009 Canonical.join( hrnSummary.getPreds(),
1014 // and afterward, this node is gone
1015 wipeOut( hrn, true );
1019 protected void transferOnto( HeapRegionNode hrnA,
1020 HeapRegionNode hrnB ) {
1022 assert belongsToThis( hrnA );
1023 assert belongsToThis( hrnB );
1024 assert hrnA != hrnB;
1026 // clear references in and out of node b?
1027 assert hrnB.isWiped();
1029 // copy each: (edge in and out of A) to B
1030 Iterator<RefEdge> itrReferencee = hrnA.iteratorToReferencees();
1031 while( itrReferencee.hasNext() ) {
1032 RefEdge edge = itrReferencee.next();
1033 HeapRegionNode hrnReferencee = edge.getDst();
1034 RefEdge edgeNew = edge.copy();
1035 edgeNew.setSrc( hrnB );
1036 edgeNew.setDst( hrnReferencee );
1038 addRefEdge( hrnB, hrnReferencee, edgeNew );
1041 Iterator<RefEdge> itrReferencer = hrnA.iteratorToReferencers();
1042 while( itrReferencer.hasNext() ) {
1043 RefEdge edge = itrReferencer.next();
1044 RefSrcNode rsnReferencer = edge.getSrc();
1045 RefEdge edgeNew = edge.copy();
1046 edgeNew.setSrc( rsnReferencer );
1047 edgeNew.setDst( hrnB );
1049 addRefEdge( rsnReferencer, hrnB, edgeNew );
1052 // replace hrnB reachability and preds with hrnA's
1053 hrnB.setAlpha( hrnA.getAlpha() );
1054 hrnB.setPreds( hrnA.getPreds() );
1056 // after transfer, wipe out source
1057 wipeOut( hrnA, true );
1061 // the purpose of this method is to conceptually "wipe out"
1062 // a heap region from the graph--purposefully not called REMOVE
1063 // because the node is still hanging around in the graph, just
1064 // not mechanically connected or have any reach or predicate
1065 // information on it anymore--lots of ops can use this
1066 protected void wipeOut( HeapRegionNode hrn,
1067 boolean wipeVariableReferences ) {
1069 assert belongsToThis( hrn );
1071 clearRefEdgesFrom( hrn, null, null, true );
1073 if( wipeVariableReferences ) {
1074 clearRefEdgesTo( hrn, null, null, true );
1076 clearNonVarRefEdgesTo( hrn );
1079 hrn.setAlpha( rsetEmpty );
1080 hrn.setPreds( predsEmpty );
1084 protected void ageTuplesFrom( AllocSite as, RefEdge edge ) {
1086 Canonical.ageTuplesFrom( edge.getBeta(),
1092 protected void ageTuplesFrom( AllocSite as, HeapRegionNode hrn ) {
1094 Canonical.ageTuplesFrom( hrn.getAlpha(),
1102 protected void propagateTokensOverNodes( HeapRegionNode nPrime,
1104 HashSet<HeapRegionNode> nodesWithNewAlpha,
1105 HashSet<RefEdge> edgesWithNewBeta ) {
1107 HashSet<HeapRegionNode> todoNodes
1108 = new HashSet<HeapRegionNode>();
1109 todoNodes.add( nPrime );
1111 HashSet<RefEdge> todoEdges
1112 = new HashSet<RefEdge>();
1114 Hashtable<HeapRegionNode, ChangeSet> nodePlannedChanges
1115 = new Hashtable<HeapRegionNode, ChangeSet>();
1116 nodePlannedChanges.put( nPrime, c0 );
1118 Hashtable<RefEdge, ChangeSet> edgePlannedChanges
1119 = new Hashtable<RefEdge, ChangeSet>();
1121 // first propagate change sets everywhere they can go
1122 while( !todoNodes.isEmpty() ) {
1123 HeapRegionNode n = todoNodes.iterator().next();
1124 ChangeSet C = nodePlannedChanges.get( n );
1126 Iterator<RefEdge> referItr = n.iteratorToReferencers();
1127 while( referItr.hasNext() ) {
1128 RefEdge edge = referItr.next();
1129 todoEdges.add( edge );
1131 if( !edgePlannedChanges.containsKey( edge ) ) {
1132 edgePlannedChanges.put( edge,
1137 edgePlannedChanges.put( edge,
1138 Canonical.union( edgePlannedChanges.get( edge ),
1144 Iterator<RefEdge> refeeItr = n.iteratorToReferencees();
1145 while( refeeItr.hasNext() ) {
1146 RefEdge edgeF = refeeItr.next();
1147 HeapRegionNode m = edgeF.getDst();
1149 ChangeSet changesToPass = ChangeSet.factory();
1151 Iterator<ChangeTuple> itrCprime = C.iterator();
1152 while( itrCprime.hasNext() ) {
1153 ChangeTuple c = itrCprime.next();
1154 if( edgeF.getBeta().containsIgnorePreds( c.getStateToMatch() )
1157 changesToPass = Canonical.add( changesToPass, c );
1161 if( !changesToPass.isEmpty() ) {
1162 if( !nodePlannedChanges.containsKey( m ) ) {
1163 nodePlannedChanges.put( m, ChangeSet.factory() );
1166 ChangeSet currentChanges = nodePlannedChanges.get( m );
1168 if( !changesToPass.isSubset( currentChanges ) ) {
1170 nodePlannedChanges.put( m,
1171 Canonical.union( currentChanges,
1180 todoNodes.remove( n );
1183 // then apply all of the changes for each node at once
1184 Iterator itrMap = nodePlannedChanges.entrySet().iterator();
1185 while( itrMap.hasNext() ) {
1186 Map.Entry me = (Map.Entry) itrMap.next();
1187 HeapRegionNode n = (HeapRegionNode) me.getKey();
1188 ChangeSet C = (ChangeSet) me.getValue();
1190 // this propagation step is with respect to one change,
1191 // so we capture the full change from the old alpha:
1192 ReachSet localDelta = Canonical.applyChangeSet( n.getAlpha(),
1196 // but this propagation may be only one of many concurrent
1197 // possible changes, so keep a running union with the node's
1198 // partially updated new alpha set
1199 n.setAlphaNew( Canonical.unionORpreds( n.getAlphaNew(),
1204 nodesWithNewAlpha.add( n );
1207 propagateTokensOverEdges( todoEdges,
1214 protected void propagateTokensOverEdges( HashSet <RefEdge> todoEdges,
1215 Hashtable<RefEdge, ChangeSet> edgePlannedChanges,
1216 HashSet <RefEdge> edgesWithNewBeta ) {
1218 // first propagate all change tuples everywhere they can go
1219 while( !todoEdges.isEmpty() ) {
1220 RefEdge edgeE = todoEdges.iterator().next();
1221 todoEdges.remove( edgeE );
1223 if( !edgePlannedChanges.containsKey( edgeE ) ) {
1224 edgePlannedChanges.put( edgeE,
1229 ChangeSet C = edgePlannedChanges.get( edgeE );
1231 ChangeSet changesToPass = ChangeSet.factory();
1233 Iterator<ChangeTuple> itrC = C.iterator();
1234 while( itrC.hasNext() ) {
1235 ChangeTuple c = itrC.next();
1236 if( edgeE.getBeta().containsIgnorePreds( c.getStateToMatch() )
1239 changesToPass = Canonical.add( changesToPass, c );
1243 RefSrcNode rsn = edgeE.getSrc();
1245 if( !changesToPass.isEmpty() && rsn instanceof HeapRegionNode ) {
1246 HeapRegionNode n = (HeapRegionNode) rsn;
1248 Iterator<RefEdge> referItr = n.iteratorToReferencers();
1249 while( referItr.hasNext() ) {
1250 RefEdge edgeF = referItr.next();
1252 if( !edgePlannedChanges.containsKey( edgeF ) ) {
1253 edgePlannedChanges.put( edgeF,
1258 ChangeSet currentChanges = edgePlannedChanges.get( edgeF );
1260 if( !changesToPass.isSubset( currentChanges ) ) {
1261 todoEdges.add( edgeF );
1262 edgePlannedChanges.put( edgeF,
1263 Canonical.union( currentChanges,
1272 // then apply all of the changes for each edge at once
1273 Iterator itrMap = edgePlannedChanges.entrySet().iterator();
1274 while( itrMap.hasNext() ) {
1275 Map.Entry me = (Map.Entry) itrMap.next();
1276 RefEdge e = (RefEdge) me.getKey();
1277 ChangeSet C = (ChangeSet) me.getValue();
1279 // this propagation step is with respect to one change,
1280 // so we capture the full change from the old beta:
1281 ReachSet localDelta =
1282 Canonical.applyChangeSet( e.getBeta(),
1287 // but this propagation may be only one of many concurrent
1288 // possible changes, so keep a running union with the edge's
1289 // partially updated new beta set
1290 e.setBetaNew( Canonical.unionORpreds( e.getBetaNew(),
1295 edgesWithNewBeta.add( e );
1300 public void taintInSetVars( FlatSESEEnterNode sese ) {
1301 if( sese.getIsCallerSESEplaceholder() ) {
1305 Iterator<TempDescriptor> isvItr = sese.getInVarSet().iterator();
1306 while( isvItr.hasNext() ) {
1307 TempDescriptor isv = isvItr.next();
1308 VariableNode vn = getVariableNodeFromTemp( isv );
1310 Iterator<RefEdge> reItr = vn.iteratorToReferencees();
1311 while( reItr.hasNext() ) {
1312 RefEdge re = reItr.next();
1314 // these in-set taints should have empty
1315 // predicates so they never propagate
1317 Taint t = Taint.factory( sese,
1320 re.getDst().getAllocSite(),
1321 ExistPredSet.factory()
1324 re.setTaints( Canonical.add( re.getTaints(),
1332 // this is useful for more general tainting
1333 public void taintTemp( Taint taint,
1338 VariableNode vn = getVariableNodeFromTemp( td );
1340 Iterator<RefEdge> reItr = vn.iteratorToReferencees();
1341 while( reItr.hasNext() ) {
1342 RefEdge re = reItr.next();
1344 re.setTaints( Canonical.add( re.getTaints(),
1351 public void removeInContextTaints( FlatSESEEnterNode sese ) {
1352 if( sese.getIsCallerSESEplaceholder() ) {
1356 Iterator meItr = id2hrn.entrySet().iterator();
1357 while( meItr.hasNext() ) {
1358 Map.Entry me = (Map.Entry) meItr.next();
1359 Integer id = (Integer) me.getKey();
1360 HeapRegionNode hrn = (HeapRegionNode) me.getValue();
1362 Iterator<RefEdge> reItr = hrn.iteratorToReferencers();
1363 while( reItr.hasNext() ) {
1364 RefEdge re = reItr.next();
1366 re.setTaints( Canonical.removeTaintsBy( re.getTaints(),
1375 // used in makeCalleeView below to decide if there is
1376 // already an appropriate out-of-context edge in a callee
1377 // view graph for merging, or null if a new one will be added
1379 getOutOfContextReferenceTo( HeapRegionNode hrn,
1380 TypeDescriptor srcType,
1381 TypeDescriptor refType,
1383 assert belongsToThis( hrn );
1385 HeapRegionNode hrnInContext = id2hrn.get( hrn.getID() );
1386 if( hrnInContext == null ) {
1390 Iterator<RefEdge> refItr = hrnInContext.iteratorToReferencers();
1391 while( refItr.hasNext() ) {
1392 RefEdge re = refItr.next();
1394 assert belongsToThis( re.getSrc() );
1395 assert belongsToThis( re.getDst() );
1397 if( !(re.getSrc() instanceof HeapRegionNode) ) {
1401 HeapRegionNode hrnSrc = (HeapRegionNode) re.getSrc();
1402 if( !hrnSrc.isOutOfContext() ) {
1406 if( srcType == null ) {
1407 if( hrnSrc.getType() != null ) {
1411 if( !srcType.equals( hrnSrc.getType() ) ) {
1416 if( !re.typeEquals( refType ) ) {
1420 if( !re.fieldEquals( refField ) ) {
1424 // tada! We found it!
1431 // used below to convert a ReachSet to its callee-context
1432 // equivalent with respect to allocation sites in this graph
1433 protected ReachSet toCalleeContext( ReachSet rs,
1434 ExistPredSet predsNodeOrEdge,
1435 Set<HrnIdOoc> oocHrnIdOoc2callee
1437 ReachSet out = ReachSet.factory();
1439 Iterator<ReachState> itr = rs.iterator();
1440 while( itr.hasNext() ) {
1441 ReachState stateCaller = itr.next();
1443 ReachState stateCallee = stateCaller;
1445 Iterator<AllocSite> asItr = allocSites.iterator();
1446 while( asItr.hasNext() ) {
1447 AllocSite as = asItr.next();
1449 ReachState stateNew = ReachState.factory();
1450 Iterator<ReachTuple> rtItr = stateCallee.iterator();
1451 while( rtItr.hasNext() ) {
1452 ReachTuple rt = rtItr.next();
1454 // only translate this tuple if it is
1455 // in the out-callee-context bag
1456 HrnIdOoc hio = new HrnIdOoc( rt.getHrnID(),
1459 if( !oocHrnIdOoc2callee.contains( hio ) ) {
1460 stateNew = Canonical.add( stateNew, rt );
1464 int age = as.getAgeCategory( rt.getHrnID() );
1466 // this is the current mapping, where 0, 1, 2S were allocated
1467 // in the current context, 0?, 1? and 2S? were allocated in a
1468 // previous context, and we're translating to a future context
1480 if( age == AllocSite.AGE_notInThisSite ) {
1481 // things not from the site just go back in
1482 stateNew = Canonical.add( stateNew, rt );
1484 } else if( age == AllocSite.AGE_summary ||
1487 // the in-context summary and all existing out-of-context
1489 stateNew = Canonical.add( stateNew,
1490 ReachTuple.factory( as.getSummary(),
1493 true // out-of-context
1497 // otherwise everything else just goes to an out-of-context
1498 // version, everything else the same
1499 Integer I = as.getAge( rt.getHrnID() );
1502 assert !rt.isMultiObject();
1504 stateNew = Canonical.add( stateNew,
1505 ReachTuple.factory( rt.getHrnID(),
1508 true // out-of-context
1514 stateCallee = stateNew;
1517 // make a predicate of the caller graph element
1518 // and the caller state we just converted
1519 ExistPredSet predsWithState = ExistPredSet.factory();
1521 Iterator<ExistPred> predItr = predsNodeOrEdge.iterator();
1522 while( predItr.hasNext() ) {
1523 ExistPred predNodeOrEdge = predItr.next();
1526 Canonical.add( predsWithState,
1527 ExistPred.factory( predNodeOrEdge.n_hrnID,
1528 predNodeOrEdge.e_tdSrc,
1529 predNodeOrEdge.e_hrnSrcID,
1530 predNodeOrEdge.e_hrnDstID,
1531 predNodeOrEdge.e_type,
1532 predNodeOrEdge.e_field,
1535 predNodeOrEdge.e_srcOutCalleeContext,
1536 predNodeOrEdge.e_srcOutCallerContext
1541 stateCallee = Canonical.changePredsTo( stateCallee,
1544 out = Canonical.add( out,
1548 assert out.isCanonical();
1552 // used below to convert a ReachSet to its caller-context
1553 // equivalent with respect to allocation sites in this graph
1555 toCallerContext( ReachSet rs,
1556 Hashtable<ReachState, ExistPredSet> calleeStatesSatisfied
1558 ReachSet out = ReachSet.factory();
1560 // when the mapping is null it means there were no
1561 // predicates satisfied
1562 if( calleeStatesSatisfied == null ) {
1566 Iterator<ReachState> itr = rs.iterator();
1567 while( itr.hasNext() ) {
1568 ReachState stateCallee = itr.next();
1570 if( calleeStatesSatisfied.containsKey( stateCallee ) ) {
1572 // starting from one callee state...
1573 ReachSet rsCaller = ReachSet.factory( stateCallee );
1575 // possibly branch it into many states, which any
1576 // allocation site might do, so lots of derived states
1577 Iterator<AllocSite> asItr = allocSites.iterator();
1578 while( asItr.hasNext() ) {
1579 AllocSite as = asItr.next();
1580 rsCaller = Canonical.toCallerContext( rsCaller, as );
1583 // then before adding each derived, now caller-context
1584 // states to the output, attach the appropriate pred
1585 // based on the source callee state
1586 Iterator<ReachState> stateItr = rsCaller.iterator();
1587 while( stateItr.hasNext() ) {
1588 ReachState stateCaller = stateItr.next();
1589 stateCaller = Canonical.attach( stateCaller,
1590 calleeStatesSatisfied.get( stateCallee )
1592 out = Canonical.add( out,
1599 assert out.isCanonical();
1604 // used below to convert a ReachSet to an equivalent
1605 // version with shadow IDs merged into unshadowed IDs
1606 protected ReachSet unshadow( ReachSet rs ) {
1608 Iterator<AllocSite> asItr = allocSites.iterator();
1609 while( asItr.hasNext() ) {
1610 AllocSite as = asItr.next();
1611 out = Canonical.unshadow( out, as );
1613 assert out.isCanonical();
1618 // convert a caller taint set into a callee taint set
1620 toCalleeContext( TaintSet ts,
1621 ExistPredSet predsEdge ) {
1623 TaintSet out = TaintSet.factory();
1625 // the idea is easy, the taint identifier itself doesn't
1626 // change at all, but the predicates should be tautology:
1627 // start with the preds passed in from the caller edge
1628 // that host the taints, and alter them to have the taint
1629 // added, just becoming more specific than edge predicate alone
1631 Iterator<Taint> itr = ts.iterator();
1632 while( itr.hasNext() ) {
1633 Taint tCaller = itr.next();
1635 ExistPredSet predsWithTaint = ExistPredSet.factory();
1637 Iterator<ExistPred> predItr = predsEdge.iterator();
1638 while( predItr.hasNext() ) {
1639 ExistPred predEdge = predItr.next();
1642 Canonical.add( predsWithTaint,
1643 ExistPred.factory( predEdge.e_tdSrc,
1644 predEdge.e_hrnSrcID,
1645 predEdge.e_hrnDstID,
1650 predEdge.e_srcOutCalleeContext,
1651 predEdge.e_srcOutCallerContext
1656 Taint tCallee = Canonical.changePredsTo( tCaller,
1659 out = Canonical.add( out,
1664 assert out.isCanonical();
1669 // used below to convert a TaintSet to its caller-context
1670 // equivalent, just eliminate Taints with bad preds
1672 toCallerContext( TaintSet ts,
1673 Hashtable<Taint, ExistPredSet> calleeTaintsSatisfied,
1674 Hashtable<Taint, TaintSet> tCallee2tsCaller
1677 TaintSet out = TaintSet.factory();
1679 // when the mapping is null it means there were no
1680 // predicates satisfied
1681 if( calleeTaintsSatisfied == null ) {
1685 Iterator<Taint> itr = ts.iterator();
1686 while( itr.hasNext() ) {
1687 Taint tCallee = itr.next();
1689 if( calleeTaintsSatisfied.containsKey( tCallee ) ) {
1692 Canonical.attach( Taint.factory( tCallee.sese,
1696 ExistPredSet.factory() ),
1697 calleeTaintsSatisfied.get( tCallee )
1699 out = Canonical.add( out,
1703 // this mapping aids the effects analysis--
1704 // ONLY DO IF MASTER MAP IS NOT NULL
1705 if( tCallee2tsCaller != null ) {
1706 TaintSet tsCaller = tCallee2tsCaller.get( tCallee );
1707 if( tsCaller == null ) {
1708 tsCaller = TaintSet.factory();
1710 tsCaller = Canonical.add( tsCaller, tCaller );
1711 tCallee2tsCaller.put( tCallee, tsCaller );
1716 assert out.isCanonical();
1723 // use this method to make a new reach graph that is
1724 // what heap the FlatMethod callee from the FlatCall
1725 // would start with reaching from its arguments in
1728 makeCalleeView( FlatCall fc,
1729 FlatMethod fmCallee,
1730 Set<Integer> callerNodeIDsCopiedToCallee,
1731 boolean writeDebugDOTs
1735 // first traverse this context to find nodes and edges
1736 // that will be callee-reachable
1737 Set<HeapRegionNode> reachableCallerNodes =
1738 new HashSet<HeapRegionNode>();
1740 // caller edges between callee-reachable nodes
1741 Set<RefEdge> reachableCallerEdges =
1742 new HashSet<RefEdge>();
1744 // caller edges from arg vars, and the matching param index
1745 // because these become a special edge in callee
1746 Hashtable<RefEdge, Integer> reachableCallerArgEdges2paramIndex =
1747 new Hashtable<RefEdge, Integer>();
1749 // caller edges from local vars or callee-unreachable nodes
1750 // (out-of-context sources) to callee-reachable nodes
1751 Set<RefEdge> oocCallerEdges =
1752 new HashSet<RefEdge>();
1755 for( int i = 0; i < fmCallee.numParameters(); ++i ) {
1757 TempDescriptor tdArg = fc.getArgMatchingParamIndex( fmCallee, i );
1758 VariableNode vnArgCaller = this.getVariableNodeFromTemp( tdArg );
1760 Set<RefSrcNode> toVisitInCaller = new HashSet<RefSrcNode>();
1761 Set<RefSrcNode> visitedInCaller = new HashSet<RefSrcNode>();
1763 toVisitInCaller.add( vnArgCaller );
1765 while( !toVisitInCaller.isEmpty() ) {
1766 RefSrcNode rsnCaller = toVisitInCaller.iterator().next();
1767 toVisitInCaller.remove( rsnCaller );
1768 visitedInCaller.add( rsnCaller );
1770 Iterator<RefEdge> itrRefEdges = rsnCaller.iteratorToReferencees();
1771 while( itrRefEdges.hasNext() ) {
1772 RefEdge reCaller = itrRefEdges.next();
1773 HeapRegionNode hrnCaller = reCaller.getDst();
1775 callerNodeIDsCopiedToCallee.add( hrnCaller.getID() );
1776 reachableCallerNodes.add( hrnCaller );
1778 if( reCaller.getSrc() instanceof HeapRegionNode ) {
1779 reachableCallerEdges.add( reCaller );
1781 if( rsnCaller.equals( vnArgCaller ) ) {
1782 reachableCallerArgEdges2paramIndex.put( reCaller, i );
1784 oocCallerEdges.add( reCaller );
1788 if( !visitedInCaller.contains( hrnCaller ) ) {
1789 toVisitInCaller.add( hrnCaller );
1792 } // end edge iteration
1793 } // end visiting heap nodes in caller
1794 } // end iterating over parameters as starting points
1797 // now collect out-of-callee-context IDs and
1798 // map them to whether the ID is out of the caller
1800 Set<HrnIdOoc> oocHrnIdOoc2callee = new HashSet<HrnIdOoc>();
1802 Iterator<Integer> itrInContext =
1803 callerNodeIDsCopiedToCallee.iterator();
1804 while( itrInContext.hasNext() ) {
1805 Integer hrnID = itrInContext.next();
1806 HeapRegionNode hrnCallerAndInContext = id2hrn.get( hrnID );
1808 Iterator<RefEdge> itrMightCross =
1809 hrnCallerAndInContext.iteratorToReferencers();
1810 while( itrMightCross.hasNext() ) {
1811 RefEdge edgeMightCross = itrMightCross.next();
1813 RefSrcNode rsnCallerAndOutContext =
1814 edgeMightCross.getSrc();
1816 if( rsnCallerAndOutContext instanceof VariableNode ) {
1817 // variables do not have out-of-context reach states,
1819 oocCallerEdges.add( edgeMightCross );
1823 HeapRegionNode hrnCallerAndOutContext =
1824 (HeapRegionNode) rsnCallerAndOutContext;
1826 // is this source node out-of-context?
1827 if( callerNodeIDsCopiedToCallee.contains( hrnCallerAndOutContext.getID() ) ) {
1828 // no, skip this edge
1833 oocCallerEdges.add( edgeMightCross );
1835 // add all reach tuples on the node to list
1836 // of things that are out-of-context: insight
1837 // if this node is reachable from someting that WAS
1838 // in-context, then this node should already be in-context
1839 Iterator<ReachState> stateItr = hrnCallerAndOutContext.getAlpha().iterator();
1840 while( stateItr.hasNext() ) {
1841 ReachState state = stateItr.next();
1843 Iterator<ReachTuple> rtItr = state.iterator();
1844 while( rtItr.hasNext() ) {
1845 ReachTuple rt = rtItr.next();
1847 oocHrnIdOoc2callee.add( new HrnIdOoc( rt.getHrnID(),
1856 // the callee view is a new graph: DON'T MODIFY *THIS* graph
1857 ReachGraph rg = new ReachGraph();
1859 // add nodes to callee graph
1860 Iterator<HeapRegionNode> hrnItr = reachableCallerNodes.iterator();
1861 while( hrnItr.hasNext() ) {
1862 HeapRegionNode hrnCaller = hrnItr.next();
1864 assert callerNodeIDsCopiedToCallee.contains( hrnCaller.getID() );
1865 assert !rg.id2hrn.containsKey( hrnCaller.getID() );
1867 ExistPred pred = ExistPred.factory( hrnCaller.getID(), null );
1868 ExistPredSet preds = ExistPredSet.factory( pred );
1870 rg.createNewHeapRegionNode( hrnCaller.getID(),
1871 hrnCaller.isSingleObject(),
1872 hrnCaller.isNewSummary(),
1873 false, // out-of-context?
1874 hrnCaller.getType(),
1875 hrnCaller.getAllocSite(),
1876 toCalleeContext( hrnCaller.getInherent(),
1880 toCalleeContext( hrnCaller.getAlpha(),
1885 hrnCaller.getDescription()
1889 // add param edges to callee graph
1891 reachableCallerArgEdges2paramIndex.entrySet().iterator();
1892 while( argEdges.hasNext() ) {
1893 Map.Entry me = (Map.Entry) argEdges.next();
1894 RefEdge reArg = (RefEdge) me.getKey();
1895 Integer index = (Integer) me.getValue();
1897 VariableNode vnCaller = (VariableNode) reArg.getSrc();
1898 TempDescriptor argCaller = vnCaller.getTempDescriptor();
1900 TempDescriptor paramCallee = fmCallee.getParameter( index );
1901 VariableNode vnCallee = rg.getVariableNodeFromTemp( paramCallee );
1903 HeapRegionNode hrnDstCaller = reArg.getDst();
1904 HeapRegionNode hrnDstCallee = rg.id2hrn.get( hrnDstCaller.getID() );
1905 assert hrnDstCallee != null;
1908 ExistPred.factory( argCaller,
1910 hrnDstCallee.getID(),
1915 true, // out-of-callee-context
1916 false // out-of-caller-context
1919 ExistPredSet preds =
1920 ExistPredSet.factory( pred );
1923 new RefEdge( vnCallee,
1927 toCalleeContext( reArg.getBeta(),
1932 toCalleeContext( reArg.getTaints(),
1936 rg.addRefEdge( vnCallee,
1942 // add in-context edges to callee graph
1943 Iterator<RefEdge> reItr = reachableCallerEdges.iterator();
1944 while( reItr.hasNext() ) {
1945 RefEdge reCaller = reItr.next();
1946 RefSrcNode rsnCaller = reCaller.getSrc();
1947 assert rsnCaller instanceof HeapRegionNode;
1948 HeapRegionNode hrnSrcCaller = (HeapRegionNode) rsnCaller;
1949 HeapRegionNode hrnDstCaller = reCaller.getDst();
1951 HeapRegionNode hrnSrcCallee = rg.id2hrn.get( hrnSrcCaller.getID() );
1952 HeapRegionNode hrnDstCallee = rg.id2hrn.get( hrnDstCaller.getID() );
1953 assert hrnSrcCallee != null;
1954 assert hrnDstCallee != null;
1957 ExistPred.factory( null,
1958 hrnSrcCallee.getID(),
1959 hrnDstCallee.getID(),
1961 reCaller.getField(),
1964 false, // out-of-callee-context
1965 false // out-of-caller-context
1968 ExistPredSet preds =
1969 ExistPredSet.factory( pred );
1972 new RefEdge( hrnSrcCallee,
1975 reCaller.getField(),
1976 toCalleeContext( reCaller.getBeta(),
1981 TaintSet.factory() // no taints for in-context edges
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 = true;
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 Hashtable<Taint, TaintSet> tCallee2tsCaller,
2222 boolean writeDebugDOTs
2225 if( writeDebugDOTs ) {
2226 System.out.println( " Writing out visit "+
2227 debugCallSiteVisitCounter+
2228 " to debug call site" );
2230 debugGraphPrefix = String.format( "call%03d",
2231 debugCallSiteVisitCounter );
2233 rgCallee.writeGraph( debugGraphPrefix+"callee",
2234 resolveMethodDebugDOTwriteLabels,
2235 resolveMethodDebugDOTselectTemps,
2236 resolveMethodDebugDOTpruneGarbage,
2237 resolveMethodDebugDOThideReach,
2238 resolveMethodDebugDOThideSubsetReach,
2239 resolveMethodDebugDOThidePreds,
2240 resolveMethodDebugDOThideEdgeTaints );
2242 writeGraph( debugGraphPrefix+"caller00In",
2243 resolveMethodDebugDOTwriteLabels,
2244 resolveMethodDebugDOTselectTemps,
2245 resolveMethodDebugDOTpruneGarbage,
2246 resolveMethodDebugDOThideReach,
2247 resolveMethodDebugDOThideSubsetReach,
2248 resolveMethodDebugDOThidePreds,
2249 resolveMethodDebugDOThideEdgeTaints,
2250 callerNodeIDsCopiedToCallee );
2255 // method call transfer function steps:
2256 // 1. Use current callee-reachable heap (CRH) to test callee
2257 // predicates and mark what will be coming in.
2258 // 2. Wipe CRH out of caller.
2259 // 3. Transplant marked callee parts in:
2260 // a) bring in nodes
2261 // b) bring in callee -> callee edges
2262 // c) resolve out-of-context -> callee edges
2263 // d) assign return value
2264 // 4. Collapse shadow nodes down
2265 // 5. Global sweep it.
2268 // 1. mark what callee elements have satisfied predicates
2269 Hashtable<HeapRegionNode, ExistPredSet> calleeNodesSatisfied =
2270 new Hashtable<HeapRegionNode, ExistPredSet>();
2272 Hashtable<RefEdge, ExistPredSet> calleeEdgesSatisfied =
2273 new Hashtable<RefEdge, ExistPredSet>();
2275 Hashtable< HeapRegionNode, Hashtable<ReachState, ExistPredSet> >
2276 calleeNode2calleeStatesSatisfied =
2277 new Hashtable< HeapRegionNode, Hashtable<ReachState, ExistPredSet> >();
2279 Hashtable< RefEdge, Hashtable<ReachState, ExistPredSet> >
2280 calleeEdge2calleeStatesSatisfied =
2281 new Hashtable< RefEdge, Hashtable<ReachState, ExistPredSet> >();
2283 Hashtable< RefEdge, Hashtable<Taint, ExistPredSet> >
2284 calleeEdge2calleeTaintsSatisfied =
2285 new Hashtable< RefEdge, Hashtable<Taint, ExistPredSet> >();
2287 Hashtable< RefEdge, Set<RefSrcNode> > calleeEdges2oocCallerSrcMatches =
2288 new Hashtable< RefEdge, Set<RefSrcNode> >();
2291 Iterator meItr = rgCallee.id2hrn.entrySet().iterator();
2292 while( meItr.hasNext() ) {
2293 Map.Entry me = (Map.Entry) meItr.next();
2294 Integer id = (Integer) me.getKey();
2295 HeapRegionNode hrnCallee = (HeapRegionNode) me.getValue();
2297 // if a callee element's predicates are satisfied then a set
2298 // of CALLER predicates is returned: they are the predicates
2299 // that the callee element moved into the caller context
2300 // should have, and it is inefficient to find this again later
2301 ExistPredSet predsIfSatis =
2302 hrnCallee.getPreds().isSatisfiedBy( this,
2303 callerNodeIDsCopiedToCallee
2306 if( predsIfSatis != null ) {
2307 calleeNodesSatisfied.put( hrnCallee, predsIfSatis );
2309 // otherwise don't bother looking at edges to this node
2313 // since the node is coming over, find out which reach
2314 // states on it should come over, too
2315 assert calleeNode2calleeStatesSatisfied.get( hrnCallee ) == null;
2317 Iterator<ReachState> stateItr = hrnCallee.getAlpha().iterator();
2318 while( stateItr.hasNext() ) {
2319 ReachState stateCallee = stateItr.next();
2322 stateCallee.getPreds().isSatisfiedBy( this,
2323 callerNodeIDsCopiedToCallee
2325 if( predsIfSatis != null ) {
2327 Hashtable<ReachState, ExistPredSet> calleeStatesSatisfied =
2328 calleeNode2calleeStatesSatisfied.get( hrnCallee );
2330 if( calleeStatesSatisfied == null ) {
2331 calleeStatesSatisfied =
2332 new Hashtable<ReachState, ExistPredSet>();
2334 calleeNode2calleeStatesSatisfied.put( hrnCallee, calleeStatesSatisfied );
2337 calleeStatesSatisfied.put( stateCallee, predsIfSatis );
2341 // then look at edges to the node
2342 Iterator<RefEdge> reItr = hrnCallee.iteratorToReferencers();
2343 while( reItr.hasNext() ) {
2344 RefEdge reCallee = reItr.next();
2345 RefSrcNode rsnCallee = reCallee.getSrc();
2347 // (caller local variables to in-context heap regions)
2348 // have an (out-of-context heap region -> in-context heap region)
2349 // abstraction in the callEE, so its true we never need to
2350 // look at a (var node -> heap region) edge in callee to bring
2351 // those over for the call site transfer, except for the special
2352 // case of *RETURN var* -> heap region edges.
2353 // What about (param var->heap region)
2354 // edges in callee? They are dealt with below this loop.
2356 if( rsnCallee instanceof VariableNode ) {
2358 // looking for the return-value variable only
2359 VariableNode vnCallee = (VariableNode) rsnCallee;
2360 if( vnCallee.getTempDescriptor() != tdReturn ) {
2364 TempDescriptor returnTemp = fc.getReturnTemp();
2365 if( returnTemp == null ||
2366 !DisjointAnalysis.shouldAnalysisTrack( returnTemp.getType() )
2371 // note that the assignment of the return value is to a
2372 // variable in the caller which is out-of-context with
2373 // respect to the callee
2374 VariableNode vnLhsCaller = getVariableNodeFromTemp( returnTemp );
2375 Set<RefSrcNode> rsnCallers = new HashSet<RefSrcNode>();
2376 rsnCallers.add( vnLhsCaller );
2377 calleeEdges2oocCallerSrcMatches.put( reCallee, rsnCallers );
2381 // for HeapRegionNode callee sources...
2383 // first see if the source is out-of-context, and only
2384 // proceed with this edge if we find some caller-context
2386 HeapRegionNode hrnSrcCallee = (HeapRegionNode) rsnCallee;
2387 boolean matchedOutOfContext = false;
2389 if( !hrnSrcCallee.isOutOfContext() ) {
2392 hrnSrcCallee.getPreds().isSatisfiedBy( this,
2393 callerNodeIDsCopiedToCallee
2395 if( predsIfSatis != null ) {
2396 calleeNodesSatisfied.put( hrnSrcCallee, predsIfSatis );
2398 // otherwise forget this edge
2403 // hrnSrcCallee is out-of-context
2405 assert !calleeEdges2oocCallerSrcMatches.containsKey( reCallee );
2407 Set<RefSrcNode> rsnCallers = new HashSet<RefSrcNode>();
2409 // is the target node in the caller?
2410 HeapRegionNode hrnDstCaller = this.id2hrn.get( hrnCallee.getID() );
2411 if( hrnDstCaller == null ) {
2415 Iterator<RefEdge> reDstItr = hrnDstCaller.iteratorToReferencers();
2416 while( reDstItr.hasNext() ) {
2417 // the edge and field (either possibly null) must match
2418 RefEdge reCaller = reDstItr.next();
2420 if( !reCaller.typeEquals ( reCallee.getType() ) ||
2421 !reCaller.fieldEquals( reCallee.getField() )
2426 RefSrcNode rsnCaller = reCaller.getSrc();
2427 if( rsnCaller instanceof VariableNode ) {
2429 // a variable node matches an OOC region with null type
2430 if( hrnSrcCallee.getType() != null ) {
2435 // otherwise types should match
2436 HeapRegionNode hrnCallerSrc = (HeapRegionNode) rsnCaller;
2437 if( hrnSrcCallee.getType() == null ) {
2438 if( hrnCallerSrc.getType() != null ) {
2442 if( !hrnSrcCallee.getType().equals( hrnCallerSrc.getType() ) ) {
2448 rsnCallers.add( rsnCaller );
2449 matchedOutOfContext = true;
2452 if( !rsnCallers.isEmpty() ) {
2453 calleeEdges2oocCallerSrcMatches.put( reCallee, rsnCallers );
2457 if( hrnSrcCallee.isOutOfContext() &&
2458 !matchedOutOfContext ) {
2465 reCallee.getPreds().isSatisfiedBy( this,
2466 callerNodeIDsCopiedToCallee
2469 if( predsIfSatis != null ) {
2470 calleeEdgesSatisfied.put( reCallee, predsIfSatis );
2472 // since the edge is coming over, find out which reach
2473 // states on it should come over, too
2474 assert calleeEdge2calleeStatesSatisfied.get( reCallee ) == null;
2476 stateItr = reCallee.getBeta().iterator();
2477 while( stateItr.hasNext() ) {
2478 ReachState stateCallee = stateItr.next();
2481 stateCallee.getPreds().isSatisfiedBy( this,
2482 callerNodeIDsCopiedToCallee
2484 if( predsIfSatis != null ) {
2486 Hashtable<ReachState, ExistPredSet> calleeStatesSatisfied =
2487 calleeEdge2calleeStatesSatisfied.get( reCallee );
2489 if( calleeStatesSatisfied == null ) {
2490 calleeStatesSatisfied =
2491 new Hashtable<ReachState, ExistPredSet>();
2493 calleeEdge2calleeStatesSatisfied.put( reCallee, calleeStatesSatisfied );
2496 calleeStatesSatisfied.put( stateCallee, predsIfSatis );
2500 // since the edge is coming over, find out which taints
2501 // on it should come over, too
2502 assert calleeEdge2calleeTaintsSatisfied.get( reCallee ) == null;
2504 Iterator<Taint> tItr = reCallee.getTaints().iterator();
2505 while( tItr.hasNext() ) {
2506 Taint tCallee = tItr.next();
2509 tCallee.getPreds().isSatisfiedBy( this,
2510 callerNodeIDsCopiedToCallee
2512 if( predsIfSatis != null ) {
2514 Hashtable<Taint, ExistPredSet> calleeTaintsSatisfied =
2515 calleeEdge2calleeTaintsSatisfied.get( reCallee );
2517 if( calleeTaintsSatisfied == null ) {
2518 calleeTaintsSatisfied =
2519 new Hashtable<Taint, ExistPredSet>();
2521 calleeEdge2calleeTaintsSatisfied.put( reCallee, calleeTaintsSatisfied );
2524 calleeTaintsSatisfied.put( tCallee, predsIfSatis );
2531 if( writeDebugDOTs ) {
2532 writeGraph( debugGraphPrefix+"caller20BeforeWipe",
2533 resolveMethodDebugDOTwriteLabels,
2534 resolveMethodDebugDOTselectTemps,
2535 resolveMethodDebugDOTpruneGarbage,
2536 resolveMethodDebugDOThideReach,
2537 resolveMethodDebugDOThideSubsetReach,
2538 resolveMethodDebugDOThidePreds,
2539 resolveMethodDebugDOThideEdgeTaints );
2543 // 2. predicates tested, ok to wipe out caller part
2544 Iterator<Integer> hrnItr = callerNodeIDsCopiedToCallee.iterator();
2545 while( hrnItr.hasNext() ) {
2546 Integer hrnID = hrnItr.next();
2547 HeapRegionNode hrnCaller = id2hrn.get( hrnID );
2548 assert hrnCaller != null;
2550 // when clearing off nodes, also eliminate variable
2552 wipeOut( hrnCaller, true );
2555 // if we are assigning the return value to something, clobber now
2556 // as part of the wipe
2557 TempDescriptor returnTemp = fc.getReturnTemp();
2558 if( returnTemp != null &&
2559 DisjointAnalysis.shouldAnalysisTrack( returnTemp.getType() )
2562 VariableNode vnLhsCaller = getVariableNodeFromTemp( returnTemp );
2563 clearRefEdgesFrom( vnLhsCaller, null, null, true );
2569 if( writeDebugDOTs ) {
2570 writeGraph( debugGraphPrefix+"caller30BeforeAddingNodes",
2571 resolveMethodDebugDOTwriteLabels,
2572 resolveMethodDebugDOTselectTemps,
2573 resolveMethodDebugDOTpruneGarbage,
2574 resolveMethodDebugDOThideReach,
2575 resolveMethodDebugDOThideSubsetReach,
2576 resolveMethodDebugDOThidePreds,
2577 resolveMethodDebugDOThideEdgeTaints );
2583 // 3. callee elements with satisfied preds come in, note that
2584 // the mapping of elements satisfied to preds is like this:
2585 // A callee element EE has preds EEp that are satisfied by
2586 // some caller element ER. We bring EE into the caller
2587 // context as ERee with the preds of ER, namely ERp, which
2588 // in the following algorithm is the value in the mapping
2591 Iterator satisItr = calleeNodesSatisfied.entrySet().iterator();
2592 while( satisItr.hasNext() ) {
2593 Map.Entry me = (Map.Entry) satisItr.next();
2594 HeapRegionNode hrnCallee = (HeapRegionNode) me.getKey();
2595 ExistPredSet preds = (ExistPredSet) me.getValue();
2597 // TODO: I think its true that the current implementation uses
2598 // the type of the OOC region and the predicates OF THE EDGE from
2599 // it to link everything up in caller context, so that's why we're
2600 // skipping this... maybe that's a sillier way to do it?
2601 if( hrnCallee.isOutOfContext() ) {
2605 AllocSite as = hrnCallee.getAllocSite();
2606 allocSites.add( as );
2608 Integer hrnIDshadow = as.getShadowIDfromID( hrnCallee.getID() );
2610 HeapRegionNode hrnCaller = id2hrn.get( hrnIDshadow );
2611 if( hrnCaller == null ) {
2613 createNewHeapRegionNode( hrnIDshadow, // id or null to generate a new one
2614 hrnCallee.isSingleObject(), // single object?
2615 hrnCallee.isNewSummary(), // summary?
2616 false, // out-of-context?
2617 hrnCallee.getType(), // type
2618 hrnCallee.getAllocSite(), // allocation site
2619 toCallerContext( hrnCallee.getInherent(),
2620 calleeNode2calleeStatesSatisfied.get( hrnCallee ) ), // inherent reach
2621 null, // current reach
2622 predsEmpty, // predicates
2623 hrnCallee.getDescription() // description
2626 assert hrnCaller.isWiped();
2629 hrnCaller.setAlpha( toCallerContext( hrnCallee.getAlpha(),
2630 calleeNode2calleeStatesSatisfied.get( hrnCallee )
2634 hrnCaller.setPreds( preds );
2641 if( writeDebugDOTs ) {
2642 writeGraph( debugGraphPrefix+"caller31BeforeAddingEdges",
2643 resolveMethodDebugDOTwriteLabels,
2644 resolveMethodDebugDOTselectTemps,
2645 resolveMethodDebugDOTpruneGarbage,
2646 resolveMethodDebugDOThideReach,
2647 resolveMethodDebugDOThideSubsetReach,
2648 resolveMethodDebugDOThidePreds,
2649 resolveMethodDebugDOThideEdgeTaints );
2653 // set these up during the next procedure so after
2654 // the caller has all of its nodes and edges put
2655 // back together we can propagate the callee's
2656 // reach changes backwards into the caller graph
2657 HashSet<RefEdge> edgesForPropagation = new HashSet<RefEdge>();
2659 Hashtable<RefEdge, ChangeSet> edgePlannedChanges =
2660 new Hashtable<RefEdge, ChangeSet>();
2663 // 3.b) callee -> callee edges AND out-of-context -> callee
2664 // which includes return temp -> callee edges now, too
2665 satisItr = calleeEdgesSatisfied.entrySet().iterator();
2666 while( satisItr.hasNext() ) {
2667 Map.Entry me = (Map.Entry) satisItr.next();
2668 RefEdge reCallee = (RefEdge) me.getKey();
2669 ExistPredSet preds = (ExistPredSet) me.getValue();
2671 HeapRegionNode hrnDstCallee = reCallee.getDst();
2672 AllocSite asDst = hrnDstCallee.getAllocSite();
2673 allocSites.add( asDst );
2675 Integer hrnIDDstShadow =
2676 asDst.getShadowIDfromID( hrnDstCallee.getID() );
2678 HeapRegionNode hrnDstCaller = id2hrn.get( hrnIDDstShadow );
2679 assert hrnDstCaller != null;
2682 RefSrcNode rsnCallee = reCallee.getSrc();
2684 Set<RefSrcNode> rsnCallers =
2685 new HashSet<RefSrcNode>();
2687 Set<RefSrcNode> oocCallers =
2688 calleeEdges2oocCallerSrcMatches.get( reCallee );
2690 if( rsnCallee instanceof HeapRegionNode ) {
2691 HeapRegionNode hrnCalleeSrc = (HeapRegionNode) rsnCallee;
2692 if( hrnCalleeSrc.isOutOfContext() ) {
2693 assert oocCallers != null;
2698 if( oocCallers == null ) {
2699 // there are no out-of-context matches, so it's
2700 // either a param/arg var or one in-context heap region
2701 if( rsnCallee instanceof VariableNode ) {
2702 // variable -> node in the callee should only
2703 // come into the caller if its from a param var
2704 VariableNode vnCallee = (VariableNode) rsnCallee;
2705 TempDescriptor tdParam = vnCallee.getTempDescriptor();
2706 TempDescriptor tdArg = fc.getArgMatchingParam( fmCallee,
2708 if( tdArg == null ) {
2709 // this means the variable isn't a parameter, its local
2710 // to the callee so we ignore it in call site transfer
2711 // shouldn't this NEVER HAPPEN?
2715 rsnCallers.add( this.getVariableNodeFromTemp( tdArg ) );
2718 // otherwise source is in context, one region
2720 HeapRegionNode hrnSrcCallee = (HeapRegionNode) rsnCallee;
2722 // translate an in-context node to shadow
2723 AllocSite asSrc = hrnSrcCallee.getAllocSite();
2724 allocSites.add( asSrc );
2726 Integer hrnIDSrcShadow =
2727 asSrc.getShadowIDfromID( hrnSrcCallee.getID() );
2729 HeapRegionNode hrnSrcCallerShadow =
2730 this.id2hrn.get( hrnIDSrcShadow );
2732 assert hrnSrcCallerShadow != null;
2734 rsnCallers.add( hrnSrcCallerShadow );
2738 // otherwise we have a set of out-of-context srcs
2739 // that should NOT be translated to shadow nodes
2740 assert !oocCallers.isEmpty();
2741 rsnCallers.addAll( oocCallers );
2744 // now make all caller edges we've identified from
2745 // this callee edge with a satisfied predicate
2746 assert !rsnCallers.isEmpty();
2747 Iterator<RefSrcNode> rsnItr = rsnCallers.iterator();
2748 while( rsnItr.hasNext() ) {
2749 RefSrcNode rsnCaller = rsnItr.next();
2751 RefEdge reCaller = new RefEdge( rsnCaller,
2754 reCallee.getField(),
2755 toCallerContext( reCallee.getBeta(),
2756 calleeEdge2calleeStatesSatisfied.get( reCallee ) ),
2758 toCallerContext( reCallee.getTaints(),
2759 calleeEdge2calleeTaintsSatisfied.get( reCallee ),
2763 ChangeSet cs = ChangeSet.factory();
2764 Iterator<ReachState> rsItr = reCaller.getBeta().iterator();
2765 while( rsItr.hasNext() ) {
2766 ReachState state = rsItr.next();
2767 ExistPredSet predsPreCallee = state.getPreds();
2769 if( state.isEmpty() ) {
2773 Iterator<ExistPred> predItr = predsPreCallee.iterator();
2774 while( predItr.hasNext() ) {
2775 ExistPred pred = predItr.next();
2776 ReachState old = pred.ne_state;
2782 cs = Canonical.add( cs,
2783 ChangeTuple.factory( old,
2790 // we're just going to use the convenient "merge-if-exists"
2791 // edge call below, but still take a separate look if there
2792 // is an existing caller edge to build change sets properly
2793 if( !cs.isEmpty() ) {
2794 RefEdge edgeExisting = rsnCaller.getReferenceTo( hrnDstCaller,
2798 if( edgeExisting != null ) {
2799 ChangeSet csExisting = edgePlannedChanges.get( edgeExisting );
2800 if( csExisting == null ) {
2801 csExisting = ChangeSet.factory();
2803 edgePlannedChanges.put( edgeExisting,
2804 Canonical.union( csExisting,
2809 edgesForPropagation.add( reCaller );
2810 assert !edgePlannedChanges.containsKey( reCaller );
2811 edgePlannedChanges.put( reCaller, cs );
2815 // then add new caller edge or merge
2816 addEdgeOrMergeWithExisting( reCaller );
2824 if( writeDebugDOTs ) {
2825 writeGraph( debugGraphPrefix+"caller38propagateReach",
2826 resolveMethodDebugDOTwriteLabels,
2827 resolveMethodDebugDOTselectTemps,
2828 resolveMethodDebugDOTpruneGarbage,
2829 resolveMethodDebugDOThideReach,
2830 resolveMethodDebugDOThideSubsetReach,
2831 resolveMethodDebugDOThidePreds,
2832 resolveMethodDebugDOThideEdgeTaints );
2835 // propagate callee reachability changes to the rest
2836 // of the caller graph edges
2837 HashSet<RefEdge> edgesUpdated = new HashSet<RefEdge>();
2839 propagateTokensOverEdges( edgesForPropagation, // source edges
2840 edgePlannedChanges, // map src edge to change set
2841 edgesUpdated ); // list of updated edges
2843 // commit beta' (beta<-betaNew)
2844 Iterator<RefEdge> edgeItr = edgesUpdated.iterator();
2845 while( edgeItr.hasNext() ) {
2846 edgeItr.next().applyBetaNew();
2855 if( writeDebugDOTs ) {
2856 writeGraph( debugGraphPrefix+"caller40BeforeShadowMerge",
2857 resolveMethodDebugDOTwriteLabels,
2858 resolveMethodDebugDOTselectTemps,
2859 resolveMethodDebugDOTpruneGarbage,
2860 resolveMethodDebugDOThideReach,
2861 resolveMethodDebugDOThideSubsetReach,
2862 resolveMethodDebugDOThidePreds,
2863 resolveMethodDebugDOThideEdgeTaints );
2867 // 4) merge shadow nodes so alloc sites are back to k
2868 Iterator<AllocSite> asItr = rgCallee.allocSites.iterator();
2869 while( asItr.hasNext() ) {
2870 // for each allocation site do the following to merge
2871 // shadow nodes (newest from callee) with any existing
2872 // look for the newest normal and newest shadow "slot"
2873 // not being used, transfer normal to shadow. Keep
2874 // doing this until there are no more normal nodes, or
2875 // no empty shadow slots: then merge all remaining normal
2876 // nodes into the shadow summary. Finally, convert all
2877 // shadow to their normal versions.
2878 AllocSite as = asItr.next();
2881 while( ageNorm < allocationDepth &&
2882 ageShad < allocationDepth ) {
2884 // first, are there any normal nodes left?
2885 Integer idNorm = as.getIthOldest( ageNorm );
2886 HeapRegionNode hrnNorm = id2hrn.get( idNorm );
2887 if( hrnNorm == null ) {
2888 // no, this age of normal node not in the caller graph
2893 // yes, a normal node exists, is there an empty shadow
2894 // "slot" to transfer it onto?
2895 HeapRegionNode hrnShad = getIthNode( as, ageShad, true );
2896 if( !hrnShad.isWiped() ) {
2897 // no, this age of shadow node is not empty
2902 // yes, this shadow node is empty
2903 transferOnto( hrnNorm, hrnShad );
2908 // now, while there are still normal nodes but no shadow
2909 // slots, merge normal nodes into the shadow summary
2910 while( ageNorm < allocationDepth ) {
2912 // first, are there any normal nodes left?
2913 Integer idNorm = as.getIthOldest( ageNorm );
2914 HeapRegionNode hrnNorm = id2hrn.get( idNorm );
2915 if( hrnNorm == null ) {
2916 // no, this age of normal node not in the caller graph
2921 // yes, a normal node exists, so get the shadow summary
2922 HeapRegionNode summShad = getSummaryNode( as, true );
2923 mergeIntoSummary( hrnNorm, summShad );
2927 // if there is a normal summary, merge it into shadow summary
2928 Integer idNorm = as.getSummary();
2929 HeapRegionNode summNorm = id2hrn.get( idNorm );
2930 if( summNorm != null ) {
2931 HeapRegionNode summShad = getSummaryNode( as, true );
2932 mergeIntoSummary( summNorm, summShad );
2935 // finally, flip all existing shadow nodes onto the normal
2936 for( int i = 0; i < allocationDepth; ++i ) {
2937 Integer idShad = as.getIthOldestShadow( i );
2938 HeapRegionNode hrnShad = id2hrn.get( idShad );
2939 if( hrnShad != null ) {
2941 HeapRegionNode hrnNorm = getIthNode( as, i, false );
2942 assert hrnNorm.isWiped();
2943 transferOnto( hrnShad, hrnNorm );
2947 Integer idShad = as.getSummaryShadow();
2948 HeapRegionNode summShad = id2hrn.get( idShad );
2949 if( summShad != null ) {
2950 summNorm = getSummaryNode( as, false );
2951 transferOnto( summShad, summNorm );
2960 if( writeDebugDOTs ) {
2961 writeGraph( debugGraphPrefix+"caller45BeforeUnshadow",
2962 resolveMethodDebugDOTwriteLabels,
2963 resolveMethodDebugDOTselectTemps,
2964 resolveMethodDebugDOTpruneGarbage,
2965 resolveMethodDebugDOThideReach,
2966 resolveMethodDebugDOThideSubsetReach,
2967 resolveMethodDebugDOThidePreds,
2968 resolveMethodDebugDOThideEdgeTaints );
2972 Iterator itrAllHRNodes = id2hrn.entrySet().iterator();
2973 while( itrAllHRNodes.hasNext() ) {
2974 Map.Entry me = (Map.Entry) itrAllHRNodes.next();
2975 HeapRegionNode hrn = (HeapRegionNode) me.getValue();
2977 hrn.setAlpha( unshadow( hrn.getAlpha() ) );
2979 Iterator<RefEdge> itrEdges = hrn.iteratorToReferencers();
2980 while( itrEdges.hasNext() ) {
2981 RefEdge re = itrEdges.next();
2982 re.setBeta( unshadow( re.getBeta() ) );
2989 if( writeDebugDOTs ) {
2990 writeGraph( debugGraphPrefix+"caller50BeforeGlobalSweep",
2991 resolveMethodDebugDOTwriteLabels,
2992 resolveMethodDebugDOTselectTemps,
2993 resolveMethodDebugDOTpruneGarbage,
2994 resolveMethodDebugDOThideReach,
2995 resolveMethodDebugDOThideSubsetReach,
2996 resolveMethodDebugDOThidePreds,
2997 resolveMethodDebugDOThideEdgeTaints );
3002 if( !DISABLE_GLOBAL_SWEEP ) {
3007 if( writeDebugDOTs ) {
3008 writeGraph( debugGraphPrefix+"caller90AfterTransfer",
3009 resolveMethodDebugDOTwriteLabels,
3010 resolveMethodDebugDOTselectTemps,
3011 resolveMethodDebugDOTpruneGarbage,
3012 resolveMethodDebugDOThideReach,
3013 resolveMethodDebugDOThideSubsetReach,
3014 resolveMethodDebugDOThidePreds,
3015 resolveMethodDebugDOThideEdgeTaints );
3021 ////////////////////////////////////////////////////
3023 // Abstract garbage collection simply removes
3024 // heap region nodes that are not mechanically
3025 // reachable from a root set. This step is
3026 // essential for testing node and edge existence
3027 // predicates efficiently
3029 ////////////////////////////////////////////////////
3030 public void abstractGarbageCollect( Set<TempDescriptor> liveSet ) {
3032 // calculate a root set, will be different for Java
3033 // version of analysis versus Bamboo version
3034 Set<RefSrcNode> toVisit = new HashSet<RefSrcNode>();
3036 // visit every variable in graph while building root
3037 // set, and do iterating on a copy, so we can remove
3038 // dead variables while we're at this
3039 Iterator makeCopyItr = td2vn.entrySet().iterator();
3040 Set entrysCopy = new HashSet();
3041 while( makeCopyItr.hasNext() ) {
3042 entrysCopy.add( makeCopyItr.next() );
3045 Iterator eItr = entrysCopy.iterator();
3046 while( eItr.hasNext() ) {
3047 Map.Entry me = (Map.Entry) eItr.next();
3048 TempDescriptor td = (TempDescriptor) me.getKey();
3049 VariableNode vn = (VariableNode) me.getValue();
3051 if( liveSet.contains( td ) ) {
3055 // dead var, remove completely from graph
3057 clearRefEdgesFrom( vn, null, null, true );
3061 // everything visited in a traversal is
3062 // considered abstractly live
3063 Set<RefSrcNode> visited = new HashSet<RefSrcNode>();
3065 while( !toVisit.isEmpty() ) {
3066 RefSrcNode rsn = toVisit.iterator().next();
3067 toVisit.remove( rsn );
3070 Iterator<RefEdge> hrnItr = rsn.iteratorToReferencees();
3071 while( hrnItr.hasNext() ) {
3072 RefEdge edge = hrnItr.next();
3073 HeapRegionNode hrn = edge.getDst();
3075 if( !visited.contains( hrn ) ) {
3081 // get a copy of the set to iterate over because
3082 // we're going to monkey with the graph when we
3083 // identify a garbage node
3084 Set<HeapRegionNode> hrnAllPrior = new HashSet<HeapRegionNode>();
3085 Iterator<HeapRegionNode> hrnItr = id2hrn.values().iterator();
3086 while( hrnItr.hasNext() ) {
3087 hrnAllPrior.add( hrnItr.next() );
3090 Iterator<HeapRegionNode> hrnAllItr = hrnAllPrior.iterator();
3091 while( hrnAllItr.hasNext() ) {
3092 HeapRegionNode hrn = hrnAllItr.next();
3094 if( !visited.contains( hrn ) ) {
3096 // heap region nodes are compared across ReachGraph
3097 // objects by their integer ID, so when discarding
3098 // garbage nodes we must also discard entries in
3099 // the ID -> heap region hashtable.
3100 id2hrn.remove( hrn.getID() );
3102 // RefEdge objects are two-way linked between
3103 // nodes, so when a node is identified as garbage,
3104 // actively clear references to and from it so
3105 // live nodes won't have dangling RefEdge's
3106 wipeOut( hrn, true );
3108 // if we just removed the last node from an allocation
3109 // site, it should be taken out of the ReachGraph's list
3110 AllocSite as = hrn.getAllocSite();
3111 if( !hasNodesOf( as ) ) {
3112 allocSites.remove( as );
3118 protected boolean hasNodesOf( AllocSite as ) {
3119 if( id2hrn.containsKey( as.getSummary() ) ) {
3123 for( int i = 0; i < allocationDepth; ++i ) {
3124 if( id2hrn.containsKey( as.getIthOldest( i ) ) ) {
3132 ////////////////////////////////////////////////////
3134 // This global sweep is an optional step to prune
3135 // reachability sets that are not internally
3136 // consistent with the global graph. It should be
3137 // invoked after strong updates or method calls.
3139 ////////////////////////////////////////////////////
3140 public void globalSweep() {
3142 // boldB is part of the phase 1 sweep
3143 // it has an in-context table and an out-of-context table
3144 Hashtable< Integer, Hashtable<RefEdge, ReachSet> > boldBic =
3145 new Hashtable< Integer, Hashtable<RefEdge, ReachSet> >();
3147 Hashtable< Integer, Hashtable<RefEdge, ReachSet> > boldBooc =
3148 new Hashtable< Integer, Hashtable<RefEdge, ReachSet> >();
3150 // visit every heap region to initialize alphaNew and betaNew,
3151 // and make a map of every hrnID to the source nodes it should
3152 // propagate forward from. In-context flagged hrnID's propagate
3153 // from only the in-context node they name, but out-of-context
3154 // ID's may propagate from several out-of-context nodes
3155 Hashtable< Integer, Set<HeapRegionNode> > icID2srcs =
3156 new Hashtable< Integer, Set<HeapRegionNode> >();
3158 Hashtable< Integer, Set<HeapRegionNode> > oocID2srcs =
3159 new Hashtable< Integer, Set<HeapRegionNode> >();
3162 Iterator itrHrns = id2hrn.entrySet().iterator();
3163 while( itrHrns.hasNext() ) {
3164 Map.Entry me = (Map.Entry) itrHrns.next();
3165 Integer hrnID = (Integer) me.getKey();
3166 HeapRegionNode hrn = (HeapRegionNode) me.getValue();
3168 // assert that this node and incoming edges have clean alphaNew
3169 // and betaNew sets, respectively
3170 assert rsetEmpty.equals( hrn.getAlphaNew() );
3172 Iterator<RefEdge> itrRers = hrn.iteratorToReferencers();
3173 while( itrRers.hasNext() ) {
3174 RefEdge edge = itrRers.next();
3175 assert rsetEmpty.equals( edge.getBetaNew() );
3178 // make a mapping of IDs to heap regions they propagate from
3179 if( hrn.isFlagged() ) {
3180 assert !hrn.isOutOfContext();
3181 assert !icID2srcs.containsKey( hrn.getID() );
3183 // in-context flagged node IDs simply propagate from the
3185 Set<HeapRegionNode> srcs = new HashSet<HeapRegionNode>();
3187 icID2srcs.put( hrn.getID(), srcs );
3190 if( hrn.isOutOfContext() ) {
3191 assert !hrn.isFlagged();
3193 // the reachability states on an out-of-context
3194 // node are not really important (combinations of
3195 // IDs or arity)--what matters is that the states
3196 // specify which nodes this out-of-context node
3197 // stands in for. For example, if the state [17?, 19*]
3198 // appears on the ooc node, it may serve as a source
3199 // for node 17? and a source for node 19.
3200 Iterator<ReachState> stateItr = hrn.getAlpha().iterator();
3201 while( stateItr.hasNext() ) {
3202 ReachState state = stateItr.next();
3204 Iterator<ReachTuple> rtItr = state.iterator();
3205 while( rtItr.hasNext() ) {
3206 ReachTuple rt = rtItr.next();
3207 assert rt.isOutOfContext();
3209 Set<HeapRegionNode> srcs = oocID2srcs.get( rt.getHrnID() );
3210 if( srcs == null ) {
3211 srcs = new HashSet<HeapRegionNode>();
3214 oocID2srcs.put( rt.getHrnID(), srcs );
3220 // calculate boldB for all hrnIDs identified by the above
3221 // node traversal, propagating from every source
3222 while( !icID2srcs.isEmpty() || !oocID2srcs.isEmpty() ) {
3225 Set<HeapRegionNode> srcs;
3228 if( !icID2srcs.isEmpty() ) {
3229 Map.Entry me = (Map.Entry) icID2srcs.entrySet().iterator().next();
3230 hrnID = (Integer) me.getKey();
3231 srcs = (Set<HeapRegionNode>) me.getValue();
3233 icID2srcs.remove( hrnID );
3236 assert !oocID2srcs.isEmpty();
3238 Map.Entry me = (Map.Entry) oocID2srcs.entrySet().iterator().next();
3239 hrnID = (Integer) me.getKey();
3240 srcs = (Set<HeapRegionNode>) me.getValue();
3242 oocID2srcs.remove( hrnID );
3246 Hashtable<RefEdge, ReachSet> boldB_f =
3247 new Hashtable<RefEdge, ReachSet>();
3249 Set<RefEdge> workSetEdges = new HashSet<RefEdge>();
3251 Iterator<HeapRegionNode> hrnItr = srcs.iterator();
3252 while( hrnItr.hasNext() ) {
3253 HeapRegionNode hrn = hrnItr.next();
3255 assert workSetEdges.isEmpty();
3257 // initial boldB_f constraints
3258 Iterator<RefEdge> itrRees = hrn.iteratorToReferencees();
3259 while( itrRees.hasNext() ) {
3260 RefEdge edge = itrRees.next();
3262 assert !boldB_f.containsKey( edge );
3263 boldB_f.put( edge, edge.getBeta() );
3265 assert !workSetEdges.contains( edge );
3266 workSetEdges.add( edge );
3269 // enforce the boldB_f constraint at edges until we reach a fixed point
3270 while( !workSetEdges.isEmpty() ) {
3271 RefEdge edge = workSetEdges.iterator().next();
3272 workSetEdges.remove( edge );
3274 Iterator<RefEdge> itrPrime = edge.getDst().iteratorToReferencees();
3275 while( itrPrime.hasNext() ) {
3276 RefEdge edgePrime = itrPrime.next();
3278 ReachSet prevResult = boldB_f.get( edgePrime );
3279 ReachSet intersection = Canonical.intersection( boldB_f.get( edge ),
3283 if( prevResult == null ||
3284 Canonical.unionORpreds( prevResult,
3285 intersection ).size()
3289 if( prevResult == null ) {
3290 boldB_f.put( edgePrime,
3291 Canonical.unionORpreds( edgePrime.getBeta(),
3296 boldB_f.put( edgePrime,
3297 Canonical.unionORpreds( prevResult,
3302 workSetEdges.add( edgePrime );
3309 boldBic.put( hrnID, boldB_f );
3311 boldBooc.put( hrnID, boldB_f );
3316 // use boldB to prune hrnIDs from alpha states that are impossible
3317 // and propagate the differences backwards across edges
3318 HashSet<RefEdge> edgesForPropagation = new HashSet<RefEdge>();
3320 Hashtable<RefEdge, ChangeSet> edgePlannedChanges =
3321 new Hashtable<RefEdge, ChangeSet>();
3324 itrHrns = id2hrn.entrySet().iterator();
3325 while( itrHrns.hasNext() ) {
3326 Map.Entry me = (Map.Entry) itrHrns.next();
3327 Integer hrnID = (Integer) me.getKey();
3328 HeapRegionNode hrn = (HeapRegionNode) me.getValue();
3330 // out-of-context nodes don't participate in the
3331 // global sweep, they serve as sources for the pass
3333 if( hrn.isOutOfContext() ) {
3337 // the inherent states of a region are the exception
3338 // to removal as the global sweep prunes
3339 ReachTuple rtException = ReachTuple.factory( hrnID,
3340 !hrn.isSingleObject(),
3341 ReachTuple.ARITY_ONE,
3342 false // out-of-context
3345 ChangeSet cts = ChangeSet.factory();
3347 // mark hrnIDs for removal
3348 Iterator<ReachState> stateItr = hrn.getAlpha().iterator();
3349 while( stateItr.hasNext() ) {
3350 ReachState stateOld = stateItr.next();
3352 ReachState markedHrnIDs = ReachState.factory();
3354 Iterator<ReachTuple> rtItr = stateOld.iterator();
3355 while( rtItr.hasNext() ) {
3356 ReachTuple rtOld = rtItr.next();
3358 // never remove the inherent hrnID from a flagged region
3359 // because it is trivially satisfied
3360 if( hrn.isFlagged() ) {
3361 if( rtOld == rtException ) {
3366 // does boldB allow this hrnID?
3367 boolean foundState = false;
3368 Iterator<RefEdge> incidentEdgeItr = hrn.iteratorToReferencers();
3369 while( incidentEdgeItr.hasNext() ) {
3370 RefEdge incidentEdge = incidentEdgeItr.next();
3372 Hashtable<RefEdge, ReachSet> B;
3373 if( rtOld.isOutOfContext() ) {
3374 B = boldBooc.get( rtOld.getHrnID() );
3377 if( !id2hrn.containsKey( rtOld.getHrnID() ) ) {
3378 // let symbols not in the graph get pruned
3382 B = boldBic.get( rtOld.getHrnID() );
3386 ReachSet boldB_rtOld_incident = B.get( incidentEdge );
3387 if( boldB_rtOld_incident != null &&
3388 boldB_rtOld_incident.containsIgnorePreds( stateOld ) != null
3396 markedHrnIDs = Canonical.add( markedHrnIDs, rtOld );
3400 // if there is nothing marked, just move on
3401 if( markedHrnIDs.isEmpty() ) {
3402 hrn.setAlphaNew( Canonical.add( hrn.getAlphaNew(),
3409 // remove all marked hrnIDs and establish a change set that should
3410 // propagate backwards over edges from this node
3411 ReachState statePruned = ReachState.factory();
3412 rtItr = stateOld.iterator();
3413 while( rtItr.hasNext() ) {
3414 ReachTuple rtOld = rtItr.next();
3416 if( !markedHrnIDs.containsTuple( rtOld ) ) {
3417 statePruned = Canonical.add( statePruned, rtOld );
3420 assert !stateOld.equals( statePruned );
3422 hrn.setAlphaNew( Canonical.add( hrn.getAlphaNew(),
3426 ChangeTuple ct = ChangeTuple.factory( stateOld,
3429 cts = Canonical.add( cts, ct );
3432 // throw change tuple set on all incident edges
3433 if( !cts.isEmpty() ) {
3434 Iterator<RefEdge> incidentEdgeItr = hrn.iteratorToReferencers();
3435 while( incidentEdgeItr.hasNext() ) {
3436 RefEdge incidentEdge = incidentEdgeItr.next();
3438 edgesForPropagation.add( incidentEdge );
3440 if( edgePlannedChanges.get( incidentEdge ) == null ) {
3441 edgePlannedChanges.put( incidentEdge, cts );
3443 edgePlannedChanges.put(
3445 Canonical.union( edgePlannedChanges.get( incidentEdge ),
3454 HashSet<RefEdge> edgesUpdated = new HashSet<RefEdge>();
3456 propagateTokensOverEdges( edgesForPropagation,
3460 // at the end of the 1st phase reference edges have
3461 // beta, betaNew that correspond to beta and betaR
3463 // commit beta<-betaNew, so beta=betaR and betaNew
3464 // will represent the beta' calculation in 2nd phase
3466 // commit alpha<-alphaNew because it won't change
3467 HashSet<RefEdge> res = new HashSet<RefEdge>();
3469 Iterator<HeapRegionNode> nodeItr = id2hrn.values().iterator();
3470 while( nodeItr.hasNext() ) {
3471 HeapRegionNode hrn = nodeItr.next();
3473 // as mentioned above, out-of-context nodes only serve
3474 // as sources of reach states for the sweep, not part
3476 if( hrn.isOutOfContext() ) {
3477 assert hrn.getAlphaNew().equals( rsetEmpty );
3479 hrn.applyAlphaNew();
3482 Iterator<RefEdge> itrRes = hrn.iteratorToReferencers();
3483 while( itrRes.hasNext() ) {
3484 res.add( itrRes.next() );
3490 Iterator<RefEdge> edgeItr = res.iterator();
3491 while( edgeItr.hasNext() ) {
3492 RefEdge edge = edgeItr.next();
3493 HeapRegionNode hrn = edge.getDst();
3495 // commit results of last phase
3496 if( edgesUpdated.contains( edge ) ) {
3497 edge.applyBetaNew();
3500 // compute intial condition of 2nd phase
3501 edge.setBetaNew( Canonical.intersection( edge.getBeta(),
3507 // every edge in the graph is the initial workset
3508 Set<RefEdge> edgeWorkSet = (Set) res.clone();
3509 while( !edgeWorkSet.isEmpty() ) {
3510 RefEdge edgePrime = edgeWorkSet.iterator().next();
3511 edgeWorkSet.remove( edgePrime );
3513 RefSrcNode rsn = edgePrime.getSrc();
3514 if( !(rsn instanceof HeapRegionNode) ) {
3517 HeapRegionNode hrn = (HeapRegionNode) rsn;
3519 Iterator<RefEdge> itrEdge = hrn.iteratorToReferencers();
3520 while( itrEdge.hasNext() ) {
3521 RefEdge edge = itrEdge.next();
3523 ReachSet prevResult = edge.getBetaNew();
3524 assert prevResult != null;
3526 ReachSet intersection =
3527 Canonical.intersection( edge.getBeta(),
3528 edgePrime.getBetaNew()
3531 if( Canonical.unionORpreds( prevResult,
3538 Canonical.unionORpreds( prevResult,
3542 edgeWorkSet.add( edge );
3547 // commit beta' (beta<-betaNew)
3548 edgeItr = res.iterator();
3549 while( edgeItr.hasNext() ) {
3550 edgeItr.next().applyBetaNew();
3555 // a useful assertion for debugging:
3556 // every in-context tuple on any edge or
3557 // any node should name a node that is
3558 // part of the graph
3559 public boolean inContextTuplesInGraph() {
3561 Iterator hrnItr = id2hrn.entrySet().iterator();
3562 while( hrnItr.hasNext() ) {
3563 Map.Entry me = (Map.Entry) hrnItr.next();
3564 HeapRegionNode hrn = (HeapRegionNode) me.getValue();
3567 Iterator<ReachState> stateItr = hrn.getAlpha().iterator();
3568 while( stateItr.hasNext() ) {
3569 ReachState state = stateItr.next();
3571 Iterator<ReachTuple> rtItr = state.iterator();
3572 while( rtItr.hasNext() ) {
3573 ReachTuple rt = rtItr.next();
3575 if( !rt.isOutOfContext() ) {
3576 if( !id2hrn.containsKey( rt.getHrnID() ) ) {
3577 System.out.println( rt.getHrnID()+" is missing" );
3585 Iterator<RefEdge> edgeItr = hrn.iteratorToReferencers();
3586 while( edgeItr.hasNext() ) {
3587 RefEdge edge = edgeItr.next();
3589 Iterator<ReachState> stateItr = edge.getBeta().iterator();
3590 while( stateItr.hasNext() ) {
3591 ReachState state = stateItr.next();
3593 Iterator<ReachTuple> rtItr = state.iterator();
3594 while( rtItr.hasNext() ) {
3595 ReachTuple rt = rtItr.next();
3597 if( !rt.isOutOfContext() ) {
3598 if( !id2hrn.containsKey( rt.getHrnID() ) ) {
3599 System.out.println( rt.getHrnID()+" is missing" );
3612 // another useful assertion for debugging
3613 public boolean noEmptyReachSetsInGraph() {
3615 Iterator hrnItr = id2hrn.entrySet().iterator();
3616 while( hrnItr.hasNext() ) {
3617 Map.Entry me = (Map.Entry) hrnItr.next();
3618 HeapRegionNode hrn = (HeapRegionNode) me.getValue();
3620 if( !hrn.isOutOfContext() &&
3622 hrn.getAlpha().isEmpty()
3624 System.out.println( "!!! "+hrn+" has an empty ReachSet !!!" );
3628 Iterator<RefEdge> edgeItr = hrn.iteratorToReferencers();
3629 while( edgeItr.hasNext() ) {
3630 RefEdge edge = edgeItr.next();
3632 if( edge.getBeta().isEmpty() ) {
3633 System.out.println( "!!! "+edge+" has an empty ReachSet !!!" );
3643 public boolean everyReachStateWTrue() {
3645 Iterator hrnItr = id2hrn.entrySet().iterator();
3646 while( hrnItr.hasNext() ) {
3647 Map.Entry me = (Map.Entry) hrnItr.next();
3648 HeapRegionNode hrn = (HeapRegionNode) me.getValue();
3651 Iterator<ReachState> stateItr = hrn.getAlpha().iterator();
3652 while( stateItr.hasNext() ) {
3653 ReachState state = stateItr.next();
3655 if( !state.getPreds().equals( predsTrue ) ) {
3661 Iterator<RefEdge> edgeItr = hrn.iteratorToReferencers();
3662 while( edgeItr.hasNext() ) {
3663 RefEdge edge = edgeItr.next();
3665 Iterator<ReachState> stateItr = edge.getBeta().iterator();
3666 while( stateItr.hasNext() ) {
3667 ReachState state = stateItr.next();
3669 if( !state.getPreds().equals( predsTrue ) ) {
3682 ////////////////////////////////////////////////////
3683 // in merge() and equals() methods the suffix A
3684 // represents the passed in graph and the suffix
3685 // B refers to the graph in this object
3686 // Merging means to take the incoming graph A and
3687 // merge it into B, so after the operation graph B
3688 // is the final result.
3689 ////////////////////////////////////////////////////
3690 protected void merge( ReachGraph rg ) {
3697 mergeRefEdges ( rg );
3698 mergeAllocSites( rg );
3699 mergeAccessibleSet( rg );
3702 protected void mergeNodes( ReachGraph rg ) {
3704 // start with heap region nodes
3705 Set sA = rg.id2hrn.entrySet();
3706 Iterator iA = sA.iterator();
3707 while( iA.hasNext() ) {
3708 Map.Entry meA = (Map.Entry) iA.next();
3709 Integer idA = (Integer) meA.getKey();
3710 HeapRegionNode hrnA = (HeapRegionNode) meA.getValue();
3712 // if this graph doesn't have a node the
3713 // incoming graph has, allocate it
3714 if( !id2hrn.containsKey( idA ) ) {
3715 HeapRegionNode hrnB = hrnA.copy();
3716 id2hrn.put( idA, hrnB );
3719 // otherwise this is a node present in both graphs
3720 // so make the new reachability set a union of the
3721 // nodes' reachability sets
3722 HeapRegionNode hrnB = id2hrn.get( idA );
3723 hrnB.setAlpha( Canonical.unionORpreds( hrnB.getAlpha(),
3728 hrnB.setPreds( Canonical.join( hrnB.getPreds(),
3735 if( !hrnA.equals( hrnB ) ) {
3736 rg.writeGraph( "graphA" );
3737 this.writeGraph( "graphB" );
3738 throw new Error( "flagged not matching" );
3746 // now add any variable nodes that are in graph B but
3748 sA = rg.td2vn.entrySet();
3750 while( iA.hasNext() ) {
3751 Map.Entry meA = (Map.Entry) iA.next();
3752 TempDescriptor tdA = (TempDescriptor) meA.getKey();
3753 VariableNode lnA = (VariableNode) meA.getValue();
3755 // if the variable doesn't exist in B, allocate and add it
3756 VariableNode lnB = getVariableNodeFromTemp( tdA );
3760 protected void mergeRefEdges( ReachGraph rg ) {
3762 // between heap regions
3763 Set sA = rg.id2hrn.entrySet();
3764 Iterator iA = sA.iterator();
3765 while( iA.hasNext() ) {
3766 Map.Entry meA = (Map.Entry) iA.next();
3767 Integer idA = (Integer) meA.getKey();
3768 HeapRegionNode hrnA = (HeapRegionNode) meA.getValue();
3770 Iterator<RefEdge> heapRegionsItrA = hrnA.iteratorToReferencees();
3771 while( heapRegionsItrA.hasNext() ) {
3772 RefEdge edgeA = heapRegionsItrA.next();
3773 HeapRegionNode hrnChildA = edgeA.getDst();
3774 Integer idChildA = hrnChildA.getID();
3776 // at this point we know an edge in graph A exists
3777 // idA -> idChildA, does this exist in B?
3778 assert id2hrn.containsKey( idA );
3779 HeapRegionNode hrnB = id2hrn.get( idA );
3780 RefEdge edgeToMerge = null;
3782 Iterator<RefEdge> heapRegionsItrB = hrnB.iteratorToReferencees();
3783 while( heapRegionsItrB.hasNext() &&
3784 edgeToMerge == null ) {
3786 RefEdge edgeB = heapRegionsItrB.next();
3787 HeapRegionNode hrnChildB = edgeB.getDst();
3788 Integer idChildB = hrnChildB.getID();
3790 // don't use the RefEdge.equals() here because
3791 // we're talking about existence between graphs,
3792 // not intragraph equal
3793 if( idChildB.equals( idChildA ) &&
3794 edgeB.typeAndFieldEquals( edgeA ) ) {
3796 edgeToMerge = edgeB;
3800 // if the edge from A was not found in B,
3802 if( edgeToMerge == null ) {
3803 assert id2hrn.containsKey( idChildA );
3804 HeapRegionNode hrnChildB = id2hrn.get( idChildA );
3805 edgeToMerge = edgeA.copy();
3806 edgeToMerge.setSrc( hrnB );
3807 edgeToMerge.setDst( hrnChildB );
3808 addRefEdge( hrnB, hrnChildB, edgeToMerge );
3810 // otherwise, the edge already existed in both graphs
3811 // so merge their reachability sets
3813 // just replace this beta set with the union
3814 assert edgeToMerge != null;
3815 edgeToMerge.setBeta(
3816 Canonical.unionORpreds( edgeToMerge.getBeta(),
3820 edgeToMerge.setPreds(
3821 Canonical.join( edgeToMerge.getPreds(),
3825 edgeToMerge.setTaints(
3826 Canonical.union( edgeToMerge.getTaints(),
3834 // and then again from variable nodes
3835 sA = rg.td2vn.entrySet();
3837 while( iA.hasNext() ) {
3838 Map.Entry meA = (Map.Entry) iA.next();
3839 TempDescriptor tdA = (TempDescriptor) meA.getKey();
3840 VariableNode vnA = (VariableNode) meA.getValue();
3842 Iterator<RefEdge> heapRegionsItrA = vnA.iteratorToReferencees();
3843 while( heapRegionsItrA.hasNext() ) {
3844 RefEdge edgeA = heapRegionsItrA.next();
3845 HeapRegionNode hrnChildA = edgeA.getDst();
3846 Integer idChildA = hrnChildA.getID();
3848 // at this point we know an edge in graph A exists
3849 // tdA -> idChildA, does this exist in B?
3850 assert td2vn.containsKey( tdA );
3851 VariableNode vnB = td2vn.get( tdA );
3852 RefEdge edgeToMerge = null;
3854 Iterator<RefEdge> heapRegionsItrB = vnB.iteratorToReferencees();
3855 while( heapRegionsItrB.hasNext() &&
3856 edgeToMerge == null ) {
3858 RefEdge edgeB = heapRegionsItrB.next();
3859 HeapRegionNode hrnChildB = edgeB.getDst();
3860 Integer idChildB = hrnChildB.getID();
3862 // don't use the RefEdge.equals() here because
3863 // we're talking about existence between graphs
3864 if( idChildB.equals( idChildA ) &&
3865 edgeB.typeAndFieldEquals( edgeA ) ) {
3867 edgeToMerge = edgeB;
3871 // if the edge from A was not found in B,
3873 if( edgeToMerge == null ) {
3874 assert id2hrn.containsKey( idChildA );
3875 HeapRegionNode hrnChildB = id2hrn.get( idChildA );
3876 edgeToMerge = edgeA.copy();
3877 edgeToMerge.setSrc( vnB );
3878 edgeToMerge.setDst( hrnChildB );
3879 addRefEdge( vnB, hrnChildB, edgeToMerge );
3881 // otherwise, the edge already existed in both graphs
3882 // so merge their reachability sets
3884 // just replace this beta set with the union
3885 edgeToMerge.setBeta( Canonical.unionORpreds( edgeToMerge.getBeta(),
3889 edgeToMerge.setPreds( Canonical.join( edgeToMerge.getPreds(),
3893 edgeToMerge.setTaints(
3894 Canonical.union( edgeToMerge.getTaints(),
3903 protected void mergeAllocSites( ReachGraph rg ) {
3904 allocSites.addAll( rg.allocSites );
3907 protected void mergeAccessibleSet( ReachGraph rg ){
3908 // inaccesible status is prior to accessible status
3910 Set<TempDescriptor> varsToMerge=rg.getAccessibleVar();
3911 Set<TempDescriptor> varsRemoved=new HashSet<TempDescriptor>();
3913 for (Iterator iterator = accessibleVars.iterator(); iterator.hasNext();) {
3914 TempDescriptor accessibleVar = (TempDescriptor) iterator.next();
3915 if(!varsToMerge.contains(accessibleVar)){
3916 varsRemoved.add(accessibleVar);
3920 accessibleVars.removeAll(varsRemoved);
3926 static boolean dbgEquals = false;
3929 // it is necessary in the equals() member functions
3930 // to "check both ways" when comparing the data
3931 // structures of two graphs. For instance, if all
3932 // edges between heap region nodes in graph A are
3933 // present and equal in graph B it is not sufficient
3934 // to say the graphs are equal. Consider that there
3935 // may be edges in graph B that are not in graph A.
3936 // the only way to know that all edges in both graphs
3937 // are equally present is to iterate over both data
3938 // structures and compare against the other graph.
3939 public boolean equals( ReachGraph rg ) {
3943 System.out.println( "rg is null" );
3948 if( !areHeapRegionNodesEqual( rg ) ) {
3950 System.out.println( "hrn not equal" );
3955 if( !areVariableNodesEqual( rg ) ) {
3957 System.out.println( "vars not equal" );
3962 if( !areRefEdgesEqual( rg ) ) {
3964 System.out.println( "edges not equal" );
3969 if( !accessibleVars.equals( rg.accessibleVars) ){
3973 // if everything is equal up to this point,
3974 // assert that allocSites is also equal--
3975 // this data is redundant but kept for efficiency
3976 assert allocSites.equals( rg.allocSites );
3982 protected boolean areHeapRegionNodesEqual( ReachGraph rg ) {
3984 if( !areallHRNinAalsoinBandequal( this, rg ) ) {
3988 if( !areallHRNinAalsoinBandequal( rg, this ) ) {
3995 static protected boolean areallHRNinAalsoinBandequal( ReachGraph rgA,
3997 Set sA = rgA.id2hrn.entrySet();
3998 Iterator iA = sA.iterator();
3999 while( iA.hasNext() ) {
4000 Map.Entry meA = (Map.Entry) iA.next();
4001 Integer idA = (Integer) meA.getKey();
4002 HeapRegionNode hrnA = (HeapRegionNode) meA.getValue();
4004 if( !rgB.id2hrn.containsKey( idA ) ) {
4008 HeapRegionNode hrnB = rgB.id2hrn.get( idA );
4009 if( !hrnA.equalsIncludingAlphaAndPreds( hrnB ) ) {
4017 protected boolean areVariableNodesEqual( ReachGraph rg ) {
4019 if( !areallVNinAalsoinBandequal( this, rg ) ) {
4023 if( !areallVNinAalsoinBandequal( rg, this ) ) {
4030 static protected boolean areallVNinAalsoinBandequal( ReachGraph rgA,
4032 Set sA = rgA.td2vn.entrySet();
4033 Iterator iA = sA.iterator();
4034 while( iA.hasNext() ) {
4035 Map.Entry meA = (Map.Entry) iA.next();
4036 TempDescriptor tdA = (TempDescriptor) meA.getKey();
4038 if( !rgB.td2vn.containsKey( tdA ) ) {
4047 protected boolean areRefEdgesEqual( ReachGraph rg ) {
4048 if( !areallREinAandBequal( this, rg ) ) {
4052 if( !areallREinAandBequal( rg, this ) ) {
4059 static protected boolean areallREinAandBequal( ReachGraph rgA,
4062 // check all the heap region->heap region edges
4063 Set sA = rgA.id2hrn.entrySet();
4064 Iterator iA = sA.iterator();
4065 while( iA.hasNext() ) {
4066 Map.Entry meA = (Map.Entry) iA.next();
4067 Integer idA = (Integer) meA.getKey();
4068 HeapRegionNode hrnA = (HeapRegionNode) meA.getValue();
4070 // we should have already checked that the same
4071 // heap regions exist in both graphs
4072 assert rgB.id2hrn.containsKey( idA );
4074 if( !areallREfromAequaltoB( rgA, hrnA, rgB ) ) {
4078 // then check every edge in B for presence in A, starting
4079 // from the same parent HeapRegionNode
4080 HeapRegionNode hrnB = rgB.id2hrn.get( idA );
4082 if( !areallREfromAequaltoB( rgB, hrnB, rgA ) ) {
4087 // then check all the variable->heap region edges
4088 sA = rgA.td2vn.entrySet();
4090 while( iA.hasNext() ) {
4091 Map.Entry meA = (Map.Entry) iA.next();
4092 TempDescriptor tdA = (TempDescriptor) meA.getKey();
4093 VariableNode vnA = (VariableNode) meA.getValue();
4095 // we should have already checked that the same
4096 // label nodes exist in both graphs
4097 assert rgB.td2vn.containsKey( tdA );
4099 if( !areallREfromAequaltoB( rgA, vnA, rgB ) ) {
4103 // then check every edge in B for presence in A, starting
4104 // from the same parent VariableNode
4105 VariableNode vnB = rgB.td2vn.get( tdA );
4107 if( !areallREfromAequaltoB( rgB, vnB, rgA ) ) {
4116 static protected boolean areallREfromAequaltoB( ReachGraph rgA,
4120 Iterator<RefEdge> itrA = rnA.iteratorToReferencees();
4121 while( itrA.hasNext() ) {
4122 RefEdge edgeA = itrA.next();
4123 HeapRegionNode hrnChildA = edgeA.getDst();
4124 Integer idChildA = hrnChildA.getID();
4126 assert rgB.id2hrn.containsKey( idChildA );
4128 // at this point we know an edge in graph A exists
4129 // rnA -> idChildA, does this exact edge exist in B?
4130 boolean edgeFound = false;
4132 RefSrcNode rnB = null;
4133 if( rnA instanceof HeapRegionNode ) {
4134 HeapRegionNode hrnA = (HeapRegionNode) rnA;
4135 rnB = rgB.id2hrn.get( hrnA.getID() );
4137 VariableNode vnA = (VariableNode) rnA;
4138 rnB = rgB.td2vn.get( vnA.getTempDescriptor() );
4141 Iterator<RefEdge> itrB = rnB.iteratorToReferencees();
4142 while( itrB.hasNext() ) {
4143 RefEdge edgeB = itrB.next();
4144 HeapRegionNode hrnChildB = edgeB.getDst();
4145 Integer idChildB = hrnChildB.getID();
4147 if( idChildA.equals( idChildB ) &&
4148 edgeA.typeAndFieldEquals( edgeB ) ) {
4150 // there is an edge in the right place with the right field,
4151 // but do they have the same attributes?
4152 if( edgeA.getBeta().equals( edgeB.getBeta() ) &&
4153 edgeA.equalsPreds( edgeB )
4169 // can be used to assert monotonicity
4170 static public boolean isNoSmallerThan( ReachGraph rgA,
4173 //System.out.println( "*** Asking if A is no smaller than B ***" );
4176 Iterator iA = rgA.id2hrn.entrySet().iterator();
4177 while( iA.hasNext() ) {
4178 Map.Entry meA = (Map.Entry) iA.next();
4179 Integer idA = (Integer) meA.getKey();
4180 HeapRegionNode hrnA = (HeapRegionNode) meA.getValue();
4182 if( !rgB.id2hrn.containsKey( idA ) ) {
4183 System.out.println( " regions smaller" );
4187 //HeapRegionNode hrnB = rgB.id2hrn.get( idA );
4188 /* NOT EQUALS, NO SMALLER THAN!
4189 if( !hrnA.equalsIncludingAlphaAndPreds( hrnB ) ) {
4190 System.out.println( " regions smaller" );
4196 // this works just fine, no smaller than
4197 if( !areallVNinAalsoinBandequal( rgA, rgB ) ) {
4198 System.out.println( " vars smaller:" );
4199 System.out.println( " A:"+rgA.td2vn.keySet() );
4200 System.out.println( " B:"+rgB.td2vn.keySet() );
4205 iA = rgA.id2hrn.entrySet().iterator();
4206 while( iA.hasNext() ) {
4207 Map.Entry meA = (Map.Entry) iA.next();
4208 Integer idA = (Integer) meA.getKey();
4209 HeapRegionNode hrnA = (HeapRegionNode) meA.getValue();
4211 Iterator<RefEdge> reItr = hrnA.iteratorToReferencers();
4212 while( reItr.hasNext() ) {
4213 RefEdge edgeA = reItr.next();
4214 RefSrcNode rsnA = edgeA.getSrc();
4216 // we already checked that nodes were present
4217 HeapRegionNode hrnB = rgB.id2hrn.get( hrnA.getID() );
4218 assert hrnB != null;
4221 if( rsnA instanceof VariableNode ) {
4222 VariableNode vnA = (VariableNode) rsnA;
4223 rsnB = rgB.td2vn.get( vnA.getTempDescriptor() );
4226 HeapRegionNode hrnSrcA = (HeapRegionNode) rsnA;
4227 rsnB = rgB.id2hrn.get( hrnSrcA.getID() );
4229 assert rsnB != null;
4231 RefEdge edgeB = rsnB.getReferenceTo( hrnB,
4235 if( edgeB == null ) {
4236 System.out.println( " edges smaller:" );
4240 // REMEMBER, IS NO SMALLER THAN
4242 System.out.println( " edges smaller" );
4258 // this analysis no longer has the "match anything"
4259 // type which was represented by null
4260 protected TypeDescriptor mostSpecificType( TypeDescriptor td1,
4261 TypeDescriptor td2 ) {
4265 if( td1.isNull() ) {
4268 if( td2.isNull() ) {
4271 return typeUtil.mostSpecific( td1, td2 );
4274 protected TypeDescriptor mostSpecificType( TypeDescriptor td1,
4276 TypeDescriptor td3 ) {
4278 return mostSpecificType( td1,
4279 mostSpecificType( td2, td3 )
4283 protected TypeDescriptor mostSpecificType( TypeDescriptor td1,
4286 TypeDescriptor td4 ) {
4288 return mostSpecificType( mostSpecificType( td1, td2 ),
4289 mostSpecificType( td3, td4 )
4293 protected boolean isSuperiorType( TypeDescriptor possibleSuper,
4294 TypeDescriptor possibleChild ) {
4295 assert possibleSuper != null;
4296 assert possibleChild != null;
4298 if( possibleSuper.isNull() ||
4299 possibleChild.isNull() ) {
4303 return typeUtil.isSuperorType( possibleSuper, possibleChild );
4307 protected boolean hasMatchingField( HeapRegionNode src,
4310 TypeDescriptor tdSrc = src.getType();
4311 assert tdSrc != null;
4313 if( tdSrc.isArray() ) {
4314 TypeDescriptor td = edge.getType();
4317 TypeDescriptor tdSrcDeref = tdSrc.dereference();
4318 assert tdSrcDeref != null;
4320 if( !typeUtil.isSuperorType( tdSrcDeref, td ) ) {
4324 return edge.getField().equals( DisjointAnalysis.arrayElementFieldName );
4327 // if it's not a class, it doesn't have any fields to match
4328 if( !tdSrc.isClass() ) {
4332 ClassDescriptor cd = tdSrc.getClassDesc();
4333 while( cd != null ) {
4334 Iterator fieldItr = cd.getFields();
4336 while( fieldItr.hasNext() ) {
4337 FieldDescriptor fd = (FieldDescriptor) fieldItr.next();
4339 if( fd.getType().equals( edge.getType() ) &&
4340 fd.getSymbol().equals( edge.getField() ) ) {
4345 cd = cd.getSuperDesc();
4348 // otherwise it is a class with fields
4349 // but we didn't find a match
4353 protected boolean hasMatchingType( RefEdge edge,
4354 HeapRegionNode dst ) {
4356 // if the region has no type, matches everything
4357 TypeDescriptor tdDst = dst.getType();
4358 assert tdDst != null;
4360 // if the type is not a class or an array, don't
4361 // match because primitives are copied, no aliases
4362 ClassDescriptor cdDst = tdDst.getClassDesc();
4363 if( cdDst == null && !tdDst.isArray() ) {
4367 // if the edge type is null, it matches everything
4368 TypeDescriptor tdEdge = edge.getType();
4369 assert tdEdge != null;
4371 return typeUtil.isSuperorType( tdEdge, tdDst );
4376 // the default signature for quick-and-dirty debugging
4377 public void writeGraph( String graphName ) {
4378 writeGraph( graphName,
4379 true, // write labels
4380 true, // label select
4381 true, // prune garbage
4382 false, // hide reachability
4383 true, // hide subset reachability
4384 true, // hide predicates
4385 true, // hide edge taints
4386 null // in-context boundary
4390 public void writeGraph( String graphName,
4391 boolean writeLabels,
4392 boolean labelSelect,
4393 boolean pruneGarbage,
4394 boolean hideReachability,
4395 boolean hideSubsetReachability,
4396 boolean hidePredicates,
4397 boolean hideEdgeTaints
4399 writeGraph( graphName,
4404 hideSubsetReachability,
4410 public void writeGraph( String graphName,
4411 boolean writeLabels,
4412 boolean labelSelect,
4413 boolean pruneGarbage,
4414 boolean hideReachability,
4415 boolean hideSubsetReachability,
4416 boolean hidePredicates,
4417 boolean hideEdgeTaints,
4418 Set<Integer> callerNodeIDsCopiedToCallee
4422 // remove all non-word characters from the graph name so
4423 // the filename and identifier in dot don't cause errors
4424 graphName = graphName.replaceAll( "[\\W]", "" );
4427 new BufferedWriter( new FileWriter( graphName+".dot" ) );
4429 bw.write( "digraph "+graphName+" {\n" );
4432 // this is an optional step to form the callee-reachable
4433 // "cut-out" into a DOT cluster for visualization
4434 if( callerNodeIDsCopiedToCallee != null ) {
4436 bw.write( " subgraph cluster0 {\n" );
4437 bw.write( " color=blue;\n" );
4439 Iterator i = id2hrn.entrySet().iterator();
4440 while( i.hasNext() ) {
4441 Map.Entry me = (Map.Entry) i.next();
4442 HeapRegionNode hrn = (HeapRegionNode) me.getValue();
4444 if( callerNodeIDsCopiedToCallee.contains( hrn.getID() ) ) {
4447 hrn.toStringDOT( hideReachability,
4448 hideSubsetReachability,
4458 Set<HeapRegionNode> visited = new HashSet<HeapRegionNode>();
4460 // then visit every heap region node
4461 Iterator i = id2hrn.entrySet().iterator();
4462 while( i.hasNext() ) {
4463 Map.Entry me = (Map.Entry) i.next();
4464 HeapRegionNode hrn = (HeapRegionNode) me.getValue();
4466 // only visit nodes worth writing out--for instance
4467 // not every node at an allocation is referenced
4468 // (think of it as garbage-collected), etc.
4469 if( !pruneGarbage ||
4470 hrn.isOutOfContext() ||
4471 (hrn.isFlagged() && hrn.getID() > 0 && !hrn.isWiped()) // a non-shadow flagged node
4474 if( !visited.contains( hrn ) ) {
4475 traverseHeapRegionNodes( hrn,
4480 hideSubsetReachability,
4483 callerNodeIDsCopiedToCallee );
4488 bw.write( " graphTitle[label=\""+graphName+"\",shape=box];\n" );
4491 // then visit every label node, useful for debugging
4493 i = td2vn.entrySet().iterator();
4494 while( i.hasNext() ) {
4495 Map.Entry me = (Map.Entry) i.next();
4496 VariableNode vn = (VariableNode) me.getValue();
4499 String labelStr = vn.getTempDescriptorString();
4500 if( labelStr.startsWith( "___temp" ) ||
4501 labelStr.startsWith( "___dst" ) ||
4502 labelStr.startsWith( "___srctmp" ) ||
4503 labelStr.startsWith( "___neverused" )
4509 Iterator<RefEdge> heapRegionsItr = vn.iteratorToReferencees();
4510 while( heapRegionsItr.hasNext() ) {
4511 RefEdge edge = heapRegionsItr.next();
4512 HeapRegionNode hrn = edge.getDst();
4514 if( !visited.contains( hrn ) ) {
4515 traverseHeapRegionNodes( hrn,
4520 hideSubsetReachability,
4523 callerNodeIDsCopiedToCallee );
4526 bw.write( " "+vn.toString()+
4527 " -> "+hrn.toString()+
4528 edge.toStringDOT( hideReachability,
4529 hideSubsetReachability,
4541 } catch( IOException e ) {
4542 throw new Error( "Error writing out DOT graph "+graphName );
4547 traverseHeapRegionNodes( HeapRegionNode hrn,
4550 Set<HeapRegionNode> visited,
4551 boolean hideReachability,
4552 boolean hideSubsetReachability,
4553 boolean hidePredicates,
4554 boolean hideEdgeTaints,
4555 Set<Integer> callerNodeIDsCopiedToCallee
4556 ) throws java.io.IOException {
4558 if( visited.contains( hrn ) ) {
4563 // if we're drawing the callee-view subgraph, only
4564 // write out the node info if it hasn't already been
4566 if( callerNodeIDsCopiedToCallee == null ||
4567 !callerNodeIDsCopiedToCallee.contains( hrn.getID() )
4571 hrn.toStringDOT( hideReachability,
4572 hideSubsetReachability,
4577 Iterator<RefEdge> childRegionsItr = hrn.iteratorToReferencees();
4578 while( childRegionsItr.hasNext() ) {
4579 RefEdge edge = childRegionsItr.next();
4580 HeapRegionNode hrnChild = edge.getDst();
4582 if( callerNodeIDsCopiedToCallee != null &&
4583 (edge.getSrc() instanceof HeapRegionNode) ) {
4584 HeapRegionNode hrnSrc = (HeapRegionNode) edge.getSrc();
4585 if( callerNodeIDsCopiedToCallee.contains( hrnSrc.getID() ) &&
4586 callerNodeIDsCopiedToCallee.contains( edge.getDst().getID() )
4588 bw.write( " "+hrn.toString()+
4589 " -> "+hrnChild.toString()+
4590 edge.toStringDOT( hideReachability,
4591 hideSubsetReachability,
4596 } else if( !callerNodeIDsCopiedToCallee.contains( hrnSrc.getID() ) &&
4597 callerNodeIDsCopiedToCallee.contains( edge.getDst().getID() )
4599 bw.write( " "+hrn.toString()+
4600 " -> "+hrnChild.toString()+
4601 edge.toStringDOT( hideReachability,
4602 hideSubsetReachability,
4605 ",color=blue,style=dashed" )+
4608 bw.write( " "+hrn.toString()+
4609 " -> "+hrnChild.toString()+
4610 edge.toStringDOT( hideReachability,
4611 hideSubsetReachability,
4618 bw.write( " "+hrn.toString()+
4619 " -> "+hrnChild.toString()+
4620 edge.toStringDOT( hideReachability,
4621 hideSubsetReachability,
4628 traverseHeapRegionNodes( hrnChild,
4633 hideSubsetReachability,
4636 callerNodeIDsCopiedToCallee );
4644 public Set<HeapRegionNode> findCommonReachableNodes( ReachSet proofOfSharing ) {
4646 Set<HeapRegionNode> exhibitProofState =
4647 new HashSet<HeapRegionNode>();
4649 Iterator hrnItr = id2hrn.entrySet().iterator();
4650 while( hrnItr.hasNext() ) {
4651 Map.Entry me = (Map.Entry) hrnItr.next();
4652 HeapRegionNode hrn = (HeapRegionNode) me.getValue();
4654 ReachSet intersection =
4655 Canonical.intersection( proofOfSharing,
4658 if( !intersection.isEmpty() ) {
4659 assert !hrn.isOutOfContext();
4660 exhibitProofState.add( hrn );
4664 return exhibitProofState;
4668 public Set<HeapRegionNode> mayReachSharedObjects(HeapRegionNode hrn1,
4669 HeapRegionNode hrn2) {
4670 assert hrn1 != null;
4671 assert hrn2 != null;
4673 assert !hrn1.isOutOfContext();
4674 assert !hrn2.isOutOfContext();
4676 assert belongsToThis( hrn1 );
4677 assert belongsToThis( hrn2 );
4679 assert !hrn1.getID().equals( hrn2.getID() );
4682 // then get the various tokens for these heap regions
4684 ReachTuple.factory( hrn1.getID(),
4685 !hrn1.isSingleObject(), // multi?
4686 ReachTuple.ARITY_ONE,
4689 ReachTuple h1star = null;
4690 if( !hrn1.isSingleObject() ) {
4692 ReachTuple.factory( hrn1.getID(),
4693 !hrn1.isSingleObject(),
4694 ReachTuple.ARITY_ZEROORMORE,
4699 ReachTuple.factory( hrn2.getID(),
4700 !hrn2.isSingleObject(),
4701 ReachTuple.ARITY_ONE,
4704 ReachTuple h2star = null;
4705 if( !hrn2.isSingleObject() ) {
4707 ReachTuple.factory( hrn2.getID(),
4708 !hrn2.isSingleObject(),
4709 ReachTuple.ARITY_ZEROORMORE,
4713 // then get the merged beta of all out-going edges from these heap
4716 ReachSet beta1 = ReachSet.factory();
4717 Iterator<RefEdge> itrEdge = hrn1.iteratorToReferencees();
4718 while (itrEdge.hasNext()) {
4719 RefEdge edge = itrEdge.next();
4720 beta1 = Canonical.unionORpreds(beta1, edge.getBeta());
4723 ReachSet beta2 = ReachSet.factory();
4724 itrEdge = hrn2.iteratorToReferencees();
4725 while (itrEdge.hasNext()) {
4726 RefEdge edge = itrEdge.next();
4727 beta2 = Canonical.unionORpreds(beta2, edge.getBeta());
4730 ReachSet proofOfSharing = ReachSet.factory();
4733 Canonical.unionORpreds( proofOfSharing,
4734 beta1.getStatesWithBoth( h1, h2 )
4737 Canonical.unionORpreds( proofOfSharing,
4738 beta2.getStatesWithBoth( h1, h2 )
4741 if( !hrn1.isSingleObject() ) {
4743 Canonical.unionORpreds( proofOfSharing,
4744 beta1.getStatesWithBoth( h1star, h2 )
4747 Canonical.unionORpreds( proofOfSharing,
4748 beta2.getStatesWithBoth( h1star, h2 )
4752 if( !hrn2.isSingleObject() ) {
4754 Canonical.unionORpreds( proofOfSharing,
4755 beta1.getStatesWithBoth( h1, h2star )
4758 Canonical.unionORpreds( proofOfSharing,
4759 beta2.getStatesWithBoth( h1, h2star )
4763 if( !hrn1.isSingleObject() &&
4764 !hrn2.isSingleObject()
4767 Canonical.unionORpreds( proofOfSharing,
4768 beta1.getStatesWithBoth( h1star, h2star )
4771 Canonical.unionORpreds( proofOfSharing,
4772 beta2.getStatesWithBoth( h1star, h2star )
4776 Set<HeapRegionNode> common = new HashSet<HeapRegionNode>();
4777 if( !proofOfSharing.isEmpty() ) {
4778 common = findCommonReachableNodes( proofOfSharing );
4779 if( !DISABLE_STRONG_UPDATES &&
4780 !DISABLE_GLOBAL_SWEEP
4782 assert !common.isEmpty();
4789 // this version of the above method checks whether there is sharing
4790 // among the objects in a summary node
4791 public Set<HeapRegionNode> mayReachSharedObjects(HeapRegionNode hrn) {
4793 assert hrn.isNewSummary();
4794 assert !hrn.isOutOfContext();
4795 assert belongsToThis( hrn );
4798 ReachTuple.factory( hrn.getID(),
4800 ReachTuple.ARITY_ZEROORMORE,
4803 // then get the merged beta of all out-going edges from
4806 ReachSet beta = ReachSet.factory();
4807 Iterator<RefEdge> itrEdge = hrn.iteratorToReferencees();
4808 while (itrEdge.hasNext()) {
4809 RefEdge edge = itrEdge.next();
4810 beta = Canonical.unionORpreds(beta, edge.getBeta());
4813 ReachSet proofOfSharing = ReachSet.factory();
4816 Canonical.unionORpreds( proofOfSharing,
4817 beta.getStatesWithBoth( hstar, hstar )
4820 Set<HeapRegionNode> common = new HashSet<HeapRegionNode>();
4821 if( !proofOfSharing.isEmpty() ) {
4822 common = findCommonReachableNodes( proofOfSharing );
4823 if( !DISABLE_STRONG_UPDATES &&
4824 !DISABLE_GLOBAL_SWEEP
4826 assert !common.isEmpty();
4834 public Set<HeapRegionNode> mayReachSharedObjects(FlatMethod fm,
4835 Integer paramIndex1,
4836 Integer paramIndex2) {
4838 // get parameter's heap regions
4839 TempDescriptor paramTemp1 = fm.getParameter(paramIndex1.intValue());
4840 assert this.hasVariable( paramTemp1 );
4841 VariableNode paramVar1 = getVariableNodeFromTemp(paramTemp1);
4844 if( !(paramVar1.getNumReferencees() == 1) ) {
4845 System.out.println( "\n fm="+fm+"\n param="+paramTemp1 );
4846 writeGraph( "whatup" );
4850 assert paramVar1.getNumReferencees() == 1;
4851 RefEdge paramEdge1 = paramVar1.iteratorToReferencees().next();
4852 HeapRegionNode hrnParam1 = paramEdge1.getDst();
4854 TempDescriptor paramTemp2 = fm.getParameter(paramIndex2.intValue());
4855 assert this.hasVariable( paramTemp2 );
4856 VariableNode paramVar2 = getVariableNodeFromTemp(paramTemp2);
4858 if( !(paramVar2.getNumReferencees() == 1) ) {
4859 System.out.println( "\n fm="+fm+"\n param="+paramTemp2 );
4860 writeGraph( "whatup" );
4863 assert paramVar2.getNumReferencees() == 1;
4864 RefEdge paramEdge2 = paramVar2.iteratorToReferencees().next();
4865 HeapRegionNode hrnParam2 = paramEdge2.getDst();
4867 Set<HeapRegionNode> common = new HashSet<HeapRegionNode>();
4868 common.addAll(mayReachSharedObjects(hrnParam1, hrnParam2));
4873 public Set<HeapRegionNode> mayReachSharedObjects(FlatMethod fm,
4877 // get parameter's heap regions
4878 TempDescriptor paramTemp = fm.getParameter(paramIndex.intValue());
4879 assert this.hasVariable( paramTemp );
4880 VariableNode paramVar = getVariableNodeFromTemp(paramTemp);
4881 assert paramVar.getNumReferencees() == 1;
4882 RefEdge paramEdge = paramVar.iteratorToReferencees().next();
4883 HeapRegionNode hrnParam = paramEdge.getDst();
4886 HeapRegionNode hrnSummary=null;
4887 if(id2hrn.containsKey(as.getSummary())){
4888 // if summary node doesn't exist, ignore this case
4889 hrnSummary = id2hrn.get(as.getSummary());
4890 assert hrnSummary != null;
4893 Set<HeapRegionNode> common = new HashSet<HeapRegionNode>();
4894 if(hrnSummary!=null){
4895 common.addAll( mayReachSharedObjects(hrnParam, hrnSummary) );
4898 // check for other nodes
4899 for (int i = 0; i < as.getAllocationDepth(); ++i) {
4901 assert id2hrn.containsKey(as.getIthOldest(i));
4902 HeapRegionNode hrnIthOldest = id2hrn.get(as.getIthOldest(i));
4903 assert hrnIthOldest != null;
4905 common.addAll(mayReachSharedObjects(hrnParam, hrnIthOldest));
4912 public Set<HeapRegionNode> mayReachSharedObjects(AllocSite as1,
4915 // get summary node 1's alpha
4916 Integer idSum1 = as1.getSummary();
4917 HeapRegionNode hrnSum1=null;
4918 if(id2hrn.containsKey(idSum1)){
4919 hrnSum1 = id2hrn.get(idSum1);
4922 // get summary node 2's alpha
4923 Integer idSum2 = as2.getSummary();
4924 HeapRegionNode hrnSum2=null;
4925 if(id2hrn.containsKey(idSum2)){
4926 hrnSum2 = id2hrn.get(idSum2);
4929 Set<HeapRegionNode> common = new HashSet<HeapRegionNode>();
4930 if(hrnSum1!=null && hrnSum2!=null && hrnSum1!=hrnSum2){
4931 common.addAll(mayReachSharedObjects(hrnSum1, hrnSum2));
4935 // ask if objects from this summary share among each other
4936 common.addAll(mayReachSharedObjects(hrnSum1));
4939 // check sum2 against alloc1 nodes
4941 for (int i = 0; i < as1.getAllocationDepth(); ++i) {
4942 Integer idI1 = as1.getIthOldest(i);
4943 assert id2hrn.containsKey(idI1);
4944 HeapRegionNode hrnI1 = id2hrn.get(idI1);
4945 assert hrnI1 != null;
4946 common.addAll(mayReachSharedObjects(hrnI1, hrnSum2));
4949 // also ask if objects from this summary share among each other
4950 common.addAll(mayReachSharedObjects(hrnSum2));
4953 // check sum1 against alloc2 nodes
4954 for (int i = 0; i < as2.getAllocationDepth(); ++i) {
4955 Integer idI2 = as2.getIthOldest(i);
4956 assert id2hrn.containsKey(idI2);
4957 HeapRegionNode hrnI2 = id2hrn.get(idI2);
4958 assert hrnI2 != null;
4961 common.addAll(mayReachSharedObjects(hrnSum1, hrnI2));
4964 // while we're at it, do an inner loop for alloc2 vs alloc1 nodes
4965 for (int j = 0; j < as1.getAllocationDepth(); ++j) {
4966 Integer idI1 = as1.getIthOldest(j);
4968 // if these are the same site, don't look for the same token, no
4970 // different tokens of the same site could alias together though
4971 if (idI1.equals(idI2)) {
4975 HeapRegionNode hrnI1 = id2hrn.get(idI1);
4977 common.addAll(mayReachSharedObjects(hrnI1, hrnI2));
4984 public void addAccessibleVar(TempDescriptor td){
4985 accessibleVars.add(td);
4988 public Set<TempDescriptor> getAccessibleVar(){
4989 return accessibleVars;
4992 public void clearAccessibleVarSet(){
4993 accessibleVars.clear();