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 // some frequently used reachability constants
19 protected static final ReachState rstateEmpty = ReachState.factory();
20 protected static final ReachSet rsetEmpty = ReachSet.factory();
21 protected static final ReachSet rsetWithEmptyState = Canonical.makePredsTrue(ReachSet.factory( rstateEmpty ));
23 // predicate constants
24 public static final ExistPred predTrue = ExistPred.factory(); // if no args, true
25 public static final ExistPredSet predsEmpty = ExistPredSet.factory();
26 public static final ExistPredSet predsTrue = ExistPredSet.factory( predTrue );
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.makePredsTrue(
140 ReachTuple.factory( id,
142 ReachTuple.ARITY_ONE,
143 false // out-of-context
149 inherent = rsetWithEmptyState;
153 if( alpha == null ) {
157 assert preds != null;
159 HeapRegionNode hrn = new HeapRegionNode( id,
170 id2hrn.put( id, hrn );
176 ////////////////////////////////////////////////
178 // Low-level referencee and referencer methods
180 // These methods provide the lowest level for
181 // creating references between reachability nodes
182 // and handling the details of maintaining both
183 // list of referencers and referencees.
185 ////////////////////////////////////////////////
186 protected void addRefEdge( RefSrcNode referencer,
187 HeapRegionNode referencee,
189 assert referencer != null;
190 assert referencee != null;
192 assert edge.getSrc() == referencer;
193 assert edge.getDst() == referencee;
194 assert belongsToThis( referencer );
195 assert belongsToThis( referencee );
197 // edges are getting added twice to graphs now, the
198 // kind that should have abstract facts merged--use
199 // this check to prevent that
200 assert referencer.getReferenceTo( referencee,
205 referencer.addReferencee( edge );
206 referencee.addReferencer( edge );
209 protected void removeRefEdge( RefEdge e ) {
210 removeRefEdge( e.getSrc(),
216 protected void removeRefEdge( RefSrcNode referencer,
217 HeapRegionNode referencee,
220 assert referencer != null;
221 assert referencee != null;
223 RefEdge edge = referencer.getReferenceTo( referencee,
227 assert edge == referencee.getReferenceFrom( referencer,
231 referencer.removeReferencee( edge );
232 referencee.removeReferencer( edge );
236 // int oldTaint=edge.getTaintIdentifier();
237 // if(referencer instanceof HeapRegionNode){
238 // depropagateTaintIdentifier((HeapRegionNode)referencer,oldTaint,new HashSet<HeapRegionNode>());
244 protected void clearRefEdgesFrom( RefSrcNode referencer,
247 boolean removeAll ) {
248 assert referencer != null;
250 // get a copy of the set to iterate over, otherwise
251 // we will be trying to take apart the set as we
252 // are iterating over it, which won't work
253 Iterator<RefEdge> i = referencer.iteratorToReferenceesClone();
254 while( i.hasNext() ) {
255 RefEdge edge = i.next();
258 (edge.typeEquals( type ) && edge.fieldEquals( field ))
261 HeapRegionNode referencee = edge.getDst();
263 removeRefEdge( referencer,
271 protected void clearRefEdgesTo( HeapRegionNode referencee,
274 boolean removeAll ) {
275 assert referencee != null;
277 // get a copy of the set to iterate over, otherwise
278 // we will be trying to take apart the set as we
279 // are iterating over it, which won't work
280 Iterator<RefEdge> i = referencee.iteratorToReferencersClone();
281 while( i.hasNext() ) {
282 RefEdge edge = i.next();
285 (edge.typeEquals( type ) && edge.fieldEquals( field ))
288 RefSrcNode referencer = edge.getSrc();
290 removeRefEdge( referencer,
298 protected void clearNonVarRefEdgesTo( HeapRegionNode referencee ) {
299 assert referencee != null;
301 // get a copy of the set to iterate over, otherwise
302 // we will be trying to take apart the set as we
303 // are iterating over it, which won't work
304 Iterator<RefEdge> i = referencee.iteratorToReferencersClone();
305 while( i.hasNext() ) {
306 RefEdge edge = i.next();
307 RefSrcNode referencer = edge.getSrc();
308 if( !(referencer instanceof VariableNode) ) {
309 removeRefEdge( referencer,
317 // this is a common operation in many transfer functions: we want
318 // to add an edge, but if there is already such an edge we should
319 // merge the properties of the existing and the new edges
320 protected void addEdgeOrMergeWithExisting( RefEdge edgeNew ) {
322 RefSrcNode src = edgeNew.getSrc();
323 assert belongsToThis( src );
325 HeapRegionNode dst = edgeNew.getDst();
326 assert belongsToThis( dst );
328 // look to see if an edge with same field exists
329 // and merge with it, otherwise just add the edge
330 RefEdge edgeExisting = src.getReferenceTo( dst,
335 if( edgeExisting != null ) {
336 edgeExisting.setBeta(
337 Canonical.unionORpreds( edgeExisting.getBeta(),
341 edgeExisting.setPreds(
342 Canonical.join( edgeExisting.getPreds(),
346 edgeExisting.setTaints(
347 Canonical.unionORpreds( edgeExisting.getTaints(),
353 addRefEdge( src, dst, edgeNew );
359 ////////////////////////////////////////////////////
361 // Assignment Operation Methods
363 // These methods are high-level operations for
364 // modeling program assignment statements using
365 // the low-level reference create/remove methods
368 ////////////////////////////////////////////////////
370 public void assignTempXEqualToTempY( TempDescriptor x,
372 assignTempXEqualToCastedTempY( x, y, null );
374 // x gets status of y
375 // if it is in region,
376 //if(accessibleVars.contains(y)){
377 // accessibleVars.add(x);
381 public void assignTempXEqualToCastedTempY( TempDescriptor x,
383 TypeDescriptor tdCast ) {
385 VariableNode lnX = getVariableNodeFromTemp( x );
386 VariableNode lnY = getVariableNodeFromTemp( y );
388 clearRefEdgesFrom( lnX, null, null, true );
390 // note it is possible that the types of temps in the
391 // flat node to analyze will reveal that some typed
392 // edges in the reachability graph are impossible
393 Set<RefEdge> impossibleEdges = new HashSet<RefEdge>();
395 Iterator<RefEdge> itrYhrn = lnY.iteratorToReferencees();
396 while( itrYhrn.hasNext() ) {
397 RefEdge edgeY = itrYhrn.next();
398 HeapRegionNode referencee = edgeY.getDst();
399 RefEdge edgeNew = edgeY.copy();
401 if( !isSuperiorType( x.getType(), edgeY.getType() ) ) {
402 impossibleEdges.add( edgeY );
406 edgeNew.setSrc( lnX );
408 if( tdCast == null ) {
409 edgeNew.setType( mostSpecificType( y.getType(),
415 edgeNew.setType( mostSpecificType( y.getType(),
417 referencee.getType(),
423 edgeNew.setField( null );
425 addRefEdge( lnX, referencee, edgeNew );
428 Iterator<RefEdge> itrImp = impossibleEdges.iterator();
429 while( itrImp.hasNext() ) {
430 RefEdge edgeImp = itrImp.next();
431 removeRefEdge( edgeImp );
436 public void assignTempXEqualToTempYFieldF( TempDescriptor x,
438 FieldDescriptor f ) {
439 VariableNode lnX = getVariableNodeFromTemp( x );
440 VariableNode lnY = getVariableNodeFromTemp( y );
442 clearRefEdgesFrom( lnX, null, null, true );
444 // note it is possible that the types of temps in the
445 // flat node to analyze will reveal that some typed
446 // edges in the reachability graph are impossible
447 Set<RefEdge> impossibleEdges = new HashSet<RefEdge>();
449 Iterator<RefEdge> itrYhrn = lnY.iteratorToReferencees();
450 while( itrYhrn.hasNext() ) {
451 RefEdge edgeY = itrYhrn.next();
452 HeapRegionNode hrnY = edgeY.getDst();
453 ReachSet betaY = edgeY.getBeta();
455 Iterator<RefEdge> itrHrnFhrn = hrnY.iteratorToReferencees();
456 while( itrHrnFhrn.hasNext() ) {
457 RefEdge edgeHrn = itrHrnFhrn.next();
458 HeapRegionNode hrnHrn = edgeHrn.getDst();
459 ReachSet betaHrn = edgeHrn.getBeta();
461 // prune edges that are not a matching field
462 if( edgeHrn.getType() != null &&
463 !edgeHrn.getField().equals( f.getSymbol() )
468 // check for impossible edges
469 if( !isSuperiorType( x.getType(), edgeHrn.getType() ) ) {
470 impossibleEdges.add( edgeHrn );
474 TypeDescriptor tdNewEdge =
475 mostSpecificType( edgeHrn.getType(),
479 RefEdge edgeNew = new RefEdge( lnX,
483 Canonical.intersection( betaY, betaHrn ),
488 addEdgeOrMergeWithExisting( edgeNew );
492 Iterator<RefEdge> itrImp = impossibleEdges.iterator();
493 while( itrImp.hasNext() ) {
494 RefEdge edgeImp = itrImp.next();
495 removeRefEdge( edgeImp );
498 // anytime you might remove edges between heap regions
499 // you must global sweep to clean up broken reachability
500 if( !impossibleEdges.isEmpty() ) {
501 if( !DISABLE_GLOBAL_SWEEP ) {
506 // accessible status update
507 // if it is in region,
508 //accessibleVars.add(x);
509 //accessibleVars.add(y);
513 public void assignTempXFieldFEqualToTempY( TempDescriptor x,
517 VariableNode lnX = getVariableNodeFromTemp( x );
518 VariableNode lnY = getVariableNodeFromTemp( y );
520 HashSet<HeapRegionNode> nodesWithNewAlpha = new HashSet<HeapRegionNode>();
521 HashSet<RefEdge> edgesWithNewBeta = new HashSet<RefEdge>();
523 // note it is possible that the types of temps in the
524 // flat node to analyze will reveal that some typed
525 // edges in the reachability graph are impossible
526 Set<RefEdge> impossibleEdges = new HashSet<RefEdge>();
528 // first look for possible strong updates and remove those edges
529 boolean strongUpdate = false;
531 Iterator<RefEdge> itrXhrn = lnX.iteratorToReferencees();
532 while( itrXhrn.hasNext() ) {
533 RefEdge edgeX = itrXhrn.next();
534 HeapRegionNode hrnX = edgeX.getDst();
536 // we can do a strong update here if one of two cases holds
538 f != DisjointAnalysis.getArrayField( f.getType() ) &&
539 ( (hrnX.getNumReferencers() == 1) || // case 1
540 (hrnX.isSingleObject() && lnX.getNumReferencees() == 1) // case 2
543 if( !DISABLE_STRONG_UPDATES ) {
545 clearRefEdgesFrom( hrnX, f.getType(), f.getSymbol(), false );
550 // then do all token propagation
551 itrXhrn = lnX.iteratorToReferencees();
552 while( itrXhrn.hasNext() ) {
553 RefEdge edgeX = itrXhrn.next();
554 HeapRegionNode hrnX = edgeX.getDst();
555 ReachSet betaX = edgeX.getBeta();
556 ReachSet R = Canonical.intersection( hrnX.getAlpha(),
560 Iterator<RefEdge> itrYhrn = lnY.iteratorToReferencees();
561 while( itrYhrn.hasNext() ) {
562 RefEdge edgeY = itrYhrn.next();
563 HeapRegionNode hrnY = edgeY.getDst();
564 ReachSet O = edgeY.getBeta();
566 // check for impossible edges
567 if( !isSuperiorType( f.getType(), edgeY.getType() ) ) {
568 impossibleEdges.add( edgeY );
572 // propagate tokens over nodes starting from hrnSrc, and it will
573 // take care of propagating back up edges from any touched nodes
574 ChangeSet Cy = Canonical.unionUpArityToChangeSet( O, R );
575 propagateTokensOverNodes( hrnY, Cy, nodesWithNewAlpha, edgesWithNewBeta );
577 // then propagate back just up the edges from hrn
578 ChangeSet Cx = Canonical.unionUpArityToChangeSet( R, O );
579 HashSet<RefEdge> todoEdges = new HashSet<RefEdge>();
581 Hashtable<RefEdge, ChangeSet> edgePlannedChanges =
582 new Hashtable<RefEdge, ChangeSet>();
584 Iterator<RefEdge> referItr = hrnX.iteratorToReferencers();
585 while( referItr.hasNext() ) {
586 RefEdge edgeUpstream = referItr.next();
587 todoEdges.add( edgeUpstream );
588 edgePlannedChanges.put( edgeUpstream, Cx );
591 propagateTokensOverEdges( todoEdges,
598 // apply the updates to reachability
599 Iterator<HeapRegionNode> nodeItr = nodesWithNewAlpha.iterator();
600 while( nodeItr.hasNext() ) {
601 nodeItr.next().applyAlphaNew();
604 Iterator<RefEdge> edgeItr = edgesWithNewBeta.iterator();
605 while( edgeItr.hasNext() ) {
606 edgeItr.next().applyBetaNew();
610 // then go back through and add the new edges
611 itrXhrn = lnX.iteratorToReferencees();
612 while( itrXhrn.hasNext() ) {
613 RefEdge edgeX = itrXhrn.next();
614 HeapRegionNode hrnX = edgeX.getDst();
616 Iterator<RefEdge> itrYhrn = lnY.iteratorToReferencees();
617 while( itrYhrn.hasNext() ) {
618 RefEdge edgeY = itrYhrn.next();
619 HeapRegionNode hrnY = edgeY.getDst();
621 // skip impossible edges here, we already marked them
622 // when computing reachability propagations above
623 if( !isSuperiorType( f.getType(), edgeY.getType() ) ) {
627 // prepare the new reference edge hrnX.f -> hrnY
628 TypeDescriptor tdNewEdge =
629 mostSpecificType( y.getType(),
639 Canonical.makePredsTrue(
640 Canonical.pruneBy( edgeY.getBeta(),
645 Canonical.makePredsTrue( edgeY.getTaints() )
648 addEdgeOrMergeWithExisting( edgeNew );
652 Iterator<RefEdge> itrImp = impossibleEdges.iterator();
653 while( itrImp.hasNext() ) {
654 RefEdge edgeImp = itrImp.next();
655 removeRefEdge( edgeImp );
658 // if there was a strong update, make sure to improve
659 // reachability with a global sweep
660 if( strongUpdate || !impossibleEdges.isEmpty() ) {
661 if( !DISABLE_GLOBAL_SWEEP ) {
666 // after x.y=f , stall x and y if they are not accessible
667 // also contribute write effects on stall site of x
668 // accessible status update
669 // if it is in region
670 //accessibleVars.add(x);
671 //accessibleVars.add(y);
676 public void assignReturnEqualToTemp( TempDescriptor x ) {
678 VariableNode lnR = getVariableNodeFromTemp( tdReturn );
679 VariableNode lnX = getVariableNodeFromTemp( x );
681 clearRefEdgesFrom( lnR, null, null, true );
683 Iterator<RefEdge> itrXhrn = lnX.iteratorToReferencees();
684 while( itrXhrn.hasNext() ) {
685 RefEdge edgeX = itrXhrn.next();
686 HeapRegionNode referencee = edgeX.getDst();
687 RefEdge edgeNew = edgeX.copy();
688 edgeNew.setSrc( lnR );
689 edgeNew.setTaints( Canonical.makePredsTrue( edgeNew.getTaints() ) );
691 addRefEdge( lnR, referencee, edgeNew );
696 public void assignTempEqualToNewAlloc( TempDescriptor x,
703 // after the age operation the newest (or zero-ith oldest)
704 // node associated with the allocation site should have
705 // no references to it as if it were a newly allocated
707 Integer idNewest = as.getIthOldest( 0 );
708 HeapRegionNode hrnNewest = id2hrn.get( idNewest );
709 assert hrnNewest != null;
711 VariableNode lnX = getVariableNodeFromTemp( x );
712 clearRefEdgesFrom( lnX, null, null, true );
714 // make a new reference to allocated node
715 TypeDescriptor type = as.getType();
718 new RefEdge( lnX, // source
722 hrnNewest.getAlpha(), // beta
723 predsTrue, // predicates
724 TaintSet.factory() // taints
727 addRefEdge( lnX, hrnNewest, edgeNew );
729 // after x=new , x is accessible
730 // if (isInRegion()) {
731 //accessibleVars.add(x);
735 // use the allocation site (unique to entire analysis) to
736 // locate the heap region nodes in this reachability graph
737 // that should be aged. The process models the allocation
738 // of new objects and collects all the oldest allocations
739 // in a summary node to allow for a finite analysis
741 // There is an additional property of this method. After
742 // running it on a particular reachability graph (many graphs
743 // may have heap regions related to the same allocation site)
744 // the heap region node objects in this reachability graph will be
745 // allocated. Therefore, after aging a graph for an allocation
746 // site, attempts to retrieve the heap region nodes using the
747 // integer id's contained in the allocation site should always
748 // return non-null heap regions.
749 public void age( AllocSite as ) {
751 // keep track of allocation sites that are represented
752 // in this graph for efficiency with other operations
753 allocSites.add( as );
755 // if there is a k-th oldest node, it merges into
757 Integer idK = as.getOldest();
758 if( id2hrn.containsKey( idK ) ) {
759 HeapRegionNode hrnK = id2hrn.get( idK );
761 // retrieve the summary node, or make it
763 HeapRegionNode hrnSummary = getSummaryNode( as, false );
765 mergeIntoSummary( hrnK, hrnSummary );
768 // move down the line of heap region nodes
769 // clobbering the ith and transferring all references
770 // to and from i-1 to node i.
771 for( int i = allocationDepth - 1; i > 0; --i ) {
773 // only do the transfer if the i-1 node exists
774 Integer idImin1th = as.getIthOldest( i - 1 );
775 if( id2hrn.containsKey( idImin1th ) ) {
776 HeapRegionNode hrnImin1 = id2hrn.get( idImin1th );
777 if( hrnImin1.isWiped() ) {
778 // there is no info on this node, just skip
782 // either retrieve or make target of transfer
783 HeapRegionNode hrnI = getIthNode( as, i, false );
785 transferOnto( hrnImin1, hrnI );
790 // as stated above, the newest node should have had its
791 // references moved over to the second oldest, so we wipe newest
792 // in preparation for being the new object to assign something to
793 HeapRegionNode hrn0 = getIthNode( as, 0, false );
794 wipeOut( hrn0, true );
796 // now tokens in reachability sets need to "age" also
797 Iterator itrAllVariableNodes = td2vn.entrySet().iterator();
798 while( itrAllVariableNodes.hasNext() ) {
799 Map.Entry me = (Map.Entry) itrAllVariableNodes.next();
800 VariableNode ln = (VariableNode) me.getValue();
802 Iterator<RefEdge> itrEdges = ln.iteratorToReferencees();
803 while( itrEdges.hasNext() ) {
804 ageTuplesFrom( as, itrEdges.next() );
808 Iterator itrAllHRNodes = id2hrn.entrySet().iterator();
809 while( itrAllHRNodes.hasNext() ) {
810 Map.Entry me = (Map.Entry) itrAllHRNodes.next();
811 HeapRegionNode hrnToAge = (HeapRegionNode) me.getValue();
813 ageTuplesFrom( as, hrnToAge );
815 Iterator<RefEdge> itrEdges = hrnToAge.iteratorToReferencees();
816 while( itrEdges.hasNext() ) {
817 ageTuplesFrom( as, itrEdges.next() );
822 // after tokens have been aged, reset newest node's reachability
823 // and a brand new node has a "true" predicate
824 hrn0.setAlpha( hrn0.getInherent() );
825 hrn0.setPreds( predsTrue );
829 // either retrieve or create the needed heap region node
830 protected HeapRegionNode getSummaryNode( AllocSite as,
835 idSummary = as.getSummaryShadow();
837 idSummary = as.getSummary();
840 HeapRegionNode hrnSummary = id2hrn.get( idSummary );
842 if( hrnSummary == null ) {
844 String strDesc = as.toStringForDOT()+"\\nsummary";
847 createNewHeapRegionNode( idSummary, // id or null to generate a new one
848 false, // single object?
850 false, // out-of-context?
851 as.getType(), // type
852 as, // allocation site
853 null, // inherent reach
854 null, // current reach
855 predsEmpty, // predicates
856 strDesc // description
863 // either retrieve or create the needed heap region node
864 protected HeapRegionNode getIthNode( AllocSite as,
870 idIth = as.getIthOldestShadow( i );
872 idIth = as.getIthOldest( i );
875 HeapRegionNode hrnIth = id2hrn.get( idIth );
877 if( hrnIth == null ) {
879 String strDesc = as.toStringForDOT()+"\\n"+i+" oldest";
881 hrnIth = createNewHeapRegionNode( idIth, // id or null to generate a new one
882 true, // single object?
884 false, // out-of-context?
885 as.getType(), // type
886 as, // allocation site
887 null, // inherent reach
888 null, // current reach
889 predsEmpty, // predicates
890 strDesc // description
898 protected void mergeIntoSummary( HeapRegionNode hrn,
899 HeapRegionNode hrnSummary ) {
900 assert hrnSummary.isNewSummary();
902 // assert that these nodes belong to THIS graph
903 assert belongsToThis( hrn );
904 assert belongsToThis( hrnSummary );
906 assert hrn != hrnSummary;
908 // transfer references _from_ hrn over to hrnSummary
909 Iterator<RefEdge> itrReferencee = hrn.iteratorToReferencees();
910 while( itrReferencee.hasNext() ) {
911 RefEdge edge = itrReferencee.next();
912 RefEdge edgeMerged = edge.copy();
913 edgeMerged.setSrc( hrnSummary );
915 HeapRegionNode hrnReferencee = edge.getDst();
916 RefEdge edgeSummary =
917 hrnSummary.getReferenceTo( hrnReferencee,
922 if( edgeSummary == null ) {
923 // the merge is trivial, nothing to be done
924 addRefEdge( hrnSummary, hrnReferencee, edgeMerged );
927 // otherwise an edge from the referencer to hrnSummary exists already
928 // and the edge referencer->hrn should be merged with it
930 Canonical.unionORpreds( edgeMerged.getBeta(),
931 edgeSummary.getBeta()
934 edgeSummary.setPreds(
935 Canonical.join( edgeMerged.getPreds(),
936 edgeSummary.getPreds()
942 // next transfer references _to_ hrn over to hrnSummary
943 Iterator<RefEdge> itrReferencer = hrn.iteratorToReferencers();
944 while( itrReferencer.hasNext() ) {
945 RefEdge edge = itrReferencer.next();
946 RefEdge edgeMerged = edge.copy();
947 edgeMerged.setDst( hrnSummary );
949 RefSrcNode onReferencer = edge.getSrc();
950 RefEdge edgeSummary =
951 onReferencer.getReferenceTo( hrnSummary,
956 if( edgeSummary == null ) {
957 // the merge is trivial, nothing to be done
958 addRefEdge( onReferencer, hrnSummary, edgeMerged );
961 // otherwise an edge from the referencer to alpha_S exists already
962 // and the edge referencer->alpha_K should be merged with it
964 Canonical.unionORpreds( edgeMerged.getBeta(),
965 edgeSummary.getBeta()
968 edgeSummary.setPreds(
969 Canonical.join( edgeMerged.getPreds(),
970 edgeSummary.getPreds()
976 // then merge hrn reachability into hrnSummary
978 Canonical.unionORpreds( hrnSummary.getAlpha(),
984 Canonical.join( hrnSummary.getPreds(),
989 // and afterward, this node is gone
990 wipeOut( hrn, true );
994 protected void transferOnto( HeapRegionNode hrnA,
995 HeapRegionNode hrnB ) {
997 assert belongsToThis( hrnA );
998 assert belongsToThis( hrnB );
1001 // clear references in and out of node b?
1002 assert hrnB.isWiped();
1004 // copy each: (edge in and out of A) to B
1005 Iterator<RefEdge> itrReferencee = hrnA.iteratorToReferencees();
1006 while( itrReferencee.hasNext() ) {
1007 RefEdge edge = itrReferencee.next();
1008 HeapRegionNode hrnReferencee = edge.getDst();
1009 RefEdge edgeNew = edge.copy();
1010 edgeNew.setSrc( hrnB );
1011 edgeNew.setDst( hrnReferencee );
1013 addRefEdge( hrnB, hrnReferencee, edgeNew );
1016 Iterator<RefEdge> itrReferencer = hrnA.iteratorToReferencers();
1017 while( itrReferencer.hasNext() ) {
1018 RefEdge edge = itrReferencer.next();
1019 RefSrcNode rsnReferencer = edge.getSrc();
1020 RefEdge edgeNew = edge.copy();
1021 edgeNew.setSrc( rsnReferencer );
1022 edgeNew.setDst( hrnB );
1024 addRefEdge( rsnReferencer, hrnB, edgeNew );
1027 // replace hrnB reachability and preds with hrnA's
1028 hrnB.setAlpha( hrnA.getAlpha() );
1029 hrnB.setPreds( hrnA.getPreds() );
1031 // after transfer, wipe out source
1032 wipeOut( hrnA, true );
1036 // the purpose of this method is to conceptually "wipe out"
1037 // a heap region from the graph--purposefully not called REMOVE
1038 // because the node is still hanging around in the graph, just
1039 // not mechanically connected or have any reach or predicate
1040 // information on it anymore--lots of ops can use this
1041 protected void wipeOut( HeapRegionNode hrn,
1042 boolean wipeVariableReferences ) {
1044 assert belongsToThis( hrn );
1046 clearRefEdgesFrom( hrn, null, null, true );
1048 if( wipeVariableReferences ) {
1049 clearRefEdgesTo( hrn, null, null, true );
1051 clearNonVarRefEdgesTo( hrn );
1054 hrn.setAlpha( rsetEmpty );
1055 hrn.setPreds( predsEmpty );
1059 protected void ageTuplesFrom( AllocSite as, RefEdge edge ) {
1061 Canonical.ageTuplesFrom( edge.getBeta(),
1067 protected void ageTuplesFrom( AllocSite as, HeapRegionNode hrn ) {
1069 Canonical.ageTuplesFrom( hrn.getAlpha(),
1077 protected void propagateTokensOverNodes( HeapRegionNode nPrime,
1079 HashSet<HeapRegionNode> nodesWithNewAlpha,
1080 HashSet<RefEdge> edgesWithNewBeta ) {
1082 HashSet<HeapRegionNode> todoNodes
1083 = new HashSet<HeapRegionNode>();
1084 todoNodes.add( nPrime );
1086 HashSet<RefEdge> todoEdges
1087 = new HashSet<RefEdge>();
1089 Hashtable<HeapRegionNode, ChangeSet> nodePlannedChanges
1090 = new Hashtable<HeapRegionNode, ChangeSet>();
1091 nodePlannedChanges.put( nPrime, c0 );
1093 Hashtable<RefEdge, ChangeSet> edgePlannedChanges
1094 = new Hashtable<RefEdge, ChangeSet>();
1096 // first propagate change sets everywhere they can go
1097 while( !todoNodes.isEmpty() ) {
1098 HeapRegionNode n = todoNodes.iterator().next();
1099 ChangeSet C = nodePlannedChanges.get( n );
1101 Iterator<RefEdge> referItr = n.iteratorToReferencers();
1102 while( referItr.hasNext() ) {
1103 RefEdge edge = referItr.next();
1104 todoEdges.add( edge );
1106 if( !edgePlannedChanges.containsKey( edge ) ) {
1107 edgePlannedChanges.put( edge,
1112 edgePlannedChanges.put( edge,
1113 Canonical.union( edgePlannedChanges.get( edge ),
1119 Iterator<RefEdge> refeeItr = n.iteratorToReferencees();
1120 while( refeeItr.hasNext() ) {
1121 RefEdge edgeF = refeeItr.next();
1122 HeapRegionNode m = edgeF.getDst();
1124 ChangeSet changesToPass = ChangeSet.factory();
1126 Iterator<ChangeTuple> itrCprime = C.iterator();
1127 while( itrCprime.hasNext() ) {
1128 ChangeTuple c = itrCprime.next();
1129 if( edgeF.getBeta().containsIgnorePreds( c.getStateToMatch() )
1132 changesToPass = Canonical.add( changesToPass, c );
1136 if( !changesToPass.isEmpty() ) {
1137 if( !nodePlannedChanges.containsKey( m ) ) {
1138 nodePlannedChanges.put( m, ChangeSet.factory() );
1141 ChangeSet currentChanges = nodePlannedChanges.get( m );
1143 if( !changesToPass.isSubset( currentChanges ) ) {
1145 nodePlannedChanges.put( m,
1146 Canonical.union( currentChanges,
1155 todoNodes.remove( n );
1158 // then apply all of the changes for each node at once
1159 Iterator itrMap = nodePlannedChanges.entrySet().iterator();
1160 while( itrMap.hasNext() ) {
1161 Map.Entry me = (Map.Entry) itrMap.next();
1162 HeapRegionNode n = (HeapRegionNode) me.getKey();
1163 ChangeSet C = (ChangeSet) me.getValue();
1165 // this propagation step is with respect to one change,
1166 // so we capture the full change from the old alpha:
1167 ReachSet localDelta = Canonical.applyChangeSet( n.getAlpha(),
1171 // but this propagation may be only one of many concurrent
1172 // possible changes, so keep a running union with the node's
1173 // partially updated new alpha set
1174 n.setAlphaNew( Canonical.unionORpreds( n.getAlphaNew(),
1179 nodesWithNewAlpha.add( n );
1182 propagateTokensOverEdges( todoEdges,
1189 protected void propagateTokensOverEdges( HashSet <RefEdge> todoEdges,
1190 Hashtable<RefEdge, ChangeSet> edgePlannedChanges,
1191 HashSet <RefEdge> edgesWithNewBeta ) {
1193 // first propagate all change tuples everywhere they can go
1194 while( !todoEdges.isEmpty() ) {
1195 RefEdge edgeE = todoEdges.iterator().next();
1196 todoEdges.remove( edgeE );
1198 if( !edgePlannedChanges.containsKey( edgeE ) ) {
1199 edgePlannedChanges.put( edgeE,
1204 ChangeSet C = edgePlannedChanges.get( edgeE );
1206 ChangeSet changesToPass = ChangeSet.factory();
1208 Iterator<ChangeTuple> itrC = C.iterator();
1209 while( itrC.hasNext() ) {
1210 ChangeTuple c = itrC.next();
1211 if( edgeE.getBeta().containsIgnorePreds( c.getStateToMatch() )
1214 changesToPass = Canonical.add( changesToPass, c );
1218 RefSrcNode rsn = edgeE.getSrc();
1220 if( !changesToPass.isEmpty() && rsn instanceof HeapRegionNode ) {
1221 HeapRegionNode n = (HeapRegionNode) rsn;
1223 Iterator<RefEdge> referItr = n.iteratorToReferencers();
1224 while( referItr.hasNext() ) {
1225 RefEdge edgeF = referItr.next();
1227 if( !edgePlannedChanges.containsKey( edgeF ) ) {
1228 edgePlannedChanges.put( edgeF,
1233 ChangeSet currentChanges = edgePlannedChanges.get( edgeF );
1235 if( !changesToPass.isSubset( currentChanges ) ) {
1236 todoEdges.add( edgeF );
1237 edgePlannedChanges.put( edgeF,
1238 Canonical.union( currentChanges,
1247 // then apply all of the changes for each edge at once
1248 Iterator itrMap = edgePlannedChanges.entrySet().iterator();
1249 while( itrMap.hasNext() ) {
1250 Map.Entry me = (Map.Entry) itrMap.next();
1251 RefEdge e = (RefEdge) me.getKey();
1252 ChangeSet C = (ChangeSet) me.getValue();
1254 // this propagation step is with respect to one change,
1255 // so we capture the full change from the old beta:
1256 ReachSet localDelta =
1257 Canonical.applyChangeSet( e.getBeta(),
1262 // but this propagation may be only one of many concurrent
1263 // possible changes, so keep a running union with the edge's
1264 // partially updated new beta set
1265 e.setBetaNew( Canonical.unionORpreds( e.getBetaNew(),
1270 edgesWithNewBeta.add( e );
1275 public void taintInSetVars( FlatSESEEnterNode sese ) {
1276 Iterator<TempDescriptor> isvItr = sese.getInVarSet().iterator()
1278 while( isvItr.hasNext() ) {
1279 TempDescriptor isv = isvItr.next();
1280 VariableNode vn = td2vn.get( isv );
1282 Iterator<RefEdge> reItr = vn.iteratorToReferencees();
1283 while( reItr.hasNext() ) {
1284 RefEdge re = reItr.next();
1286 // these in-set taints should have empty
1287 // predicates so they never propagate
1289 Taint t = Taint.factory( sese,
1292 re.getDst().getAllocSite(),
1293 ExistPredSet.factory()
1296 re.setTaints( Canonical.add( re.getTaints(),
1304 // this is useful for more general tainting
1305 public void taintTemp( Taint taint,
1310 VariableNode vn = td2vn.get( td );
1312 Iterator<RefEdge> reItr = vn.iteratorToReferencees();
1313 while( reItr.hasNext() ) {
1314 RefEdge re = reItr.next();
1316 re.setTaints( Canonical.add( re.getTaints(),
1323 public void removeInContextTaints( FlatSESEEnterNode sese ) {
1324 Iterator meItr = id2hrn.entrySet().iterator();
1325 while( meItr.hasNext() ) {
1326 Map.Entry me = (Map.Entry) meItr.next();
1327 Integer id = (Integer) me.getKey();
1328 HeapRegionNode hrn = (HeapRegionNode) me.getValue();
1330 Iterator<RefEdge> reItr = hrn.iteratorToReferencers();
1331 while( reItr.hasNext() ) {
1332 RefEdge re = reItr.next();
1334 re.setTaints( Canonical.removeTaintsBy( re.getTaints(),
1343 // used in makeCalleeView below to decide if there is
1344 // already an appropriate out-of-context edge in a callee
1345 // view graph for merging, or null if a new one will be added
1347 getOutOfContextReferenceTo( HeapRegionNode hrn,
1348 TypeDescriptor srcType,
1349 TypeDescriptor refType,
1351 assert belongsToThis( hrn );
1353 HeapRegionNode hrnInContext = id2hrn.get( hrn.getID() );
1354 if( hrnInContext == null ) {
1358 Iterator<RefEdge> refItr = hrnInContext.iteratorToReferencers();
1359 while( refItr.hasNext() ) {
1360 RefEdge re = refItr.next();
1362 assert belongsToThis( re.getSrc() );
1363 assert belongsToThis( re.getDst() );
1365 if( !(re.getSrc() instanceof HeapRegionNode) ) {
1369 HeapRegionNode hrnSrc = (HeapRegionNode) re.getSrc();
1370 if( !hrnSrc.isOutOfContext() ) {
1374 if( srcType == null ) {
1375 if( hrnSrc.getType() != null ) {
1379 if( !srcType.equals( hrnSrc.getType() ) ) {
1384 if( !re.typeEquals( refType ) ) {
1388 if( !re.fieldEquals( refField ) ) {
1392 // tada! We found it!
1399 // used below to convert a ReachSet to its callee-context
1400 // equivalent with respect to allocation sites in this graph
1401 protected ReachSet toCalleeContext( ReachSet rs,
1403 Set<HrnIdOoc> oocHrnIdOoc2callee
1405 ReachSet out = ReachSet.factory();
1407 Iterator<ReachState> itr = rs.iterator();
1408 while( itr.hasNext() ) {
1409 ReachState stateCaller = itr.next();
1411 ReachState stateCallee = stateCaller;
1413 Iterator<AllocSite> asItr = allocSites.iterator();
1414 while( asItr.hasNext() ) {
1415 AllocSite as = asItr.next();
1417 ReachState stateNew = ReachState.factory();
1418 Iterator<ReachTuple> rtItr = stateCallee.iterator();
1419 while( rtItr.hasNext() ) {
1420 ReachTuple rt = rtItr.next();
1422 // only translate this tuple if it is
1423 // in the out-callee-context bag
1424 HrnIdOoc hio = new HrnIdOoc( rt.getHrnID(),
1427 if( !oocHrnIdOoc2callee.contains( hio ) ) {
1428 stateNew = Canonical.add( stateNew, rt );
1432 int age = as.getAgeCategory( rt.getHrnID() );
1434 // this is the current mapping, where 0, 1, 2S were allocated
1435 // in the current context, 0?, 1? and 2S? were allocated in a
1436 // previous context, and we're translating to a future context
1448 if( age == AllocSite.AGE_notInThisSite ) {
1449 // things not from the site just go back in
1450 stateNew = Canonical.add( stateNew, rt );
1452 } else if( age == AllocSite.AGE_summary ||
1455 // the in-context summary and all existing out-of-context
1457 stateNew = Canonical.add( stateNew,
1458 ReachTuple.factory( as.getSummary(),
1461 true // out-of-context
1465 // otherwise everything else just goes to an out-of-context
1466 // version, everything else the same
1467 Integer I = as.getAge( rt.getHrnID() );
1470 assert !rt.isMultiObject();
1472 stateNew = Canonical.add( stateNew,
1473 ReachTuple.factory( rt.getHrnID(),
1476 true // out-of-context
1482 stateCallee = stateNew;
1485 // attach the passed in preds
1486 stateCallee = Canonical.attach( stateCallee,
1489 out = Canonical.add( out,
1494 assert out.isCanonical();
1498 // used below to convert a ReachSet to its caller-context
1499 // equivalent with respect to allocation sites in this graph
1501 toCallerContext( ReachSet rs,
1502 Hashtable<ReachState, ExistPredSet> calleeStatesSatisfied
1504 ReachSet out = ReachSet.factory();
1506 // when the mapping is null it means there were no
1507 // predicates satisfied
1508 if( calleeStatesSatisfied == null ) {
1512 Iterator<ReachState> itr = rs.iterator();
1513 while( itr.hasNext() ) {
1514 ReachState stateCallee = itr.next();
1516 if( calleeStatesSatisfied.containsKey( stateCallee ) ) {
1518 // starting from one callee state...
1519 ReachSet rsCaller = ReachSet.factory( stateCallee );
1521 // possibly branch it into many states, which any
1522 // allocation site might do, so lots of derived states
1523 Iterator<AllocSite> asItr = allocSites.iterator();
1524 while( asItr.hasNext() ) {
1525 AllocSite as = asItr.next();
1526 rsCaller = Canonical.toCallerContext( rsCaller, as );
1529 // then before adding each derived, now caller-context
1530 // states to the output, attach the appropriate pred
1531 // based on the source callee state
1532 Iterator<ReachState> stateItr = rsCaller.iterator();
1533 while( stateItr.hasNext() ) {
1534 ReachState stateCaller = stateItr.next();
1535 stateCaller = Canonical.attach( stateCaller,
1536 calleeStatesSatisfied.get( stateCallee )
1538 out = Canonical.add( out,
1545 assert out.isCanonical();
1550 // used below to convert a ReachSet to an equivalent
1551 // version with shadow IDs merged into unshadowed IDs
1552 protected ReachSet unshadow( ReachSet rs ) {
1554 Iterator<AllocSite> asItr = allocSites.iterator();
1555 while( asItr.hasNext() ) {
1556 AllocSite as = asItr.next();
1557 out = Canonical.unshadow( out, as );
1559 assert out.isCanonical();
1564 // used below to convert a TaintSet to its caller-context
1565 // equivalent, just eliminate Taints with bad preds
1567 toCallerContext( TaintSet ts,
1568 Hashtable<Taint, ExistPredSet> calleeTaintsSatisfied
1570 TaintSet out = TaintSet.factory();
1572 // when the mapping is null it means there were no
1573 // predicates satisfied
1574 if( calleeTaintsSatisfied == null ) {
1578 Iterator<Taint> itr = ts.iterator();
1579 while( itr.hasNext() ) {
1580 Taint tCallee = itr.next();
1582 if( calleeTaintsSatisfied.containsKey( tCallee ) ) {
1585 Canonical.attach( Taint.factory( tCallee.sese,
1589 ExistPredSet.factory() ),
1590 calleeTaintsSatisfied.get( tCallee )
1592 out = Canonical.add( out,
1598 assert out.isCanonical();
1605 // use this method to make a new reach graph that is
1606 // what heap the FlatMethod callee from the FlatCall
1607 // would start with reaching from its arguments in
1610 makeCalleeView( FlatCall fc,
1611 FlatMethod fmCallee,
1612 Set<Integer> callerNodeIDsCopiedToCallee,
1613 boolean writeDebugDOTs
1617 // first traverse this context to find nodes and edges
1618 // that will be callee-reachable
1619 Set<HeapRegionNode> reachableCallerNodes =
1620 new HashSet<HeapRegionNode>();
1622 // caller edges between callee-reachable nodes
1623 Set<RefEdge> reachableCallerEdges =
1624 new HashSet<RefEdge>();
1626 // caller edges from arg vars, and the matching param index
1627 // because these become a special edge in callee
1628 Hashtable<RefEdge, Integer> reachableCallerArgEdges2paramIndex =
1629 new Hashtable<RefEdge, Integer>();
1631 // caller edges from local vars or callee-unreachable nodes
1632 // (out-of-context sources) to callee-reachable nodes
1633 Set<RefEdge> oocCallerEdges =
1634 new HashSet<RefEdge>();
1637 for( int i = 0; i < fmCallee.numParameters(); ++i ) {
1639 TempDescriptor tdArg = fc.getArgMatchingParamIndex( fmCallee, i );
1640 VariableNode vnArgCaller = this.getVariableNodeFromTemp( tdArg );
1642 Set<RefSrcNode> toVisitInCaller = new HashSet<RefSrcNode>();
1643 Set<RefSrcNode> visitedInCaller = new HashSet<RefSrcNode>();
1645 toVisitInCaller.add( vnArgCaller );
1647 while( !toVisitInCaller.isEmpty() ) {
1648 RefSrcNode rsnCaller = toVisitInCaller.iterator().next();
1649 toVisitInCaller.remove( rsnCaller );
1650 visitedInCaller.add( rsnCaller );
1652 Iterator<RefEdge> itrRefEdges = rsnCaller.iteratorToReferencees();
1653 while( itrRefEdges.hasNext() ) {
1654 RefEdge reCaller = itrRefEdges.next();
1655 HeapRegionNode hrnCaller = reCaller.getDst();
1657 callerNodeIDsCopiedToCallee.add( hrnCaller.getID() );
1658 reachableCallerNodes.add( hrnCaller );
1660 if( reCaller.getSrc() instanceof HeapRegionNode ) {
1661 reachableCallerEdges.add( reCaller );
1663 if( rsnCaller.equals( vnArgCaller ) ) {
1664 reachableCallerArgEdges2paramIndex.put( reCaller, i );
1666 oocCallerEdges.add( reCaller );
1670 if( !visitedInCaller.contains( hrnCaller ) ) {
1671 toVisitInCaller.add( hrnCaller );
1674 } // end edge iteration
1675 } // end visiting heap nodes in caller
1676 } // end iterating over parameters as starting points
1679 // now collect out-of-callee-context IDs and
1680 // map them to whether the ID is out of the caller
1682 Set<HrnIdOoc> oocHrnIdOoc2callee = new HashSet<HrnIdOoc>();
1684 Iterator<Integer> itrInContext =
1685 callerNodeIDsCopiedToCallee.iterator();
1686 while( itrInContext.hasNext() ) {
1687 Integer hrnID = itrInContext.next();
1688 HeapRegionNode hrnCallerAndInContext = id2hrn.get( hrnID );
1690 Iterator<RefEdge> itrMightCross =
1691 hrnCallerAndInContext.iteratorToReferencers();
1692 while( itrMightCross.hasNext() ) {
1693 RefEdge edgeMightCross = itrMightCross.next();
1695 RefSrcNode rsnCallerAndOutContext =
1696 edgeMightCross.getSrc();
1698 if( rsnCallerAndOutContext instanceof VariableNode ) {
1699 // variables do not have out-of-context reach states,
1701 oocCallerEdges.add( edgeMightCross );
1705 HeapRegionNode hrnCallerAndOutContext =
1706 (HeapRegionNode) rsnCallerAndOutContext;
1708 // is this source node out-of-context?
1709 if( callerNodeIDsCopiedToCallee.contains( hrnCallerAndOutContext.getID() ) ) {
1710 // no, skip this edge
1715 oocCallerEdges.add( edgeMightCross );
1717 // add all reach tuples on the node to list
1718 // of things that are out-of-context: insight
1719 // if this node is reachable from someting that WAS
1720 // in-context, then this node should already be in-context
1721 Iterator<ReachState> stateItr = hrnCallerAndOutContext.getAlpha().iterator();
1722 while( stateItr.hasNext() ) {
1723 ReachState state = stateItr.next();
1725 Iterator<ReachTuple> rtItr = state.iterator();
1726 while( rtItr.hasNext() ) {
1727 ReachTuple rt = rtItr.next();
1729 oocHrnIdOoc2callee.add( new HrnIdOoc( rt.getHrnID(),
1738 // the callee view is a new graph: DON'T MODIFY *THIS* graph
1739 ReachGraph rg = new ReachGraph();
1741 // add nodes to callee graph
1742 Iterator<HeapRegionNode> hrnItr = reachableCallerNodes.iterator();
1743 while( hrnItr.hasNext() ) {
1744 HeapRegionNode hrnCaller = hrnItr.next();
1746 assert callerNodeIDsCopiedToCallee.contains( hrnCaller.getID() );
1747 assert !rg.id2hrn.containsKey( hrnCaller.getID() );
1749 ExistPred pred = ExistPred.factory( hrnCaller.getID(), null );
1750 ExistPredSet preds = ExistPredSet.factory( pred );
1752 rg.createNewHeapRegionNode( hrnCaller.getID(),
1753 hrnCaller.isSingleObject(),
1754 hrnCaller.isNewSummary(),
1755 false, // out-of-context?
1756 hrnCaller.getType(),
1757 hrnCaller.getAllocSite(),
1758 toCalleeContext( hrnCaller.getInherent(),
1762 toCalleeContext( hrnCaller.getAlpha(),
1767 hrnCaller.getDescription()
1771 // add param edges to callee graph
1773 reachableCallerArgEdges2paramIndex.entrySet().iterator();
1774 while( argEdges.hasNext() ) {
1775 Map.Entry me = (Map.Entry) argEdges.next();
1776 RefEdge reArg = (RefEdge) me.getKey();
1777 Integer index = (Integer) me.getValue();
1779 VariableNode vnCaller = (VariableNode) reArg.getSrc();
1780 TempDescriptor argCaller = vnCaller.getTempDescriptor();
1782 TempDescriptor paramCallee = fmCallee.getParameter( index );
1783 VariableNode vnCallee = rg.getVariableNodeFromTemp( paramCallee );
1785 HeapRegionNode hrnDstCaller = reArg.getDst();
1786 HeapRegionNode hrnDstCallee = rg.id2hrn.get( hrnDstCaller.getID() );
1787 assert hrnDstCallee != null;
1790 ExistPred.factory( argCaller,
1792 hrnDstCallee.getID(),
1796 true, // out-of-callee-context
1797 false // out-of-caller-context
1800 ExistPredSet preds =
1801 ExistPredSet.factory( pred );
1803 TaintSet taints = TaintSet.factory( reArg.getTaints(),
1808 new RefEdge( vnCallee,
1812 toCalleeContext( reArg.getBeta(),
1820 rg.addRefEdge( vnCallee,
1826 // add in-context edges to callee graph
1827 Iterator<RefEdge> reItr = reachableCallerEdges.iterator();
1828 while( reItr.hasNext() ) {
1829 RefEdge reCaller = reItr.next();
1830 RefSrcNode rsnCaller = reCaller.getSrc();
1831 assert rsnCaller instanceof HeapRegionNode;
1832 HeapRegionNode hrnSrcCaller = (HeapRegionNode) rsnCaller;
1833 HeapRegionNode hrnDstCaller = reCaller.getDst();
1835 HeapRegionNode hrnSrcCallee = rg.id2hrn.get( hrnSrcCaller.getID() );
1836 HeapRegionNode hrnDstCallee = rg.id2hrn.get( hrnDstCaller.getID() );
1837 assert hrnSrcCallee != null;
1838 assert hrnDstCallee != null;
1841 ExistPred.factory( null,
1842 hrnSrcCallee.getID(),
1843 hrnDstCallee.getID(),
1845 reCaller.getField(),
1847 false, // out-of-callee-context
1848 false // out-of-caller-context
1851 ExistPredSet preds =
1852 ExistPredSet.factory( pred );
1855 new RefEdge( hrnSrcCallee,
1858 reCaller.getField(),
1859 toCalleeContext( reCaller.getBeta(),
1864 TaintSet.factory() // no taints for in-context edges
1867 rg.addRefEdge( hrnSrcCallee,
1873 // add out-of-context edges to callee graph
1874 reItr = oocCallerEdges.iterator();
1875 while( reItr.hasNext() ) {
1876 RefEdge reCaller = reItr.next();
1877 RefSrcNode rsnCaller = reCaller.getSrc();
1878 HeapRegionNode hrnDstCaller = reCaller.getDst();
1879 HeapRegionNode hrnDstCallee = rg.id2hrn.get( hrnDstCaller.getID() );
1880 assert hrnDstCallee != null;
1882 TypeDescriptor oocNodeType;
1884 TempDescriptor oocPredSrcTemp = null;
1885 Integer oocPredSrcID = null;
1886 boolean outOfCalleeContext;
1887 boolean outOfCallerContext;
1889 if( rsnCaller instanceof VariableNode ) {
1890 VariableNode vnCaller = (VariableNode) rsnCaller;
1892 oocReach = rsetEmpty;
1893 oocPredSrcTemp = vnCaller.getTempDescriptor();
1894 outOfCalleeContext = true;
1895 outOfCallerContext = false;
1898 HeapRegionNode hrnSrcCaller = (HeapRegionNode) rsnCaller;
1899 assert !callerNodeIDsCopiedToCallee.contains( hrnSrcCaller.getID() );
1900 oocNodeType = hrnSrcCaller.getType();
1901 oocReach = hrnSrcCaller.getAlpha();
1902 oocPredSrcID = hrnSrcCaller.getID();
1903 if( hrnSrcCaller.isOutOfContext() ) {
1904 outOfCalleeContext = false;
1905 outOfCallerContext = true;
1907 outOfCalleeContext = true;
1908 outOfCallerContext = false;
1913 ExistPred.factory( oocPredSrcTemp,
1915 hrnDstCallee.getID(),
1917 reCaller.getField(),
1923 ExistPredSet preds =
1924 ExistPredSet.factory( pred );
1926 RefEdge oocEdgeExisting =
1927 rg.getOutOfContextReferenceTo( hrnDstCallee,
1933 if( oocEdgeExisting == null ) {
1934 // for consistency, map one out-of-context "identifier"
1935 // to one heap region node id, otherwise no convergence
1936 String oocid = "oocid"+
1938 hrnDstCallee.getIDString()+
1941 reCaller.getField();
1943 Integer oocHrnID = oocid2hrnid.get( oocid );
1945 HeapRegionNode hrnCalleeAndOutContext;
1947 if( oocHrnID == null ) {
1949 hrnCalleeAndOutContext =
1950 rg.createNewHeapRegionNode( null, // ID
1951 false, // single object?
1952 false, // new summary?
1953 true, // out-of-context?
1955 null, // alloc site, shouldn't be used
1956 toCalleeContext( oocReach,
1960 toCalleeContext( oocReach,
1968 oocid2hrnid.put( oocid, hrnCalleeAndOutContext.getID() );
1972 // the mapping already exists, so see if node is there
1973 hrnCalleeAndOutContext = rg.id2hrn.get( oocHrnID );
1975 if( hrnCalleeAndOutContext == null ) {
1977 hrnCalleeAndOutContext =
1978 rg.createNewHeapRegionNode( oocHrnID, // ID
1979 false, // single object?
1980 false, // new summary?
1981 true, // out-of-context?
1983 null, // alloc site, shouldn't be used
1984 toCalleeContext( oocReach,
1988 toCalleeContext( oocReach,
1997 // otherwise it is there, so merge reachability
1998 hrnCalleeAndOutContext.setAlpha( Canonical.unionORpreds( hrnCalleeAndOutContext.getAlpha(),
1999 toCalleeContext( oocReach,
2008 assert hrnCalleeAndOutContext.reachHasOnlyOOC();
2010 rg.addRefEdge( hrnCalleeAndOutContext,
2012 new RefEdge( hrnCalleeAndOutContext,
2015 reCaller.getField(),
2016 toCalleeContext( reCaller.getBeta(),
2021 TaintSet.factory() // no taints
2026 // the out-of-context edge already exists
2027 oocEdgeExisting.setBeta( Canonical.unionORpreds( oocEdgeExisting.getBeta(),
2028 toCalleeContext( reCaller.getBeta(),
2035 oocEdgeExisting.setPreds( Canonical.join( oocEdgeExisting.getPreds(),
2040 HeapRegionNode hrnCalleeAndOutContext =
2041 (HeapRegionNode) oocEdgeExisting.getSrc();
2042 hrnCalleeAndOutContext.setAlpha( Canonical.unionORpreds( hrnCalleeAndOutContext.getAlpha(),
2043 toCalleeContext( oocReach,
2050 assert hrnCalleeAndOutContext.reachHasOnlyOOC();
2055 if( writeDebugDOTs ) {
2056 debugGraphPrefix = String.format( "call%03d", debugCallSiteVisitCounter );
2057 rg.writeGraph( debugGraphPrefix+"calleeview",
2058 resolveMethodDebugDOTwriteLabels,
2059 resolveMethodDebugDOTselectTemps,
2060 resolveMethodDebugDOTpruneGarbage,
2061 resolveMethodDebugDOThideReach,
2062 resolveMethodDebugDOThideSubsetReach,
2063 resolveMethodDebugDOThidePreds,
2064 resolveMethodDebugDOThideEdgeTaints );
2070 private static Hashtable<String, Integer> oocid2hrnid =
2071 new Hashtable<String, Integer>();
2074 // useful since many graphs writes in the method call debug code
2075 private static boolean resolveMethodDebugDOTwriteLabels = true;
2076 private static boolean resolveMethodDebugDOTselectTemps = true;
2077 private static boolean resolveMethodDebugDOTpruneGarbage = true;
2078 private static boolean resolveMethodDebugDOThideReach = true;
2079 private static boolean resolveMethodDebugDOThideSubsetReach = true;
2080 private static boolean resolveMethodDebugDOThidePreds = true;
2081 private static boolean resolveMethodDebugDOThideEdgeTaints = true;
2083 static String debugGraphPrefix;
2084 static int debugCallSiteVisitCounter;
2085 static int debugCallSiteVisitStartCapture;
2086 static int debugCallSiteNumVisitsToCapture;
2087 static boolean debugCallSiteStopAfter;
2091 resolveMethodCall( FlatCall fc,
2092 FlatMethod fmCallee,
2093 ReachGraph rgCallee,
2094 Set<Integer> callerNodeIDsCopiedToCallee,
2095 boolean writeDebugDOTs
2098 if( writeDebugDOTs ) {
2099 System.out.println( " Writing out visit "+
2100 debugCallSiteVisitCounter+
2101 " to debug call site" );
2103 debugGraphPrefix = String.format( "call%03d",
2104 debugCallSiteVisitCounter );
2106 rgCallee.writeGraph( debugGraphPrefix+"callee",
2107 resolveMethodDebugDOTwriteLabels,
2108 resolveMethodDebugDOTselectTemps,
2109 resolveMethodDebugDOTpruneGarbage,
2110 resolveMethodDebugDOThideReach,
2111 resolveMethodDebugDOThideSubsetReach,
2112 resolveMethodDebugDOThidePreds,
2113 resolveMethodDebugDOThideEdgeTaints );
2115 writeGraph( debugGraphPrefix+"caller00In",
2116 resolveMethodDebugDOTwriteLabels,
2117 resolveMethodDebugDOTselectTemps,
2118 resolveMethodDebugDOTpruneGarbage,
2119 resolveMethodDebugDOThideReach,
2120 resolveMethodDebugDOThideSubsetReach,
2121 resolveMethodDebugDOThidePreds,
2122 resolveMethodDebugDOThideEdgeTaints,
2123 callerNodeIDsCopiedToCallee );
2128 // method call transfer function steps:
2129 // 1. Use current callee-reachable heap (CRH) to test callee
2130 // predicates and mark what will be coming in.
2131 // 2. Wipe CRH out of caller.
2132 // 3. Transplant marked callee parts in:
2133 // a) bring in nodes
2134 // b) bring in callee -> callee edges
2135 // c) resolve out-of-context -> callee edges
2136 // d) assign return value
2137 // 4. Collapse shadow nodes down
2138 // 5. Global sweep it.
2141 // 1. mark what callee elements have satisfied predicates
2142 Hashtable<HeapRegionNode, ExistPredSet> calleeNodesSatisfied =
2143 new Hashtable<HeapRegionNode, ExistPredSet>();
2145 Hashtable<RefEdge, ExistPredSet> calleeEdgesSatisfied =
2146 new Hashtable<RefEdge, ExistPredSet>();
2148 Hashtable< HeapRegionNode, Hashtable<ReachState, ExistPredSet> >
2149 calleeNode2calleeStatesSatisfied =
2150 new Hashtable< HeapRegionNode, Hashtable<ReachState, ExistPredSet> >();
2152 Hashtable< RefEdge, Hashtable<ReachState, ExistPredSet> >
2153 calleeEdge2calleeStatesSatisfied =
2154 new Hashtable< RefEdge, Hashtable<ReachState, ExistPredSet> >();
2156 Hashtable< RefEdge, Hashtable<Taint, ExistPredSet> >
2157 calleeEdge2calleeTaintsSatisfied =
2158 new Hashtable< RefEdge, Hashtable<Taint, ExistPredSet> >();
2160 Hashtable< RefEdge, Set<RefSrcNode> > calleeEdges2oocCallerSrcMatches =
2161 new Hashtable< RefEdge, Set<RefSrcNode> >();
2164 Iterator meItr = rgCallee.id2hrn.entrySet().iterator();
2165 while( meItr.hasNext() ) {
2166 Map.Entry me = (Map.Entry) meItr.next();
2167 Integer id = (Integer) me.getKey();
2168 HeapRegionNode hrnCallee = (HeapRegionNode) me.getValue();
2170 // if a callee element's predicates are satisfied then a set
2171 // of CALLER predicates is returned: they are the predicates
2172 // that the callee element moved into the caller context
2173 // should have, and it is inefficient to find this again later
2174 ExistPredSet predsIfSatis =
2175 hrnCallee.getPreds().isSatisfiedBy( this,
2176 callerNodeIDsCopiedToCallee
2179 if( predsIfSatis != null ) {
2180 calleeNodesSatisfied.put( hrnCallee, predsIfSatis );
2182 // otherwise don't bother looking at edges to this node
2186 // since the node is coming over, find out which reach
2187 // states on it should come over, too
2188 assert calleeNode2calleeStatesSatisfied.get( hrnCallee ) == null;
2190 Iterator<ReachState> stateItr = hrnCallee.getAlpha().iterator();
2191 while( stateItr.hasNext() ) {
2192 ReachState stateCallee = stateItr.next();
2195 stateCallee.getPreds().isSatisfiedBy( this,
2196 callerNodeIDsCopiedToCallee
2198 if( predsIfSatis != null ) {
2200 Hashtable<ReachState, ExistPredSet> calleeStatesSatisfied =
2201 calleeNode2calleeStatesSatisfied.get( hrnCallee );
2203 if( calleeStatesSatisfied == null ) {
2204 calleeStatesSatisfied =
2205 new Hashtable<ReachState, ExistPredSet>();
2207 calleeNode2calleeStatesSatisfied.put( hrnCallee, calleeStatesSatisfied );
2210 calleeStatesSatisfied.put( stateCallee, predsIfSatis );
2214 // then look at edges to the node
2215 Iterator<RefEdge> reItr = hrnCallee.iteratorToReferencers();
2216 while( reItr.hasNext() ) {
2217 RefEdge reCallee = reItr.next();
2218 RefSrcNode rsnCallee = reCallee.getSrc();
2220 // (caller local variables to in-context heap regions)
2221 // have an (out-of-context heap region -> in-context heap region)
2222 // abstraction in the callEE, so its true we never need to
2223 // look at a (var node -> heap region) edge in callee to bring
2224 // those over for the call site transfer, except for the special
2225 // case of *RETURN var* -> heap region edges.
2226 // What about (param var->heap region)
2227 // edges in callee? They are dealt with below this loop.
2229 if( rsnCallee instanceof VariableNode ) {
2231 // looking for the return-value variable only
2232 VariableNode vnCallee = (VariableNode) rsnCallee;
2233 if( vnCallee.getTempDescriptor() != tdReturn ) {
2237 TempDescriptor returnTemp = fc.getReturnTemp();
2238 if( returnTemp == null ||
2239 !DisjointAnalysis.shouldAnalysisTrack( returnTemp.getType() )
2244 // note that the assignment of the return value is to a
2245 // variable in the caller which is out-of-context with
2246 // respect to the callee
2247 VariableNode vnLhsCaller = getVariableNodeFromTemp( returnTemp );
2248 Set<RefSrcNode> rsnCallers = new HashSet<RefSrcNode>();
2249 rsnCallers.add( vnLhsCaller );
2250 calleeEdges2oocCallerSrcMatches.put( reCallee, rsnCallers );
2254 // for HeapRegionNode callee sources...
2256 // first see if the source is out-of-context, and only
2257 // proceed with this edge if we find some caller-context
2259 HeapRegionNode hrnSrcCallee = (HeapRegionNode) rsnCallee;
2260 boolean matchedOutOfContext = false;
2262 if( !hrnSrcCallee.isOutOfContext() ) {
2265 hrnSrcCallee.getPreds().isSatisfiedBy( this,
2266 callerNodeIDsCopiedToCallee
2268 if( predsIfSatis != null ) {
2269 calleeNodesSatisfied.put( hrnSrcCallee, predsIfSatis );
2271 // otherwise forget this edge
2276 // hrnSrcCallee is out-of-context
2278 assert !calleeEdges2oocCallerSrcMatches.containsKey( reCallee );
2280 Set<RefSrcNode> rsnCallers = new HashSet<RefSrcNode>();
2282 // is the target node in the caller?
2283 HeapRegionNode hrnDstCaller = this.id2hrn.get( hrnCallee.getID() );
2284 if( hrnDstCaller == null ) {
2288 Iterator<RefEdge> reDstItr = hrnDstCaller.iteratorToReferencers();
2289 while( reDstItr.hasNext() ) {
2290 // the edge and field (either possibly null) must match
2291 RefEdge reCaller = reDstItr.next();
2293 if( !reCaller.typeEquals ( reCallee.getType() ) ||
2294 !reCaller.fieldEquals( reCallee.getField() )
2299 RefSrcNode rsnCaller = reCaller.getSrc();
2300 if( rsnCaller instanceof VariableNode ) {
2302 // a variable node matches an OOC region with null type
2303 if( hrnSrcCallee.getType() != null ) {
2308 // otherwise types should match
2309 HeapRegionNode hrnCallerSrc = (HeapRegionNode) rsnCaller;
2310 if( hrnSrcCallee.getType() == null ) {
2311 if( hrnCallerSrc.getType() != null ) {
2315 if( !hrnSrcCallee.getType().equals( hrnCallerSrc.getType() ) ) {
2321 rsnCallers.add( rsnCaller );
2322 matchedOutOfContext = true;
2325 if( !rsnCallers.isEmpty() ) {
2326 calleeEdges2oocCallerSrcMatches.put( reCallee, rsnCallers );
2330 if( hrnSrcCallee.isOutOfContext() &&
2331 !matchedOutOfContext ) {
2338 reCallee.getPreds().isSatisfiedBy( this,
2339 callerNodeIDsCopiedToCallee
2342 if( predsIfSatis != null ) {
2343 calleeEdgesSatisfied.put( reCallee, predsIfSatis );
2345 // since the edge is coming over, find out which reach
2346 // states on it should come over, too
2347 assert calleeEdge2calleeStatesSatisfied.get( reCallee ) == null;
2349 stateItr = reCallee.getBeta().iterator();
2350 while( stateItr.hasNext() ) {
2351 ReachState stateCallee = stateItr.next();
2354 stateCallee.getPreds().isSatisfiedBy( this,
2355 callerNodeIDsCopiedToCallee
2357 if( predsIfSatis != null ) {
2359 Hashtable<ReachState, ExistPredSet> calleeStatesSatisfied =
2360 calleeEdge2calleeStatesSatisfied.get( reCallee );
2362 if( calleeStatesSatisfied == null ) {
2363 calleeStatesSatisfied =
2364 new Hashtable<ReachState, ExistPredSet>();
2366 calleeEdge2calleeStatesSatisfied.put( reCallee, calleeStatesSatisfied );
2369 calleeStatesSatisfied.put( stateCallee, predsIfSatis );
2373 // since the edge is coming over, find out which taints
2374 // on it should come over, too
2375 assert calleeEdge2calleeTaintsSatisfied.get( reCallee ) == null;
2377 Iterator<Taint> tItr = reCallee.getTaints().iterator();
2378 while( tItr.hasNext() ) {
2379 Taint tCallee = tItr.next();
2382 tCallee.getPreds().isSatisfiedBy( this,
2383 callerNodeIDsCopiedToCallee
2385 if( predsIfSatis != null ) {
2387 Hashtable<Taint, ExistPredSet> calleeTaintsSatisfied =
2388 calleeEdge2calleeTaintsSatisfied.get( reCallee );
2390 if( calleeTaintsSatisfied == null ) {
2391 calleeTaintsSatisfied =
2392 new Hashtable<Taint, ExistPredSet>();
2394 calleeEdge2calleeTaintsSatisfied.put( reCallee, calleeTaintsSatisfied );
2397 calleeTaintsSatisfied.put( tCallee, predsIfSatis );
2404 if( writeDebugDOTs ) {
2405 writeGraph( debugGraphPrefix+"caller20BeforeWipe",
2406 resolveMethodDebugDOTwriteLabels,
2407 resolveMethodDebugDOTselectTemps,
2408 resolveMethodDebugDOTpruneGarbage,
2409 resolveMethodDebugDOThideReach,
2410 resolveMethodDebugDOThideSubsetReach,
2411 resolveMethodDebugDOThidePreds,
2412 resolveMethodDebugDOThideEdgeTaints );
2416 // 2. predicates tested, ok to wipe out caller part
2417 Iterator<Integer> hrnItr = callerNodeIDsCopiedToCallee.iterator();
2418 while( hrnItr.hasNext() ) {
2419 Integer hrnID = hrnItr.next();
2420 HeapRegionNode hrnCaller = id2hrn.get( hrnID );
2421 assert hrnCaller != null;
2423 // when clearing off nodes, also eliminate variable
2425 wipeOut( hrnCaller, true );
2428 // if we are assigning the return value to something, clobber now
2429 // as part of the wipe
2430 TempDescriptor returnTemp = fc.getReturnTemp();
2431 if( returnTemp != null &&
2432 DisjointAnalysis.shouldAnalysisTrack( returnTemp.getType() )
2435 VariableNode vnLhsCaller = getVariableNodeFromTemp( returnTemp );
2436 clearRefEdgesFrom( vnLhsCaller, null, null, true );
2442 if( writeDebugDOTs ) {
2443 writeGraph( debugGraphPrefix+"caller30BeforeAddingNodes",
2444 resolveMethodDebugDOTwriteLabels,
2445 resolveMethodDebugDOTselectTemps,
2446 resolveMethodDebugDOTpruneGarbage,
2447 resolveMethodDebugDOThideReach,
2448 resolveMethodDebugDOThideSubsetReach,
2449 resolveMethodDebugDOThidePreds,
2450 resolveMethodDebugDOThideEdgeTaints );
2456 // 3. callee elements with satisfied preds come in, note that
2457 // the mapping of elements satisfied to preds is like this:
2458 // A callee element EE has preds EEp that are satisfied by
2459 // some caller element ER. We bring EE into the caller
2460 // context as ERee with the preds of ER, namely ERp, which
2461 // in the following algorithm is the value in the mapping
2464 Iterator satisItr = calleeNodesSatisfied.entrySet().iterator();
2465 while( satisItr.hasNext() ) {
2466 Map.Entry me = (Map.Entry) satisItr.next();
2467 HeapRegionNode hrnCallee = (HeapRegionNode) me.getKey();
2468 ExistPredSet preds = (ExistPredSet) me.getValue();
2470 // TODO: I think its true that the current implementation uses
2471 // the type of the OOC region and the predicates OF THE EDGE from
2472 // it to link everything up in caller context, so that's why we're
2473 // skipping this... maybe that's a sillier way to do it?
2474 if( hrnCallee.isOutOfContext() ) {
2478 AllocSite as = hrnCallee.getAllocSite();
2479 allocSites.add( as );
2481 Integer hrnIDshadow = as.getShadowIDfromID( hrnCallee.getID() );
2483 HeapRegionNode hrnCaller = id2hrn.get( hrnIDshadow );
2484 if( hrnCaller == null ) {
2486 createNewHeapRegionNode( hrnIDshadow, // id or null to generate a new one
2487 hrnCallee.isSingleObject(), // single object?
2488 hrnCallee.isNewSummary(), // summary?
2489 false, // out-of-context?
2490 hrnCallee.getType(), // type
2491 hrnCallee.getAllocSite(), // allocation site
2492 toCallerContext( hrnCallee.getInherent(),
2493 calleeNode2calleeStatesSatisfied.get( hrnCallee ) ), // inherent reach
2494 null, // current reach
2495 predsEmpty, // predicates
2496 hrnCallee.getDescription() // description
2499 assert hrnCaller.isWiped();
2502 hrnCaller.setAlpha( toCallerContext( hrnCallee.getAlpha(),
2503 calleeNode2calleeStatesSatisfied.get( hrnCallee )
2507 hrnCaller.setPreds( preds );
2514 if( writeDebugDOTs ) {
2515 writeGraph( debugGraphPrefix+"caller31BeforeAddingEdges",
2516 resolveMethodDebugDOTwriteLabels,
2517 resolveMethodDebugDOTselectTemps,
2518 resolveMethodDebugDOTpruneGarbage,
2519 resolveMethodDebugDOThideReach,
2520 resolveMethodDebugDOThideSubsetReach,
2521 resolveMethodDebugDOThidePreds,
2522 resolveMethodDebugDOThideEdgeTaints );
2526 // set these up during the next procedure so after
2527 // the caller has all of its nodes and edges put
2528 // back together we can propagate the callee's
2529 // reach changes backwards into the caller graph
2530 HashSet<RefEdge> edgesForPropagation = new HashSet<RefEdge>();
2532 Hashtable<RefEdge, ChangeSet> edgePlannedChanges =
2533 new Hashtable<RefEdge, ChangeSet>();
2536 // 3.b) callee -> callee edges AND out-of-context -> callee
2537 // which includes return temp -> callee edges now, too
2538 satisItr = calleeEdgesSatisfied.entrySet().iterator();
2539 while( satisItr.hasNext() ) {
2540 Map.Entry me = (Map.Entry) satisItr.next();
2541 RefEdge reCallee = (RefEdge) me.getKey();
2542 ExistPredSet preds = (ExistPredSet) me.getValue();
2544 HeapRegionNode hrnDstCallee = reCallee.getDst();
2545 AllocSite asDst = hrnDstCallee.getAllocSite();
2546 allocSites.add( asDst );
2548 Integer hrnIDDstShadow =
2549 asDst.getShadowIDfromID( hrnDstCallee.getID() );
2551 HeapRegionNode hrnDstCaller = id2hrn.get( hrnIDDstShadow );
2552 assert hrnDstCaller != null;
2555 RefSrcNode rsnCallee = reCallee.getSrc();
2557 Set<RefSrcNode> rsnCallers =
2558 new HashSet<RefSrcNode>();
2560 Set<RefSrcNode> oocCallers =
2561 calleeEdges2oocCallerSrcMatches.get( reCallee );
2563 if( rsnCallee instanceof HeapRegionNode ) {
2564 HeapRegionNode hrnCalleeSrc = (HeapRegionNode) rsnCallee;
2565 if( hrnCalleeSrc.isOutOfContext() ) {
2566 assert oocCallers != null;
2571 if( oocCallers == null ) {
2572 // there are no out-of-context matches, so it's
2573 // either a param/arg var or one in-context heap region
2574 if( rsnCallee instanceof VariableNode ) {
2575 // variable -> node in the callee should only
2576 // come into the caller if its from a param var
2577 VariableNode vnCallee = (VariableNode) rsnCallee;
2578 TempDescriptor tdParam = vnCallee.getTempDescriptor();
2579 TempDescriptor tdArg = fc.getArgMatchingParam( fmCallee,
2581 if( tdArg == null ) {
2582 // this means the variable isn't a parameter, its local
2583 // to the callee so we ignore it in call site transfer
2584 // shouldn't this NEVER HAPPEN?
2588 rsnCallers.add( this.getVariableNodeFromTemp( tdArg ) );
2591 // otherwise source is in context, one region
2593 HeapRegionNode hrnSrcCallee = (HeapRegionNode) rsnCallee;
2595 // translate an in-context node to shadow
2596 AllocSite asSrc = hrnSrcCallee.getAllocSite();
2597 allocSites.add( asSrc );
2599 Integer hrnIDSrcShadow =
2600 asSrc.getShadowIDfromID( hrnSrcCallee.getID() );
2602 HeapRegionNode hrnSrcCallerShadow =
2603 this.id2hrn.get( hrnIDSrcShadow );
2605 assert hrnSrcCallerShadow != null;
2607 rsnCallers.add( hrnSrcCallerShadow );
2611 // otherwise we have a set of out-of-context srcs
2612 // that should NOT be translated to shadow nodes
2613 assert !oocCallers.isEmpty();
2614 rsnCallers.addAll( oocCallers );
2617 // now make all caller edges we've identified from
2618 // this callee edge with a satisfied predicate
2619 assert !rsnCallers.isEmpty();
2620 Iterator<RefSrcNode> rsnItr = rsnCallers.iterator();
2621 while( rsnItr.hasNext() ) {
2622 RefSrcNode rsnCaller = rsnItr.next();
2624 RefEdge reCaller = new RefEdge( rsnCaller,
2627 reCallee.getField(),
2628 toCallerContext( reCallee.getBeta(),
2629 calleeEdge2calleeStatesSatisfied.get( reCallee ) ),
2631 toCallerContext( reCallee.getTaints(),
2632 calleeEdge2calleeTaintsSatisfied.get( reCallee ) )
2635 ChangeSet cs = ChangeSet.factory();
2636 Iterator<ReachState> rsItr = reCaller.getBeta().iterator();
2637 while( rsItr.hasNext() ) {
2638 ReachState state = rsItr.next();
2639 ExistPredSet predsPreCallee = state.getPreds();
2641 if( state.isEmpty() ) {
2645 Iterator<ExistPred> predItr = predsPreCallee.iterator();
2646 while( predItr.hasNext() ) {
2647 ExistPred pred = predItr.next();
2648 ReachState old = pred.ne_state;
2654 cs = Canonical.add( cs,
2655 ChangeTuple.factory( old,
2662 // we're just going to use the convenient "merge-if-exists"
2663 // edge call below, but still take a separate look if there
2664 // is an existing caller edge to build change sets properly
2665 if( !cs.isEmpty() ) {
2666 RefEdge edgeExisting = rsnCaller.getReferenceTo( hrnDstCaller,
2670 if( edgeExisting != null ) {
2671 ChangeSet csExisting = edgePlannedChanges.get( edgeExisting );
2672 if( csExisting == null ) {
2673 csExisting = ChangeSet.factory();
2675 edgePlannedChanges.put( edgeExisting,
2676 Canonical.union( csExisting,
2681 edgesForPropagation.add( reCaller );
2682 assert !edgePlannedChanges.containsKey( reCaller );
2683 edgePlannedChanges.put( reCaller, cs );
2687 // then add new caller edge or merge
2688 addEdgeOrMergeWithExisting( reCaller );
2696 if( writeDebugDOTs ) {
2697 writeGraph( debugGraphPrefix+"caller38propagateReach",
2698 resolveMethodDebugDOTwriteLabels,
2699 resolveMethodDebugDOTselectTemps,
2700 resolveMethodDebugDOTpruneGarbage,
2701 resolveMethodDebugDOThideReach,
2702 resolveMethodDebugDOThideSubsetReach,
2703 resolveMethodDebugDOThidePreds,
2704 resolveMethodDebugDOThideEdgeTaints );
2707 // propagate callee reachability changes to the rest
2708 // of the caller graph edges
2709 HashSet<RefEdge> edgesUpdated = new HashSet<RefEdge>();
2711 propagateTokensOverEdges( edgesForPropagation, // source edges
2712 edgePlannedChanges, // map src edge to change set
2713 edgesUpdated ); // list of updated edges
2715 // commit beta' (beta<-betaNew)
2716 Iterator<RefEdge> edgeItr = edgesUpdated.iterator();
2717 while( edgeItr.hasNext() ) {
2718 edgeItr.next().applyBetaNew();
2727 if( writeDebugDOTs ) {
2728 writeGraph( debugGraphPrefix+"caller40BeforeShadowMerge",
2729 resolveMethodDebugDOTwriteLabels,
2730 resolveMethodDebugDOTselectTemps,
2731 resolveMethodDebugDOTpruneGarbage,
2732 resolveMethodDebugDOThideReach,
2733 resolveMethodDebugDOThideSubsetReach,
2734 resolveMethodDebugDOThidePreds,
2735 resolveMethodDebugDOThideEdgeTaints );
2739 // 4) merge shadow nodes so alloc sites are back to k
2740 Iterator<AllocSite> asItr = rgCallee.allocSites.iterator();
2741 while( asItr.hasNext() ) {
2742 // for each allocation site do the following to merge
2743 // shadow nodes (newest from callee) with any existing
2744 // look for the newest normal and newest shadow "slot"
2745 // not being used, transfer normal to shadow. Keep
2746 // doing this until there are no more normal nodes, or
2747 // no empty shadow slots: then merge all remaining normal
2748 // nodes into the shadow summary. Finally, convert all
2749 // shadow to their normal versions.
2750 AllocSite as = asItr.next();
2753 while( ageNorm < allocationDepth &&
2754 ageShad < allocationDepth ) {
2756 // first, are there any normal nodes left?
2757 Integer idNorm = as.getIthOldest( ageNorm );
2758 HeapRegionNode hrnNorm = id2hrn.get( idNorm );
2759 if( hrnNorm == null ) {
2760 // no, this age of normal node not in the caller graph
2765 // yes, a normal node exists, is there an empty shadow
2766 // "slot" to transfer it onto?
2767 HeapRegionNode hrnShad = getIthNode( as, ageShad, true );
2768 if( !hrnShad.isWiped() ) {
2769 // no, this age of shadow node is not empty
2774 // yes, this shadow node is empty
2775 transferOnto( hrnNorm, hrnShad );
2780 // now, while there are still normal nodes but no shadow
2781 // slots, merge normal nodes into the shadow summary
2782 while( ageNorm < allocationDepth ) {
2784 // first, are there any normal nodes left?
2785 Integer idNorm = as.getIthOldest( ageNorm );
2786 HeapRegionNode hrnNorm = id2hrn.get( idNorm );
2787 if( hrnNorm == null ) {
2788 // no, this age of normal node not in the caller graph
2793 // yes, a normal node exists, so get the shadow summary
2794 HeapRegionNode summShad = getSummaryNode( as, true );
2795 mergeIntoSummary( hrnNorm, summShad );
2799 // if there is a normal summary, merge it into shadow summary
2800 Integer idNorm = as.getSummary();
2801 HeapRegionNode summNorm = id2hrn.get( idNorm );
2802 if( summNorm != null ) {
2803 HeapRegionNode summShad = getSummaryNode( as, true );
2804 mergeIntoSummary( summNorm, summShad );
2807 // finally, flip all existing shadow nodes onto the normal
2808 for( int i = 0; i < allocationDepth; ++i ) {
2809 Integer idShad = as.getIthOldestShadow( i );
2810 HeapRegionNode hrnShad = id2hrn.get( idShad );
2811 if( hrnShad != null ) {
2813 HeapRegionNode hrnNorm = getIthNode( as, i, false );
2814 assert hrnNorm.isWiped();
2815 transferOnto( hrnShad, hrnNorm );
2819 Integer idShad = as.getSummaryShadow();
2820 HeapRegionNode summShad = id2hrn.get( idShad );
2821 if( summShad != null ) {
2822 summNorm = getSummaryNode( as, false );
2823 transferOnto( summShad, summNorm );
2832 if( writeDebugDOTs ) {
2833 writeGraph( debugGraphPrefix+"caller45BeforeUnshadow",
2834 resolveMethodDebugDOTwriteLabels,
2835 resolveMethodDebugDOTselectTemps,
2836 resolveMethodDebugDOTpruneGarbage,
2837 resolveMethodDebugDOThideReach,
2838 resolveMethodDebugDOThideSubsetReach,
2839 resolveMethodDebugDOThidePreds,
2840 resolveMethodDebugDOThideEdgeTaints );
2844 Iterator itrAllHRNodes = id2hrn.entrySet().iterator();
2845 while( itrAllHRNodes.hasNext() ) {
2846 Map.Entry me = (Map.Entry) itrAllHRNodes.next();
2847 HeapRegionNode hrn = (HeapRegionNode) me.getValue();
2849 hrn.setAlpha( unshadow( hrn.getAlpha() ) );
2851 Iterator<RefEdge> itrEdges = hrn.iteratorToReferencers();
2852 while( itrEdges.hasNext() ) {
2853 RefEdge re = itrEdges.next();
2854 re.setBeta( unshadow( re.getBeta() ) );
2861 if( writeDebugDOTs ) {
2862 writeGraph( debugGraphPrefix+"caller50BeforeGlobalSweep",
2863 resolveMethodDebugDOTwriteLabels,
2864 resolveMethodDebugDOTselectTemps,
2865 resolveMethodDebugDOTpruneGarbage,
2866 resolveMethodDebugDOThideReach,
2867 resolveMethodDebugDOThideSubsetReach,
2868 resolveMethodDebugDOThidePreds,
2869 resolveMethodDebugDOThideEdgeTaints );
2874 if( !DISABLE_GLOBAL_SWEEP ) {
2879 if( writeDebugDOTs ) {
2880 writeGraph( debugGraphPrefix+"caller90AfterTransfer",
2881 resolveMethodDebugDOTwriteLabels,
2882 resolveMethodDebugDOTselectTemps,
2883 resolveMethodDebugDOTpruneGarbage,
2884 resolveMethodDebugDOThideReach,
2885 resolveMethodDebugDOThideSubsetReach,
2886 resolveMethodDebugDOThidePreds,
2887 resolveMethodDebugDOThideEdgeTaints );
2893 ////////////////////////////////////////////////////
2895 // Abstract garbage collection simply removes
2896 // heap region nodes that are not mechanically
2897 // reachable from a root set. This step is
2898 // essential for testing node and edge existence
2899 // predicates efficiently
2901 ////////////////////////////////////////////////////
2902 public void abstractGarbageCollect( Set<TempDescriptor> liveSet ) {
2904 // calculate a root set, will be different for Java
2905 // version of analysis versus Bamboo version
2906 Set<RefSrcNode> toVisit = new HashSet<RefSrcNode>();
2908 // visit every variable in graph while building root
2909 // set, and do iterating on a copy, so we can remove
2910 // dead variables while we're at this
2911 Iterator makeCopyItr = td2vn.entrySet().iterator();
2912 Set entrysCopy = new HashSet();
2913 while( makeCopyItr.hasNext() ) {
2914 entrysCopy.add( makeCopyItr.next() );
2917 Iterator eItr = entrysCopy.iterator();
2918 while( eItr.hasNext() ) {
2919 Map.Entry me = (Map.Entry) eItr.next();
2920 TempDescriptor td = (TempDescriptor) me.getKey();
2921 VariableNode vn = (VariableNode) me.getValue();
2923 if( liveSet.contains( td ) ) {
2927 // dead var, remove completely from graph
2929 clearRefEdgesFrom( vn, null, null, true );
2933 // everything visited in a traversal is
2934 // considered abstractly live
2935 Set<RefSrcNode> visited = new HashSet<RefSrcNode>();
2937 while( !toVisit.isEmpty() ) {
2938 RefSrcNode rsn = toVisit.iterator().next();
2939 toVisit.remove( rsn );
2942 Iterator<RefEdge> hrnItr = rsn.iteratorToReferencees();
2943 while( hrnItr.hasNext() ) {
2944 RefEdge edge = hrnItr.next();
2945 HeapRegionNode hrn = edge.getDst();
2947 if( !visited.contains( hrn ) ) {
2953 // get a copy of the set to iterate over because
2954 // we're going to monkey with the graph when we
2955 // identify a garbage node
2956 Set<HeapRegionNode> hrnAllPrior = new HashSet<HeapRegionNode>();
2957 Iterator<HeapRegionNode> hrnItr = id2hrn.values().iterator();
2958 while( hrnItr.hasNext() ) {
2959 hrnAllPrior.add( hrnItr.next() );
2962 Iterator<HeapRegionNode> hrnAllItr = hrnAllPrior.iterator();
2963 while( hrnAllItr.hasNext() ) {
2964 HeapRegionNode hrn = hrnAllItr.next();
2966 if( !visited.contains( hrn ) ) {
2968 // heap region nodes are compared across ReachGraph
2969 // objects by their integer ID, so when discarding
2970 // garbage nodes we must also discard entries in
2971 // the ID -> heap region hashtable.
2972 id2hrn.remove( hrn.getID() );
2974 // RefEdge objects are two-way linked between
2975 // nodes, so when a node is identified as garbage,
2976 // actively clear references to and from it so
2977 // live nodes won't have dangling RefEdge's
2978 wipeOut( hrn, true );
2980 // if we just removed the last node from an allocation
2981 // site, it should be taken out of the ReachGraph's list
2982 AllocSite as = hrn.getAllocSite();
2983 if( !hasNodesOf( as ) ) {
2984 allocSites.remove( as );
2990 protected boolean hasNodesOf( AllocSite as ) {
2991 if( id2hrn.containsKey( as.getSummary() ) ) {
2995 for( int i = 0; i < allocationDepth; ++i ) {
2996 if( id2hrn.containsKey( as.getIthOldest( i ) ) ) {
3004 ////////////////////////////////////////////////////
3006 // This global sweep is an optional step to prune
3007 // reachability sets that are not internally
3008 // consistent with the global graph. It should be
3009 // invoked after strong updates or method calls.
3011 ////////////////////////////////////////////////////
3012 public void globalSweep() {
3014 // boldB is part of the phase 1 sweep
3015 // it has an in-context table and an out-of-context table
3016 Hashtable< Integer, Hashtable<RefEdge, ReachSet> > boldBic =
3017 new Hashtable< Integer, Hashtable<RefEdge, ReachSet> >();
3019 Hashtable< Integer, Hashtable<RefEdge, ReachSet> > boldBooc =
3020 new Hashtable< Integer, Hashtable<RefEdge, ReachSet> >();
3022 // visit every heap region to initialize alphaNew and betaNew,
3023 // and make a map of every hrnID to the source nodes it should
3024 // propagate forward from. In-context flagged hrnID's propagate
3025 // from only the in-context node they name, but out-of-context
3026 // ID's may propagate from several out-of-context nodes
3027 Hashtable< Integer, Set<HeapRegionNode> > icID2srcs =
3028 new Hashtable< Integer, Set<HeapRegionNode> >();
3030 Hashtable< Integer, Set<HeapRegionNode> > oocID2srcs =
3031 new Hashtable< Integer, Set<HeapRegionNode> >();
3034 Iterator itrHrns = id2hrn.entrySet().iterator();
3035 while( itrHrns.hasNext() ) {
3036 Map.Entry me = (Map.Entry) itrHrns.next();
3037 Integer hrnID = (Integer) me.getKey();
3038 HeapRegionNode hrn = (HeapRegionNode) me.getValue();
3040 // assert that this node and incoming edges have clean alphaNew
3041 // and betaNew sets, respectively
3042 assert rsetEmpty.equals( hrn.getAlphaNew() );
3044 Iterator<RefEdge> itrRers = hrn.iteratorToReferencers();
3045 while( itrRers.hasNext() ) {
3046 RefEdge edge = itrRers.next();
3047 assert rsetEmpty.equals( edge.getBetaNew() );
3050 // make a mapping of IDs to heap regions they propagate from
3051 if( hrn.isFlagged() ) {
3052 assert !hrn.isOutOfContext();
3053 assert !icID2srcs.containsKey( hrn.getID() );
3055 // in-context flagged node IDs simply propagate from the
3057 Set<HeapRegionNode> srcs = new HashSet<HeapRegionNode>();
3059 icID2srcs.put( hrn.getID(), srcs );
3062 if( hrn.isOutOfContext() ) {
3063 assert !hrn.isFlagged();
3065 // the reachability states on an out-of-context
3066 // node are not really important (combinations of
3067 // IDs or arity)--what matters is that the states
3068 // specify which nodes this out-of-context node
3069 // stands in for. For example, if the state [17?, 19*]
3070 // appears on the ooc node, it may serve as a source
3071 // for node 17? and a source for node 19.
3072 Iterator<ReachState> stateItr = hrn.getAlpha().iterator();
3073 while( stateItr.hasNext() ) {
3074 ReachState state = stateItr.next();
3076 Iterator<ReachTuple> rtItr = state.iterator();
3077 while( rtItr.hasNext() ) {
3078 ReachTuple rt = rtItr.next();
3079 assert rt.isOutOfContext();
3081 Set<HeapRegionNode> srcs = oocID2srcs.get( rt.getHrnID() );
3082 if( srcs == null ) {
3083 srcs = new HashSet<HeapRegionNode>();
3086 oocID2srcs.put( rt.getHrnID(), srcs );
3092 // calculate boldB for all hrnIDs identified by the above
3093 // node traversal, propagating from every source
3094 while( !icID2srcs.isEmpty() || !oocID2srcs.isEmpty() ) {
3097 Set<HeapRegionNode> srcs;
3100 if( !icID2srcs.isEmpty() ) {
3101 Map.Entry me = (Map.Entry) icID2srcs.entrySet().iterator().next();
3102 hrnID = (Integer) me.getKey();
3103 srcs = (Set<HeapRegionNode>) me.getValue();
3105 icID2srcs.remove( hrnID );
3108 assert !oocID2srcs.isEmpty();
3110 Map.Entry me = (Map.Entry) oocID2srcs.entrySet().iterator().next();
3111 hrnID = (Integer) me.getKey();
3112 srcs = (Set<HeapRegionNode>) me.getValue();
3114 oocID2srcs.remove( hrnID );
3118 Hashtable<RefEdge, ReachSet> boldB_f =
3119 new Hashtable<RefEdge, ReachSet>();
3121 Set<RefEdge> workSetEdges = new HashSet<RefEdge>();
3123 Iterator<HeapRegionNode> hrnItr = srcs.iterator();
3124 while( hrnItr.hasNext() ) {
3125 HeapRegionNode hrn = hrnItr.next();
3127 assert workSetEdges.isEmpty();
3129 // initial boldB_f constraints
3130 Iterator<RefEdge> itrRees = hrn.iteratorToReferencees();
3131 while( itrRees.hasNext() ) {
3132 RefEdge edge = itrRees.next();
3134 assert !boldB_f.containsKey( edge );
3135 boldB_f.put( edge, edge.getBeta() );
3137 assert !workSetEdges.contains( edge );
3138 workSetEdges.add( edge );
3141 // enforce the boldB_f constraint at edges until we reach a fixed point
3142 while( !workSetEdges.isEmpty() ) {
3143 RefEdge edge = workSetEdges.iterator().next();
3144 workSetEdges.remove( edge );
3146 Iterator<RefEdge> itrPrime = edge.getDst().iteratorToReferencees();
3147 while( itrPrime.hasNext() ) {
3148 RefEdge edgePrime = itrPrime.next();
3150 ReachSet prevResult = boldB_f.get( edgePrime );
3151 ReachSet intersection = Canonical.intersection( boldB_f.get( edge ),
3155 if( prevResult == null ||
3156 Canonical.unionORpreds( prevResult,
3157 intersection ).size()
3161 if( prevResult == null ) {
3162 boldB_f.put( edgePrime,
3163 Canonical.unionORpreds( edgePrime.getBeta(),
3168 boldB_f.put( edgePrime,
3169 Canonical.unionORpreds( prevResult,
3174 workSetEdges.add( edgePrime );
3181 boldBic.put( hrnID, boldB_f );
3183 boldBooc.put( hrnID, boldB_f );
3188 // use boldB to prune hrnIDs from alpha states that are impossible
3189 // and propagate the differences backwards across edges
3190 HashSet<RefEdge> edgesForPropagation = new HashSet<RefEdge>();
3192 Hashtable<RefEdge, ChangeSet> edgePlannedChanges =
3193 new Hashtable<RefEdge, ChangeSet>();
3196 itrHrns = id2hrn.entrySet().iterator();
3197 while( itrHrns.hasNext() ) {
3198 Map.Entry me = (Map.Entry) itrHrns.next();
3199 Integer hrnID = (Integer) me.getKey();
3200 HeapRegionNode hrn = (HeapRegionNode) me.getValue();
3202 // out-of-context nodes don't participate in the
3203 // global sweep, they serve as sources for the pass
3205 if( hrn.isOutOfContext() ) {
3209 // the inherent states of a region are the exception
3210 // to removal as the global sweep prunes
3211 ReachTuple rtException = ReachTuple.factory( hrnID,
3212 !hrn.isSingleObject(),
3213 ReachTuple.ARITY_ONE,
3214 false // out-of-context
3217 ChangeSet cts = ChangeSet.factory();
3219 // mark hrnIDs for removal
3220 Iterator<ReachState> stateItr = hrn.getAlpha().iterator();
3221 while( stateItr.hasNext() ) {
3222 ReachState stateOld = stateItr.next();
3224 ReachState markedHrnIDs = ReachState.factory();
3226 Iterator<ReachTuple> rtItr = stateOld.iterator();
3227 while( rtItr.hasNext() ) {
3228 ReachTuple rtOld = rtItr.next();
3230 // never remove the inherent hrnID from a flagged region
3231 // because it is trivially satisfied
3232 if( hrn.isFlagged() ) {
3233 if( rtOld == rtException ) {
3238 // does boldB allow this hrnID?
3239 boolean foundState = false;
3240 Iterator<RefEdge> incidentEdgeItr = hrn.iteratorToReferencers();
3241 while( incidentEdgeItr.hasNext() ) {
3242 RefEdge incidentEdge = incidentEdgeItr.next();
3244 Hashtable<RefEdge, ReachSet> B;
3245 if( rtOld.isOutOfContext() ) {
3246 B = boldBooc.get( rtOld.getHrnID() );
3249 if( !id2hrn.containsKey( rtOld.getHrnID() ) ) {
3250 // let symbols not in the graph get pruned
3254 B = boldBic.get( rtOld.getHrnID() );
3258 ReachSet boldB_rtOld_incident = B.get( incidentEdge );
3259 if( boldB_rtOld_incident != null &&
3260 boldB_rtOld_incident.containsIgnorePreds( stateOld ) != null
3268 markedHrnIDs = Canonical.add( markedHrnIDs, rtOld );
3272 // if there is nothing marked, just move on
3273 if( markedHrnIDs.isEmpty() ) {
3274 hrn.setAlphaNew( Canonical.add( hrn.getAlphaNew(),
3281 // remove all marked hrnIDs and establish a change set that should
3282 // propagate backwards over edges from this node
3283 ReachState statePruned = ReachState.factory();
3284 rtItr = stateOld.iterator();
3285 while( rtItr.hasNext() ) {
3286 ReachTuple rtOld = rtItr.next();
3288 if( !markedHrnIDs.containsTuple( rtOld ) ) {
3289 statePruned = Canonical.add( statePruned, rtOld );
3292 assert !stateOld.equals( statePruned );
3294 hrn.setAlphaNew( Canonical.add( hrn.getAlphaNew(),
3298 ChangeTuple ct = ChangeTuple.factory( stateOld,
3301 cts = Canonical.add( cts, ct );
3304 // throw change tuple set on all incident edges
3305 if( !cts.isEmpty() ) {
3306 Iterator<RefEdge> incidentEdgeItr = hrn.iteratorToReferencers();
3307 while( incidentEdgeItr.hasNext() ) {
3308 RefEdge incidentEdge = incidentEdgeItr.next();
3310 edgesForPropagation.add( incidentEdge );
3312 if( edgePlannedChanges.get( incidentEdge ) == null ) {
3313 edgePlannedChanges.put( incidentEdge, cts );
3315 edgePlannedChanges.put(
3317 Canonical.union( edgePlannedChanges.get( incidentEdge ),
3326 HashSet<RefEdge> edgesUpdated = new HashSet<RefEdge>();
3328 propagateTokensOverEdges( edgesForPropagation,
3332 // at the end of the 1st phase reference edges have
3333 // beta, betaNew that correspond to beta and betaR
3335 // commit beta<-betaNew, so beta=betaR and betaNew
3336 // will represent the beta' calculation in 2nd phase
3338 // commit alpha<-alphaNew because it won't change
3339 HashSet<RefEdge> res = new HashSet<RefEdge>();
3341 Iterator<HeapRegionNode> nodeItr = id2hrn.values().iterator();
3342 while( nodeItr.hasNext() ) {
3343 HeapRegionNode hrn = nodeItr.next();
3345 // as mentioned above, out-of-context nodes only serve
3346 // as sources of reach states for the sweep, not part
3348 if( hrn.isOutOfContext() ) {
3349 assert hrn.getAlphaNew().equals( rsetEmpty );
3351 hrn.applyAlphaNew();
3354 Iterator<RefEdge> itrRes = hrn.iteratorToReferencers();
3355 while( itrRes.hasNext() ) {
3356 res.add( itrRes.next() );
3362 Iterator<RefEdge> edgeItr = res.iterator();
3363 while( edgeItr.hasNext() ) {
3364 RefEdge edge = edgeItr.next();
3365 HeapRegionNode hrn = edge.getDst();
3367 // commit results of last phase
3368 if( edgesUpdated.contains( edge ) ) {
3369 edge.applyBetaNew();
3372 // compute intial condition of 2nd phase
3373 edge.setBetaNew( Canonical.intersection( edge.getBeta(),
3379 // every edge in the graph is the initial workset
3380 Set<RefEdge> edgeWorkSet = (Set) res.clone();
3381 while( !edgeWorkSet.isEmpty() ) {
3382 RefEdge edgePrime = edgeWorkSet.iterator().next();
3383 edgeWorkSet.remove( edgePrime );
3385 RefSrcNode rsn = edgePrime.getSrc();
3386 if( !(rsn instanceof HeapRegionNode) ) {
3389 HeapRegionNode hrn = (HeapRegionNode) rsn;
3391 Iterator<RefEdge> itrEdge = hrn.iteratorToReferencers();
3392 while( itrEdge.hasNext() ) {
3393 RefEdge edge = itrEdge.next();
3395 ReachSet prevResult = edge.getBetaNew();
3396 assert prevResult != null;
3398 ReachSet intersection =
3399 Canonical.intersection( edge.getBeta(),
3400 edgePrime.getBetaNew()
3403 if( Canonical.unionORpreds( prevResult,
3410 Canonical.unionORpreds( prevResult,
3414 edgeWorkSet.add( edge );
3419 // commit beta' (beta<-betaNew)
3420 edgeItr = res.iterator();
3421 while( edgeItr.hasNext() ) {
3422 edgeItr.next().applyBetaNew();
3427 // a useful assertion for debugging:
3428 // every in-context tuple on any edge or
3429 // any node should name a node that is
3430 // part of the graph
3431 public boolean inContextTuplesInGraph() {
3433 Iterator hrnItr = id2hrn.entrySet().iterator();
3434 while( hrnItr.hasNext() ) {
3435 Map.Entry me = (Map.Entry) hrnItr.next();
3436 HeapRegionNode hrn = (HeapRegionNode) me.getValue();
3439 Iterator<ReachState> stateItr = hrn.getAlpha().iterator();
3440 while( stateItr.hasNext() ) {
3441 ReachState state = stateItr.next();
3443 Iterator<ReachTuple> rtItr = state.iterator();
3444 while( rtItr.hasNext() ) {
3445 ReachTuple rt = rtItr.next();
3447 if( !rt.isOutOfContext() ) {
3448 if( !id2hrn.containsKey( rt.getHrnID() ) ) {
3449 System.out.println( rt.getHrnID()+" is missing" );
3457 Iterator<RefEdge> edgeItr = hrn.iteratorToReferencers();
3458 while( edgeItr.hasNext() ) {
3459 RefEdge edge = edgeItr.next();
3461 Iterator<ReachState> stateItr = edge.getBeta().iterator();
3462 while( stateItr.hasNext() ) {
3463 ReachState state = stateItr.next();
3465 Iterator<ReachTuple> rtItr = state.iterator();
3466 while( rtItr.hasNext() ) {
3467 ReachTuple rt = rtItr.next();
3469 if( !rt.isOutOfContext() ) {
3470 if( !id2hrn.containsKey( rt.getHrnID() ) ) {
3471 System.out.println( rt.getHrnID()+" is missing" );
3484 // another useful assertion for debugging
3485 public boolean noEmptyReachSetsInGraph() {
3487 Iterator hrnItr = id2hrn.entrySet().iterator();
3488 while( hrnItr.hasNext() ) {
3489 Map.Entry me = (Map.Entry) hrnItr.next();
3490 HeapRegionNode hrn = (HeapRegionNode) me.getValue();
3492 if( !hrn.isOutOfContext() &&
3494 hrn.getAlpha().isEmpty()
3496 System.out.println( "!!! "+hrn+" has an empty ReachSet !!!" );
3500 Iterator<RefEdge> edgeItr = hrn.iteratorToReferencers();
3501 while( edgeItr.hasNext() ) {
3502 RefEdge edge = edgeItr.next();
3504 if( edge.getBeta().isEmpty() ) {
3505 System.out.println( "!!! "+edge+" has an empty ReachSet !!!" );
3515 public boolean everyReachStateWTrue() {
3517 Iterator hrnItr = id2hrn.entrySet().iterator();
3518 while( hrnItr.hasNext() ) {
3519 Map.Entry me = (Map.Entry) hrnItr.next();
3520 HeapRegionNode hrn = (HeapRegionNode) me.getValue();
3523 Iterator<ReachState> stateItr = hrn.getAlpha().iterator();
3524 while( stateItr.hasNext() ) {
3525 ReachState state = stateItr.next();
3527 if( !state.getPreds().equals( predsTrue ) ) {
3533 Iterator<RefEdge> edgeItr = hrn.iteratorToReferencers();
3534 while( edgeItr.hasNext() ) {
3535 RefEdge edge = edgeItr.next();
3537 Iterator<ReachState> stateItr = edge.getBeta().iterator();
3538 while( stateItr.hasNext() ) {
3539 ReachState state = stateItr.next();
3541 if( !state.getPreds().equals( predsTrue ) ) {
3554 ////////////////////////////////////////////////////
3555 // in merge() and equals() methods the suffix A
3556 // represents the passed in graph and the suffix
3557 // B refers to the graph in this object
3558 // Merging means to take the incoming graph A and
3559 // merge it into B, so after the operation graph B
3560 // is the final result.
3561 ////////////////////////////////////////////////////
3562 protected void merge( ReachGraph rg ) {
3569 mergeRefEdges ( rg );
3570 mergeAllocSites( rg );
3571 mergeAccessibleSet( rg );
3574 protected void mergeNodes( ReachGraph rg ) {
3576 // start with heap region nodes
3577 Set sA = rg.id2hrn.entrySet();
3578 Iterator iA = sA.iterator();
3579 while( iA.hasNext() ) {
3580 Map.Entry meA = (Map.Entry) iA.next();
3581 Integer idA = (Integer) meA.getKey();
3582 HeapRegionNode hrnA = (HeapRegionNode) meA.getValue();
3584 // if this graph doesn't have a node the
3585 // incoming graph has, allocate it
3586 if( !id2hrn.containsKey( idA ) ) {
3587 HeapRegionNode hrnB = hrnA.copy();
3588 id2hrn.put( idA, hrnB );
3591 // otherwise this is a node present in both graphs
3592 // so make the new reachability set a union of the
3593 // nodes' reachability sets
3594 HeapRegionNode hrnB = id2hrn.get( idA );
3595 hrnB.setAlpha( Canonical.unionORpreds( hrnB.getAlpha(),
3600 hrnB.setPreds( Canonical.join( hrnB.getPreds(),
3607 if( !hrnA.equals( hrnB ) ) {
3608 rg.writeGraph( "graphA" );
3609 this.writeGraph( "graphB" );
3610 throw new Error( "flagged not matching" );
3618 // now add any variable nodes that are in graph B but
3620 sA = rg.td2vn.entrySet();
3622 while( iA.hasNext() ) {
3623 Map.Entry meA = (Map.Entry) iA.next();
3624 TempDescriptor tdA = (TempDescriptor) meA.getKey();
3625 VariableNode lnA = (VariableNode) meA.getValue();
3627 // if the variable doesn't exist in B, allocate and add it
3628 VariableNode lnB = getVariableNodeFromTemp( tdA );
3632 protected void mergeRefEdges( ReachGraph rg ) {
3634 // between heap regions
3635 Set sA = rg.id2hrn.entrySet();
3636 Iterator iA = sA.iterator();
3637 while( iA.hasNext() ) {
3638 Map.Entry meA = (Map.Entry) iA.next();
3639 Integer idA = (Integer) meA.getKey();
3640 HeapRegionNode hrnA = (HeapRegionNode) meA.getValue();
3642 Iterator<RefEdge> heapRegionsItrA = hrnA.iteratorToReferencees();
3643 while( heapRegionsItrA.hasNext() ) {
3644 RefEdge edgeA = heapRegionsItrA.next();
3645 HeapRegionNode hrnChildA = edgeA.getDst();
3646 Integer idChildA = hrnChildA.getID();
3648 // at this point we know an edge in graph A exists
3649 // idA -> idChildA, does this exist in B?
3650 assert id2hrn.containsKey( idA );
3651 HeapRegionNode hrnB = id2hrn.get( idA );
3652 RefEdge edgeToMerge = null;
3654 Iterator<RefEdge> heapRegionsItrB = hrnB.iteratorToReferencees();
3655 while( heapRegionsItrB.hasNext() &&
3656 edgeToMerge == null ) {
3658 RefEdge edgeB = heapRegionsItrB.next();
3659 HeapRegionNode hrnChildB = edgeB.getDst();
3660 Integer idChildB = hrnChildB.getID();
3662 // don't use the RefEdge.equals() here because
3663 // we're talking about existence between graphs,
3664 // not intragraph equal
3665 if( idChildB.equals( idChildA ) &&
3666 edgeB.typeAndFieldEquals( edgeA ) ) {
3668 edgeToMerge = edgeB;
3672 // if the edge from A was not found in B,
3674 if( edgeToMerge == null ) {
3675 assert id2hrn.containsKey( idChildA );
3676 HeapRegionNode hrnChildB = id2hrn.get( idChildA );
3677 edgeToMerge = edgeA.copy();
3678 edgeToMerge.setSrc( hrnB );
3679 edgeToMerge.setDst( hrnChildB );
3680 addRefEdge( hrnB, hrnChildB, edgeToMerge );
3682 // otherwise, the edge already existed in both graphs
3683 // so merge their reachability sets
3685 // just replace this beta set with the union
3686 assert edgeToMerge != null;
3687 edgeToMerge.setBeta(
3688 Canonical.unionORpreds( edgeToMerge.getBeta(),
3692 edgeToMerge.setPreds(
3693 Canonical.join( edgeToMerge.getPreds(),
3697 edgeToMerge.setTaints(
3698 Canonical.union( edgeToMerge.getTaints(),
3706 // and then again from variable nodes
3707 sA = rg.td2vn.entrySet();
3709 while( iA.hasNext() ) {
3710 Map.Entry meA = (Map.Entry) iA.next();
3711 TempDescriptor tdA = (TempDescriptor) meA.getKey();
3712 VariableNode vnA = (VariableNode) meA.getValue();
3714 Iterator<RefEdge> heapRegionsItrA = vnA.iteratorToReferencees();
3715 while( heapRegionsItrA.hasNext() ) {
3716 RefEdge edgeA = heapRegionsItrA.next();
3717 HeapRegionNode hrnChildA = edgeA.getDst();
3718 Integer idChildA = hrnChildA.getID();
3720 // at this point we know an edge in graph A exists
3721 // tdA -> idChildA, does this exist in B?
3722 assert td2vn.containsKey( tdA );
3723 VariableNode vnB = td2vn.get( tdA );
3724 RefEdge edgeToMerge = null;
3726 Iterator<RefEdge> heapRegionsItrB = vnB.iteratorToReferencees();
3727 while( heapRegionsItrB.hasNext() &&
3728 edgeToMerge == null ) {
3730 RefEdge edgeB = heapRegionsItrB.next();
3731 HeapRegionNode hrnChildB = edgeB.getDst();
3732 Integer idChildB = hrnChildB.getID();
3734 // don't use the RefEdge.equals() here because
3735 // we're talking about existence between graphs
3736 if( idChildB.equals( idChildA ) &&
3737 edgeB.typeAndFieldEquals( edgeA ) ) {
3739 edgeToMerge = edgeB;
3743 // if the edge from A was not found in B,
3745 if( edgeToMerge == null ) {
3746 assert id2hrn.containsKey( idChildA );
3747 HeapRegionNode hrnChildB = id2hrn.get( idChildA );
3748 edgeToMerge = edgeA.copy();
3749 edgeToMerge.setSrc( vnB );
3750 edgeToMerge.setDst( hrnChildB );
3751 addRefEdge( vnB, hrnChildB, edgeToMerge );
3753 // otherwise, the edge already existed in both graphs
3754 // so merge their reachability sets
3756 // just replace this beta set with the union
3757 edgeToMerge.setBeta( Canonical.unionORpreds( edgeToMerge.getBeta(),
3761 edgeToMerge.setPreds( Canonical.join( edgeToMerge.getPreds(),
3765 edgeToMerge.setTaints(
3766 Canonical.union( edgeToMerge.getTaints(),
3775 protected void mergeAllocSites( ReachGraph rg ) {
3776 allocSites.addAll( rg.allocSites );
3779 protected void mergeAccessibleSet( ReachGraph rg ){
3780 // inaccesible status is prior to accessible status
3782 Set<TempDescriptor> varsToMerge=rg.getAccessibleVar();
3783 Set<TempDescriptor> varsRemoved=new HashSet<TempDescriptor>();
3785 for (Iterator iterator = accessibleVars.iterator(); iterator.hasNext();) {
3786 TempDescriptor accessibleVar = (TempDescriptor) iterator.next();
3787 if(!varsToMerge.contains(accessibleVar)){
3788 varsRemoved.add(accessibleVar);
3792 accessibleVars.removeAll(varsRemoved);
3798 static boolean dbgEquals = false;
3801 // it is necessary in the equals() member functions
3802 // to "check both ways" when comparing the data
3803 // structures of two graphs. For instance, if all
3804 // edges between heap region nodes in graph A are
3805 // present and equal in graph B it is not sufficient
3806 // to say the graphs are equal. Consider that there
3807 // may be edges in graph B that are not in graph A.
3808 // the only way to know that all edges in both graphs
3809 // are equally present is to iterate over both data
3810 // structures and compare against the other graph.
3811 public boolean equals( ReachGraph rg ) {
3815 System.out.println( "rg is null" );
3820 if( !areHeapRegionNodesEqual( rg ) ) {
3822 System.out.println( "hrn not equal" );
3827 if( !areVariableNodesEqual( rg ) ) {
3829 System.out.println( "vars not equal" );
3834 if( !areRefEdgesEqual( rg ) ) {
3836 System.out.println( "edges not equal" );
3841 if( !accessibleVars.equals( rg.accessibleVars) ){
3845 // if everything is equal up to this point,
3846 // assert that allocSites is also equal--
3847 // this data is redundant but kept for efficiency
3848 assert allocSites.equals( rg.allocSites );
3854 protected boolean areHeapRegionNodesEqual( ReachGraph rg ) {
3856 if( !areallHRNinAalsoinBandequal( this, rg ) ) {
3860 if( !areallHRNinAalsoinBandequal( rg, this ) ) {
3867 static protected boolean areallHRNinAalsoinBandequal( ReachGraph rgA,
3869 Set sA = rgA.id2hrn.entrySet();
3870 Iterator iA = sA.iterator();
3871 while( iA.hasNext() ) {
3872 Map.Entry meA = (Map.Entry) iA.next();
3873 Integer idA = (Integer) meA.getKey();
3874 HeapRegionNode hrnA = (HeapRegionNode) meA.getValue();
3876 if( !rgB.id2hrn.containsKey( idA ) ) {
3880 HeapRegionNode hrnB = rgB.id2hrn.get( idA );
3881 if( !hrnA.equalsIncludingAlphaAndPreds( hrnB ) ) {
3889 protected boolean areVariableNodesEqual( ReachGraph rg ) {
3891 if( !areallVNinAalsoinBandequal( this, rg ) ) {
3895 if( !areallVNinAalsoinBandequal( rg, this ) ) {
3902 static protected boolean areallVNinAalsoinBandequal( ReachGraph rgA,
3904 Set sA = rgA.td2vn.entrySet();
3905 Iterator iA = sA.iterator();
3906 while( iA.hasNext() ) {
3907 Map.Entry meA = (Map.Entry) iA.next();
3908 TempDescriptor tdA = (TempDescriptor) meA.getKey();
3910 if( !rgB.td2vn.containsKey( tdA ) ) {
3919 protected boolean areRefEdgesEqual( ReachGraph rg ) {
3920 if( !areallREinAandBequal( this, rg ) ) {
3924 if( !areallREinAandBequal( rg, this ) ) {
3931 static protected boolean areallREinAandBequal( ReachGraph rgA,
3934 // check all the heap region->heap region edges
3935 Set sA = rgA.id2hrn.entrySet();
3936 Iterator iA = sA.iterator();
3937 while( iA.hasNext() ) {
3938 Map.Entry meA = (Map.Entry) iA.next();
3939 Integer idA = (Integer) meA.getKey();
3940 HeapRegionNode hrnA = (HeapRegionNode) meA.getValue();
3942 // we should have already checked that the same
3943 // heap regions exist in both graphs
3944 assert rgB.id2hrn.containsKey( idA );
3946 if( !areallREfromAequaltoB( rgA, hrnA, rgB ) ) {
3950 // then check every edge in B for presence in A, starting
3951 // from the same parent HeapRegionNode
3952 HeapRegionNode hrnB = rgB.id2hrn.get( idA );
3954 if( !areallREfromAequaltoB( rgB, hrnB, rgA ) ) {
3959 // then check all the variable->heap region edges
3960 sA = rgA.td2vn.entrySet();
3962 while( iA.hasNext() ) {
3963 Map.Entry meA = (Map.Entry) iA.next();
3964 TempDescriptor tdA = (TempDescriptor) meA.getKey();
3965 VariableNode vnA = (VariableNode) meA.getValue();
3967 // we should have already checked that the same
3968 // label nodes exist in both graphs
3969 assert rgB.td2vn.containsKey( tdA );
3971 if( !areallREfromAequaltoB( rgA, vnA, rgB ) ) {
3975 // then check every edge in B for presence in A, starting
3976 // from the same parent VariableNode
3977 VariableNode vnB = rgB.td2vn.get( tdA );
3979 if( !areallREfromAequaltoB( rgB, vnB, rgA ) ) {
3988 static protected boolean areallREfromAequaltoB( ReachGraph rgA,
3992 Iterator<RefEdge> itrA = rnA.iteratorToReferencees();
3993 while( itrA.hasNext() ) {
3994 RefEdge edgeA = itrA.next();
3995 HeapRegionNode hrnChildA = edgeA.getDst();
3996 Integer idChildA = hrnChildA.getID();
3998 assert rgB.id2hrn.containsKey( idChildA );
4000 // at this point we know an edge in graph A exists
4001 // rnA -> idChildA, does this exact edge exist in B?
4002 boolean edgeFound = false;
4004 RefSrcNode rnB = null;
4005 if( rnA instanceof HeapRegionNode ) {
4006 HeapRegionNode hrnA = (HeapRegionNode) rnA;
4007 rnB = rgB.id2hrn.get( hrnA.getID() );
4009 VariableNode vnA = (VariableNode) rnA;
4010 rnB = rgB.td2vn.get( vnA.getTempDescriptor() );
4013 Iterator<RefEdge> itrB = rnB.iteratorToReferencees();
4014 while( itrB.hasNext() ) {
4015 RefEdge edgeB = itrB.next();
4016 HeapRegionNode hrnChildB = edgeB.getDst();
4017 Integer idChildB = hrnChildB.getID();
4019 if( idChildA.equals( idChildB ) &&
4020 edgeA.typeAndFieldEquals( edgeB ) ) {
4022 // there is an edge in the right place with the right field,
4023 // but do they have the same attributes?
4024 if( edgeA.getBeta().equals( edgeB.getBeta() ) &&
4025 edgeA.equalsPreds( edgeB )
4041 // can be used to assert monotonicity
4042 static public boolean isNoSmallerThan( ReachGraph rgA,
4045 //System.out.println( "*** Asking if A is no smaller than B ***" );
4048 Iterator iA = rgA.id2hrn.entrySet().iterator();
4049 while( iA.hasNext() ) {
4050 Map.Entry meA = (Map.Entry) iA.next();
4051 Integer idA = (Integer) meA.getKey();
4052 HeapRegionNode hrnA = (HeapRegionNode) meA.getValue();
4054 if( !rgB.id2hrn.containsKey( idA ) ) {
4055 System.out.println( " regions smaller" );
4059 //HeapRegionNode hrnB = rgB.id2hrn.get( idA );
4060 /* NOT EQUALS, NO SMALLER THAN!
4061 if( !hrnA.equalsIncludingAlphaAndPreds( hrnB ) ) {
4062 System.out.println( " regions smaller" );
4068 // this works just fine, no smaller than
4069 if( !areallVNinAalsoinBandequal( rgA, rgB ) ) {
4070 System.out.println( " vars smaller:" );
4071 System.out.println( " A:"+rgA.td2vn.keySet() );
4072 System.out.println( " B:"+rgB.td2vn.keySet() );
4077 iA = rgA.id2hrn.entrySet().iterator();
4078 while( iA.hasNext() ) {
4079 Map.Entry meA = (Map.Entry) iA.next();
4080 Integer idA = (Integer) meA.getKey();
4081 HeapRegionNode hrnA = (HeapRegionNode) meA.getValue();
4083 Iterator<RefEdge> reItr = hrnA.iteratorToReferencers();
4084 while( reItr.hasNext() ) {
4085 RefEdge edgeA = reItr.next();
4086 RefSrcNode rsnA = edgeA.getSrc();
4088 // we already checked that nodes were present
4089 HeapRegionNode hrnB = rgB.id2hrn.get( hrnA.getID() );
4090 assert hrnB != null;
4093 if( rsnA instanceof VariableNode ) {
4094 VariableNode vnA = (VariableNode) rsnA;
4095 rsnB = rgB.td2vn.get( vnA.getTempDescriptor() );
4098 HeapRegionNode hrnSrcA = (HeapRegionNode) rsnA;
4099 rsnB = rgB.id2hrn.get( hrnSrcA.getID() );
4101 assert rsnB != null;
4103 RefEdge edgeB = rsnB.getReferenceTo( hrnB,
4107 if( edgeB == null ) {
4108 System.out.println( " edges smaller:" );
4112 // REMEMBER, IS NO SMALLER THAN
4114 System.out.println( " edges smaller" );
4130 // this analysis no longer has the "match anything"
4131 // type which was represented by null
4132 protected TypeDescriptor mostSpecificType( TypeDescriptor td1,
4133 TypeDescriptor td2 ) {
4137 if( td1.isNull() ) {
4140 if( td2.isNull() ) {
4143 return typeUtil.mostSpecific( td1, td2 );
4146 protected TypeDescriptor mostSpecificType( TypeDescriptor td1,
4148 TypeDescriptor td3 ) {
4150 return mostSpecificType( td1,
4151 mostSpecificType( td2, td3 )
4155 protected TypeDescriptor mostSpecificType( TypeDescriptor td1,
4158 TypeDescriptor td4 ) {
4160 return mostSpecificType( mostSpecificType( td1, td2 ),
4161 mostSpecificType( td3, td4 )
4165 protected boolean isSuperiorType( TypeDescriptor possibleSuper,
4166 TypeDescriptor possibleChild ) {
4167 assert possibleSuper != null;
4168 assert possibleChild != null;
4170 if( possibleSuper.isNull() ||
4171 possibleChild.isNull() ) {
4175 return typeUtil.isSuperorType( possibleSuper, possibleChild );
4179 protected boolean hasMatchingField( HeapRegionNode src,
4182 TypeDescriptor tdSrc = src.getType();
4183 assert tdSrc != null;
4185 if( tdSrc.isArray() ) {
4186 TypeDescriptor td = edge.getType();
4189 TypeDescriptor tdSrcDeref = tdSrc.dereference();
4190 assert tdSrcDeref != null;
4192 if( !typeUtil.isSuperorType( tdSrcDeref, td ) ) {
4196 return edge.getField().equals( DisjointAnalysis.arrayElementFieldName );
4199 // if it's not a class, it doesn't have any fields to match
4200 if( !tdSrc.isClass() ) {
4204 ClassDescriptor cd = tdSrc.getClassDesc();
4205 while( cd != null ) {
4206 Iterator fieldItr = cd.getFields();
4208 while( fieldItr.hasNext() ) {
4209 FieldDescriptor fd = (FieldDescriptor) fieldItr.next();
4211 if( fd.getType().equals( edge.getType() ) &&
4212 fd.getSymbol().equals( edge.getField() ) ) {
4217 cd = cd.getSuperDesc();
4220 // otherwise it is a class with fields
4221 // but we didn't find a match
4225 protected boolean hasMatchingType( RefEdge edge,
4226 HeapRegionNode dst ) {
4228 // if the region has no type, matches everything
4229 TypeDescriptor tdDst = dst.getType();
4230 assert tdDst != null;
4232 // if the type is not a class or an array, don't
4233 // match because primitives are copied, no aliases
4234 ClassDescriptor cdDst = tdDst.getClassDesc();
4235 if( cdDst == null && !tdDst.isArray() ) {
4239 // if the edge type is null, it matches everything
4240 TypeDescriptor tdEdge = edge.getType();
4241 assert tdEdge != null;
4243 return typeUtil.isSuperorType( tdEdge, tdDst );
4248 // the default signature for quick-and-dirty debugging
4249 public void writeGraph( String graphName ) {
4250 writeGraph( graphName,
4251 true, // write labels
4252 true, // label select
4253 true, // prune garbage
4254 false, // hide reachability
4255 true, // hide subset reachability
4256 true, // hide predicates
4257 true, // hide edge taints
4258 null // in-context boundary
4262 public void writeGraph( String graphName,
4263 boolean writeLabels,
4264 boolean labelSelect,
4265 boolean pruneGarbage,
4266 boolean hideReachability,
4267 boolean hideSubsetReachability,
4268 boolean hidePredicates,
4269 boolean hideEdgeTaints
4271 writeGraph( graphName,
4276 hideSubsetReachability,
4282 public void writeGraph( String graphName,
4283 boolean writeLabels,
4284 boolean labelSelect,
4285 boolean pruneGarbage,
4286 boolean hideReachability,
4287 boolean hideSubsetReachability,
4288 boolean hidePredicates,
4289 boolean hideEdgeTaints,
4290 Set<Integer> callerNodeIDsCopiedToCallee
4294 // remove all non-word characters from the graph name so
4295 // the filename and identifier in dot don't cause errors
4296 graphName = graphName.replaceAll( "[\\W]", "" );
4299 new BufferedWriter( new FileWriter( graphName+".dot" ) );
4301 bw.write( "digraph "+graphName+" {\n" );
4304 // this is an optional step to form the callee-reachable
4305 // "cut-out" into a DOT cluster for visualization
4306 if( callerNodeIDsCopiedToCallee != null ) {
4308 bw.write( " subgraph cluster0 {\n" );
4309 bw.write( " color=blue;\n" );
4311 Iterator i = id2hrn.entrySet().iterator();
4312 while( i.hasNext() ) {
4313 Map.Entry me = (Map.Entry) i.next();
4314 HeapRegionNode hrn = (HeapRegionNode) me.getValue();
4316 if( callerNodeIDsCopiedToCallee.contains( hrn.getID() ) ) {
4319 hrn.toStringDOT( hideReachability,
4320 hideSubsetReachability,
4330 Set<HeapRegionNode> visited = new HashSet<HeapRegionNode>();
4332 // then visit every heap region node
4333 Iterator i = id2hrn.entrySet().iterator();
4334 while( i.hasNext() ) {
4335 Map.Entry me = (Map.Entry) i.next();
4336 HeapRegionNode hrn = (HeapRegionNode) me.getValue();
4338 // only visit nodes worth writing out--for instance
4339 // not every node at an allocation is referenced
4340 // (think of it as garbage-collected), etc.
4341 if( !pruneGarbage ||
4342 hrn.isOutOfContext() ||
4343 (hrn.isFlagged() && hrn.getID() > 0 && !hrn.isWiped()) // a non-shadow flagged node
4346 if( !visited.contains( hrn ) ) {
4347 traverseHeapRegionNodes( hrn,
4352 hideSubsetReachability,
4355 callerNodeIDsCopiedToCallee );
4360 bw.write( " graphTitle[label=\""+graphName+"\",shape=box];\n" );
4363 // then visit every label node, useful for debugging
4365 i = td2vn.entrySet().iterator();
4366 while( i.hasNext() ) {
4367 Map.Entry me = (Map.Entry) i.next();
4368 VariableNode vn = (VariableNode) me.getValue();
4371 String labelStr = vn.getTempDescriptorString();
4372 if( labelStr.startsWith( "___temp" ) ||
4373 labelStr.startsWith( "___dst" ) ||
4374 labelStr.startsWith( "___srctmp" ) ||
4375 labelStr.startsWith( "___neverused" )
4381 Iterator<RefEdge> heapRegionsItr = vn.iteratorToReferencees();
4382 while( heapRegionsItr.hasNext() ) {
4383 RefEdge edge = heapRegionsItr.next();
4384 HeapRegionNode hrn = edge.getDst();
4386 if( !visited.contains( hrn ) ) {
4387 traverseHeapRegionNodes( hrn,
4392 hideSubsetReachability,
4395 callerNodeIDsCopiedToCallee );
4398 bw.write( " "+vn.toString()+
4399 " -> "+hrn.toString()+
4400 edge.toStringDOT( hideReachability,
4401 hideSubsetReachability,
4413 } catch( IOException e ) {
4414 throw new Error( "Error writing out DOT graph "+graphName );
4419 traverseHeapRegionNodes( HeapRegionNode hrn,
4422 Set<HeapRegionNode> visited,
4423 boolean hideReachability,
4424 boolean hideSubsetReachability,
4425 boolean hidePredicates,
4426 boolean hideEdgeTaints,
4427 Set<Integer> callerNodeIDsCopiedToCallee
4428 ) throws java.io.IOException {
4430 if( visited.contains( hrn ) ) {
4435 // if we're drawing the callee-view subgraph, only
4436 // write out the node info if it hasn't already been
4438 if( callerNodeIDsCopiedToCallee == null ||
4439 !callerNodeIDsCopiedToCallee.contains( hrn.getID() )
4443 hrn.toStringDOT( hideReachability,
4444 hideSubsetReachability,
4449 Iterator<RefEdge> childRegionsItr = hrn.iteratorToReferencees();
4450 while( childRegionsItr.hasNext() ) {
4451 RefEdge edge = childRegionsItr.next();
4452 HeapRegionNode hrnChild = edge.getDst();
4454 if( callerNodeIDsCopiedToCallee != null &&
4455 (edge.getSrc() instanceof HeapRegionNode) ) {
4456 HeapRegionNode hrnSrc = (HeapRegionNode) edge.getSrc();
4457 if( callerNodeIDsCopiedToCallee.contains( hrnSrc.getID() ) &&
4458 callerNodeIDsCopiedToCallee.contains( edge.getDst().getID() )
4460 bw.write( " "+hrn.toString()+
4461 " -> "+hrnChild.toString()+
4462 edge.toStringDOT( hideReachability,
4463 hideSubsetReachability,
4468 } else if( !callerNodeIDsCopiedToCallee.contains( hrnSrc.getID() ) &&
4469 callerNodeIDsCopiedToCallee.contains( edge.getDst().getID() )
4471 bw.write( " "+hrn.toString()+
4472 " -> "+hrnChild.toString()+
4473 edge.toStringDOT( hideReachability,
4474 hideSubsetReachability,
4477 ",color=blue,style=dashed" )+
4480 bw.write( " "+hrn.toString()+
4481 " -> "+hrnChild.toString()+
4482 edge.toStringDOT( hideReachability,
4483 hideSubsetReachability,
4490 bw.write( " "+hrn.toString()+
4491 " -> "+hrnChild.toString()+
4492 edge.toStringDOT( hideReachability,
4493 hideSubsetReachability,
4500 traverseHeapRegionNodes( hrnChild,
4505 hideSubsetReachability,
4508 callerNodeIDsCopiedToCallee );
4516 public Set<HeapRegionNode> findCommonReachableNodes( ReachSet proofOfSharing ) {
4518 Set<HeapRegionNode> exhibitProofState =
4519 new HashSet<HeapRegionNode>();
4521 Iterator hrnItr = id2hrn.entrySet().iterator();
4522 while( hrnItr.hasNext() ) {
4523 Map.Entry me = (Map.Entry) hrnItr.next();
4524 HeapRegionNode hrn = (HeapRegionNode) me.getValue();
4526 ReachSet intersection =
4527 Canonical.intersection( proofOfSharing,
4530 if( !intersection.isEmpty() ) {
4531 assert !hrn.isOutOfContext();
4532 exhibitProofState.add( hrn );
4536 return exhibitProofState;
4540 public Set<HeapRegionNode> mayReachSharedObjects(HeapRegionNode hrn1,
4541 HeapRegionNode hrn2) {
4542 assert hrn1 != null;
4543 assert hrn2 != null;
4545 assert !hrn1.isOutOfContext();
4546 assert !hrn2.isOutOfContext();
4548 assert belongsToThis( hrn1 );
4549 assert belongsToThis( hrn2 );
4551 assert !hrn1.getID().equals( hrn2.getID() );
4554 // then get the various tokens for these heap regions
4556 ReachTuple.factory( hrn1.getID(),
4557 !hrn1.isSingleObject(), // multi?
4558 ReachTuple.ARITY_ONE,
4561 ReachTuple h1star = null;
4562 if( !hrn1.isSingleObject() ) {
4564 ReachTuple.factory( hrn1.getID(),
4565 !hrn1.isSingleObject(),
4566 ReachTuple.ARITY_ZEROORMORE,
4571 ReachTuple.factory( hrn2.getID(),
4572 !hrn2.isSingleObject(),
4573 ReachTuple.ARITY_ONE,
4576 ReachTuple h2star = null;
4577 if( !hrn2.isSingleObject() ) {
4579 ReachTuple.factory( hrn2.getID(),
4580 !hrn2.isSingleObject(),
4581 ReachTuple.ARITY_ZEROORMORE,
4585 // then get the merged beta of all out-going edges from these heap
4588 ReachSet beta1 = ReachSet.factory();
4589 Iterator<RefEdge> itrEdge = hrn1.iteratorToReferencees();
4590 while (itrEdge.hasNext()) {
4591 RefEdge edge = itrEdge.next();
4592 beta1 = Canonical.unionORpreds(beta1, edge.getBeta());
4595 ReachSet beta2 = ReachSet.factory();
4596 itrEdge = hrn2.iteratorToReferencees();
4597 while (itrEdge.hasNext()) {
4598 RefEdge edge = itrEdge.next();
4599 beta2 = Canonical.unionORpreds(beta2, edge.getBeta());
4602 ReachSet proofOfSharing = ReachSet.factory();
4605 Canonical.unionORpreds( proofOfSharing,
4606 beta1.getStatesWithBoth( h1, h2 )
4609 Canonical.unionORpreds( proofOfSharing,
4610 beta2.getStatesWithBoth( h1, h2 )
4613 if( !hrn1.isSingleObject() ) {
4615 Canonical.unionORpreds( proofOfSharing,
4616 beta1.getStatesWithBoth( h1star, h2 )
4619 Canonical.unionORpreds( proofOfSharing,
4620 beta2.getStatesWithBoth( h1star, h2 )
4624 if( !hrn2.isSingleObject() ) {
4626 Canonical.unionORpreds( proofOfSharing,
4627 beta1.getStatesWithBoth( h1, h2star )
4630 Canonical.unionORpreds( proofOfSharing,
4631 beta2.getStatesWithBoth( h1, h2star )
4635 if( !hrn1.isSingleObject() &&
4636 !hrn2.isSingleObject()
4639 Canonical.unionORpreds( proofOfSharing,
4640 beta1.getStatesWithBoth( h1star, h2star )
4643 Canonical.unionORpreds( proofOfSharing,
4644 beta2.getStatesWithBoth( h1star, h2star )
4648 Set<HeapRegionNode> common = new HashSet<HeapRegionNode>();
4649 if( !proofOfSharing.isEmpty() ) {
4650 common = findCommonReachableNodes( proofOfSharing );
4651 if( !DISABLE_STRONG_UPDATES &&
4652 !DISABLE_GLOBAL_SWEEP
4654 assert !common.isEmpty();
4661 // this version of the above method checks whether there is sharing
4662 // among the objects in a summary node
4663 public Set<HeapRegionNode> mayReachSharedObjects(HeapRegionNode hrn) {
4665 assert hrn.isNewSummary();
4666 assert !hrn.isOutOfContext();
4667 assert belongsToThis( hrn );
4670 ReachTuple.factory( hrn.getID(),
4672 ReachTuple.ARITY_ZEROORMORE,
4675 // then get the merged beta of all out-going edges from
4678 ReachSet beta = ReachSet.factory();
4679 Iterator<RefEdge> itrEdge = hrn.iteratorToReferencees();
4680 while (itrEdge.hasNext()) {
4681 RefEdge edge = itrEdge.next();
4682 beta = Canonical.unionORpreds(beta, edge.getBeta());
4685 ReachSet proofOfSharing = ReachSet.factory();
4688 Canonical.unionORpreds( proofOfSharing,
4689 beta.getStatesWithBoth( hstar, hstar )
4692 Set<HeapRegionNode> common = new HashSet<HeapRegionNode>();
4693 if( !proofOfSharing.isEmpty() ) {
4694 common = findCommonReachableNodes( proofOfSharing );
4695 if( !DISABLE_STRONG_UPDATES &&
4696 !DISABLE_GLOBAL_SWEEP
4698 assert !common.isEmpty();
4706 public Set<HeapRegionNode> mayReachSharedObjects(FlatMethod fm,
4707 Integer paramIndex1,
4708 Integer paramIndex2) {
4710 // get parameter's heap regions
4711 TempDescriptor paramTemp1 = fm.getParameter(paramIndex1.intValue());
4712 assert this.hasVariable( paramTemp1 );
4713 VariableNode paramVar1 = getVariableNodeFromTemp(paramTemp1);
4716 if( !(paramVar1.getNumReferencees() == 1) ) {
4717 System.out.println( "\n fm="+fm+"\n param="+paramTemp1 );
4718 writeGraph( "whatup" );
4722 assert paramVar1.getNumReferencees() == 1;
4723 RefEdge paramEdge1 = paramVar1.iteratorToReferencees().next();
4724 HeapRegionNode hrnParam1 = paramEdge1.getDst();
4726 TempDescriptor paramTemp2 = fm.getParameter(paramIndex2.intValue());
4727 assert this.hasVariable( paramTemp2 );
4728 VariableNode paramVar2 = getVariableNodeFromTemp(paramTemp2);
4730 if( !(paramVar2.getNumReferencees() == 1) ) {
4731 System.out.println( "\n fm="+fm+"\n param="+paramTemp2 );
4732 writeGraph( "whatup" );
4735 assert paramVar2.getNumReferencees() == 1;
4736 RefEdge paramEdge2 = paramVar2.iteratorToReferencees().next();
4737 HeapRegionNode hrnParam2 = paramEdge2.getDst();
4739 Set<HeapRegionNode> common = new HashSet<HeapRegionNode>();
4740 common.addAll(mayReachSharedObjects(hrnParam1, hrnParam2));
4745 public Set<HeapRegionNode> mayReachSharedObjects(FlatMethod fm,
4749 // get parameter's heap regions
4750 TempDescriptor paramTemp = fm.getParameter(paramIndex.intValue());
4751 assert this.hasVariable( paramTemp );
4752 VariableNode paramVar = getVariableNodeFromTemp(paramTemp);
4753 assert paramVar.getNumReferencees() == 1;
4754 RefEdge paramEdge = paramVar.iteratorToReferencees().next();
4755 HeapRegionNode hrnParam = paramEdge.getDst();
4758 HeapRegionNode hrnSummary=null;
4759 if(id2hrn.containsKey(as.getSummary())){
4760 // if summary node doesn't exist, ignore this case
4761 hrnSummary = id2hrn.get(as.getSummary());
4762 assert hrnSummary != null;
4765 Set<HeapRegionNode> common = new HashSet<HeapRegionNode>();
4766 if(hrnSummary!=null){
4767 common.addAll( mayReachSharedObjects(hrnParam, hrnSummary) );
4770 // check for other nodes
4771 for (int i = 0; i < as.getAllocationDepth(); ++i) {
4773 assert id2hrn.containsKey(as.getIthOldest(i));
4774 HeapRegionNode hrnIthOldest = id2hrn.get(as.getIthOldest(i));
4775 assert hrnIthOldest != null;
4777 common.addAll(mayReachSharedObjects(hrnParam, hrnIthOldest));
4784 public Set<HeapRegionNode> mayReachSharedObjects(AllocSite as1,
4787 // get summary node 1's alpha
4788 Integer idSum1 = as1.getSummary();
4789 HeapRegionNode hrnSum1=null;
4790 if(id2hrn.containsKey(idSum1)){
4791 hrnSum1 = id2hrn.get(idSum1);
4794 // get summary node 2's alpha
4795 Integer idSum2 = as2.getSummary();
4796 HeapRegionNode hrnSum2=null;
4797 if(id2hrn.containsKey(idSum2)){
4798 hrnSum2 = id2hrn.get(idSum2);
4801 Set<HeapRegionNode> common = new HashSet<HeapRegionNode>();
4802 if(hrnSum1!=null && hrnSum2!=null && hrnSum1!=hrnSum2){
4803 common.addAll(mayReachSharedObjects(hrnSum1, hrnSum2));
4807 // ask if objects from this summary share among each other
4808 common.addAll(mayReachSharedObjects(hrnSum1));
4811 // check sum2 against alloc1 nodes
4813 for (int i = 0; i < as1.getAllocationDepth(); ++i) {
4814 Integer idI1 = as1.getIthOldest(i);
4815 assert id2hrn.containsKey(idI1);
4816 HeapRegionNode hrnI1 = id2hrn.get(idI1);
4817 assert hrnI1 != null;
4818 common.addAll(mayReachSharedObjects(hrnI1, hrnSum2));
4821 // also ask if objects from this summary share among each other
4822 common.addAll(mayReachSharedObjects(hrnSum2));
4825 // check sum1 against alloc2 nodes
4826 for (int i = 0; i < as2.getAllocationDepth(); ++i) {
4827 Integer idI2 = as2.getIthOldest(i);
4828 assert id2hrn.containsKey(idI2);
4829 HeapRegionNode hrnI2 = id2hrn.get(idI2);
4830 assert hrnI2 != null;
4833 common.addAll(mayReachSharedObjects(hrnSum1, hrnI2));
4836 // while we're at it, do an inner loop for alloc2 vs alloc1 nodes
4837 for (int j = 0; j < as1.getAllocationDepth(); ++j) {
4838 Integer idI1 = as1.getIthOldest(j);
4840 // if these are the same site, don't look for the same token, no
4842 // different tokens of the same site could alias together though
4843 if (idI1.equals(idI2)) {
4847 HeapRegionNode hrnI1 = id2hrn.get(idI1);
4849 common.addAll(mayReachSharedObjects(hrnI1, hrnI2));
4856 public void addAccessibleVar(TempDescriptor td){
4857 accessibleVars.add(td);
4860 public Set<TempDescriptor> getAccessibleVar(){
4861 return accessibleVars;
4864 public void clearAccessibleVarSet(){
4865 accessibleVars.clear();