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 // edges are getting added twice to graphs now, the
165 // kind that should have abstract facts merged--use
166 // this check to prevent that
167 assert referencer.getReferenceTo( referencee,
172 referencer.addReferencee( edge );
173 referencee.addReferencer( edge );
176 protected void removeRefEdge( RefEdge e ) {
177 removeRefEdge( e.getSrc(),
183 protected void removeRefEdge( RefSrcNode referencer,
184 HeapRegionNode referencee,
187 assert referencer != null;
188 assert referencee != null;
190 RefEdge edge = referencer.getReferenceTo( referencee,
194 assert edge == referencee.getReferenceFrom( referencer,
198 referencer.removeReferencee( edge );
199 referencee.removeReferencer( edge );
202 protected void clearRefEdgesFrom( RefSrcNode referencer,
205 boolean removeAll ) {
206 assert referencer != null;
208 // get a copy of the set to iterate over, otherwise
209 // we will be trying to take apart the set as we
210 // are iterating over it, which won't work
211 Iterator<RefEdge> i = referencer.iteratorToReferenceesClone();
212 while( i.hasNext() ) {
213 RefEdge edge = i.next();
216 (edge.typeEquals( type ) && edge.fieldEquals( field ))
219 HeapRegionNode referencee = edge.getDst();
221 removeRefEdge( referencer,
229 protected void clearRefEdgesTo( HeapRegionNode referencee,
232 boolean removeAll ) {
233 assert referencee != null;
235 // get a copy of the set to iterate over, otherwise
236 // we will be trying to take apart the set as we
237 // are iterating over it, which won't work
238 Iterator<RefEdge> i = referencee.iteratorToReferencersClone();
239 while( i.hasNext() ) {
240 RefEdge edge = i.next();
243 (edge.typeEquals( type ) && edge.fieldEquals( field ))
246 RefSrcNode referencer = edge.getSrc();
248 removeRefEdge( referencer,
257 ////////////////////////////////////////////////////
259 // Assignment Operation Methods
261 // These methods are high-level operations for
262 // modeling program assignment statements using
263 // the low-level reference create/remove methods
266 ////////////////////////////////////////////////////
268 public void assignTempXEqualToTempY( TempDescriptor x,
270 assignTempXEqualToCastedTempY( x, y, null );
273 public void assignTempXEqualToCastedTempY( TempDescriptor x,
275 TypeDescriptor tdCast ) {
277 VariableNode lnX = getVariableNodeFromTemp( x );
278 VariableNode lnY = getVariableNodeFromTemp( y );
280 clearRefEdgesFrom( lnX, null, null, true );
282 // note it is possible that the types of temps in the
283 // flat node to analyze will reveal that some typed
284 // edges in the reachability graph are impossible
285 Set<RefEdge> impossibleEdges = new HashSet<RefEdge>();
287 Iterator<RefEdge> itrYhrn = lnY.iteratorToReferencees();
288 while( itrYhrn.hasNext() ) {
289 RefEdge edgeY = itrYhrn.next();
290 HeapRegionNode referencee = edgeY.getDst();
291 RefEdge edgeNew = edgeY.copy();
293 if( !isSuperiorType( x.getType(), edgeY.getType() ) ) {
294 impossibleEdges.add( edgeY );
298 edgeNew.setSrc( lnX );
300 if( tdCast == null ) {
301 edgeNew.setType( mostSpecificType( y.getType(),
307 edgeNew.setType( mostSpecificType( y.getType(),
309 referencee.getType(),
315 edgeNew.setField( null );
317 addRefEdge( lnX, referencee, edgeNew );
320 Iterator<RefEdge> itrImp = impossibleEdges.iterator();
321 while( itrImp.hasNext() ) {
322 RefEdge edgeImp = itrImp.next();
323 removeRefEdge( edgeImp );
328 public void assignTempXEqualToTempYFieldF( TempDescriptor x,
330 FieldDescriptor f ) {
331 VariableNode lnX = getVariableNodeFromTemp( x );
332 VariableNode lnY = getVariableNodeFromTemp( y );
334 clearRefEdgesFrom( lnX, null, null, true );
336 // note it is possible that the types of temps in the
337 // flat node to analyze will reveal that some typed
338 // edges in the reachability graph are impossible
339 Set<RefEdge> impossibleEdges = new HashSet<RefEdge>();
341 Iterator<RefEdge> itrYhrn = lnY.iteratorToReferencees();
342 while( itrYhrn.hasNext() ) {
343 RefEdge edgeY = itrYhrn.next();
344 HeapRegionNode hrnY = edgeY.getDst();
345 ReachSet betaY = edgeY.getBeta();
347 Iterator<RefEdge> itrHrnFhrn = hrnY.iteratorToReferencees();
348 while( itrHrnFhrn.hasNext() ) {
349 RefEdge edgeHrn = itrHrnFhrn.next();
350 HeapRegionNode hrnHrn = edgeHrn.getDst();
351 ReachSet betaHrn = edgeHrn.getBeta();
353 // prune edges that are not a matching field
354 if( edgeHrn.getType() != null &&
355 !edgeHrn.getField().equals( f.getSymbol() )
360 // check for impossible edges
361 if( !isSuperiorType( x.getType(), edgeHrn.getType() ) ) {
362 impossibleEdges.add( edgeHrn );
366 TypeDescriptor tdNewEdge =
367 mostSpecificType( edgeHrn.getType(),
371 RefEdge edgeNew = new RefEdge( lnX,
375 Canonical.intersection( betaY, betaHrn ),
379 addRefEdge( lnX, hrnHrn, edgeNew );
383 Iterator<RefEdge> itrImp = impossibleEdges.iterator();
384 while( itrImp.hasNext() ) {
385 RefEdge edgeImp = itrImp.next();
386 removeRefEdge( edgeImp );
389 // anytime you might remove edges between heap regions
390 // you must global sweep to clean up broken reachability
391 if( !impossibleEdges.isEmpty() ) {
392 if( !DISABLE_GLOBAL_SWEEP ) {
399 public void assignTempXFieldFEqualToTempY( TempDescriptor x,
403 VariableNode lnX = getVariableNodeFromTemp( x );
404 VariableNode lnY = getVariableNodeFromTemp( y );
406 HashSet<HeapRegionNode> nodesWithNewAlpha = new HashSet<HeapRegionNode>();
407 HashSet<RefEdge> edgesWithNewBeta = new HashSet<RefEdge>();
409 // note it is possible that the types of temps in the
410 // flat node to analyze will reveal that some typed
411 // edges in the reachability graph are impossible
412 Set<RefEdge> impossibleEdges = new HashSet<RefEdge>();
414 // first look for possible strong updates and remove those edges
415 boolean strongUpdate = false;
417 Iterator<RefEdge> itrXhrn = lnX.iteratorToReferencees();
418 while( itrXhrn.hasNext() ) {
419 RefEdge edgeX = itrXhrn.next();
420 HeapRegionNode hrnX = edgeX.getDst();
422 // we can do a strong update here if one of two cases holds
424 f != DisjointAnalysis.getArrayField( f.getType() ) &&
425 ( (hrnX.getNumReferencers() == 1) || // case 1
426 (hrnX.isSingleObject() && lnX.getNumReferencees() == 1) // case 2
429 if( !DISABLE_STRONG_UPDATES ) {
431 clearRefEdgesFrom( hrnX, f.getType(), f.getSymbol(), false );
436 // then do all token propagation
437 itrXhrn = lnX.iteratorToReferencees();
438 while( itrXhrn.hasNext() ) {
439 RefEdge edgeX = itrXhrn.next();
440 HeapRegionNode hrnX = edgeX.getDst();
441 ReachSet betaX = edgeX.getBeta();
442 ReachSet R = Canonical.intersection( hrnX.getAlpha(),
446 Iterator<RefEdge> itrYhrn = lnY.iteratorToReferencees();
447 while( itrYhrn.hasNext() ) {
448 RefEdge edgeY = itrYhrn.next();
449 HeapRegionNode hrnY = edgeY.getDst();
450 ReachSet O = edgeY.getBeta();
452 // check for impossible edges
453 if( !isSuperiorType( f.getType(), edgeY.getType() ) ) {
454 impossibleEdges.add( edgeY );
458 // propagate tokens over nodes starting from hrnSrc, and it will
459 // take care of propagating back up edges from any touched nodes
460 ChangeSet Cy = Canonical.unionUpArityToChangeSet( O, R );
461 propagateTokensOverNodes( hrnY, Cy, nodesWithNewAlpha, edgesWithNewBeta );
463 // then propagate back just up the edges from hrn
464 ChangeSet Cx = Canonical.unionUpArityToChangeSet( R, O );
465 HashSet<RefEdge> todoEdges = new HashSet<RefEdge>();
467 Hashtable<RefEdge, ChangeSet> edgePlannedChanges =
468 new Hashtable<RefEdge, ChangeSet>();
470 Iterator<RefEdge> referItr = hrnX.iteratorToReferencers();
471 while( referItr.hasNext() ) {
472 RefEdge edgeUpstream = referItr.next();
473 todoEdges.add( edgeUpstream );
474 edgePlannedChanges.put( edgeUpstream, Cx );
477 propagateTokensOverEdges( todoEdges,
484 // apply the updates to reachability
485 Iterator<HeapRegionNode> nodeItr = nodesWithNewAlpha.iterator();
486 while( nodeItr.hasNext() ) {
487 nodeItr.next().applyAlphaNew();
490 Iterator<RefEdge> edgeItr = edgesWithNewBeta.iterator();
491 while( edgeItr.hasNext() ) {
492 edgeItr.next().applyBetaNew();
496 // then go back through and add the new edges
497 itrXhrn = lnX.iteratorToReferencees();
498 while( itrXhrn.hasNext() ) {
499 RefEdge edgeX = itrXhrn.next();
500 HeapRegionNode hrnX = edgeX.getDst();
502 Iterator<RefEdge> itrYhrn = lnY.iteratorToReferencees();
503 while( itrYhrn.hasNext() ) {
504 RefEdge edgeY = itrYhrn.next();
505 HeapRegionNode hrnY = edgeY.getDst();
507 // skip impossible edges here, we already marked them
508 // when computing reachability propagations above
509 if( !isSuperiorType( f.getType(), edgeY.getType() ) ) {
513 // prepare the new reference edge hrnX.f -> hrnY
514 TypeDescriptor tdNewEdge =
515 mostSpecificType( y.getType(),
520 RefEdge edgeNew = new RefEdge( hrnX,
524 Canonical.pruneBy( edgeY.getBeta(),
530 // look to see if an edge with same field exists
531 // and merge with it, otherwise just add the edge
532 RefEdge edgeExisting = hrnX.getReferenceTo( hrnY,
536 if( edgeExisting != null ) {
537 edgeExisting.setBeta(
538 Canonical.union( edgeExisting.getBeta(),
542 edgeExisting.setPreds(
543 Canonical.join( edgeExisting.getPreds(),
549 addRefEdge( hrnX, hrnY, edgeNew );
554 Iterator<RefEdge> itrImp = impossibleEdges.iterator();
555 while( itrImp.hasNext() ) {
556 RefEdge edgeImp = itrImp.next();
557 removeRefEdge( edgeImp );
560 // if there was a strong update, make sure to improve
561 // reachability with a global sweep
562 if( strongUpdate || !impossibleEdges.isEmpty() ) {
563 if( !DISABLE_GLOBAL_SWEEP ) {
570 public void assignReturnEqualToTemp( TempDescriptor x ) {
572 VariableNode lnR = getVariableNodeFromTemp( tdReturn );
573 VariableNode lnX = getVariableNodeFromTemp( x );
575 clearRefEdgesFrom( lnR, null, null, true );
577 Iterator<RefEdge> itrXhrn = lnX.iteratorToReferencees();
578 while( itrXhrn.hasNext() ) {
579 RefEdge edgeX = itrXhrn.next();
580 HeapRegionNode referencee = edgeX.getDst();
581 RefEdge edgeNew = edgeX.copy();
582 edgeNew.setSrc( lnR );
584 addRefEdge( lnR, referencee, edgeNew );
589 public void assignTempEqualToNewAlloc( TempDescriptor x,
596 // after the age operation the newest (or zero-ith oldest)
597 // node associated with the allocation site should have
598 // no references to it as if it were a newly allocated
600 Integer idNewest = as.getIthOldest( 0 );
601 HeapRegionNode hrnNewest = id2hrn.get( idNewest );
602 assert hrnNewest != null;
604 VariableNode lnX = getVariableNodeFromTemp( x );
605 clearRefEdgesFrom( lnX, null, null, true );
607 // make a new reference to allocated node
608 TypeDescriptor type = as.getType();
611 new RefEdge( lnX, // source
615 hrnNewest.getAlpha(), // beta
616 predsTrue // predicates
619 addRefEdge( lnX, hrnNewest, edgeNew );
623 // use the allocation site (unique to entire analysis) to
624 // locate the heap region nodes in this reachability graph
625 // that should be aged. The process models the allocation
626 // of new objects and collects all the oldest allocations
627 // in a summary node to allow for a finite analysis
629 // There is an additional property of this method. After
630 // running it on a particular reachability graph (many graphs
631 // may have heap regions related to the same allocation site)
632 // the heap region node objects in this reachability graph will be
633 // allocated. Therefore, after aging a graph for an allocation
634 // site, attempts to retrieve the heap region nodes using the
635 // integer id's contained in the allocation site should always
636 // return non-null heap regions.
637 public void age( AllocSite as ) {
639 // keep track of allocation sites that are represented
640 // in this graph for efficiency with other operations
641 allocSites.add( as );
643 // if there is a k-th oldest node, it merges into
645 Integer idK = as.getOldest();
646 if( id2hrn.containsKey( idK ) ) {
647 HeapRegionNode hrnK = id2hrn.get( idK );
649 // retrieve the summary node, or make it
651 HeapRegionNode hrnSummary = getSummaryNode( as );
653 mergeIntoSummary( hrnK, hrnSummary );
656 // move down the line of heap region nodes
657 // clobbering the ith and transferring all references
658 // to and from i-1 to node i.
659 for( int i = allocationDepth - 1; i > 0; --i ) {
661 // if the target (ith) node exists, clobber it
662 // whether the i-1 node exists or not
663 Integer idIth = as.getIthOldest( i );
664 if( id2hrn.containsKey( idIth ) ) {
665 HeapRegionNode hrnI = id2hrn.get( idIth );
667 // clear all references in and out
671 // only do the transfer if the i-1 node exists
672 Integer idImin1th = as.getIthOldest( i - 1 );
673 if( id2hrn.containsKey( idImin1th ) ) {
674 HeapRegionNode hrnImin1 = id2hrn.get( idImin1th );
676 // either retrieve or make target of transfer
677 HeapRegionNode hrnI = getIthNode( as, i );
679 transferOnto( hrnImin1, hrnI );
684 // as stated above, the newest node should have had its
685 // references moved over to the second oldest, so we wipe newest
686 // in preparation for being the new object to assign something to
687 HeapRegionNode hrn0 = getIthNode( as, 0 );
690 // now tokens in reachability sets need to "age" also
691 Iterator itrAllVariableNodes = td2vn.entrySet().iterator();
692 while( itrAllVariableNodes.hasNext() ) {
693 Map.Entry me = (Map.Entry) itrAllVariableNodes.next();
694 VariableNode ln = (VariableNode) me.getValue();
696 Iterator<RefEdge> itrEdges = ln.iteratorToReferencees();
697 while( itrEdges.hasNext() ) {
698 ageTuplesFrom( as, itrEdges.next() );
702 Iterator itrAllHRNodes = id2hrn.entrySet().iterator();
703 while( itrAllHRNodes.hasNext() ) {
704 Map.Entry me = (Map.Entry) itrAllHRNodes.next();
705 HeapRegionNode hrnToAge = (HeapRegionNode) me.getValue();
707 ageTuplesFrom( as, hrnToAge );
709 Iterator<RefEdge> itrEdges = hrnToAge.iteratorToReferencees();
710 while( itrEdges.hasNext() ) {
711 ageTuplesFrom( as, itrEdges.next() );
716 // after tokens have been aged, reset newest node's reachability
717 // and a brand new node has a "true" predicate
718 hrn0.setAlpha( hrn0.getInherent() );
719 hrn0.setPreds( predsTrue );
723 // either retrieve or create the needed heap region node
724 protected HeapRegionNode getSummaryNode( AllocSite as ) {
726 Integer idSummary = as.getSummary();
727 HeapRegionNode hrnSummary = id2hrn.get( idSummary );
729 if( hrnSummary == null ) {
731 boolean hasFlags = false;
732 if( as.getType().isClass() ) {
733 hasFlags = as.getType().getClassDesc().hasFlags();
737 hasFlags = as.getFlag();
740 String strDesc = as.toStringForDOT()+"\\nsummary";
742 createNewHeapRegionNode( idSummary, // id or null to generate a new one
743 false, // single object?
745 hasFlags, // flagged?
746 false, // out-of-context?
747 as.getType(), // type
748 as, // allocation site
749 null, // inherent reach
750 null, // current reach
751 predsEmpty, // predicates
752 strDesc // description
759 // either retrieve or create the needed heap region node
760 protected HeapRegionNode getIthNode( AllocSite as, Integer i ) {
762 Integer idIth = as.getIthOldest( i );
763 HeapRegionNode hrnIth = id2hrn.get( idIth );
765 if( hrnIth == null ) {
767 boolean hasFlags = false;
768 if( as.getType().isClass() ) {
769 hasFlags = as.getType().getClassDesc().hasFlags();
773 hasFlags = as.getFlag();
776 String strDesc = as.toStringForDOT()+"\\n"+i+" oldest";
777 hrnIth = createNewHeapRegionNode( idIth, // id or null to generate a new one
778 true, // single object?
780 hasFlags, // flagged?
781 false, // out-of-context?
782 as.getType(), // type
783 as, // allocation site
784 null, // inherent reach
785 null, // current reach
786 predsEmpty, // predicates
787 strDesc // description
796 protected void mergeIntoSummary( HeapRegionNode hrn,
797 HeapRegionNode hrnSummary ) {
798 assert hrnSummary.isNewSummary();
800 // transfer references _from_ hrn over to hrnSummary
801 Iterator<RefEdge> itrReferencee = hrn.iteratorToReferencees();
802 while( itrReferencee.hasNext() ) {
803 RefEdge edge = itrReferencee.next();
804 RefEdge edgeMerged = edge.copy();
805 edgeMerged.setSrc( hrnSummary );
807 HeapRegionNode hrnReferencee = edge.getDst();
808 RefEdge edgeSummary =
809 hrnSummary.getReferenceTo( hrnReferencee,
814 if( edgeSummary == null ) {
815 // the merge is trivial, nothing to be done
817 // otherwise an edge from the referencer to hrnSummary exists already
818 // and the edge referencer->hrn should be merged with it
820 Canonical.union( edgeMerged.getBeta(),
821 edgeSummary.getBeta()
825 Canonical.join( edgeMerged.getPreds(),
826 edgeSummary.getPreds()
831 addRefEdge( hrnSummary, hrnReferencee, edgeMerged );
834 // next transfer references _to_ hrn over to hrnSummary
835 Iterator<RefEdge> itrReferencer = hrn.iteratorToReferencers();
836 while( itrReferencer.hasNext() ) {
837 RefEdge edge = itrReferencer.next();
838 RefEdge edgeMerged = edge.copy();
839 edgeMerged.setDst( hrnSummary );
841 RefSrcNode onReferencer = edge.getSrc();
842 RefEdge edgeSummary =
843 onReferencer.getReferenceTo( hrnSummary,
848 if( edgeSummary == null ) {
849 // the merge is trivial, nothing to be done
851 // otherwise an edge from the referencer to alpha_S exists already
852 // and the edge referencer->alpha_K should be merged with it
854 Canonical.union( edgeMerged.getBeta(),
855 edgeSummary.getBeta()
859 Canonical.join( edgeMerged.getPreds(),
860 edgeSummary.getPreds()
865 addRefEdge( onReferencer, hrnSummary, edgeMerged );
868 // then merge hrn reachability into hrnSummary
870 Canonical.union( hrnSummary.getAlpha(),
877 protected void transferOnto( HeapRegionNode hrnA,
878 HeapRegionNode hrnB ) {
880 // don't allow a heap region from one graph to
881 // get transferred onto a region from another
882 // graph!! Do the transfer on the equivalent
884 assert id2hrn.get( hrnA.getID() ) == hrnA;
885 assert id2hrn.get( hrnB.getID() ) == hrnB;
887 // clear references in and out of node b
890 // copy each edge in and out of A to B
891 Iterator<RefEdge> itrReferencee = hrnA.iteratorToReferencees();
892 while( itrReferencee.hasNext() ) {
893 RefEdge edge = itrReferencee.next();
894 HeapRegionNode hrnReferencee = edge.getDst();
895 RefEdge edgeNew = edge.copy();
896 edgeNew.setSrc( hrnB );
897 edgeNew.setDst( hrnReferencee );
899 addRefEdge( hrnB, hrnReferencee, edgeNew );
902 Iterator<RefEdge> itrReferencer = hrnA.iteratorToReferencers();
903 while( itrReferencer.hasNext() ) {
904 RefEdge edge = itrReferencer.next();
905 RefSrcNode onReferencer = edge.getSrc();
906 RefEdge edgeNew = edge.copy();
907 edgeNew.setDst( hrnB );
908 edgeNew.setDst( hrnB );
910 addRefEdge( onReferencer, hrnB, edgeNew );
913 // replace hrnB reachability and preds with hrnA's
914 hrnB.setAlpha( hrnA.getAlpha() );
915 hrnB.setPreds( hrnA.getPreds() );
919 // the purpose of this method is to conceptually "wipe out"
920 // a heap region from the graph--purposefully not called REMOVE
921 // because the node is still hanging around in the graph, just
922 // not mechanically connected or have any reach or predicate
923 // information on it anymore--lots of ops can use this
924 protected void wipeOut( HeapRegionNode hrn ) {
925 clearRefEdgesFrom( hrn, null, null, true );
926 clearRefEdgesTo ( hrn, null, null, true );
927 hrn.setAlpha( rsetEmpty );
928 hrn.setPreds( predsEmpty );
932 protected void ageTuplesFrom( AllocSite as, RefEdge edge ) {
934 Canonical.ageTuplesFrom( edge.getBeta(),
940 protected void ageTuplesFrom( AllocSite as, HeapRegionNode hrn ) {
942 Canonical.ageTuplesFrom( hrn.getAlpha(),
950 protected void propagateTokensOverNodes( HeapRegionNode nPrime,
952 HashSet<HeapRegionNode> nodesWithNewAlpha,
953 HashSet<RefEdge> edgesWithNewBeta ) {
955 HashSet<HeapRegionNode> todoNodes
956 = new HashSet<HeapRegionNode>();
957 todoNodes.add( nPrime );
959 HashSet<RefEdge> todoEdges
960 = new HashSet<RefEdge>();
962 Hashtable<HeapRegionNode, ChangeSet> nodePlannedChanges
963 = new Hashtable<HeapRegionNode, ChangeSet>();
964 nodePlannedChanges.put( nPrime, c0 );
966 Hashtable<RefEdge, ChangeSet> edgePlannedChanges
967 = new Hashtable<RefEdge, ChangeSet>();
969 // first propagate change sets everywhere they can go
970 while( !todoNodes.isEmpty() ) {
971 HeapRegionNode n = todoNodes.iterator().next();
972 ChangeSet C = nodePlannedChanges.get( n );
974 Iterator<RefEdge> referItr = n.iteratorToReferencers();
975 while( referItr.hasNext() ) {
976 RefEdge edge = referItr.next();
977 todoEdges.add( edge );
979 if( !edgePlannedChanges.containsKey( edge ) ) {
980 edgePlannedChanges.put( edge,
985 edgePlannedChanges.put( edge,
986 Canonical.union( edgePlannedChanges.get( edge ),
992 Iterator<RefEdge> refeeItr = n.iteratorToReferencees();
993 while( refeeItr.hasNext() ) {
994 RefEdge edgeF = refeeItr.next();
995 HeapRegionNode m = edgeF.getDst();
997 ChangeSet changesToPass = ChangeSet.factory();
999 Iterator<ChangeTuple> itrCprime = C.iterator();
1000 while( itrCprime.hasNext() ) {
1001 ChangeTuple c = itrCprime.next();
1002 if( edgeF.getBeta().contains( c.getSetToMatch() ) ) {
1003 changesToPass = Canonical.union( changesToPass, c );
1007 if( !changesToPass.isEmpty() ) {
1008 if( !nodePlannedChanges.containsKey( m ) ) {
1009 nodePlannedChanges.put( m, ChangeSet.factory() );
1012 ChangeSet currentChanges = nodePlannedChanges.get( m );
1014 if( !changesToPass.isSubset( currentChanges ) ) {
1016 nodePlannedChanges.put( m,
1017 Canonical.union( currentChanges,
1026 todoNodes.remove( n );
1029 // then apply all of the changes for each node at once
1030 Iterator itrMap = nodePlannedChanges.entrySet().iterator();
1031 while( itrMap.hasNext() ) {
1032 Map.Entry me = (Map.Entry) itrMap.next();
1033 HeapRegionNode n = (HeapRegionNode) me.getKey();
1034 ChangeSet C = (ChangeSet) me.getValue();
1036 // this propagation step is with respect to one change,
1037 // so we capture the full change from the old alpha:
1038 ReachSet localDelta = Canonical.applyChangeSet( n.getAlpha(),
1042 // but this propagation may be only one of many concurrent
1043 // possible changes, so keep a running union with the node's
1044 // partially updated new alpha set
1045 n.setAlphaNew( Canonical.union( n.getAlphaNew(),
1050 nodesWithNewAlpha.add( n );
1053 propagateTokensOverEdges( todoEdges,
1060 protected void propagateTokensOverEdges( HashSet <RefEdge> todoEdges,
1061 Hashtable<RefEdge, ChangeSet> edgePlannedChanges,
1062 HashSet <RefEdge> edgesWithNewBeta ) {
1064 // first propagate all change tuples everywhere they can go
1065 while( !todoEdges.isEmpty() ) {
1066 RefEdge edgeE = todoEdges.iterator().next();
1067 todoEdges.remove( edgeE );
1069 if( !edgePlannedChanges.containsKey( edgeE ) ) {
1070 edgePlannedChanges.put( edgeE,
1075 ChangeSet C = edgePlannedChanges.get( edgeE );
1077 ChangeSet changesToPass = ChangeSet.factory();
1079 Iterator<ChangeTuple> itrC = C.iterator();
1080 while( itrC.hasNext() ) {
1081 ChangeTuple c = itrC.next();
1082 if( edgeE.getBeta().contains( c.getSetToMatch() ) ) {
1083 changesToPass = Canonical.union( changesToPass, c );
1087 RefSrcNode rsn = edgeE.getSrc();
1089 if( !changesToPass.isEmpty() && rsn instanceof HeapRegionNode ) {
1090 HeapRegionNode n = (HeapRegionNode) rsn;
1092 Iterator<RefEdge> referItr = n.iteratorToReferencers();
1093 while( referItr.hasNext() ) {
1094 RefEdge edgeF = referItr.next();
1096 if( !edgePlannedChanges.containsKey( edgeF ) ) {
1097 edgePlannedChanges.put( edgeF,
1102 ChangeSet currentChanges = edgePlannedChanges.get( edgeF );
1104 if( !changesToPass.isSubset( currentChanges ) ) {
1105 todoEdges.add( edgeF );
1106 edgePlannedChanges.put( edgeF,
1107 Canonical.union( currentChanges,
1116 // then apply all of the changes for each edge at once
1117 Iterator itrMap = edgePlannedChanges.entrySet().iterator();
1118 while( itrMap.hasNext() ) {
1119 Map.Entry me = (Map.Entry) itrMap.next();
1120 RefEdge e = (RefEdge) me.getKey();
1121 ChangeSet C = (ChangeSet) me.getValue();
1123 // this propagation step is with respect to one change,
1124 // so we capture the full change from the old beta:
1125 ReachSet localDelta =
1126 Canonical.applyChangeSet( e.getBeta(),
1131 // but this propagation may be only one of many concurrent
1132 // possible changes, so keep a running union with the edge's
1133 // partially updated new beta set
1134 e.setBetaNew( Canonical.union( e.getBetaNew(),
1139 edgesWithNewBeta.add( e );
1145 // use this method to make a new reach graph that is
1146 // what heap the FlatMethod callee from the FlatCall
1147 // would start with reaching from its arguments in
1150 makeCalleeView( FlatCall fc,
1152 Set<HeapRegionNode> callerNodesCopiedToCallee,
1153 Set<RefEdge> callerEdgesCopiedToCallee,
1154 boolean writeDebugDOTs
1157 // the callee view is a new graph: DON'T MODIFY
1159 ReachGraph rg = new ReachGraph();
1161 // track what parts of this graph have already been
1162 // added to callee view, variables not needed.
1163 // Note that we need this because when we traverse
1164 // this caller graph for each parameter we may find
1165 // nodes and edges more than once (which the per-param
1166 // "visit" sets won't show) and we only want to create
1167 // an element in the new callee view one time
1168 //Set callerNodesCopiedToCallee = new HashSet<HeapRegionNode>();
1169 //Set callerEdgesCopiedToCallee = new HashSet<RefEdge>();
1172 // a conservative starting point is to take the
1173 // mechanically-reachable-from-arguments graph
1174 // as opposed to using reachability information
1175 // to prune the graph further
1176 for( int i = 0; i < fm.numParameters(); ++i ) {
1178 // for each parameter index, get the symbol in the
1179 // caller view and callee view
1181 // argument defined here is the symbol in the caller
1182 TempDescriptor tdArg = fc.getArgMatchingParamIndex( fm, i );
1184 // parameter defined here is the symbol in the callee
1185 TempDescriptor tdParam = fm.getParameter( i );
1187 // use these two VariableNode objects to translate
1188 // between caller and callee--its easy to compare
1189 // a HeapRegionNode across callee and caller because
1190 // they will have the same heap region ID
1191 VariableNode vnCaller = this.getVariableNodeFromTemp( tdArg );
1192 VariableNode vnCallee = rg.getVariableNodeFromTemp( tdParam );
1194 // now traverse the calleR view using the argument to
1195 // build the calleE view which has the parameter symbol
1196 Set<RefSrcNode> toVisitInCaller = new HashSet<RefSrcNode>();
1197 Set<RefSrcNode> visitedInCaller = new HashSet<RefSrcNode>();
1198 toVisitInCaller.add( vnCaller );
1200 while( !toVisitInCaller.isEmpty() ) {
1201 RefSrcNode rsnCaller = toVisitInCaller.iterator().next();
1202 RefSrcNode rsnCallee;
1204 toVisitInCaller.remove( rsnCaller );
1205 visitedInCaller.add( rsnCaller );
1207 // FIRST - setup the source end of an edge, and
1208 // remember the identifying info of the source
1209 // to build predicates
1210 TempDescriptor tdSrc = null;
1211 Integer hrnSrcID = null;
1213 if( rsnCaller == vnCaller ) {
1214 // if the caller node is the param symbol, we
1215 // have to do this translation for the callee
1216 rsnCallee = vnCallee;
1220 // otherwise the callee-view node is a heap
1221 // region with the same ID, that may or may
1222 // not have been created already
1223 assert rsnCaller instanceof HeapRegionNode;
1225 HeapRegionNode hrnSrcCaller = (HeapRegionNode) rsnCaller;
1226 hrnSrcID = hrnSrcCaller.getID();
1228 if( !callerNodesCopiedToCallee.contains( rsnCaller ) ) {
1231 ExistPred.factory( hrnSrcID, null );
1233 ExistPredSet preds =
1234 ExistPredSet.factory( pred );
1237 rg.createNewHeapRegionNode( hrnSrcCaller.getID(),
1238 hrnSrcCaller.isSingleObject(),
1239 hrnSrcCaller.isNewSummary(),
1240 hrnSrcCaller.isFlagged(),
1241 false, // out-of-context?
1242 hrnSrcCaller.getType(),
1243 hrnSrcCaller.getAllocSite(),
1244 /*toShadowTokens( this,*/ hrnSrcCaller.getInherent() /*)*/,
1245 /*toShadowTokens( this,*/ hrnSrcCaller.getAlpha() /*)*/,
1247 hrnSrcCaller.getDescription()
1249 callerNodesCopiedToCallee.add( (HeapRegionNode) rsnCaller );
1252 rsnCallee = rg.id2hrn.get( hrnSrcID );
1256 // SECOND - go over all edges from that source
1258 Iterator<RefEdge> itrRefEdges = rsnCaller.iteratorToReferencees();
1259 while( itrRefEdges.hasNext() ) {
1260 RefEdge reCaller = itrRefEdges.next();
1261 HeapRegionNode hrnCaller = reCaller.getDst();
1262 HeapRegionNode hrnCallee;
1264 // THIRD - setup destination ends of edges
1265 Integer hrnDstID = hrnCaller.getID();
1267 if( !callerNodesCopiedToCallee.contains( hrnCaller ) ) {
1270 ExistPred.factory( hrnDstID, null );
1272 ExistPredSet preds =
1273 ExistPredSet.factory( pred );
1276 rg.createNewHeapRegionNode( hrnCaller.getID(),
1277 hrnCaller.isSingleObject(),
1278 hrnCaller.isNewSummary(),
1279 hrnCaller.isFlagged(),
1280 false, // out-of-context?
1281 hrnCaller.getType(),
1282 hrnCaller.getAllocSite(),
1283 /*toShadowTokens( this,*/ hrnCaller.getInherent() /*)*/,
1284 /*toShadowTokens( this,*/ hrnCaller.getAlpha() /*)*/,
1286 hrnCaller.getDescription()
1288 callerNodesCopiedToCallee.add( hrnCaller );
1290 hrnCallee = rg.id2hrn.get( hrnDstID );
1293 // FOURTH - copy edge over if needed
1294 if( !callerEdgesCopiedToCallee.contains( reCaller ) ) {
1297 ExistPred.factory( tdSrc,
1301 reCaller.getField(),
1304 ExistPredSet preds =
1305 ExistPredSet.factory( pred );
1307 rg.addRefEdge( rsnCallee,
1309 new RefEdge( rsnCallee,
1312 reCaller.getField(),
1313 /*toShadowTokens( this,*/ reCaller.getBeta() /*)*/,
1317 callerEdgesCopiedToCallee.add( reCaller );
1320 // keep traversing nodes reachable from param i
1321 // that we haven't visited yet
1322 if( !visitedInCaller.contains( hrnCaller ) ) {
1323 toVisitInCaller.add( hrnCaller );
1326 } // end edge iteration
1327 } // end visiting heap nodes in caller
1328 } // end iterating over parameters as starting points
1331 // find the set of edges in this graph with source
1332 // out-of-context (not in nodes copied) and have a
1333 // destination in context (one of nodes copied) as
1334 // a starting point for building out-of-context nodes
1335 Iterator<HeapRegionNode> itrInContext =
1336 callerNodesCopiedToCallee.iterator();
1337 while( itrInContext.hasNext() ) {
1338 HeapRegionNode hrnCallerAndInContext = itrInContext.next();
1340 Iterator<RefEdge> itrMightCross =
1341 hrnCallerAndInContext.iteratorToReferencers();
1342 while( itrMightCross.hasNext() ) {
1343 RefEdge edgeMightCross = itrMightCross.next();
1345 // we're only interested in edges with a source
1346 // 1) out-of-context and 2) is a heap region
1347 if( callerNodesCopiedToCallee.contains( edgeMightCross.getSrc() ) ||
1348 !(edgeMightCross.getSrc() instanceof HeapRegionNode)
1354 HeapRegionNode hrnCallerAndOutContext =
1355 (HeapRegionNode) edgeMightCross.getSrc();
1357 // we found a reference that crosses from out-of-context
1358 // to in-context, so build a special out-of-context node
1359 // for the callee IHM and its reference edge
1360 HeapRegionNode hrnCalleeAndOutContext =
1361 rg.createNewHeapRegionNode( null, // ID
1362 false, // single object?
1363 false, // new summary?
1365 true, // out-of-context?
1366 hrnCallerAndOutContext.getType(),
1367 null, // alloc site, shouldn't be used
1368 /*toShadowTokens( this,*/ hrnCallerAndOutContext.getAlpha() /*)*/, // inherent
1369 /*toShadowTokens( this,*/ hrnCallerAndOutContext.getAlpha() /*)*/, // alpha
1374 HeapRegionNode hrnCalleeAndInContext =
1375 rg.id2hrn.get( hrnCallerAndInContext.getID() );
1377 rg.addRefEdge( hrnCalleeAndOutContext,
1378 hrnCalleeAndInContext,
1379 new RefEdge( hrnCalleeAndOutContext,
1380 hrnCalleeAndInContext,
1381 edgeMightCross.getType(),
1382 edgeMightCross.getField(),
1383 /*toShadowTokens( this,*/ edgeMightCross.getBeta() /*)*/,
1390 if( writeDebugDOTs ) {
1392 rg.writeGraph( "calleeview", true, false, false, false, true, true );
1393 } catch( IOException e ) {}
1400 resolveMethodCall( FlatCall fc,
1402 ReachGraph rgCallee,
1403 Set<HeapRegionNode> callerNodesCopiedToCallee,
1404 Set<RefEdge> callerEdgesCopiedToCallee,
1405 boolean writeDebugDOTs
1409 if( writeDebugDOTs ) {
1411 this.writeGraph( "caller", true, false, false, false, true, true,
1412 callerNodesCopiedToCallee, callerEdgesCopiedToCallee );
1413 rgCallee.writeGraph( "callee", true, false, false, false, true, true );
1414 } catch( IOException e ) {}
1418 // method call transfer function steps:
1419 // 1. Use current callee-reachable heap (CRH) to test callee
1420 // predicates and mark what will be coming in.
1421 // 2. Wipe CRH out of caller.
1422 // 3. Transplant marked callee parts in:
1423 // a) bring in nodes
1424 // b) bring in callee -> callee edges
1425 // c) resolve out-of-context -> callee edges
1426 // 4. Global sweep it.
1430 // 1. mark what callee elements have satisfied predicates
1431 Set<HeapRegionNode> calleeNodesSatisfied =
1432 new HashSet<HeapRegionNode>();
1434 Set<RefEdge> calleeEdgesSatisfied =
1435 new HashSet<RefEdge>();
1437 Iterator meItr = rgCallee.id2hrn.entrySet().iterator();
1438 while( meItr.hasNext() ) {
1439 Map.Entry me = (Map.Entry) meItr.next();
1440 Integer id = (Integer) me.getKey();
1441 HeapRegionNode hrnCallee = (HeapRegionNode) me.getValue();
1443 if( hrnCallee.getPreds().isSatisfiedBy( this,
1444 callerNodesCopiedToCallee,
1445 callerEdgesCopiedToCallee
1448 calleeNodesSatisfied.add( hrnCallee );
1451 Iterator<RefEdge> reItr = hrnCallee.iteratorToReferencees();
1452 while( reItr.hasNext() ) {
1453 RefEdge reCallee = reItr.next();
1455 if( reCallee.getPreds().isSatisfiedBy( this,
1456 callerNodesCopiedToCallee,
1457 callerEdgesCopiedToCallee
1460 calleeEdgesSatisfied.add( reCallee );
1465 // test param -> HRN edges, also
1466 for( int i = 0; i < fm.numParameters(); ++i ) {
1468 // parameter defined here is the symbol in the callee
1469 TempDescriptor tdParam = fm.getParameter( i );
1470 VariableNode vnCallee = rgCallee.getVariableNodeFromTemp( tdParam );
1472 Iterator<RefEdge> reItr = vnCallee.iteratorToReferencees();
1473 while( reItr.hasNext() ) {
1474 RefEdge reCallee = reItr.next();
1476 if( reCallee.getPreds().isSatisfiedBy( this,
1477 callerNodesCopiedToCallee,
1478 callerEdgesCopiedToCallee
1481 calleeEdgesSatisfied.add( reCallee );
1488 // 2. predicates tested, ok to wipe out caller part
1489 Iterator<HeapRegionNode> hrnItr = callerNodesCopiedToCallee.iterator();
1490 while( hrnItr.hasNext() ) {
1491 HeapRegionNode hrnCaller = hrnItr.next();
1492 wipeOut( hrnCaller );
1496 // 3. callee elements with satisfied preds come in
1499 hrnItr = calleeNodesSatisfied.iterator();
1500 while( hrnItr.hasNext() ) {
1501 HeapRegionNode hrnCallee = hrnItr.next();
1503 if( hrnCallee.isOutOfContext() ) {
1507 HeapRegionNode hrnCaller = id2hrn.get( hrnCallee.getID() );
1508 if( hrnCaller == null ) {
1510 createNewHeapRegionNode( hrnCallee.getID(), // id or null to generate a new one
1511 hrnCallee.isSingleObject(), // single object?
1512 hrnCallee.isNewSummary(), // summary?
1513 hrnCallee.isFlagged(), // flagged?
1514 false, // out-of-context?
1515 hrnCallee.getType(), // type
1516 hrnCallee.getAllocSite(), // allocation site
1517 hrnCallee.getInherent(), // inherent reach
1518 null, // current reach
1519 predsEmpty, // predicates
1520 hrnCallee.getDescription() // description
1524 // TODO: alpha should be some rewritten version of callee in caller context
1525 hrnCaller.setAlpha( rsetEmpty );
1527 // TODO: predicates should be exact same from caller version that satisfied
1528 hrnCaller.setPreds( predsTrue );
1531 // 3.b) callee -> callee edges
1532 Iterator<RefEdge> reItr = calleeEdgesSatisfied.iterator();
1533 while( reItr.hasNext() ) {
1534 RefEdge reCallee = reItr.next();
1536 RefSrcNode rsnCallee = reCallee.getSrc();
1537 RefSrcNode rsnCaller;
1539 if( rsnCallee instanceof VariableNode ) {
1540 VariableNode vnCallee = (VariableNode) rsnCallee;
1541 TempDescriptor tdParam = vnCallee.getTempDescriptor();
1542 TempDescriptor tdArg = fc.getArgMatchingParam( fm,
1544 if( tdArg == null ) {
1545 // this means the variable isn't a parameter, its local
1546 // to the callee so we ignore it in call site transfer
1550 rsnCaller = this.getVariableNodeFromTemp( tdArg );
1553 HeapRegionNode hrnSrcCallee = (HeapRegionNode) reCallee.getSrc();
1554 rsnCaller = id2hrn.get( hrnSrcCallee.getID() );
1557 assert rsnCaller != null;
1559 HeapRegionNode hrnDstCallee = reCallee.getDst();
1560 HeapRegionNode hrnDstCaller = id2hrn.get( hrnDstCallee.getID() );
1561 assert hrnDstCaller != null;
1563 // TODO: beta rewrites, preds from satisfier in caller
1564 RefEdge reCaller = new RefEdge( rsnCaller,
1567 reCallee.getField(),
1571 addRefEdge( rsnCaller, hrnDstCaller, reCaller );
1574 // 3.c) resolve out-of-context -> callee edges
1583 if( writeDebugDOTs ) {
1585 writeGraph( "callerAfterTransfer",
1586 true, false, false, false, true, true,
1588 } catch( IOException e ) {}
1595 ////////////////////////////////////////////////////
1597 // Abstract garbage collection simply removes
1598 // heap region nodes that are not mechanically
1599 // reachable from a root set. This step is
1600 // essential for testing node and edge existence
1601 // predicates efficiently
1603 ////////////////////////////////////////////////////
1604 public void abstractGarbageCollect( Set<TempDescriptor> liveSet ) {
1606 // calculate a root set, will be different for Java
1607 // version of analysis versus Bamboo version
1608 Set<RefSrcNode> toVisit = new HashSet<RefSrcNode>();
1610 // visit every variable in graph while building root
1611 // set, and do iterating on a copy, so we can remove
1612 // dead variables while we're at this
1613 Iterator makeCopyItr = td2vn.entrySet().iterator();
1614 Set entrysCopy = new HashSet();
1615 while( makeCopyItr.hasNext() ) {
1616 entrysCopy.add( makeCopyItr.next() );
1619 Iterator eItr = entrysCopy.iterator();
1620 while( eItr.hasNext() ) {
1621 Map.Entry me = (Map.Entry) eItr.next();
1622 TempDescriptor td = (TempDescriptor) me.getKey();
1623 VariableNode vn = (VariableNode) me.getValue();
1625 if( liveSet.contains( td ) ) {
1629 // dead var, remove completely from graph
1631 clearRefEdgesFrom( vn, null, null, true );
1635 // everything visited in a traversal is
1636 // considered abstractly live
1637 Set<RefSrcNode> visited = new HashSet<RefSrcNode>();
1639 while( !toVisit.isEmpty() ) {
1640 RefSrcNode rsn = toVisit.iterator().next();
1641 toVisit.remove( rsn );
1644 Iterator<RefEdge> hrnItr = rsn.iteratorToReferencees();
1645 while( hrnItr.hasNext() ) {
1646 RefEdge edge = hrnItr.next();
1647 HeapRegionNode hrn = edge.getDst();
1649 if( !visited.contains( hrn ) ) {
1655 // get a copy of the set to iterate over because
1656 // we're going to monkey with the graph when we
1657 // identify a garbage node
1658 Set<HeapRegionNode> hrnAllPrior = new HashSet<HeapRegionNode>();
1659 Iterator<HeapRegionNode> hrnItr = id2hrn.values().iterator();
1660 while( hrnItr.hasNext() ) {
1661 hrnAllPrior.add( hrnItr.next() );
1664 Iterator<HeapRegionNode> hrnAllItr = hrnAllPrior.iterator();
1665 while( hrnAllItr.hasNext() ) {
1666 HeapRegionNode hrn = hrnAllItr.next();
1668 if( !visited.contains( hrn ) ) {
1670 // heap region nodes are compared across ReachGraph
1671 // objects by their integer ID, so when discarding
1672 // garbage nodes we must also discard entries in
1673 // the ID -> heap region hashtable.
1674 id2hrn.remove( hrn.getID() );
1676 // RefEdge objects are two-way linked between
1677 // nodes, so when a node is identified as garbage,
1678 // actively clear references to and from it so
1679 // live nodes won't have dangling RefEdge's
1682 // if we just removed the last node from an allocation
1683 // site, it should be taken out of the ReachGraph's list
1684 AllocSite as = hrn.getAllocSite();
1685 if( !hasNodesOf( as ) ) {
1686 allocSites.remove( as );
1692 protected boolean hasNodesOf( AllocSite as ) {
1693 if( id2hrn.containsKey( as.getSummary() ) ) {
1697 for( int i = 0; i < allocationDepth; ++i ) {
1698 if( id2hrn.containsKey( as.getIthOldest( i ) ) ) {
1706 ////////////////////////////////////////////////////
1708 // This global sweep is an optional step to prune
1709 // reachability sets that are not internally
1710 // consistent with the global graph. It should be
1711 // invoked after strong updates or method calls.
1713 ////////////////////////////////////////////////////
1714 public void globalSweep() {
1716 // boldB is part of the phase 1 sweep
1717 Hashtable< Integer, Hashtable<RefEdge, ReachSet> > boldB =
1718 new Hashtable< Integer, Hashtable<RefEdge, ReachSet> >();
1720 // visit every heap region to initialize alphaNew and calculate boldB
1721 Iterator itrHrns = id2hrn.entrySet().iterator();
1722 while( itrHrns.hasNext() ) {
1723 Map.Entry me = (Map.Entry) itrHrns.next();
1724 Integer hrnID = (Integer) me.getKey();
1725 HeapRegionNode hrn = (HeapRegionNode) me.getValue();
1727 // assert that this node and incoming edges have clean alphaNew
1728 // and betaNew sets, respectively
1729 assert rsetEmpty.equals( hrn.getAlphaNew() );
1731 Iterator<RefEdge> itrRers = hrn.iteratorToReferencers();
1732 while( itrRers.hasNext() ) {
1733 RefEdge edge = itrRers.next();
1734 assert rsetEmpty.equals( edge.getBetaNew() );
1737 // calculate boldB for this flagged node
1738 if( hrn.isFlagged() ) {
1740 Hashtable<RefEdge, ReachSet> boldB_f =
1741 new Hashtable<RefEdge, ReachSet>();
1743 Set<RefEdge> workSetEdges = new HashSet<RefEdge>();
1745 // initial boldB_f constraints
1746 Iterator<RefEdge> itrRees = hrn.iteratorToReferencees();
1747 while( itrRees.hasNext() ) {
1748 RefEdge edge = itrRees.next();
1750 assert !boldB.containsKey( edge );
1751 boldB_f.put( edge, edge.getBeta() );
1753 assert !workSetEdges.contains( edge );
1754 workSetEdges.add( edge );
1757 // enforce the boldB_f constraint at edges until we reach a fixed point
1758 while( !workSetEdges.isEmpty() ) {
1759 RefEdge edge = workSetEdges.iterator().next();
1760 workSetEdges.remove( edge );
1762 Iterator<RefEdge> itrPrime = edge.getDst().iteratorToReferencees();
1763 while( itrPrime.hasNext() ) {
1764 RefEdge edgePrime = itrPrime.next();
1766 ReachSet prevResult = boldB_f.get( edgePrime );
1767 ReachSet intersection = Canonical.intersection( boldB_f.get( edge ),
1771 if( prevResult == null ||
1772 Canonical.union( prevResult,
1773 intersection ).size() > prevResult.size() ) {
1775 if( prevResult == null ) {
1776 boldB_f.put( edgePrime,
1777 Canonical.union( edgePrime.getBeta(),
1782 boldB_f.put( edgePrime,
1783 Canonical.union( prevResult,
1788 workSetEdges.add( edgePrime );
1793 boldB.put( hrnID, boldB_f );
1798 // use boldB to prune hrnIDs from alpha states that are impossible
1799 // and propagate the differences backwards across edges
1800 HashSet<RefEdge> edgesForPropagation = new HashSet<RefEdge>();
1802 Hashtable<RefEdge, ChangeSet> edgePlannedChanges =
1803 new Hashtable<RefEdge, ChangeSet>();
1806 itrHrns = id2hrn.entrySet().iterator();
1807 while( itrHrns.hasNext() ) {
1808 Map.Entry me = (Map.Entry) itrHrns.next();
1809 Integer hrnID = (Integer) me.getKey();
1810 HeapRegionNode hrn = (HeapRegionNode) me.getValue();
1812 // create the inherent hrnID from a flagged region
1813 // as an exception to removal below
1814 ReachTuple rtException =
1815 ReachTuple.factory( hrnID,
1816 !hrn.isSingleObject(),
1817 ReachTuple.ARITY_ONE
1820 ChangeSet cts = ChangeSet.factory();
1822 // mark hrnIDs for removal
1823 Iterator<ReachState> stateItr = hrn.getAlpha().iterator();
1824 while( stateItr.hasNext() ) {
1825 ReachState stateOld = stateItr.next();
1827 ReachState markedHrnIDs = ReachState.factory();
1829 Iterator<ReachTuple> rtItr = stateOld.iterator();
1830 while( rtItr.hasNext() ) {
1831 ReachTuple rtOld = rtItr.next();
1833 // never remove the inherent hrnID from a flagged region
1834 // because it is trivially satisfied
1835 if( hrn.isFlagged() ) {
1836 if( rtOld == rtException ) {
1841 // does boldB_ttOld allow this hrnID?
1842 boolean foundState = false;
1843 Iterator<RefEdge> incidentEdgeItr = hrn.iteratorToReferencers();
1844 while( incidentEdgeItr.hasNext() ) {
1845 RefEdge incidentEdge = incidentEdgeItr.next();
1847 // if it isn't allowed, mark for removal
1848 Integer idOld = rtOld.getHrnID();
1849 assert id2hrn.containsKey( idOld );
1850 Hashtable<RefEdge, ReachSet> B = boldB.get( idOld );
1851 ReachSet boldB_ttOld_incident = B.get( incidentEdge );
1852 if( boldB_ttOld_incident != null &&
1853 boldB_ttOld_incident.contains( stateOld ) ) {
1859 markedHrnIDs = Canonical.add( markedHrnIDs, rtOld );
1863 // if there is nothing marked, just move on
1864 if( markedHrnIDs.isEmpty() ) {
1865 hrn.setAlphaNew( Canonical.union( hrn.getAlphaNew(),
1872 // remove all marked hrnIDs and establish a change set that should
1873 // propagate backwards over edges from this node
1874 ReachState statePruned = ReachState.factory();
1875 rtItr = stateOld.iterator();
1876 while( rtItr.hasNext() ) {
1877 ReachTuple rtOld = rtItr.next();
1879 if( !markedHrnIDs.containsTuple( rtOld ) ) {
1880 statePruned = Canonical.union( statePruned, rtOld );
1883 assert !stateOld.equals( statePruned );
1885 hrn.setAlphaNew( Canonical.union( hrn.getAlphaNew(),
1889 ChangeTuple ct = ChangeTuple.factory( stateOld,
1892 cts = Canonical.union( cts, ct );
1895 // throw change tuple set on all incident edges
1896 if( !cts.isEmpty() ) {
1897 Iterator<RefEdge> incidentEdgeItr = hrn.iteratorToReferencers();
1898 while( incidentEdgeItr.hasNext() ) {
1899 RefEdge incidentEdge = incidentEdgeItr.next();
1901 edgesForPropagation.add( incidentEdge );
1903 if( edgePlannedChanges.get( incidentEdge ) == null ) {
1904 edgePlannedChanges.put( incidentEdge, cts );
1906 edgePlannedChanges.put(
1908 Canonical.union( edgePlannedChanges.get( incidentEdge ),
1917 HashSet<RefEdge> edgesUpdated = new HashSet<RefEdge>();
1919 propagateTokensOverEdges( edgesForPropagation,
1923 // at the end of the 1st phase reference edges have
1924 // beta, betaNew that correspond to beta and betaR
1926 // commit beta<-betaNew, so beta=betaR and betaNew
1927 // will represent the beta' calculation in 2nd phase
1929 // commit alpha<-alphaNew because it won't change
1930 HashSet<RefEdge> res = new HashSet<RefEdge>();
1932 Iterator<HeapRegionNode> nodeItr = id2hrn.values().iterator();
1933 while( nodeItr.hasNext() ) {
1934 HeapRegionNode hrn = nodeItr.next();
1935 hrn.applyAlphaNew();
1936 Iterator<RefEdge> itrRes = hrn.iteratorToReferencers();
1937 while( itrRes.hasNext() ) {
1938 res.add( itrRes.next() );
1944 Iterator<RefEdge> edgeItr = res.iterator();
1945 while( edgeItr.hasNext() ) {
1946 RefEdge edge = edgeItr.next();
1947 HeapRegionNode hrn = edge.getDst();
1949 // commit results of last phase
1950 if( edgesUpdated.contains( edge ) ) {
1951 edge.applyBetaNew();
1954 // compute intial condition of 2nd phase
1955 edge.setBetaNew( Canonical.intersection( edge.getBeta(),
1961 // every edge in the graph is the initial workset
1962 Set<RefEdge> edgeWorkSet = (Set) res.clone();
1963 while( !edgeWorkSet.isEmpty() ) {
1964 RefEdge edgePrime = edgeWorkSet.iterator().next();
1965 edgeWorkSet.remove( edgePrime );
1967 RefSrcNode rsn = edgePrime.getSrc();
1968 if( !(rsn instanceof HeapRegionNode) ) {
1971 HeapRegionNode hrn = (HeapRegionNode) rsn;
1973 Iterator<RefEdge> itrEdge = hrn.iteratorToReferencers();
1974 while( itrEdge.hasNext() ) {
1975 RefEdge edge = itrEdge.next();
1977 ReachSet prevResult = edge.getBetaNew();
1978 assert prevResult != null;
1980 ReachSet intersection =
1981 Canonical.intersection( edge.getBeta(),
1982 edgePrime.getBetaNew()
1985 if( Canonical.union( prevResult,
1987 ).size() > prevResult.size() ) {
1989 Canonical.union( prevResult,
1993 edgeWorkSet.add( edge );
1998 // commit beta' (beta<-betaNew)
1999 edgeItr = res.iterator();
2000 while( edgeItr.hasNext() ) {
2001 edgeItr.next().applyBetaNew();
2007 ////////////////////////////////////////////////////
2008 // high-level merge operations
2009 ////////////////////////////////////////////////////
2010 public void merge_sameMethodContext( ReachGraph rg ) {
2011 // when merging two graphs that abstract the heap
2012 // of the same method context, we just call the
2013 // basic merge operation
2017 public void merge_diffMethodContext( ReachGraph rg ) {
2018 // when merging graphs for abstract heaps in
2019 // different method contexts we should:
2020 // 1) age the allocation sites?
2024 ////////////////////////////////////////////////////
2025 // in merge() and equals() methods the suffix A
2026 // represents the passed in graph and the suffix
2027 // B refers to the graph in this object
2028 // Merging means to take the incoming graph A and
2029 // merge it into B, so after the operation graph B
2030 // is the final result.
2031 ////////////////////////////////////////////////////
2032 protected void merge( ReachGraph rg ) {
2039 mergeRefEdges ( rg );
2040 mergeAllocSites( rg );
2043 protected void mergeNodes( ReachGraph rg ) {
2045 // start with heap region nodes
2046 Set sA = rg.id2hrn.entrySet();
2047 Iterator iA = sA.iterator();
2048 while( iA.hasNext() ) {
2049 Map.Entry meA = (Map.Entry) iA.next();
2050 Integer idA = (Integer) meA.getKey();
2051 HeapRegionNode hrnA = (HeapRegionNode) meA.getValue();
2053 // if this graph doesn't have a node the
2054 // incoming graph has, allocate it
2055 if( !id2hrn.containsKey( idA ) ) {
2056 HeapRegionNode hrnB = hrnA.copy();
2057 id2hrn.put( idA, hrnB );
2060 // otherwise this is a node present in both graphs
2061 // so make the new reachability set a union of the
2062 // nodes' reachability sets
2063 HeapRegionNode hrnB = id2hrn.get( idA );
2064 hrnB.setAlpha( Canonical.union( hrnB.getAlpha(),
2069 // if hrnB is already dirty or hrnA is dirty,
2070 // the hrnB should end up dirty: TODO
2072 if( !hrnA.isClean() ) {
2073 hrnB.setIsClean( false );
2079 // now add any variable nodes that are in graph B but
2081 sA = rg.td2vn.entrySet();
2083 while( iA.hasNext() ) {
2084 Map.Entry meA = (Map.Entry) iA.next();
2085 TempDescriptor tdA = (TempDescriptor) meA.getKey();
2086 VariableNode lnA = (VariableNode) meA.getValue();
2088 // if the variable doesn't exist in B, allocate and add it
2089 VariableNode lnB = getVariableNodeFromTemp( tdA );
2093 protected void mergeRefEdges( ReachGraph rg ) {
2095 // between heap regions
2096 Set sA = rg.id2hrn.entrySet();
2097 Iterator iA = sA.iterator();
2098 while( iA.hasNext() ) {
2099 Map.Entry meA = (Map.Entry) iA.next();
2100 Integer idA = (Integer) meA.getKey();
2101 HeapRegionNode hrnA = (HeapRegionNode) meA.getValue();
2103 Iterator<RefEdge> heapRegionsItrA = hrnA.iteratorToReferencees();
2104 while( heapRegionsItrA.hasNext() ) {
2105 RefEdge edgeA = heapRegionsItrA.next();
2106 HeapRegionNode hrnChildA = edgeA.getDst();
2107 Integer idChildA = hrnChildA.getID();
2109 // at this point we know an edge in graph A exists
2110 // idA -> idChildA, does this exist in B?
2111 assert id2hrn.containsKey( idA );
2112 HeapRegionNode hrnB = id2hrn.get( idA );
2113 RefEdge edgeToMerge = null;
2115 Iterator<RefEdge> heapRegionsItrB = hrnB.iteratorToReferencees();
2116 while( heapRegionsItrB.hasNext() &&
2117 edgeToMerge == null ) {
2119 RefEdge edgeB = heapRegionsItrB.next();
2120 HeapRegionNode hrnChildB = edgeB.getDst();
2121 Integer idChildB = hrnChildB.getID();
2123 // don't use the RefEdge.equals() here because
2124 // we're talking about existence between graphs,
2125 // not intragraph equal
2126 if( idChildB.equals( idChildA ) &&
2127 edgeB.typeAndFieldEquals( edgeA ) ) {
2129 edgeToMerge = edgeB;
2133 // if the edge from A was not found in B,
2135 if( edgeToMerge == null ) {
2136 assert id2hrn.containsKey( idChildA );
2137 HeapRegionNode hrnChildB = id2hrn.get( idChildA );
2138 edgeToMerge = edgeA.copy();
2139 edgeToMerge.setSrc( hrnB );
2140 edgeToMerge.setDst( hrnChildB );
2141 addRefEdge( hrnB, hrnChildB, edgeToMerge );
2143 // otherwise, the edge already existed in both graphs
2144 // so merge their reachability sets
2146 // just replace this beta set with the union
2147 assert edgeToMerge != null;
2148 edgeToMerge.setBeta(
2149 Canonical.union( edgeToMerge.getBeta(),
2155 if( !edgeA.isClean() ) {
2156 edgeToMerge.setIsClean( false );
2163 // and then again from variable nodes
2164 sA = rg.td2vn.entrySet();
2166 while( iA.hasNext() ) {
2167 Map.Entry meA = (Map.Entry) iA.next();
2168 TempDescriptor tdA = (TempDescriptor) meA.getKey();
2169 VariableNode vnA = (VariableNode) meA.getValue();
2171 Iterator<RefEdge> heapRegionsItrA = vnA.iteratorToReferencees();
2172 while( heapRegionsItrA.hasNext() ) {
2173 RefEdge edgeA = heapRegionsItrA.next();
2174 HeapRegionNode hrnChildA = edgeA.getDst();
2175 Integer idChildA = hrnChildA.getID();
2177 // at this point we know an edge in graph A exists
2178 // tdA -> idChildA, does this exist in B?
2179 assert td2vn.containsKey( tdA );
2180 VariableNode vnB = td2vn.get( tdA );
2181 RefEdge edgeToMerge = null;
2183 Iterator<RefEdge> heapRegionsItrB = vnB.iteratorToReferencees();
2184 while( heapRegionsItrB.hasNext() &&
2185 edgeToMerge == null ) {
2187 RefEdge edgeB = heapRegionsItrB.next();
2188 HeapRegionNode hrnChildB = edgeB.getDst();
2189 Integer idChildB = hrnChildB.getID();
2191 // don't use the RefEdge.equals() here because
2192 // we're talking about existence between graphs
2193 if( idChildB.equals( idChildA ) &&
2194 edgeB.typeAndFieldEquals( edgeA ) ) {
2196 edgeToMerge = edgeB;
2200 // if the edge from A was not found in B,
2202 if( edgeToMerge == null ) {
2203 assert id2hrn.containsKey( idChildA );
2204 HeapRegionNode hrnChildB = id2hrn.get( idChildA );
2205 edgeToMerge = edgeA.copy();
2206 edgeToMerge.setSrc( vnB );
2207 edgeToMerge.setDst( hrnChildB );
2208 addRefEdge( vnB, hrnChildB, edgeToMerge );
2210 // otherwise, the edge already existed in both graphs
2211 // so merge their reachability sets
2213 // just replace this beta set with the union
2214 edgeToMerge.setBeta( Canonical.union( edgeToMerge.getBeta(),
2220 if( !edgeA.isClean() ) {
2221 edgeToMerge.setIsClean( false );
2229 protected void mergeAllocSites( ReachGraph rg ) {
2230 allocSites.addAll( rg.allocSites );
2234 // it is necessary in the equals() member functions
2235 // to "check both ways" when comparing the data
2236 // structures of two graphs. For instance, if all
2237 // edges between heap region nodes in graph A are
2238 // present and equal in graph B it is not sufficient
2239 // to say the graphs are equal. Consider that there
2240 // may be edges in graph B that are not in graph A.
2241 // the only way to know that all edges in both graphs
2242 // are equally present is to iterate over both data
2243 // structures and compare against the other graph.
2244 public boolean equals( ReachGraph rg ) {
2250 if( !areHeapRegionNodesEqual( rg ) ) {
2254 if( !areVariableNodesEqual( rg ) ) {
2258 if( !areRefEdgesEqual( rg ) ) {
2262 // if everything is equal up to this point,
2263 // assert that allocSites is also equal--
2264 // this data is redundant but kept for efficiency
2265 assert allocSites.equals( rg.allocSites );
2271 protected boolean areHeapRegionNodesEqual( ReachGraph rg ) {
2273 if( !areallHRNinAalsoinBandequal( this, rg ) ) {
2277 if( !areallHRNinAalsoinBandequal( rg, this ) ) {
2284 static protected boolean areallHRNinAalsoinBandequal( ReachGraph rgA,
2286 Set sA = rgA.id2hrn.entrySet();
2287 Iterator iA = sA.iterator();
2288 while( iA.hasNext() ) {
2289 Map.Entry meA = (Map.Entry) iA.next();
2290 Integer idA = (Integer) meA.getKey();
2291 HeapRegionNode hrnA = (HeapRegionNode) meA.getValue();
2293 if( !rgB.id2hrn.containsKey( idA ) ) {
2297 HeapRegionNode hrnB = rgB.id2hrn.get( idA );
2298 if( !hrnA.equalsIncludingAlphaAndPreds( hrnB ) ) {
2307 protected boolean areVariableNodesEqual( ReachGraph rg ) {
2309 if( !areallVNinAalsoinBandequal( this, rg ) ) {
2313 if( !areallVNinAalsoinBandequal( rg, this ) ) {
2320 static protected boolean areallVNinAalsoinBandequal( ReachGraph rgA,
2322 Set sA = rgA.td2vn.entrySet();
2323 Iterator iA = sA.iterator();
2324 while( iA.hasNext() ) {
2325 Map.Entry meA = (Map.Entry) iA.next();
2326 TempDescriptor tdA = (TempDescriptor) meA.getKey();
2328 if( !rgB.td2vn.containsKey( tdA ) ) {
2337 protected boolean areRefEdgesEqual( ReachGraph rg ) {
2338 if( !areallREinAandBequal( this, rg ) ) {
2345 static protected boolean areallREinAandBequal( ReachGraph rgA,
2348 // check all the heap region->heap region edges
2349 Set sA = rgA.id2hrn.entrySet();
2350 Iterator iA = sA.iterator();
2351 while( iA.hasNext() ) {
2352 Map.Entry meA = (Map.Entry) iA.next();
2353 Integer idA = (Integer) meA.getKey();
2354 HeapRegionNode hrnA = (HeapRegionNode) meA.getValue();
2356 // we should have already checked that the same
2357 // heap regions exist in both graphs
2358 assert rgB.id2hrn.containsKey( idA );
2360 if( !areallREfromAequaltoB( rgA, hrnA, rgB ) ) {
2364 // then check every edge in B for presence in A, starting
2365 // from the same parent HeapRegionNode
2366 HeapRegionNode hrnB = rgB.id2hrn.get( idA );
2368 if( !areallREfromAequaltoB( rgB, hrnB, rgA ) ) {
2373 // then check all the variable->heap region edges
2374 sA = rgA.td2vn.entrySet();
2376 while( iA.hasNext() ) {
2377 Map.Entry meA = (Map.Entry) iA.next();
2378 TempDescriptor tdA = (TempDescriptor) meA.getKey();
2379 VariableNode vnA = (VariableNode) meA.getValue();
2381 // we should have already checked that the same
2382 // label nodes exist in both graphs
2383 assert rgB.td2vn.containsKey( tdA );
2385 if( !areallREfromAequaltoB( rgA, vnA, rgB ) ) {
2389 // then check every edge in B for presence in A, starting
2390 // from the same parent VariableNode
2391 VariableNode vnB = rgB.td2vn.get( tdA );
2393 if( !areallREfromAequaltoB( rgB, vnB, rgA ) ) {
2402 static protected boolean areallREfromAequaltoB( ReachGraph rgA,
2406 Iterator<RefEdge> itrA = rnA.iteratorToReferencees();
2407 while( itrA.hasNext() ) {
2408 RefEdge edgeA = itrA.next();
2409 HeapRegionNode hrnChildA = edgeA.getDst();
2410 Integer idChildA = hrnChildA.getID();
2412 assert rgB.id2hrn.containsKey( idChildA );
2414 // at this point we know an edge in graph A exists
2415 // rnA -> idChildA, does this exact edge exist in B?
2416 boolean edgeFound = false;
2418 RefSrcNode rnB = null;
2419 if( rnA instanceof HeapRegionNode ) {
2420 HeapRegionNode hrnA = (HeapRegionNode) rnA;
2421 rnB = rgB.id2hrn.get( hrnA.getID() );
2423 VariableNode vnA = (VariableNode) rnA;
2424 rnB = rgB.td2vn.get( vnA.getTempDescriptor() );
2427 Iterator<RefEdge> itrB = rnB.iteratorToReferencees();
2428 while( itrB.hasNext() ) {
2429 RefEdge edgeB = itrB.next();
2430 HeapRegionNode hrnChildB = edgeB.getDst();
2431 Integer idChildB = hrnChildB.getID();
2433 if( idChildA.equals( idChildB ) &&
2434 edgeA.typeAndFieldEquals( edgeB ) ) {
2436 // there is an edge in the right place with the right field,
2437 // but do they have the same attributes?
2438 if( edgeA.getBeta().equals( edgeB.getBeta() ) &&
2439 edgeA.equalsPreds( edgeB )
2456 // this analysis no longer has the "match anything"
2457 // type which was represented by null
2458 protected TypeDescriptor mostSpecificType( TypeDescriptor td1,
2459 TypeDescriptor td2 ) {
2463 if( td1.isNull() ) {
2466 if( td2.isNull() ) {
2469 return typeUtil.mostSpecific( td1, td2 );
2472 protected TypeDescriptor mostSpecificType( TypeDescriptor td1,
2474 TypeDescriptor td3 ) {
2476 return mostSpecificType( td1,
2477 mostSpecificType( td2, td3 )
2481 protected TypeDescriptor mostSpecificType( TypeDescriptor td1,
2484 TypeDescriptor td4 ) {
2486 return mostSpecificType( mostSpecificType( td1, td2 ),
2487 mostSpecificType( td3, td4 )
2491 protected boolean isSuperiorType( TypeDescriptor possibleSuper,
2492 TypeDescriptor possibleChild ) {
2493 assert possibleSuper != null;
2494 assert possibleChild != null;
2496 if( possibleSuper.isNull() ||
2497 possibleChild.isNull() ) {
2501 return typeUtil.isSuperorType( possibleSuper, possibleChild );
2505 protected boolean hasMatchingField( HeapRegionNode src,
2508 TypeDescriptor tdSrc = src.getType();
2509 assert tdSrc != null;
2511 if( tdSrc.isArray() ) {
2512 TypeDescriptor td = edge.getType();
2515 TypeDescriptor tdSrcDeref = tdSrc.dereference();
2516 assert tdSrcDeref != null;
2518 if( !typeUtil.isSuperorType( tdSrcDeref, td ) ) {
2522 return edge.getField().equals( DisjointAnalysis.arrayElementFieldName );
2525 // if it's not a class, it doesn't have any fields to match
2526 if( !tdSrc.isClass() ) {
2530 ClassDescriptor cd = tdSrc.getClassDesc();
2531 while( cd != null ) {
2532 Iterator fieldItr = cd.getFields();
2534 while( fieldItr.hasNext() ) {
2535 FieldDescriptor fd = (FieldDescriptor) fieldItr.next();
2537 if( fd.getType().equals( edge.getType() ) &&
2538 fd.getSymbol().equals( edge.getField() ) ) {
2543 cd = cd.getSuperDesc();
2546 // otherwise it is a class with fields
2547 // but we didn't find a match
2551 protected boolean hasMatchingType( RefEdge edge,
2552 HeapRegionNode dst ) {
2554 // if the region has no type, matches everything
2555 TypeDescriptor tdDst = dst.getType();
2556 assert tdDst != null;
2558 // if the type is not a class or an array, don't
2559 // match because primitives are copied, no aliases
2560 ClassDescriptor cdDst = tdDst.getClassDesc();
2561 if( cdDst == null && !tdDst.isArray() ) {
2565 // if the edge type is null, it matches everything
2566 TypeDescriptor tdEdge = edge.getType();
2567 assert tdEdge != null;
2569 return typeUtil.isSuperorType( tdEdge, tdDst );
2574 public void writeGraph( String graphName,
2575 boolean writeLabels,
2576 boolean labelSelect,
2577 boolean pruneGarbage,
2578 boolean writeReferencers,
2579 boolean hideSubsetReachability,
2580 boolean hideEdgeTaints
2581 ) throws java.io.IOException {
2582 writeGraph( graphName,
2587 hideSubsetReachability,
2593 public void writeGraph( String graphName,
2594 boolean writeLabels,
2595 boolean labelSelect,
2596 boolean pruneGarbage,
2597 boolean writeReferencers,
2598 boolean hideSubsetReachability,
2599 boolean hideEdgeTaints,
2600 Set<HeapRegionNode> callerNodesCopiedToCallee,
2601 Set<RefEdge> callerEdgesCopiedToCallee
2602 ) throws java.io.IOException {
2604 // remove all non-word characters from the graph name so
2605 // the filename and identifier in dot don't cause errors
2606 graphName = graphName.replaceAll( "[\\W]", "" );
2609 new BufferedWriter( new FileWriter( graphName+".dot" ) );
2611 bw.write( "digraph "+graphName+" {\n" );
2614 // this is an optional step to form the callee-reachable
2615 // "cut-out" into a DOT cluster for visualization
2616 if( callerNodesCopiedToCallee != null ) {
2618 bw.write( " subgraph cluster0 {\n" );
2619 bw.write( " color=blue;\n" );
2621 Iterator i = id2hrn.entrySet().iterator();
2622 while( i.hasNext() ) {
2623 Map.Entry me = (Map.Entry) i.next();
2624 HeapRegionNode hrn = (HeapRegionNode) me.getValue();
2626 if( callerNodesCopiedToCallee.contains( hrn ) ) {
2627 bw.write( " "+hrn.toString()+
2628 hrn.toStringDOT( hideSubsetReachability )+
2638 Set<HeapRegionNode> visited = new HashSet<HeapRegionNode>();
2640 // then visit every heap region node
2641 Iterator i = id2hrn.entrySet().iterator();
2642 while( i.hasNext() ) {
2643 Map.Entry me = (Map.Entry) i.next();
2644 HeapRegionNode hrn = (HeapRegionNode) me.getValue();
2646 // only visit nodes worth writing out--for instance
2647 // not every node at an allocation is referenced
2648 // (think of it as garbage-collected), etc.
2649 if( !pruneGarbage ||
2650 (hrn.isFlagged() && hrn.getID() > 0) ||
2651 hrn.getDescription().startsWith( "param" ) ||
2652 hrn.isOutOfContext()
2655 if( !visited.contains( hrn ) ) {
2656 traverseHeapRegionNodes( hrn,
2661 hideSubsetReachability,
2663 callerNodesCopiedToCallee,
2664 callerEdgesCopiedToCallee );
2669 bw.write( " graphTitle[label=\""+graphName+"\",shape=box];\n" );
2672 // then visit every label node, useful for debugging
2674 i = td2vn.entrySet().iterator();
2675 while( i.hasNext() ) {
2676 Map.Entry me = (Map.Entry) i.next();
2677 VariableNode vn = (VariableNode) me.getValue();
2680 String labelStr = vn.getTempDescriptorString();
2681 if( labelStr.startsWith("___temp") ||
2682 labelStr.startsWith("___dst") ||
2683 labelStr.startsWith("___srctmp") ||
2684 labelStr.startsWith("___neverused")
2690 Iterator<RefEdge> heapRegionsItr = vn.iteratorToReferencees();
2691 while( heapRegionsItr.hasNext() ) {
2692 RefEdge edge = heapRegionsItr.next();
2693 HeapRegionNode hrn = edge.getDst();
2695 if( pruneGarbage && !visited.contains( hrn ) ) {
2696 traverseHeapRegionNodes( hrn,
2701 hideSubsetReachability,
2703 callerNodesCopiedToCallee,
2704 callerEdgesCopiedToCallee );
2707 bw.write( " "+vn.toString()+
2708 " -> "+hrn.toString()+
2709 edge.toStringDOT( hideSubsetReachability, "" )+
2719 protected void traverseHeapRegionNodes( HeapRegionNode hrn,
2722 Set<HeapRegionNode> visited,
2723 boolean writeReferencers,
2724 boolean hideSubsetReachability,
2725 boolean hideEdgeTaints,
2726 Set<HeapRegionNode> callerNodesCopiedToCallee,
2727 Set<RefEdge> callerEdgesCopiedToCallee
2728 ) throws java.io.IOException {
2730 if( visited.contains( hrn ) ) {
2735 // if we're drawing the callee-view subgraph, only
2736 // write out the node info if it hasn't already been
2738 if( callerNodesCopiedToCallee == null ||
2739 !callerNodesCopiedToCallee.contains( hrn )
2741 bw.write( " "+hrn.toString()+
2742 hrn.toStringDOT( hideSubsetReachability )+
2746 Iterator<RefEdge> childRegionsItr = hrn.iteratorToReferencees();
2747 while( childRegionsItr.hasNext() ) {
2748 RefEdge edge = childRegionsItr.next();
2749 HeapRegionNode hrnChild = edge.getDst();
2751 if( callerEdgesCopiedToCallee != null &&
2752 callerEdgesCopiedToCallee.contains( hrn )
2754 bw.write( " "+hrn.toString()+
2755 " -> "+hrnChild.toString()+
2756 edge.toStringDOT( hideSubsetReachability, ",color=blue" )+
2759 bw.write( " "+hrn.toString()+
2760 " -> "+hrnChild.toString()+
2761 edge.toStringDOT( hideSubsetReachability, "" )+
2765 traverseHeapRegionNodes( hrnChild,
2770 hideSubsetReachability,
2772 callerNodesCopiedToCallee,
2773 callerEdgesCopiedToCallee );