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 = new ReachState().makeCanonical();
20 protected static final ReachSet rsetEmpty = new ReachSet().makeCanonical();
21 protected static final ReachSet rsetWithEmptyState = new ReachSet( rstateEmpty ).makeCanonical();
23 // predicate constants
24 protected static final ExistPredTrue predTrue = new ExistPredTrue();
25 protected static final ExistPredSet predsEmpty = new ExistPredSet().makeCanonical();
26 protected static final ExistPredSet predsTrue = new ExistPredSet( predTrue ).makeCanonical();
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 ) {
105 inherent = new ReachSet(
112 inherent = rsetWithEmptyState;
116 if( alpha == null ) {
120 if( preds == null ) {
121 // TODO: do this right? For out-of-context nodes?
122 preds = new ExistPredSet().makeCanonical();
125 HeapRegionNode hrn = new HeapRegionNode( id,
136 id2hrn.put( id, hrn );
142 ////////////////////////////////////////////////
144 // Low-level referencee and referencer methods
146 // These methods provide the lowest level for
147 // creating references between reachability nodes
148 // and handling the details of maintaining both
149 // list of referencers and referencees.
151 ////////////////////////////////////////////////
152 protected void addRefEdge( RefSrcNode referencer,
153 HeapRegionNode referencee,
155 assert referencer != null;
156 assert referencee != null;
158 assert edge.getSrc() == referencer;
159 assert edge.getDst() == referencee;
161 referencer.addReferencee( edge );
162 referencee.addReferencer( edge );
165 protected void removeRefEdge( RefEdge e ) {
166 removeRefEdge( e.getSrc(),
172 protected void removeRefEdge( RefSrcNode referencer,
173 HeapRegionNode referencee,
176 assert referencer != null;
177 assert referencee != null;
179 RefEdge edge = referencer.getReferenceTo( referencee,
183 assert edge == referencee.getReferenceFrom( referencer,
187 referencer.removeReferencee( edge );
188 referencee.removeReferencer( edge );
191 protected void clearRefEdgesFrom( RefSrcNode referencer,
194 boolean removeAll ) {
195 assert referencer != null;
197 // get a copy of the set to iterate over, otherwise
198 // we will be trying to take apart the set as we
199 // are iterating over it, which won't work
200 Iterator<RefEdge> i = referencer.iteratorToReferenceesClone();
201 while( i.hasNext() ) {
202 RefEdge edge = i.next();
205 (edge.typeEquals( type ) && edge.fieldEquals( field ))
208 HeapRegionNode referencee = edge.getDst();
210 removeRefEdge( referencer,
218 protected void clearRefEdgesTo( HeapRegionNode referencee,
221 boolean removeAll ) {
222 assert referencee != null;
224 // get a copy of the set to iterate over, otherwise
225 // we will be trying to take apart the set as we
226 // are iterating over it, which won't work
227 Iterator<RefEdge> i = referencee.iteratorToReferencersClone();
228 while( i.hasNext() ) {
229 RefEdge edge = i.next();
232 (edge.typeEquals( type ) && edge.fieldEquals( field ))
235 RefSrcNode referencer = edge.getSrc();
237 removeRefEdge( referencer,
246 ////////////////////////////////////////////////////
248 // Assignment Operation Methods
250 // These methods are high-level operations for
251 // modeling program assignment statements using
252 // the low-level reference create/remove methods
255 ////////////////////////////////////////////////////
257 public void assignTempXEqualToTempY( TempDescriptor x,
259 assignTempXEqualToCastedTempY( x, y, null );
262 public void assignTempXEqualToCastedTempY( TempDescriptor x,
264 TypeDescriptor tdCast ) {
266 VariableNode lnX = getVariableNodeFromTemp( x );
267 VariableNode lnY = getVariableNodeFromTemp( y );
269 clearRefEdgesFrom( lnX, null, null, true );
271 // note it is possible that the types of temps in the
272 // flat node to analyze will reveal that some typed
273 // edges in the reachability graph are impossible
274 Set<RefEdge> impossibleEdges = new HashSet<RefEdge>();
276 Iterator<RefEdge> itrYhrn = lnY.iteratorToReferencees();
277 while( itrYhrn.hasNext() ) {
278 RefEdge edgeY = itrYhrn.next();
279 HeapRegionNode referencee = edgeY.getDst();
280 RefEdge edgeNew = edgeY.copy();
282 if( !isSuperiorType( x.getType(), edgeY.getType() ) ) {
283 impossibleEdges.add( edgeY );
287 edgeNew.setSrc( lnX );
289 if( tdCast == null ) {
290 edgeNew.setType( mostSpecificType( y.getType(),
296 edgeNew.setType( mostSpecificType( y.getType(),
298 referencee.getType(),
304 edgeNew.setField( null );
306 addRefEdge( lnX, referencee, edgeNew );
309 Iterator<RefEdge> itrImp = impossibleEdges.iterator();
310 while( itrImp.hasNext() ) {
311 RefEdge edgeImp = itrImp.next();
312 removeRefEdge( edgeImp );
317 public void assignTempXEqualToTempYFieldF( TempDescriptor x,
319 FieldDescriptor f ) {
320 VariableNode lnX = getVariableNodeFromTemp( x );
321 VariableNode lnY = getVariableNodeFromTemp( y );
323 clearRefEdgesFrom( lnX, null, null, true );
325 // note it is possible that the types of temps in the
326 // flat node to analyze will reveal that some typed
327 // edges in the reachability graph are impossible
328 Set<RefEdge> impossibleEdges = new HashSet<RefEdge>();
330 Iterator<RefEdge> itrYhrn = lnY.iteratorToReferencees();
331 while( itrYhrn.hasNext() ) {
332 RefEdge edgeY = itrYhrn.next();
333 HeapRegionNode hrnY = edgeY.getDst();
334 ReachSet betaY = edgeY.getBeta();
336 Iterator<RefEdge> itrHrnFhrn = hrnY.iteratorToReferencees();
337 while( itrHrnFhrn.hasNext() ) {
338 RefEdge edgeHrn = itrHrnFhrn.next();
339 HeapRegionNode hrnHrn = edgeHrn.getDst();
340 ReachSet betaHrn = edgeHrn.getBeta();
342 // prune edges that are not a matching field
343 if( edgeHrn.getType() != null &&
344 !edgeHrn.getField().equals( f.getSymbol() )
349 // check for impossible edges
350 if( !isSuperiorType( x.getType(), edgeHrn.getType() ) ) {
351 impossibleEdges.add( edgeHrn );
355 TypeDescriptor tdNewEdge =
356 mostSpecificType( edgeHrn.getType(),
360 RefEdge edgeNew = new RefEdge( lnX,
364 betaY.intersection( betaHrn ),
368 addRefEdge( lnX, hrnHrn, edgeNew );
372 Iterator<RefEdge> itrImp = impossibleEdges.iterator();
373 while( itrImp.hasNext() ) {
374 RefEdge edgeImp = itrImp.next();
375 removeRefEdge( edgeImp );
378 // anytime you might remove edges between heap regions
379 // you must global sweep to clean up broken reachability
380 if( !impossibleEdges.isEmpty() ) {
381 if( !DISABLE_GLOBAL_SWEEP ) {
388 public void assignTempXFieldFEqualToTempY( TempDescriptor x,
392 VariableNode lnX = getVariableNodeFromTemp( x );
393 VariableNode lnY = getVariableNodeFromTemp( y );
395 HashSet<HeapRegionNode> nodesWithNewAlpha = new HashSet<HeapRegionNode>();
396 HashSet<RefEdge> edgesWithNewBeta = new HashSet<RefEdge>();
398 // note it is possible that the types of temps in the
399 // flat node to analyze will reveal that some typed
400 // edges in the reachability graph are impossible
401 Set<RefEdge> impossibleEdges = new HashSet<RefEdge>();
403 // first look for possible strong updates and remove those edges
404 boolean strongUpdate = false;
406 Iterator<RefEdge> itrXhrn = lnX.iteratorToReferencees();
407 while( itrXhrn.hasNext() ) {
408 RefEdge edgeX = itrXhrn.next();
409 HeapRegionNode hrnX = edgeX.getDst();
411 // we can do a strong update here if one of two cases holds
413 f != DisjointAnalysis.getArrayField( f.getType() ) &&
414 ( (hrnX.getNumReferencers() == 1) || // case 1
415 (hrnX.isSingleObject() && lnX.getNumReferencees() == 1) // case 2
418 if( !DISABLE_STRONG_UPDATES ) {
420 clearRefEdgesFrom( hrnX, f.getType(), f.getSymbol(), false );
425 // then do all token propagation
426 itrXhrn = lnX.iteratorToReferencees();
427 while( itrXhrn.hasNext() ) {
428 RefEdge edgeX = itrXhrn.next();
429 HeapRegionNode hrnX = edgeX.getDst();
430 ReachSet betaX = edgeX.getBeta();
431 ReachSet R = hrnX.getAlpha().intersection( edgeX.getBeta() );
433 Iterator<RefEdge> itrYhrn = lnY.iteratorToReferencees();
434 while( itrYhrn.hasNext() ) {
435 RefEdge edgeY = itrYhrn.next();
436 HeapRegionNode hrnY = edgeY.getDst();
437 ReachSet O = edgeY.getBeta();
439 // check for impossible edges
440 if( !isSuperiorType( f.getType(), edgeY.getType() ) ) {
441 impossibleEdges.add( edgeY );
445 // propagate tokens over nodes starting from hrnSrc, and it will
446 // take care of propagating back up edges from any touched nodes
447 ChangeSet Cy = O.unionUpArityToChangeSet( R );
448 propagateTokensOverNodes( hrnY, Cy, nodesWithNewAlpha, edgesWithNewBeta );
450 // then propagate back just up the edges from hrn
451 ChangeSet Cx = R.unionUpArityToChangeSet(O);
452 HashSet<RefEdge> todoEdges = new HashSet<RefEdge>();
454 Hashtable<RefEdge, ChangeSet> edgePlannedChanges =
455 new Hashtable<RefEdge, ChangeSet>();
457 Iterator<RefEdge> referItr = hrnX.iteratorToReferencers();
458 while( referItr.hasNext() ) {
459 RefEdge edgeUpstream = referItr.next();
460 todoEdges.add( edgeUpstream );
461 edgePlannedChanges.put( edgeUpstream, Cx );
464 propagateTokensOverEdges( todoEdges,
471 // apply the updates to reachability
472 Iterator<HeapRegionNode> nodeItr = nodesWithNewAlpha.iterator();
473 while( nodeItr.hasNext() ) {
474 nodeItr.next().applyAlphaNew();
477 Iterator<RefEdge> edgeItr = edgesWithNewBeta.iterator();
478 while( edgeItr.hasNext() ) {
479 edgeItr.next().applyBetaNew();
483 // then go back through and add the new edges
484 itrXhrn = lnX.iteratorToReferencees();
485 while( itrXhrn.hasNext() ) {
486 RefEdge edgeX = itrXhrn.next();
487 HeapRegionNode hrnX = edgeX.getDst();
489 Iterator<RefEdge> itrYhrn = lnY.iteratorToReferencees();
490 while( itrYhrn.hasNext() ) {
491 RefEdge edgeY = itrYhrn.next();
492 HeapRegionNode hrnY = edgeY.getDst();
494 // skip impossible edges here, we already marked them
495 // when computing reachability propagations above
496 if( !isSuperiorType( f.getType(), edgeY.getType() ) ) {
500 // prepare the new reference edge hrnX.f -> hrnY
501 TypeDescriptor tdNewEdge =
502 mostSpecificType( y.getType(),
507 RefEdge edgeNew = new RefEdge( hrnX,
511 edgeY.getBeta().pruneBy( hrnX.getAlpha() ),
515 // look to see if an edge with same field exists
516 // and merge with it, otherwise just add the edge
517 RefEdge edgeExisting = hrnX.getReferenceTo( hrnY,
521 if( edgeExisting != null ) {
522 edgeExisting.setBeta(
523 edgeExisting.getBeta().union( edgeNew.getBeta() )
525 edgeExisting.setPreds(
526 edgeExisting.getPreds().join( edgeNew.getPreds() )
530 addRefEdge( hrnX, hrnY, edgeNew );
535 Iterator<RefEdge> itrImp = impossibleEdges.iterator();
536 while( itrImp.hasNext() ) {
537 RefEdge edgeImp = itrImp.next();
538 removeRefEdge( edgeImp );
541 // if there was a strong update, make sure to improve
542 // reachability with a global sweep
543 if( strongUpdate || !impossibleEdges.isEmpty() ) {
544 if( !DISABLE_GLOBAL_SWEEP ) {
551 public void assignReturnEqualToTemp( TempDescriptor x ) {
553 VariableNode lnR = getVariableNodeFromTemp( tdReturn );
554 VariableNode lnX = getVariableNodeFromTemp( x );
556 clearRefEdgesFrom( lnR, null, null, true );
558 Iterator<RefEdge> itrXhrn = lnX.iteratorToReferencees();
559 while( itrXhrn.hasNext() ) {
560 RefEdge edgeX = itrXhrn.next();
561 HeapRegionNode referencee = edgeX.getDst();
562 RefEdge edgeNew = edgeX.copy();
563 edgeNew.setSrc( lnR );
565 addRefEdge( lnR, referencee, edgeNew );
570 public void assignTempEqualToNewAlloc( TempDescriptor x,
577 // after the age operation the newest (or zero-ith oldest)
578 // node associated with the allocation site should have
579 // no references to it as if it were a newly allocated
581 Integer idNewest = as.getIthOldest( 0 );
582 HeapRegionNode hrnNewest = id2hrn.get( idNewest );
583 assert hrnNewest != null;
585 VariableNode lnX = getVariableNodeFromTemp( x );
586 clearRefEdgesFrom( lnX, null, null, true );
588 // make a new reference to allocated node
589 TypeDescriptor type = as.getType();
592 new RefEdge( lnX, // source
596 hrnNewest.getAlpha(), // beta
597 predsTrue // predicates
600 addRefEdge( lnX, hrnNewest, edgeNew );
604 // use the allocation site (unique to entire analysis) to
605 // locate the heap region nodes in this reachability graph
606 // that should be aged. The process models the allocation
607 // of new objects and collects all the oldest allocations
608 // in a summary node to allow for a finite analysis
610 // There is an additional property of this method. After
611 // running it on a particular reachability graph (many graphs
612 // may have heap regions related to the same allocation site)
613 // the heap region node objects in this reachability graph will be
614 // allocated. Therefore, after aging a graph for an allocation
615 // site, attempts to retrieve the heap region nodes using the
616 // integer id's contained in the allocation site should always
617 // return non-null heap regions.
618 public void age( AllocSite as ) {
620 // keep track of allocation sites that are represented
621 // in this graph for efficiency with other operations
622 allocSites.add( as );
624 // if there is a k-th oldest node, it merges into
626 Integer idK = as.getOldest();
627 if( id2hrn.containsKey( idK ) ) {
628 HeapRegionNode hrnK = id2hrn.get( idK );
630 // retrieve the summary node, or make it
632 HeapRegionNode hrnSummary = getSummaryNode( as );
634 mergeIntoSummary( hrnK, hrnSummary );
637 // move down the line of heap region nodes
638 // clobbering the ith and transferring all references
639 // to and from i-1 to node i.
640 for( int i = allocationDepth - 1; i > 0; --i ) {
642 // if the target (ith) node exists, clobber it
643 // whether the i-1 node exists or not
644 Integer idIth = as.getIthOldest( i );
645 if( id2hrn.containsKey( idIth ) ) {
646 HeapRegionNode hrnI = id2hrn.get( idIth );
648 // clear all references in and out
649 clearRefEdgesFrom( hrnI, null, null, true );
650 clearRefEdgesTo ( hrnI, null, null, true );
653 // only do the transfer if the i-1 node exists
654 Integer idImin1th = as.getIthOldest( i - 1 );
655 if( id2hrn.containsKey( idImin1th ) ) {
656 HeapRegionNode hrnImin1 = id2hrn.get( idImin1th );
658 // either retrieve or make target of transfer
659 HeapRegionNode hrnI = getIthNode( as, i );
661 transferOnto( hrnImin1, hrnI );
666 // as stated above, the newest node should have had its
667 // references moved over to the second oldest, so we wipe newest
668 // in preparation for being the new object to assign something to
669 HeapRegionNode hrn0 = getIthNode( as, 0 );
670 clearRefEdgesFrom( hrn0, null, null, true );
671 clearRefEdgesTo ( hrn0, null, null, true );
673 // now tokens in reachability sets need to "age" also
674 Iterator itrAllVariableNodes = td2vn.entrySet().iterator();
675 while( itrAllVariableNodes.hasNext() ) {
676 Map.Entry me = (Map.Entry) itrAllVariableNodes.next();
677 VariableNode ln = (VariableNode) me.getValue();
679 Iterator<RefEdge> itrEdges = ln.iteratorToReferencees();
680 while( itrEdges.hasNext() ) {
681 ageTokens(as, itrEdges.next() );
685 Iterator itrAllHRNodes = id2hrn.entrySet().iterator();
686 while( itrAllHRNodes.hasNext() ) {
687 Map.Entry me = (Map.Entry) itrAllHRNodes.next();
688 HeapRegionNode hrnToAge = (HeapRegionNode) me.getValue();
690 ageTokens( as, hrnToAge );
692 Iterator<RefEdge> itrEdges = hrnToAge.iteratorToReferencees();
693 while( itrEdges.hasNext() ) {
694 ageTokens( as, itrEdges.next() );
699 // after tokens have been aged, reset newest node's reachability
700 // and a brand new node has a "true" predicate
701 hrn0.setAlpha( hrn0.getInherent() );
702 hrn0.setPreds( predsTrue );
706 // either retrieve or create the needed heap region node
707 protected HeapRegionNode getSummaryNode( AllocSite as ) {
709 Integer idSummary = as.getSummary();
710 HeapRegionNode hrnSummary = id2hrn.get( idSummary );
712 if( hrnSummary == null ) {
714 boolean hasFlags = false;
715 if( as.getType().isClass() ) {
716 hasFlags = as.getType().getClassDesc().hasFlags();
720 hasFlags = as.getFlag();
723 String strDesc = as.toStringForDOT()+"\\nsummary";
725 createNewHeapRegionNode( idSummary, // id or null to generate a new one
726 false, // single object?
728 hasFlags, // flagged?
729 false, // out-of-context?
730 as.getType(), // type
731 as, // allocation site
732 null, // inherent reach
733 null, // current reach
734 predsEmpty, // predicates
735 strDesc // description
742 // either retrieve or create the needed heap region node
743 protected HeapRegionNode getIthNode( AllocSite as, Integer i ) {
745 Integer idIth = as.getIthOldest( i );
746 HeapRegionNode hrnIth = id2hrn.get( idIth );
748 if( hrnIth == null ) {
750 boolean hasFlags = false;
751 if( as.getType().isClass() ) {
752 hasFlags = as.getType().getClassDesc().hasFlags();
756 hasFlags = as.getFlag();
759 String strDesc = as.toStringForDOT()+"\\n"+i+" oldest";
760 hrnIth = createNewHeapRegionNode( idIth, // id or null to generate a new one
761 true, // single object?
763 hasFlags, // flagged?
764 false, // out-of-context?
765 as.getType(), // type
766 as, // allocation site
767 null, // inherent reach
768 null, // current reach
769 predsEmpty, // predicates
770 strDesc // description
778 protected HeapRegionNode getShadowSummaryNode( AllocSite as ) {
780 Integer idShadowSummary = as.getSummaryShadow();
781 HeapRegionNode hrnShadowSummary = id2hrn.get( idShadowSummary );
783 if( hrnShadowSummary == null ) {
785 boolean hasFlags = false;
786 if( as.getType().isClass() ) {
787 hasFlags = as.getType().getClassDesc().hasFlags();
791 hasFlags = as.getFlag();
794 String strDesc = as+"\\n"+as.getType()+"\\nshadowSum";
796 createNewHeapRegionNode( idShadowSummary, // id or null to generate a new one
797 false, // single object?
799 hasFlags, // flagged?
800 false, // out-of-context?
801 as.getType(), // type
802 as, // allocation site
803 null, // inherent reach
804 null, // current reach
805 predsEmpty, // predicates
806 strDesc // description
809 for( int i = 0; i < as.getAllocationDepth(); ++i ) {
810 Integer idShadowIth = as.getIthOldestShadow( i );
811 assert !id2hrn.containsKey( idShadowIth );
812 strDesc = as+"\\n"+as.getType()+"\\n"+i+" shadow";
813 createNewHeapRegionNode( idShadowIth, // id or null to generate a new one
814 true, // single object?
816 hasFlags, // flagged?
817 false, // out-of-context?
818 as.getType(), // type
819 as, // allocation site
820 null, // inherent reach
821 null, // current reach
822 predsEmpty, // predicates
823 strDesc // description
828 return hrnShadowSummary;
832 protected void mergeIntoSummary( HeapRegionNode hrn,
833 HeapRegionNode hrnSummary ) {
834 assert hrnSummary.isNewSummary();
836 // transfer references _from_ hrn over to hrnSummary
837 Iterator<RefEdge> itrReferencee = hrn.iteratorToReferencees();
838 while( itrReferencee.hasNext() ) {
839 RefEdge edge = itrReferencee.next();
840 RefEdge edgeMerged = edge.copy();
841 edgeMerged.setSrc( hrnSummary );
843 HeapRegionNode hrnReferencee = edge.getDst();
844 RefEdge edgeSummary =
845 hrnSummary.getReferenceTo( hrnReferencee,
850 if( edgeSummary == null ) {
851 // the merge is trivial, nothing to be done
853 // otherwise an edge from the referencer to hrnSummary exists already
854 // and the edge referencer->hrn should be merged with it
855 edgeMerged.setBeta( edgeMerged.getBeta().union( edgeSummary.getBeta() ) );
856 edgeMerged.setPreds( edgeMerged.getPreds().join( edgeSummary.getPreds() ) );
859 addRefEdge( hrnSummary, hrnReferencee, edgeMerged );
862 // next transfer references _to_ hrn over to hrnSummary
863 Iterator<RefEdge> itrReferencer = hrn.iteratorToReferencers();
864 while( itrReferencer.hasNext() ) {
865 RefEdge edge = itrReferencer.next();
866 RefEdge edgeMerged = edge.copy();
867 edgeMerged.setDst( hrnSummary );
869 RefSrcNode onReferencer = edge.getSrc();
870 RefEdge edgeSummary =
871 onReferencer.getReferenceTo( hrnSummary,
876 if( edgeSummary == null ) {
877 // the merge is trivial, nothing to be done
879 // otherwise an edge from the referencer to alpha_S exists already
880 // and the edge referencer->alpha_K should be merged with it
881 edgeMerged.setBeta( edgeMerged.getBeta().union( edgeSummary.getBeta() ) );
882 edgeMerged.setPreds( edgeMerged.getPreds().join( edgeSummary.getPreds() ) );
885 addRefEdge( onReferencer, hrnSummary, edgeMerged );
888 // then merge hrn reachability into hrnSummary
889 hrnSummary.setAlpha( hrnSummary.getAlpha().union( hrn.getAlpha() ) );
893 protected void transferOnto( HeapRegionNode hrnA,
894 HeapRegionNode hrnB ) {
896 // clear references in and out of node b
897 clearRefEdgesFrom( hrnB, null, null, true );
898 clearRefEdgesTo ( hrnB, null, null, true );
900 // copy each edge in and out of A to B
901 Iterator<RefEdge> itrReferencee = hrnA.iteratorToReferencees();
902 while( itrReferencee.hasNext() ) {
903 RefEdge edge = itrReferencee.next();
904 HeapRegionNode hrnReferencee = edge.getDst();
905 RefEdge edgeNew = edge.copy();
906 edgeNew.setSrc( hrnB );
908 addRefEdge( hrnB, hrnReferencee, edgeNew );
911 Iterator<RefEdge> itrReferencer = hrnA.iteratorToReferencers();
912 while( itrReferencer.hasNext() ) {
913 RefEdge edge = itrReferencer.next();
914 RefSrcNode onReferencer = edge.getSrc();
915 RefEdge edgeNew = edge.copy();
916 edgeNew.setDst( hrnB );
918 addRefEdge( onReferencer, hrnB, edgeNew );
921 // replace hrnB reachability and preds with hrnA's
922 hrnB.setAlpha( hrnA.getAlpha() );
923 hrnB.setPreds( hrnA.getPreds() );
927 protected void ageTokens( AllocSite as, RefEdge edge ) {
928 edge.setBeta( edge.getBeta().ageTokens( as ) );
931 protected void ageTokens( AllocSite as, HeapRegionNode hrn ) {
932 hrn.setAlpha( hrn.getAlpha().ageTokens( as ) );
937 protected void propagateTokensOverNodes(
938 HeapRegionNode nPrime,
940 HashSet<HeapRegionNode> nodesWithNewAlpha,
941 HashSet<RefEdge> edgesWithNewBeta ) {
943 HashSet<HeapRegionNode> todoNodes
944 = new HashSet<HeapRegionNode>();
945 todoNodes.add(nPrime);
947 HashSet<RefEdge> todoEdges
948 = new HashSet<RefEdge>();
950 Hashtable<HeapRegionNode, ChangeSet> nodePlannedChanges
951 = new Hashtable<HeapRegionNode, ChangeSet>();
952 nodePlannedChanges.put(nPrime, c0);
954 Hashtable<RefEdge, ChangeSet> edgePlannedChanges
955 = new Hashtable<RefEdge, ChangeSet>();
957 // first propagate change sets everywhere they can go
958 while( !todoNodes.isEmpty() ) {
959 HeapRegionNode n = todoNodes.iterator().next();
960 ChangeSet C = nodePlannedChanges.get(n);
962 Iterator<RefEdge> referItr = n.iteratorToReferencers();
963 while( referItr.hasNext() ) {
964 RefEdge edge = referItr.next();
967 if( !edgePlannedChanges.containsKey(edge) ) {
968 edgePlannedChanges.put(edge, new ChangeSet().makeCanonical() );
971 edgePlannedChanges.put(edge, edgePlannedChanges.get(edge).union(C) );
974 Iterator<RefEdge> refeeItr = n.iteratorToReferencees();
975 while( refeeItr.hasNext() ) {
976 RefEdge edgeF = refeeItr.next();
977 HeapRegionNode m = edgeF.getDst();
979 ChangeSet changesToPass = new ChangeSet().makeCanonical();
981 Iterator<ChangeTuple> itrCprime = C.iterator();
982 while( itrCprime.hasNext() ) {
983 ChangeTuple c = itrCprime.next();
984 if( edgeF.getBeta().contains( c.getSetToMatch() ) ) {
985 changesToPass = changesToPass.union(c);
989 if( !changesToPass.isEmpty() ) {
990 if( !nodePlannedChanges.containsKey(m) ) {
991 nodePlannedChanges.put(m, new ChangeSet().makeCanonical() );
994 ChangeSet currentChanges = nodePlannedChanges.get(m);
996 if( !changesToPass.isSubset(currentChanges) ) {
998 nodePlannedChanges.put(m, currentChanges.union(changesToPass) );
1004 todoNodes.remove(n);
1007 // then apply all of the changes for each node at once
1008 Iterator itrMap = nodePlannedChanges.entrySet().iterator();
1009 while( itrMap.hasNext() ) {
1010 Map.Entry me = (Map.Entry) itrMap.next();
1011 HeapRegionNode n = (HeapRegionNode) me.getKey();
1012 ChangeSet C = (ChangeSet) me.getValue();
1014 // this propagation step is with respect to one change,
1015 // so we capture the full change from the old alpha:
1016 ReachSet localDelta = n.getAlpha().applyChangeSet( C, true );
1018 // but this propagation may be only one of many concurrent
1019 // possible changes, so keep a running union with the node's
1020 // partially updated new alpha set
1021 n.setAlphaNew( n.getAlphaNew().union( localDelta ) );
1023 nodesWithNewAlpha.add( n );
1026 propagateTokensOverEdges(todoEdges, edgePlannedChanges, edgesWithNewBeta);
1030 protected void propagateTokensOverEdges(
1031 HashSet <RefEdge> todoEdges,
1032 Hashtable<RefEdge, ChangeSet> edgePlannedChanges,
1033 HashSet <RefEdge> edgesWithNewBeta ) {
1035 // first propagate all change tuples everywhere they can go
1036 while( !todoEdges.isEmpty() ) {
1037 RefEdge edgeE = todoEdges.iterator().next();
1038 todoEdges.remove(edgeE);
1040 if( !edgePlannedChanges.containsKey(edgeE) ) {
1041 edgePlannedChanges.put(edgeE, new ChangeSet().makeCanonical() );
1044 ChangeSet C = edgePlannedChanges.get(edgeE);
1046 ChangeSet changesToPass = new ChangeSet().makeCanonical();
1048 Iterator<ChangeTuple> itrC = C.iterator();
1049 while( itrC.hasNext() ) {
1050 ChangeTuple c = itrC.next();
1051 if( edgeE.getBeta().contains( c.getSetToMatch() ) ) {
1052 changesToPass = changesToPass.union(c);
1056 RefSrcNode onSrc = edgeE.getSrc();
1058 if( !changesToPass.isEmpty() && onSrc instanceof HeapRegionNode ) {
1059 HeapRegionNode n = (HeapRegionNode) onSrc;
1061 Iterator<RefEdge> referItr = n.iteratorToReferencers();
1062 while( referItr.hasNext() ) {
1063 RefEdge edgeF = referItr.next();
1065 if( !edgePlannedChanges.containsKey(edgeF) ) {
1066 edgePlannedChanges.put(edgeF, new ChangeSet().makeCanonical() );
1069 ChangeSet currentChanges = edgePlannedChanges.get(edgeF);
1071 if( !changesToPass.isSubset(currentChanges) ) {
1072 todoEdges.add(edgeF);
1073 edgePlannedChanges.put(edgeF, currentChanges.union(changesToPass) );
1079 // then apply all of the changes for each edge at once
1080 Iterator itrMap = edgePlannedChanges.entrySet().iterator();
1081 while( itrMap.hasNext() ) {
1082 Map.Entry me = (Map.Entry) itrMap.next();
1083 RefEdge e = (RefEdge) me.getKey();
1084 ChangeSet C = (ChangeSet) me.getValue();
1086 // this propagation step is with respect to one change,
1087 // so we capture the full change from the old beta:
1088 ReachSet localDelta = e.getBeta().applyChangeSet( C, true );
1090 // but this propagation may be only one of many concurrent
1091 // possible changes, so keep a running union with the edge's
1092 // partially updated new beta set
1093 e.setBetaNew( e.getBetaNew().union( localDelta ) );
1095 edgesWithNewBeta.add( e );
1101 // use this method to make a new reach graph that is
1102 // what heap the FlatMethod callee from the FlatCall
1103 // would start with reaching from its arguments in
1105 public ReachGraph makeCalleeView( FlatCall fc,
1108 // the callee view is a new graph: DON'T MODIFY
1110 ReachGraph rg = new ReachGraph();
1112 // track what parts of this graph have already been
1113 // added to callee view, variables not needed.
1114 // Note that we need this because when we traverse
1115 // this caller graph for each parameter we may find
1116 // nodes and edges more than once (which the per-param
1117 // "visit" sets won't show) and we only want to create
1118 // an element in the new callee view one time
1119 Set callerNodesCopiedToCallee = new HashSet<HeapRegionNode>();
1120 Set callerEdgesCopiedToCallee = new HashSet<RefEdge>();
1123 // a conservative starting point is to take the
1124 // mechanically-reachable-from-arguments graph
1125 // as opposed to using reachability information
1126 // to prune the graph further
1127 for( int i = 0; i < fm.numParameters(); ++i ) {
1129 // for each parameter index, get the symbol in the
1130 // caller view and callee view
1132 // argument defined here is the symbol in the caller
1133 TempDescriptor tdArg = fc.getArgMatchingParamIndex( fm, i );
1135 // parameter defined here is the symbol in the callee
1136 TempDescriptor tdParam = fm.getParameter( i );
1138 // use these two VariableNode objects to translate
1139 // between caller and callee--its easy to compare
1140 // a HeapRegionNode across callee and caller because
1141 // they will have the same heap region ID
1142 VariableNode vnCaller = this.getVariableNodeFromTemp( tdArg );
1143 VariableNode vnCallee = rg.getVariableNodeFromTemp( tdParam );
1145 // now traverse the calleR view using the argument to
1146 // build the calleE view which has the parameter symbol
1147 Set<RefSrcNode> toVisitInCaller = new HashSet<RefSrcNode>();
1148 Set<RefSrcNode> visitedInCaller = new HashSet<RefSrcNode>();
1149 toVisitInCaller.add( vnCaller );
1151 while( !toVisitInCaller.isEmpty() ) {
1152 RefSrcNode rsnCaller = toVisitInCaller.iterator().next();
1153 RefSrcNode rsnCallee;
1155 toVisitInCaller.remove( rsnCaller );
1156 visitedInCaller.add( rsnCaller );
1158 // FIRST - setup the source end of an edge, and
1159 // remember the identifying info of the source
1160 // to build predicates
1161 TempDescriptor tdSrc = null;
1162 Integer hrnSrcID = null;
1164 if( rsnCaller == vnCaller ) {
1165 // if the caller node is the param symbol, we
1166 // have to do this translation for the callee
1167 rsnCallee = vnCallee;
1171 // otherwise the callee-view node is a heap
1172 // region with the same ID, that may or may
1173 // not have been created already
1174 assert rsnCaller instanceof HeapRegionNode;
1176 HeapRegionNode hrnSrcCaller = (HeapRegionNode) rsnCaller; hrnSrcID = hrnSrcCaller.getID();
1178 if( !callerNodesCopiedToCallee.contains( rsnCaller ) ) {
1180 ExistPredNode pred =
1181 new ExistPredNode( hrnSrcID, null );
1183 ExistPredSet preds = new ExistPredSet();
1187 rg.createNewHeapRegionNode( hrnSrcCaller.getID(),
1188 hrnSrcCaller.isSingleObject(),
1189 hrnSrcCaller.isNewSummary(),
1190 hrnSrcCaller.isFlagged(),
1191 false, // out-of-context?
1192 hrnSrcCaller.getType(),
1193 hrnSrcCaller.getAllocSite(),
1194 toShadowTokens( this, hrnSrcCaller.getInherent() ),
1195 toShadowTokens( this, hrnSrcCaller.getAlpha() ),
1197 hrnSrcCaller.getDescription()
1199 callerNodesCopiedToCallee.add( rsnCaller );
1202 rsnCallee = rg.id2hrn.get( hrnSrcID );
1206 // SECOND - go over all edges from that source
1208 Iterator<RefEdge> itrRefEdges = rsnCaller.iteratorToReferencees();
1209 while( itrRefEdges.hasNext() ) {
1210 RefEdge reCaller = itrRefEdges.next();
1211 HeapRegionNode hrnCaller = reCaller.getDst();
1212 HeapRegionNode hrnCallee;
1214 // THIRD - setup destination ends of edges
1215 Integer hrnDstID = hrnCaller.getID();
1217 if( !callerNodesCopiedToCallee.contains( hrnCaller ) ) {
1219 ExistPredNode pred =
1220 new ExistPredNode( hrnDstID, null );
1222 ExistPredSet preds = new ExistPredSet();
1226 rg.createNewHeapRegionNode( hrnCaller.getID(),
1227 hrnCaller.isSingleObject(),
1228 hrnCaller.isNewSummary(),
1229 hrnCaller.isFlagged(),
1230 false, // out-of-context?
1231 hrnCaller.getType(),
1232 hrnCaller.getAllocSite(),
1233 toShadowTokens( this, hrnCaller.getInherent() ),
1234 toShadowTokens( this, hrnCaller.getAlpha() ),
1236 hrnCaller.getDescription()
1238 callerNodesCopiedToCallee.add( hrnCaller );
1240 hrnCallee = rg.id2hrn.get( hrnDstID );
1243 // FOURTH - copy edge over if needed
1244 if( !callerEdgesCopiedToCallee.contains( reCaller ) ) {
1246 ExistPredEdge pred =
1247 new ExistPredEdge( tdSrc,
1251 reCaller.getField(),
1254 ExistPredSet preds = new ExistPredSet();
1257 rg.addRefEdge( rsnCallee,
1259 new RefEdge( rsnCallee,
1262 reCaller.getField(),
1263 toShadowTokens( this, reCaller.getBeta() ),
1267 callerEdgesCopiedToCallee.add( reCaller );
1270 // keep traversing nodes reachable from param i
1271 // that we haven't visited yet
1272 if( !visitedInCaller.contains( hrnCaller ) ) {
1273 toVisitInCaller.add( hrnCaller );
1276 } // end edge iteration
1277 } // end visiting heap nodes in caller
1278 } // end iterating over parameters as starting points
1281 // find the set of edges in this graph with source
1282 // out-of-context (not in nodes copied) and have a
1283 // destination in context (one of nodes copied) as
1284 // a starting point for building out-of-context nodes
1285 Iterator<HeapRegionNode> itrInContext =
1286 callerNodesCopiedToCallee.iterator();
1287 while( itrInContext.hasNext() ) {
1288 HeapRegionNode hrnCallerAndInContext = itrInContext.next();
1290 Iterator<RefEdge> itrMightCross =
1291 hrnCallerAndInContext.iteratorToReferencers();
1292 while( itrMightCross.hasNext() ) {
1293 RefEdge edgeMightCross = itrMightCross.next();
1295 // we're only interested in edges with a source
1296 // 1) out-of-context and 2) is a heap region
1297 if( callerNodesCopiedToCallee.contains( edgeMightCross.getSrc() ) ||
1298 !(edgeMightCross.getSrc() instanceof HeapRegionNode)
1304 HeapRegionNode hrnCallerAndOutContext =
1305 (HeapRegionNode)edgeMightCross.getSrc();
1307 // we found a reference that crosses from out-of-context
1308 // to in-context, so build a special out-of-context node
1309 // for the callee IHM and its reference edge
1310 HeapRegionNode hrnCalleeAndOutContext =
1311 rg.createNewHeapRegionNode( null, // ID
1312 false, // single object?
1313 false, // new summary?
1315 true, // out-of-context?
1316 hrnCallerAndOutContext.getType(),
1317 null, // alloc site, shouldn't be used
1318 toShadowTokens( this, hrnCallerAndOutContext.getAlpha() ), // inherent
1319 toShadowTokens( this, hrnCallerAndOutContext.getAlpha() ), // alpha
1324 HeapRegionNode hrnCalleeAndInContext =
1325 rg.id2hrn.get( hrnCallerAndInContext.getID() );
1327 rg.addRefEdge( hrnCalleeAndOutContext,
1328 hrnCalleeAndInContext,
1329 new RefEdge( hrnCalleeAndOutContext,
1330 hrnCalleeAndInContext,
1331 edgeMightCross.getType(),
1332 edgeMightCross.getField(),
1333 toShadowTokens( this, edgeMightCross.getBeta() ),
1343 rg.writeGraph( "calleeview", true, false, false, false, true, true );
1344 } catch( IOException e ) {}
1347 if( fc.getMethod().getSymbol().equals( "addSomething" ) ) {
1355 public void resolveMethodCall( FlatCall fc,
1360 // to map the callee effects into the caller graph,
1361 // traverse the callee and categorize each element as,
1363 // 1) new node (not in caller)
1364 // 2) old node, clean (not modified in callee)
1365 // 3) old node, dirty
1367 // 5) old edge, clean
1368 // 6) old edge, dirty
1369 // 7) out-of-context nodes
1370 // 8) edge that crosses out-of-context to in-
1372 Iterator hrnItr = rgCallee.id2hrn.entrySet().iterator();
1373 while( hrnItr.hasNext() ) {
1374 Map.Entry me = (Map.Entry) hrnItr.next();
1375 Integer id = (Integer) me.getKey();
1376 HeapRegionNode hrnCallee = (HeapRegionNode) me.getValue();
1378 if( hrnCallee.isOutOfContext() ) {
1379 // 7) out-of-context nodes aren't altered by callee
1380 // analysis, they just help calculate changes to other
1381 // elements, so do nothing for this node
1384 // node is in the callee context...
1386 if( !this.id2hrn.containsKey( id ) ) {
1387 // 1) this is a new node in the callee
1388 assert !hrnCallee.isClean();
1390 // bring this node into caller as-is, and do the
1391 // unshadow of tokens in-place
1392 this.createNewHeapRegionNode( id,
1393 hrnCallee.isSingleObject(),
1394 hrnCallee.isNewSummary(),
1395 hrnCallee.isFlagged(),
1397 false, // out-of-context?
1398 hrnCallee.getType(),
1399 hrnCallee.getAllocSite(),
1400 unShadowTokens( rgCallee, hrnCallee.getInherent() ),
1401 unShadowTokens( rgCallee, hrnCallee.getAlpha() ),
1403 hrnCallee.getDescription()
1407 // otherwise, both graphs have this node, so...
1409 if( hrnCallee.isClean() ) {
1410 // 2) this node was not modified by callee,
1411 // just leave it alone in caller
1414 // 3) this node is already in caller, was modified
1415 // by the callee, so update caller node in-place
1416 hrnCaller = this.id2hrn.get( id );
1418 assert hrnCaller.getInherent().equals(
1419 unShadowTokens( rgCallee, hrnCallee.getInherent() )
1422 unShadowTokens( rgCallee, hrnCallee.getAlpha() )
1425 hrnCaller.setClean( false );
1429 } // end visiting callee nodes
1436 protected void unshadowTokens( AllocSite as,
1439 edge.setBeta( edge.getBeta().unshadowTokens( as ) );
1442 protected void unshadowTokens( AllocSite as,
1445 hrn.setAlpha( hrn.getAlpha().unshadowTokens( as ) );
1449 private ReachSet toShadowTokens( ReachGraph rg,
1452 ReachSet rsOut = new ReachSet( rsIn ).makeCanonical();
1454 Iterator<AllocSite> allocItr = rg.allocSites.iterator();
1455 while( allocItr.hasNext() ) {
1456 AllocSite as = allocItr.next();
1457 rsOut = rsOut.toShadowTokens( as );
1460 return rsOut.makeCanonical();
1464 ////////////////////////////////////////////////////
1466 // Abstract garbage collection simply removes
1467 // heap region nodes that are not mechanically
1468 // reachable from a root set. This step is
1469 // essential for testing node and edge existence
1470 // predicates efficiently
1472 ////////////////////////////////////////////////////
1473 public void abstractGarbageCollect( Set<TempDescriptor> liveSet ) {
1475 // calculate a root set, will be different for Java
1476 // version of analysis versus Bamboo version
1477 Set<RefSrcNode> toVisit = new HashSet<RefSrcNode>();
1479 // visit every variable in graph while building root
1480 // set, and do iterating on a copy, so we can remove
1481 // dead variables while we're at this
1482 Iterator makeCopyItr = td2vn.entrySet().iterator();
1483 Set entrysCopy = new HashSet();
1484 while( makeCopyItr.hasNext() ) {
1485 entrysCopy.add( makeCopyItr.next() );
1488 Iterator eItr = entrysCopy.iterator();
1489 while( eItr.hasNext() ) {
1490 Map.Entry me = (Map.Entry) eItr.next();
1491 TempDescriptor td = (TempDescriptor) me.getKey();
1492 VariableNode vn = (VariableNode) me.getValue();
1494 if( liveSet.contains( td ) ) {
1498 // dead var, remove completely from graph
1500 clearRefEdgesFrom( vn, null, null, true );
1504 // everything visited in a traversal is
1505 // considered abstractly live
1506 Set<RefSrcNode> visited = new HashSet<RefSrcNode>();
1508 while( !toVisit.isEmpty() ) {
1509 RefSrcNode rsn = toVisit.iterator().next();
1510 toVisit.remove( rsn );
1513 Iterator<RefEdge> hrnItr = rsn.iteratorToReferencees();
1514 while( hrnItr.hasNext() ) {
1515 RefEdge edge = hrnItr.next();
1516 HeapRegionNode hrn = edge.getDst();
1518 if( !visited.contains( hrn ) ) {
1524 // get a copy of the set to iterate over because
1525 // we're going to monkey with the graph when we
1526 // identify a garbage node
1527 Set<HeapRegionNode> hrnAllPrior = new HashSet<HeapRegionNode>();
1528 Iterator<HeapRegionNode> hrnItr = id2hrn.values().iterator();
1529 while( hrnItr.hasNext() ) {
1530 hrnAllPrior.add( hrnItr.next() );
1533 Iterator<HeapRegionNode> hrnAllItr = hrnAllPrior.iterator();
1534 while( hrnAllItr.hasNext() ) {
1535 HeapRegionNode hrn = hrnAllItr.next();
1537 if( !visited.contains( hrn ) ) {
1539 // heap region nodes are compared across ReachGraph
1540 // objects by their integer ID, so when discarding
1541 // garbage nodes we must also discard entries in
1542 // the ID -> heap region hashtable.
1543 id2hrn.remove( hrn.getID() );
1545 // RefEdge objects are two-way linked between
1546 // nodes, so when a node is identified as garbage,
1547 // actively clear references to and from it so
1548 // live nodes won't have dangling RefEdge's
1549 clearRefEdgesFrom( hrn, null, null, true );
1550 clearRefEdgesTo ( hrn, null, null, true );
1552 // if we just removed the last node from an allocation
1553 // site, it should be taken out of the ReachGraph's list
1554 AllocSite as = hrn.getAllocSite();
1555 if( !hasNodesOf( as ) ) {
1556 allocSites.remove( as );
1562 protected boolean hasNodesOf( AllocSite as ) {
1563 if( id2hrn.containsKey( as.getSummary() ) ) {
1567 for( int i = 0; i < allocationDepth; ++i ) {
1568 if( id2hrn.containsKey( as.getIthOldest( i ) ) ) {
1576 ////////////////////////////////////////////////////
1578 // This global sweep is an optional step to prune
1579 // reachability sets that are not internally
1580 // consistent with the global graph. It should be
1581 // invoked after strong updates or method calls.
1583 ////////////////////////////////////////////////////
1584 public void globalSweep() {
1586 // boldB is part of the phase 1 sweep
1587 Hashtable< Integer, Hashtable<RefEdge, ReachSet> > boldB =
1588 new Hashtable< Integer, Hashtable<RefEdge, ReachSet> >();
1590 // visit every heap region to initialize alphaNew and calculate boldB
1591 Set hrns = id2hrn.entrySet();
1592 Iterator itrHrns = hrns.iterator();
1593 while( itrHrns.hasNext() ) {
1594 Map.Entry me = (Map.Entry)itrHrns.next();
1595 Integer token = (Integer) me.getKey();
1596 HeapRegionNode hrn = (HeapRegionNode) me.getValue();
1598 // assert that this node and incoming edges have clean alphaNew
1599 // and betaNew sets, respectively
1600 assert rsetEmpty.equals( hrn.getAlphaNew() );
1602 Iterator<RefEdge> itrRers = hrn.iteratorToReferencers();
1603 while( itrRers.hasNext() ) {
1604 RefEdge edge = itrRers.next();
1605 assert rsetEmpty.equals( edge.getBetaNew() );
1608 // calculate boldB for this flagged node
1609 if( hrn.isFlagged() ) {
1611 Hashtable<RefEdge, ReachSet> boldB_f =
1612 new Hashtable<RefEdge, ReachSet>();
1614 Set<RefEdge> workSetEdges = new HashSet<RefEdge>();
1616 // initial boldB_f constraints
1617 Iterator<RefEdge> itrRees = hrn.iteratorToReferencees();
1618 while( itrRees.hasNext() ) {
1619 RefEdge edge = itrRees.next();
1621 assert !boldB.containsKey( edge );
1622 boldB_f.put( edge, edge.getBeta() );
1624 assert !workSetEdges.contains( edge );
1625 workSetEdges.add( edge );
1628 // enforce the boldB_f constraint at edges until we reach a fixed point
1629 while( !workSetEdges.isEmpty() ) {
1630 RefEdge edge = workSetEdges.iterator().next();
1631 workSetEdges.remove( edge );
1633 Iterator<RefEdge> itrPrime = edge.getDst().iteratorToReferencees();
1634 while( itrPrime.hasNext() ) {
1635 RefEdge edgePrime = itrPrime.next();
1637 ReachSet prevResult = boldB_f.get( edgePrime );
1638 ReachSet intersection = boldB_f.get( edge ).intersection( edgePrime.getBeta() );
1640 if( prevResult == null ||
1641 prevResult.union( intersection ).size() > prevResult.size() ) {
1643 if( prevResult == null ) {
1644 boldB_f.put( edgePrime, edgePrime.getBeta().union( intersection ) );
1646 boldB_f.put( edgePrime, prevResult .union( intersection ) );
1648 workSetEdges.add( edgePrime );
1653 boldB.put( token, boldB_f );
1658 // use boldB to prune tokens from alpha states that are impossible
1659 // and propagate the differences backwards across edges
1660 HashSet<RefEdge> edgesForPropagation = new HashSet<RefEdge>();
1662 Hashtable<RefEdge, ChangeSet> edgePlannedChanges =
1663 new Hashtable<RefEdge, ChangeSet>();
1665 hrns = id2hrn.entrySet();
1666 itrHrns = hrns.iterator();
1667 while( itrHrns.hasNext() ) {
1668 Map.Entry me = (Map.Entry)itrHrns.next();
1669 Integer token = (Integer) me.getKey();
1670 HeapRegionNode hrn = (HeapRegionNode) me.getValue();
1672 // never remove the identity token from a flagged region
1673 // because it is trivially satisfied
1674 ReachTuple ttException = new ReachTuple( token,
1675 !hrn.isSingleObject(),
1676 ReachTuple.ARITY_ONE ).makeCanonical();
1678 ChangeSet cts = new ChangeSet().makeCanonical();
1680 // mark tokens for removal
1681 Iterator<ReachState> stateItr = hrn.getAlpha().iterator();
1682 while( stateItr.hasNext() ) {
1683 ReachState ttsOld = stateItr.next();
1685 ReachState markedTokens = new ReachState().makeCanonical();
1687 Iterator<ReachTuple> ttItr = ttsOld.iterator();
1688 while( ttItr.hasNext() ) {
1689 ReachTuple ttOld = ttItr.next();
1691 // never remove the identity token from a flagged region
1692 // because it is trivially satisfied
1693 if( hrn.isFlagged() ) {
1694 if( ttOld == ttException ) {
1699 // does boldB_ttOld allow this token?
1700 boolean foundState = false;
1701 Iterator<RefEdge> incidentEdgeItr = hrn.iteratorToReferencers();
1702 while( incidentEdgeItr.hasNext() ) {
1703 RefEdge incidentEdge = incidentEdgeItr.next();
1705 // if it isn't allowed, mark for removal
1706 Integer idOld = ttOld.getToken();
1707 assert id2hrn.containsKey( idOld );
1708 Hashtable<RefEdge, ReachSet> B = boldB.get( idOld );
1709 ReachSet boldB_ttOld_incident = B.get( incidentEdge );// B is NULL!
1710 if( boldB_ttOld_incident != null &&
1711 boldB_ttOld_incident.contains( ttsOld ) ) {
1717 markedTokens = markedTokens.add( ttOld );
1721 // if there is nothing marked, just move on
1722 if( markedTokens.isEmpty() ) {
1723 hrn.setAlphaNew( hrn.getAlphaNew().union( ttsOld ) );
1727 // remove all marked tokens and establish a change set that should
1728 // propagate backwards over edges from this node
1729 ReachState ttsPruned = new ReachState().makeCanonical();
1730 ttItr = ttsOld.iterator();
1731 while( ttItr.hasNext() ) {
1732 ReachTuple ttOld = ttItr.next();
1734 if( !markedTokens.containsTuple( ttOld ) ) {
1735 ttsPruned = ttsPruned.union( ttOld );
1738 assert !ttsOld.equals( ttsPruned );
1740 hrn.setAlphaNew( hrn.getAlphaNew().union( ttsPruned ) );
1741 ChangeTuple ct = new ChangeTuple( ttsOld, ttsPruned ).makeCanonical();
1742 cts = cts.union( ct );
1745 // throw change tuple set on all incident edges
1746 if( !cts.isEmpty() ) {
1747 Iterator<RefEdge> incidentEdgeItr = hrn.iteratorToReferencers();
1748 while( incidentEdgeItr.hasNext() ) {
1749 RefEdge incidentEdge = incidentEdgeItr.next();
1751 edgesForPropagation.add( incidentEdge );
1753 if( edgePlannedChanges.get( incidentEdge ) == null ) {
1754 edgePlannedChanges.put( incidentEdge, cts );
1756 edgePlannedChanges.put(
1758 edgePlannedChanges.get( incidentEdge ).union( cts )
1765 HashSet<RefEdge> edgesUpdated = new HashSet<RefEdge>();
1767 propagateTokensOverEdges( edgesForPropagation,
1771 // at the end of the 1st phase reference edges have
1772 // beta, betaNew that correspond to beta and betaR
1774 // commit beta<-betaNew, so beta=betaR and betaNew
1775 // will represent the beta' calculation in 2nd phase
1777 // commit alpha<-alphaNew because it won't change
1778 HashSet<RefEdge> res = new HashSet<RefEdge>();
1780 Iterator<HeapRegionNode> nodeItr = id2hrn.values().iterator();
1781 while( nodeItr.hasNext() ) {
1782 HeapRegionNode hrn = nodeItr.next();
1783 hrn.applyAlphaNew();
1784 Iterator<RefEdge> itrRes = hrn.iteratorToReferencers();
1785 while( itrRes.hasNext() ) {
1786 res.add( itrRes.next() );
1792 Iterator<RefEdge> edgeItr = res.iterator();
1793 while( edgeItr.hasNext() ) {
1794 RefEdge edge = edgeItr.next();
1795 HeapRegionNode hrn = edge.getDst();
1797 // commit results of last phase
1798 if( edgesUpdated.contains( edge ) ) {
1799 edge.applyBetaNew();
1802 // compute intial condition of 2nd phase
1803 edge.setBetaNew( edge.getBeta().intersection( hrn.getAlpha() ) );
1806 // every edge in the graph is the initial workset
1807 Set<RefEdge> edgeWorkSet = (Set) res.clone();
1808 while( !edgeWorkSet.isEmpty() ) {
1809 RefEdge edgePrime = edgeWorkSet.iterator().next();
1810 edgeWorkSet.remove( edgePrime );
1812 RefSrcNode on = edgePrime.getSrc();
1813 if( !(on instanceof HeapRegionNode) ) {
1816 HeapRegionNode hrn = (HeapRegionNode) on;
1818 Iterator<RefEdge> itrEdge = hrn.iteratorToReferencers();
1819 while( itrEdge.hasNext() ) {
1820 RefEdge edge = itrEdge.next();
1822 ReachSet prevResult = edge.getBetaNew();
1823 assert prevResult != null;
1825 ReachSet intersection = edge.getBeta().intersection( edgePrime.getBetaNew() );
1827 if( prevResult.union( intersection ).size() > prevResult.size() ) {
1828 edge.setBetaNew( prevResult.union( intersection ) );
1829 edgeWorkSet.add( edge );
1834 // commit beta' (beta<-betaNew)
1835 edgeItr = res.iterator();
1836 while( edgeItr.hasNext() ) {
1837 edgeItr.next().applyBetaNew();
1843 ////////////////////////////////////////////////////
1844 // high-level merge operations
1845 ////////////////////////////////////////////////////
1846 public void merge_sameMethodContext( ReachGraph rg ) {
1847 // when merging two graphs that abstract the heap
1848 // of the same method context, we just call the
1849 // basic merge operation
1853 public void merge_diffMethodContext( ReachGraph rg ) {
1854 // when merging graphs for abstract heaps in
1855 // different method contexts we should:
1856 // 1) age the allocation sites?
1860 ////////////////////////////////////////////////////
1861 // in merge() and equals() methods the suffix A
1862 // represents the passed in graph and the suffix
1863 // B refers to the graph in this object
1864 // Merging means to take the incoming graph A and
1865 // merge it into B, so after the operation graph B
1866 // is the final result.
1867 ////////////////////////////////////////////////////
1868 protected void merge( ReachGraph rg ) {
1875 mergeRefEdges ( rg );
1876 mergeAllocSites( rg );
1879 protected void mergeNodes( ReachGraph rg ) {
1881 // start with heap region nodes
1882 Set sA = rg.id2hrn.entrySet();
1883 Iterator iA = sA.iterator();
1884 while( iA.hasNext() ) {
1885 Map.Entry meA = (Map.Entry) iA.next();
1886 Integer idA = (Integer) meA.getKey();
1887 HeapRegionNode hrnA = (HeapRegionNode) meA.getValue();
1889 // if this graph doesn't have a node the
1890 // incoming graph has, allocate it
1891 if( !id2hrn.containsKey( idA ) ) {
1892 HeapRegionNode hrnB = hrnA.copy();
1893 id2hrn.put( idA, hrnB );
1896 // otherwise this is a node present in both graphs
1897 // so make the new reachability set a union of the
1898 // nodes' reachability sets
1899 HeapRegionNode hrnB = id2hrn.get( idA );
1900 hrnB.setAlpha( hrnB.getAlpha().union( hrnA.getAlpha() ) );
1902 // if hrnB is already dirty or hrnA is dirty,
1903 // the hrnB should end up dirty: TODO
1905 if( !hrnA.isClean() ) {
1906 hrnB.setIsClean( false );
1912 // now add any variable nodes that are in graph B but
1914 sA = rg.td2vn.entrySet();
1916 while( iA.hasNext() ) {
1917 Map.Entry meA = (Map.Entry) iA.next();
1918 TempDescriptor tdA = (TempDescriptor) meA.getKey();
1919 VariableNode lnA = (VariableNode) meA.getValue();
1921 // if the variable doesn't exist in B, allocate and add it
1922 VariableNode lnB = getVariableNodeFromTemp( tdA );
1926 protected void mergeRefEdges( ReachGraph rg ) {
1928 // between heap regions
1929 Set sA = rg.id2hrn.entrySet();
1930 Iterator iA = sA.iterator();
1931 while( iA.hasNext() ) {
1932 Map.Entry meA = (Map.Entry) iA.next();
1933 Integer idA = (Integer) meA.getKey();
1934 HeapRegionNode hrnA = (HeapRegionNode) meA.getValue();
1936 Iterator<RefEdge> heapRegionsItrA = hrnA.iteratorToReferencees();
1937 while( heapRegionsItrA.hasNext() ) {
1938 RefEdge edgeA = heapRegionsItrA.next();
1939 HeapRegionNode hrnChildA = edgeA.getDst();
1940 Integer idChildA = hrnChildA.getID();
1942 // at this point we know an edge in graph A exists
1943 // idA -> idChildA, does this exist in B?
1944 assert id2hrn.containsKey( idA );
1945 HeapRegionNode hrnB = id2hrn.get( idA );
1946 RefEdge edgeToMerge = null;
1948 Iterator<RefEdge> heapRegionsItrB = hrnB.iteratorToReferencees();
1949 while( heapRegionsItrB.hasNext() &&
1950 edgeToMerge == null ) {
1952 RefEdge edgeB = heapRegionsItrB.next();
1953 HeapRegionNode hrnChildB = edgeB.getDst();
1954 Integer idChildB = hrnChildB.getID();
1956 // don't use the RefEdge.equals() here because
1957 // we're talking about existence between graphs,
1958 // not intragraph equal
1959 if( idChildB.equals( idChildA ) &&
1960 edgeB.typeAndFieldEquals( edgeA ) ) {
1962 edgeToMerge = edgeB;
1966 // if the edge from A was not found in B,
1968 if( edgeToMerge == null ) {
1969 assert id2hrn.containsKey( idChildA );
1970 HeapRegionNode hrnChildB = id2hrn.get( idChildA );
1971 edgeToMerge = edgeA.copy();
1972 edgeToMerge.setSrc( hrnB );
1973 edgeToMerge.setDst( hrnChildB );
1974 addRefEdge( hrnB, hrnChildB, edgeToMerge );
1976 // otherwise, the edge already existed in both graphs
1977 // so merge their reachability sets
1979 // just replace this beta set with the union
1980 assert edgeToMerge != null;
1981 edgeToMerge.setBeta(
1982 edgeToMerge.getBeta().union( edgeA.getBeta() )
1986 if( !edgeA.isClean() ) {
1987 edgeToMerge.setIsClean( false );
1994 // and then again from variable nodes
1995 sA = rg.td2vn.entrySet();
1997 while( iA.hasNext() ) {
1998 Map.Entry meA = (Map.Entry) iA.next();
1999 TempDescriptor tdA = (TempDescriptor) meA.getKey();
2000 VariableNode vnA = (VariableNode) meA.getValue();
2002 Iterator<RefEdge> heapRegionsItrA = vnA.iteratorToReferencees();
2003 while( heapRegionsItrA.hasNext() ) {
2004 RefEdge edgeA = heapRegionsItrA.next();
2005 HeapRegionNode hrnChildA = edgeA.getDst();
2006 Integer idChildA = hrnChildA.getID();
2008 // at this point we know an edge in graph A exists
2009 // tdA -> idChildA, does this exist in B?
2010 assert td2vn.containsKey( tdA );
2011 VariableNode vnB = td2vn.get( tdA );
2012 RefEdge edgeToMerge = null;
2014 Iterator<RefEdge> heapRegionsItrB = vnB.iteratorToReferencees();
2015 while( heapRegionsItrB.hasNext() &&
2016 edgeToMerge == null ) {
2018 RefEdge edgeB = heapRegionsItrB.next();
2019 HeapRegionNode hrnChildB = edgeB.getDst();
2020 Integer idChildB = hrnChildB.getID();
2022 // don't use the RefEdge.equals() here because
2023 // we're talking about existence between graphs
2024 if( idChildB.equals( idChildA ) &&
2025 edgeB.typeAndFieldEquals( edgeA ) ) {
2027 edgeToMerge = edgeB;
2031 // if the edge from A was not found in B,
2033 if( edgeToMerge == null ) {
2034 assert id2hrn.containsKey( idChildA );
2035 HeapRegionNode hrnChildB = id2hrn.get( idChildA );
2036 edgeToMerge = edgeA.copy();
2037 edgeToMerge.setSrc( vnB );
2038 edgeToMerge.setDst( hrnChildB );
2039 addRefEdge( vnB, hrnChildB, edgeToMerge );
2041 // otherwise, the edge already existed in both graphs
2042 // so merge their reachability sets
2044 // just replace this beta set with the union
2045 edgeToMerge.setBeta(
2046 edgeToMerge.getBeta().union( edgeA.getBeta() )
2050 if( !edgeA.isClean() ) {
2051 edgeToMerge.setIsClean( false );
2059 protected void mergeAllocSites( ReachGraph rg ) {
2060 allocSites.addAll( rg.allocSites );
2064 // it is necessary in the equals() member functions
2065 // to "check both ways" when comparing the data
2066 // structures of two graphs. For instance, if all
2067 // edges between heap region nodes in graph A are
2068 // present and equal in graph B it is not sufficient
2069 // to say the graphs are equal. Consider that there
2070 // may be edges in graph B that are not in graph A.
2071 // the only way to know that all edges in both graphs
2072 // are equally present is to iterate over both data
2073 // structures and compare against the other graph.
2074 public boolean equals( ReachGraph rg ) {
2080 if( !areHeapRegionNodesEqual( rg ) ) {
2084 if( !areVariableNodesEqual( rg ) ) {
2088 if( !areRefEdgesEqual( rg ) ) {
2092 // if everything is equal up to this point,
2093 // assert that allocSites is also equal--
2094 // this data is redundant but kept for efficiency
2095 assert allocSites.equals( rg.allocSites );
2101 protected boolean areHeapRegionNodesEqual( ReachGraph rg ) {
2103 if( !areallHRNinAalsoinBandequal( this, rg ) ) {
2107 if( !areallHRNinAalsoinBandequal( rg, this ) ) {
2114 static protected boolean areallHRNinAalsoinBandequal( ReachGraph rgA,
2116 Set sA = rgA.id2hrn.entrySet();
2117 Iterator iA = sA.iterator();
2118 while( iA.hasNext() ) {
2119 Map.Entry meA = (Map.Entry) iA.next();
2120 Integer idA = (Integer) meA.getKey();
2121 HeapRegionNode hrnA = (HeapRegionNode) meA.getValue();
2123 if( !rgB.id2hrn.containsKey( idA ) ) {
2127 HeapRegionNode hrnB = rgB.id2hrn.get( idA );
2128 if( !hrnA.equalsIncludingAlphaAndPreds( hrnB ) ) {
2137 protected boolean areVariableNodesEqual( ReachGraph rg ) {
2139 if( !areallVNinAalsoinBandequal( this, rg ) ) {
2143 if( !areallVNinAalsoinBandequal( rg, this ) ) {
2150 static protected boolean areallVNinAalsoinBandequal( ReachGraph rgA,
2152 Set sA = rgA.td2vn.entrySet();
2153 Iterator iA = sA.iterator();
2154 while( iA.hasNext() ) {
2155 Map.Entry meA = (Map.Entry) iA.next();
2156 TempDescriptor tdA = (TempDescriptor) meA.getKey();
2158 if( !rgB.td2vn.containsKey( tdA ) ) {
2167 protected boolean areRefEdgesEqual( ReachGraph rg ) {
2168 if( !areallREinAandBequal( this, rg ) ) {
2175 static protected boolean areallREinAandBequal( ReachGraph rgA,
2178 // check all the heap region->heap region edges
2179 Set sA = rgA.id2hrn.entrySet();
2180 Iterator iA = sA.iterator();
2181 while( iA.hasNext() ) {
2182 Map.Entry meA = (Map.Entry) iA.next();
2183 Integer idA = (Integer) meA.getKey();
2184 HeapRegionNode hrnA = (HeapRegionNode) meA.getValue();
2186 // we should have already checked that the same
2187 // heap regions exist in both graphs
2188 assert rgB.id2hrn.containsKey( idA );
2190 if( !areallREfromAequaltoB( rgA, hrnA, rgB ) ) {
2194 // then check every edge in B for presence in A, starting
2195 // from the same parent HeapRegionNode
2196 HeapRegionNode hrnB = rgB.id2hrn.get( idA );
2198 if( !areallREfromAequaltoB( rgB, hrnB, rgA ) ) {
2203 // then check all the variable->heap region edges
2204 sA = rgA.td2vn.entrySet();
2206 while( iA.hasNext() ) {
2207 Map.Entry meA = (Map.Entry) iA.next();
2208 TempDescriptor tdA = (TempDescriptor) meA.getKey();
2209 VariableNode vnA = (VariableNode) meA.getValue();
2211 // we should have already checked that the same
2212 // label nodes exist in both graphs
2213 assert rgB.td2vn.containsKey( tdA );
2215 if( !areallREfromAequaltoB( rgA, vnA, rgB ) ) {
2219 // then check every edge in B for presence in A, starting
2220 // from the same parent VariableNode
2221 VariableNode vnB = rgB.td2vn.get( tdA );
2223 if( !areallREfromAequaltoB( rgB, vnB, rgA ) ) {
2232 static protected boolean areallREfromAequaltoB( ReachGraph rgA,
2236 Iterator<RefEdge> itrA = rnA.iteratorToReferencees();
2237 while( itrA.hasNext() ) {
2238 RefEdge edgeA = itrA.next();
2239 HeapRegionNode hrnChildA = edgeA.getDst();
2240 Integer idChildA = hrnChildA.getID();
2242 assert rgB.id2hrn.containsKey( idChildA );
2244 // at this point we know an edge in graph A exists
2245 // rnA -> idChildA, does this exact edge exist in B?
2246 boolean edgeFound = false;
2248 RefSrcNode rnB = null;
2249 if( rnA instanceof HeapRegionNode ) {
2250 HeapRegionNode hrnA = (HeapRegionNode) rnA;
2251 rnB = rgB.id2hrn.get( hrnA.getID() );
2253 VariableNode vnA = (VariableNode) rnA;
2254 rnB = rgB.td2vn.get( vnA.getTempDescriptor() );
2257 Iterator<RefEdge> itrB = rnB.iteratorToReferencees();
2258 while( itrB.hasNext() ) {
2259 RefEdge edgeB = itrB.next();
2260 HeapRegionNode hrnChildB = edgeB.getDst();
2261 Integer idChildB = hrnChildB.getID();
2263 if( idChildA.equals( idChildB ) &&
2264 edgeA.typeAndFieldEquals( edgeB ) ) {
2266 // there is an edge in the right place with the right field,
2267 // but do they have the same attributes?
2268 if( edgeA.getBeta().equals( edgeB.getBeta() ) &&
2269 edgeA.equalsPreds( edgeB )
2286 // this analysis no longer has the "match anything"
2287 // type which was represented by null
2288 protected TypeDescriptor mostSpecificType( TypeDescriptor td1,
2289 TypeDescriptor td2 ) {
2293 if( td1.isNull() ) {
2296 if( td2.isNull() ) {
2299 return typeUtil.mostSpecific( td1, td2 );
2302 protected TypeDescriptor mostSpecificType( TypeDescriptor td1,
2304 TypeDescriptor td3 ) {
2306 return mostSpecificType( td1,
2307 mostSpecificType( td2, td3 )
2311 protected TypeDescriptor mostSpecificType( TypeDescriptor td1,
2314 TypeDescriptor td4 ) {
2316 return mostSpecificType( mostSpecificType( td1, td2 ),
2317 mostSpecificType( td3, td4 )
2321 protected boolean isSuperiorType( TypeDescriptor possibleSuper,
2322 TypeDescriptor possibleChild ) {
2323 assert possibleSuper != null;
2324 assert possibleChild != null;
2326 if( possibleSuper.isNull() ||
2327 possibleChild.isNull() ) {
2331 return typeUtil.isSuperorType( possibleSuper, possibleChild );
2335 protected boolean hasMatchingField( HeapRegionNode src,
2338 TypeDescriptor tdSrc = src.getType();
2339 assert tdSrc != null;
2341 if( tdSrc.isArray() ) {
2342 TypeDescriptor td = edge.getType();
2345 TypeDescriptor tdSrcDeref = tdSrc.dereference();
2346 assert tdSrcDeref != null;
2348 if( !typeUtil.isSuperorType( tdSrcDeref, td ) ) {
2352 return edge.getField().equals( DisjointAnalysis.arrayElementFieldName );
2355 // if it's not a class, it doesn't have any fields to match
2356 if( !tdSrc.isClass() ) {
2360 ClassDescriptor cd = tdSrc.getClassDesc();
2361 while( cd != null ) {
2362 Iterator fieldItr = cd.getFields();
2364 while( fieldItr.hasNext() ) {
2365 FieldDescriptor fd = (FieldDescriptor) fieldItr.next();
2367 if( fd.getType().equals( edge.getType() ) &&
2368 fd.getSymbol().equals( edge.getField() ) ) {
2373 cd = cd.getSuperDesc();
2376 // otherwise it is a class with fields
2377 // but we didn't find a match
2381 protected boolean hasMatchingType( RefEdge edge,
2382 HeapRegionNode dst ) {
2384 // if the region has no type, matches everything
2385 TypeDescriptor tdDst = dst.getType();
2386 assert tdDst != null;
2388 // if the type is not a class or an array, don't
2389 // match because primitives are copied, no aliases
2390 ClassDescriptor cdDst = tdDst.getClassDesc();
2391 if( cdDst == null && !tdDst.isArray() ) {
2395 // if the edge type is null, it matches everything
2396 TypeDescriptor tdEdge = edge.getType();
2397 assert tdEdge != null;
2399 return typeUtil.isSuperorType( tdEdge, tdDst );
2403 public void writeGraph( String graphName,
2404 boolean writeLabels,
2405 boolean labelSelect,
2406 boolean pruneGarbage,
2407 boolean writeReferencers,
2408 boolean hideSubsetReachability,
2409 boolean hideEdgeTaints
2410 ) throws java.io.IOException {
2412 // remove all non-word characters from the graph name so
2413 // the filename and identifier in dot don't cause errors
2414 graphName = graphName.replaceAll( "[\\W]", "" );
2417 new BufferedWriter( new FileWriter( graphName+".dot" ) );
2419 bw.write( "digraph "+graphName+" {\n" );
2421 Set<HeapRegionNode> visited = new HashSet<HeapRegionNode>();
2423 // then visit every heap region node
2424 Set s = id2hrn.entrySet();
2425 Iterator i = s.iterator();
2426 while( i.hasNext() ) {
2427 Map.Entry me = (Map.Entry) i.next();
2428 HeapRegionNode hrn = (HeapRegionNode) me.getValue();
2430 // only visit nodes worth writing out--for instance
2431 // not every node at an allocation is referenced
2432 // (think of it as garbage-collected), etc.
2433 if( !pruneGarbage ||
2434 (hrn.isFlagged() && hrn.getID() > 0) ||
2435 hrn.getDescription().startsWith( "param" ) ||
2436 hrn.isOutOfContext()
2439 if( !visited.contains( hrn ) ) {
2440 traverseHeapRegionNodes( hrn,
2445 hideSubsetReachability,
2451 bw.write( " graphTitle[label=\""+graphName+"\",shape=box];\n" );
2454 // then visit every label node, useful for debugging
2456 s = td2vn.entrySet();
2458 while( i.hasNext() ) {
2459 Map.Entry me = (Map.Entry) i.next();
2460 VariableNode vn = (VariableNode) me.getValue();
2463 String labelStr = vn.getTempDescriptorString();
2464 if( labelStr.startsWith("___temp") ||
2465 labelStr.startsWith("___dst") ||
2466 labelStr.startsWith("___srctmp") ||
2467 labelStr.startsWith("___neverused")
2473 Iterator<RefEdge> heapRegionsItr = vn.iteratorToReferencees();
2474 while( heapRegionsItr.hasNext() ) {
2475 RefEdge edge = heapRegionsItr.next();
2476 HeapRegionNode hrn = edge.getDst();
2478 if( pruneGarbage && !visited.contains( hrn ) ) {
2479 traverseHeapRegionNodes( hrn,
2484 hideSubsetReachability,
2488 bw.write( " "+vn.toString()+
2489 " -> "+hrn.toString()+
2490 edge.toStringDOT( hideSubsetReachability )+
2500 protected void traverseHeapRegionNodes( HeapRegionNode hrn,
2503 Set<HeapRegionNode> visited,
2504 boolean writeReferencers,
2505 boolean hideSubsetReachability,
2506 boolean hideEdgeTaints
2507 ) throws java.io.IOException {
2509 if( visited.contains( hrn ) ) {
2514 bw.write( " "+hrn.toString()+
2515 hrn.toStringDOT( hideSubsetReachability )+
2518 Iterator<RefEdge> childRegionsItr = hrn.iteratorToReferencees();
2519 while( childRegionsItr.hasNext() ) {
2520 RefEdge edge = childRegionsItr.next();
2521 HeapRegionNode hrnChild = edge.getDst();
2523 bw.write( " "+hrn.toString()+
2524 " -> "+hrnChild.toString()+
2525 edge.toStringDOT( hideSubsetReachability )+
2528 traverseHeapRegionNodes( hrnChild,
2533 hideSubsetReachability,