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 = true;
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 = 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 // the reason for this method is to have the option
67 // of creating new heap regions with specific IDs, or
68 // duplicating heap regions with specific IDs (especially
69 // in the merge() operation) or to create new heap
70 // regions with a new unique ID
71 protected HeapRegionNode
72 createNewHeapRegionNode( Integer id,
73 boolean isSingleObject,
76 boolean isOutOfContext,
85 boolean markForAnalysis = isFlagged;
87 TypeDescriptor typeToUse = null;
88 if( allocSite != null ) {
89 typeToUse = allocSite.getType();
90 allocSites.add( allocSite );
95 if( allocSite != null && allocSite.getDisjointAnalysisId() != null ) {
96 markForAnalysis = true;
100 id = DisjointAnalysis.generateUniqueHeapRegionNodeID();
103 if( inherent == null ) {
104 if( markForAnalysis ) {
108 ReachTuple.factory( id,
115 inherent = rsetWithEmptyState;
119 if( alpha == null ) {
123 if( preds == null ) {
124 // TODO: do this right? For out-of-context nodes?
125 preds = ExistPredSet.factory();
128 HeapRegionNode hrn = new HeapRegionNode( id,
139 id2hrn.put( id, hrn );
145 ////////////////////////////////////////////////
147 // Low-level referencee and referencer methods
149 // These methods provide the lowest level for
150 // creating references between reachability nodes
151 // and handling the details of maintaining both
152 // list of referencers and referencees.
154 ////////////////////////////////////////////////
155 protected void addRefEdge( RefSrcNode referencer,
156 HeapRegionNode referencee,
158 assert referencer != null;
159 assert referencee != null;
161 assert edge.getSrc() == referencer;
162 assert edge.getDst() == referencee;
164 referencer.addReferencee( edge );
165 referencee.addReferencer( edge );
168 protected void removeRefEdge( RefEdge e ) {
169 removeRefEdge( e.getSrc(),
175 protected void removeRefEdge( RefSrcNode referencer,
176 HeapRegionNode referencee,
179 assert referencer != null;
180 assert referencee != null;
182 RefEdge edge = referencer.getReferenceTo( referencee,
186 assert edge == referencee.getReferenceFrom( referencer,
190 referencer.removeReferencee( edge );
191 referencee.removeReferencer( edge );
194 protected void clearRefEdgesFrom( RefSrcNode referencer,
197 boolean removeAll ) {
198 assert referencer != null;
200 // get a copy of the set to iterate over, otherwise
201 // we will be trying to take apart the set as we
202 // are iterating over it, which won't work
203 Iterator<RefEdge> i = referencer.iteratorToReferenceesClone();
204 while( i.hasNext() ) {
205 RefEdge edge = i.next();
208 (edge.typeEquals( type ) && edge.fieldEquals( field ))
211 HeapRegionNode referencee = edge.getDst();
213 removeRefEdge( referencer,
221 protected void clearRefEdgesTo( HeapRegionNode referencee,
224 boolean removeAll ) {
225 assert referencee != null;
227 // get a copy of the set to iterate over, otherwise
228 // we will be trying to take apart the set as we
229 // are iterating over it, which won't work
230 Iterator<RefEdge> i = referencee.iteratorToReferencersClone();
231 while( i.hasNext() ) {
232 RefEdge edge = i.next();
235 (edge.typeEquals( type ) && edge.fieldEquals( field ))
238 RefSrcNode referencer = edge.getSrc();
240 removeRefEdge( referencer,
249 ////////////////////////////////////////////////////
251 // Assignment Operation Methods
253 // These methods are high-level operations for
254 // modeling program assignment statements using
255 // the low-level reference create/remove methods
258 ////////////////////////////////////////////////////
260 public void assignTempXEqualToTempY( TempDescriptor x,
262 assignTempXEqualToCastedTempY( x, y, null );
265 public void assignTempXEqualToCastedTempY( TempDescriptor x,
267 TypeDescriptor tdCast ) {
269 VariableNode lnX = getVariableNodeFromTemp( x );
270 VariableNode lnY = getVariableNodeFromTemp( y );
272 clearRefEdgesFrom( lnX, null, null, true );
274 // note it is possible that the types of temps in the
275 // flat node to analyze will reveal that some typed
276 // edges in the reachability graph are impossible
277 Set<RefEdge> impossibleEdges = new HashSet<RefEdge>();
279 Iterator<RefEdge> itrYhrn = lnY.iteratorToReferencees();
280 while( itrYhrn.hasNext() ) {
281 RefEdge edgeY = itrYhrn.next();
282 HeapRegionNode referencee = edgeY.getDst();
283 RefEdge edgeNew = edgeY.copy();
285 if( !isSuperiorType( x.getType(), edgeY.getType() ) ) {
286 impossibleEdges.add( edgeY );
290 edgeNew.setSrc( lnX );
292 if( tdCast == null ) {
293 edgeNew.setType( mostSpecificType( y.getType(),
299 edgeNew.setType( mostSpecificType( y.getType(),
301 referencee.getType(),
307 edgeNew.setField( null );
309 addRefEdge( lnX, referencee, edgeNew );
312 Iterator<RefEdge> itrImp = impossibleEdges.iterator();
313 while( itrImp.hasNext() ) {
314 RefEdge edgeImp = itrImp.next();
315 removeRefEdge( edgeImp );
320 public void assignTempXEqualToTempYFieldF( TempDescriptor x,
322 FieldDescriptor f ) {
323 VariableNode lnX = getVariableNodeFromTemp( x );
324 VariableNode lnY = getVariableNodeFromTemp( y );
326 clearRefEdgesFrom( lnX, null, null, true );
328 // note it is possible that the types of temps in the
329 // flat node to analyze will reveal that some typed
330 // edges in the reachability graph are impossible
331 Set<RefEdge> impossibleEdges = new HashSet<RefEdge>();
333 Iterator<RefEdge> itrYhrn = lnY.iteratorToReferencees();
334 while( itrYhrn.hasNext() ) {
335 RefEdge edgeY = itrYhrn.next();
336 HeapRegionNode hrnY = edgeY.getDst();
337 ReachSet betaY = edgeY.getBeta();
339 Iterator<RefEdge> itrHrnFhrn = hrnY.iteratorToReferencees();
340 while( itrHrnFhrn.hasNext() ) {
341 RefEdge edgeHrn = itrHrnFhrn.next();
342 HeapRegionNode hrnHrn = edgeHrn.getDst();
343 ReachSet betaHrn = edgeHrn.getBeta();
345 // prune edges that are not a matching field
346 if( edgeHrn.getType() != null &&
347 !edgeHrn.getField().equals( f.getSymbol() )
352 // check for impossible edges
353 if( !isSuperiorType( x.getType(), edgeHrn.getType() ) ) {
354 impossibleEdges.add( edgeHrn );
358 TypeDescriptor tdNewEdge =
359 mostSpecificType( edgeHrn.getType(),
363 RefEdge edgeNew = new RefEdge( lnX,
367 Canonical.intersection( betaY, betaHrn ),
371 addRefEdge( lnX, hrnHrn, edgeNew );
375 Iterator<RefEdge> itrImp = impossibleEdges.iterator();
376 while( itrImp.hasNext() ) {
377 RefEdge edgeImp = itrImp.next();
378 removeRefEdge( edgeImp );
381 // anytime you might remove edges between heap regions
382 // you must global sweep to clean up broken reachability
383 if( !impossibleEdges.isEmpty() ) {
384 if( !DISABLE_GLOBAL_SWEEP ) {
391 public void assignTempXFieldFEqualToTempY( TempDescriptor x,
395 VariableNode lnX = getVariableNodeFromTemp( x );
396 VariableNode lnY = getVariableNodeFromTemp( y );
398 HashSet<HeapRegionNode> nodesWithNewAlpha = new HashSet<HeapRegionNode>();
399 HashSet<RefEdge> edgesWithNewBeta = new HashSet<RefEdge>();
401 // note it is possible that the types of temps in the
402 // flat node to analyze will reveal that some typed
403 // edges in the reachability graph are impossible
404 Set<RefEdge> impossibleEdges = new HashSet<RefEdge>();
406 // first look for possible strong updates and remove those edges
407 boolean strongUpdate = false;
409 Iterator<RefEdge> itrXhrn = lnX.iteratorToReferencees();
410 while( itrXhrn.hasNext() ) {
411 RefEdge edgeX = itrXhrn.next();
412 HeapRegionNode hrnX = edgeX.getDst();
414 // we can do a strong update here if one of two cases holds
416 f != DisjointAnalysis.getArrayField( f.getType() ) &&
417 ( (hrnX.getNumReferencers() == 1) || // case 1
418 (hrnX.isSingleObject() && lnX.getNumReferencees() == 1) // case 2
421 if( !DISABLE_STRONG_UPDATES ) {
423 clearRefEdgesFrom( hrnX, f.getType(), f.getSymbol(), false );
428 // then do all token propagation
429 itrXhrn = lnX.iteratorToReferencees();
430 while( itrXhrn.hasNext() ) {
431 RefEdge edgeX = itrXhrn.next();
432 HeapRegionNode hrnX = edgeX.getDst();
433 ReachSet betaX = edgeX.getBeta();
434 ReachSet R = Canonical.intersection( hrnX.getAlpha(),
438 Iterator<RefEdge> itrYhrn = lnY.iteratorToReferencees();
439 while( itrYhrn.hasNext() ) {
440 RefEdge edgeY = itrYhrn.next();
441 HeapRegionNode hrnY = edgeY.getDst();
442 ReachSet O = edgeY.getBeta();
444 // check for impossible edges
445 if( !isSuperiorType( f.getType(), edgeY.getType() ) ) {
446 impossibleEdges.add( edgeY );
450 // propagate tokens over nodes starting from hrnSrc, and it will
451 // take care of propagating back up edges from any touched nodes
452 ChangeSet Cy = Canonical.unionUpArityToChangeSet( O, R );
453 propagateTokensOverNodes( hrnY, Cy, nodesWithNewAlpha, edgesWithNewBeta );
455 // then propagate back just up the edges from hrn
456 ChangeSet Cx = Canonical.unionUpArityToChangeSet( R, O );
457 HashSet<RefEdge> todoEdges = new HashSet<RefEdge>();
459 Hashtable<RefEdge, ChangeSet> edgePlannedChanges =
460 new Hashtable<RefEdge, ChangeSet>();
462 Iterator<RefEdge> referItr = hrnX.iteratorToReferencers();
463 while( referItr.hasNext() ) {
464 RefEdge edgeUpstream = referItr.next();
465 todoEdges.add( edgeUpstream );
466 edgePlannedChanges.put( edgeUpstream, Cx );
469 propagateTokensOverEdges( todoEdges,
476 // apply the updates to reachability
477 Iterator<HeapRegionNode> nodeItr = nodesWithNewAlpha.iterator();
478 while( nodeItr.hasNext() ) {
479 nodeItr.next().applyAlphaNew();
482 Iterator<RefEdge> edgeItr = edgesWithNewBeta.iterator();
483 while( edgeItr.hasNext() ) {
484 edgeItr.next().applyBetaNew();
488 // then go back through and add the new edges
489 itrXhrn = lnX.iteratorToReferencees();
490 while( itrXhrn.hasNext() ) {
491 RefEdge edgeX = itrXhrn.next();
492 HeapRegionNode hrnX = edgeX.getDst();
494 Iterator<RefEdge> itrYhrn = lnY.iteratorToReferencees();
495 while( itrYhrn.hasNext() ) {
496 RefEdge edgeY = itrYhrn.next();
497 HeapRegionNode hrnY = edgeY.getDst();
499 // skip impossible edges here, we already marked them
500 // when computing reachability propagations above
501 if( !isSuperiorType( f.getType(), edgeY.getType() ) ) {
505 // prepare the new reference edge hrnX.f -> hrnY
506 TypeDescriptor tdNewEdge =
507 mostSpecificType( y.getType(),
512 RefEdge edgeNew = new RefEdge( hrnX,
516 Canonical.pruneBy( edgeY.getBeta(),
522 // look to see if an edge with same field exists
523 // and merge with it, otherwise just add the edge
524 RefEdge edgeExisting = hrnX.getReferenceTo( hrnY,
528 if( edgeExisting != null ) {
529 edgeExisting.setBeta(
530 Canonical.union( edgeExisting.getBeta(),
534 edgeExisting.setPreds(
535 Canonical.join( edgeExisting.getPreds(),
541 addRefEdge( hrnX, hrnY, edgeNew );
546 Iterator<RefEdge> itrImp = impossibleEdges.iterator();
547 while( itrImp.hasNext() ) {
548 RefEdge edgeImp = itrImp.next();
549 removeRefEdge( edgeImp );
552 // if there was a strong update, make sure to improve
553 // reachability with a global sweep
554 if( strongUpdate || !impossibleEdges.isEmpty() ) {
555 if( !DISABLE_GLOBAL_SWEEP ) {
562 public void assignReturnEqualToTemp( TempDescriptor x ) {
564 VariableNode lnR = getVariableNodeFromTemp( tdReturn );
565 VariableNode lnX = getVariableNodeFromTemp( x );
567 clearRefEdgesFrom( lnR, null, null, true );
569 Iterator<RefEdge> itrXhrn = lnX.iteratorToReferencees();
570 while( itrXhrn.hasNext() ) {
571 RefEdge edgeX = itrXhrn.next();
572 HeapRegionNode referencee = edgeX.getDst();
573 RefEdge edgeNew = edgeX.copy();
574 edgeNew.setSrc( lnR );
576 addRefEdge( lnR, referencee, edgeNew );
581 public void assignTempEqualToNewAlloc( TempDescriptor x,
588 // after the age operation the newest (or zero-ith oldest)
589 // node associated with the allocation site should have
590 // no references to it as if it were a newly allocated
592 Integer idNewest = as.getIthOldest( 0 );
593 HeapRegionNode hrnNewest = id2hrn.get( idNewest );
594 assert hrnNewest != null;
596 VariableNode lnX = getVariableNodeFromTemp( x );
597 clearRefEdgesFrom( lnX, null, null, true );
599 // make a new reference to allocated node
600 TypeDescriptor type = as.getType();
603 new RefEdge( lnX, // source
607 hrnNewest.getAlpha(), // beta
608 predsTrue // predicates
611 addRefEdge( lnX, hrnNewest, edgeNew );
615 // use the allocation site (unique to entire analysis) to
616 // locate the heap region nodes in this reachability graph
617 // that should be aged. The process models the allocation
618 // of new objects and collects all the oldest allocations
619 // in a summary node to allow for a finite analysis
621 // There is an additional property of this method. After
622 // running it on a particular reachability graph (many graphs
623 // may have heap regions related to the same allocation site)
624 // the heap region node objects in this reachability graph will be
625 // allocated. Therefore, after aging a graph for an allocation
626 // site, attempts to retrieve the heap region nodes using the
627 // integer id's contained in the allocation site should always
628 // return non-null heap regions.
629 public void age( AllocSite as ) {
631 // keep track of allocation sites that are represented
632 // in this graph for efficiency with other operations
633 allocSites.add( as );
635 // if there is a k-th oldest node, it merges into
637 Integer idK = as.getOldest();
638 if( id2hrn.containsKey( idK ) ) {
639 HeapRegionNode hrnK = id2hrn.get( idK );
641 // retrieve the summary node, or make it
643 HeapRegionNode hrnSummary = getSummaryNode( as );
645 mergeIntoSummary( hrnK, hrnSummary );
648 // move down the line of heap region nodes
649 // clobbering the ith and transferring all references
650 // to and from i-1 to node i.
651 for( int i = allocationDepth - 1; i > 0; --i ) {
653 // if the target (ith) node exists, clobber it
654 // whether the i-1 node exists or not
655 Integer idIth = as.getIthOldest( i );
656 if( id2hrn.containsKey( idIth ) ) {
657 HeapRegionNode hrnI = id2hrn.get( idIth );
659 // clear all references in and out
663 // only do the transfer if the i-1 node exists
664 Integer idImin1th = as.getIthOldest( i - 1 );
665 if( id2hrn.containsKey( idImin1th ) ) {
666 HeapRegionNode hrnImin1 = id2hrn.get( idImin1th );
668 // either retrieve or make target of transfer
669 HeapRegionNode hrnI = getIthNode( as, i );
671 transferOnto( hrnImin1, hrnI );
676 // as stated above, the newest node should have had its
677 // references moved over to the second oldest, so we wipe newest
678 // in preparation for being the new object to assign something to
679 HeapRegionNode hrn0 = getIthNode( as, 0 );
682 // now tokens in reachability sets need to "age" also
683 Iterator itrAllVariableNodes = td2vn.entrySet().iterator();
684 while( itrAllVariableNodes.hasNext() ) {
685 Map.Entry me = (Map.Entry) itrAllVariableNodes.next();
686 VariableNode ln = (VariableNode) me.getValue();
688 Iterator<RefEdge> itrEdges = ln.iteratorToReferencees();
689 while( itrEdges.hasNext() ) {
690 ageTuplesFrom( as, itrEdges.next() );
694 Iterator itrAllHRNodes = id2hrn.entrySet().iterator();
695 while( itrAllHRNodes.hasNext() ) {
696 Map.Entry me = (Map.Entry) itrAllHRNodes.next();
697 HeapRegionNode hrnToAge = (HeapRegionNode) me.getValue();
699 ageTuplesFrom( as, hrnToAge );
701 Iterator<RefEdge> itrEdges = hrnToAge.iteratorToReferencees();
702 while( itrEdges.hasNext() ) {
703 ageTuplesFrom( as, itrEdges.next() );
708 // after tokens have been aged, reset newest node's reachability
709 // and a brand new node has a "true" predicate
710 hrn0.setAlpha( hrn0.getInherent() );
711 hrn0.setPreds( predsTrue );
715 // either retrieve or create the needed heap region node
716 protected HeapRegionNode getSummaryNode( AllocSite as ) {
718 Integer idSummary = as.getSummary();
719 HeapRegionNode hrnSummary = id2hrn.get( idSummary );
721 if( hrnSummary == null ) {
723 boolean hasFlags = false;
724 if( as.getType().isClass() ) {
725 hasFlags = as.getType().getClassDesc().hasFlags();
729 hasFlags = as.getFlag();
732 String strDesc = as.toStringForDOT()+"\\nsummary";
734 createNewHeapRegionNode( idSummary, // id or null to generate a new one
735 false, // single object?
737 hasFlags, // flagged?
738 false, // out-of-context?
739 as.getType(), // type
740 as, // allocation site
741 null, // inherent reach
742 null, // current reach
743 predsEmpty, // predicates
744 strDesc // description
751 // either retrieve or create the needed heap region node
752 protected HeapRegionNode getIthNode( AllocSite as, Integer i ) {
754 Integer idIth = as.getIthOldest( i );
755 HeapRegionNode hrnIth = id2hrn.get( idIth );
757 if( hrnIth == null ) {
759 boolean hasFlags = false;
760 if( as.getType().isClass() ) {
761 hasFlags = as.getType().getClassDesc().hasFlags();
765 hasFlags = as.getFlag();
768 String strDesc = as.toStringForDOT()+"\\n"+i+" oldest";
769 hrnIth = createNewHeapRegionNode( idIth, // id or null to generate a new one
770 true, // single object?
772 hasFlags, // flagged?
773 false, // out-of-context?
774 as.getType(), // type
775 as, // allocation site
776 null, // inherent reach
777 null, // current reach
778 predsEmpty, // predicates
779 strDesc // description
788 protected void mergeIntoSummary( HeapRegionNode hrn,
789 HeapRegionNode hrnSummary ) {
790 assert hrnSummary.isNewSummary();
792 // transfer references _from_ hrn over to hrnSummary
793 Iterator<RefEdge> itrReferencee = hrn.iteratorToReferencees();
794 while( itrReferencee.hasNext() ) {
795 RefEdge edge = itrReferencee.next();
796 RefEdge edgeMerged = edge.copy();
797 edgeMerged.setSrc( hrnSummary );
799 HeapRegionNode hrnReferencee = edge.getDst();
800 RefEdge edgeSummary =
801 hrnSummary.getReferenceTo( hrnReferencee,
806 if( edgeSummary == null ) {
807 // the merge is trivial, nothing to be done
809 // otherwise an edge from the referencer to hrnSummary exists already
810 // and the edge referencer->hrn should be merged with it
812 Canonical.union( edgeMerged.getBeta(),
813 edgeSummary.getBeta()
817 Canonical.join( edgeMerged.getPreds(),
818 edgeSummary.getPreds()
823 addRefEdge( hrnSummary, hrnReferencee, edgeMerged );
826 // next transfer references _to_ hrn over to hrnSummary
827 Iterator<RefEdge> itrReferencer = hrn.iteratorToReferencers();
828 while( itrReferencer.hasNext() ) {
829 RefEdge edge = itrReferencer.next();
830 RefEdge edgeMerged = edge.copy();
831 edgeMerged.setDst( hrnSummary );
833 RefSrcNode onReferencer = edge.getSrc();
834 RefEdge edgeSummary =
835 onReferencer.getReferenceTo( hrnSummary,
840 if( edgeSummary == null ) {
841 // the merge is trivial, nothing to be done
843 // otherwise an edge from the referencer to alpha_S exists already
844 // and the edge referencer->alpha_K should be merged with it
846 Canonical.union( edgeMerged.getBeta(),
847 edgeSummary.getBeta()
851 Canonical.join( edgeMerged.getPreds(),
852 edgeSummary.getPreds()
857 addRefEdge( onReferencer, hrnSummary, edgeMerged );
860 // then merge hrn reachability into hrnSummary
862 Canonical.union( hrnSummary.getAlpha(),
869 protected void transferOnto( HeapRegionNode hrnA,
870 HeapRegionNode hrnB ) {
872 // clear references in and out of node b
875 // copy each edge in and out of A to B
876 Iterator<RefEdge> itrReferencee = hrnA.iteratorToReferencees();
877 while( itrReferencee.hasNext() ) {
878 RefEdge edge = itrReferencee.next();
879 HeapRegionNode hrnReferencee = edge.getDst();
880 RefEdge edgeNew = edge.copy();
881 edgeNew.setSrc( hrnB );
883 addRefEdge( hrnB, hrnReferencee, edgeNew );
886 Iterator<RefEdge> itrReferencer = hrnA.iteratorToReferencers();
887 while( itrReferencer.hasNext() ) {
888 RefEdge edge = itrReferencer.next();
889 RefSrcNode onReferencer = edge.getSrc();
890 RefEdge edgeNew = edge.copy();
891 edgeNew.setDst( hrnB );
893 addRefEdge( onReferencer, hrnB, edgeNew );
896 // replace hrnB reachability and preds with hrnA's
897 hrnB.setAlpha( hrnA.getAlpha() );
898 hrnB.setPreds( hrnA.getPreds() );
902 // the purpose of this method is to conceptually "wipe out"
903 // a heap region from the graph--purposefully not called REMOVE
904 // because the node is still hanging around in the graph, just
905 // not mechanically connected or have any reach or predicate
906 // information on it anymore--lots of ops can use this
907 protected void wipeOut( HeapRegionNode hrn ) {
908 clearRefEdgesFrom( hrn, null, null, true );
909 clearRefEdgesTo ( hrn, null, null, true );
910 hrn.setAlpha( rsetEmpty );
911 hrn.setPreds( predsEmpty );
915 protected void ageTuplesFrom( AllocSite as, RefEdge edge ) {
917 Canonical.ageTuplesFrom( edge.getBeta(),
923 protected void ageTuplesFrom( AllocSite as, HeapRegionNode hrn ) {
925 Canonical.ageTuplesFrom( hrn.getAlpha(),
933 protected void propagateTokensOverNodes( HeapRegionNode nPrime,
935 HashSet<HeapRegionNode> nodesWithNewAlpha,
936 HashSet<RefEdge> edgesWithNewBeta ) {
938 HashSet<HeapRegionNode> todoNodes
939 = new HashSet<HeapRegionNode>();
940 todoNodes.add( nPrime );
942 HashSet<RefEdge> todoEdges
943 = new HashSet<RefEdge>();
945 Hashtable<HeapRegionNode, ChangeSet> nodePlannedChanges
946 = new Hashtable<HeapRegionNode, ChangeSet>();
947 nodePlannedChanges.put( nPrime, c0 );
949 Hashtable<RefEdge, ChangeSet> edgePlannedChanges
950 = new Hashtable<RefEdge, ChangeSet>();
952 // first propagate change sets everywhere they can go
953 while( !todoNodes.isEmpty() ) {
954 HeapRegionNode n = todoNodes.iterator().next();
955 ChangeSet C = nodePlannedChanges.get( n );
957 Iterator<RefEdge> referItr = n.iteratorToReferencers();
958 while( referItr.hasNext() ) {
959 RefEdge edge = referItr.next();
960 todoEdges.add( edge );
962 if( !edgePlannedChanges.containsKey( edge ) ) {
963 edgePlannedChanges.put( edge,
968 edgePlannedChanges.put( edge,
969 Canonical.union( edgePlannedChanges.get( edge ),
975 Iterator<RefEdge> refeeItr = n.iteratorToReferencees();
976 while( refeeItr.hasNext() ) {
977 RefEdge edgeF = refeeItr.next();
978 HeapRegionNode m = edgeF.getDst();
980 ChangeSet changesToPass = ChangeSet.factory();
982 Iterator<ChangeTuple> itrCprime = C.iterator();
983 while( itrCprime.hasNext() ) {
984 ChangeTuple c = itrCprime.next();
985 if( edgeF.getBeta().contains( c.getSetToMatch() ) ) {
986 changesToPass = Canonical.union( changesToPass, c );
990 if( !changesToPass.isEmpty() ) {
991 if( !nodePlannedChanges.containsKey( m ) ) {
992 nodePlannedChanges.put( m, ChangeSet.factory() );
995 ChangeSet currentChanges = nodePlannedChanges.get( m );
997 if( !changesToPass.isSubset( currentChanges ) ) {
999 nodePlannedChanges.put( m,
1000 Canonical.union( currentChanges,
1009 todoNodes.remove( n );
1012 // then apply all of the changes for each node at once
1013 Iterator itrMap = nodePlannedChanges.entrySet().iterator();
1014 while( itrMap.hasNext() ) {
1015 Map.Entry me = (Map.Entry) itrMap.next();
1016 HeapRegionNode n = (HeapRegionNode) me.getKey();
1017 ChangeSet C = (ChangeSet) me.getValue();
1019 // this propagation step is with respect to one change,
1020 // so we capture the full change from the old alpha:
1021 ReachSet localDelta = Canonical.applyChangeSet( n.getAlpha(),
1025 // but this propagation may be only one of many concurrent
1026 // possible changes, so keep a running union with the node's
1027 // partially updated new alpha set
1028 n.setAlphaNew( Canonical.union( n.getAlphaNew(),
1033 nodesWithNewAlpha.add( n );
1036 propagateTokensOverEdges( todoEdges,
1043 protected void propagateTokensOverEdges( HashSet <RefEdge> todoEdges,
1044 Hashtable<RefEdge, ChangeSet> edgePlannedChanges,
1045 HashSet <RefEdge> edgesWithNewBeta ) {
1047 // first propagate all change tuples everywhere they can go
1048 while( !todoEdges.isEmpty() ) {
1049 RefEdge edgeE = todoEdges.iterator().next();
1050 todoEdges.remove( edgeE );
1052 if( !edgePlannedChanges.containsKey( edgeE ) ) {
1053 edgePlannedChanges.put( edgeE,
1058 ChangeSet C = edgePlannedChanges.get( edgeE );
1060 ChangeSet changesToPass = ChangeSet.factory();
1062 Iterator<ChangeTuple> itrC = C.iterator();
1063 while( itrC.hasNext() ) {
1064 ChangeTuple c = itrC.next();
1065 if( edgeE.getBeta().contains( c.getSetToMatch() ) ) {
1066 changesToPass = Canonical.union( changesToPass, c );
1070 RefSrcNode rsn = edgeE.getSrc();
1072 if( !changesToPass.isEmpty() && rsn instanceof HeapRegionNode ) {
1073 HeapRegionNode n = (HeapRegionNode) rsn;
1075 Iterator<RefEdge> referItr = n.iteratorToReferencers();
1076 while( referItr.hasNext() ) {
1077 RefEdge edgeF = referItr.next();
1079 if( !edgePlannedChanges.containsKey( edgeF ) ) {
1080 edgePlannedChanges.put( edgeF,
1085 ChangeSet currentChanges = edgePlannedChanges.get( edgeF );
1087 if( !changesToPass.isSubset( currentChanges ) ) {
1088 todoEdges.add( edgeF );
1089 edgePlannedChanges.put( edgeF,
1090 Canonical.union( currentChanges,
1099 // then apply all of the changes for each edge at once
1100 Iterator itrMap = edgePlannedChanges.entrySet().iterator();
1101 while( itrMap.hasNext() ) {
1102 Map.Entry me = (Map.Entry) itrMap.next();
1103 RefEdge e = (RefEdge) me.getKey();
1104 ChangeSet C = (ChangeSet) me.getValue();
1106 // this propagation step is with respect to one change,
1107 // so we capture the full change from the old beta:
1108 ReachSet localDelta =
1109 Canonical.applyChangeSet( e.getBeta(),
1114 // but this propagation may be only one of many concurrent
1115 // possible changes, so keep a running union with the edge's
1116 // partially updated new beta set
1117 e.setBetaNew( Canonical.union( e.getBetaNew(),
1122 edgesWithNewBeta.add( e );
1128 // use this method to make a new reach graph that is
1129 // what heap the FlatMethod callee from the FlatCall
1130 // would start with reaching from its arguments in
1133 makeCalleeView( FlatCall fc,
1135 Set<HeapRegionNode> callerNodesCopiedToCallee,
1136 Set<RefEdge> callerEdgesCopiedToCallee,
1137 boolean writeDebugDOTs
1140 // the callee view is a new graph: DON'T MODIFY
1142 ReachGraph rg = new ReachGraph();
1144 // track what parts of this graph have already been
1145 // added to callee view, variables not needed.
1146 // Note that we need this because when we traverse
1147 // this caller graph for each parameter we may find
1148 // nodes and edges more than once (which the per-param
1149 // "visit" sets won't show) and we only want to create
1150 // an element in the new callee view one time
1151 //Set callerNodesCopiedToCallee = new HashSet<HeapRegionNode>();
1152 //Set callerEdgesCopiedToCallee = new HashSet<RefEdge>();
1155 // a conservative starting point is to take the
1156 // mechanically-reachable-from-arguments graph
1157 // as opposed to using reachability information
1158 // to prune the graph further
1159 for( int i = 0; i < fm.numParameters(); ++i ) {
1161 // for each parameter index, get the symbol in the
1162 // caller view and callee view
1164 // argument defined here is the symbol in the caller
1165 TempDescriptor tdArg = fc.getArgMatchingParamIndex( fm, i );
1167 // parameter defined here is the symbol in the callee
1168 TempDescriptor tdParam = fm.getParameter( i );
1170 // use these two VariableNode objects to translate
1171 // between caller and callee--its easy to compare
1172 // a HeapRegionNode across callee and caller because
1173 // they will have the same heap region ID
1174 VariableNode vnCaller = this.getVariableNodeFromTemp( tdArg );
1175 VariableNode vnCallee = rg.getVariableNodeFromTemp( tdParam );
1177 // now traverse the calleR view using the argument to
1178 // build the calleE view which has the parameter symbol
1179 Set<RefSrcNode> toVisitInCaller = new HashSet<RefSrcNode>();
1180 Set<RefSrcNode> visitedInCaller = new HashSet<RefSrcNode>();
1181 toVisitInCaller.add( vnCaller );
1183 while( !toVisitInCaller.isEmpty() ) {
1184 RefSrcNode rsnCaller = toVisitInCaller.iterator().next();
1185 RefSrcNode rsnCallee;
1187 toVisitInCaller.remove( rsnCaller );
1188 visitedInCaller.add( rsnCaller );
1190 // FIRST - setup the source end of an edge, and
1191 // remember the identifying info of the source
1192 // to build predicates
1193 TempDescriptor tdSrc = null;
1194 Integer hrnSrcID = null;
1196 if( rsnCaller == vnCaller ) {
1197 // if the caller node is the param symbol, we
1198 // have to do this translation for the callee
1199 rsnCallee = vnCallee;
1203 // otherwise the callee-view node is a heap
1204 // region with the same ID, that may or may
1205 // not have been created already
1206 assert rsnCaller instanceof HeapRegionNode;
1208 HeapRegionNode hrnSrcCaller = (HeapRegionNode) rsnCaller;
1209 hrnSrcID = hrnSrcCaller.getID();
1211 if( !callerNodesCopiedToCallee.contains( rsnCaller ) ) {
1214 ExistPred.factory( hrnSrcID, null );
1216 ExistPredSet preds =
1217 ExistPredSet.factory( pred );
1220 rg.createNewHeapRegionNode( hrnSrcCaller.getID(),
1221 hrnSrcCaller.isSingleObject(),
1222 hrnSrcCaller.isNewSummary(),
1223 hrnSrcCaller.isFlagged(),
1224 false, // out-of-context?
1225 hrnSrcCaller.getType(),
1226 hrnSrcCaller.getAllocSite(),
1227 /*toShadowTokens( this,*/ hrnSrcCaller.getInherent() /*)*/,
1228 /*toShadowTokens( this,*/ hrnSrcCaller.getAlpha() /*)*/,
1230 hrnSrcCaller.getDescription()
1232 callerNodesCopiedToCallee.add( (HeapRegionNode) rsnCaller );
1235 rsnCallee = rg.id2hrn.get( hrnSrcID );
1239 // SECOND - go over all edges from that source
1241 Iterator<RefEdge> itrRefEdges = rsnCaller.iteratorToReferencees();
1242 while( itrRefEdges.hasNext() ) {
1243 RefEdge reCaller = itrRefEdges.next();
1244 HeapRegionNode hrnCaller = reCaller.getDst();
1245 HeapRegionNode hrnCallee;
1247 // THIRD - setup destination ends of edges
1248 Integer hrnDstID = hrnCaller.getID();
1250 if( !callerNodesCopiedToCallee.contains( hrnCaller ) ) {
1253 ExistPred.factory( hrnDstID, null );
1255 ExistPredSet preds =
1256 ExistPredSet.factory( pred );
1259 rg.createNewHeapRegionNode( hrnCaller.getID(),
1260 hrnCaller.isSingleObject(),
1261 hrnCaller.isNewSummary(),
1262 hrnCaller.isFlagged(),
1263 false, // out-of-context?
1264 hrnCaller.getType(),
1265 hrnCaller.getAllocSite(),
1266 /*toShadowTokens( this,*/ hrnCaller.getInherent() /*)*/,
1267 /*toShadowTokens( this,*/ hrnCaller.getAlpha() /*)*/,
1269 hrnCaller.getDescription()
1271 callerNodesCopiedToCallee.add( hrnCaller );
1273 hrnCallee = rg.id2hrn.get( hrnDstID );
1276 // FOURTH - copy edge over if needed
1277 if( !callerEdgesCopiedToCallee.contains( reCaller ) ) {
1280 ExistPred.factory( tdSrc,
1284 reCaller.getField(),
1287 ExistPredSet preds =
1288 ExistPredSet.factory( pred );
1290 rg.addRefEdge( rsnCallee,
1292 new RefEdge( rsnCallee,
1295 reCaller.getField(),
1296 /*toShadowTokens( this,*/ reCaller.getBeta() /*)*/,
1300 callerEdgesCopiedToCallee.add( reCaller );
1303 // keep traversing nodes reachable from param i
1304 // that we haven't visited yet
1305 if( !visitedInCaller.contains( hrnCaller ) ) {
1306 toVisitInCaller.add( hrnCaller );
1309 } // end edge iteration
1310 } // end visiting heap nodes in caller
1311 } // end iterating over parameters as starting points
1314 // find the set of edges in this graph with source
1315 // out-of-context (not in nodes copied) and have a
1316 // destination in context (one of nodes copied) as
1317 // a starting point for building out-of-context nodes
1318 Iterator<HeapRegionNode> itrInContext =
1319 callerNodesCopiedToCallee.iterator();
1320 while( itrInContext.hasNext() ) {
1321 HeapRegionNode hrnCallerAndInContext = itrInContext.next();
1323 Iterator<RefEdge> itrMightCross =
1324 hrnCallerAndInContext.iteratorToReferencers();
1325 while( itrMightCross.hasNext() ) {
1326 RefEdge edgeMightCross = itrMightCross.next();
1328 // we're only interested in edges with a source
1329 // 1) out-of-context and 2) is a heap region
1330 if( callerNodesCopiedToCallee.contains( edgeMightCross.getSrc() ) ||
1331 !(edgeMightCross.getSrc() instanceof HeapRegionNode)
1337 HeapRegionNode hrnCallerAndOutContext =
1338 (HeapRegionNode) edgeMightCross.getSrc();
1340 // we found a reference that crosses from out-of-context
1341 // to in-context, so build a special out-of-context node
1342 // for the callee IHM and its reference edge
1343 HeapRegionNode hrnCalleeAndOutContext =
1344 rg.createNewHeapRegionNode( null, // ID
1345 false, // single object?
1346 false, // new summary?
1348 true, // out-of-context?
1349 hrnCallerAndOutContext.getType(),
1350 null, // alloc site, shouldn't be used
1351 /*toShadowTokens( this,*/ hrnCallerAndOutContext.getAlpha() /*)*/, // inherent
1352 /*toShadowTokens( this,*/ hrnCallerAndOutContext.getAlpha() /*)*/, // alpha
1357 HeapRegionNode hrnCalleeAndInContext =
1358 rg.id2hrn.get( hrnCallerAndInContext.getID() );
1360 rg.addRefEdge( hrnCalleeAndOutContext,
1361 hrnCalleeAndInContext,
1362 new RefEdge( hrnCalleeAndOutContext,
1363 hrnCalleeAndInContext,
1364 edgeMightCross.getType(),
1365 edgeMightCross.getField(),
1366 /*toShadowTokens( this,*/ edgeMightCross.getBeta() /*)*/,
1374 if( writeDebugDOTs ) {
1376 rg.writeGraph( "calleeview", true, false, false, false, true, true );
1377 } catch( IOException e ) {}
1385 resolveMethodCall( FlatCall fc,
1387 ReachGraph rgCallee,
1388 Set<HeapRegionNode> callerNodesCopiedToCallee,
1389 Set<RefEdge> callerEdgesCopiedToCallee,
1390 boolean writeDebugDOTs
1394 if( writeDebugDOTs ) {
1396 this.writeGraph( "caller", true, false, false, false, true, true,
1397 callerNodesCopiedToCallee, callerEdgesCopiedToCallee );
1398 rgCallee.writeGraph( "callee", true, false, false, false, true, true );
1399 } catch( IOException e ) {}
1403 // method call transfer function steps:
1404 // 1. Use current callee-reachable heap (CRH) to test callee
1405 // predicates and mark what will be coming in.
1406 // 2. Wipe CRH out of caller.
1407 // 3. Transplant marked callee parts in:
1408 // a) bring in nodes
1409 // b) bring in callee -> callee edges
1410 // c) resolve out-of-context -> callee edges
1411 // 4. Global sweep it.
1414 System.out.println( );
1418 // 1. mark what callee elements have satisfied predicates
1419 Set<HeapRegionNode> calleeNodesSatisfied =
1420 new HashSet<HeapRegionNode>();
1422 Set<RefEdge> calleeEdgesSatisfied =
1423 new HashSet<RefEdge>();
1425 Iterator meItr = rgCallee.id2hrn.entrySet().iterator();
1426 while( meItr.hasNext() ) {
1427 Map.Entry me = (Map.Entry) meItr.next();
1428 Integer id = (Integer) me.getKey();
1429 HeapRegionNode hrnCallee = (HeapRegionNode) me.getValue();
1431 if( hrnCallee.getPreds().isSatisfiedBy( this,
1432 callerNodesCopiedToCallee,
1433 callerEdgesCopiedToCallee
1436 calleeNodesSatisfied.add( hrnCallee );
1444 Iterator<RefEdge> reItr = hrnCallee.iteratorToReferencees();
1445 while( reItr.hasNext() ) {
1446 RefEdge reCallee = reItr.next();
1448 if( reCallee.getPreds().isSatisfiedBy( this,
1449 callerNodesCopiedToCallee,
1450 callerEdgesCopiedToCallee
1453 calleeEdgesSatisfied.add( reCallee );
1459 // 2. predicates tested, ok to wipe out caller part
1460 Iterator<HeapRegionNode> hrnItr = callerNodesCopiedToCallee.iterator();
1461 while( hrnItr.hasNext() ) {
1462 HeapRegionNode hrnCaller = hrnItr.next();
1463 wipeOut( hrnCaller );
1467 // 3. callee elements with satisfied preds come in
1470 hrnItr = calleeNodesSatisfied.iterator();
1471 while( hrnItr.hasNext() ) {
1472 HeapRegionNode hrnCallee = hrnItr.next();
1474 if( hrnCallee.isOutOfContext() ) {
1478 HeapRegionNode hrnCaller = id2hrn.get( hrnCallee.getID() );
1479 if( hrnCaller == null ) {
1481 createNewHeapRegionNode( hrnCallee.getID(), // id or null to generate a new one
1482 hrnCallee.isSingleObject(), // single object?
1483 hrnCallee.isNewSummary(), // summary?
1484 hrnCallee.isFlagged(), // flagged?
1485 false, // out-of-context?
1486 hrnCallee.getType(), // type
1487 hrnCallee.getAllocSite(), // allocation site
1488 hrnCallee.getInherent(), // inherent reach
1489 null, // current reach
1490 predsEmpty, // predicates
1491 hrnCallee.getDescription() // description
1495 transferOnto( hrnCallee, hrnCaller );
1498 // 3.b) callee -> callee edges
1499 Iterator<RefEdge> reItr = calleeEdgesSatisfied.iterator();
1500 while( reItr.hasNext() ) {
1501 RefEdge reCallee = reItr.next();
1503 RefSrcNode rsnCallee = reCallee.getSrc();
1504 RefSrcNode rsnCaller;
1506 if( rsnCallee instanceof VariableNode ) {
1507 VariableNode vnCallee = (VariableNode) rsnCallee;
1508 TempDescriptor tdParam = vnCallee.getTempDescriptor();
1509 TempDescriptor tdArg = fc.getArgMatchingParam( fm,
1511 if( tdArg == null ) {
1512 // this means the variable isn't a parameter, its local
1513 // to the callee so we ignore it in call site transfer
1517 rsnCaller = this.getVariableNodeFromTemp( tdArg );
1520 HeapRegionNode hrnSrcCallee = (HeapRegionNode) reCallee.getSrc();
1521 rsnCaller = id2hrn.get( hrnSrcCallee.getID() );
1524 assert rsnCaller != null;
1526 HeapRegionNode hrnDstCallee = reCallee.getDst();
1527 HeapRegionNode hrnDstCaller = id2hrn.get( hrnDstCallee.getID() );
1528 assert hrnDstCaller != null;
1530 RefEdge reCaller = new RefEdge( rsnCaller,
1533 reCallee.getField(),
1537 addRefEdge( rsnCaller, hrnDstCaller, reCaller );
1540 // 3.c) resolve out-of-context -> callee edges
1549 if( writeDebugDOTs ) {
1551 writeGraph( "callerAfter",
1552 true, false, false, false, true, true,
1554 } catch( IOException e ) {}
1561 ////////////////////////////////////////////////////
1563 // Abstract garbage collection simply removes
1564 // heap region nodes that are not mechanically
1565 // reachable from a root set. This step is
1566 // essential for testing node and edge existence
1567 // predicates efficiently
1569 ////////////////////////////////////////////////////
1570 public void abstractGarbageCollect( Set<TempDescriptor> liveSet ) {
1572 // calculate a root set, will be different for Java
1573 // version of analysis versus Bamboo version
1574 Set<RefSrcNode> toVisit = new HashSet<RefSrcNode>();
1576 // visit every variable in graph while building root
1577 // set, and do iterating on a copy, so we can remove
1578 // dead variables while we're at this
1579 Iterator makeCopyItr = td2vn.entrySet().iterator();
1580 Set entrysCopy = new HashSet();
1581 while( makeCopyItr.hasNext() ) {
1582 entrysCopy.add( makeCopyItr.next() );
1585 Iterator eItr = entrysCopy.iterator();
1586 while( eItr.hasNext() ) {
1587 Map.Entry me = (Map.Entry) eItr.next();
1588 TempDescriptor td = (TempDescriptor) me.getKey();
1589 VariableNode vn = (VariableNode) me.getValue();
1591 if( liveSet.contains( td ) ) {
1595 // dead var, remove completely from graph
1597 clearRefEdgesFrom( vn, null, null, true );
1601 // everything visited in a traversal is
1602 // considered abstractly live
1603 Set<RefSrcNode> visited = new HashSet<RefSrcNode>();
1605 while( !toVisit.isEmpty() ) {
1606 RefSrcNode rsn = toVisit.iterator().next();
1607 toVisit.remove( rsn );
1610 Iterator<RefEdge> hrnItr = rsn.iteratorToReferencees();
1611 while( hrnItr.hasNext() ) {
1612 RefEdge edge = hrnItr.next();
1613 HeapRegionNode hrn = edge.getDst();
1615 if( !visited.contains( hrn ) ) {
1621 // get a copy of the set to iterate over because
1622 // we're going to monkey with the graph when we
1623 // identify a garbage node
1624 Set<HeapRegionNode> hrnAllPrior = new HashSet<HeapRegionNode>();
1625 Iterator<HeapRegionNode> hrnItr = id2hrn.values().iterator();
1626 while( hrnItr.hasNext() ) {
1627 hrnAllPrior.add( hrnItr.next() );
1630 Iterator<HeapRegionNode> hrnAllItr = hrnAllPrior.iterator();
1631 while( hrnAllItr.hasNext() ) {
1632 HeapRegionNode hrn = hrnAllItr.next();
1634 if( !visited.contains( hrn ) ) {
1636 // heap region nodes are compared across ReachGraph
1637 // objects by their integer ID, so when discarding
1638 // garbage nodes we must also discard entries in
1639 // the ID -> heap region hashtable.
1640 id2hrn.remove( hrn.getID() );
1642 // RefEdge objects are two-way linked between
1643 // nodes, so when a node is identified as garbage,
1644 // actively clear references to and from it so
1645 // live nodes won't have dangling RefEdge's
1648 // if we just removed the last node from an allocation
1649 // site, it should be taken out of the ReachGraph's list
1650 AllocSite as = hrn.getAllocSite();
1651 if( !hasNodesOf( as ) ) {
1652 allocSites.remove( as );
1658 protected boolean hasNodesOf( AllocSite as ) {
1659 if( id2hrn.containsKey( as.getSummary() ) ) {
1663 for( int i = 0; i < allocationDepth; ++i ) {
1664 if( id2hrn.containsKey( as.getIthOldest( i ) ) ) {
1672 ////////////////////////////////////////////////////
1674 // This global sweep is an optional step to prune
1675 // reachability sets that are not internally
1676 // consistent with the global graph. It should be
1677 // invoked after strong updates or method calls.
1679 ////////////////////////////////////////////////////
1680 public void globalSweep() {
1682 // boldB is part of the phase 1 sweep
1683 Hashtable< Integer, Hashtable<RefEdge, ReachSet> > boldB =
1684 new Hashtable< Integer, Hashtable<RefEdge, ReachSet> >();
1686 // visit every heap region to initialize alphaNew and calculate boldB
1687 Iterator itrHrns = id2hrn.entrySet().iterator();
1688 while( itrHrns.hasNext() ) {
1689 Map.Entry me = (Map.Entry) itrHrns.next();
1690 Integer hrnID = (Integer) me.getKey();
1691 HeapRegionNode hrn = (HeapRegionNode) me.getValue();
1693 // assert that this node and incoming edges have clean alphaNew
1694 // and betaNew sets, respectively
1695 assert rsetEmpty.equals( hrn.getAlphaNew() );
1697 Iterator<RefEdge> itrRers = hrn.iteratorToReferencers();
1698 while( itrRers.hasNext() ) {
1699 RefEdge edge = itrRers.next();
1700 assert rsetEmpty.equals( edge.getBetaNew() );
1703 // calculate boldB for this flagged node
1704 if( hrn.isFlagged() ) {
1706 Hashtable<RefEdge, ReachSet> boldB_f =
1707 new Hashtable<RefEdge, ReachSet>();
1709 Set<RefEdge> workSetEdges = new HashSet<RefEdge>();
1711 // initial boldB_f constraints
1712 Iterator<RefEdge> itrRees = hrn.iteratorToReferencees();
1713 while( itrRees.hasNext() ) {
1714 RefEdge edge = itrRees.next();
1716 assert !boldB.containsKey( edge );
1717 boldB_f.put( edge, edge.getBeta() );
1719 assert !workSetEdges.contains( edge );
1720 workSetEdges.add( edge );
1723 // enforce the boldB_f constraint at edges until we reach a fixed point
1724 while( !workSetEdges.isEmpty() ) {
1725 RefEdge edge = workSetEdges.iterator().next();
1726 workSetEdges.remove( edge );
1728 Iterator<RefEdge> itrPrime = edge.getDst().iteratorToReferencees();
1729 while( itrPrime.hasNext() ) {
1730 RefEdge edgePrime = itrPrime.next();
1732 ReachSet prevResult = boldB_f.get( edgePrime );
1733 ReachSet intersection = Canonical.intersection( boldB_f.get( edge ),
1737 if( prevResult == null ||
1738 Canonical.union( prevResult,
1739 intersection ).size() > prevResult.size() ) {
1741 if( prevResult == null ) {
1742 boldB_f.put( edgePrime,
1743 Canonical.union( edgePrime.getBeta(),
1748 boldB_f.put( edgePrime,
1749 Canonical.union( prevResult,
1754 workSetEdges.add( edgePrime );
1759 boldB.put( hrnID, boldB_f );
1764 // use boldB to prune hrnIDs from alpha states that are impossible
1765 // and propagate the differences backwards across edges
1766 HashSet<RefEdge> edgesForPropagation = new HashSet<RefEdge>();
1768 Hashtable<RefEdge, ChangeSet> edgePlannedChanges =
1769 new Hashtable<RefEdge, ChangeSet>();
1772 itrHrns = id2hrn.entrySet().iterator();
1773 while( itrHrns.hasNext() ) {
1774 Map.Entry me = (Map.Entry) itrHrns.next();
1775 Integer hrnID = (Integer) me.getKey();
1776 HeapRegionNode hrn = (HeapRegionNode) me.getValue();
1778 // create the inherent hrnID from a flagged region
1779 // as an exception to removal below
1780 ReachTuple rtException =
1781 ReachTuple.factory( hrnID,
1782 !hrn.isSingleObject(),
1783 ReachTuple.ARITY_ONE
1786 ChangeSet cts = ChangeSet.factory();
1788 // mark hrnIDs for removal
1789 Iterator<ReachState> stateItr = hrn.getAlpha().iterator();
1790 while( stateItr.hasNext() ) {
1791 ReachState stateOld = stateItr.next();
1793 ReachState markedHrnIDs = ReachState.factory();
1795 Iterator<ReachTuple> rtItr = stateOld.iterator();
1796 while( rtItr.hasNext() ) {
1797 ReachTuple rtOld = rtItr.next();
1799 // never remove the inherent hrnID from a flagged region
1800 // because it is trivially satisfied
1801 if( hrn.isFlagged() ) {
1802 if( rtOld == rtException ) {
1807 // does boldB_ttOld allow this hrnID?
1808 boolean foundState = false;
1809 Iterator<RefEdge> incidentEdgeItr = hrn.iteratorToReferencers();
1810 while( incidentEdgeItr.hasNext() ) {
1811 RefEdge incidentEdge = incidentEdgeItr.next();
1813 // if it isn't allowed, mark for removal
1814 Integer idOld = rtOld.getHrnID();
1815 assert id2hrn.containsKey( idOld );
1816 Hashtable<RefEdge, ReachSet> B = boldB.get( idOld );
1817 ReachSet boldB_ttOld_incident = B.get( incidentEdge );
1818 if( boldB_ttOld_incident != null &&
1819 boldB_ttOld_incident.contains( stateOld ) ) {
1825 markedHrnIDs = Canonical.add( markedHrnIDs, rtOld );
1829 // if there is nothing marked, just move on
1830 if( markedHrnIDs.isEmpty() ) {
1831 hrn.setAlphaNew( Canonical.union( hrn.getAlphaNew(),
1838 // remove all marked hrnIDs and establish a change set that should
1839 // propagate backwards over edges from this node
1840 ReachState statePruned = ReachState.factory();
1841 rtItr = stateOld.iterator();
1842 while( rtItr.hasNext() ) {
1843 ReachTuple rtOld = rtItr.next();
1845 if( !markedHrnIDs.containsTuple( rtOld ) ) {
1846 statePruned = Canonical.union( statePruned, rtOld );
1849 assert !stateOld.equals( statePruned );
1851 hrn.setAlphaNew( Canonical.union( hrn.getAlphaNew(),
1855 ChangeTuple ct = ChangeTuple.factory( stateOld,
1858 cts = Canonical.union( cts, ct );
1861 // throw change tuple set on all incident edges
1862 if( !cts.isEmpty() ) {
1863 Iterator<RefEdge> incidentEdgeItr = hrn.iteratorToReferencers();
1864 while( incidentEdgeItr.hasNext() ) {
1865 RefEdge incidentEdge = incidentEdgeItr.next();
1867 edgesForPropagation.add( incidentEdge );
1869 if( edgePlannedChanges.get( incidentEdge ) == null ) {
1870 edgePlannedChanges.put( incidentEdge, cts );
1872 edgePlannedChanges.put(
1874 Canonical.union( edgePlannedChanges.get( incidentEdge ),
1883 HashSet<RefEdge> edgesUpdated = new HashSet<RefEdge>();
1885 propagateTokensOverEdges( edgesForPropagation,
1889 // at the end of the 1st phase reference edges have
1890 // beta, betaNew that correspond to beta and betaR
1892 // commit beta<-betaNew, so beta=betaR and betaNew
1893 // will represent the beta' calculation in 2nd phase
1895 // commit alpha<-alphaNew because it won't change
1896 HashSet<RefEdge> res = new HashSet<RefEdge>();
1898 Iterator<HeapRegionNode> nodeItr = id2hrn.values().iterator();
1899 while( nodeItr.hasNext() ) {
1900 HeapRegionNode hrn = nodeItr.next();
1901 hrn.applyAlphaNew();
1902 Iterator<RefEdge> itrRes = hrn.iteratorToReferencers();
1903 while( itrRes.hasNext() ) {
1904 res.add( itrRes.next() );
1910 Iterator<RefEdge> edgeItr = res.iterator();
1911 while( edgeItr.hasNext() ) {
1912 RefEdge edge = edgeItr.next();
1913 HeapRegionNode hrn = edge.getDst();
1915 // commit results of last phase
1916 if( edgesUpdated.contains( edge ) ) {
1917 edge.applyBetaNew();
1920 // compute intial condition of 2nd phase
1921 edge.setBetaNew( Canonical.intersection( edge.getBeta(),
1927 // every edge in the graph is the initial workset
1928 Set<RefEdge> edgeWorkSet = (Set) res.clone();
1929 while( !edgeWorkSet.isEmpty() ) {
1930 RefEdge edgePrime = edgeWorkSet.iterator().next();
1931 edgeWorkSet.remove( edgePrime );
1933 RefSrcNode rsn = edgePrime.getSrc();
1934 if( !(rsn instanceof HeapRegionNode) ) {
1937 HeapRegionNode hrn = (HeapRegionNode) rsn;
1939 Iterator<RefEdge> itrEdge = hrn.iteratorToReferencers();
1940 while( itrEdge.hasNext() ) {
1941 RefEdge edge = itrEdge.next();
1943 ReachSet prevResult = edge.getBetaNew();
1944 assert prevResult != null;
1946 ReachSet intersection =
1947 Canonical.intersection( edge.getBeta(),
1948 edgePrime.getBetaNew()
1951 if( Canonical.union( prevResult,
1953 ).size() > prevResult.size() ) {
1955 Canonical.union( prevResult,
1959 edgeWorkSet.add( edge );
1964 // commit beta' (beta<-betaNew)
1965 edgeItr = res.iterator();
1966 while( edgeItr.hasNext() ) {
1967 edgeItr.next().applyBetaNew();
1973 ////////////////////////////////////////////////////
1974 // high-level merge operations
1975 ////////////////////////////////////////////////////
1976 public void merge_sameMethodContext( ReachGraph rg ) {
1977 // when merging two graphs that abstract the heap
1978 // of the same method context, we just call the
1979 // basic merge operation
1983 public void merge_diffMethodContext( ReachGraph rg ) {
1984 // when merging graphs for abstract heaps in
1985 // different method contexts we should:
1986 // 1) age the allocation sites?
1990 ////////////////////////////////////////////////////
1991 // in merge() and equals() methods the suffix A
1992 // represents the passed in graph and the suffix
1993 // B refers to the graph in this object
1994 // Merging means to take the incoming graph A and
1995 // merge it into B, so after the operation graph B
1996 // is the final result.
1997 ////////////////////////////////////////////////////
1998 protected void merge( ReachGraph rg ) {
2005 mergeRefEdges ( rg );
2006 mergeAllocSites( rg );
2009 protected void mergeNodes( ReachGraph rg ) {
2011 // start with heap region nodes
2012 Set sA = rg.id2hrn.entrySet();
2013 Iterator iA = sA.iterator();
2014 while( iA.hasNext() ) {
2015 Map.Entry meA = (Map.Entry) iA.next();
2016 Integer idA = (Integer) meA.getKey();
2017 HeapRegionNode hrnA = (HeapRegionNode) meA.getValue();
2019 // if this graph doesn't have a node the
2020 // incoming graph has, allocate it
2021 if( !id2hrn.containsKey( idA ) ) {
2022 HeapRegionNode hrnB = hrnA.copy();
2023 id2hrn.put( idA, hrnB );
2026 // otherwise this is a node present in both graphs
2027 // so make the new reachability set a union of the
2028 // nodes' reachability sets
2029 HeapRegionNode hrnB = id2hrn.get( idA );
2030 hrnB.setAlpha( Canonical.union( hrnB.getAlpha(),
2035 // if hrnB is already dirty or hrnA is dirty,
2036 // the hrnB should end up dirty: TODO
2038 if( !hrnA.isClean() ) {
2039 hrnB.setIsClean( false );
2045 // now add any variable nodes that are in graph B but
2047 sA = rg.td2vn.entrySet();
2049 while( iA.hasNext() ) {
2050 Map.Entry meA = (Map.Entry) iA.next();
2051 TempDescriptor tdA = (TempDescriptor) meA.getKey();
2052 VariableNode lnA = (VariableNode) meA.getValue();
2054 // if the variable doesn't exist in B, allocate and add it
2055 VariableNode lnB = getVariableNodeFromTemp( tdA );
2059 protected void mergeRefEdges( ReachGraph rg ) {
2061 // between heap regions
2062 Set sA = rg.id2hrn.entrySet();
2063 Iterator iA = sA.iterator();
2064 while( iA.hasNext() ) {
2065 Map.Entry meA = (Map.Entry) iA.next();
2066 Integer idA = (Integer) meA.getKey();
2067 HeapRegionNode hrnA = (HeapRegionNode) meA.getValue();
2069 Iterator<RefEdge> heapRegionsItrA = hrnA.iteratorToReferencees();
2070 while( heapRegionsItrA.hasNext() ) {
2071 RefEdge edgeA = heapRegionsItrA.next();
2072 HeapRegionNode hrnChildA = edgeA.getDst();
2073 Integer idChildA = hrnChildA.getID();
2075 // at this point we know an edge in graph A exists
2076 // idA -> idChildA, does this exist in B?
2077 assert id2hrn.containsKey( idA );
2078 HeapRegionNode hrnB = id2hrn.get( idA );
2079 RefEdge edgeToMerge = null;
2081 Iterator<RefEdge> heapRegionsItrB = hrnB.iteratorToReferencees();
2082 while( heapRegionsItrB.hasNext() &&
2083 edgeToMerge == null ) {
2085 RefEdge edgeB = heapRegionsItrB.next();
2086 HeapRegionNode hrnChildB = edgeB.getDst();
2087 Integer idChildB = hrnChildB.getID();
2089 // don't use the RefEdge.equals() here because
2090 // we're talking about existence between graphs,
2091 // not intragraph equal
2092 if( idChildB.equals( idChildA ) &&
2093 edgeB.typeAndFieldEquals( edgeA ) ) {
2095 edgeToMerge = edgeB;
2099 // if the edge from A was not found in B,
2101 if( edgeToMerge == null ) {
2102 assert id2hrn.containsKey( idChildA );
2103 HeapRegionNode hrnChildB = id2hrn.get( idChildA );
2104 edgeToMerge = edgeA.copy();
2105 edgeToMerge.setSrc( hrnB );
2106 edgeToMerge.setDst( hrnChildB );
2107 addRefEdge( hrnB, hrnChildB, edgeToMerge );
2109 // otherwise, the edge already existed in both graphs
2110 // so merge their reachability sets
2112 // just replace this beta set with the union
2113 assert edgeToMerge != null;
2114 edgeToMerge.setBeta(
2115 Canonical.union( edgeToMerge.getBeta(),
2121 if( !edgeA.isClean() ) {
2122 edgeToMerge.setIsClean( false );
2129 // and then again from variable nodes
2130 sA = rg.td2vn.entrySet();
2132 while( iA.hasNext() ) {
2133 Map.Entry meA = (Map.Entry) iA.next();
2134 TempDescriptor tdA = (TempDescriptor) meA.getKey();
2135 VariableNode vnA = (VariableNode) meA.getValue();
2137 Iterator<RefEdge> heapRegionsItrA = vnA.iteratorToReferencees();
2138 while( heapRegionsItrA.hasNext() ) {
2139 RefEdge edgeA = heapRegionsItrA.next();
2140 HeapRegionNode hrnChildA = edgeA.getDst();
2141 Integer idChildA = hrnChildA.getID();
2143 // at this point we know an edge in graph A exists
2144 // tdA -> idChildA, does this exist in B?
2145 assert td2vn.containsKey( tdA );
2146 VariableNode vnB = td2vn.get( tdA );
2147 RefEdge edgeToMerge = null;
2149 Iterator<RefEdge> heapRegionsItrB = vnB.iteratorToReferencees();
2150 while( heapRegionsItrB.hasNext() &&
2151 edgeToMerge == null ) {
2153 RefEdge edgeB = heapRegionsItrB.next();
2154 HeapRegionNode hrnChildB = edgeB.getDst();
2155 Integer idChildB = hrnChildB.getID();
2157 // don't use the RefEdge.equals() here because
2158 // we're talking about existence between graphs
2159 if( idChildB.equals( idChildA ) &&
2160 edgeB.typeAndFieldEquals( edgeA ) ) {
2162 edgeToMerge = edgeB;
2166 // if the edge from A was not found in B,
2168 if( edgeToMerge == null ) {
2169 assert id2hrn.containsKey( idChildA );
2170 HeapRegionNode hrnChildB = id2hrn.get( idChildA );
2171 edgeToMerge = edgeA.copy();
2172 edgeToMerge.setSrc( vnB );
2173 edgeToMerge.setDst( hrnChildB );
2174 addRefEdge( vnB, hrnChildB, edgeToMerge );
2176 // otherwise, the edge already existed in both graphs
2177 // so merge their reachability sets
2179 // just replace this beta set with the union
2180 edgeToMerge.setBeta( Canonical.union( edgeToMerge.getBeta(),
2186 if( !edgeA.isClean() ) {
2187 edgeToMerge.setIsClean( false );
2195 protected void mergeAllocSites( ReachGraph rg ) {
2196 allocSites.addAll( rg.allocSites );
2200 // it is necessary in the equals() member functions
2201 // to "check both ways" when comparing the data
2202 // structures of two graphs. For instance, if all
2203 // edges between heap region nodes in graph A are
2204 // present and equal in graph B it is not sufficient
2205 // to say the graphs are equal. Consider that there
2206 // may be edges in graph B that are not in graph A.
2207 // the only way to know that all edges in both graphs
2208 // are equally present is to iterate over both data
2209 // structures and compare against the other graph.
2210 public boolean equals( ReachGraph rg ) {
2216 if( !areHeapRegionNodesEqual( rg ) ) {
2220 if( !areVariableNodesEqual( rg ) ) {
2224 if( !areRefEdgesEqual( rg ) ) {
2228 // if everything is equal up to this point,
2229 // assert that allocSites is also equal--
2230 // this data is redundant but kept for efficiency
2231 assert allocSites.equals( rg.allocSites );
2237 protected boolean areHeapRegionNodesEqual( ReachGraph rg ) {
2239 if( !areallHRNinAalsoinBandequal( this, rg ) ) {
2243 if( !areallHRNinAalsoinBandequal( rg, this ) ) {
2250 static protected boolean areallHRNinAalsoinBandequal( ReachGraph rgA,
2252 Set sA = rgA.id2hrn.entrySet();
2253 Iterator iA = sA.iterator();
2254 while( iA.hasNext() ) {
2255 Map.Entry meA = (Map.Entry) iA.next();
2256 Integer idA = (Integer) meA.getKey();
2257 HeapRegionNode hrnA = (HeapRegionNode) meA.getValue();
2259 if( !rgB.id2hrn.containsKey( idA ) ) {
2263 HeapRegionNode hrnB = rgB.id2hrn.get( idA );
2264 if( !hrnA.equalsIncludingAlphaAndPreds( hrnB ) ) {
2273 protected boolean areVariableNodesEqual( ReachGraph rg ) {
2275 if( !areallVNinAalsoinBandequal( this, rg ) ) {
2279 if( !areallVNinAalsoinBandequal( rg, this ) ) {
2286 static protected boolean areallVNinAalsoinBandequal( ReachGraph rgA,
2288 Set sA = rgA.td2vn.entrySet();
2289 Iterator iA = sA.iterator();
2290 while( iA.hasNext() ) {
2291 Map.Entry meA = (Map.Entry) iA.next();
2292 TempDescriptor tdA = (TempDescriptor) meA.getKey();
2294 if( !rgB.td2vn.containsKey( tdA ) ) {
2303 protected boolean areRefEdgesEqual( ReachGraph rg ) {
2304 if( !areallREinAandBequal( this, rg ) ) {
2311 static protected boolean areallREinAandBequal( ReachGraph rgA,
2314 // check all the heap region->heap region edges
2315 Set sA = rgA.id2hrn.entrySet();
2316 Iterator iA = sA.iterator();
2317 while( iA.hasNext() ) {
2318 Map.Entry meA = (Map.Entry) iA.next();
2319 Integer idA = (Integer) meA.getKey();
2320 HeapRegionNode hrnA = (HeapRegionNode) meA.getValue();
2322 // we should have already checked that the same
2323 // heap regions exist in both graphs
2324 assert rgB.id2hrn.containsKey( idA );
2326 if( !areallREfromAequaltoB( rgA, hrnA, rgB ) ) {
2330 // then check every edge in B for presence in A, starting
2331 // from the same parent HeapRegionNode
2332 HeapRegionNode hrnB = rgB.id2hrn.get( idA );
2334 if( !areallREfromAequaltoB( rgB, hrnB, rgA ) ) {
2339 // then check all the variable->heap region edges
2340 sA = rgA.td2vn.entrySet();
2342 while( iA.hasNext() ) {
2343 Map.Entry meA = (Map.Entry) iA.next();
2344 TempDescriptor tdA = (TempDescriptor) meA.getKey();
2345 VariableNode vnA = (VariableNode) meA.getValue();
2347 // we should have already checked that the same
2348 // label nodes exist in both graphs
2349 assert rgB.td2vn.containsKey( tdA );
2351 if( !areallREfromAequaltoB( rgA, vnA, rgB ) ) {
2355 // then check every edge in B for presence in A, starting
2356 // from the same parent VariableNode
2357 VariableNode vnB = rgB.td2vn.get( tdA );
2359 if( !areallREfromAequaltoB( rgB, vnB, rgA ) ) {
2368 static protected boolean areallREfromAequaltoB( ReachGraph rgA,
2372 Iterator<RefEdge> itrA = rnA.iteratorToReferencees();
2373 while( itrA.hasNext() ) {
2374 RefEdge edgeA = itrA.next();
2375 HeapRegionNode hrnChildA = edgeA.getDst();
2376 Integer idChildA = hrnChildA.getID();
2378 assert rgB.id2hrn.containsKey( idChildA );
2380 // at this point we know an edge in graph A exists
2381 // rnA -> idChildA, does this exact edge exist in B?
2382 boolean edgeFound = false;
2384 RefSrcNode rnB = null;
2385 if( rnA instanceof HeapRegionNode ) {
2386 HeapRegionNode hrnA = (HeapRegionNode) rnA;
2387 rnB = rgB.id2hrn.get( hrnA.getID() );
2389 VariableNode vnA = (VariableNode) rnA;
2390 rnB = rgB.td2vn.get( vnA.getTempDescriptor() );
2393 Iterator<RefEdge> itrB = rnB.iteratorToReferencees();
2394 while( itrB.hasNext() ) {
2395 RefEdge edgeB = itrB.next();
2396 HeapRegionNode hrnChildB = edgeB.getDst();
2397 Integer idChildB = hrnChildB.getID();
2399 if( idChildA.equals( idChildB ) &&
2400 edgeA.typeAndFieldEquals( edgeB ) ) {
2402 // there is an edge in the right place with the right field,
2403 // but do they have the same attributes?
2404 if( edgeA.getBeta().equals( edgeB.getBeta() ) &&
2405 edgeA.equalsPreds( edgeB )
2422 // this analysis no longer has the "match anything"
2423 // type which was represented by null
2424 protected TypeDescriptor mostSpecificType( TypeDescriptor td1,
2425 TypeDescriptor td2 ) {
2429 if( td1.isNull() ) {
2432 if( td2.isNull() ) {
2435 return typeUtil.mostSpecific( td1, td2 );
2438 protected TypeDescriptor mostSpecificType( TypeDescriptor td1,
2440 TypeDescriptor td3 ) {
2442 return mostSpecificType( td1,
2443 mostSpecificType( td2, td3 )
2447 protected TypeDescriptor mostSpecificType( TypeDescriptor td1,
2450 TypeDescriptor td4 ) {
2452 return mostSpecificType( mostSpecificType( td1, td2 ),
2453 mostSpecificType( td3, td4 )
2457 protected boolean isSuperiorType( TypeDescriptor possibleSuper,
2458 TypeDescriptor possibleChild ) {
2459 assert possibleSuper != null;
2460 assert possibleChild != null;
2462 if( possibleSuper.isNull() ||
2463 possibleChild.isNull() ) {
2467 return typeUtil.isSuperorType( possibleSuper, possibleChild );
2471 protected boolean hasMatchingField( HeapRegionNode src,
2474 TypeDescriptor tdSrc = src.getType();
2475 assert tdSrc != null;
2477 if( tdSrc.isArray() ) {
2478 TypeDescriptor td = edge.getType();
2481 TypeDescriptor tdSrcDeref = tdSrc.dereference();
2482 assert tdSrcDeref != null;
2484 if( !typeUtil.isSuperorType( tdSrcDeref, td ) ) {
2488 return edge.getField().equals( DisjointAnalysis.arrayElementFieldName );
2491 // if it's not a class, it doesn't have any fields to match
2492 if( !tdSrc.isClass() ) {
2496 ClassDescriptor cd = tdSrc.getClassDesc();
2497 while( cd != null ) {
2498 Iterator fieldItr = cd.getFields();
2500 while( fieldItr.hasNext() ) {
2501 FieldDescriptor fd = (FieldDescriptor) fieldItr.next();
2503 if( fd.getType().equals( edge.getType() ) &&
2504 fd.getSymbol().equals( edge.getField() ) ) {
2509 cd = cd.getSuperDesc();
2512 // otherwise it is a class with fields
2513 // but we didn't find a match
2517 protected boolean hasMatchingType( RefEdge edge,
2518 HeapRegionNode dst ) {
2520 // if the region has no type, matches everything
2521 TypeDescriptor tdDst = dst.getType();
2522 assert tdDst != null;
2524 // if the type is not a class or an array, don't
2525 // match because primitives are copied, no aliases
2526 ClassDescriptor cdDst = tdDst.getClassDesc();
2527 if( cdDst == null && !tdDst.isArray() ) {
2531 // if the edge type is null, it matches everything
2532 TypeDescriptor tdEdge = edge.getType();
2533 assert tdEdge != null;
2535 return typeUtil.isSuperorType( tdEdge, tdDst );
2540 public void writeGraph( String graphName,
2541 boolean writeLabels,
2542 boolean labelSelect,
2543 boolean pruneGarbage,
2544 boolean writeReferencers,
2545 boolean hideSubsetReachability,
2546 boolean hideEdgeTaints
2547 ) throws java.io.IOException {
2548 writeGraph( graphName,
2553 hideSubsetReachability,
2559 public void writeGraph( String graphName,
2560 boolean writeLabels,
2561 boolean labelSelect,
2562 boolean pruneGarbage,
2563 boolean writeReferencers,
2564 boolean hideSubsetReachability,
2565 boolean hideEdgeTaints,
2566 Set<HeapRegionNode> callerNodesCopiedToCallee,
2567 Set<RefEdge> callerEdgesCopiedToCallee
2568 ) throws java.io.IOException {
2570 // remove all non-word characters from the graph name so
2571 // the filename and identifier in dot don't cause errors
2572 graphName = graphName.replaceAll( "[\\W]", "" );
2575 new BufferedWriter( new FileWriter( graphName+".dot" ) );
2577 bw.write( "digraph "+graphName+" {\n" );
2580 // this is an optional step to form the callee-reachable
2581 // "cut-out" into a DOT cluster for visualization
2582 if( callerNodesCopiedToCallee != null ) {
2584 bw.write( " subgraph cluster0 {\n" );
2585 bw.write( " color=blue;\n" );
2587 Iterator i = id2hrn.entrySet().iterator();
2588 while( i.hasNext() ) {
2589 Map.Entry me = (Map.Entry) i.next();
2590 HeapRegionNode hrn = (HeapRegionNode) me.getValue();
2592 if( callerNodesCopiedToCallee.contains( hrn ) ) {
2593 bw.write( " "+hrn.toString()+
2594 hrn.toStringDOT( hideSubsetReachability )+
2604 Set<HeapRegionNode> visited = new HashSet<HeapRegionNode>();
2606 // then visit every heap region node
2607 Iterator i = id2hrn.entrySet().iterator();
2608 while( i.hasNext() ) {
2609 Map.Entry me = (Map.Entry) i.next();
2610 HeapRegionNode hrn = (HeapRegionNode) me.getValue();
2612 // only visit nodes worth writing out--for instance
2613 // not every node at an allocation is referenced
2614 // (think of it as garbage-collected), etc.
2615 if( !pruneGarbage ||
2616 (hrn.isFlagged() && hrn.getID() > 0) ||
2617 hrn.getDescription().startsWith( "param" ) ||
2618 hrn.isOutOfContext()
2621 if( !visited.contains( hrn ) ) {
2622 traverseHeapRegionNodes( hrn,
2627 hideSubsetReachability,
2629 callerNodesCopiedToCallee,
2630 callerEdgesCopiedToCallee );
2635 bw.write( " graphTitle[label=\""+graphName+"\",shape=box];\n" );
2638 // then visit every label node, useful for debugging
2640 i = td2vn.entrySet().iterator();
2641 while( i.hasNext() ) {
2642 Map.Entry me = (Map.Entry) i.next();
2643 VariableNode vn = (VariableNode) me.getValue();
2646 String labelStr = vn.getTempDescriptorString();
2647 if( labelStr.startsWith("___temp") ||
2648 labelStr.startsWith("___dst") ||
2649 labelStr.startsWith("___srctmp") ||
2650 labelStr.startsWith("___neverused")
2656 Iterator<RefEdge> heapRegionsItr = vn.iteratorToReferencees();
2657 while( heapRegionsItr.hasNext() ) {
2658 RefEdge edge = heapRegionsItr.next();
2659 HeapRegionNode hrn = edge.getDst();
2661 if( pruneGarbage && !visited.contains( hrn ) ) {
2662 traverseHeapRegionNodes( hrn,
2667 hideSubsetReachability,
2669 callerNodesCopiedToCallee,
2670 callerEdgesCopiedToCallee );
2673 bw.write( " "+vn.toString()+
2674 " -> "+hrn.toString()+
2675 edge.toStringDOT( hideSubsetReachability, "" )+
2685 protected void traverseHeapRegionNodes( HeapRegionNode hrn,
2688 Set<HeapRegionNode> visited,
2689 boolean writeReferencers,
2690 boolean hideSubsetReachability,
2691 boolean hideEdgeTaints,
2692 Set<HeapRegionNode> callerNodesCopiedToCallee,
2693 Set<RefEdge> callerEdgesCopiedToCallee
2694 ) throws java.io.IOException {
2696 if( visited.contains( hrn ) ) {
2701 // if we're drawing the callee-view subgraph, only
2702 // write out the node info if it hasn't already been
2704 if( callerNodesCopiedToCallee == null ||
2705 !callerNodesCopiedToCallee.contains( hrn )
2707 bw.write( " "+hrn.toString()+
2708 hrn.toStringDOT( hideSubsetReachability )+
2712 Iterator<RefEdge> childRegionsItr = hrn.iteratorToReferencees();
2713 while( childRegionsItr.hasNext() ) {
2714 RefEdge edge = childRegionsItr.next();
2715 HeapRegionNode hrnChild = edge.getDst();
2717 if( callerEdgesCopiedToCallee != null &&
2718 callerEdgesCopiedToCallee.contains( hrn )
2720 bw.write( " "+hrn.toString()+
2721 " -> "+hrnChild.toString()+
2722 edge.toStringDOT( hideSubsetReachability, ",color=blue" )+
2725 bw.write( " "+hrn.toString()+
2726 " -> "+hrnChild.toString()+
2727 edge.toStringDOT( hideSubsetReachability, "" )+
2731 traverseHeapRegionNodes( hrnChild,
2736 hideSubsetReachability,
2738 callerNodesCopiedToCallee,
2739 callerEdgesCopiedToCallee );