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
1139 // the callee view is a new graph: DON'T MODIFY
1141 ReachGraph rg = new ReachGraph();
1143 // track what parts of this graph have already been
1144 // added to callee view, variables not needed.
1145 // Note that we need this because when we traverse
1146 // this caller graph for each parameter we may find
1147 // nodes and edges more than once (which the per-param
1148 // "visit" sets won't show) and we only want to create
1149 // an element in the new callee view one time
1150 //Set callerNodesCopiedToCallee = new HashSet<HeapRegionNode>();
1151 //Set callerEdgesCopiedToCallee = new HashSet<RefEdge>();
1154 // a conservative starting point is to take the
1155 // mechanically-reachable-from-arguments graph
1156 // as opposed to using reachability information
1157 // to prune the graph further
1158 for( int i = 0; i < fm.numParameters(); ++i ) {
1160 // for each parameter index, get the symbol in the
1161 // caller view and callee view
1163 // argument defined here is the symbol in the caller
1164 TempDescriptor tdArg = fc.getArgMatchingParamIndex( fm, i );
1166 // parameter defined here is the symbol in the callee
1167 TempDescriptor tdParam = fm.getParameter( i );
1169 // use these two VariableNode objects to translate
1170 // between caller and callee--its easy to compare
1171 // a HeapRegionNode across callee and caller because
1172 // they will have the same heap region ID
1173 VariableNode vnCaller = this.getVariableNodeFromTemp( tdArg );
1174 VariableNode vnCallee = rg.getVariableNodeFromTemp( tdParam );
1176 // now traverse the calleR view using the argument to
1177 // build the calleE view which has the parameter symbol
1178 Set<RefSrcNode> toVisitInCaller = new HashSet<RefSrcNode>();
1179 Set<RefSrcNode> visitedInCaller = new HashSet<RefSrcNode>();
1180 toVisitInCaller.add( vnCaller );
1182 while( !toVisitInCaller.isEmpty() ) {
1183 RefSrcNode rsnCaller = toVisitInCaller.iterator().next();
1184 RefSrcNode rsnCallee;
1186 toVisitInCaller.remove( rsnCaller );
1187 visitedInCaller.add( rsnCaller );
1189 // FIRST - setup the source end of an edge, and
1190 // remember the identifying info of the source
1191 // to build predicates
1192 TempDescriptor tdSrc = null;
1193 Integer hrnSrcID = null;
1195 if( rsnCaller == vnCaller ) {
1196 // if the caller node is the param symbol, we
1197 // have to do this translation for the callee
1198 rsnCallee = vnCallee;
1202 // otherwise the callee-view node is a heap
1203 // region with the same ID, that may or may
1204 // not have been created already
1205 assert rsnCaller instanceof HeapRegionNode;
1207 HeapRegionNode hrnSrcCaller = (HeapRegionNode) rsnCaller;
1208 hrnSrcID = hrnSrcCaller.getID();
1210 if( !callerNodesCopiedToCallee.contains( rsnCaller ) ) {
1213 ExistPred.factory( hrnSrcID, null );
1215 ExistPredSet preds =
1216 ExistPredSet.factory( pred );
1219 rg.createNewHeapRegionNode( hrnSrcCaller.getID(),
1220 hrnSrcCaller.isSingleObject(),
1221 hrnSrcCaller.isNewSummary(),
1222 hrnSrcCaller.isFlagged(),
1223 false, // out-of-context?
1224 hrnSrcCaller.getType(),
1225 hrnSrcCaller.getAllocSite(),
1226 /*toShadowTokens( this,*/ hrnSrcCaller.getInherent() /*)*/,
1227 /*toShadowTokens( this,*/ hrnSrcCaller.getAlpha() /*)*/,
1229 hrnSrcCaller.getDescription()
1231 callerNodesCopiedToCallee.add( (HeapRegionNode) rsnCaller );
1234 rsnCallee = rg.id2hrn.get( hrnSrcID );
1238 // SECOND - go over all edges from that source
1240 Iterator<RefEdge> itrRefEdges = rsnCaller.iteratorToReferencees();
1241 while( itrRefEdges.hasNext() ) {
1242 RefEdge reCaller = itrRefEdges.next();
1243 HeapRegionNode hrnCaller = reCaller.getDst();
1244 HeapRegionNode hrnCallee;
1246 // THIRD - setup destination ends of edges
1247 Integer hrnDstID = hrnCaller.getID();
1249 if( !callerNodesCopiedToCallee.contains( hrnCaller ) ) {
1252 ExistPred.factory( hrnDstID, null );
1254 ExistPredSet preds =
1255 ExistPredSet.factory( pred );
1258 rg.createNewHeapRegionNode( hrnCaller.getID(),
1259 hrnCaller.isSingleObject(),
1260 hrnCaller.isNewSummary(),
1261 hrnCaller.isFlagged(),
1262 false, // out-of-context?
1263 hrnCaller.getType(),
1264 hrnCaller.getAllocSite(),
1265 /*toShadowTokens( this,*/ hrnCaller.getInherent() /*)*/,
1266 /*toShadowTokens( this,*/ hrnCaller.getAlpha() /*)*/,
1268 hrnCaller.getDescription()
1270 callerNodesCopiedToCallee.add( hrnCaller );
1272 hrnCallee = rg.id2hrn.get( hrnDstID );
1275 // FOURTH - copy edge over if needed
1276 if( !callerEdgesCopiedToCallee.contains( reCaller ) ) {
1279 ExistPred.factory( tdSrc,
1283 reCaller.getField(),
1286 ExistPredSet preds =
1287 ExistPredSet.factory( pred );
1289 rg.addRefEdge( rsnCallee,
1291 new RefEdge( rsnCallee,
1294 reCaller.getField(),
1295 /*toShadowTokens( this,*/ reCaller.getBeta() /*)*/,
1299 callerEdgesCopiedToCallee.add( reCaller );
1302 // keep traversing nodes reachable from param i
1303 // that we haven't visited yet
1304 if( !visitedInCaller.contains( hrnCaller ) ) {
1305 toVisitInCaller.add( hrnCaller );
1308 } // end edge iteration
1309 } // end visiting heap nodes in caller
1310 } // end iterating over parameters as starting points
1313 // find the set of edges in this graph with source
1314 // out-of-context (not in nodes copied) and have a
1315 // destination in context (one of nodes copied) as
1316 // a starting point for building out-of-context nodes
1317 Iterator<HeapRegionNode> itrInContext =
1318 callerNodesCopiedToCallee.iterator();
1319 while( itrInContext.hasNext() ) {
1320 HeapRegionNode hrnCallerAndInContext = itrInContext.next();
1322 Iterator<RefEdge> itrMightCross =
1323 hrnCallerAndInContext.iteratorToReferencers();
1324 while( itrMightCross.hasNext() ) {
1325 RefEdge edgeMightCross = itrMightCross.next();
1327 // we're only interested in edges with a source
1328 // 1) out-of-context and 2) is a heap region
1329 if( callerNodesCopiedToCallee.contains( edgeMightCross.getSrc() ) ||
1330 !(edgeMightCross.getSrc() instanceof HeapRegionNode)
1336 HeapRegionNode hrnCallerAndOutContext =
1337 (HeapRegionNode) edgeMightCross.getSrc();
1339 // we found a reference that crosses from out-of-context
1340 // to in-context, so build a special out-of-context node
1341 // for the callee IHM and its reference edge
1342 HeapRegionNode hrnCalleeAndOutContext =
1343 rg.createNewHeapRegionNode( null, // ID
1344 false, // single object?
1345 false, // new summary?
1347 true, // out-of-context?
1348 hrnCallerAndOutContext.getType(),
1349 null, // alloc site, shouldn't be used
1350 /*toShadowTokens( this,*/ hrnCallerAndOutContext.getAlpha() /*)*/, // inherent
1351 /*toShadowTokens( this,*/ hrnCallerAndOutContext.getAlpha() /*)*/, // alpha
1356 HeapRegionNode hrnCalleeAndInContext =
1357 rg.id2hrn.get( hrnCallerAndInContext.getID() );
1359 rg.addRefEdge( hrnCalleeAndOutContext,
1360 hrnCalleeAndInContext,
1361 new RefEdge( hrnCalleeAndOutContext,
1362 hrnCalleeAndInContext,
1363 edgeMightCross.getType(),
1364 edgeMightCross.getField(),
1365 /*toShadowTokens( this,*/ edgeMightCross.getBeta() /*)*/,
1375 rg.writeGraph( "calleeview", true, false, false, false, true, true );
1376 } catch( IOException e ) {}
1379 if( fc.getMethod().getSymbol().equals( "addSomething" ) ) {
1388 resolveMethodCall( FlatCall fc,
1390 ReachGraph rgCallee,
1391 Set<HeapRegionNode> callerNodesCopiedToCallee,
1392 Set<RefEdge> callerEdgesCopiedToCallee
1396 if( fc.getMethod().getSymbol().equals( "addBar" ) ) {
1399 writeGraph( "caller", true, false, false, false, true, true, callerNodesCopiedToCallee, callerEdgesCopiedToCallee );
1400 rgCallee.writeGraph( "callee", true, false, false, false, true, true );
1401 } catch( IOException e ) {}
1407 // method call transfer function steps:
1408 // 1. Use current callee-reachable heap (CRH) to test callee
1409 // predicates and mark what will be coming in.
1410 // 2. Wipe CRH out of caller.
1411 // 3. Transplant marked callee parts in:
1412 // a) bring in nodes
1413 // b) bring in callee -> callee edges
1414 // c) resolve out-of-context -> callee edges
1415 // 4. Global sweep it.
1419 // 1. mark what callee elements have satisfied predicates
1420 Set<HeapRegionNode> calleeNodesSatisfied =
1421 new HashSet<HeapRegionNode>();
1423 Set<RefEdge> calleeEdgesSatisfied =
1424 new HashSet<RefEdge>();
1426 Iterator meItr = rgCallee.id2hrn.entrySet().iterator();
1427 while( meItr.hasNext() ) {
1428 Map.Entry me = (Map.Entry) meItr.next();
1429 Integer id = (Integer) me.getKey();
1430 HeapRegionNode hrnCallee = (HeapRegionNode) me.getValue();
1432 if( hrnCallee.getPreds().isSatisfiedBy( this,
1433 callerNodesCopiedToCallee,
1434 callerEdgesCopiedToCallee
1437 calleeNodesSatisfied.add( hrnCallee );
1440 Iterator<RefEdge> reItr = hrnCallee.iteratorToReferencees();
1441 while( reItr.hasNext() ) {
1442 RefEdge reCallee = reItr.next();
1444 if( reCallee.getPreds().isSatisfiedBy( this,
1445 callerNodesCopiedToCallee,
1446 callerEdgesCopiedToCallee
1449 calleeEdgesSatisfied.add( reCallee );
1455 // 2. predicates tested, ok to wipe out caller part
1456 Iterator<HeapRegionNode> hrnItr = callerNodesCopiedToCallee.iterator();
1457 while( hrnItr.hasNext() ) {
1458 HeapRegionNode hrnCaller = hrnItr.next();
1459 wipeOut( hrnCaller );
1464 // 3. callee elements with satisfied preds come in
1467 hrnItr = calleeNodesSatisfied.iterator();
1468 while( hrnItr.hasNext() ) {
1469 HeapRegionNode hrnCallee = hrnItr.next();
1471 if( hrnCallee.isOutOfContext() ) {
1475 HeapRegionNode hrnCaller = id2hrn.get( hrnCallee.getID() );
1476 if( hrnCaller == null ) {
1478 createNewHeapRegionNode( hrnCallee.getID(), // id or null to generate a new one
1479 hrnCallee.isSingleObject(), // single object?
1480 hrnCallee.isNewSummary(), // summary?
1481 hrnCallee.isFlagged(), // flagged?
1482 false, // out-of-context?
1483 hrnCallee.getType(), // type
1484 hrnCallee.getAllocSite(), // allocation site
1485 hrnCallee.getInherent(), // inherent reach
1486 null, // current reach
1487 predsEmpty, // predicates
1488 hrnCallee.getDescription() // description
1492 transferOnto( hrnCallee, hrnCaller );
1495 // 3.b) callee -> callee edges
1496 Iterator<RefEdge> reItr = calleeEdgesSatisfied.iterator();
1497 while( reItr.hasNext() ) {
1498 RefEdge reCallee = reItr.next();
1500 RefSrcNode rsnCallee = reCallee.getSrc();
1501 RefSrcNode rsnCaller;
1503 if( rsnCallee instanceof VariableNode ) {
1504 VariableNode vnCallee = (VariableNode) rsnCallee;
1505 TempDescriptor tdParam = vnCallee.getTempDescriptor();
1506 TempDescriptor tdArg = fc.getArgMatchingParam( fm,
1508 if( tdArg == null ) {
1509 // this means the variable isn't a parameter, its local
1510 // to the callee so we ignore it in call site transfer
1514 rsnCaller = this.getVariableNodeFromTemp( tdArg );
1517 HeapRegionNode hrnSrcCallee = (HeapRegionNode) reCallee.getSrc();
1518 rsnCaller = id2hrn.get( hrnSrcCallee.getID() );
1521 assert rsnCaller != null;
1523 HeapRegionNode hrnDstCallee = reCallee.getDst();
1524 HeapRegionNode hrnDstCaller = id2hrn.get( hrnDstCallee.getID() );
1525 assert hrnDstCaller != null;
1527 RefEdge reCaller = new RefEdge( rsnCaller,
1530 reCallee.getField(),
1534 addRefEdge( rsnCaller, hrnDstCaller, reCaller );
1537 // 3.c) resolve out-of-context -> callee edges
1546 if( fc.getMethod().getSymbol().equals( "addBar" ) ) {
1549 writeGraph( "callerAfter", true, false, false, false, true, true, null, null );
1550 } catch( IOException e ) {}
1559 ////////////////////////////////////////////////////
1561 // Abstract garbage collection simply removes
1562 // heap region nodes that are not mechanically
1563 // reachable from a root set. This step is
1564 // essential for testing node and edge existence
1565 // predicates efficiently
1567 ////////////////////////////////////////////////////
1568 public void abstractGarbageCollect( Set<TempDescriptor> liveSet ) {
1570 // calculate a root set, will be different for Java
1571 // version of analysis versus Bamboo version
1572 Set<RefSrcNode> toVisit = new HashSet<RefSrcNode>();
1574 // visit every variable in graph while building root
1575 // set, and do iterating on a copy, so we can remove
1576 // dead variables while we're at this
1577 Iterator makeCopyItr = td2vn.entrySet().iterator();
1578 Set entrysCopy = new HashSet();
1579 while( makeCopyItr.hasNext() ) {
1580 entrysCopy.add( makeCopyItr.next() );
1583 Iterator eItr = entrysCopy.iterator();
1584 while( eItr.hasNext() ) {
1585 Map.Entry me = (Map.Entry) eItr.next();
1586 TempDescriptor td = (TempDescriptor) me.getKey();
1587 VariableNode vn = (VariableNode) me.getValue();
1589 if( liveSet.contains( td ) ) {
1593 // dead var, remove completely from graph
1595 clearRefEdgesFrom( vn, null, null, true );
1599 // everything visited in a traversal is
1600 // considered abstractly live
1601 Set<RefSrcNode> visited = new HashSet<RefSrcNode>();
1603 while( !toVisit.isEmpty() ) {
1604 RefSrcNode rsn = toVisit.iterator().next();
1605 toVisit.remove( rsn );
1608 Iterator<RefEdge> hrnItr = rsn.iteratorToReferencees();
1609 while( hrnItr.hasNext() ) {
1610 RefEdge edge = hrnItr.next();
1611 HeapRegionNode hrn = edge.getDst();
1613 if( !visited.contains( hrn ) ) {
1619 // get a copy of the set to iterate over because
1620 // we're going to monkey with the graph when we
1621 // identify a garbage node
1622 Set<HeapRegionNode> hrnAllPrior = new HashSet<HeapRegionNode>();
1623 Iterator<HeapRegionNode> hrnItr = id2hrn.values().iterator();
1624 while( hrnItr.hasNext() ) {
1625 hrnAllPrior.add( hrnItr.next() );
1628 Iterator<HeapRegionNode> hrnAllItr = hrnAllPrior.iterator();
1629 while( hrnAllItr.hasNext() ) {
1630 HeapRegionNode hrn = hrnAllItr.next();
1632 if( !visited.contains( hrn ) ) {
1634 // heap region nodes are compared across ReachGraph
1635 // objects by their integer ID, so when discarding
1636 // garbage nodes we must also discard entries in
1637 // the ID -> heap region hashtable.
1638 id2hrn.remove( hrn.getID() );
1640 // RefEdge objects are two-way linked between
1641 // nodes, so when a node is identified as garbage,
1642 // actively clear references to and from it so
1643 // live nodes won't have dangling RefEdge's
1646 // if we just removed the last node from an allocation
1647 // site, it should be taken out of the ReachGraph's list
1648 AllocSite as = hrn.getAllocSite();
1649 if( !hasNodesOf( as ) ) {
1650 allocSites.remove( as );
1656 protected boolean hasNodesOf( AllocSite as ) {
1657 if( id2hrn.containsKey( as.getSummary() ) ) {
1661 for( int i = 0; i < allocationDepth; ++i ) {
1662 if( id2hrn.containsKey( as.getIthOldest( i ) ) ) {
1670 ////////////////////////////////////////////////////
1672 // This global sweep is an optional step to prune
1673 // reachability sets that are not internally
1674 // consistent with the global graph. It should be
1675 // invoked after strong updates or method calls.
1677 ////////////////////////////////////////////////////
1678 public void globalSweep() {
1680 // boldB is part of the phase 1 sweep
1681 Hashtable< Integer, Hashtable<RefEdge, ReachSet> > boldB =
1682 new Hashtable< Integer, Hashtable<RefEdge, ReachSet> >();
1684 // visit every heap region to initialize alphaNew and calculate boldB
1685 Iterator itrHrns = id2hrn.entrySet().iterator();
1686 while( itrHrns.hasNext() ) {
1687 Map.Entry me = (Map.Entry) itrHrns.next();
1688 Integer hrnID = (Integer) me.getKey();
1689 HeapRegionNode hrn = (HeapRegionNode) me.getValue();
1691 // assert that this node and incoming edges have clean alphaNew
1692 // and betaNew sets, respectively
1693 assert rsetEmpty.equals( hrn.getAlphaNew() );
1695 Iterator<RefEdge> itrRers = hrn.iteratorToReferencers();
1696 while( itrRers.hasNext() ) {
1697 RefEdge edge = itrRers.next();
1698 assert rsetEmpty.equals( edge.getBetaNew() );
1701 // calculate boldB for this flagged node
1702 if( hrn.isFlagged() ) {
1704 Hashtable<RefEdge, ReachSet> boldB_f =
1705 new Hashtable<RefEdge, ReachSet>();
1707 Set<RefEdge> workSetEdges = new HashSet<RefEdge>();
1709 // initial boldB_f constraints
1710 Iterator<RefEdge> itrRees = hrn.iteratorToReferencees();
1711 while( itrRees.hasNext() ) {
1712 RefEdge edge = itrRees.next();
1714 assert !boldB.containsKey( edge );
1715 boldB_f.put( edge, edge.getBeta() );
1717 assert !workSetEdges.contains( edge );
1718 workSetEdges.add( edge );
1721 // enforce the boldB_f constraint at edges until we reach a fixed point
1722 while( !workSetEdges.isEmpty() ) {
1723 RefEdge edge = workSetEdges.iterator().next();
1724 workSetEdges.remove( edge );
1726 Iterator<RefEdge> itrPrime = edge.getDst().iteratorToReferencees();
1727 while( itrPrime.hasNext() ) {
1728 RefEdge edgePrime = itrPrime.next();
1730 ReachSet prevResult = boldB_f.get( edgePrime );
1731 ReachSet intersection = Canonical.intersection( boldB_f.get( edge ),
1735 if( prevResult == null ||
1736 Canonical.union( prevResult,
1737 intersection ).size() > prevResult.size() ) {
1739 if( prevResult == null ) {
1740 boldB_f.put( edgePrime,
1741 Canonical.union( edgePrime.getBeta(),
1746 boldB_f.put( edgePrime,
1747 Canonical.union( prevResult,
1752 workSetEdges.add( edgePrime );
1757 boldB.put( hrnID, boldB_f );
1762 // use boldB to prune hrnIDs from alpha states that are impossible
1763 // and propagate the differences backwards across edges
1764 HashSet<RefEdge> edgesForPropagation = new HashSet<RefEdge>();
1766 Hashtable<RefEdge, ChangeSet> edgePlannedChanges =
1767 new Hashtable<RefEdge, ChangeSet>();
1770 itrHrns = id2hrn.entrySet().iterator();
1771 while( itrHrns.hasNext() ) {
1772 Map.Entry me = (Map.Entry) itrHrns.next();
1773 Integer hrnID = (Integer) me.getKey();
1774 HeapRegionNode hrn = (HeapRegionNode) me.getValue();
1776 // create the inherent hrnID from a flagged region
1777 // as an exception to removal below
1778 ReachTuple rtException =
1779 ReachTuple.factory( hrnID,
1780 !hrn.isSingleObject(),
1781 ReachTuple.ARITY_ONE
1784 ChangeSet cts = ChangeSet.factory();
1786 // mark hrnIDs for removal
1787 Iterator<ReachState> stateItr = hrn.getAlpha().iterator();
1788 while( stateItr.hasNext() ) {
1789 ReachState stateOld = stateItr.next();
1791 ReachState markedHrnIDs = ReachState.factory();
1793 Iterator<ReachTuple> rtItr = stateOld.iterator();
1794 while( rtItr.hasNext() ) {
1795 ReachTuple rtOld = rtItr.next();
1797 // never remove the inherent hrnID from a flagged region
1798 // because it is trivially satisfied
1799 if( hrn.isFlagged() ) {
1800 if( rtOld == rtException ) {
1805 // does boldB_ttOld allow this hrnID?
1806 boolean foundState = false;
1807 Iterator<RefEdge> incidentEdgeItr = hrn.iteratorToReferencers();
1808 while( incidentEdgeItr.hasNext() ) {
1809 RefEdge incidentEdge = incidentEdgeItr.next();
1811 // if it isn't allowed, mark for removal
1812 Integer idOld = rtOld.getHrnID();
1813 assert id2hrn.containsKey( idOld );
1814 Hashtable<RefEdge, ReachSet> B = boldB.get( idOld );
1815 ReachSet boldB_ttOld_incident = B.get( incidentEdge );
1816 if( boldB_ttOld_incident != null &&
1817 boldB_ttOld_incident.contains( stateOld ) ) {
1823 markedHrnIDs = Canonical.add( markedHrnIDs, rtOld );
1827 // if there is nothing marked, just move on
1828 if( markedHrnIDs.isEmpty() ) {
1829 hrn.setAlphaNew( Canonical.union( hrn.getAlphaNew(),
1836 // remove all marked hrnIDs and establish a change set that should
1837 // propagate backwards over edges from this node
1838 ReachState statePruned = ReachState.factory();
1839 rtItr = stateOld.iterator();
1840 while( rtItr.hasNext() ) {
1841 ReachTuple rtOld = rtItr.next();
1843 if( !markedHrnIDs.containsTuple( rtOld ) ) {
1844 statePruned = Canonical.union( statePruned, rtOld );
1847 assert !stateOld.equals( statePruned );
1849 hrn.setAlphaNew( Canonical.union( hrn.getAlphaNew(),
1853 ChangeTuple ct = ChangeTuple.factory( stateOld,
1856 cts = Canonical.union( cts, ct );
1859 // throw change tuple set on all incident edges
1860 if( !cts.isEmpty() ) {
1861 Iterator<RefEdge> incidentEdgeItr = hrn.iteratorToReferencers();
1862 while( incidentEdgeItr.hasNext() ) {
1863 RefEdge incidentEdge = incidentEdgeItr.next();
1865 edgesForPropagation.add( incidentEdge );
1867 if( edgePlannedChanges.get( incidentEdge ) == null ) {
1868 edgePlannedChanges.put( incidentEdge, cts );
1870 edgePlannedChanges.put(
1872 Canonical.union( edgePlannedChanges.get( incidentEdge ),
1881 HashSet<RefEdge> edgesUpdated = new HashSet<RefEdge>();
1883 propagateTokensOverEdges( edgesForPropagation,
1887 // at the end of the 1st phase reference edges have
1888 // beta, betaNew that correspond to beta and betaR
1890 // commit beta<-betaNew, so beta=betaR and betaNew
1891 // will represent the beta' calculation in 2nd phase
1893 // commit alpha<-alphaNew because it won't change
1894 HashSet<RefEdge> res = new HashSet<RefEdge>();
1896 Iterator<HeapRegionNode> nodeItr = id2hrn.values().iterator();
1897 while( nodeItr.hasNext() ) {
1898 HeapRegionNode hrn = nodeItr.next();
1899 hrn.applyAlphaNew();
1900 Iterator<RefEdge> itrRes = hrn.iteratorToReferencers();
1901 while( itrRes.hasNext() ) {
1902 res.add( itrRes.next() );
1908 Iterator<RefEdge> edgeItr = res.iterator();
1909 while( edgeItr.hasNext() ) {
1910 RefEdge edge = edgeItr.next();
1911 HeapRegionNode hrn = edge.getDst();
1913 // commit results of last phase
1914 if( edgesUpdated.contains( edge ) ) {
1915 edge.applyBetaNew();
1918 // compute intial condition of 2nd phase
1919 edge.setBetaNew( Canonical.intersection( edge.getBeta(),
1925 // every edge in the graph is the initial workset
1926 Set<RefEdge> edgeWorkSet = (Set) res.clone();
1927 while( !edgeWorkSet.isEmpty() ) {
1928 RefEdge edgePrime = edgeWorkSet.iterator().next();
1929 edgeWorkSet.remove( edgePrime );
1931 RefSrcNode rsn = edgePrime.getSrc();
1932 if( !(rsn instanceof HeapRegionNode) ) {
1935 HeapRegionNode hrn = (HeapRegionNode) rsn;
1937 Iterator<RefEdge> itrEdge = hrn.iteratorToReferencers();
1938 while( itrEdge.hasNext() ) {
1939 RefEdge edge = itrEdge.next();
1941 ReachSet prevResult = edge.getBetaNew();
1942 assert prevResult != null;
1944 ReachSet intersection =
1945 Canonical.intersection( edge.getBeta(),
1946 edgePrime.getBetaNew()
1949 if( Canonical.union( prevResult,
1951 ).size() > prevResult.size() ) {
1953 Canonical.union( prevResult,
1957 edgeWorkSet.add( edge );
1962 // commit beta' (beta<-betaNew)
1963 edgeItr = res.iterator();
1964 while( edgeItr.hasNext() ) {
1965 edgeItr.next().applyBetaNew();
1971 ////////////////////////////////////////////////////
1972 // high-level merge operations
1973 ////////////////////////////////////////////////////
1974 public void merge_sameMethodContext( ReachGraph rg ) {
1975 // when merging two graphs that abstract the heap
1976 // of the same method context, we just call the
1977 // basic merge operation
1981 public void merge_diffMethodContext( ReachGraph rg ) {
1982 // when merging graphs for abstract heaps in
1983 // different method contexts we should:
1984 // 1) age the allocation sites?
1988 ////////////////////////////////////////////////////
1989 // in merge() and equals() methods the suffix A
1990 // represents the passed in graph and the suffix
1991 // B refers to the graph in this object
1992 // Merging means to take the incoming graph A and
1993 // merge it into B, so after the operation graph B
1994 // is the final result.
1995 ////////////////////////////////////////////////////
1996 protected void merge( ReachGraph rg ) {
2003 mergeRefEdges ( rg );
2004 mergeAllocSites( rg );
2007 protected void mergeNodes( ReachGraph rg ) {
2009 // start with heap region nodes
2010 Set sA = rg.id2hrn.entrySet();
2011 Iterator iA = sA.iterator();
2012 while( iA.hasNext() ) {
2013 Map.Entry meA = (Map.Entry) iA.next();
2014 Integer idA = (Integer) meA.getKey();
2015 HeapRegionNode hrnA = (HeapRegionNode) meA.getValue();
2017 // if this graph doesn't have a node the
2018 // incoming graph has, allocate it
2019 if( !id2hrn.containsKey( idA ) ) {
2020 HeapRegionNode hrnB = hrnA.copy();
2021 id2hrn.put( idA, hrnB );
2024 // otherwise this is a node present in both graphs
2025 // so make the new reachability set a union of the
2026 // nodes' reachability sets
2027 HeapRegionNode hrnB = id2hrn.get( idA );
2028 hrnB.setAlpha( Canonical.union( hrnB.getAlpha(),
2033 // if hrnB is already dirty or hrnA is dirty,
2034 // the hrnB should end up dirty: TODO
2036 if( !hrnA.isClean() ) {
2037 hrnB.setIsClean( false );
2043 // now add any variable nodes that are in graph B but
2045 sA = rg.td2vn.entrySet();
2047 while( iA.hasNext() ) {
2048 Map.Entry meA = (Map.Entry) iA.next();
2049 TempDescriptor tdA = (TempDescriptor) meA.getKey();
2050 VariableNode lnA = (VariableNode) meA.getValue();
2052 // if the variable doesn't exist in B, allocate and add it
2053 VariableNode lnB = getVariableNodeFromTemp( tdA );
2057 protected void mergeRefEdges( ReachGraph rg ) {
2059 // between heap regions
2060 Set sA = rg.id2hrn.entrySet();
2061 Iterator iA = sA.iterator();
2062 while( iA.hasNext() ) {
2063 Map.Entry meA = (Map.Entry) iA.next();
2064 Integer idA = (Integer) meA.getKey();
2065 HeapRegionNode hrnA = (HeapRegionNode) meA.getValue();
2067 Iterator<RefEdge> heapRegionsItrA = hrnA.iteratorToReferencees();
2068 while( heapRegionsItrA.hasNext() ) {
2069 RefEdge edgeA = heapRegionsItrA.next();
2070 HeapRegionNode hrnChildA = edgeA.getDst();
2071 Integer idChildA = hrnChildA.getID();
2073 // at this point we know an edge in graph A exists
2074 // idA -> idChildA, does this exist in B?
2075 assert id2hrn.containsKey( idA );
2076 HeapRegionNode hrnB = id2hrn.get( idA );
2077 RefEdge edgeToMerge = null;
2079 Iterator<RefEdge> heapRegionsItrB = hrnB.iteratorToReferencees();
2080 while( heapRegionsItrB.hasNext() &&
2081 edgeToMerge == null ) {
2083 RefEdge edgeB = heapRegionsItrB.next();
2084 HeapRegionNode hrnChildB = edgeB.getDst();
2085 Integer idChildB = hrnChildB.getID();
2087 // don't use the RefEdge.equals() here because
2088 // we're talking about existence between graphs,
2089 // not intragraph equal
2090 if( idChildB.equals( idChildA ) &&
2091 edgeB.typeAndFieldEquals( edgeA ) ) {
2093 edgeToMerge = edgeB;
2097 // if the edge from A was not found in B,
2099 if( edgeToMerge == null ) {
2100 assert id2hrn.containsKey( idChildA );
2101 HeapRegionNode hrnChildB = id2hrn.get( idChildA );
2102 edgeToMerge = edgeA.copy();
2103 edgeToMerge.setSrc( hrnB );
2104 edgeToMerge.setDst( hrnChildB );
2105 addRefEdge( hrnB, hrnChildB, edgeToMerge );
2107 // otherwise, the edge already existed in both graphs
2108 // so merge their reachability sets
2110 // just replace this beta set with the union
2111 assert edgeToMerge != null;
2112 edgeToMerge.setBeta(
2113 Canonical.union( edgeToMerge.getBeta(),
2119 if( !edgeA.isClean() ) {
2120 edgeToMerge.setIsClean( false );
2127 // and then again from variable nodes
2128 sA = rg.td2vn.entrySet();
2130 while( iA.hasNext() ) {
2131 Map.Entry meA = (Map.Entry) iA.next();
2132 TempDescriptor tdA = (TempDescriptor) meA.getKey();
2133 VariableNode vnA = (VariableNode) meA.getValue();
2135 Iterator<RefEdge> heapRegionsItrA = vnA.iteratorToReferencees();
2136 while( heapRegionsItrA.hasNext() ) {
2137 RefEdge edgeA = heapRegionsItrA.next();
2138 HeapRegionNode hrnChildA = edgeA.getDst();
2139 Integer idChildA = hrnChildA.getID();
2141 // at this point we know an edge in graph A exists
2142 // tdA -> idChildA, does this exist in B?
2143 assert td2vn.containsKey( tdA );
2144 VariableNode vnB = td2vn.get( tdA );
2145 RefEdge edgeToMerge = null;
2147 Iterator<RefEdge> heapRegionsItrB = vnB.iteratorToReferencees();
2148 while( heapRegionsItrB.hasNext() &&
2149 edgeToMerge == null ) {
2151 RefEdge edgeB = heapRegionsItrB.next();
2152 HeapRegionNode hrnChildB = edgeB.getDst();
2153 Integer idChildB = hrnChildB.getID();
2155 // don't use the RefEdge.equals() here because
2156 // we're talking about existence between graphs
2157 if( idChildB.equals( idChildA ) &&
2158 edgeB.typeAndFieldEquals( edgeA ) ) {
2160 edgeToMerge = edgeB;
2164 // if the edge from A was not found in B,
2166 if( edgeToMerge == null ) {
2167 assert id2hrn.containsKey( idChildA );
2168 HeapRegionNode hrnChildB = id2hrn.get( idChildA );
2169 edgeToMerge = edgeA.copy();
2170 edgeToMerge.setSrc( vnB );
2171 edgeToMerge.setDst( hrnChildB );
2172 addRefEdge( vnB, hrnChildB, edgeToMerge );
2174 // otherwise, the edge already existed in both graphs
2175 // so merge their reachability sets
2177 // just replace this beta set with the union
2178 edgeToMerge.setBeta( Canonical.union( edgeToMerge.getBeta(),
2184 if( !edgeA.isClean() ) {
2185 edgeToMerge.setIsClean( false );
2193 protected void mergeAllocSites( ReachGraph rg ) {
2194 allocSites.addAll( rg.allocSites );
2198 // it is necessary in the equals() member functions
2199 // to "check both ways" when comparing the data
2200 // structures of two graphs. For instance, if all
2201 // edges between heap region nodes in graph A are
2202 // present and equal in graph B it is not sufficient
2203 // to say the graphs are equal. Consider that there
2204 // may be edges in graph B that are not in graph A.
2205 // the only way to know that all edges in both graphs
2206 // are equally present is to iterate over both data
2207 // structures and compare against the other graph.
2208 public boolean equals( ReachGraph rg ) {
2214 if( !areHeapRegionNodesEqual( rg ) ) {
2218 if( !areVariableNodesEqual( rg ) ) {
2222 if( !areRefEdgesEqual( rg ) ) {
2226 // if everything is equal up to this point,
2227 // assert that allocSites is also equal--
2228 // this data is redundant but kept for efficiency
2229 assert allocSites.equals( rg.allocSites );
2235 protected boolean areHeapRegionNodesEqual( ReachGraph rg ) {
2237 if( !areallHRNinAalsoinBandequal( this, rg ) ) {
2241 if( !areallHRNinAalsoinBandequal( rg, this ) ) {
2248 static protected boolean areallHRNinAalsoinBandequal( ReachGraph rgA,
2250 Set sA = rgA.id2hrn.entrySet();
2251 Iterator iA = sA.iterator();
2252 while( iA.hasNext() ) {
2253 Map.Entry meA = (Map.Entry) iA.next();
2254 Integer idA = (Integer) meA.getKey();
2255 HeapRegionNode hrnA = (HeapRegionNode) meA.getValue();
2257 if( !rgB.id2hrn.containsKey( idA ) ) {
2261 HeapRegionNode hrnB = rgB.id2hrn.get( idA );
2262 if( !hrnA.equalsIncludingAlphaAndPreds( hrnB ) ) {
2271 protected boolean areVariableNodesEqual( ReachGraph rg ) {
2273 if( !areallVNinAalsoinBandequal( this, rg ) ) {
2277 if( !areallVNinAalsoinBandequal( rg, this ) ) {
2284 static protected boolean areallVNinAalsoinBandequal( ReachGraph rgA,
2286 Set sA = rgA.td2vn.entrySet();
2287 Iterator iA = sA.iterator();
2288 while( iA.hasNext() ) {
2289 Map.Entry meA = (Map.Entry) iA.next();
2290 TempDescriptor tdA = (TempDescriptor) meA.getKey();
2292 if( !rgB.td2vn.containsKey( tdA ) ) {
2301 protected boolean areRefEdgesEqual( ReachGraph rg ) {
2302 if( !areallREinAandBequal( this, rg ) ) {
2309 static protected boolean areallREinAandBequal( ReachGraph rgA,
2312 // check all the heap region->heap region edges
2313 Set sA = rgA.id2hrn.entrySet();
2314 Iterator iA = sA.iterator();
2315 while( iA.hasNext() ) {
2316 Map.Entry meA = (Map.Entry) iA.next();
2317 Integer idA = (Integer) meA.getKey();
2318 HeapRegionNode hrnA = (HeapRegionNode) meA.getValue();
2320 // we should have already checked that the same
2321 // heap regions exist in both graphs
2322 assert rgB.id2hrn.containsKey( idA );
2324 if( !areallREfromAequaltoB( rgA, hrnA, rgB ) ) {
2328 // then check every edge in B for presence in A, starting
2329 // from the same parent HeapRegionNode
2330 HeapRegionNode hrnB = rgB.id2hrn.get( idA );
2332 if( !areallREfromAequaltoB( rgB, hrnB, rgA ) ) {
2337 // then check all the variable->heap region edges
2338 sA = rgA.td2vn.entrySet();
2340 while( iA.hasNext() ) {
2341 Map.Entry meA = (Map.Entry) iA.next();
2342 TempDescriptor tdA = (TempDescriptor) meA.getKey();
2343 VariableNode vnA = (VariableNode) meA.getValue();
2345 // we should have already checked that the same
2346 // label nodes exist in both graphs
2347 assert rgB.td2vn.containsKey( tdA );
2349 if( !areallREfromAequaltoB( rgA, vnA, rgB ) ) {
2353 // then check every edge in B for presence in A, starting
2354 // from the same parent VariableNode
2355 VariableNode vnB = rgB.td2vn.get( tdA );
2357 if( !areallREfromAequaltoB( rgB, vnB, rgA ) ) {
2366 static protected boolean areallREfromAequaltoB( ReachGraph rgA,
2370 Iterator<RefEdge> itrA = rnA.iteratorToReferencees();
2371 while( itrA.hasNext() ) {
2372 RefEdge edgeA = itrA.next();
2373 HeapRegionNode hrnChildA = edgeA.getDst();
2374 Integer idChildA = hrnChildA.getID();
2376 assert rgB.id2hrn.containsKey( idChildA );
2378 // at this point we know an edge in graph A exists
2379 // rnA -> idChildA, does this exact edge exist in B?
2380 boolean edgeFound = false;
2382 RefSrcNode rnB = null;
2383 if( rnA instanceof HeapRegionNode ) {
2384 HeapRegionNode hrnA = (HeapRegionNode) rnA;
2385 rnB = rgB.id2hrn.get( hrnA.getID() );
2387 VariableNode vnA = (VariableNode) rnA;
2388 rnB = rgB.td2vn.get( vnA.getTempDescriptor() );
2391 Iterator<RefEdge> itrB = rnB.iteratorToReferencees();
2392 while( itrB.hasNext() ) {
2393 RefEdge edgeB = itrB.next();
2394 HeapRegionNode hrnChildB = edgeB.getDst();
2395 Integer idChildB = hrnChildB.getID();
2397 if( idChildA.equals( idChildB ) &&
2398 edgeA.typeAndFieldEquals( edgeB ) ) {
2400 // there is an edge in the right place with the right field,
2401 // but do they have the same attributes?
2402 if( edgeA.getBeta().equals( edgeB.getBeta() ) &&
2403 edgeA.equalsPreds( edgeB )
2420 // this analysis no longer has the "match anything"
2421 // type which was represented by null
2422 protected TypeDescriptor mostSpecificType( TypeDescriptor td1,
2423 TypeDescriptor td2 ) {
2427 if( td1.isNull() ) {
2430 if( td2.isNull() ) {
2433 return typeUtil.mostSpecific( td1, td2 );
2436 protected TypeDescriptor mostSpecificType( TypeDescriptor td1,
2438 TypeDescriptor td3 ) {
2440 return mostSpecificType( td1,
2441 mostSpecificType( td2, td3 )
2445 protected TypeDescriptor mostSpecificType( TypeDescriptor td1,
2448 TypeDescriptor td4 ) {
2450 return mostSpecificType( mostSpecificType( td1, td2 ),
2451 mostSpecificType( td3, td4 )
2455 protected boolean isSuperiorType( TypeDescriptor possibleSuper,
2456 TypeDescriptor possibleChild ) {
2457 assert possibleSuper != null;
2458 assert possibleChild != null;
2460 if( possibleSuper.isNull() ||
2461 possibleChild.isNull() ) {
2465 return typeUtil.isSuperorType( possibleSuper, possibleChild );
2469 protected boolean hasMatchingField( HeapRegionNode src,
2472 TypeDescriptor tdSrc = src.getType();
2473 assert tdSrc != null;
2475 if( tdSrc.isArray() ) {
2476 TypeDescriptor td = edge.getType();
2479 TypeDescriptor tdSrcDeref = tdSrc.dereference();
2480 assert tdSrcDeref != null;
2482 if( !typeUtil.isSuperorType( tdSrcDeref, td ) ) {
2486 return edge.getField().equals( DisjointAnalysis.arrayElementFieldName );
2489 // if it's not a class, it doesn't have any fields to match
2490 if( !tdSrc.isClass() ) {
2494 ClassDescriptor cd = tdSrc.getClassDesc();
2495 while( cd != null ) {
2496 Iterator fieldItr = cd.getFields();
2498 while( fieldItr.hasNext() ) {
2499 FieldDescriptor fd = (FieldDescriptor) fieldItr.next();
2501 if( fd.getType().equals( edge.getType() ) &&
2502 fd.getSymbol().equals( edge.getField() ) ) {
2507 cd = cd.getSuperDesc();
2510 // otherwise it is a class with fields
2511 // but we didn't find a match
2515 protected boolean hasMatchingType( RefEdge edge,
2516 HeapRegionNode dst ) {
2518 // if the region has no type, matches everything
2519 TypeDescriptor tdDst = dst.getType();
2520 assert tdDst != null;
2522 // if the type is not a class or an array, don't
2523 // match because primitives are copied, no aliases
2524 ClassDescriptor cdDst = tdDst.getClassDesc();
2525 if( cdDst == null && !tdDst.isArray() ) {
2529 // if the edge type is null, it matches everything
2530 TypeDescriptor tdEdge = edge.getType();
2531 assert tdEdge != null;
2533 return typeUtil.isSuperorType( tdEdge, tdDst );
2538 public void writeGraph( String graphName,
2539 boolean writeLabels,
2540 boolean labelSelect,
2541 boolean pruneGarbage,
2542 boolean writeReferencers,
2543 boolean hideSubsetReachability,
2544 boolean hideEdgeTaints
2545 ) throws java.io.IOException {
2546 writeGraph( graphName,
2551 hideSubsetReachability,
2557 public void writeGraph( String graphName,
2558 boolean writeLabels,
2559 boolean labelSelect,
2560 boolean pruneGarbage,
2561 boolean writeReferencers,
2562 boolean hideSubsetReachability,
2563 boolean hideEdgeTaints,
2564 Set<HeapRegionNode> callerNodesCopiedToCallee,
2565 Set<RefEdge> callerEdgesCopiedToCallee
2566 ) throws java.io.IOException {
2568 // remove all non-word characters from the graph name so
2569 // the filename and identifier in dot don't cause errors
2570 graphName = graphName.replaceAll( "[\\W]", "" );
2573 new BufferedWriter( new FileWriter( graphName+".dot" ) );
2575 bw.write( "digraph "+graphName+" {\n" );
2578 // this is an optional step to form the callee-reachable
2579 // "cut-out" into a DOT cluster for visualization
2580 if( callerNodesCopiedToCallee != null ) {
2582 bw.write( " subgraph cluster0 {\n" );
2583 bw.write( " color=blue;\n" );
2585 Iterator i = id2hrn.entrySet().iterator();
2586 while( i.hasNext() ) {
2587 Map.Entry me = (Map.Entry) i.next();
2588 HeapRegionNode hrn = (HeapRegionNode) me.getValue();
2590 if( callerNodesCopiedToCallee.contains( hrn ) ) {
2591 bw.write( " "+hrn.toString()+
2592 hrn.toStringDOT( hideSubsetReachability )+
2602 Set<HeapRegionNode> visited = new HashSet<HeapRegionNode>();
2604 // then visit every heap region node
2605 Iterator i = id2hrn.entrySet().iterator();
2606 while( i.hasNext() ) {
2607 Map.Entry me = (Map.Entry) i.next();
2608 HeapRegionNode hrn = (HeapRegionNode) me.getValue();
2610 // only visit nodes worth writing out--for instance
2611 // not every node at an allocation is referenced
2612 // (think of it as garbage-collected), etc.
2613 if( !pruneGarbage ||
2614 (hrn.isFlagged() && hrn.getID() > 0) ||
2615 hrn.getDescription().startsWith( "param" ) ||
2616 hrn.isOutOfContext()
2619 if( !visited.contains( hrn ) ) {
2620 traverseHeapRegionNodes( hrn,
2625 hideSubsetReachability,
2627 callerNodesCopiedToCallee,
2628 callerEdgesCopiedToCallee );
2633 bw.write( " graphTitle[label=\""+graphName+"\",shape=box];\n" );
2636 // then visit every label node, useful for debugging
2638 i = td2vn.entrySet().iterator();
2639 while( i.hasNext() ) {
2640 Map.Entry me = (Map.Entry) i.next();
2641 VariableNode vn = (VariableNode) me.getValue();
2644 String labelStr = vn.getTempDescriptorString();
2645 if( labelStr.startsWith("___temp") ||
2646 labelStr.startsWith("___dst") ||
2647 labelStr.startsWith("___srctmp") ||
2648 labelStr.startsWith("___neverused")
2654 Iterator<RefEdge> heapRegionsItr = vn.iteratorToReferencees();
2655 while( heapRegionsItr.hasNext() ) {
2656 RefEdge edge = heapRegionsItr.next();
2657 HeapRegionNode hrn = edge.getDst();
2659 if( pruneGarbage && !visited.contains( hrn ) ) {
2660 traverseHeapRegionNodes( hrn,
2665 hideSubsetReachability,
2667 callerNodesCopiedToCallee,
2668 callerEdgesCopiedToCallee );
2671 bw.write( " "+vn.toString()+
2672 " -> "+hrn.toString()+
2673 edge.toStringDOT( hideSubsetReachability, "" )+
2683 protected void traverseHeapRegionNodes( HeapRegionNode hrn,
2686 Set<HeapRegionNode> visited,
2687 boolean writeReferencers,
2688 boolean hideSubsetReachability,
2689 boolean hideEdgeTaints,
2690 Set<HeapRegionNode> callerNodesCopiedToCallee,
2691 Set<RefEdge> callerEdgesCopiedToCallee
2692 ) throws java.io.IOException {
2694 if( visited.contains( hrn ) ) {
2699 // if we're drawing the callee-view subgraph, only
2700 // write out the node info if it hasn't already been
2702 if( callerNodesCopiedToCallee == null ||
2703 !callerNodesCopiedToCallee.contains( hrn )
2705 bw.write( " "+hrn.toString()+
2706 hrn.toStringDOT( hideSubsetReachability )+
2710 Iterator<RefEdge> childRegionsItr = hrn.iteratorToReferencees();
2711 while( childRegionsItr.hasNext() ) {
2712 RefEdge edge = childRegionsItr.next();
2713 HeapRegionNode hrnChild = edge.getDst();
2715 if( callerEdgesCopiedToCallee != null &&
2716 callerEdgesCopiedToCallee.contains( hrn )
2718 bw.write( " "+hrn.toString()+
2719 " -> "+hrnChild.toString()+
2720 edge.toStringDOT( hideSubsetReachability, ",color=blue" )+
2723 bw.write( " "+hrn.toString()+
2724 " -> "+hrnChild.toString()+
2725 edge.toStringDOT( hideSubsetReachability, "" )+
2729 traverseHeapRegionNodes( hrnChild,
2734 hideSubsetReachability,
2736 callerNodesCopiedToCallee,
2737 callerEdgesCopiedToCallee );