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 protected static final ExistPred predTrue = ExistPred.factory(); // if no args, true
25 protected static final ExistPredSet predsEmpty = ExistPredSet.factory();
26 protected 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;
43 id2hrn = new Hashtable<Integer, HeapRegionNode>();
44 td2vn = new Hashtable<TempDescriptor, VariableNode >();
45 allocSites = new HashSet<AllocSite>();
49 // temp descriptors are globally unique and map to
50 // exactly one variable node, easy
51 protected VariableNode getVariableNodeFromTemp( TempDescriptor td ) {
54 if( !td2vn.containsKey( td ) ) {
55 td2vn.put( td, new VariableNode( td ) );
58 return td2vn.get( td );
61 public boolean hasVariable( TempDescriptor td ) {
62 return td2vn.containsKey( td );
66 // this suite of methods can be used to assert a
67 // very important property of ReachGraph objects:
68 // some element, HeapRegionNode, RefEdge etc.
69 // should be referenced by at most ONE ReachGraph!!
70 // If a heap region or edge or variable should be
71 // in another graph, make a new object with
72 // equivalent properties for a new graph
73 public boolean belongsToThis( RefSrcNode rsn ) {
74 if( rsn instanceof VariableNode ) {
75 VariableNode vn = (VariableNode) rsn;
76 return this.td2vn.get( vn.getTempDescriptor() ) == vn;
78 HeapRegionNode hrn = (HeapRegionNode) rsn;
79 return this.id2hrn.get( hrn.getID() ) == hrn;
86 // the reason for this method is to have the option
87 // of creating new heap regions with specific IDs, or
88 // duplicating heap regions with specific IDs (especially
89 // in the merge() operation) or to create new heap
90 // regions with a new unique ID
91 protected HeapRegionNode
92 createNewHeapRegionNode( Integer id,
93 boolean isSingleObject,
95 boolean isOutOfContext,
104 TypeDescriptor typeToUse = null;
105 if( allocSite != null ) {
106 typeToUse = allocSite.getType();
107 allocSites.add( allocSite );
112 boolean markForAnalysis = false;
113 if( allocSite != null && allocSite.isFlagged() ) {
114 markForAnalysis = true;
117 if( allocSite == null ) {
118 assert !markForAnalysis;
120 } else if( markForAnalysis != allocSite.isFlagged() ) {
126 id = DisjointAnalysis.generateUniqueHeapRegionNodeID();
129 if( inherent == null ) {
130 if( markForAnalysis ) {
132 Canonical.makePredsTrue(
135 ReachTuple.factory( id,
137 ReachTuple.ARITY_ONE,
138 false // out-of-context
144 inherent = rsetWithEmptyState;
148 if( alpha == null ) {
152 assert preds != null;
154 HeapRegionNode hrn = new HeapRegionNode( id,
165 id2hrn.put( id, hrn );
171 ////////////////////////////////////////////////
173 // Low-level referencee and referencer methods
175 // These methods provide the lowest level for
176 // creating references between reachability nodes
177 // and handling the details of maintaining both
178 // list of referencers and referencees.
180 ////////////////////////////////////////////////
181 protected void addRefEdge( RefSrcNode referencer,
182 HeapRegionNode referencee,
184 assert referencer != null;
185 assert referencee != null;
187 assert edge.getSrc() == referencer;
188 assert edge.getDst() == referencee;
189 assert belongsToThis( referencer );
190 assert belongsToThis( referencee );
192 // edges are getting added twice to graphs now, the
193 // kind that should have abstract facts merged--use
194 // this check to prevent that
195 assert referencer.getReferenceTo( referencee,
200 referencer.addReferencee( edge );
201 referencee.addReferencer( edge );
204 protected void removeRefEdge( RefEdge e ) {
205 removeRefEdge( e.getSrc(),
211 protected void removeRefEdge( RefSrcNode referencer,
212 HeapRegionNode referencee,
215 assert referencer != null;
216 assert referencee != null;
218 RefEdge edge = referencer.getReferenceTo( referencee,
222 assert edge == referencee.getReferenceFrom( referencer,
226 referencer.removeReferencee( edge );
227 referencee.removeReferencer( edge );
231 // int oldTaint=edge.getTaintIdentifier();
232 // if(referencer instanceof HeapRegionNode){
233 // depropagateTaintIdentifier((HeapRegionNode)referencer,oldTaint,new HashSet<HeapRegionNode>());
239 protected void clearRefEdgesFrom( RefSrcNode referencer,
242 boolean removeAll ) {
243 assert referencer != null;
245 // get a copy of the set to iterate over, otherwise
246 // we will be trying to take apart the set as we
247 // are iterating over it, which won't work
248 Iterator<RefEdge> i = referencer.iteratorToReferenceesClone();
249 while( i.hasNext() ) {
250 RefEdge edge = i.next();
253 (edge.typeEquals( type ) && edge.fieldEquals( field ))
256 HeapRegionNode referencee = edge.getDst();
258 removeRefEdge( referencer,
266 protected void clearRefEdgesTo( HeapRegionNode referencee,
269 boolean removeAll ) {
270 assert referencee != null;
272 // get a copy of the set to iterate over, otherwise
273 // we will be trying to take apart the set as we
274 // are iterating over it, which won't work
275 Iterator<RefEdge> i = referencee.iteratorToReferencersClone();
276 while( i.hasNext() ) {
277 RefEdge edge = i.next();
280 (edge.typeEquals( type ) && edge.fieldEquals( field ))
283 RefSrcNode referencer = edge.getSrc();
285 removeRefEdge( referencer,
293 protected void clearNonVarRefEdgesTo( HeapRegionNode referencee ) {
294 assert referencee != null;
296 // get a copy of the set to iterate over, otherwise
297 // we will be trying to take apart the set as we
298 // are iterating over it, which won't work
299 Iterator<RefEdge> i = referencee.iteratorToReferencersClone();
300 while( i.hasNext() ) {
301 RefEdge edge = i.next();
302 RefSrcNode referencer = edge.getSrc();
303 if( !(referencer instanceof VariableNode) ) {
304 removeRefEdge( referencer,
312 // this is a common operation in many transfer functions: we want
313 // to add an edge, but if there is already such an edge we should
314 // merge the properties of the existing and the new edges
315 protected void addEdgeOrMergeWithExisting( RefEdge edgeNew ) {
317 RefSrcNode src = edgeNew.getSrc();
318 assert belongsToThis( src );
320 HeapRegionNode dst = edgeNew.getDst();
321 assert belongsToThis( dst );
323 // look to see if an edge with same field exists
324 // and merge with it, otherwise just add the edge
325 RefEdge edgeExisting = src.getReferenceTo( dst,
330 if( edgeExisting != null ) {
331 edgeExisting.setBeta(
332 Canonical.unionORpreds( edgeExisting.getBeta(),
336 edgeExisting.setPreds(
337 Canonical.join( edgeExisting.getPreds(),
343 addRefEdge( src, dst, edgeNew );
349 ////////////////////////////////////////////////////
351 // Assignment Operation Methods
353 // These methods are high-level operations for
354 // modeling program assignment statements using
355 // the low-level reference create/remove methods
358 ////////////////////////////////////////////////////
360 public void assignTempXEqualToTempY( TempDescriptor x,
362 assignTempXEqualToCastedTempY( x, y, null );
365 public void assignTempXEqualToCastedTempY( TempDescriptor x,
367 TypeDescriptor tdCast ) {
369 VariableNode lnX = getVariableNodeFromTemp( x );
370 VariableNode lnY = getVariableNodeFromTemp( y );
372 clearRefEdgesFrom( lnX, null, null, true );
374 // note it is possible that the types of temps in the
375 // flat node to analyze will reveal that some typed
376 // edges in the reachability graph are impossible
377 Set<RefEdge> impossibleEdges = new HashSet<RefEdge>();
379 Iterator<RefEdge> itrYhrn = lnY.iteratorToReferencees();
380 while( itrYhrn.hasNext() ) {
381 RefEdge edgeY = itrYhrn.next();
382 HeapRegionNode referencee = edgeY.getDst();
383 RefEdge edgeNew = edgeY.copy();
385 if( !isSuperiorType( x.getType(), edgeY.getType() ) ) {
386 impossibleEdges.add( edgeY );
390 edgeNew.setSrc( lnX );
392 if( tdCast == null ) {
393 edgeNew.setType( mostSpecificType( y.getType(),
399 edgeNew.setType( mostSpecificType( y.getType(),
401 referencee.getType(),
407 edgeNew.setField( null );
409 addRefEdge( lnX, referencee, edgeNew );
412 Iterator<RefEdge> itrImp = impossibleEdges.iterator();
413 while( itrImp.hasNext() ) {
414 RefEdge edgeImp = itrImp.next();
415 removeRefEdge( edgeImp );
420 public void assignTempXEqualToTempYFieldF( TempDescriptor x,
422 FieldDescriptor f ) {
423 VariableNode lnX = getVariableNodeFromTemp( x );
424 VariableNode lnY = getVariableNodeFromTemp( y );
426 clearRefEdgesFrom( lnX, null, null, true );
428 // note it is possible that the types of temps in the
429 // flat node to analyze will reveal that some typed
430 // edges in the reachability graph are impossible
431 Set<RefEdge> impossibleEdges = new HashSet<RefEdge>();
433 Iterator<RefEdge> itrYhrn = lnY.iteratorToReferencees();
434 while( itrYhrn.hasNext() ) {
435 RefEdge edgeY = itrYhrn.next();
436 HeapRegionNode hrnY = edgeY.getDst();
437 ReachSet betaY = edgeY.getBeta();
439 Iterator<RefEdge> itrHrnFhrn = hrnY.iteratorToReferencees();
440 while( itrHrnFhrn.hasNext() ) {
441 RefEdge edgeHrn = itrHrnFhrn.next();
442 HeapRegionNode hrnHrn = edgeHrn.getDst();
443 ReachSet betaHrn = edgeHrn.getBeta();
445 // prune edges that are not a matching field
446 if( edgeHrn.getType() != null &&
447 !edgeHrn.getField().equals( f.getSymbol() )
452 // check for impossible edges
453 if( !isSuperiorType( x.getType(), edgeHrn.getType() ) ) {
454 impossibleEdges.add( edgeHrn );
458 TypeDescriptor tdNewEdge =
459 mostSpecificType( edgeHrn.getType(),
463 RefEdge edgeNew = new RefEdge( lnX,
467 Canonical.intersection( betaY, betaHrn ),
473 addEdgeOrMergeWithExisting( edgeNew );
477 Iterator<RefEdge> itrImp = impossibleEdges.iterator();
478 while( itrImp.hasNext() ) {
479 RefEdge edgeImp = itrImp.next();
480 removeRefEdge( edgeImp );
483 // anytime you might remove edges between heap regions
484 // you must global sweep to clean up broken reachability
485 if( !impossibleEdges.isEmpty() ) {
486 if( !DISABLE_GLOBAL_SWEEP ) {
493 public void assignTempXFieldFEqualToTempY( TempDescriptor x,
497 VariableNode lnX = getVariableNodeFromTemp( x );
498 VariableNode lnY = getVariableNodeFromTemp( y );
500 HashSet<HeapRegionNode> nodesWithNewAlpha = new HashSet<HeapRegionNode>();
501 HashSet<RefEdge> edgesWithNewBeta = new HashSet<RefEdge>();
503 // note it is possible that the types of temps in the
504 // flat node to analyze will reveal that some typed
505 // edges in the reachability graph are impossible
506 Set<RefEdge> impossibleEdges = new HashSet<RefEdge>();
508 // first look for possible strong updates and remove those edges
509 boolean strongUpdate = false;
511 Iterator<RefEdge> itrXhrn = lnX.iteratorToReferencees();
512 while( itrXhrn.hasNext() ) {
513 RefEdge edgeX = itrXhrn.next();
514 HeapRegionNode hrnX = edgeX.getDst();
516 // we can do a strong update here if one of two cases holds
518 f != DisjointAnalysis.getArrayField( f.getType() ) &&
519 ( (hrnX.getNumReferencers() == 1) || // case 1
520 (hrnX.isSingleObject() && lnX.getNumReferencees() == 1) // case 2
523 if( !DISABLE_STRONG_UPDATES ) {
525 clearRefEdgesFrom( hrnX, f.getType(), f.getSymbol(), false );
530 // then do all token propagation
531 itrXhrn = lnX.iteratorToReferencees();
532 while( itrXhrn.hasNext() ) {
533 RefEdge edgeX = itrXhrn.next();
534 HeapRegionNode hrnX = edgeX.getDst();
535 ReachSet betaX = edgeX.getBeta();
536 ReachSet R = Canonical.intersection( hrnX.getAlpha(),
540 Iterator<RefEdge> itrYhrn = lnY.iteratorToReferencees();
541 while( itrYhrn.hasNext() ) {
542 RefEdge edgeY = itrYhrn.next();
543 HeapRegionNode hrnY = edgeY.getDst();
544 ReachSet O = edgeY.getBeta();
546 // check for impossible edges
547 if( !isSuperiorType( f.getType(), edgeY.getType() ) ) {
548 impossibleEdges.add( edgeY );
552 // propagate tokens over nodes starting from hrnSrc, and it will
553 // take care of propagating back up edges from any touched nodes
554 ChangeSet Cy = Canonical.unionUpArityToChangeSet( O, R );
555 propagateTokensOverNodes( hrnY, Cy, nodesWithNewAlpha, edgesWithNewBeta );
557 // then propagate back just up the edges from hrn
558 ChangeSet Cx = Canonical.unionUpArityToChangeSet( R, O );
559 HashSet<RefEdge> todoEdges = new HashSet<RefEdge>();
561 Hashtable<RefEdge, ChangeSet> edgePlannedChanges =
562 new Hashtable<RefEdge, ChangeSet>();
564 Iterator<RefEdge> referItr = hrnX.iteratorToReferencers();
565 while( referItr.hasNext() ) {
566 RefEdge edgeUpstream = referItr.next();
567 todoEdges.add( edgeUpstream );
568 edgePlannedChanges.put( edgeUpstream, Cx );
571 propagateTokensOverEdges( todoEdges,
578 // apply the updates to reachability
579 Iterator<HeapRegionNode> nodeItr = nodesWithNewAlpha.iterator();
580 while( nodeItr.hasNext() ) {
581 nodeItr.next().applyAlphaNew();
584 Iterator<RefEdge> edgeItr = edgesWithNewBeta.iterator();
585 while( edgeItr.hasNext() ) {
586 edgeItr.next().applyBetaNew();
590 // then go back through and add the new edges
591 itrXhrn = lnX.iteratorToReferencees();
592 while( itrXhrn.hasNext() ) {
593 RefEdge edgeX = itrXhrn.next();
594 HeapRegionNode hrnX = edgeX.getDst();
596 Iterator<RefEdge> itrYhrn = lnY.iteratorToReferencees();
597 while( itrYhrn.hasNext() ) {
598 RefEdge edgeY = itrYhrn.next();
599 HeapRegionNode hrnY = edgeY.getDst();
601 // skip impossible edges here, we already marked them
602 // when computing reachability propagations above
603 if( !isSuperiorType( f.getType(), edgeY.getType() ) ) {
607 // prepare the new reference edge hrnX.f -> hrnY
608 TypeDescriptor tdNewEdge =
609 mostSpecificType( y.getType(),
619 Canonical.makePredsTrue(
620 Canonical.pruneBy( edgeY.getBeta(),
629 addEdgeOrMergeWithExisting( edgeNew );
633 Iterator<RefEdge> itrImp = impossibleEdges.iterator();
634 while( itrImp.hasNext() ) {
635 RefEdge edgeImp = itrImp.next();
636 removeRefEdge( edgeImp );
639 // if there was a strong update, make sure to improve
640 // reachability with a global sweep
641 if( strongUpdate || !impossibleEdges.isEmpty() ) {
642 if( !DISABLE_GLOBAL_SWEEP ) {
649 public void assignReturnEqualToTemp( TempDescriptor x ) {
651 VariableNode lnR = getVariableNodeFromTemp( tdReturn );
652 VariableNode lnX = getVariableNodeFromTemp( x );
654 clearRefEdgesFrom( lnR, null, null, true );
656 Iterator<RefEdge> itrXhrn = lnX.iteratorToReferencees();
657 while( itrXhrn.hasNext() ) {
658 RefEdge edgeX = itrXhrn.next();
659 HeapRegionNode referencee = edgeX.getDst();
660 RefEdge edgeNew = edgeX.copy();
661 edgeNew.setSrc( lnR );
663 addRefEdge( lnR, referencee, edgeNew );
668 public void assignTempEqualToNewAlloc( TempDescriptor x,
675 // after the age operation the newest (or zero-ith oldest)
676 // node associated with the allocation site should have
677 // no references to it as if it were a newly allocated
679 Integer idNewest = as.getIthOldest( 0 );
680 HeapRegionNode hrnNewest = id2hrn.get( idNewest );
681 assert hrnNewest != null;
683 VariableNode lnX = getVariableNodeFromTemp( x );
684 clearRefEdgesFrom( lnX, null, null, true );
686 // make a new reference to allocated node
687 TypeDescriptor type = as.getType();
690 new RefEdge( lnX, // source
694 hrnNewest.getAlpha(), // beta
695 predsTrue, // predicates
699 addRefEdge( lnX, hrnNewest, edgeNew );
703 // use the allocation site (unique to entire analysis) to
704 // locate the heap region nodes in this reachability graph
705 // that should be aged. The process models the allocation
706 // of new objects and collects all the oldest allocations
707 // in a summary node to allow for a finite analysis
709 // There is an additional property of this method. After
710 // running it on a particular reachability graph (many graphs
711 // may have heap regions related to the same allocation site)
712 // the heap region node objects in this reachability graph will be
713 // allocated. Therefore, after aging a graph for an allocation
714 // site, attempts to retrieve the heap region nodes using the
715 // integer id's contained in the allocation site should always
716 // return non-null heap regions.
717 public void age( AllocSite as ) {
719 // keep track of allocation sites that are represented
720 // in this graph for efficiency with other operations
721 allocSites.add( as );
723 // if there is a k-th oldest node, it merges into
725 Integer idK = as.getOldest();
726 if( id2hrn.containsKey( idK ) ) {
727 HeapRegionNode hrnK = id2hrn.get( idK );
729 // retrieve the summary node, or make it
731 HeapRegionNode hrnSummary = getSummaryNode( as, false );
733 mergeIntoSummary( hrnK, hrnSummary );
736 // move down the line of heap region nodes
737 // clobbering the ith and transferring all references
738 // to and from i-1 to node i.
739 for( int i = allocationDepth - 1; i > 0; --i ) {
741 // only do the transfer if the i-1 node exists
742 Integer idImin1th = as.getIthOldest( i - 1 );
743 if( id2hrn.containsKey( idImin1th ) ) {
744 HeapRegionNode hrnImin1 = id2hrn.get( idImin1th );
745 if( hrnImin1.isWiped() ) {
746 // there is no info on this node, just skip
750 // either retrieve or make target of transfer
751 HeapRegionNode hrnI = getIthNode( as, i, false );
753 transferOnto( hrnImin1, hrnI );
758 // as stated above, the newest node should have had its
759 // references moved over to the second oldest, so we wipe newest
760 // in preparation for being the new object to assign something to
761 HeapRegionNode hrn0 = getIthNode( as, 0, false );
762 wipeOut( hrn0, true );
764 // now tokens in reachability sets need to "age" also
765 Iterator itrAllVariableNodes = td2vn.entrySet().iterator();
766 while( itrAllVariableNodes.hasNext() ) {
767 Map.Entry me = (Map.Entry) itrAllVariableNodes.next();
768 VariableNode ln = (VariableNode) me.getValue();
770 Iterator<RefEdge> itrEdges = ln.iteratorToReferencees();
771 while( itrEdges.hasNext() ) {
772 ageTuplesFrom( as, itrEdges.next() );
776 Iterator itrAllHRNodes = id2hrn.entrySet().iterator();
777 while( itrAllHRNodes.hasNext() ) {
778 Map.Entry me = (Map.Entry) itrAllHRNodes.next();
779 HeapRegionNode hrnToAge = (HeapRegionNode) me.getValue();
781 ageTuplesFrom( as, hrnToAge );
783 Iterator<RefEdge> itrEdges = hrnToAge.iteratorToReferencees();
784 while( itrEdges.hasNext() ) {
785 ageTuplesFrom( as, itrEdges.next() );
790 // after tokens have been aged, reset newest node's reachability
791 // and a brand new node has a "true" predicate
792 hrn0.setAlpha( hrn0.getInherent() );
793 hrn0.setPreds( predsTrue );
797 // either retrieve or create the needed heap region node
798 protected HeapRegionNode getSummaryNode( AllocSite as,
803 idSummary = as.getSummaryShadow();
805 idSummary = as.getSummary();
808 HeapRegionNode hrnSummary = id2hrn.get( idSummary );
810 if( hrnSummary == null ) {
812 String strDesc = as.toStringForDOT()+"\\nsummary";
815 createNewHeapRegionNode( idSummary, // id or null to generate a new one
816 false, // single object?
818 false, // out-of-context?
819 as.getType(), // type
820 as, // allocation site
821 null, // inherent reach
822 null, // current reach
823 predsEmpty, // predicates
824 strDesc // description
831 // either retrieve or create the needed heap region node
832 protected HeapRegionNode getIthNode( AllocSite as,
838 idIth = as.getIthOldestShadow( i );
840 idIth = as.getIthOldest( i );
843 HeapRegionNode hrnIth = id2hrn.get( idIth );
845 if( hrnIth == null ) {
847 String strDesc = as.toStringForDOT()+"\\n"+i+" oldest";
849 hrnIth = createNewHeapRegionNode( idIth, // id or null to generate a new one
850 true, // single object?
852 false, // out-of-context?
853 as.getType(), // type
854 as, // allocation site
855 null, // inherent reach
856 null, // current reach
857 predsEmpty, // predicates
858 strDesc // description
866 protected void mergeIntoSummary( HeapRegionNode hrn,
867 HeapRegionNode hrnSummary ) {
868 assert hrnSummary.isNewSummary();
870 // assert that these nodes belong to THIS graph
871 assert belongsToThis( hrn );
872 assert belongsToThis( hrnSummary );
874 assert hrn != hrnSummary;
876 // transfer references _from_ hrn over to hrnSummary
877 Iterator<RefEdge> itrReferencee = hrn.iteratorToReferencees();
878 while( itrReferencee.hasNext() ) {
879 RefEdge edge = itrReferencee.next();
880 RefEdge edgeMerged = edge.copy();
881 edgeMerged.setSrc( hrnSummary );
883 HeapRegionNode hrnReferencee = edge.getDst();
884 RefEdge edgeSummary =
885 hrnSummary.getReferenceTo( hrnReferencee,
890 if( edgeSummary == null ) {
891 // the merge is trivial, nothing to be done
892 addRefEdge( hrnSummary, hrnReferencee, edgeMerged );
895 // otherwise an edge from the referencer to hrnSummary exists already
896 // and the edge referencer->hrn should be merged with it
898 Canonical.unionORpreds( edgeMerged.getBeta(),
899 edgeSummary.getBeta()
902 edgeSummary.setPreds(
903 Canonical.join( edgeMerged.getPreds(),
904 edgeSummary.getPreds()
910 // next transfer references _to_ hrn over to hrnSummary
911 Iterator<RefEdge> itrReferencer = hrn.iteratorToReferencers();
912 while( itrReferencer.hasNext() ) {
913 RefEdge edge = itrReferencer.next();
914 RefEdge edgeMerged = edge.copy();
915 edgeMerged.setDst( hrnSummary );
917 RefSrcNode onReferencer = edge.getSrc();
918 RefEdge edgeSummary =
919 onReferencer.getReferenceTo( hrnSummary,
924 if( edgeSummary == null ) {
925 // the merge is trivial, nothing to be done
926 addRefEdge( onReferencer, hrnSummary, edgeMerged );
929 // otherwise an edge from the referencer to alpha_S exists already
930 // and the edge referencer->alpha_K should be merged with it
932 Canonical.unionORpreds( edgeMerged.getBeta(),
933 edgeSummary.getBeta()
936 edgeSummary.setPreds(
937 Canonical.join( edgeMerged.getPreds(),
938 edgeSummary.getPreds()
944 // then merge hrn reachability into hrnSummary
946 Canonical.unionORpreds( hrnSummary.getAlpha(),
952 Canonical.join( hrnSummary.getPreds(),
957 // and afterward, this node is gone
958 wipeOut( hrn, true );
962 protected void transferOnto( HeapRegionNode hrnA,
963 HeapRegionNode hrnB ) {
965 assert belongsToThis( hrnA );
966 assert belongsToThis( hrnB );
969 // clear references in and out of node b?
970 assert hrnB.isWiped();
972 // copy each: (edge in and out of A) to B
973 Iterator<RefEdge> itrReferencee = hrnA.iteratorToReferencees();
974 while( itrReferencee.hasNext() ) {
975 RefEdge edge = itrReferencee.next();
976 HeapRegionNode hrnReferencee = edge.getDst();
977 RefEdge edgeNew = edge.copy();
978 edgeNew.setSrc( hrnB );
979 edgeNew.setDst( hrnReferencee );
981 addRefEdge( hrnB, hrnReferencee, edgeNew );
984 Iterator<RefEdge> itrReferencer = hrnA.iteratorToReferencers();
985 while( itrReferencer.hasNext() ) {
986 RefEdge edge = itrReferencer.next();
987 RefSrcNode rsnReferencer = edge.getSrc();
988 RefEdge edgeNew = edge.copy();
989 edgeNew.setSrc( rsnReferencer );
990 edgeNew.setDst( hrnB );
992 addRefEdge( rsnReferencer, hrnB, edgeNew );
995 // replace hrnB reachability and preds with hrnA's
996 hrnB.setAlpha( hrnA.getAlpha() );
997 hrnB.setPreds( hrnA.getPreds() );
999 // after transfer, wipe out source
1000 wipeOut( hrnA, true );
1004 // the purpose of this method is to conceptually "wipe out"
1005 // a heap region from the graph--purposefully not called REMOVE
1006 // because the node is still hanging around in the graph, just
1007 // not mechanically connected or have any reach or predicate
1008 // information on it anymore--lots of ops can use this
1009 protected void wipeOut( HeapRegionNode hrn,
1010 boolean wipeVariableReferences ) {
1012 assert belongsToThis( hrn );
1014 clearRefEdgesFrom( hrn, null, null, true );
1016 if( wipeVariableReferences ) {
1017 clearRefEdgesTo( hrn, null, null, true );
1019 clearNonVarRefEdgesTo( hrn );
1022 hrn.setAlpha( rsetEmpty );
1023 hrn.setPreds( predsEmpty );
1027 protected void ageTuplesFrom( AllocSite as, RefEdge edge ) {
1029 Canonical.ageTuplesFrom( edge.getBeta(),
1035 protected void ageTuplesFrom( AllocSite as, HeapRegionNode hrn ) {
1037 Canonical.ageTuplesFrom( hrn.getAlpha(),
1045 protected void propagateTokensOverNodes( HeapRegionNode nPrime,
1047 HashSet<HeapRegionNode> nodesWithNewAlpha,
1048 HashSet<RefEdge> edgesWithNewBeta ) {
1050 HashSet<HeapRegionNode> todoNodes
1051 = new HashSet<HeapRegionNode>();
1052 todoNodes.add( nPrime );
1054 HashSet<RefEdge> todoEdges
1055 = new HashSet<RefEdge>();
1057 Hashtable<HeapRegionNode, ChangeSet> nodePlannedChanges
1058 = new Hashtable<HeapRegionNode, ChangeSet>();
1059 nodePlannedChanges.put( nPrime, c0 );
1061 Hashtable<RefEdge, ChangeSet> edgePlannedChanges
1062 = new Hashtable<RefEdge, ChangeSet>();
1064 // first propagate change sets everywhere they can go
1065 while( !todoNodes.isEmpty() ) {
1066 HeapRegionNode n = todoNodes.iterator().next();
1067 ChangeSet C = nodePlannedChanges.get( n );
1069 Iterator<RefEdge> referItr = n.iteratorToReferencers();
1070 while( referItr.hasNext() ) {
1071 RefEdge edge = referItr.next();
1072 todoEdges.add( edge );
1074 if( !edgePlannedChanges.containsKey( edge ) ) {
1075 edgePlannedChanges.put( edge,
1080 edgePlannedChanges.put( edge,
1081 Canonical.union( edgePlannedChanges.get( edge ),
1087 Iterator<RefEdge> refeeItr = n.iteratorToReferencees();
1088 while( refeeItr.hasNext() ) {
1089 RefEdge edgeF = refeeItr.next();
1090 HeapRegionNode m = edgeF.getDst();
1092 ChangeSet changesToPass = ChangeSet.factory();
1094 Iterator<ChangeTuple> itrCprime = C.iterator();
1095 while( itrCprime.hasNext() ) {
1096 ChangeTuple c = itrCprime.next();
1097 if( edgeF.getBeta().containsIgnorePreds( c.getStateToMatch() )
1100 changesToPass = Canonical.add( changesToPass, c );
1104 if( !changesToPass.isEmpty() ) {
1105 if( !nodePlannedChanges.containsKey( m ) ) {
1106 nodePlannedChanges.put( m, ChangeSet.factory() );
1109 ChangeSet currentChanges = nodePlannedChanges.get( m );
1111 if( !changesToPass.isSubset( currentChanges ) ) {
1113 nodePlannedChanges.put( m,
1114 Canonical.union( currentChanges,
1123 todoNodes.remove( n );
1126 // then apply all of the changes for each node at once
1127 Iterator itrMap = nodePlannedChanges.entrySet().iterator();
1128 while( itrMap.hasNext() ) {
1129 Map.Entry me = (Map.Entry) itrMap.next();
1130 HeapRegionNode n = (HeapRegionNode) me.getKey();
1131 ChangeSet C = (ChangeSet) me.getValue();
1133 // this propagation step is with respect to one change,
1134 // so we capture the full change from the old alpha:
1135 ReachSet localDelta = Canonical.applyChangeSet( n.getAlpha(),
1139 // but this propagation may be only one of many concurrent
1140 // possible changes, so keep a running union with the node's
1141 // partially updated new alpha set
1142 n.setAlphaNew( Canonical.unionORpreds( n.getAlphaNew(),
1147 nodesWithNewAlpha.add( n );
1150 propagateTokensOverEdges( todoEdges,
1157 protected void propagateTokensOverEdges( HashSet <RefEdge> todoEdges,
1158 Hashtable<RefEdge, ChangeSet> edgePlannedChanges,
1159 HashSet <RefEdge> edgesWithNewBeta ) {
1161 // first propagate all change tuples everywhere they can go
1162 while( !todoEdges.isEmpty() ) {
1163 RefEdge edgeE = todoEdges.iterator().next();
1164 todoEdges.remove( edgeE );
1166 if( !edgePlannedChanges.containsKey( edgeE ) ) {
1167 edgePlannedChanges.put( edgeE,
1172 ChangeSet C = edgePlannedChanges.get( edgeE );
1174 ChangeSet changesToPass = ChangeSet.factory();
1176 Iterator<ChangeTuple> itrC = C.iterator();
1177 while( itrC.hasNext() ) {
1178 ChangeTuple c = itrC.next();
1179 if( edgeE.getBeta().containsIgnorePreds( c.getStateToMatch() )
1182 changesToPass = Canonical.add( changesToPass, c );
1186 RefSrcNode rsn = edgeE.getSrc();
1188 if( !changesToPass.isEmpty() && rsn instanceof HeapRegionNode ) {
1189 HeapRegionNode n = (HeapRegionNode) rsn;
1191 Iterator<RefEdge> referItr = n.iteratorToReferencers();
1192 while( referItr.hasNext() ) {
1193 RefEdge edgeF = referItr.next();
1195 if( !edgePlannedChanges.containsKey( edgeF ) ) {
1196 edgePlannedChanges.put( edgeF,
1201 ChangeSet currentChanges = edgePlannedChanges.get( edgeF );
1203 if( !changesToPass.isSubset( currentChanges ) ) {
1204 todoEdges.add( edgeF );
1205 edgePlannedChanges.put( edgeF,
1206 Canonical.union( currentChanges,
1215 // then apply all of the changes for each edge at once
1216 Iterator itrMap = edgePlannedChanges.entrySet().iterator();
1217 while( itrMap.hasNext() ) {
1218 Map.Entry me = (Map.Entry) itrMap.next();
1219 RefEdge e = (RefEdge) me.getKey();
1220 ChangeSet C = (ChangeSet) me.getValue();
1222 // this propagation step is with respect to one change,
1223 // so we capture the full change from the old beta:
1224 ReachSet localDelta =
1225 Canonical.applyChangeSet( e.getBeta(),
1230 // but this propagation may be only one of many concurrent
1231 // possible changes, so keep a running union with the edge's
1232 // partially updated new beta set
1233 e.setBetaNew( Canonical.unionORpreds( e.getBetaNew(),
1238 edgesWithNewBeta.add( e );
1243 // used in makeCalleeView below to decide if there is
1244 // already an appropriate out-of-context edge in a callee
1245 // view graph for merging, or null if a new one will be added
1247 getOutOfContextReferenceTo( HeapRegionNode hrn,
1248 TypeDescriptor srcType,
1249 TypeDescriptor refType,
1251 assert belongsToThis( hrn );
1253 HeapRegionNode hrnInContext = id2hrn.get( hrn.getID() );
1254 if( hrnInContext == null ) {
1258 Iterator<RefEdge> refItr = hrnInContext.iteratorToReferencers();
1259 while( refItr.hasNext() ) {
1260 RefEdge re = refItr.next();
1262 assert belongsToThis( re.getSrc() );
1263 assert belongsToThis( re.getDst() );
1265 if( !(re.getSrc() instanceof HeapRegionNode) ) {
1269 HeapRegionNode hrnSrc = (HeapRegionNode) re.getSrc();
1270 if( !hrnSrc.isOutOfContext() ) {
1274 if( srcType == null ) {
1275 if( hrnSrc.getType() != null ) {
1279 if( !srcType.equals( hrnSrc.getType() ) ) {
1284 if( !re.typeEquals( refType ) ) {
1288 if( !re.fieldEquals( refField ) ) {
1292 // tada! We found it!
1299 // used below to convert a ReachSet to its callee-context
1300 // equivalent with respect to allocation sites in this graph
1301 protected ReachSet toCalleeContext( ReachSet rs,
1303 Set<HrnIdOoc> oocHrnIdOoc2callee
1305 ReachSet out = ReachSet.factory();
1307 Iterator<ReachState> itr = rs.iterator();
1308 while( itr.hasNext() ) {
1309 ReachState stateCaller = itr.next();
1311 ReachState stateCallee = stateCaller;
1313 Iterator<AllocSite> asItr = allocSites.iterator();
1314 while( asItr.hasNext() ) {
1315 AllocSite as = asItr.next();
1317 ReachState stateNew = ReachState.factory();
1318 Iterator<ReachTuple> rtItr = stateCallee.iterator();
1319 while( rtItr.hasNext() ) {
1320 ReachTuple rt = rtItr.next();
1322 // only translate this tuple if it is
1323 // in the out-callee-context bag
1324 HrnIdOoc hio = new HrnIdOoc( rt.getHrnID(),
1327 if( !oocHrnIdOoc2callee.contains( hio ) ) {
1328 stateNew = Canonical.add( stateNew, rt );
1332 int age = as.getAgeCategory( rt.getHrnID() );
1334 // this is the current mapping, where 0, 1, 2S were allocated
1335 // in the current context, 0?, 1? and 2S? were allocated in a
1336 // previous context, and we're translating to a future context
1348 if( age == AllocSite.AGE_notInThisSite ) {
1349 // things not from the site just go back in
1350 stateNew = Canonical.add( stateNew, rt );
1352 } else if( age == AllocSite.AGE_summary ||
1355 // the in-context summary and all existing out-of-context
1357 stateNew = Canonical.add( stateNew,
1358 ReachTuple.factory( as.getSummary(),
1361 true // out-of-context
1365 // otherwise everything else just goes to an out-of-context
1366 // version, everything else the same
1367 Integer I = as.getAge( rt.getHrnID() );
1370 assert !rt.isMultiObject();
1372 stateNew = Canonical.add( stateNew,
1373 ReachTuple.factory( rt.getHrnID(),
1376 true // out-of-context
1382 stateCallee = stateNew;
1385 // attach the passed in preds
1386 stateCallee = Canonical.attach( stateCallee,
1389 out = Canonical.add( out,
1394 assert out.isCanonical();
1398 // used below to convert a ReachSet to its caller-context
1399 // equivalent with respect to allocation sites in this graph
1401 toCallerContext( ReachSet rs,
1402 Hashtable<ReachState, ExistPredSet> calleeStatesSatisfied
1404 ReachSet out = ReachSet.factory();
1406 Iterator<ReachState> itr = rs.iterator();
1407 while( itr.hasNext() ) {
1408 ReachState stateCallee = itr.next();
1410 if( calleeStatesSatisfied.containsKey( stateCallee ) ) {
1412 // starting from one callee state...
1413 ReachSet rsCaller = ReachSet.factory( stateCallee );
1415 // possibly branch it into many states, which any
1416 // allocation site might do, so lots of derived states
1417 Iterator<AllocSite> asItr = allocSites.iterator();
1418 while( asItr.hasNext() ) {
1419 AllocSite as = asItr.next();
1420 rsCaller = Canonical.toCallerContext( rsCaller, as );
1423 // then before adding each derived, now caller-context
1424 // states to the output, attach the appropriate pred
1425 // based on the source callee state
1426 Iterator<ReachState> stateItr = rsCaller.iterator();
1427 while( stateItr.hasNext() ) {
1428 ReachState stateCaller = stateItr.next();
1429 stateCaller = Canonical.attach( stateCaller,
1430 calleeStatesSatisfied.get( stateCallee )
1432 out = Canonical.add( out,
1439 assert out.isCanonical();
1443 // used below to convert a ReachSet to an equivalent
1444 // version with shadow IDs merged into unshadowed IDs
1445 protected ReachSet unshadow( ReachSet rs ) {
1447 Iterator<AllocSite> asItr = allocSites.iterator();
1448 while( asItr.hasNext() ) {
1449 AllocSite as = asItr.next();
1450 out = Canonical.unshadow( out, as );
1452 assert out.isCanonical();
1457 // use this method to make a new reach graph that is
1458 // what heap the FlatMethod callee from the FlatCall
1459 // would start with reaching from its arguments in
1462 makeCalleeView( FlatCall fc,
1463 FlatMethod fmCallee,
1464 Set<Integer> callerNodeIDsCopiedToCallee,
1465 boolean writeDebugDOTs
1469 // first traverse this context to find nodes and edges
1470 // that will be callee-reachable
1471 Set<HeapRegionNode> reachableCallerNodes =
1472 new HashSet<HeapRegionNode>();
1474 // caller edges between callee-reachable nodes
1475 Set<RefEdge> reachableCallerEdges =
1476 new HashSet<RefEdge>();
1478 // caller edges from arg vars, and the matching param index
1479 // because these become a special edge in callee
1480 Hashtable<RefEdge, Integer> reachableCallerArgEdges2paramIndex =
1481 new Hashtable<RefEdge, Integer>();
1483 // caller edges from local vars or callee-unreachable nodes
1484 // (out-of-context sources) to callee-reachable nodes
1485 Set<RefEdge> oocCallerEdges =
1486 new HashSet<RefEdge>();
1489 for( int i = 0; i < fmCallee.numParameters(); ++i ) {
1491 TempDescriptor tdArg = fc.getArgMatchingParamIndex( fmCallee, i );
1492 VariableNode vnArgCaller = this.getVariableNodeFromTemp( tdArg );
1494 Set<RefSrcNode> toVisitInCaller = new HashSet<RefSrcNode>();
1495 Set<RefSrcNode> visitedInCaller = new HashSet<RefSrcNode>();
1497 toVisitInCaller.add( vnArgCaller );
1499 while( !toVisitInCaller.isEmpty() ) {
1500 RefSrcNode rsnCaller = toVisitInCaller.iterator().next();
1501 toVisitInCaller.remove( rsnCaller );
1502 visitedInCaller.add( rsnCaller );
1504 Iterator<RefEdge> itrRefEdges = rsnCaller.iteratorToReferencees();
1505 while( itrRefEdges.hasNext() ) {
1506 RefEdge reCaller = itrRefEdges.next();
1507 HeapRegionNode hrnCaller = reCaller.getDst();
1509 callerNodeIDsCopiedToCallee.add( hrnCaller.getID() );
1510 reachableCallerNodes.add( hrnCaller );
1512 if( reCaller.getSrc() instanceof HeapRegionNode ) {
1513 reachableCallerEdges.add( reCaller );
1515 if( rsnCaller.equals( vnArgCaller ) ) {
1516 reachableCallerArgEdges2paramIndex.put( reCaller, i );
1518 oocCallerEdges.add( reCaller );
1522 if( !visitedInCaller.contains( hrnCaller ) ) {
1523 toVisitInCaller.add( hrnCaller );
1526 } // end edge iteration
1527 } // end visiting heap nodes in caller
1528 } // end iterating over parameters as starting points
1531 // now collect out-of-callee-context IDs and
1532 // map them to whether the ID is out of the caller
1534 Set<HrnIdOoc> oocHrnIdOoc2callee = new HashSet<HrnIdOoc>();
1536 Iterator<Integer> itrInContext =
1537 callerNodeIDsCopiedToCallee.iterator();
1538 while( itrInContext.hasNext() ) {
1539 Integer hrnID = itrInContext.next();
1540 HeapRegionNode hrnCallerAndInContext = id2hrn.get( hrnID );
1542 Iterator<RefEdge> itrMightCross =
1543 hrnCallerAndInContext.iteratorToReferencers();
1544 while( itrMightCross.hasNext() ) {
1545 RefEdge edgeMightCross = itrMightCross.next();
1547 RefSrcNode rsnCallerAndOutContext =
1548 edgeMightCross.getSrc();
1550 if( rsnCallerAndOutContext instanceof VariableNode ) {
1551 // variables do not have out-of-context reach states,
1553 oocCallerEdges.add( edgeMightCross );
1557 HeapRegionNode hrnCallerAndOutContext =
1558 (HeapRegionNode) rsnCallerAndOutContext;
1560 // is this source node out-of-context?
1561 if( callerNodeIDsCopiedToCallee.contains( hrnCallerAndOutContext.getID() ) ) {
1562 // no, skip this edge
1567 oocCallerEdges.add( edgeMightCross );
1569 // add all reach tuples on the node to list
1570 // of things that are out-of-context: insight
1571 // if this node is reachable from someting that WAS
1572 // in-context, then this node should already be in-context
1573 Iterator<ReachState> stateItr = hrnCallerAndOutContext.getAlpha().iterator();
1574 while( stateItr.hasNext() ) {
1575 ReachState state = stateItr.next();
1577 Iterator<ReachTuple> rtItr = state.iterator();
1578 while( rtItr.hasNext() ) {
1579 ReachTuple rt = rtItr.next();
1581 oocHrnIdOoc2callee.add( new HrnIdOoc( rt.getHrnID(),
1590 // the callee view is a new graph: DON'T MODIFY *THIS* graph
1591 ReachGraph rg = new ReachGraph();
1593 // add nodes to callee graph
1594 Iterator<HeapRegionNode> hrnItr = reachableCallerNodes.iterator();
1595 while( hrnItr.hasNext() ) {
1596 HeapRegionNode hrnCaller = hrnItr.next();
1598 assert callerNodeIDsCopiedToCallee.contains( hrnCaller.getID() );
1599 assert !rg.id2hrn.containsKey( hrnCaller.getID() );
1601 ExistPred pred = ExistPred.factory( hrnCaller.getID(), null );
1602 ExistPredSet preds = ExistPredSet.factory( pred );
1604 rg.createNewHeapRegionNode( hrnCaller.getID(),
1605 hrnCaller.isSingleObject(),
1606 hrnCaller.isNewSummary(),
1607 false, // out-of-context?
1608 hrnCaller.getType(),
1609 hrnCaller.getAllocSite(),
1610 toCalleeContext( hrnCaller.getInherent(),
1614 toCalleeContext( hrnCaller.getAlpha(),
1619 hrnCaller.getDescription()
1623 // add param edges to callee graph
1625 reachableCallerArgEdges2paramIndex.entrySet().iterator();
1626 while( argEdges.hasNext() ) {
1627 Map.Entry me = (Map.Entry) argEdges.next();
1628 RefEdge reArg = (RefEdge) me.getKey();
1629 Integer index = (Integer) me.getValue();
1631 VariableNode vnCaller = (VariableNode) reArg.getSrc();
1632 TempDescriptor argCaller = vnCaller.getTempDescriptor();
1634 TempDescriptor paramCallee = fmCallee.getParameter( index );
1635 VariableNode vnCallee = rg.getVariableNodeFromTemp( paramCallee );
1637 HeapRegionNode hrnDstCaller = reArg.getDst();
1638 HeapRegionNode hrnDstCallee = rg.id2hrn.get( hrnDstCaller.getID() );
1639 assert hrnDstCallee != null;
1642 ExistPred.factory( argCaller,
1644 hrnDstCallee.getID(),
1648 true, // out-of-callee-context
1649 false // out-of-caller-context
1652 ExistPredSet preds =
1653 ExistPredSet.factory( pred );
1655 //Taint paramTaint =
1656 // Taint.factory( 0, null, null, );
1658 TaintSet paramTaints =
1659 //TaintSet.factory( paramTaint );
1663 new RefEdge( vnCallee,
1667 toCalleeContext( reArg.getBeta(),
1676 rg.addRefEdge( vnCallee,
1682 // add in-context edges to callee graph
1683 Iterator<RefEdge> reItr = reachableCallerEdges.iterator();
1684 while( reItr.hasNext() ) {
1685 RefEdge reCaller = reItr.next();
1686 RefSrcNode rsnCaller = reCaller.getSrc();
1687 assert rsnCaller instanceof HeapRegionNode;
1688 HeapRegionNode hrnSrcCaller = (HeapRegionNode) rsnCaller;
1689 HeapRegionNode hrnDstCaller = reCaller.getDst();
1691 HeapRegionNode hrnSrcCallee = rg.id2hrn.get( hrnSrcCaller.getID() );
1692 HeapRegionNode hrnDstCallee = rg.id2hrn.get( hrnDstCaller.getID() );
1693 assert hrnSrcCallee != null;
1694 assert hrnDstCallee != null;
1697 ExistPred.factory( null,
1698 hrnSrcCallee.getID(),
1699 hrnDstCallee.getID(),
1701 reCaller.getField(),
1703 false, // out-of-callee-context
1704 false // out-of-caller-context
1707 ExistPredSet preds =
1708 ExistPredSet.factory( pred );
1711 new RefEdge( hrnSrcCallee,
1714 reCaller.getField(),
1715 toCalleeContext( reCaller.getBeta(),
1723 rg.addRefEdge( hrnSrcCallee,
1729 // add out-of-context edges to callee graph
1730 reItr = oocCallerEdges.iterator();
1731 while( reItr.hasNext() ) {
1732 RefEdge reCaller = reItr.next();
1733 RefSrcNode rsnCaller = reCaller.getSrc();
1734 HeapRegionNode hrnDstCaller = reCaller.getDst();
1735 HeapRegionNode hrnDstCallee = rg.id2hrn.get( hrnDstCaller.getID() );
1736 assert hrnDstCallee != null;
1738 TypeDescriptor oocNodeType;
1740 TempDescriptor oocPredSrcTemp = null;
1741 Integer oocPredSrcID = null;
1742 boolean outOfCalleeContext;
1743 boolean outOfCallerContext;
1745 if( rsnCaller instanceof VariableNode ) {
1746 VariableNode vnCaller = (VariableNode) rsnCaller;
1748 oocReach = rsetEmpty;
1749 oocPredSrcTemp = vnCaller.getTempDescriptor();
1750 outOfCalleeContext = true;
1751 outOfCallerContext = false;
1754 HeapRegionNode hrnSrcCaller = (HeapRegionNode) rsnCaller;
1755 assert !callerNodeIDsCopiedToCallee.contains( hrnSrcCaller.getID() );
1756 oocNodeType = hrnSrcCaller.getType();
1757 oocReach = hrnSrcCaller.getAlpha();
1758 oocPredSrcID = hrnSrcCaller.getID();
1759 if( hrnSrcCaller.isOutOfContext() ) {
1760 outOfCalleeContext = false;
1761 outOfCallerContext = true;
1763 outOfCalleeContext = true;
1764 outOfCallerContext = false;
1769 ExistPred.factory( oocPredSrcTemp,
1771 hrnDstCallee.getID(),
1773 reCaller.getField(),
1779 ExistPredSet preds =
1780 ExistPredSet.factory( pred );
1782 RefEdge oocEdgeExisting =
1783 rg.getOutOfContextReferenceTo( hrnDstCallee,
1789 if( oocEdgeExisting == null ) {
1790 // for consistency, map one out-of-context "identifier"
1791 // to one heap region node id, otherwise no convergence
1792 String oocid = "oocid"+
1794 hrnDstCallee.getIDString()+
1797 reCaller.getField();
1799 Integer oocHrnID = oocid2hrnid.get( oocid );
1801 HeapRegionNode hrnCalleeAndOutContext;
1803 if( oocHrnID == null ) {
1805 hrnCalleeAndOutContext =
1806 rg.createNewHeapRegionNode( null, // ID
1807 false, // single object?
1808 false, // new summary?
1809 true, // out-of-context?
1811 null, // alloc site, shouldn't be used
1812 toCalleeContext( oocReach,
1816 toCalleeContext( oocReach,
1824 oocid2hrnid.put( oocid, hrnCalleeAndOutContext.getID() );
1828 // the mapping already exists, so see if node is there
1829 hrnCalleeAndOutContext = rg.id2hrn.get( oocHrnID );
1831 if( hrnCalleeAndOutContext == null ) {
1833 hrnCalleeAndOutContext =
1834 rg.createNewHeapRegionNode( oocHrnID, // ID
1835 false, // single object?
1836 false, // new summary?
1837 true, // out-of-context?
1839 null, // alloc site, shouldn't be used
1840 toCalleeContext( oocReach,
1844 toCalleeContext( oocReach,
1853 // otherwise it is there, so merge reachability
1854 hrnCalleeAndOutContext.setAlpha( Canonical.unionORpreds( hrnCalleeAndOutContext.getAlpha(),
1855 toCalleeContext( oocReach,
1864 assert hrnCalleeAndOutContext.reachHasOnlyOOC();
1866 rg.addRefEdge( hrnCalleeAndOutContext,
1868 new RefEdge( hrnCalleeAndOutContext,
1871 reCaller.getField(),
1872 toCalleeContext( reCaller.getBeta(),
1882 // the out-of-context edge already exists
1883 oocEdgeExisting.setBeta( Canonical.unionORpreds( oocEdgeExisting.getBeta(),
1884 toCalleeContext( reCaller.getBeta(),
1891 oocEdgeExisting.setPreds( Canonical.join( oocEdgeExisting.getPreds(),
1896 HeapRegionNode hrnCalleeAndOutContext =
1897 (HeapRegionNode) oocEdgeExisting.getSrc();
1898 hrnCalleeAndOutContext.setAlpha( Canonical.unionORpreds( hrnCalleeAndOutContext.getAlpha(),
1899 toCalleeContext( oocReach,
1906 assert hrnCalleeAndOutContext.reachHasOnlyOOC();
1911 if( writeDebugDOTs ) {
1912 debugGraphPrefix = String.format( "call%03d", debugCallSiteVisitCounter );
1913 rg.writeGraph( debugGraphPrefix+"calleeview",
1914 resolveMethodDebugDOTwriteLabels,
1915 resolveMethodDebugDOTselectTemps,
1916 resolveMethodDebugDOTpruneGarbage,
1917 resolveMethodDebugDOThideReach,
1918 resolveMethodDebugDOThideSubsetReach,
1919 resolveMethodDebugDOThidePreds,
1920 resolveMethodDebugDOThideEdgeTaints );
1926 private static Hashtable<String, Integer> oocid2hrnid =
1927 new Hashtable<String, Integer>();
1930 // useful since many graphs writes in the method call debug code
1931 private static boolean resolveMethodDebugDOTwriteLabels = true;
1932 private static boolean resolveMethodDebugDOTselectTemps = true;
1933 private static boolean resolveMethodDebugDOTpruneGarbage = true;
1934 private static boolean resolveMethodDebugDOThideReach = true;
1935 private static boolean resolveMethodDebugDOThideSubsetReach = true;
1936 private static boolean resolveMethodDebugDOThidePreds = true;
1937 private static boolean resolveMethodDebugDOThideEdgeTaints = true;
1939 static String debugGraphPrefix;
1940 static int debugCallSiteVisitCounter;
1941 static int debugCallSiteVisitStartCapture;
1942 static int debugCallSiteNumVisitsToCapture;
1943 static boolean debugCallSiteStopAfter;
1947 resolveMethodCall( FlatCall fc,
1948 FlatMethod fmCallee,
1949 ReachGraph rgCallee,
1950 Set<Integer> callerNodeIDsCopiedToCallee,
1951 boolean writeDebugDOTs
1954 if( writeDebugDOTs ) {
1955 System.out.println( " Writing out visit "+
1956 debugCallSiteVisitCounter+
1957 " to debug call site" );
1959 debugGraphPrefix = String.format( "call%03d",
1960 debugCallSiteVisitCounter );
1962 rgCallee.writeGraph( debugGraphPrefix+"callee",
1963 resolveMethodDebugDOTwriteLabels,
1964 resolveMethodDebugDOTselectTemps,
1965 resolveMethodDebugDOTpruneGarbage,
1966 resolveMethodDebugDOThideReach,
1967 resolveMethodDebugDOThideSubsetReach,
1968 resolveMethodDebugDOThidePreds,
1969 resolveMethodDebugDOThideEdgeTaints );
1971 writeGraph( debugGraphPrefix+"caller00In",
1972 resolveMethodDebugDOTwriteLabels,
1973 resolveMethodDebugDOTselectTemps,
1974 resolveMethodDebugDOTpruneGarbage,
1975 resolveMethodDebugDOThideReach,
1976 resolveMethodDebugDOThideSubsetReach,
1977 resolveMethodDebugDOThidePreds,
1978 resolveMethodDebugDOThideEdgeTaints,
1979 callerNodeIDsCopiedToCallee );
1984 // method call transfer function steps:
1985 // 1. Use current callee-reachable heap (CRH) to test callee
1986 // predicates and mark what will be coming in.
1987 // 2. Wipe CRH out of caller.
1988 // 3. Transplant marked callee parts in:
1989 // a) bring in nodes
1990 // b) bring in callee -> callee edges
1991 // c) resolve out-of-context -> callee edges
1992 // d) assign return value
1993 // 4. Collapse shadow nodes down
1994 // 5. Global sweep it.
1997 // 1. mark what callee elements have satisfied predicates
1998 Hashtable<HeapRegionNode, ExistPredSet> calleeNodesSatisfied =
1999 new Hashtable<HeapRegionNode, ExistPredSet>();
2001 Hashtable<RefEdge, ExistPredSet> calleeEdgesSatisfied =
2002 new Hashtable<RefEdge, ExistPredSet>();
2004 Hashtable<ReachState, ExistPredSet> calleeStatesSatisfied =
2005 new Hashtable<ReachState, ExistPredSet>();
2007 Hashtable< RefEdge, Set<RefSrcNode> > calleeEdges2oocCallerSrcMatches =
2008 new Hashtable< RefEdge, Set<RefSrcNode> >();
2010 Iterator meItr = rgCallee.id2hrn.entrySet().iterator();
2011 while( meItr.hasNext() ) {
2012 Map.Entry me = (Map.Entry) meItr.next();
2013 Integer id = (Integer) me.getKey();
2014 HeapRegionNode hrnCallee = (HeapRegionNode) me.getValue();
2016 // if a callee element's predicates are satisfied then a set
2017 // of CALLER predicates is returned: they are the predicates
2018 // that the callee element moved into the caller context
2019 // should have, and it is inefficient to find this again later
2020 ExistPredSet predsIfSatis =
2021 hrnCallee.getPreds().isSatisfiedBy( this,
2022 callerNodeIDsCopiedToCallee
2025 if( predsIfSatis != null ) {
2026 calleeNodesSatisfied.put( hrnCallee, predsIfSatis );
2028 // otherwise don't bother looking at edges to this node
2032 // since the node is coming over, find out which reach
2033 // states on it should come over, too
2034 Iterator<ReachState> stateItr = hrnCallee.getAlpha().iterator();
2035 while( stateItr.hasNext() ) {
2036 ReachState stateCallee = stateItr.next();
2039 stateCallee.getPreds().isSatisfiedBy( this,
2040 callerNodeIDsCopiedToCallee
2042 if( predsIfSatis != null ) {
2043 ExistPredSet predsAlready = calleeStatesSatisfied.get( stateCallee );
2044 if( predsAlready == null ) {
2045 calleeStatesSatisfied.put( stateCallee, predsIfSatis );
2047 calleeStatesSatisfied.put( stateCallee,
2048 Canonical.join( predsIfSatis,
2056 // then look at edges to the node
2057 Iterator<RefEdge> reItr = hrnCallee.iteratorToReferencers();
2058 while( reItr.hasNext() ) {
2059 RefEdge reCallee = reItr.next();
2060 RefSrcNode rsnCallee = reCallee.getSrc();
2062 // (caller local variables to in-context heap regions)
2063 // have an (out-of-context heap region -> in-context heap region)
2064 // abstraction in the callEE, so its true we never need to
2065 // look at a (var node -> heap region) edge in callee to bring
2066 // those over for the call site transfer, except for the special
2067 // case of *RETURN var* -> heap region edges.
2068 // What about (param var->heap region)
2069 // edges in callee? They are dealt with below this loop.
2071 if( rsnCallee instanceof VariableNode ) {
2073 // looking for the return-value variable only
2074 VariableNode vnCallee = (VariableNode) rsnCallee;
2075 if( vnCallee.getTempDescriptor() != tdReturn ) {
2079 TempDescriptor returnTemp = fc.getReturnTemp();
2080 if( returnTemp == null ||
2081 !DisjointAnalysis.shouldAnalysisTrack( returnTemp.getType() )
2086 // note that the assignment of the return value is to a
2087 // variable in the caller which is out-of-context with
2088 // respect to the callee
2089 VariableNode vnLhsCaller = getVariableNodeFromTemp( returnTemp );
2090 Set<RefSrcNode> rsnCallers = new HashSet<RefSrcNode>();
2091 rsnCallers.add( vnLhsCaller );
2092 calleeEdges2oocCallerSrcMatches.put( reCallee, rsnCallers );
2096 // for HeapRegionNode callee sources...
2098 // first see if the source is out-of-context, and only
2099 // proceed with this edge if we find some caller-context
2101 HeapRegionNode hrnSrcCallee = (HeapRegionNode) rsnCallee;
2102 boolean matchedOutOfContext = false;
2104 if( !hrnSrcCallee.isOutOfContext() ) {
2107 hrnSrcCallee.getPreds().isSatisfiedBy( this,
2108 callerNodeIDsCopiedToCallee
2110 if( predsIfSatis != null ) {
2111 calleeNodesSatisfied.put( hrnSrcCallee, predsIfSatis );
2113 // otherwise forget this edge
2118 // hrnSrcCallee is out-of-context
2120 assert !calleeEdges2oocCallerSrcMatches.containsKey( reCallee );
2122 Set<RefSrcNode> rsnCallers = new HashSet<RefSrcNode>();
2124 // is the target node in the caller?
2125 HeapRegionNode hrnDstCaller = this.id2hrn.get( hrnCallee.getID() );
2126 if( hrnDstCaller == null ) {
2130 Iterator<RefEdge> reDstItr = hrnDstCaller.iteratorToReferencers();
2131 while( reDstItr.hasNext() ) {
2132 // the edge and field (either possibly null) must match
2133 RefEdge reCaller = reDstItr.next();
2135 if( !reCaller.typeEquals ( reCallee.getType() ) ||
2136 !reCaller.fieldEquals( reCallee.getField() )
2141 RefSrcNode rsnCaller = reCaller.getSrc();
2142 if( rsnCaller instanceof VariableNode ) {
2144 // a variable node matches an OOC region with null type
2145 if( hrnSrcCallee.getType() != null ) {
2150 // otherwise types should match
2151 HeapRegionNode hrnCallerSrc = (HeapRegionNode) rsnCaller;
2152 if( hrnSrcCallee.getType() == null ) {
2153 if( hrnCallerSrc.getType() != null ) {
2157 if( !hrnSrcCallee.getType().equals( hrnCallerSrc.getType() ) ) {
2163 rsnCallers.add( rsnCaller );
2164 matchedOutOfContext = true;
2167 if( !rsnCallers.isEmpty() ) {
2168 calleeEdges2oocCallerSrcMatches.put( reCallee, rsnCallers );
2172 if( hrnSrcCallee.isOutOfContext() &&
2173 !matchedOutOfContext ) {
2180 reCallee.getPreds().isSatisfiedBy( this,
2181 callerNodeIDsCopiedToCallee
2184 if( predsIfSatis != null ) {
2185 calleeEdgesSatisfied.put( reCallee, predsIfSatis );
2187 // since the edge is coming over, find out which reach
2188 // states on it should come over, too
2189 stateItr = reCallee.getBeta().iterator();
2190 while( stateItr.hasNext() ) {
2191 ReachState stateCallee = stateItr.next();
2194 stateCallee.getPreds().isSatisfiedBy( this,
2195 callerNodeIDsCopiedToCallee
2197 if( predsIfSatis != null ) {
2198 ExistPredSet predsAlready = calleeStatesSatisfied.get( stateCallee );
2199 if( predsAlready == null ) {
2200 calleeStatesSatisfied.put( stateCallee, predsIfSatis );
2202 calleeStatesSatisfied.put( stateCallee,
2203 Canonical.join( predsIfSatis,
2214 if( writeDebugDOTs ) {
2215 writeGraph( debugGraphPrefix+"caller20BeforeWipe",
2216 resolveMethodDebugDOTwriteLabels,
2217 resolveMethodDebugDOTselectTemps,
2218 resolveMethodDebugDOTpruneGarbage,
2219 resolveMethodDebugDOThideReach,
2220 resolveMethodDebugDOThideSubsetReach,
2221 resolveMethodDebugDOThidePreds,
2222 resolveMethodDebugDOThideEdgeTaints );
2226 // 2. predicates tested, ok to wipe out caller part
2227 Iterator<Integer> hrnItr = callerNodeIDsCopiedToCallee.iterator();
2228 while( hrnItr.hasNext() ) {
2229 Integer hrnID = hrnItr.next();
2230 HeapRegionNode hrnCaller = id2hrn.get( hrnID );
2231 assert hrnCaller != null;
2233 // when clearing off nodes, also eliminate variable
2235 wipeOut( hrnCaller, true );
2238 // if we are assigning the return value to something, clobber now
2239 // as part of the wipe
2240 TempDescriptor returnTemp = fc.getReturnTemp();
2241 if( returnTemp != null &&
2242 DisjointAnalysis.shouldAnalysisTrack( returnTemp.getType() )
2245 VariableNode vnLhsCaller = getVariableNodeFromTemp( returnTemp );
2246 clearRefEdgesFrom( vnLhsCaller, null, null, true );
2252 if( writeDebugDOTs ) {
2253 writeGraph( debugGraphPrefix+"caller30BeforeAddingNodes",
2254 resolveMethodDebugDOTwriteLabels,
2255 resolveMethodDebugDOTselectTemps,
2256 resolveMethodDebugDOTpruneGarbage,
2257 resolveMethodDebugDOThideReach,
2258 resolveMethodDebugDOThideSubsetReach,
2259 resolveMethodDebugDOThidePreds,
2260 resolveMethodDebugDOThideEdgeTaints );
2266 // 3. callee elements with satisfied preds come in, note that
2267 // the mapping of elements satisfied to preds is like this:
2268 // A callee element EE has preds EEp that are satisfied by
2269 // some caller element ER. We bring EE into the caller
2270 // context as ERee with the preds of ER, namely ERp, which
2271 // in the following algorithm is the value in the mapping
2274 Iterator satisItr = calleeNodesSatisfied.entrySet().iterator();
2275 while( satisItr.hasNext() ) {
2276 Map.Entry me = (Map.Entry) satisItr.next();
2277 HeapRegionNode hrnCallee = (HeapRegionNode) me.getKey();
2278 ExistPredSet preds = (ExistPredSet) me.getValue();
2280 // TODO: I think its true that the current implementation uses
2281 // the type of the OOC region and the predicates OF THE EDGE from
2282 // it to link everything up in caller context, so that's why we're
2283 // skipping this... maybe that's a sillier way to do it?
2284 if( hrnCallee.isOutOfContext() ) {
2288 AllocSite as = hrnCallee.getAllocSite();
2289 allocSites.add( as );
2291 Integer hrnIDshadow = as.getShadowIDfromID( hrnCallee.getID() );
2293 HeapRegionNode hrnCaller = id2hrn.get( hrnIDshadow );
2294 if( hrnCaller == null ) {
2296 createNewHeapRegionNode( hrnIDshadow, // id or null to generate a new one
2297 hrnCallee.isSingleObject(), // single object?
2298 hrnCallee.isNewSummary(), // summary?
2299 false, // out-of-context?
2300 hrnCallee.getType(), // type
2301 hrnCallee.getAllocSite(), // allocation site
2302 toCallerContext( hrnCallee.getInherent(),
2303 calleeStatesSatisfied ), // inherent reach
2304 null, // current reach
2305 predsEmpty, // predicates
2306 hrnCallee.getDescription() // description
2309 assert hrnCaller.isWiped();
2312 hrnCaller.setAlpha( toCallerContext( hrnCallee.getAlpha(),
2313 calleeStatesSatisfied
2317 hrnCaller.setPreds( preds );
2324 if( writeDebugDOTs ) {
2325 writeGraph( debugGraphPrefix+"caller31BeforeAddingEdges",
2326 resolveMethodDebugDOTwriteLabels,
2327 resolveMethodDebugDOTselectTemps,
2328 resolveMethodDebugDOTpruneGarbage,
2329 resolveMethodDebugDOThideReach,
2330 resolveMethodDebugDOThideSubsetReach,
2331 resolveMethodDebugDOThidePreds,
2332 resolveMethodDebugDOThideEdgeTaints );
2336 // set these up during the next procedure so after
2337 // the caller has all of its nodes and edges put
2338 // back together we can propagate the callee's
2339 // reach changes backwards into the caller graph
2340 HashSet<RefEdge> edgesForPropagation = new HashSet<RefEdge>();
2342 Hashtable<RefEdge, ChangeSet> edgePlannedChanges =
2343 new Hashtable<RefEdge, ChangeSet>();
2346 // 3.b) callee -> callee edges AND out-of-context -> callee
2347 // which includes return temp -> callee edges now, too
2348 satisItr = calleeEdgesSatisfied.entrySet().iterator();
2349 while( satisItr.hasNext() ) {
2350 Map.Entry me = (Map.Entry) satisItr.next();
2351 RefEdge reCallee = (RefEdge) me.getKey();
2352 ExistPredSet preds = (ExistPredSet) me.getValue();
2354 HeapRegionNode hrnDstCallee = reCallee.getDst();
2355 AllocSite asDst = hrnDstCallee.getAllocSite();
2356 allocSites.add( asDst );
2358 Integer hrnIDDstShadow =
2359 asDst.getShadowIDfromID( hrnDstCallee.getID() );
2361 HeapRegionNode hrnDstCaller = id2hrn.get( hrnIDDstShadow );
2362 assert hrnDstCaller != null;
2365 RefSrcNode rsnCallee = reCallee.getSrc();
2367 Set<RefSrcNode> rsnCallers =
2368 new HashSet<RefSrcNode>();
2370 Set<RefSrcNode> oocCallers =
2371 calleeEdges2oocCallerSrcMatches.get( reCallee );
2373 if( rsnCallee instanceof HeapRegionNode ) {
2374 HeapRegionNode hrnCalleeSrc = (HeapRegionNode) rsnCallee;
2375 if( hrnCalleeSrc.isOutOfContext() ) {
2376 assert oocCallers != null;
2381 if( oocCallers == null ) {
2382 // there are no out-of-context matches, so it's
2383 // either a param/arg var or one in-context heap region
2384 if( rsnCallee instanceof VariableNode ) {
2385 // variable -> node in the callee should only
2386 // come into the caller if its from a param var
2387 VariableNode vnCallee = (VariableNode) rsnCallee;
2388 TempDescriptor tdParam = vnCallee.getTempDescriptor();
2389 TempDescriptor tdArg = fc.getArgMatchingParam( fmCallee,
2391 if( tdArg == null ) {
2392 // this means the variable isn't a parameter, its local
2393 // to the callee so we ignore it in call site transfer
2394 // shouldn't this NEVER HAPPEN?
2398 rsnCallers.add( this.getVariableNodeFromTemp( tdArg ) );
2401 // otherwise source is in context, one region
2403 HeapRegionNode hrnSrcCallee = (HeapRegionNode) rsnCallee;
2405 // translate an in-context node to shadow
2406 AllocSite asSrc = hrnSrcCallee.getAllocSite();
2407 allocSites.add( asSrc );
2409 Integer hrnIDSrcShadow =
2410 asSrc.getShadowIDfromID( hrnSrcCallee.getID() );
2412 HeapRegionNode hrnSrcCallerShadow =
2413 this.id2hrn.get( hrnIDSrcShadow );
2415 assert hrnSrcCallerShadow != null;
2417 rsnCallers.add( hrnSrcCallerShadow );
2421 // otherwise we have a set of out-of-context srcs
2422 // that should NOT be translated to shadow nodes
2423 assert !oocCallers.isEmpty();
2424 rsnCallers.addAll( oocCallers );
2427 // now make all caller edges we've identified from
2428 // this callee edge with a satisfied predicate
2429 assert !rsnCallers.isEmpty();
2430 Iterator<RefSrcNode> rsnItr = rsnCallers.iterator();
2431 while( rsnItr.hasNext() ) {
2432 RefSrcNode rsnCaller = rsnItr.next();
2434 RefEdge reCaller = new RefEdge( rsnCaller,
2437 reCallee.getField(),
2438 toCallerContext( reCallee.getBeta(),
2439 calleeStatesSatisfied ),
2444 ChangeSet cs = ChangeSet.factory();
2445 Iterator<ReachState> rsItr = reCaller.getBeta().iterator();
2446 while( rsItr.hasNext() ) {
2447 ReachState state = rsItr.next();
2448 ExistPredSet predsPreCallee = state.getPreds();
2450 if( state.isEmpty() ) {
2454 Iterator<ExistPred> predItr = predsPreCallee.iterator();
2455 while( predItr.hasNext() ) {
2456 ExistPred pred = predItr.next();
2457 ReachState old = pred.ne_state;
2463 cs = Canonical.add( cs,
2464 ChangeTuple.factory( old,
2472 // look to see if an edge with same field exists
2473 // and merge with it, otherwise just add the edge
2474 RefEdge edgeExisting = rsnCaller.getReferenceTo( hrnDstCaller,
2478 if( edgeExisting != null ) {
2479 edgeExisting.setBeta(
2480 Canonical.unionORpreds( edgeExisting.getBeta(),
2484 edgeExisting.setPreds(
2485 Canonical.join( edgeExisting.getPreds(),
2490 // for reach propagation
2491 if( !cs.isEmpty() ) {
2492 ChangeSet csExisting = edgePlannedChanges.get( edgeExisting );
2493 if( csExisting == null ) {
2494 csExisting = ChangeSet.factory();
2496 edgePlannedChanges.put( edgeExisting,
2497 Canonical.union( csExisting,
2504 addRefEdge( rsnCaller, hrnDstCaller, reCaller );
2506 // for reach propagation
2507 if( !cs.isEmpty() ) {
2508 edgesForPropagation.add( reCaller );
2509 assert !edgePlannedChanges.containsKey( reCaller );
2510 edgePlannedChanges.put( reCaller, cs );
2520 if( writeDebugDOTs ) {
2521 writeGraph( debugGraphPrefix+"caller38propagateReach",
2522 resolveMethodDebugDOTwriteLabels,
2523 resolveMethodDebugDOTselectTemps,
2524 resolveMethodDebugDOTpruneGarbage,
2525 resolveMethodDebugDOThideReach,
2526 resolveMethodDebugDOThideSubsetReach,
2527 resolveMethodDebugDOThidePreds,
2528 resolveMethodDebugDOThideEdgeTaints );
2531 // propagate callee reachability changes to the rest
2532 // of the caller graph edges
2533 HashSet<RefEdge> edgesUpdated = new HashSet<RefEdge>();
2535 propagateTokensOverEdges( edgesForPropagation, // source edges
2536 edgePlannedChanges, // map src edge to change set
2537 edgesUpdated ); // list of updated edges
2539 // commit beta' (beta<-betaNew)
2540 Iterator<RefEdge> edgeItr = edgesUpdated.iterator();
2541 while( edgeItr.hasNext() ) {
2542 edgeItr.next().applyBetaNew();
2551 if( writeDebugDOTs ) {
2552 writeGraph( debugGraphPrefix+"caller40BeforeShadowMerge",
2553 resolveMethodDebugDOTwriteLabels,
2554 resolveMethodDebugDOTselectTemps,
2555 resolveMethodDebugDOTpruneGarbage,
2556 resolveMethodDebugDOThideReach,
2557 resolveMethodDebugDOThideSubsetReach,
2558 resolveMethodDebugDOThidePreds,
2559 resolveMethodDebugDOThideEdgeTaints );
2563 // 4) merge shadow nodes so alloc sites are back to k
2564 Iterator<AllocSite> asItr = rgCallee.allocSites.iterator();
2565 while( asItr.hasNext() ) {
2566 // for each allocation site do the following to merge
2567 // shadow nodes (newest from callee) with any existing
2568 // look for the newest normal and newest shadow "slot"
2569 // not being used, transfer normal to shadow. Keep
2570 // doing this until there are no more normal nodes, or
2571 // no empty shadow slots: then merge all remaining normal
2572 // nodes into the shadow summary. Finally, convert all
2573 // shadow to their normal versions.
2574 AllocSite as = asItr.next();
2577 while( ageNorm < allocationDepth &&
2578 ageShad < allocationDepth ) {
2580 // first, are there any normal nodes left?
2581 Integer idNorm = as.getIthOldest( ageNorm );
2582 HeapRegionNode hrnNorm = id2hrn.get( idNorm );
2583 if( hrnNorm == null ) {
2584 // no, this age of normal node not in the caller graph
2589 // yes, a normal node exists, is there an empty shadow
2590 // "slot" to transfer it onto?
2591 HeapRegionNode hrnShad = getIthNode( as, ageShad, true );
2592 if( !hrnShad.isWiped() ) {
2593 // no, this age of shadow node is not empty
2598 // yes, this shadow node is empty
2599 transferOnto( hrnNorm, hrnShad );
2604 // now, while there are still normal nodes but no shadow
2605 // slots, merge normal nodes into the shadow summary
2606 while( ageNorm < allocationDepth ) {
2608 // first, are there any normal nodes left?
2609 Integer idNorm = as.getIthOldest( ageNorm );
2610 HeapRegionNode hrnNorm = id2hrn.get( idNorm );
2611 if( hrnNorm == null ) {
2612 // no, this age of normal node not in the caller graph
2617 // yes, a normal node exists, so get the shadow summary
2618 HeapRegionNode summShad = getSummaryNode( as, true );
2619 mergeIntoSummary( hrnNorm, summShad );
2623 // if there is a normal summary, merge it into shadow summary
2624 Integer idNorm = as.getSummary();
2625 HeapRegionNode summNorm = id2hrn.get( idNorm );
2626 if( summNorm != null ) {
2627 HeapRegionNode summShad = getSummaryNode( as, true );
2628 mergeIntoSummary( summNorm, summShad );
2631 // finally, flip all existing shadow nodes onto the normal
2632 for( int i = 0; i < allocationDepth; ++i ) {
2633 Integer idShad = as.getIthOldestShadow( i );
2634 HeapRegionNode hrnShad = id2hrn.get( idShad );
2635 if( hrnShad != null ) {
2637 HeapRegionNode hrnNorm = getIthNode( as, i, false );
2638 assert hrnNorm.isWiped();
2639 transferOnto( hrnShad, hrnNorm );
2643 Integer idShad = as.getSummaryShadow();
2644 HeapRegionNode summShad = id2hrn.get( idShad );
2645 if( summShad != null ) {
2646 summNorm = getSummaryNode( as, false );
2647 transferOnto( summShad, summNorm );
2656 if( writeDebugDOTs ) {
2657 writeGraph( debugGraphPrefix+"caller45BeforeUnshadow",
2658 resolveMethodDebugDOTwriteLabels,
2659 resolveMethodDebugDOTselectTemps,
2660 resolveMethodDebugDOTpruneGarbage,
2661 resolveMethodDebugDOThideReach,
2662 resolveMethodDebugDOThideSubsetReach,
2663 resolveMethodDebugDOThidePreds,
2664 resolveMethodDebugDOThideEdgeTaints );
2668 Iterator itrAllHRNodes = id2hrn.entrySet().iterator();
2669 while( itrAllHRNodes.hasNext() ) {
2670 Map.Entry me = (Map.Entry) itrAllHRNodes.next();
2671 HeapRegionNode hrn = (HeapRegionNode) me.getValue();
2673 hrn.setAlpha( unshadow( hrn.getAlpha() ) );
2675 Iterator<RefEdge> itrEdges = hrn.iteratorToReferencers();
2676 while( itrEdges.hasNext() ) {
2677 RefEdge re = itrEdges.next();
2678 re.setBeta( unshadow( re.getBeta() ) );
2685 if( writeDebugDOTs ) {
2686 writeGraph( debugGraphPrefix+"caller50BeforeGlobalSweep",
2687 resolveMethodDebugDOTwriteLabels,
2688 resolveMethodDebugDOTselectTemps,
2689 resolveMethodDebugDOTpruneGarbage,
2690 resolveMethodDebugDOThideReach,
2691 resolveMethodDebugDOThideSubsetReach,
2692 resolveMethodDebugDOThidePreds,
2693 resolveMethodDebugDOThideEdgeTaints );
2698 if( !DISABLE_GLOBAL_SWEEP ) {
2703 if( writeDebugDOTs ) {
2704 writeGraph( debugGraphPrefix+"caller90AfterTransfer",
2705 resolveMethodDebugDOTwriteLabels,
2706 resolveMethodDebugDOTselectTemps,
2707 resolveMethodDebugDOTpruneGarbage,
2708 resolveMethodDebugDOThideReach,
2709 resolveMethodDebugDOThideSubsetReach,
2710 resolveMethodDebugDOThidePreds,
2711 resolveMethodDebugDOThideEdgeTaints );
2717 ////////////////////////////////////////////////////
2719 // Abstract garbage collection simply removes
2720 // heap region nodes that are not mechanically
2721 // reachable from a root set. This step is
2722 // essential for testing node and edge existence
2723 // predicates efficiently
2725 ////////////////////////////////////////////////////
2726 public void abstractGarbageCollect( Set<TempDescriptor> liveSet ) {
2728 // calculate a root set, will be different for Java
2729 // version of analysis versus Bamboo version
2730 Set<RefSrcNode> toVisit = new HashSet<RefSrcNode>();
2732 // visit every variable in graph while building root
2733 // set, and do iterating on a copy, so we can remove
2734 // dead variables while we're at this
2735 Iterator makeCopyItr = td2vn.entrySet().iterator();
2736 Set entrysCopy = new HashSet();
2737 while( makeCopyItr.hasNext() ) {
2738 entrysCopy.add( makeCopyItr.next() );
2741 Iterator eItr = entrysCopy.iterator();
2742 while( eItr.hasNext() ) {
2743 Map.Entry me = (Map.Entry) eItr.next();
2744 TempDescriptor td = (TempDescriptor) me.getKey();
2745 VariableNode vn = (VariableNode) me.getValue();
2747 if( liveSet.contains( td ) ) {
2751 // dead var, remove completely from graph
2753 clearRefEdgesFrom( vn, null, null, true );
2757 // everything visited in a traversal is
2758 // considered abstractly live
2759 Set<RefSrcNode> visited = new HashSet<RefSrcNode>();
2761 while( !toVisit.isEmpty() ) {
2762 RefSrcNode rsn = toVisit.iterator().next();
2763 toVisit.remove( rsn );
2766 Iterator<RefEdge> hrnItr = rsn.iteratorToReferencees();
2767 while( hrnItr.hasNext() ) {
2768 RefEdge edge = hrnItr.next();
2769 HeapRegionNode hrn = edge.getDst();
2771 if( !visited.contains( hrn ) ) {
2777 // get a copy of the set to iterate over because
2778 // we're going to monkey with the graph when we
2779 // identify a garbage node
2780 Set<HeapRegionNode> hrnAllPrior = new HashSet<HeapRegionNode>();
2781 Iterator<HeapRegionNode> hrnItr = id2hrn.values().iterator();
2782 while( hrnItr.hasNext() ) {
2783 hrnAllPrior.add( hrnItr.next() );
2786 Iterator<HeapRegionNode> hrnAllItr = hrnAllPrior.iterator();
2787 while( hrnAllItr.hasNext() ) {
2788 HeapRegionNode hrn = hrnAllItr.next();
2790 if( !visited.contains( hrn ) ) {
2792 // heap region nodes are compared across ReachGraph
2793 // objects by their integer ID, so when discarding
2794 // garbage nodes we must also discard entries in
2795 // the ID -> heap region hashtable.
2796 id2hrn.remove( hrn.getID() );
2798 // RefEdge objects are two-way linked between
2799 // nodes, so when a node is identified as garbage,
2800 // actively clear references to and from it so
2801 // live nodes won't have dangling RefEdge's
2802 wipeOut( hrn, true );
2804 // if we just removed the last node from an allocation
2805 // site, it should be taken out of the ReachGraph's list
2806 AllocSite as = hrn.getAllocSite();
2807 if( !hasNodesOf( as ) ) {
2808 allocSites.remove( as );
2814 protected boolean hasNodesOf( AllocSite as ) {
2815 if( id2hrn.containsKey( as.getSummary() ) ) {
2819 for( int i = 0; i < allocationDepth; ++i ) {
2820 if( id2hrn.containsKey( as.getIthOldest( i ) ) ) {
2828 ////////////////////////////////////////////////////
2830 // This global sweep is an optional step to prune
2831 // reachability sets that are not internally
2832 // consistent with the global graph. It should be
2833 // invoked after strong updates or method calls.
2835 ////////////////////////////////////////////////////
2836 public void globalSweep() {
2838 // boldB is part of the phase 1 sweep
2839 // it has an in-context table and an out-of-context table
2840 Hashtable< Integer, Hashtable<RefEdge, ReachSet> > boldBic =
2841 new Hashtable< Integer, Hashtable<RefEdge, ReachSet> >();
2843 Hashtable< Integer, Hashtable<RefEdge, ReachSet> > boldBooc =
2844 new Hashtable< Integer, Hashtable<RefEdge, ReachSet> >();
2846 // visit every heap region to initialize alphaNew and betaNew,
2847 // and make a map of every hrnID to the source nodes it should
2848 // propagate forward from. In-context flagged hrnID's propagate
2849 // from only the in-context node they name, but out-of-context
2850 // ID's may propagate from several out-of-context nodes
2851 Hashtable< Integer, Set<HeapRegionNode> > icID2srcs =
2852 new Hashtable< Integer, Set<HeapRegionNode> >();
2854 Hashtable< Integer, Set<HeapRegionNode> > oocID2srcs =
2855 new Hashtable< Integer, Set<HeapRegionNode> >();
2858 Iterator itrHrns = id2hrn.entrySet().iterator();
2859 while( itrHrns.hasNext() ) {
2860 Map.Entry me = (Map.Entry) itrHrns.next();
2861 Integer hrnID = (Integer) me.getKey();
2862 HeapRegionNode hrn = (HeapRegionNode) me.getValue();
2864 // assert that this node and incoming edges have clean alphaNew
2865 // and betaNew sets, respectively
2866 assert rsetEmpty.equals( hrn.getAlphaNew() );
2868 Iterator<RefEdge> itrRers = hrn.iteratorToReferencers();
2869 while( itrRers.hasNext() ) {
2870 RefEdge edge = itrRers.next();
2871 assert rsetEmpty.equals( edge.getBetaNew() );
2874 // make a mapping of IDs to heap regions they propagate from
2875 if( hrn.isFlagged() ) {
2876 assert !hrn.isOutOfContext();
2877 assert !icID2srcs.containsKey( hrn.getID() );
2879 // in-context flagged node IDs simply propagate from the
2881 Set<HeapRegionNode> srcs = new HashSet<HeapRegionNode>();
2883 icID2srcs.put( hrn.getID(), srcs );
2886 if( hrn.isOutOfContext() ) {
2887 assert !hrn.isFlagged();
2889 // the reachability states on an out-of-context
2890 // node are not really important (combinations of
2891 // IDs or arity)--what matters is that the states
2892 // specify which nodes this out-of-context node
2893 // stands in for. For example, if the state [17?, 19*]
2894 // appears on the ooc node, it may serve as a source
2895 // for node 17? and a source for node 19.
2896 Iterator<ReachState> stateItr = hrn.getAlpha().iterator();
2897 while( stateItr.hasNext() ) {
2898 ReachState state = stateItr.next();
2900 Iterator<ReachTuple> rtItr = state.iterator();
2901 while( rtItr.hasNext() ) {
2902 ReachTuple rt = rtItr.next();
2903 assert rt.isOutOfContext();
2905 Set<HeapRegionNode> srcs = oocID2srcs.get( rt.getHrnID() );
2906 if( srcs == null ) {
2907 srcs = new HashSet<HeapRegionNode>();
2910 oocID2srcs.put( rt.getHrnID(), srcs );
2916 // calculate boldB for all hrnIDs identified by the above
2917 // node traversal, propagating from every source
2918 while( !icID2srcs.isEmpty() || !oocID2srcs.isEmpty() ) {
2921 Set<HeapRegionNode> srcs;
2924 if( !icID2srcs.isEmpty() ) {
2925 Map.Entry me = (Map.Entry) icID2srcs.entrySet().iterator().next();
2926 hrnID = (Integer) me.getKey();
2927 srcs = (Set<HeapRegionNode>) me.getValue();
2929 icID2srcs.remove( hrnID );
2932 assert !oocID2srcs.isEmpty();
2934 Map.Entry me = (Map.Entry) oocID2srcs.entrySet().iterator().next();
2935 hrnID = (Integer) me.getKey();
2936 srcs = (Set<HeapRegionNode>) me.getValue();
2938 oocID2srcs.remove( hrnID );
2942 Hashtable<RefEdge, ReachSet> boldB_f =
2943 new Hashtable<RefEdge, ReachSet>();
2945 Set<RefEdge> workSetEdges = new HashSet<RefEdge>();
2947 Iterator<HeapRegionNode> hrnItr = srcs.iterator();
2948 while( hrnItr.hasNext() ) {
2949 HeapRegionNode hrn = hrnItr.next();
2951 assert workSetEdges.isEmpty();
2953 // initial boldB_f constraints
2954 Iterator<RefEdge> itrRees = hrn.iteratorToReferencees();
2955 while( itrRees.hasNext() ) {
2956 RefEdge edge = itrRees.next();
2958 assert !boldB_f.containsKey( edge );
2959 boldB_f.put( edge, edge.getBeta() );
2961 assert !workSetEdges.contains( edge );
2962 workSetEdges.add( edge );
2965 // enforce the boldB_f constraint at edges until we reach a fixed point
2966 while( !workSetEdges.isEmpty() ) {
2967 RefEdge edge = workSetEdges.iterator().next();
2968 workSetEdges.remove( edge );
2970 Iterator<RefEdge> itrPrime = edge.getDst().iteratorToReferencees();
2971 while( itrPrime.hasNext() ) {
2972 RefEdge edgePrime = itrPrime.next();
2974 ReachSet prevResult = boldB_f.get( edgePrime );
2975 ReachSet intersection = Canonical.intersection( boldB_f.get( edge ),
2979 if( prevResult == null ||
2980 Canonical.unionORpreds( prevResult,
2981 intersection ).size()
2985 if( prevResult == null ) {
2986 boldB_f.put( edgePrime,
2987 Canonical.unionORpreds( edgePrime.getBeta(),
2992 boldB_f.put( edgePrime,
2993 Canonical.unionORpreds( prevResult,
2998 workSetEdges.add( edgePrime );
3005 boldBic.put( hrnID, boldB_f );
3007 boldBooc.put( hrnID, boldB_f );
3012 // use boldB to prune hrnIDs from alpha states that are impossible
3013 // and propagate the differences backwards across edges
3014 HashSet<RefEdge> edgesForPropagation = new HashSet<RefEdge>();
3016 Hashtable<RefEdge, ChangeSet> edgePlannedChanges =
3017 new Hashtable<RefEdge, ChangeSet>();
3020 itrHrns = id2hrn.entrySet().iterator();
3021 while( itrHrns.hasNext() ) {
3022 Map.Entry me = (Map.Entry) itrHrns.next();
3023 Integer hrnID = (Integer) me.getKey();
3024 HeapRegionNode hrn = (HeapRegionNode) me.getValue();
3026 // out-of-context nodes don't participate in the
3027 // global sweep, they serve as sources for the pass
3029 if( hrn.isOutOfContext() ) {
3033 // the inherent states of a region are the exception
3034 // to removal as the global sweep prunes
3035 ReachTuple rtException = ReachTuple.factory( hrnID,
3036 !hrn.isSingleObject(),
3037 ReachTuple.ARITY_ONE,
3038 false // out-of-context
3041 ChangeSet cts = ChangeSet.factory();
3043 // mark hrnIDs for removal
3044 Iterator<ReachState> stateItr = hrn.getAlpha().iterator();
3045 while( stateItr.hasNext() ) {
3046 ReachState stateOld = stateItr.next();
3048 ReachState markedHrnIDs = ReachState.factory();
3050 Iterator<ReachTuple> rtItr = stateOld.iterator();
3051 while( rtItr.hasNext() ) {
3052 ReachTuple rtOld = rtItr.next();
3054 // never remove the inherent hrnID from a flagged region
3055 // because it is trivially satisfied
3056 if( hrn.isFlagged() ) {
3057 if( rtOld == rtException ) {
3062 // does boldB allow this hrnID?
3063 boolean foundState = false;
3064 Iterator<RefEdge> incidentEdgeItr = hrn.iteratorToReferencers();
3065 while( incidentEdgeItr.hasNext() ) {
3066 RefEdge incidentEdge = incidentEdgeItr.next();
3068 Hashtable<RefEdge, ReachSet> B;
3069 if( rtOld.isOutOfContext() ) {
3070 B = boldBooc.get( rtOld.getHrnID() );
3073 if( !id2hrn.containsKey( rtOld.getHrnID() ) ) {
3074 // let symbols not in the graph get pruned
3078 B = boldBic.get( rtOld.getHrnID() );
3082 ReachSet boldB_rtOld_incident = B.get( incidentEdge );
3083 if( boldB_rtOld_incident != null &&
3084 boldB_rtOld_incident.containsIgnorePreds( stateOld ) != null
3092 markedHrnIDs = Canonical.add( markedHrnIDs, rtOld );
3096 // if there is nothing marked, just move on
3097 if( markedHrnIDs.isEmpty() ) {
3098 hrn.setAlphaNew( Canonical.add( hrn.getAlphaNew(),
3105 // remove all marked hrnIDs and establish a change set that should
3106 // propagate backwards over edges from this node
3107 ReachState statePruned = ReachState.factory();
3108 rtItr = stateOld.iterator();
3109 while( rtItr.hasNext() ) {
3110 ReachTuple rtOld = rtItr.next();
3112 if( !markedHrnIDs.containsTuple( rtOld ) ) {
3113 statePruned = Canonical.add( statePruned, rtOld );
3116 assert !stateOld.equals( statePruned );
3118 hrn.setAlphaNew( Canonical.add( hrn.getAlphaNew(),
3122 ChangeTuple ct = ChangeTuple.factory( stateOld,
3125 cts = Canonical.add( cts, ct );
3128 // throw change tuple set on all incident edges
3129 if( !cts.isEmpty() ) {
3130 Iterator<RefEdge> incidentEdgeItr = hrn.iteratorToReferencers();
3131 while( incidentEdgeItr.hasNext() ) {
3132 RefEdge incidentEdge = incidentEdgeItr.next();
3134 edgesForPropagation.add( incidentEdge );
3136 if( edgePlannedChanges.get( incidentEdge ) == null ) {
3137 edgePlannedChanges.put( incidentEdge, cts );
3139 edgePlannedChanges.put(
3141 Canonical.union( edgePlannedChanges.get( incidentEdge ),
3150 HashSet<RefEdge> edgesUpdated = new HashSet<RefEdge>();
3152 propagateTokensOverEdges( edgesForPropagation,
3156 // at the end of the 1st phase reference edges have
3157 // beta, betaNew that correspond to beta and betaR
3159 // commit beta<-betaNew, so beta=betaR and betaNew
3160 // will represent the beta' calculation in 2nd phase
3162 // commit alpha<-alphaNew because it won't change
3163 HashSet<RefEdge> res = new HashSet<RefEdge>();
3165 Iterator<HeapRegionNode> nodeItr = id2hrn.values().iterator();
3166 while( nodeItr.hasNext() ) {
3167 HeapRegionNode hrn = nodeItr.next();
3169 // as mentioned above, out-of-context nodes only serve
3170 // as sources of reach states for the sweep, not part
3172 if( hrn.isOutOfContext() ) {
3173 assert hrn.getAlphaNew().equals( rsetEmpty );
3175 hrn.applyAlphaNew();
3178 Iterator<RefEdge> itrRes = hrn.iteratorToReferencers();
3179 while( itrRes.hasNext() ) {
3180 res.add( itrRes.next() );
3186 Iterator<RefEdge> edgeItr = res.iterator();
3187 while( edgeItr.hasNext() ) {
3188 RefEdge edge = edgeItr.next();
3189 HeapRegionNode hrn = edge.getDst();
3191 // commit results of last phase
3192 if( edgesUpdated.contains( edge ) ) {
3193 edge.applyBetaNew();
3196 // compute intial condition of 2nd phase
3197 edge.setBetaNew( Canonical.intersection( edge.getBeta(),
3203 // every edge in the graph is the initial workset
3204 Set<RefEdge> edgeWorkSet = (Set) res.clone();
3205 while( !edgeWorkSet.isEmpty() ) {
3206 RefEdge edgePrime = edgeWorkSet.iterator().next();
3207 edgeWorkSet.remove( edgePrime );
3209 RefSrcNode rsn = edgePrime.getSrc();
3210 if( !(rsn instanceof HeapRegionNode) ) {
3213 HeapRegionNode hrn = (HeapRegionNode) rsn;
3215 Iterator<RefEdge> itrEdge = hrn.iteratorToReferencers();
3216 while( itrEdge.hasNext() ) {
3217 RefEdge edge = itrEdge.next();
3219 ReachSet prevResult = edge.getBetaNew();
3220 assert prevResult != null;
3222 ReachSet intersection =
3223 Canonical.intersection( edge.getBeta(),
3224 edgePrime.getBetaNew()
3227 if( Canonical.unionORpreds( prevResult,
3234 Canonical.unionORpreds( prevResult,
3238 edgeWorkSet.add( edge );
3243 // commit beta' (beta<-betaNew)
3244 edgeItr = res.iterator();
3245 while( edgeItr.hasNext() ) {
3246 edgeItr.next().applyBetaNew();
3251 // a useful assertion for debugging:
3252 // every in-context tuple on any edge or
3253 // any node should name a node that is
3254 // part of the graph
3255 public boolean inContextTuplesInGraph() {
3257 Iterator hrnItr = id2hrn.entrySet().iterator();
3258 while( hrnItr.hasNext() ) {
3259 Map.Entry me = (Map.Entry) hrnItr.next();
3260 HeapRegionNode hrn = (HeapRegionNode) me.getValue();
3263 Iterator<ReachState> stateItr = hrn.getAlpha().iterator();
3264 while( stateItr.hasNext() ) {
3265 ReachState state = stateItr.next();
3267 Iterator<ReachTuple> rtItr = state.iterator();
3268 while( rtItr.hasNext() ) {
3269 ReachTuple rt = rtItr.next();
3271 if( !rt.isOutOfContext() ) {
3272 if( !id2hrn.containsKey( rt.getHrnID() ) ) {
3273 System.out.println( rt.getHrnID()+" is missing" );
3281 Iterator<RefEdge> edgeItr = hrn.iteratorToReferencers();
3282 while( edgeItr.hasNext() ) {
3283 RefEdge edge = edgeItr.next();
3285 Iterator<ReachState> stateItr = edge.getBeta().iterator();
3286 while( stateItr.hasNext() ) {
3287 ReachState state = stateItr.next();
3289 Iterator<ReachTuple> rtItr = state.iterator();
3290 while( rtItr.hasNext() ) {
3291 ReachTuple rt = rtItr.next();
3293 if( !rt.isOutOfContext() ) {
3294 if( !id2hrn.containsKey( rt.getHrnID() ) ) {
3295 System.out.println( rt.getHrnID()+" is missing" );
3308 // another useful assertion for debugging
3309 public boolean noEmptyReachSetsInGraph() {
3311 Iterator hrnItr = id2hrn.entrySet().iterator();
3312 while( hrnItr.hasNext() ) {
3313 Map.Entry me = (Map.Entry) hrnItr.next();
3314 HeapRegionNode hrn = (HeapRegionNode) me.getValue();
3316 if( !hrn.isOutOfContext() &&
3318 hrn.getAlpha().isEmpty()
3320 System.out.println( "!!! "+hrn+" has an empty ReachSet !!!" );
3324 Iterator<RefEdge> edgeItr = hrn.iteratorToReferencers();
3325 while( edgeItr.hasNext() ) {
3326 RefEdge edge = edgeItr.next();
3328 if( edge.getBeta().isEmpty() ) {
3329 System.out.println( "!!! "+edge+" has an empty ReachSet !!!" );
3339 public boolean everyReachStateWTrue() {
3341 Iterator hrnItr = id2hrn.entrySet().iterator();
3342 while( hrnItr.hasNext() ) {
3343 Map.Entry me = (Map.Entry) hrnItr.next();
3344 HeapRegionNode hrn = (HeapRegionNode) me.getValue();
3347 Iterator<ReachState> stateItr = hrn.getAlpha().iterator();
3348 while( stateItr.hasNext() ) {
3349 ReachState state = stateItr.next();
3351 if( !state.getPreds().equals( predsTrue ) ) {
3357 Iterator<RefEdge> edgeItr = hrn.iteratorToReferencers();
3358 while( edgeItr.hasNext() ) {
3359 RefEdge edge = edgeItr.next();
3361 Iterator<ReachState> stateItr = edge.getBeta().iterator();
3362 while( stateItr.hasNext() ) {
3363 ReachState state = stateItr.next();
3365 if( !state.getPreds().equals( predsTrue ) ) {
3378 ////////////////////////////////////////////////////
3379 // in merge() and equals() methods the suffix A
3380 // represents the passed in graph and the suffix
3381 // B refers to the graph in this object
3382 // Merging means to take the incoming graph A and
3383 // merge it into B, so after the operation graph B
3384 // is the final result.
3385 ////////////////////////////////////////////////////
3386 protected void merge( ReachGraph rg ) {
3393 mergeRefEdges ( rg );
3394 mergeAllocSites( rg );
3397 protected void mergeNodes( ReachGraph rg ) {
3399 // start with heap region nodes
3400 Set sA = rg.id2hrn.entrySet();
3401 Iterator iA = sA.iterator();
3402 while( iA.hasNext() ) {
3403 Map.Entry meA = (Map.Entry) iA.next();
3404 Integer idA = (Integer) meA.getKey();
3405 HeapRegionNode hrnA = (HeapRegionNode) meA.getValue();
3407 // if this graph doesn't have a node the
3408 // incoming graph has, allocate it
3409 if( !id2hrn.containsKey( idA ) ) {
3410 HeapRegionNode hrnB = hrnA.copy();
3411 id2hrn.put( idA, hrnB );
3414 // otherwise this is a node present in both graphs
3415 // so make the new reachability set a union of the
3416 // nodes' reachability sets
3417 HeapRegionNode hrnB = id2hrn.get( idA );
3418 hrnB.setAlpha( Canonical.unionORpreds( hrnB.getAlpha(),
3423 hrnB.setPreds( Canonical.join( hrnB.getPreds(),
3430 if( !hrnA.equals( hrnB ) ) {
3431 rg.writeGraph( "graphA" );
3432 this.writeGraph( "graphB" );
3433 throw new Error( "flagged not matching" );
3441 // now add any variable nodes that are in graph B but
3443 sA = rg.td2vn.entrySet();
3445 while( iA.hasNext() ) {
3446 Map.Entry meA = (Map.Entry) iA.next();
3447 TempDescriptor tdA = (TempDescriptor) meA.getKey();
3448 VariableNode lnA = (VariableNode) meA.getValue();
3450 // if the variable doesn't exist in B, allocate and add it
3451 VariableNode lnB = getVariableNodeFromTemp( tdA );
3455 protected void mergeRefEdges( ReachGraph rg ) {
3457 // between heap regions
3458 Set sA = rg.id2hrn.entrySet();
3459 Iterator iA = sA.iterator();
3460 while( iA.hasNext() ) {
3461 Map.Entry meA = (Map.Entry) iA.next();
3462 Integer idA = (Integer) meA.getKey();
3463 HeapRegionNode hrnA = (HeapRegionNode) meA.getValue();
3465 Iterator<RefEdge> heapRegionsItrA = hrnA.iteratorToReferencees();
3466 while( heapRegionsItrA.hasNext() ) {
3467 RefEdge edgeA = heapRegionsItrA.next();
3468 HeapRegionNode hrnChildA = edgeA.getDst();
3469 Integer idChildA = hrnChildA.getID();
3471 // at this point we know an edge in graph A exists
3472 // idA -> idChildA, does this exist in B?
3473 assert id2hrn.containsKey( idA );
3474 HeapRegionNode hrnB = id2hrn.get( idA );
3475 RefEdge edgeToMerge = null;
3477 Iterator<RefEdge> heapRegionsItrB = hrnB.iteratorToReferencees();
3478 while( heapRegionsItrB.hasNext() &&
3479 edgeToMerge == null ) {
3481 RefEdge edgeB = heapRegionsItrB.next();
3482 HeapRegionNode hrnChildB = edgeB.getDst();
3483 Integer idChildB = hrnChildB.getID();
3485 // don't use the RefEdge.equals() here because
3486 // we're talking about existence between graphs,
3487 // not intragraph equal
3488 if( idChildB.equals( idChildA ) &&
3489 edgeB.typeAndFieldEquals( edgeA ) ) {
3491 edgeToMerge = edgeB;
3495 // if the edge from A was not found in B,
3497 if( edgeToMerge == null ) {
3498 assert id2hrn.containsKey( idChildA );
3499 HeapRegionNode hrnChildB = id2hrn.get( idChildA );
3500 edgeToMerge = edgeA.copy();
3501 edgeToMerge.setSrc( hrnB );
3502 edgeToMerge.setDst( hrnChildB );
3503 addRefEdge( hrnB, hrnChildB, edgeToMerge );
3505 // otherwise, the edge already existed in both graphs
3506 // so merge their reachability sets
3508 // just replace this beta set with the union
3509 assert edgeToMerge != null;
3510 edgeToMerge.setBeta(
3511 Canonical.unionORpreds( edgeToMerge.getBeta(),
3515 edgeToMerge.setPreds(
3516 Canonical.join( edgeToMerge.getPreds(),
3520 edgeToMerge.setParamTaints(
3521 Canonical.union( edgeToMerge.getParamTaints(),
3522 edgeA.getParamTaints()
3525 edgeToMerge.setRblockTaints(
3526 Canonical.union( edgeToMerge.getRblockTaints(),
3527 edgeA.getRblockTaints()
3534 // and then again from variable nodes
3535 sA = rg.td2vn.entrySet();
3537 while( iA.hasNext() ) {
3538 Map.Entry meA = (Map.Entry) iA.next();
3539 TempDescriptor tdA = (TempDescriptor) meA.getKey();
3540 VariableNode vnA = (VariableNode) meA.getValue();
3542 Iterator<RefEdge> heapRegionsItrA = vnA.iteratorToReferencees();
3543 while( heapRegionsItrA.hasNext() ) {
3544 RefEdge edgeA = heapRegionsItrA.next();
3545 HeapRegionNode hrnChildA = edgeA.getDst();
3546 Integer idChildA = hrnChildA.getID();
3548 // at this point we know an edge in graph A exists
3549 // tdA -> idChildA, does this exist in B?
3550 assert td2vn.containsKey( tdA );
3551 VariableNode vnB = td2vn.get( tdA );
3552 RefEdge edgeToMerge = null;
3554 Iterator<RefEdge> heapRegionsItrB = vnB.iteratorToReferencees();
3555 while( heapRegionsItrB.hasNext() &&
3556 edgeToMerge == null ) {
3558 RefEdge edgeB = heapRegionsItrB.next();
3559 HeapRegionNode hrnChildB = edgeB.getDst();
3560 Integer idChildB = hrnChildB.getID();
3562 // don't use the RefEdge.equals() here because
3563 // we're talking about existence between graphs
3564 if( idChildB.equals( idChildA ) &&
3565 edgeB.typeAndFieldEquals( edgeA ) ) {
3567 edgeToMerge = edgeB;
3571 // if the edge from A was not found in B,
3573 if( edgeToMerge == null ) {
3574 assert id2hrn.containsKey( idChildA );
3575 HeapRegionNode hrnChildB = id2hrn.get( idChildA );
3576 edgeToMerge = edgeA.copy();
3577 edgeToMerge.setSrc( vnB );
3578 edgeToMerge.setDst( hrnChildB );
3579 addRefEdge( vnB, hrnChildB, edgeToMerge );
3581 // otherwise, the edge already existed in both graphs
3582 // so merge their reachability sets
3584 // just replace this beta set with the union
3585 edgeToMerge.setBeta( Canonical.unionORpreds( edgeToMerge.getBeta(),
3589 edgeToMerge.setPreds( Canonical.join( edgeToMerge.getPreds(),
3593 edgeToMerge.setParamTaints(
3594 Canonical.union( edgeToMerge.getParamTaints(),
3595 edgeA.getParamTaints()
3598 edgeToMerge.setRblockTaints(
3599 Canonical.union( edgeToMerge.getRblockTaints(),
3600 edgeA.getRblockTaints()
3608 protected void mergeAllocSites( ReachGraph rg ) {
3609 allocSites.addAll( rg.allocSites );
3614 static boolean dbgEquals = false;
3617 // it is necessary in the equals() member functions
3618 // to "check both ways" when comparing the data
3619 // structures of two graphs. For instance, if all
3620 // edges between heap region nodes in graph A are
3621 // present and equal in graph B it is not sufficient
3622 // to say the graphs are equal. Consider that there
3623 // may be edges in graph B that are not in graph A.
3624 // the only way to know that all edges in both graphs
3625 // are equally present is to iterate over both data
3626 // structures and compare against the other graph.
3627 public boolean equals( ReachGraph rg ) {
3631 System.out.println( "rg is null" );
3636 if( !areHeapRegionNodesEqual( rg ) ) {
3638 System.out.println( "hrn not equal" );
3643 if( !areVariableNodesEqual( rg ) ) {
3645 System.out.println( "vars not equal" );
3650 if( !areRefEdgesEqual( rg ) ) {
3652 System.out.println( "edges not equal" );
3657 // if everything is equal up to this point,
3658 // assert that allocSites is also equal--
3659 // this data is redundant but kept for efficiency
3660 assert allocSites.equals( rg.allocSites );
3666 protected boolean areHeapRegionNodesEqual( ReachGraph rg ) {
3668 if( !areallHRNinAalsoinBandequal( this, rg ) ) {
3672 if( !areallHRNinAalsoinBandequal( rg, this ) ) {
3679 static protected boolean areallHRNinAalsoinBandequal( ReachGraph rgA,
3681 Set sA = rgA.id2hrn.entrySet();
3682 Iterator iA = sA.iterator();
3683 while( iA.hasNext() ) {
3684 Map.Entry meA = (Map.Entry) iA.next();
3685 Integer idA = (Integer) meA.getKey();
3686 HeapRegionNode hrnA = (HeapRegionNode) meA.getValue();
3688 if( !rgB.id2hrn.containsKey( idA ) ) {
3692 HeapRegionNode hrnB = rgB.id2hrn.get( idA );
3693 if( !hrnA.equalsIncludingAlphaAndPreds( hrnB ) ) {
3701 protected boolean areVariableNodesEqual( ReachGraph rg ) {
3703 if( !areallVNinAalsoinBandequal( this, rg ) ) {
3707 if( !areallVNinAalsoinBandequal( rg, this ) ) {
3714 static protected boolean areallVNinAalsoinBandequal( ReachGraph rgA,
3716 Set sA = rgA.td2vn.entrySet();
3717 Iterator iA = sA.iterator();
3718 while( iA.hasNext() ) {
3719 Map.Entry meA = (Map.Entry) iA.next();
3720 TempDescriptor tdA = (TempDescriptor) meA.getKey();
3722 if( !rgB.td2vn.containsKey( tdA ) ) {
3731 protected boolean areRefEdgesEqual( ReachGraph rg ) {
3732 if( !areallREinAandBequal( this, rg ) ) {
3736 if( !areallREinAandBequal( rg, this ) ) {
3743 static protected boolean areallREinAandBequal( ReachGraph rgA,
3746 // check all the heap region->heap region edges
3747 Set sA = rgA.id2hrn.entrySet();
3748 Iterator iA = sA.iterator();
3749 while( iA.hasNext() ) {
3750 Map.Entry meA = (Map.Entry) iA.next();
3751 Integer idA = (Integer) meA.getKey();
3752 HeapRegionNode hrnA = (HeapRegionNode) meA.getValue();
3754 // we should have already checked that the same
3755 // heap regions exist in both graphs
3756 assert rgB.id2hrn.containsKey( idA );
3758 if( !areallREfromAequaltoB( rgA, hrnA, rgB ) ) {
3762 // then check every edge in B for presence in A, starting
3763 // from the same parent HeapRegionNode
3764 HeapRegionNode hrnB = rgB.id2hrn.get( idA );
3766 if( !areallREfromAequaltoB( rgB, hrnB, rgA ) ) {
3771 // then check all the variable->heap region edges
3772 sA = rgA.td2vn.entrySet();
3774 while( iA.hasNext() ) {
3775 Map.Entry meA = (Map.Entry) iA.next();
3776 TempDescriptor tdA = (TempDescriptor) meA.getKey();
3777 VariableNode vnA = (VariableNode) meA.getValue();
3779 // we should have already checked that the same
3780 // label nodes exist in both graphs
3781 assert rgB.td2vn.containsKey( tdA );
3783 if( !areallREfromAequaltoB( rgA, vnA, rgB ) ) {
3787 // then check every edge in B for presence in A, starting
3788 // from the same parent VariableNode
3789 VariableNode vnB = rgB.td2vn.get( tdA );
3791 if( !areallREfromAequaltoB( rgB, vnB, rgA ) ) {
3800 static protected boolean areallREfromAequaltoB( ReachGraph rgA,
3804 Iterator<RefEdge> itrA = rnA.iteratorToReferencees();
3805 while( itrA.hasNext() ) {
3806 RefEdge edgeA = itrA.next();
3807 HeapRegionNode hrnChildA = edgeA.getDst();
3808 Integer idChildA = hrnChildA.getID();
3810 assert rgB.id2hrn.containsKey( idChildA );
3812 // at this point we know an edge in graph A exists
3813 // rnA -> idChildA, does this exact edge exist in B?
3814 boolean edgeFound = false;
3816 RefSrcNode rnB = null;
3817 if( rnA instanceof HeapRegionNode ) {
3818 HeapRegionNode hrnA = (HeapRegionNode) rnA;
3819 rnB = rgB.id2hrn.get( hrnA.getID() );
3821 VariableNode vnA = (VariableNode) rnA;
3822 rnB = rgB.td2vn.get( vnA.getTempDescriptor() );
3825 Iterator<RefEdge> itrB = rnB.iteratorToReferencees();
3826 while( itrB.hasNext() ) {
3827 RefEdge edgeB = itrB.next();
3828 HeapRegionNode hrnChildB = edgeB.getDst();
3829 Integer idChildB = hrnChildB.getID();
3831 if( idChildA.equals( idChildB ) &&
3832 edgeA.typeAndFieldEquals( edgeB ) ) {
3834 // there is an edge in the right place with the right field,
3835 // but do they have the same attributes?
3836 if( edgeA.getBeta().equals( edgeB.getBeta() ) &&
3837 edgeA.equalsPreds( edgeB )
3853 // can be used to assert monotonicity
3854 static public boolean isNoSmallerThan( ReachGraph rgA,
3857 //System.out.println( "*** Asking if A is no smaller than B ***" );
3860 Iterator iA = rgA.id2hrn.entrySet().iterator();
3861 while( iA.hasNext() ) {
3862 Map.Entry meA = (Map.Entry) iA.next();
3863 Integer idA = (Integer) meA.getKey();
3864 HeapRegionNode hrnA = (HeapRegionNode) meA.getValue();
3866 if( !rgB.id2hrn.containsKey( idA ) ) {
3867 System.out.println( " regions smaller" );
3871 //HeapRegionNode hrnB = rgB.id2hrn.get( idA );
3872 /* NOT EQUALS, NO SMALLER THAN!
3873 if( !hrnA.equalsIncludingAlphaAndPreds( hrnB ) ) {
3874 System.out.println( " regions smaller" );
3880 // this works just fine, no smaller than
3881 if( !areallVNinAalsoinBandequal( rgA, rgB ) ) {
3882 System.out.println( " vars smaller:" );
3883 System.out.println( " A:"+rgA.td2vn.keySet() );
3884 System.out.println( " B:"+rgB.td2vn.keySet() );
3889 iA = rgA.id2hrn.entrySet().iterator();
3890 while( iA.hasNext() ) {
3891 Map.Entry meA = (Map.Entry) iA.next();
3892 Integer idA = (Integer) meA.getKey();
3893 HeapRegionNode hrnA = (HeapRegionNode) meA.getValue();
3895 Iterator<RefEdge> reItr = hrnA.iteratorToReferencers();
3896 while( reItr.hasNext() ) {
3897 RefEdge edgeA = reItr.next();
3898 RefSrcNode rsnA = edgeA.getSrc();
3900 // we already checked that nodes were present
3901 HeapRegionNode hrnB = rgB.id2hrn.get( hrnA.getID() );
3902 assert hrnB != null;
3905 if( rsnA instanceof VariableNode ) {
3906 VariableNode vnA = (VariableNode) rsnA;
3907 rsnB = rgB.td2vn.get( vnA.getTempDescriptor() );
3910 HeapRegionNode hrnSrcA = (HeapRegionNode) rsnA;
3911 rsnB = rgB.id2hrn.get( hrnSrcA.getID() );
3913 assert rsnB != null;
3915 RefEdge edgeB = rsnB.getReferenceTo( hrnB,
3919 if( edgeB == null ) {
3920 System.out.println( " edges smaller:" );
3924 // REMEMBER, IS NO SMALLER THAN
3926 System.out.println( " edges smaller" );
3942 // this analysis no longer has the "match anything"
3943 // type which was represented by null
3944 protected TypeDescriptor mostSpecificType( TypeDescriptor td1,
3945 TypeDescriptor td2 ) {
3949 if( td1.isNull() ) {
3952 if( td2.isNull() ) {
3955 return typeUtil.mostSpecific( td1, td2 );
3958 protected TypeDescriptor mostSpecificType( TypeDescriptor td1,
3960 TypeDescriptor td3 ) {
3962 return mostSpecificType( td1,
3963 mostSpecificType( td2, td3 )
3967 protected TypeDescriptor mostSpecificType( TypeDescriptor td1,
3970 TypeDescriptor td4 ) {
3972 return mostSpecificType( mostSpecificType( td1, td2 ),
3973 mostSpecificType( td3, td4 )
3977 protected boolean isSuperiorType( TypeDescriptor possibleSuper,
3978 TypeDescriptor possibleChild ) {
3979 assert possibleSuper != null;
3980 assert possibleChild != null;
3982 if( possibleSuper.isNull() ||
3983 possibleChild.isNull() ) {
3987 return typeUtil.isSuperorType( possibleSuper, possibleChild );
3991 protected boolean hasMatchingField( HeapRegionNode src,
3994 TypeDescriptor tdSrc = src.getType();
3995 assert tdSrc != null;
3997 if( tdSrc.isArray() ) {
3998 TypeDescriptor td = edge.getType();
4001 TypeDescriptor tdSrcDeref = tdSrc.dereference();
4002 assert tdSrcDeref != null;
4004 if( !typeUtil.isSuperorType( tdSrcDeref, td ) ) {
4008 return edge.getField().equals( DisjointAnalysis.arrayElementFieldName );
4011 // if it's not a class, it doesn't have any fields to match
4012 if( !tdSrc.isClass() ) {
4016 ClassDescriptor cd = tdSrc.getClassDesc();
4017 while( cd != null ) {
4018 Iterator fieldItr = cd.getFields();
4020 while( fieldItr.hasNext() ) {
4021 FieldDescriptor fd = (FieldDescriptor) fieldItr.next();
4023 if( fd.getType().equals( edge.getType() ) &&
4024 fd.getSymbol().equals( edge.getField() ) ) {
4029 cd = cd.getSuperDesc();
4032 // otherwise it is a class with fields
4033 // but we didn't find a match
4037 protected boolean hasMatchingType( RefEdge edge,
4038 HeapRegionNode dst ) {
4040 // if the region has no type, matches everything
4041 TypeDescriptor tdDst = dst.getType();
4042 assert tdDst != null;
4044 // if the type is not a class or an array, don't
4045 // match because primitives are copied, no aliases
4046 ClassDescriptor cdDst = tdDst.getClassDesc();
4047 if( cdDst == null && !tdDst.isArray() ) {
4051 // if the edge type is null, it matches everything
4052 TypeDescriptor tdEdge = edge.getType();
4053 assert tdEdge != null;
4055 return typeUtil.isSuperorType( tdEdge, tdDst );
4060 // the default signature for quick-and-dirty debugging
4061 public void writeGraph( String graphName ) {
4062 writeGraph( graphName,
4063 true, // write labels
4064 true, // label select
4065 true, // prune garbage
4066 false, // hide reachability
4067 true, // hide subset reachability
4068 true, // hide predicates
4069 true, // hide edge taints
4070 null // in-context boundary
4074 public void writeGraph( String graphName,
4075 boolean writeLabels,
4076 boolean labelSelect,
4077 boolean pruneGarbage,
4078 boolean hideReachability,
4079 boolean hideSubsetReachability,
4080 boolean hidePredicates,
4081 boolean hideEdgeTaints
4083 writeGraph( graphName,
4088 hideSubsetReachability,
4094 public void writeGraph( String graphName,
4095 boolean writeLabels,
4096 boolean labelSelect,
4097 boolean pruneGarbage,
4098 boolean hideReachability,
4099 boolean hideSubsetReachability,
4100 boolean hidePredicates,
4101 boolean hideEdgeTaints,
4102 Set<Integer> callerNodeIDsCopiedToCallee
4106 // remove all non-word characters from the graph name so
4107 // the filename and identifier in dot don't cause errors
4108 graphName = graphName.replaceAll( "[\\W]", "" );
4111 new BufferedWriter( new FileWriter( graphName+".dot" ) );
4113 bw.write( "digraph "+graphName+" {\n" );
4116 // this is an optional step to form the callee-reachable
4117 // "cut-out" into a DOT cluster for visualization
4118 if( callerNodeIDsCopiedToCallee != null ) {
4120 bw.write( " subgraph cluster0 {\n" );
4121 bw.write( " color=blue;\n" );
4123 Iterator i = id2hrn.entrySet().iterator();
4124 while( i.hasNext() ) {
4125 Map.Entry me = (Map.Entry) i.next();
4126 HeapRegionNode hrn = (HeapRegionNode) me.getValue();
4128 if( callerNodeIDsCopiedToCallee.contains( hrn.getID() ) ) {
4131 hrn.toStringDOT( hideReachability,
4132 hideSubsetReachability,
4142 Set<HeapRegionNode> visited = new HashSet<HeapRegionNode>();
4144 // then visit every heap region node
4145 Iterator i = id2hrn.entrySet().iterator();
4146 while( i.hasNext() ) {
4147 Map.Entry me = (Map.Entry) i.next();
4148 HeapRegionNode hrn = (HeapRegionNode) me.getValue();
4150 // only visit nodes worth writing out--for instance
4151 // not every node at an allocation is referenced
4152 // (think of it as garbage-collected), etc.
4153 if( !pruneGarbage ||
4154 hrn.isOutOfContext() ||
4155 (hrn.isFlagged() && hrn.getID() > 0 && !hrn.isWiped()) // a non-shadow flagged node
4158 if( !visited.contains( hrn ) ) {
4159 traverseHeapRegionNodes( hrn,
4164 hideSubsetReachability,
4167 callerNodeIDsCopiedToCallee );
4172 bw.write( " graphTitle[label=\""+graphName+"\",shape=box];\n" );
4175 // then visit every label node, useful for debugging
4177 i = td2vn.entrySet().iterator();
4178 while( i.hasNext() ) {
4179 Map.Entry me = (Map.Entry) i.next();
4180 VariableNode vn = (VariableNode) me.getValue();
4183 String labelStr = vn.getTempDescriptorString();
4184 if( labelStr.startsWith( "___temp" ) ||
4185 labelStr.startsWith( "___dst" ) ||
4186 labelStr.startsWith( "___srctmp" ) ||
4187 labelStr.startsWith( "___neverused" )
4193 Iterator<RefEdge> heapRegionsItr = vn.iteratorToReferencees();
4194 while( heapRegionsItr.hasNext() ) {
4195 RefEdge edge = heapRegionsItr.next();
4196 HeapRegionNode hrn = edge.getDst();
4198 if( !visited.contains( hrn ) ) {
4199 traverseHeapRegionNodes( hrn,
4204 hideSubsetReachability,
4207 callerNodeIDsCopiedToCallee );
4210 bw.write( " "+vn.toString()+
4211 " -> "+hrn.toString()+
4212 edge.toStringDOT( hideReachability,
4213 hideSubsetReachability,
4225 } catch( IOException e ) {
4226 throw new Error( "Error writing out DOT graph "+graphName );
4231 traverseHeapRegionNodes( HeapRegionNode hrn,
4234 Set<HeapRegionNode> visited,
4235 boolean hideReachability,
4236 boolean hideSubsetReachability,
4237 boolean hidePredicates,
4238 boolean hideEdgeTaints,
4239 Set<Integer> callerNodeIDsCopiedToCallee
4240 ) throws java.io.IOException {
4242 if( visited.contains( hrn ) ) {
4247 // if we're drawing the callee-view subgraph, only
4248 // write out the node info if it hasn't already been
4250 if( callerNodeIDsCopiedToCallee == null ||
4251 !callerNodeIDsCopiedToCallee.contains( hrn.getID() )
4255 hrn.toStringDOT( hideReachability,
4256 hideSubsetReachability,
4261 Iterator<RefEdge> childRegionsItr = hrn.iteratorToReferencees();
4262 while( childRegionsItr.hasNext() ) {
4263 RefEdge edge = childRegionsItr.next();
4264 HeapRegionNode hrnChild = edge.getDst();
4266 if( callerNodeIDsCopiedToCallee != null &&
4267 (edge.getSrc() instanceof HeapRegionNode) ) {
4268 HeapRegionNode hrnSrc = (HeapRegionNode) edge.getSrc();
4269 if( callerNodeIDsCopiedToCallee.contains( hrnSrc.getID() ) &&
4270 callerNodeIDsCopiedToCallee.contains( edge.getDst().getID() )
4272 bw.write( " "+hrn.toString()+
4273 " -> "+hrnChild.toString()+
4274 edge.toStringDOT( hideReachability,
4275 hideSubsetReachability,
4280 } else if( !callerNodeIDsCopiedToCallee.contains( hrnSrc.getID() ) &&
4281 callerNodeIDsCopiedToCallee.contains( edge.getDst().getID() )
4283 bw.write( " "+hrn.toString()+
4284 " -> "+hrnChild.toString()+
4285 edge.toStringDOT( hideReachability,
4286 hideSubsetReachability,
4289 ",color=blue,style=dashed" )+
4292 bw.write( " "+hrn.toString()+
4293 " -> "+hrnChild.toString()+
4294 edge.toStringDOT( hideReachability,
4295 hideSubsetReachability,
4302 bw.write( " "+hrn.toString()+
4303 " -> "+hrnChild.toString()+
4304 edge.toStringDOT( hideReachability,
4305 hideSubsetReachability,
4312 traverseHeapRegionNodes( hrnChild,
4317 hideSubsetReachability,
4320 callerNodeIDsCopiedToCallee );
4328 public Set<HeapRegionNode> findCommonReachableNodes( ReachSet proofOfSharing ) {
4330 Set<HeapRegionNode> exhibitProofState =
4331 new HashSet<HeapRegionNode>();
4333 Iterator hrnItr = id2hrn.entrySet().iterator();
4334 while( hrnItr.hasNext() ) {
4335 Map.Entry me = (Map.Entry) hrnItr.next();
4336 HeapRegionNode hrn = (HeapRegionNode) me.getValue();
4338 ReachSet intersection =
4339 Canonical.intersection( proofOfSharing,
4342 if( !intersection.isEmpty() ) {
4343 assert !hrn.isOutOfContext();
4344 exhibitProofState.add( hrn );
4348 return exhibitProofState;
4352 public Set<HeapRegionNode> mayReachSharedObjects(HeapRegionNode hrn1,
4353 HeapRegionNode hrn2) {
4354 assert hrn1 != null;
4355 assert hrn2 != null;
4357 assert !hrn1.isOutOfContext();
4358 assert !hrn2.isOutOfContext();
4360 assert belongsToThis( hrn1 );
4361 assert belongsToThis( hrn2 );
4363 assert !hrn1.getID().equals( hrn2.getID() );
4366 // then get the various tokens for these heap regions
4368 ReachTuple.factory( hrn1.getID(),
4369 !hrn1.isSingleObject(), // multi?
4370 ReachTuple.ARITY_ONE,
4373 ReachTuple h1star = null;
4374 if( !hrn1.isSingleObject() ) {
4376 ReachTuple.factory( hrn1.getID(),
4377 !hrn1.isSingleObject(),
4378 ReachTuple.ARITY_ZEROORMORE,
4383 ReachTuple.factory( hrn2.getID(),
4384 !hrn2.isSingleObject(),
4385 ReachTuple.ARITY_ONE,
4388 ReachTuple h2star = null;
4389 if( !hrn2.isSingleObject() ) {
4391 ReachTuple.factory( hrn2.getID(),
4392 !hrn2.isSingleObject(),
4393 ReachTuple.ARITY_ZEROORMORE,
4397 // then get the merged beta of all out-going edges from these heap
4400 ReachSet beta1 = ReachSet.factory();
4401 Iterator<RefEdge> itrEdge = hrn1.iteratorToReferencees();
4402 while (itrEdge.hasNext()) {
4403 RefEdge edge = itrEdge.next();
4404 beta1 = Canonical.unionORpreds(beta1, edge.getBeta());
4407 ReachSet beta2 = ReachSet.factory();
4408 itrEdge = hrn2.iteratorToReferencees();
4409 while (itrEdge.hasNext()) {
4410 RefEdge edge = itrEdge.next();
4411 beta2 = Canonical.unionORpreds(beta2, edge.getBeta());
4414 ReachSet proofOfSharing = ReachSet.factory();
4417 Canonical.unionORpreds( proofOfSharing,
4418 beta1.getStatesWithBoth( h1, h2 )
4421 Canonical.unionORpreds( proofOfSharing,
4422 beta2.getStatesWithBoth( h1, h2 )
4425 if( !hrn1.isSingleObject() ) {
4427 Canonical.unionORpreds( proofOfSharing,
4428 beta1.getStatesWithBoth( h1star, h2 )
4431 Canonical.unionORpreds( proofOfSharing,
4432 beta2.getStatesWithBoth( h1star, h2 )
4436 if( !hrn2.isSingleObject() ) {
4438 Canonical.unionORpreds( proofOfSharing,
4439 beta1.getStatesWithBoth( h1, h2star )
4442 Canonical.unionORpreds( proofOfSharing,
4443 beta2.getStatesWithBoth( h1, h2star )
4447 if( !hrn1.isSingleObject() &&
4448 !hrn2.isSingleObject()
4451 Canonical.unionORpreds( proofOfSharing,
4452 beta1.getStatesWithBoth( h1star, h2star )
4455 Canonical.unionORpreds( proofOfSharing,
4456 beta2.getStatesWithBoth( h1star, h2star )
4460 Set<HeapRegionNode> common = new HashSet<HeapRegionNode>();
4461 if( !proofOfSharing.isEmpty() ) {
4462 common = findCommonReachableNodes( proofOfSharing );
4463 if( !DISABLE_STRONG_UPDATES &&
4464 !DISABLE_GLOBAL_SWEEP
4466 assert !common.isEmpty();
4473 // this version of the above method checks whether there is sharing
4474 // among the objects in a summary node
4475 public Set<HeapRegionNode> mayReachSharedObjects(HeapRegionNode hrn) {
4477 assert hrn.isNewSummary();
4478 assert !hrn.isOutOfContext();
4479 assert belongsToThis( hrn );
4482 ReachTuple.factory( hrn.getID(),
4484 ReachTuple.ARITY_ZEROORMORE,
4487 // then get the merged beta of all out-going edges from
4490 ReachSet beta = ReachSet.factory();
4491 Iterator<RefEdge> itrEdge = hrn.iteratorToReferencees();
4492 while (itrEdge.hasNext()) {
4493 RefEdge edge = itrEdge.next();
4494 beta = Canonical.unionORpreds(beta, edge.getBeta());
4497 ReachSet proofOfSharing = ReachSet.factory();
4500 Canonical.unionORpreds( proofOfSharing,
4501 beta.getStatesWithBoth( hstar, hstar )
4504 Set<HeapRegionNode> common = new HashSet<HeapRegionNode>();
4505 if( !proofOfSharing.isEmpty() ) {
4506 common = findCommonReachableNodes( proofOfSharing );
4507 if( !DISABLE_STRONG_UPDATES &&
4508 !DISABLE_GLOBAL_SWEEP
4510 assert !common.isEmpty();
4518 public Set<HeapRegionNode> mayReachSharedObjects(FlatMethod fm,
4519 Integer paramIndex1,
4520 Integer paramIndex2) {
4522 // get parameter's heap regions
4523 TempDescriptor paramTemp1 = fm.getParameter(paramIndex1.intValue());
4524 assert this.hasVariable( paramTemp1 );
4525 VariableNode paramVar1 = getVariableNodeFromTemp(paramTemp1);
4528 if( !(paramVar1.getNumReferencees() == 1) ) {
4529 System.out.println( "\n fm="+fm+"\n param="+paramTemp1 );
4530 writeGraph( "whatup" );
4534 assert paramVar1.getNumReferencees() == 1;
4535 RefEdge paramEdge1 = paramVar1.iteratorToReferencees().next();
4536 HeapRegionNode hrnParam1 = paramEdge1.getDst();
4538 TempDescriptor paramTemp2 = fm.getParameter(paramIndex2.intValue());
4539 assert this.hasVariable( paramTemp2 );
4540 VariableNode paramVar2 = getVariableNodeFromTemp(paramTemp2);
4542 if( !(paramVar2.getNumReferencees() == 1) ) {
4543 System.out.println( "\n fm="+fm+"\n param="+paramTemp2 );
4544 writeGraph( "whatup" );
4547 assert paramVar2.getNumReferencees() == 1;
4548 RefEdge paramEdge2 = paramVar2.iteratorToReferencees().next();
4549 HeapRegionNode hrnParam2 = paramEdge2.getDst();
4551 Set<HeapRegionNode> common = new HashSet<HeapRegionNode>();
4552 common.addAll(mayReachSharedObjects(hrnParam1, hrnParam2));
4557 public Set<HeapRegionNode> mayReachSharedObjects(FlatMethod fm,
4561 // get parameter's heap regions
4562 TempDescriptor paramTemp = fm.getParameter(paramIndex.intValue());
4563 assert this.hasVariable( paramTemp );
4564 VariableNode paramVar = getVariableNodeFromTemp(paramTemp);
4565 assert paramVar.getNumReferencees() == 1;
4566 RefEdge paramEdge = paramVar.iteratorToReferencees().next();
4567 HeapRegionNode hrnParam = paramEdge.getDst();
4570 HeapRegionNode hrnSummary=null;
4571 if(id2hrn.containsKey(as.getSummary())){
4572 // if summary node doesn't exist, ignore this case
4573 hrnSummary = id2hrn.get(as.getSummary());
4574 assert hrnSummary != null;
4577 Set<HeapRegionNode> common = new HashSet<HeapRegionNode>();
4578 if(hrnSummary!=null){
4579 common.addAll( mayReachSharedObjects(hrnParam, hrnSummary) );
4582 // check for other nodes
4583 for (int i = 0; i < as.getAllocationDepth(); ++i) {
4585 assert id2hrn.containsKey(as.getIthOldest(i));
4586 HeapRegionNode hrnIthOldest = id2hrn.get(as.getIthOldest(i));
4587 assert hrnIthOldest != null;
4589 common.addAll(mayReachSharedObjects(hrnParam, hrnIthOldest));
4596 public Set<HeapRegionNode> mayReachSharedObjects(AllocSite as1,
4599 // get summary node 1's alpha
4600 Integer idSum1 = as1.getSummary();
4601 HeapRegionNode hrnSum1=null;
4602 if(id2hrn.containsKey(idSum1)){
4603 hrnSum1 = id2hrn.get(idSum1);
4606 // get summary node 2's alpha
4607 Integer idSum2 = as2.getSummary();
4608 HeapRegionNode hrnSum2=null;
4609 if(id2hrn.containsKey(idSum2)){
4610 hrnSum2 = id2hrn.get(idSum2);
4613 Set<HeapRegionNode> common = new HashSet<HeapRegionNode>();
4614 if(hrnSum1!=null && hrnSum2!=null && hrnSum1!=hrnSum2){
4615 common.addAll(mayReachSharedObjects(hrnSum1, hrnSum2));
4619 // ask if objects from this summary share among each other
4620 common.addAll(mayReachSharedObjects(hrnSum1));
4623 // check sum2 against alloc1 nodes
4625 for (int i = 0; i < as1.getAllocationDepth(); ++i) {
4626 Integer idI1 = as1.getIthOldest(i);
4627 assert id2hrn.containsKey(idI1);
4628 HeapRegionNode hrnI1 = id2hrn.get(idI1);
4629 assert hrnI1 != null;
4630 common.addAll(mayReachSharedObjects(hrnI1, hrnSum2));
4633 // also ask if objects from this summary share among each other
4634 common.addAll(mayReachSharedObjects(hrnSum2));
4637 // check sum1 against alloc2 nodes
4638 for (int i = 0; i < as2.getAllocationDepth(); ++i) {
4639 Integer idI2 = as2.getIthOldest(i);
4640 assert id2hrn.containsKey(idI2);
4641 HeapRegionNode hrnI2 = id2hrn.get(idI2);
4642 assert hrnI2 != null;
4645 common.addAll(mayReachSharedObjects(hrnSum1, hrnI2));
4648 // while we're at it, do an inner loop for alloc2 vs alloc1 nodes
4649 for (int j = 0; j < as1.getAllocationDepth(); ++j) {
4650 Integer idI1 = as1.getIthOldest(j);
4652 // if these are the same site, don't look for the same token, no
4654 // different tokens of the same site could alias together though
4655 if (idI1.equals(idI2)) {
4659 HeapRegionNode hrnI1 = id2hrn.get(idI1);
4661 common.addAll(mayReachSharedObjects(hrnI1, hrnI2));