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( hrnB );
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() /*)*/,
1391 if( writeDebugDOTs ) {
1393 rg.writeGraph( "calleeview", true, false, false, false, true, true );
1394 } catch( IOException e ) {}
1402 resolveMethodCall( FlatCall fc,
1404 ReachGraph rgCallee,
1405 Set<HeapRegionNode> callerNodesCopiedToCallee,
1406 Set<RefEdge> callerEdgesCopiedToCallee,
1407 boolean writeDebugDOTs
1411 if( writeDebugDOTs ) {
1413 this.writeGraph( "caller", true, false, false, false, true, true,
1414 callerNodesCopiedToCallee, callerEdgesCopiedToCallee );
1415 rgCallee.writeGraph( "callee", true, false, false, false, true, true );
1416 } catch( IOException e ) {}
1420 // method call transfer function steps:
1421 // 1. Use current callee-reachable heap (CRH) to test callee
1422 // predicates and mark what will be coming in.
1423 // 2. Wipe CRH out of caller.
1424 // 3. Transplant marked callee parts in:
1425 // a) bring in nodes
1426 // b) bring in callee -> callee edges
1427 // c) resolve out-of-context -> callee edges
1428 // 4. Global sweep it.
1432 if( writeDebugDOTs ) {
1433 System.out.println( "doing call site, edges:"+callerEdgesCopiedToCallee );
1437 // 1. mark what callee elements have satisfied predicates
1438 Set<HeapRegionNode> calleeNodesSatisfied =
1439 new HashSet<HeapRegionNode>();
1441 Set<RefEdge> calleeEdgesSatisfied =
1442 new HashSet<RefEdge>();
1444 Iterator meItr = rgCallee.id2hrn.entrySet().iterator();
1445 while( meItr.hasNext() ) {
1446 Map.Entry me = (Map.Entry) meItr.next();
1447 Integer id = (Integer) me.getKey();
1448 HeapRegionNode hrnCallee = (HeapRegionNode) me.getValue();
1450 if( hrnCallee.getPreds().isSatisfiedBy( this,
1451 callerNodesCopiedToCallee,
1452 callerEdgesCopiedToCallee
1455 calleeNodesSatisfied.add( hrnCallee );
1459 if( writeDebugDOTs ) {
1460 System.out.println( " node satissfied: "+hrnCallee );
1465 Iterator<RefEdge> reItr = hrnCallee.iteratorToReferencees();
1466 while( reItr.hasNext() ) {
1467 RefEdge reCallee = reItr.next();
1469 if( reCallee.getPreds().isSatisfiedBy( this,
1470 callerNodesCopiedToCallee,
1471 callerEdgesCopiedToCallee
1474 calleeEdgesSatisfied.add( reCallee );
1479 // test param -> HRN edges, also
1480 for( int i = 0; i < fm.numParameters(); ++i ) {
1482 // parameter defined here is the symbol in the callee
1483 TempDescriptor tdParam = fm.getParameter( i );
1484 VariableNode vnCallee = rgCallee.getVariableNodeFromTemp( tdParam );
1486 Iterator<RefEdge> reItr = vnCallee.iteratorToReferencees();
1487 while( reItr.hasNext() ) {
1488 RefEdge reCallee = reItr.next();
1491 if( writeDebugDOTs ) {
1492 System.out.println( " satisfied?: "+reCallee );
1496 if( reCallee.getPreds().isSatisfiedBy( this,
1497 callerNodesCopiedToCallee,
1498 callerEdgesCopiedToCallee
1501 calleeEdgesSatisfied.add( reCallee );
1503 if( writeDebugDOTs ) {
1504 System.out.println( " satisfied: "+reCallee );
1509 if( writeDebugDOTs ) {
1510 System.out.println( " NOT satisfied: "+reCallee );
1520 // 2. predicates tested, ok to wipe out caller part
1521 Iterator<HeapRegionNode> hrnItr = callerNodesCopiedToCallee.iterator();
1522 while( hrnItr.hasNext() ) {
1523 HeapRegionNode hrnCaller = hrnItr.next();
1524 wipeOut( hrnCaller );
1526 if( writeDebugDOTs ) {
1527 System.out.println( " wiping: "+hrnCaller );
1532 // 3. callee elements with satisfied preds come in
1535 hrnItr = calleeNodesSatisfied.iterator();
1536 while( hrnItr.hasNext() ) {
1537 HeapRegionNode hrnCallee = hrnItr.next();
1539 if( hrnCallee.isOutOfContext() ) {
1543 HeapRegionNode hrnCaller = id2hrn.get( hrnCallee.getID() );
1544 if( hrnCaller == null ) {
1546 createNewHeapRegionNode( hrnCallee.getID(), // id or null to generate a new one
1547 hrnCallee.isSingleObject(), // single object?
1548 hrnCallee.isNewSummary(), // summary?
1549 hrnCallee.isFlagged(), // flagged?
1550 false, // out-of-context?
1551 hrnCallee.getType(), // type
1552 hrnCallee.getAllocSite(), // allocation site
1553 hrnCallee.getInherent(), // inherent reach
1554 null, // current reach
1555 predsEmpty, // predicates
1556 hrnCallee.getDescription() // description
1560 if( writeDebugDOTs ) {
1561 System.out.println( " stitching in: "+hrnCaller );
1564 // TODO: alpha should be some rewritten version of callee in caller context
1565 hrnCaller.setAlpha( rsetEmpty );
1567 // TODO: predicates should be exact same from caller version that satisfied
1568 hrnCaller.setPreds( predsTrue );
1571 // 3.b) callee -> callee edges
1572 Iterator<RefEdge> reItr = calleeEdgesSatisfied.iterator();
1573 while( reItr.hasNext() ) {
1574 RefEdge reCallee = reItr.next();
1576 RefSrcNode rsnCallee = reCallee.getSrc();
1577 RefSrcNode rsnCaller;
1579 if( rsnCallee instanceof VariableNode ) {
1580 VariableNode vnCallee = (VariableNode) rsnCallee;
1581 TempDescriptor tdParam = vnCallee.getTempDescriptor();
1582 TempDescriptor tdArg = fc.getArgMatchingParam( fm,
1585 if( writeDebugDOTs ) {
1586 System.out.println( " considering: "+rsnCallee );
1589 if( tdArg == null ) {
1590 // this means the variable isn't a parameter, its local
1591 // to the callee so we ignore it in call site transfer
1595 rsnCaller = this.getVariableNodeFromTemp( tdArg );
1597 if( writeDebugDOTs ) {
1598 System.out.println( " stitching in: "+rsnCaller );
1602 HeapRegionNode hrnSrcCallee = (HeapRegionNode) reCallee.getSrc();
1603 rsnCaller = id2hrn.get( hrnSrcCallee.getID() );
1606 assert rsnCaller != null;
1608 HeapRegionNode hrnDstCallee = reCallee.getDst();
1609 HeapRegionNode hrnDstCaller = id2hrn.get( hrnDstCallee.getID() );
1610 assert hrnDstCaller != null;
1612 // TODO: beta rewrites, preds from satisfier in caller
1613 RefEdge reCaller = new RefEdge( rsnCaller,
1616 reCallee.getField(),
1620 addRefEdge( rsnCaller, hrnDstCaller, reCaller );
1623 // 3.c) resolve out-of-context -> callee edges
1632 if( writeDebugDOTs ) {
1634 writeGraph( "callerAfter",
1635 true, false, false, false, true, true,
1637 } catch( IOException e ) {}
1644 ////////////////////////////////////////////////////
1646 // Abstract garbage collection simply removes
1647 // heap region nodes that are not mechanically
1648 // reachable from a root set. This step is
1649 // essential for testing node and edge existence
1650 // predicates efficiently
1652 ////////////////////////////////////////////////////
1653 public void abstractGarbageCollect( Set<TempDescriptor> liveSet ) {
1655 // calculate a root set, will be different for Java
1656 // version of analysis versus Bamboo version
1657 Set<RefSrcNode> toVisit = new HashSet<RefSrcNode>();
1659 // visit every variable in graph while building root
1660 // set, and do iterating on a copy, so we can remove
1661 // dead variables while we're at this
1662 Iterator makeCopyItr = td2vn.entrySet().iterator();
1663 Set entrysCopy = new HashSet();
1664 while( makeCopyItr.hasNext() ) {
1665 entrysCopy.add( makeCopyItr.next() );
1668 Iterator eItr = entrysCopy.iterator();
1669 while( eItr.hasNext() ) {
1670 Map.Entry me = (Map.Entry) eItr.next();
1671 TempDescriptor td = (TempDescriptor) me.getKey();
1672 VariableNode vn = (VariableNode) me.getValue();
1674 if( liveSet.contains( td ) ) {
1678 // dead var, remove completely from graph
1680 clearRefEdgesFrom( vn, null, null, true );
1684 // everything visited in a traversal is
1685 // considered abstractly live
1686 Set<RefSrcNode> visited = new HashSet<RefSrcNode>();
1688 while( !toVisit.isEmpty() ) {
1689 RefSrcNode rsn = toVisit.iterator().next();
1690 toVisit.remove( rsn );
1693 Iterator<RefEdge> hrnItr = rsn.iteratorToReferencees();
1694 while( hrnItr.hasNext() ) {
1695 RefEdge edge = hrnItr.next();
1696 HeapRegionNode hrn = edge.getDst();
1698 if( !visited.contains( hrn ) ) {
1704 // get a copy of the set to iterate over because
1705 // we're going to monkey with the graph when we
1706 // identify a garbage node
1707 Set<HeapRegionNode> hrnAllPrior = new HashSet<HeapRegionNode>();
1708 Iterator<HeapRegionNode> hrnItr = id2hrn.values().iterator();
1709 while( hrnItr.hasNext() ) {
1710 hrnAllPrior.add( hrnItr.next() );
1713 Iterator<HeapRegionNode> hrnAllItr = hrnAllPrior.iterator();
1714 while( hrnAllItr.hasNext() ) {
1715 HeapRegionNode hrn = hrnAllItr.next();
1717 if( !visited.contains( hrn ) ) {
1719 // heap region nodes are compared across ReachGraph
1720 // objects by their integer ID, so when discarding
1721 // garbage nodes we must also discard entries in
1722 // the ID -> heap region hashtable.
1723 id2hrn.remove( hrn.getID() );
1725 // RefEdge objects are two-way linked between
1726 // nodes, so when a node is identified as garbage,
1727 // actively clear references to and from it so
1728 // live nodes won't have dangling RefEdge's
1731 // if we just removed the last node from an allocation
1732 // site, it should be taken out of the ReachGraph's list
1733 AllocSite as = hrn.getAllocSite();
1734 if( !hasNodesOf( as ) ) {
1735 allocSites.remove( as );
1741 protected boolean hasNodesOf( AllocSite as ) {
1742 if( id2hrn.containsKey( as.getSummary() ) ) {
1746 for( int i = 0; i < allocationDepth; ++i ) {
1747 if( id2hrn.containsKey( as.getIthOldest( i ) ) ) {
1755 ////////////////////////////////////////////////////
1757 // This global sweep is an optional step to prune
1758 // reachability sets that are not internally
1759 // consistent with the global graph. It should be
1760 // invoked after strong updates or method calls.
1762 ////////////////////////////////////////////////////
1763 public void globalSweep() {
1765 // boldB is part of the phase 1 sweep
1766 Hashtable< Integer, Hashtable<RefEdge, ReachSet> > boldB =
1767 new Hashtable< Integer, Hashtable<RefEdge, ReachSet> >();
1769 // visit every heap region to initialize alphaNew and calculate boldB
1770 Iterator itrHrns = id2hrn.entrySet().iterator();
1771 while( itrHrns.hasNext() ) {
1772 Map.Entry me = (Map.Entry) itrHrns.next();
1773 Integer hrnID = (Integer) me.getKey();
1774 HeapRegionNode hrn = (HeapRegionNode) me.getValue();
1776 // assert that this node and incoming edges have clean alphaNew
1777 // and betaNew sets, respectively
1778 assert rsetEmpty.equals( hrn.getAlphaNew() );
1780 Iterator<RefEdge> itrRers = hrn.iteratorToReferencers();
1781 while( itrRers.hasNext() ) {
1782 RefEdge edge = itrRers.next();
1783 assert rsetEmpty.equals( edge.getBetaNew() );
1786 // calculate boldB for this flagged node
1787 if( hrn.isFlagged() ) {
1789 Hashtable<RefEdge, ReachSet> boldB_f =
1790 new Hashtable<RefEdge, ReachSet>();
1792 Set<RefEdge> workSetEdges = new HashSet<RefEdge>();
1794 // initial boldB_f constraints
1795 Iterator<RefEdge> itrRees = hrn.iteratorToReferencees();
1796 while( itrRees.hasNext() ) {
1797 RefEdge edge = itrRees.next();
1799 assert !boldB.containsKey( edge );
1800 boldB_f.put( edge, edge.getBeta() );
1802 assert !workSetEdges.contains( edge );
1803 workSetEdges.add( edge );
1806 // enforce the boldB_f constraint at edges until we reach a fixed point
1807 while( !workSetEdges.isEmpty() ) {
1808 RefEdge edge = workSetEdges.iterator().next();
1809 workSetEdges.remove( edge );
1811 Iterator<RefEdge> itrPrime = edge.getDst().iteratorToReferencees();
1812 while( itrPrime.hasNext() ) {
1813 RefEdge edgePrime = itrPrime.next();
1815 ReachSet prevResult = boldB_f.get( edgePrime );
1816 ReachSet intersection = Canonical.intersection( boldB_f.get( edge ),
1820 if( prevResult == null ||
1821 Canonical.union( prevResult,
1822 intersection ).size() > prevResult.size() ) {
1824 if( prevResult == null ) {
1825 boldB_f.put( edgePrime,
1826 Canonical.union( edgePrime.getBeta(),
1831 boldB_f.put( edgePrime,
1832 Canonical.union( prevResult,
1837 workSetEdges.add( edgePrime );
1842 boldB.put( hrnID, boldB_f );
1847 // use boldB to prune hrnIDs from alpha states that are impossible
1848 // and propagate the differences backwards across edges
1849 HashSet<RefEdge> edgesForPropagation = new HashSet<RefEdge>();
1851 Hashtable<RefEdge, ChangeSet> edgePlannedChanges =
1852 new Hashtable<RefEdge, ChangeSet>();
1855 itrHrns = id2hrn.entrySet().iterator();
1856 while( itrHrns.hasNext() ) {
1857 Map.Entry me = (Map.Entry) itrHrns.next();
1858 Integer hrnID = (Integer) me.getKey();
1859 HeapRegionNode hrn = (HeapRegionNode) me.getValue();
1861 // create the inherent hrnID from a flagged region
1862 // as an exception to removal below
1863 ReachTuple rtException =
1864 ReachTuple.factory( hrnID,
1865 !hrn.isSingleObject(),
1866 ReachTuple.ARITY_ONE
1869 ChangeSet cts = ChangeSet.factory();
1871 // mark hrnIDs for removal
1872 Iterator<ReachState> stateItr = hrn.getAlpha().iterator();
1873 while( stateItr.hasNext() ) {
1874 ReachState stateOld = stateItr.next();
1876 ReachState markedHrnIDs = ReachState.factory();
1878 Iterator<ReachTuple> rtItr = stateOld.iterator();
1879 while( rtItr.hasNext() ) {
1880 ReachTuple rtOld = rtItr.next();
1882 // never remove the inherent hrnID from a flagged region
1883 // because it is trivially satisfied
1884 if( hrn.isFlagged() ) {
1885 if( rtOld == rtException ) {
1890 // does boldB_ttOld allow this hrnID?
1891 boolean foundState = false;
1892 Iterator<RefEdge> incidentEdgeItr = hrn.iteratorToReferencers();
1893 while( incidentEdgeItr.hasNext() ) {
1894 RefEdge incidentEdge = incidentEdgeItr.next();
1896 // if it isn't allowed, mark for removal
1897 Integer idOld = rtOld.getHrnID();
1898 assert id2hrn.containsKey( idOld );
1899 Hashtable<RefEdge, ReachSet> B = boldB.get( idOld );
1900 ReachSet boldB_ttOld_incident = B.get( incidentEdge );
1901 if( boldB_ttOld_incident != null &&
1902 boldB_ttOld_incident.contains( stateOld ) ) {
1908 markedHrnIDs = Canonical.add( markedHrnIDs, rtOld );
1912 // if there is nothing marked, just move on
1913 if( markedHrnIDs.isEmpty() ) {
1914 hrn.setAlphaNew( Canonical.union( hrn.getAlphaNew(),
1921 // remove all marked hrnIDs and establish a change set that should
1922 // propagate backwards over edges from this node
1923 ReachState statePruned = ReachState.factory();
1924 rtItr = stateOld.iterator();
1925 while( rtItr.hasNext() ) {
1926 ReachTuple rtOld = rtItr.next();
1928 if( !markedHrnIDs.containsTuple( rtOld ) ) {
1929 statePruned = Canonical.union( statePruned, rtOld );
1932 assert !stateOld.equals( statePruned );
1934 hrn.setAlphaNew( Canonical.union( hrn.getAlphaNew(),
1938 ChangeTuple ct = ChangeTuple.factory( stateOld,
1941 cts = Canonical.union( cts, ct );
1944 // throw change tuple set on all incident edges
1945 if( !cts.isEmpty() ) {
1946 Iterator<RefEdge> incidentEdgeItr = hrn.iteratorToReferencers();
1947 while( incidentEdgeItr.hasNext() ) {
1948 RefEdge incidentEdge = incidentEdgeItr.next();
1950 edgesForPropagation.add( incidentEdge );
1952 if( edgePlannedChanges.get( incidentEdge ) == null ) {
1953 edgePlannedChanges.put( incidentEdge, cts );
1955 edgePlannedChanges.put(
1957 Canonical.union( edgePlannedChanges.get( incidentEdge ),
1966 HashSet<RefEdge> edgesUpdated = new HashSet<RefEdge>();
1968 propagateTokensOverEdges( edgesForPropagation,
1972 // at the end of the 1st phase reference edges have
1973 // beta, betaNew that correspond to beta and betaR
1975 // commit beta<-betaNew, so beta=betaR and betaNew
1976 // will represent the beta' calculation in 2nd phase
1978 // commit alpha<-alphaNew because it won't change
1979 HashSet<RefEdge> res = new HashSet<RefEdge>();
1981 Iterator<HeapRegionNode> nodeItr = id2hrn.values().iterator();
1982 while( nodeItr.hasNext() ) {
1983 HeapRegionNode hrn = nodeItr.next();
1984 hrn.applyAlphaNew();
1985 Iterator<RefEdge> itrRes = hrn.iteratorToReferencers();
1986 while( itrRes.hasNext() ) {
1987 res.add( itrRes.next() );
1993 Iterator<RefEdge> edgeItr = res.iterator();
1994 while( edgeItr.hasNext() ) {
1995 RefEdge edge = edgeItr.next();
1996 HeapRegionNode hrn = edge.getDst();
1998 // commit results of last phase
1999 if( edgesUpdated.contains( edge ) ) {
2000 edge.applyBetaNew();
2003 // compute intial condition of 2nd phase
2004 edge.setBetaNew( Canonical.intersection( edge.getBeta(),
2010 // every edge in the graph is the initial workset
2011 Set<RefEdge> edgeWorkSet = (Set) res.clone();
2012 while( !edgeWorkSet.isEmpty() ) {
2013 RefEdge edgePrime = edgeWorkSet.iterator().next();
2014 edgeWorkSet.remove( edgePrime );
2016 RefSrcNode rsn = edgePrime.getSrc();
2017 if( !(rsn instanceof HeapRegionNode) ) {
2020 HeapRegionNode hrn = (HeapRegionNode) rsn;
2022 Iterator<RefEdge> itrEdge = hrn.iteratorToReferencers();
2023 while( itrEdge.hasNext() ) {
2024 RefEdge edge = itrEdge.next();
2026 ReachSet prevResult = edge.getBetaNew();
2027 assert prevResult != null;
2029 ReachSet intersection =
2030 Canonical.intersection( edge.getBeta(),
2031 edgePrime.getBetaNew()
2034 if( Canonical.union( prevResult,
2036 ).size() > prevResult.size() ) {
2038 Canonical.union( prevResult,
2042 edgeWorkSet.add( edge );
2047 // commit beta' (beta<-betaNew)
2048 edgeItr = res.iterator();
2049 while( edgeItr.hasNext() ) {
2050 edgeItr.next().applyBetaNew();
2056 ////////////////////////////////////////////////////
2057 // high-level merge operations
2058 ////////////////////////////////////////////////////
2059 public void merge_sameMethodContext( ReachGraph rg ) {
2060 // when merging two graphs that abstract the heap
2061 // of the same method context, we just call the
2062 // basic merge operation
2066 public void merge_diffMethodContext( ReachGraph rg ) {
2067 // when merging graphs for abstract heaps in
2068 // different method contexts we should:
2069 // 1) age the allocation sites?
2073 ////////////////////////////////////////////////////
2074 // in merge() and equals() methods the suffix A
2075 // represents the passed in graph and the suffix
2076 // B refers to the graph in this object
2077 // Merging means to take the incoming graph A and
2078 // merge it into B, so after the operation graph B
2079 // is the final result.
2080 ////////////////////////////////////////////////////
2081 protected void merge( ReachGraph rg ) {
2088 mergeRefEdges ( rg );
2089 mergeAllocSites( rg );
2092 protected void mergeNodes( ReachGraph rg ) {
2094 // start with heap region nodes
2095 Set sA = rg.id2hrn.entrySet();
2096 Iterator iA = sA.iterator();
2097 while( iA.hasNext() ) {
2098 Map.Entry meA = (Map.Entry) iA.next();
2099 Integer idA = (Integer) meA.getKey();
2100 HeapRegionNode hrnA = (HeapRegionNode) meA.getValue();
2102 // if this graph doesn't have a node the
2103 // incoming graph has, allocate it
2104 if( !id2hrn.containsKey( idA ) ) {
2105 HeapRegionNode hrnB = hrnA.copy();
2106 id2hrn.put( idA, hrnB );
2109 // otherwise this is a node present in both graphs
2110 // so make the new reachability set a union of the
2111 // nodes' reachability sets
2112 HeapRegionNode hrnB = id2hrn.get( idA );
2113 hrnB.setAlpha( Canonical.union( hrnB.getAlpha(),
2118 // if hrnB is already dirty or hrnA is dirty,
2119 // the hrnB should end up dirty: TODO
2121 if( !hrnA.isClean() ) {
2122 hrnB.setIsClean( false );
2128 // now add any variable nodes that are in graph B but
2130 sA = rg.td2vn.entrySet();
2132 while( iA.hasNext() ) {
2133 Map.Entry meA = (Map.Entry) iA.next();
2134 TempDescriptor tdA = (TempDescriptor) meA.getKey();
2135 VariableNode lnA = (VariableNode) meA.getValue();
2137 // if the variable doesn't exist in B, allocate and add it
2138 VariableNode lnB = getVariableNodeFromTemp( tdA );
2142 protected void mergeRefEdges( ReachGraph rg ) {
2144 // between heap regions
2145 Set sA = rg.id2hrn.entrySet();
2146 Iterator iA = sA.iterator();
2147 while( iA.hasNext() ) {
2148 Map.Entry meA = (Map.Entry) iA.next();
2149 Integer idA = (Integer) meA.getKey();
2150 HeapRegionNode hrnA = (HeapRegionNode) meA.getValue();
2152 Iterator<RefEdge> heapRegionsItrA = hrnA.iteratorToReferencees();
2153 while( heapRegionsItrA.hasNext() ) {
2154 RefEdge edgeA = heapRegionsItrA.next();
2155 HeapRegionNode hrnChildA = edgeA.getDst();
2156 Integer idChildA = hrnChildA.getID();
2158 // at this point we know an edge in graph A exists
2159 // idA -> idChildA, does this exist in B?
2160 assert id2hrn.containsKey( idA );
2161 HeapRegionNode hrnB = id2hrn.get( idA );
2162 RefEdge edgeToMerge = null;
2164 Iterator<RefEdge> heapRegionsItrB = hrnB.iteratorToReferencees();
2165 while( heapRegionsItrB.hasNext() &&
2166 edgeToMerge == null ) {
2168 RefEdge edgeB = heapRegionsItrB.next();
2169 HeapRegionNode hrnChildB = edgeB.getDst();
2170 Integer idChildB = hrnChildB.getID();
2172 // don't use the RefEdge.equals() here because
2173 // we're talking about existence between graphs,
2174 // not intragraph equal
2175 if( idChildB.equals( idChildA ) &&
2176 edgeB.typeAndFieldEquals( edgeA ) ) {
2178 edgeToMerge = edgeB;
2182 // if the edge from A was not found in B,
2184 if( edgeToMerge == null ) {
2185 assert id2hrn.containsKey( idChildA );
2186 HeapRegionNode hrnChildB = id2hrn.get( idChildA );
2187 edgeToMerge = edgeA.copy();
2188 edgeToMerge.setSrc( hrnB );
2189 edgeToMerge.setDst( hrnChildB );
2190 addRefEdge( hrnB, hrnChildB, edgeToMerge );
2192 // otherwise, the edge already existed in both graphs
2193 // so merge their reachability sets
2195 // just replace this beta set with the union
2196 assert edgeToMerge != null;
2197 edgeToMerge.setBeta(
2198 Canonical.union( edgeToMerge.getBeta(),
2204 if( !edgeA.isClean() ) {
2205 edgeToMerge.setIsClean( false );
2212 // and then again from variable nodes
2213 sA = rg.td2vn.entrySet();
2215 while( iA.hasNext() ) {
2216 Map.Entry meA = (Map.Entry) iA.next();
2217 TempDescriptor tdA = (TempDescriptor) meA.getKey();
2218 VariableNode vnA = (VariableNode) meA.getValue();
2220 Iterator<RefEdge> heapRegionsItrA = vnA.iteratorToReferencees();
2221 while( heapRegionsItrA.hasNext() ) {
2222 RefEdge edgeA = heapRegionsItrA.next();
2223 HeapRegionNode hrnChildA = edgeA.getDst();
2224 Integer idChildA = hrnChildA.getID();
2226 // at this point we know an edge in graph A exists
2227 // tdA -> idChildA, does this exist in B?
2228 assert td2vn.containsKey( tdA );
2229 VariableNode vnB = td2vn.get( tdA );
2230 RefEdge edgeToMerge = null;
2232 Iterator<RefEdge> heapRegionsItrB = vnB.iteratorToReferencees();
2233 while( heapRegionsItrB.hasNext() &&
2234 edgeToMerge == null ) {
2236 RefEdge edgeB = heapRegionsItrB.next();
2237 HeapRegionNode hrnChildB = edgeB.getDst();
2238 Integer idChildB = hrnChildB.getID();
2240 // don't use the RefEdge.equals() here because
2241 // we're talking about existence between graphs
2242 if( idChildB.equals( idChildA ) &&
2243 edgeB.typeAndFieldEquals( edgeA ) ) {
2245 edgeToMerge = edgeB;
2249 // if the edge from A was not found in B,
2251 if( edgeToMerge == null ) {
2252 assert id2hrn.containsKey( idChildA );
2253 HeapRegionNode hrnChildB = id2hrn.get( idChildA );
2254 edgeToMerge = edgeA.copy();
2255 edgeToMerge.setSrc( vnB );
2256 edgeToMerge.setDst( hrnChildB );
2257 addRefEdge( vnB, hrnChildB, edgeToMerge );
2259 // otherwise, the edge already existed in both graphs
2260 // so merge their reachability sets
2262 // just replace this beta set with the union
2263 edgeToMerge.setBeta( Canonical.union( edgeToMerge.getBeta(),
2269 if( !edgeA.isClean() ) {
2270 edgeToMerge.setIsClean( false );
2278 protected void mergeAllocSites( ReachGraph rg ) {
2279 allocSites.addAll( rg.allocSites );
2283 // it is necessary in the equals() member functions
2284 // to "check both ways" when comparing the data
2285 // structures of two graphs. For instance, if all
2286 // edges between heap region nodes in graph A are
2287 // present and equal in graph B it is not sufficient
2288 // to say the graphs are equal. Consider that there
2289 // may be edges in graph B that are not in graph A.
2290 // the only way to know that all edges in both graphs
2291 // are equally present is to iterate over both data
2292 // structures and compare against the other graph.
2293 public boolean equals( ReachGraph rg ) {
2299 if( !areHeapRegionNodesEqual( rg ) ) {
2303 if( !areVariableNodesEqual( rg ) ) {
2307 if( !areRefEdgesEqual( rg ) ) {
2311 // if everything is equal up to this point,
2312 // assert that allocSites is also equal--
2313 // this data is redundant but kept for efficiency
2314 assert allocSites.equals( rg.allocSites );
2320 protected boolean areHeapRegionNodesEqual( ReachGraph rg ) {
2322 if( !areallHRNinAalsoinBandequal( this, rg ) ) {
2326 if( !areallHRNinAalsoinBandequal( rg, this ) ) {
2333 static protected boolean areallHRNinAalsoinBandequal( ReachGraph rgA,
2335 Set sA = rgA.id2hrn.entrySet();
2336 Iterator iA = sA.iterator();
2337 while( iA.hasNext() ) {
2338 Map.Entry meA = (Map.Entry) iA.next();
2339 Integer idA = (Integer) meA.getKey();
2340 HeapRegionNode hrnA = (HeapRegionNode) meA.getValue();
2342 if( !rgB.id2hrn.containsKey( idA ) ) {
2346 HeapRegionNode hrnB = rgB.id2hrn.get( idA );
2347 if( !hrnA.equalsIncludingAlphaAndPreds( hrnB ) ) {
2356 protected boolean areVariableNodesEqual( ReachGraph rg ) {
2358 if( !areallVNinAalsoinBandequal( this, rg ) ) {
2362 if( !areallVNinAalsoinBandequal( rg, this ) ) {
2369 static protected boolean areallVNinAalsoinBandequal( ReachGraph rgA,
2371 Set sA = rgA.td2vn.entrySet();
2372 Iterator iA = sA.iterator();
2373 while( iA.hasNext() ) {
2374 Map.Entry meA = (Map.Entry) iA.next();
2375 TempDescriptor tdA = (TempDescriptor) meA.getKey();
2377 if( !rgB.td2vn.containsKey( tdA ) ) {
2386 protected boolean areRefEdgesEqual( ReachGraph rg ) {
2387 if( !areallREinAandBequal( this, rg ) ) {
2394 static protected boolean areallREinAandBequal( ReachGraph rgA,
2397 // check all the heap region->heap region edges
2398 Set sA = rgA.id2hrn.entrySet();
2399 Iterator iA = sA.iterator();
2400 while( iA.hasNext() ) {
2401 Map.Entry meA = (Map.Entry) iA.next();
2402 Integer idA = (Integer) meA.getKey();
2403 HeapRegionNode hrnA = (HeapRegionNode) meA.getValue();
2405 // we should have already checked that the same
2406 // heap regions exist in both graphs
2407 assert rgB.id2hrn.containsKey( idA );
2409 if( !areallREfromAequaltoB( rgA, hrnA, rgB ) ) {
2413 // then check every edge in B for presence in A, starting
2414 // from the same parent HeapRegionNode
2415 HeapRegionNode hrnB = rgB.id2hrn.get( idA );
2417 if( !areallREfromAequaltoB( rgB, hrnB, rgA ) ) {
2422 // then check all the variable->heap region edges
2423 sA = rgA.td2vn.entrySet();
2425 while( iA.hasNext() ) {
2426 Map.Entry meA = (Map.Entry) iA.next();
2427 TempDescriptor tdA = (TempDescriptor) meA.getKey();
2428 VariableNode vnA = (VariableNode) meA.getValue();
2430 // we should have already checked that the same
2431 // label nodes exist in both graphs
2432 assert rgB.td2vn.containsKey( tdA );
2434 if( !areallREfromAequaltoB( rgA, vnA, rgB ) ) {
2438 // then check every edge in B for presence in A, starting
2439 // from the same parent VariableNode
2440 VariableNode vnB = rgB.td2vn.get( tdA );
2442 if( !areallREfromAequaltoB( rgB, vnB, rgA ) ) {
2451 static protected boolean areallREfromAequaltoB( ReachGraph rgA,
2455 Iterator<RefEdge> itrA = rnA.iteratorToReferencees();
2456 while( itrA.hasNext() ) {
2457 RefEdge edgeA = itrA.next();
2458 HeapRegionNode hrnChildA = edgeA.getDst();
2459 Integer idChildA = hrnChildA.getID();
2461 assert rgB.id2hrn.containsKey( idChildA );
2463 // at this point we know an edge in graph A exists
2464 // rnA -> idChildA, does this exact edge exist in B?
2465 boolean edgeFound = false;
2467 RefSrcNode rnB = null;
2468 if( rnA instanceof HeapRegionNode ) {
2469 HeapRegionNode hrnA = (HeapRegionNode) rnA;
2470 rnB = rgB.id2hrn.get( hrnA.getID() );
2472 VariableNode vnA = (VariableNode) rnA;
2473 rnB = rgB.td2vn.get( vnA.getTempDescriptor() );
2476 Iterator<RefEdge> itrB = rnB.iteratorToReferencees();
2477 while( itrB.hasNext() ) {
2478 RefEdge edgeB = itrB.next();
2479 HeapRegionNode hrnChildB = edgeB.getDst();
2480 Integer idChildB = hrnChildB.getID();
2482 if( idChildA.equals( idChildB ) &&
2483 edgeA.typeAndFieldEquals( edgeB ) ) {
2485 // there is an edge in the right place with the right field,
2486 // but do they have the same attributes?
2487 if( edgeA.getBeta().equals( edgeB.getBeta() ) &&
2488 edgeA.equalsPreds( edgeB )
2505 // this analysis no longer has the "match anything"
2506 // type which was represented by null
2507 protected TypeDescriptor mostSpecificType( TypeDescriptor td1,
2508 TypeDescriptor td2 ) {
2512 if( td1.isNull() ) {
2515 if( td2.isNull() ) {
2518 return typeUtil.mostSpecific( td1, td2 );
2521 protected TypeDescriptor mostSpecificType( TypeDescriptor td1,
2523 TypeDescriptor td3 ) {
2525 return mostSpecificType( td1,
2526 mostSpecificType( td2, td3 )
2530 protected TypeDescriptor mostSpecificType( TypeDescriptor td1,
2533 TypeDescriptor td4 ) {
2535 return mostSpecificType( mostSpecificType( td1, td2 ),
2536 mostSpecificType( td3, td4 )
2540 protected boolean isSuperiorType( TypeDescriptor possibleSuper,
2541 TypeDescriptor possibleChild ) {
2542 assert possibleSuper != null;
2543 assert possibleChild != null;
2545 if( possibleSuper.isNull() ||
2546 possibleChild.isNull() ) {
2550 return typeUtil.isSuperorType( possibleSuper, possibleChild );
2554 protected boolean hasMatchingField( HeapRegionNode src,
2557 TypeDescriptor tdSrc = src.getType();
2558 assert tdSrc != null;
2560 if( tdSrc.isArray() ) {
2561 TypeDescriptor td = edge.getType();
2564 TypeDescriptor tdSrcDeref = tdSrc.dereference();
2565 assert tdSrcDeref != null;
2567 if( !typeUtil.isSuperorType( tdSrcDeref, td ) ) {
2571 return edge.getField().equals( DisjointAnalysis.arrayElementFieldName );
2574 // if it's not a class, it doesn't have any fields to match
2575 if( !tdSrc.isClass() ) {
2579 ClassDescriptor cd = tdSrc.getClassDesc();
2580 while( cd != null ) {
2581 Iterator fieldItr = cd.getFields();
2583 while( fieldItr.hasNext() ) {
2584 FieldDescriptor fd = (FieldDescriptor) fieldItr.next();
2586 if( fd.getType().equals( edge.getType() ) &&
2587 fd.getSymbol().equals( edge.getField() ) ) {
2592 cd = cd.getSuperDesc();
2595 // otherwise it is a class with fields
2596 // but we didn't find a match
2600 protected boolean hasMatchingType( RefEdge edge,
2601 HeapRegionNode dst ) {
2603 // if the region has no type, matches everything
2604 TypeDescriptor tdDst = dst.getType();
2605 assert tdDst != null;
2607 // if the type is not a class or an array, don't
2608 // match because primitives are copied, no aliases
2609 ClassDescriptor cdDst = tdDst.getClassDesc();
2610 if( cdDst == null && !tdDst.isArray() ) {
2614 // if the edge type is null, it matches everything
2615 TypeDescriptor tdEdge = edge.getType();
2616 assert tdEdge != null;
2618 return typeUtil.isSuperorType( tdEdge, tdDst );
2623 public void writeGraph( String graphName,
2624 boolean writeLabels,
2625 boolean labelSelect,
2626 boolean pruneGarbage,
2627 boolean writeReferencers,
2628 boolean hideSubsetReachability,
2629 boolean hideEdgeTaints
2630 ) throws java.io.IOException {
2631 writeGraph( graphName,
2636 hideSubsetReachability,
2642 public void writeGraph( String graphName,
2643 boolean writeLabels,
2644 boolean labelSelect,
2645 boolean pruneGarbage,
2646 boolean writeReferencers,
2647 boolean hideSubsetReachability,
2648 boolean hideEdgeTaints,
2649 Set<HeapRegionNode> callerNodesCopiedToCallee,
2650 Set<RefEdge> callerEdgesCopiedToCallee
2651 ) throws java.io.IOException {
2653 // remove all non-word characters from the graph name so
2654 // the filename and identifier in dot don't cause errors
2655 graphName = graphName.replaceAll( "[\\W]", "" );
2658 new BufferedWriter( new FileWriter( graphName+".dot" ) );
2660 bw.write( "digraph "+graphName+" {\n" );
2663 // this is an optional step to form the callee-reachable
2664 // "cut-out" into a DOT cluster for visualization
2665 if( callerNodesCopiedToCallee != null ) {
2667 bw.write( " subgraph cluster0 {\n" );
2668 bw.write( " color=blue;\n" );
2670 Iterator i = id2hrn.entrySet().iterator();
2671 while( i.hasNext() ) {
2672 Map.Entry me = (Map.Entry) i.next();
2673 HeapRegionNode hrn = (HeapRegionNode) me.getValue();
2675 if( callerNodesCopiedToCallee.contains( hrn ) ) {
2676 bw.write( " "+hrn.toString()+
2677 hrn.toStringDOT( hideSubsetReachability )+
2687 Set<HeapRegionNode> visited = new HashSet<HeapRegionNode>();
2689 // then visit every heap region node
2690 Iterator i = id2hrn.entrySet().iterator();
2691 while( i.hasNext() ) {
2692 Map.Entry me = (Map.Entry) i.next();
2693 HeapRegionNode hrn = (HeapRegionNode) me.getValue();
2695 // only visit nodes worth writing out--for instance
2696 // not every node at an allocation is referenced
2697 // (think of it as garbage-collected), etc.
2698 if( !pruneGarbage ||
2699 (hrn.isFlagged() && hrn.getID() > 0) ||
2700 hrn.getDescription().startsWith( "param" ) ||
2701 hrn.isOutOfContext()
2704 if( !visited.contains( hrn ) ) {
2705 traverseHeapRegionNodes( hrn,
2710 hideSubsetReachability,
2712 callerNodesCopiedToCallee,
2713 callerEdgesCopiedToCallee );
2718 bw.write( " graphTitle[label=\""+graphName+"\",shape=box];\n" );
2721 // then visit every label node, useful for debugging
2723 i = td2vn.entrySet().iterator();
2724 while( i.hasNext() ) {
2725 Map.Entry me = (Map.Entry) i.next();
2726 VariableNode vn = (VariableNode) me.getValue();
2729 String labelStr = vn.getTempDescriptorString();
2730 if( labelStr.startsWith("___temp") ||
2731 labelStr.startsWith("___dst") ||
2732 labelStr.startsWith("___srctmp") ||
2733 labelStr.startsWith("___neverused")
2739 Iterator<RefEdge> heapRegionsItr = vn.iteratorToReferencees();
2740 while( heapRegionsItr.hasNext() ) {
2741 RefEdge edge = heapRegionsItr.next();
2742 HeapRegionNode hrn = edge.getDst();
2744 if( pruneGarbage && !visited.contains( hrn ) ) {
2745 traverseHeapRegionNodes( hrn,
2750 hideSubsetReachability,
2752 callerNodesCopiedToCallee,
2753 callerEdgesCopiedToCallee );
2756 bw.write( " "+vn.toString()+
2757 " -> "+hrn.toString()+
2758 edge.toStringDOT( hideSubsetReachability, "" )+
2768 protected void traverseHeapRegionNodes( HeapRegionNode hrn,
2771 Set<HeapRegionNode> visited,
2772 boolean writeReferencers,
2773 boolean hideSubsetReachability,
2774 boolean hideEdgeTaints,
2775 Set<HeapRegionNode> callerNodesCopiedToCallee,
2776 Set<RefEdge> callerEdgesCopiedToCallee
2777 ) throws java.io.IOException {
2779 if( visited.contains( hrn ) ) {
2784 // if we're drawing the callee-view subgraph, only
2785 // write out the node info if it hasn't already been
2787 if( callerNodesCopiedToCallee == null ||
2788 !callerNodesCopiedToCallee.contains( hrn )
2790 bw.write( " "+hrn.toString()+
2791 hrn.toStringDOT( hideSubsetReachability )+
2795 Iterator<RefEdge> childRegionsItr = hrn.iteratorToReferencees();
2796 while( childRegionsItr.hasNext() ) {
2797 RefEdge edge = childRegionsItr.next();
2798 HeapRegionNode hrnChild = edge.getDst();
2800 if( callerEdgesCopiedToCallee != null &&
2801 callerEdgesCopiedToCallee.contains( hrn )
2803 bw.write( " "+hrn.toString()+
2804 " -> "+hrnChild.toString()+
2805 edge.toStringDOT( hideSubsetReachability, ",color=blue" )+
2808 bw.write( " "+hrn.toString()+
2809 " -> "+hrnChild.toString()+
2810 edge.toStringDOT( hideSubsetReachability, "" )+
2814 traverseHeapRegionNodes( hrnChild,
2819 hideSubsetReachability,
2821 callerNodesCopiedToCallee,
2822 callerEdgesCopiedToCallee );