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 = false;
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 = Canonical.makePredsTrue(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 // this suite of methods can be used to assert a
67 // very important property of ReachGraph objects:
68 // some element, HeapRegionNode, RefEdge etc.
69 // should be referenced by at most ONE ReachGraph!!
70 // If a heap region or edge or variable should be
71 // in another graph, make a new object with
72 // equivalent properties for a new graph
73 public boolean belongsToThis( RefSrcNode rsn ) {
74 if( rsn instanceof VariableNode ) {
75 VariableNode vn = (VariableNode) rsn;
76 return this.td2vn.get( vn.getTempDescriptor() ) == vn;
78 HeapRegionNode hrn = (HeapRegionNode) rsn;
79 return this.id2hrn.get( hrn.getID() ) == hrn;
86 // the reason for this method is to have the option
87 // of creating new heap regions with specific IDs, or
88 // duplicating heap regions with specific IDs (especially
89 // in the merge() operation) or to create new heap
90 // regions with a new unique ID
91 protected HeapRegionNode
92 createNewHeapRegionNode( Integer id,
93 boolean isSingleObject,
96 boolean isOutOfContext,
105 boolean markForAnalysis = isFlagged;
107 TypeDescriptor typeToUse = null;
108 if( allocSite != null ) {
109 typeToUse = allocSite.getType();
110 allocSites.add( allocSite );
115 if( allocSite != null && allocSite.getDisjointAnalysisId() != null ) {
116 markForAnalysis = true;
120 id = DisjointAnalysis.generateUniqueHeapRegionNodeID();
123 if( inherent == null ) {
124 if( markForAnalysis ) {
126 Canonical.makePredsTrue(
129 ReachTuple.factory( id,
131 ReachTuple.ARITY_ONE,
132 false // out-of-context
138 inherent = rsetWithEmptyState;
142 if( alpha == null ) {
146 assert preds != null;
148 HeapRegionNode hrn = new HeapRegionNode( id,
159 id2hrn.put( id, hrn );
165 ////////////////////////////////////////////////
167 // Low-level referencee and referencer methods
169 // These methods provide the lowest level for
170 // creating references between reachability nodes
171 // and handling the details of maintaining both
172 // list of referencers and referencees.
174 ////////////////////////////////////////////////
175 protected void addRefEdge( RefSrcNode referencer,
176 HeapRegionNode referencee,
178 assert referencer != null;
179 assert referencee != null;
181 assert edge.getSrc() == referencer;
182 assert edge.getDst() == referencee;
183 assert belongsToThis( referencer );
184 assert belongsToThis( referencee );
186 // edges are getting added twice to graphs now, the
187 // kind that should have abstract facts merged--use
188 // this check to prevent that
189 assert referencer.getReferenceTo( referencee,
194 referencer.addReferencee( edge );
195 referencee.addReferencer( edge );
198 protected void removeRefEdge( RefEdge e ) {
199 removeRefEdge( e.getSrc(),
205 protected void removeRefEdge( RefSrcNode referencer,
206 HeapRegionNode referencee,
209 assert referencer != null;
210 assert referencee != null;
212 RefEdge edge = referencer.getReferenceTo( referencee,
216 assert edge == referencee.getReferenceFrom( referencer,
220 referencer.removeReferencee( edge );
221 referencee.removeReferencer( edge );
224 protected void clearRefEdgesFrom( RefSrcNode referencer,
227 boolean removeAll ) {
228 assert referencer != null;
230 // get a copy of the set to iterate over, otherwise
231 // we will be trying to take apart the set as we
232 // are iterating over it, which won't work
233 Iterator<RefEdge> i = referencer.iteratorToReferenceesClone();
234 while( i.hasNext() ) {
235 RefEdge edge = i.next();
238 (edge.typeEquals( type ) && edge.fieldEquals( field ))
241 HeapRegionNode referencee = edge.getDst();
243 removeRefEdge( referencer,
251 protected void clearRefEdgesTo( HeapRegionNode referencee,
254 boolean removeAll ) {
255 assert referencee != null;
257 // get a copy of the set to iterate over, otherwise
258 // we will be trying to take apart the set as we
259 // are iterating over it, which won't work
260 Iterator<RefEdge> i = referencee.iteratorToReferencersClone();
261 while( i.hasNext() ) {
262 RefEdge edge = i.next();
265 (edge.typeEquals( type ) && edge.fieldEquals( field ))
268 RefSrcNode referencer = edge.getSrc();
270 removeRefEdge( referencer,
278 protected void clearNonVarRefEdgesTo( HeapRegionNode referencee ) {
279 assert referencee != null;
281 // get a copy of the set to iterate over, otherwise
282 // we will be trying to take apart the set as we
283 // are iterating over it, which won't work
284 Iterator<RefEdge> i = referencee.iteratorToReferencersClone();
285 while( i.hasNext() ) {
286 RefEdge edge = i.next();
287 RefSrcNode referencer = edge.getSrc();
288 if( !(referencer instanceof VariableNode) ) {
289 removeRefEdge( referencer,
297 // this is a common operation in many transfer functions: we want
298 // to add an edge, but if there is already such an edge we should
299 // merge the properties of the existing and the new edges
300 protected void addEdgeOrMergeWithExisting( RefEdge edgeNew ) {
302 RefSrcNode src = edgeNew.getSrc();
303 assert belongsToThis( src );
305 HeapRegionNode dst = edgeNew.getDst();
306 assert belongsToThis( dst );
308 // look to see if an edge with same field exists
309 // and merge with it, otherwise just add the edge
310 RefEdge edgeExisting = src.getReferenceTo( dst,
315 if( edgeExisting != null ) {
316 edgeExisting.setBeta(
317 Canonical.unionORpreds( edgeExisting.getBeta(),
321 edgeExisting.setPreds(
322 Canonical.join( edgeExisting.getPreds(),
328 addRefEdge( src, dst, edgeNew );
334 ////////////////////////////////////////////////////
336 // Assignment Operation Methods
338 // These methods are high-level operations for
339 // modeling program assignment statements using
340 // the low-level reference create/remove methods
343 ////////////////////////////////////////////////////
345 public void assignTempXEqualToTempY( TempDescriptor x,
347 assignTempXEqualToCastedTempY( x, y, null );
350 public void assignTempXEqualToCastedTempY( TempDescriptor x,
352 TypeDescriptor tdCast ) {
354 VariableNode lnX = getVariableNodeFromTemp( x );
355 VariableNode lnY = getVariableNodeFromTemp( y );
357 clearRefEdgesFrom( lnX, null, null, true );
359 // note it is possible that the types of temps in the
360 // flat node to analyze will reveal that some typed
361 // edges in the reachability graph are impossible
362 Set<RefEdge> impossibleEdges = new HashSet<RefEdge>();
364 Iterator<RefEdge> itrYhrn = lnY.iteratorToReferencees();
365 while( itrYhrn.hasNext() ) {
366 RefEdge edgeY = itrYhrn.next();
367 HeapRegionNode referencee = edgeY.getDst();
368 RefEdge edgeNew = edgeY.copy();
370 if( !isSuperiorType( x.getType(), edgeY.getType() ) ) {
371 impossibleEdges.add( edgeY );
375 edgeNew.setSrc( lnX );
377 if( tdCast == null ) {
378 edgeNew.setType( mostSpecificType( y.getType(),
384 edgeNew.setType( mostSpecificType( y.getType(),
386 referencee.getType(),
392 edgeNew.setField( null );
394 addRefEdge( lnX, referencee, edgeNew );
397 Iterator<RefEdge> itrImp = impossibleEdges.iterator();
398 while( itrImp.hasNext() ) {
399 RefEdge edgeImp = itrImp.next();
400 removeRefEdge( edgeImp );
405 public void assignTempXEqualToTempYFieldF( TempDescriptor x,
407 FieldDescriptor f ) {
408 VariableNode lnX = getVariableNodeFromTemp( x );
409 VariableNode lnY = getVariableNodeFromTemp( y );
411 clearRefEdgesFrom( lnX, null, null, true );
413 // note it is possible that the types of temps in the
414 // flat node to analyze will reveal that some typed
415 // edges in the reachability graph are impossible
416 Set<RefEdge> impossibleEdges = new HashSet<RefEdge>();
418 Iterator<RefEdge> itrYhrn = lnY.iteratorToReferencees();
419 while( itrYhrn.hasNext() ) {
420 RefEdge edgeY = itrYhrn.next();
421 HeapRegionNode hrnY = edgeY.getDst();
422 ReachSet betaY = edgeY.getBeta();
424 Iterator<RefEdge> itrHrnFhrn = hrnY.iteratorToReferencees();
425 while( itrHrnFhrn.hasNext() ) {
426 RefEdge edgeHrn = itrHrnFhrn.next();
427 HeapRegionNode hrnHrn = edgeHrn.getDst();
428 ReachSet betaHrn = edgeHrn.getBeta();
430 // prune edges that are not a matching field
431 if( edgeHrn.getType() != null &&
432 !edgeHrn.getField().equals( f.getSymbol() )
437 // check for impossible edges
438 if( !isSuperiorType( x.getType(), edgeHrn.getType() ) ) {
439 impossibleEdges.add( edgeHrn );
443 TypeDescriptor tdNewEdge =
444 mostSpecificType( edgeHrn.getType(),
448 RefEdge edgeNew = new RefEdge( lnX,
452 Canonical.intersection( betaY, betaHrn ),
456 addEdgeOrMergeWithExisting( edgeNew );
460 Iterator<RefEdge> itrImp = impossibleEdges.iterator();
461 while( itrImp.hasNext() ) {
462 RefEdge edgeImp = itrImp.next();
463 removeRefEdge( edgeImp );
466 // anytime you might remove edges between heap regions
467 // you must global sweep to clean up broken reachability
468 if( !impossibleEdges.isEmpty() ) {
469 if( !DISABLE_GLOBAL_SWEEP ) {
476 public void assignTempXFieldFEqualToTempY( TempDescriptor x,
480 VariableNode lnX = getVariableNodeFromTemp( x );
481 VariableNode lnY = getVariableNodeFromTemp( y );
483 HashSet<HeapRegionNode> nodesWithNewAlpha = new HashSet<HeapRegionNode>();
484 HashSet<RefEdge> edgesWithNewBeta = new HashSet<RefEdge>();
486 // note it is possible that the types of temps in the
487 // flat node to analyze will reveal that some typed
488 // edges in the reachability graph are impossible
489 Set<RefEdge> impossibleEdges = new HashSet<RefEdge>();
491 // first look for possible strong updates and remove those edges
492 boolean strongUpdate = false;
494 Iterator<RefEdge> itrXhrn = lnX.iteratorToReferencees();
495 while( itrXhrn.hasNext() ) {
496 RefEdge edgeX = itrXhrn.next();
497 HeapRegionNode hrnX = edgeX.getDst();
499 // we can do a strong update here if one of two cases holds
501 f != DisjointAnalysis.getArrayField( f.getType() ) &&
502 ( (hrnX.getNumReferencers() == 1) || // case 1
503 (hrnX.isSingleObject() && lnX.getNumReferencees() == 1) // case 2
506 if( !DISABLE_STRONG_UPDATES ) {
508 clearRefEdgesFrom( hrnX, f.getType(), f.getSymbol(), false );
513 // then do all token propagation
514 itrXhrn = lnX.iteratorToReferencees();
515 while( itrXhrn.hasNext() ) {
516 RefEdge edgeX = itrXhrn.next();
517 HeapRegionNode hrnX = edgeX.getDst();
518 ReachSet betaX = edgeX.getBeta();
519 ReachSet R = Canonical.intersection( hrnX.getAlpha(),
523 Iterator<RefEdge> itrYhrn = lnY.iteratorToReferencees();
524 while( itrYhrn.hasNext() ) {
525 RefEdge edgeY = itrYhrn.next();
526 HeapRegionNode hrnY = edgeY.getDst();
527 ReachSet O = edgeY.getBeta();
529 // check for impossible edges
530 if( !isSuperiorType( f.getType(), edgeY.getType() ) ) {
531 impossibleEdges.add( edgeY );
535 // propagate tokens over nodes starting from hrnSrc, and it will
536 // take care of propagating back up edges from any touched nodes
537 ChangeSet Cy = Canonical.unionUpArityToChangeSet( O, R );
538 propagateTokensOverNodes( hrnY, Cy, nodesWithNewAlpha, edgesWithNewBeta );
540 // then propagate back just up the edges from hrn
541 ChangeSet Cx = Canonical.unionUpArityToChangeSet( R, O );
542 HashSet<RefEdge> todoEdges = new HashSet<RefEdge>();
544 Hashtable<RefEdge, ChangeSet> edgePlannedChanges =
545 new Hashtable<RefEdge, ChangeSet>();
547 Iterator<RefEdge> referItr = hrnX.iteratorToReferencers();
548 while( referItr.hasNext() ) {
549 RefEdge edgeUpstream = referItr.next();
550 todoEdges.add( edgeUpstream );
551 edgePlannedChanges.put( edgeUpstream, Cx );
554 propagateTokensOverEdges( todoEdges,
561 // apply the updates to reachability
562 Iterator<HeapRegionNode> nodeItr = nodesWithNewAlpha.iterator();
563 while( nodeItr.hasNext() ) {
564 nodeItr.next().applyAlphaNew();
567 Iterator<RefEdge> edgeItr = edgesWithNewBeta.iterator();
568 while( edgeItr.hasNext() ) {
569 edgeItr.next().applyBetaNew();
573 // then go back through and add the new edges
574 itrXhrn = lnX.iteratorToReferencees();
575 while( itrXhrn.hasNext() ) {
576 RefEdge edgeX = itrXhrn.next();
577 HeapRegionNode hrnX = edgeX.getDst();
579 Iterator<RefEdge> itrYhrn = lnY.iteratorToReferencees();
580 while( itrYhrn.hasNext() ) {
581 RefEdge edgeY = itrYhrn.next();
582 HeapRegionNode hrnY = edgeY.getDst();
584 // skip impossible edges here, we already marked them
585 // when computing reachability propagations above
586 if( !isSuperiorType( f.getType(), edgeY.getType() ) ) {
590 // prepare the new reference edge hrnX.f -> hrnY
591 TypeDescriptor tdNewEdge =
592 mostSpecificType( y.getType(),
602 Canonical.makePredsTrue(
603 Canonical.pruneBy( edgeY.getBeta(),
610 addEdgeOrMergeWithExisting( edgeNew );
614 Iterator<RefEdge> itrImp = impossibleEdges.iterator();
615 while( itrImp.hasNext() ) {
616 RefEdge edgeImp = itrImp.next();
617 removeRefEdge( edgeImp );
620 // if there was a strong update, make sure to improve
621 // reachability with a global sweep
622 if( strongUpdate || !impossibleEdges.isEmpty() ) {
623 if( !DISABLE_GLOBAL_SWEEP ) {
630 public void assignReturnEqualToTemp( TempDescriptor x ) {
632 VariableNode lnR = getVariableNodeFromTemp( tdReturn );
633 VariableNode lnX = getVariableNodeFromTemp( x );
635 clearRefEdgesFrom( lnR, null, null, true );
637 Iterator<RefEdge> itrXhrn = lnX.iteratorToReferencees();
638 while( itrXhrn.hasNext() ) {
639 RefEdge edgeX = itrXhrn.next();
640 HeapRegionNode referencee = edgeX.getDst();
641 RefEdge edgeNew = edgeX.copy();
642 edgeNew.setSrc( lnR );
644 addRefEdge( lnR, referencee, edgeNew );
649 public void assignTempEqualToNewAlloc( TempDescriptor x,
656 // after the age operation the newest (or zero-ith oldest)
657 // node associated with the allocation site should have
658 // no references to it as if it were a newly allocated
660 Integer idNewest = as.getIthOldest( 0 );
661 HeapRegionNode hrnNewest = id2hrn.get( idNewest );
662 assert hrnNewest != null;
664 VariableNode lnX = getVariableNodeFromTemp( x );
665 clearRefEdgesFrom( lnX, null, null, true );
667 // make a new reference to allocated node
668 TypeDescriptor type = as.getType();
671 new RefEdge( lnX, // source
675 hrnNewest.getAlpha(), // beta
676 predsTrue // predicates
679 addRefEdge( lnX, hrnNewest, edgeNew );
683 // use the allocation site (unique to entire analysis) to
684 // locate the heap region nodes in this reachability graph
685 // that should be aged. The process models the allocation
686 // of new objects and collects all the oldest allocations
687 // in a summary node to allow for a finite analysis
689 // There is an additional property of this method. After
690 // running it on a particular reachability graph (many graphs
691 // may have heap regions related to the same allocation site)
692 // the heap region node objects in this reachability graph will be
693 // allocated. Therefore, after aging a graph for an allocation
694 // site, attempts to retrieve the heap region nodes using the
695 // integer id's contained in the allocation site should always
696 // return non-null heap regions.
697 public void age( AllocSite as ) {
699 // keep track of allocation sites that are represented
700 // in this graph for efficiency with other operations
701 allocSites.add( as );
703 // if there is a k-th oldest node, it merges into
705 Integer idK = as.getOldest();
706 if( id2hrn.containsKey( idK ) ) {
707 HeapRegionNode hrnK = id2hrn.get( idK );
709 // retrieve the summary node, or make it
711 HeapRegionNode hrnSummary = getSummaryNode( as, false );
713 mergeIntoSummary( hrnK, hrnSummary );
716 // move down the line of heap region nodes
717 // clobbering the ith and transferring all references
718 // to and from i-1 to node i.
719 for( int i = allocationDepth - 1; i > 0; --i ) {
721 // only do the transfer if the i-1 node exists
722 Integer idImin1th = as.getIthOldest( i - 1 );
723 if( id2hrn.containsKey( idImin1th ) ) {
724 HeapRegionNode hrnImin1 = id2hrn.get( idImin1th );
725 if( hrnImin1.isWiped() ) {
726 // there is no info on this node, just skip
730 // either retrieve or make target of transfer
731 HeapRegionNode hrnI = getIthNode( as, i, false );
733 transferOnto( hrnImin1, hrnI );
738 // as stated above, the newest node should have had its
739 // references moved over to the second oldest, so we wipe newest
740 // in preparation for being the new object to assign something to
741 HeapRegionNode hrn0 = getIthNode( as, 0, false );
742 wipeOut( hrn0, true );
744 // now tokens in reachability sets need to "age" also
745 Iterator itrAllVariableNodes = td2vn.entrySet().iterator();
746 while( itrAllVariableNodes.hasNext() ) {
747 Map.Entry me = (Map.Entry) itrAllVariableNodes.next();
748 VariableNode ln = (VariableNode) me.getValue();
750 Iterator<RefEdge> itrEdges = ln.iteratorToReferencees();
751 while( itrEdges.hasNext() ) {
752 ageTuplesFrom( as, itrEdges.next() );
756 Iterator itrAllHRNodes = id2hrn.entrySet().iterator();
757 while( itrAllHRNodes.hasNext() ) {
758 Map.Entry me = (Map.Entry) itrAllHRNodes.next();
759 HeapRegionNode hrnToAge = (HeapRegionNode) me.getValue();
761 ageTuplesFrom( as, hrnToAge );
763 Iterator<RefEdge> itrEdges = hrnToAge.iteratorToReferencees();
764 while( itrEdges.hasNext() ) {
765 ageTuplesFrom( as, itrEdges.next() );
770 // after tokens have been aged, reset newest node's reachability
771 // and a brand new node has a "true" predicate
772 hrn0.setAlpha( hrn0.getInherent() );
773 hrn0.setPreds( predsTrue );
777 // either retrieve or create the needed heap region node
778 protected HeapRegionNode getSummaryNode( AllocSite as,
783 idSummary = as.getSummaryShadow();
785 idSummary = as.getSummary();
788 HeapRegionNode hrnSummary = id2hrn.get( idSummary );
790 if( hrnSummary == null ) {
792 boolean hasFlags = false;
793 if( as.getType().isClass() ) {
794 hasFlags = as.getType().getClassDesc().hasFlags();
798 hasFlags = as.getFlag();
801 String strDesc = as.toStringForDOT()+"\\nsummary";
804 createNewHeapRegionNode( idSummary, // id or null to generate a new one
805 false, // single object?
807 hasFlags, // flagged?
808 false, // out-of-context?
809 as.getType(), // type
810 as, // allocation site
811 null, // inherent reach
812 null, // current reach
813 predsEmpty, // predicates
814 strDesc // description
821 // either retrieve or create the needed heap region node
822 protected HeapRegionNode getIthNode( AllocSite as,
828 idIth = as.getIthOldestShadow( i );
830 idIth = as.getIthOldest( i );
833 HeapRegionNode hrnIth = id2hrn.get( idIth );
835 if( hrnIth == null ) {
837 boolean hasFlags = false;
838 if( as.getType().isClass() ) {
839 hasFlags = as.getType().getClassDesc().hasFlags();
843 hasFlags = as.getFlag();
846 String strDesc = as.toStringForDOT()+"\\n"+i+" oldest";
848 hrnIth = createNewHeapRegionNode( idIth, // id or null to generate a new one
849 true, // single object?
851 hasFlags, // flagged?
852 false, // out-of-context?
853 as.getType(), // type
854 as, // allocation site
855 null, // inherent reach
856 null, // current reach
857 predsEmpty, // predicates
858 strDesc // description
866 protected void mergeIntoSummary( HeapRegionNode hrn,
867 HeapRegionNode hrnSummary ) {
868 assert hrnSummary.isNewSummary();
870 // assert that these nodes belong to THIS graph
871 assert belongsToThis( hrn );
872 assert belongsToThis( hrnSummary );
874 assert hrn != hrnSummary;
876 // transfer references _from_ hrn over to hrnSummary
877 Iterator<RefEdge> itrReferencee = hrn.iteratorToReferencees();
878 while( itrReferencee.hasNext() ) {
879 RefEdge edge = itrReferencee.next();
880 RefEdge edgeMerged = edge.copy();
881 edgeMerged.setSrc( hrnSummary );
883 HeapRegionNode hrnReferencee = edge.getDst();
884 RefEdge edgeSummary =
885 hrnSummary.getReferenceTo( hrnReferencee,
890 if( edgeSummary == null ) {
891 // the merge is trivial, nothing to be done
892 addRefEdge( hrnSummary, hrnReferencee, edgeMerged );
895 // otherwise an edge from the referencer to hrnSummary exists already
896 // and the edge referencer->hrn should be merged with it
898 Canonical.unionORpreds( edgeMerged.getBeta(),
899 edgeSummary.getBeta()
902 edgeSummary.setPreds(
903 Canonical.join( edgeMerged.getPreds(),
904 edgeSummary.getPreds()
910 // next transfer references _to_ hrn over to hrnSummary
911 Iterator<RefEdge> itrReferencer = hrn.iteratorToReferencers();
912 while( itrReferencer.hasNext() ) {
913 RefEdge edge = itrReferencer.next();
914 RefEdge edgeMerged = edge.copy();
915 edgeMerged.setDst( hrnSummary );
917 RefSrcNode onReferencer = edge.getSrc();
918 RefEdge edgeSummary =
919 onReferencer.getReferenceTo( hrnSummary,
924 if( edgeSummary == null ) {
925 // the merge is trivial, nothing to be done
926 addRefEdge( onReferencer, hrnSummary, edgeMerged );
929 // otherwise an edge from the referencer to alpha_S exists already
930 // and the edge referencer->alpha_K should be merged with it
932 Canonical.unionORpreds( edgeMerged.getBeta(),
933 edgeSummary.getBeta()
936 edgeSummary.setPreds(
937 Canonical.join( edgeMerged.getPreds(),
938 edgeSummary.getPreds()
944 // then merge hrn reachability into hrnSummary
946 Canonical.unionORpreds( hrnSummary.getAlpha(),
952 Canonical.join( hrnSummary.getPreds(),
957 // and afterward, this node is gone
958 wipeOut( hrn, true );
962 protected void transferOnto( HeapRegionNode hrnA,
963 HeapRegionNode hrnB ) {
965 assert belongsToThis( hrnA );
966 assert belongsToThis( hrnB );
969 // clear references in and out of node b?
970 assert hrnB.isWiped();
972 // copy each: (edge in and out of A) to B
973 Iterator<RefEdge> itrReferencee = hrnA.iteratorToReferencees();
974 while( itrReferencee.hasNext() ) {
975 RefEdge edge = itrReferencee.next();
976 HeapRegionNode hrnReferencee = edge.getDst();
977 RefEdge edgeNew = edge.copy();
978 edgeNew.setSrc( hrnB );
979 edgeNew.setDst( hrnReferencee );
981 addRefEdge( hrnB, hrnReferencee, edgeNew );
984 Iterator<RefEdge> itrReferencer = hrnA.iteratorToReferencers();
985 while( itrReferencer.hasNext() ) {
986 RefEdge edge = itrReferencer.next();
987 RefSrcNode rsnReferencer = edge.getSrc();
988 RefEdge edgeNew = edge.copy();
989 edgeNew.setSrc( rsnReferencer );
990 edgeNew.setDst( hrnB );
992 addRefEdge( rsnReferencer, hrnB, edgeNew );
995 // replace hrnB reachability and preds with hrnA's
996 hrnB.setAlpha( hrnA.getAlpha() );
997 hrnB.setPreds( hrnA.getPreds() );
999 // after transfer, wipe out source
1000 wipeOut( hrnA, true );
1004 // the purpose of this method is to conceptually "wipe out"
1005 // a heap region from the graph--purposefully not called REMOVE
1006 // because the node is still hanging around in the graph, just
1007 // not mechanically connected or have any reach or predicate
1008 // information on it anymore--lots of ops can use this
1009 protected void wipeOut( HeapRegionNode hrn,
1010 boolean wipeVariableReferences ) {
1012 assert belongsToThis( hrn );
1014 clearRefEdgesFrom( hrn, null, null, true );
1016 if( wipeVariableReferences ) {
1017 clearRefEdgesTo( hrn, null, null, true );
1019 clearNonVarRefEdgesTo( hrn );
1022 hrn.setAlpha( rsetEmpty );
1023 hrn.setPreds( predsEmpty );
1027 protected void ageTuplesFrom( AllocSite as, RefEdge edge ) {
1029 Canonical.ageTuplesFrom( edge.getBeta(),
1035 protected void ageTuplesFrom( AllocSite as, HeapRegionNode hrn ) {
1037 Canonical.ageTuplesFrom( hrn.getAlpha(),
1045 protected void propagateTokensOverNodes( HeapRegionNode nPrime,
1047 HashSet<HeapRegionNode> nodesWithNewAlpha,
1048 HashSet<RefEdge> edgesWithNewBeta ) {
1050 HashSet<HeapRegionNode> todoNodes
1051 = new HashSet<HeapRegionNode>();
1052 todoNodes.add( nPrime );
1054 HashSet<RefEdge> todoEdges
1055 = new HashSet<RefEdge>();
1057 Hashtable<HeapRegionNode, ChangeSet> nodePlannedChanges
1058 = new Hashtable<HeapRegionNode, ChangeSet>();
1059 nodePlannedChanges.put( nPrime, c0 );
1061 Hashtable<RefEdge, ChangeSet> edgePlannedChanges
1062 = new Hashtable<RefEdge, ChangeSet>();
1064 // first propagate change sets everywhere they can go
1065 while( !todoNodes.isEmpty() ) {
1066 HeapRegionNode n = todoNodes.iterator().next();
1067 ChangeSet C = nodePlannedChanges.get( n );
1069 Iterator<RefEdge> referItr = n.iteratorToReferencers();
1070 while( referItr.hasNext() ) {
1071 RefEdge edge = referItr.next();
1072 todoEdges.add( edge );
1074 if( !edgePlannedChanges.containsKey( edge ) ) {
1075 edgePlannedChanges.put( edge,
1080 edgePlannedChanges.put( edge,
1081 Canonical.union( edgePlannedChanges.get( edge ),
1087 Iterator<RefEdge> refeeItr = n.iteratorToReferencees();
1088 while( refeeItr.hasNext() ) {
1089 RefEdge edgeF = refeeItr.next();
1090 HeapRegionNode m = edgeF.getDst();
1092 ChangeSet changesToPass = ChangeSet.factory();
1094 Iterator<ChangeTuple> itrCprime = C.iterator();
1095 while( itrCprime.hasNext() ) {
1096 ChangeTuple c = itrCprime.next();
1097 if( edgeF.getBeta().containsIgnorePreds( c.getStateToMatch() )
1100 changesToPass = Canonical.add( changesToPass, c );
1104 if( !changesToPass.isEmpty() ) {
1105 if( !nodePlannedChanges.containsKey( m ) ) {
1106 nodePlannedChanges.put( m, ChangeSet.factory() );
1109 ChangeSet currentChanges = nodePlannedChanges.get( m );
1111 if( !changesToPass.isSubset( currentChanges ) ) {
1113 nodePlannedChanges.put( m,
1114 Canonical.union( currentChanges,
1123 todoNodes.remove( n );
1126 // then apply all of the changes for each node at once
1127 Iterator itrMap = nodePlannedChanges.entrySet().iterator();
1128 while( itrMap.hasNext() ) {
1129 Map.Entry me = (Map.Entry) itrMap.next();
1130 HeapRegionNode n = (HeapRegionNode) me.getKey();
1131 ChangeSet C = (ChangeSet) me.getValue();
1133 // this propagation step is with respect to one change,
1134 // so we capture the full change from the old alpha:
1135 ReachSet localDelta = Canonical.applyChangeSet( n.getAlpha(),
1139 // but this propagation may be only one of many concurrent
1140 // possible changes, so keep a running union with the node's
1141 // partially updated new alpha set
1142 n.setAlphaNew( Canonical.unionORpreds( n.getAlphaNew(),
1147 nodesWithNewAlpha.add( n );
1150 propagateTokensOverEdges( todoEdges,
1157 protected void propagateTokensOverEdges( HashSet <RefEdge> todoEdges,
1158 Hashtable<RefEdge, ChangeSet> edgePlannedChanges,
1159 HashSet <RefEdge> edgesWithNewBeta ) {
1161 // first propagate all change tuples everywhere they can go
1162 while( !todoEdges.isEmpty() ) {
1163 RefEdge edgeE = todoEdges.iterator().next();
1164 todoEdges.remove( edgeE );
1166 if( !edgePlannedChanges.containsKey( edgeE ) ) {
1167 edgePlannedChanges.put( edgeE,
1172 ChangeSet C = edgePlannedChanges.get( edgeE );
1174 ChangeSet changesToPass = ChangeSet.factory();
1176 Iterator<ChangeTuple> itrC = C.iterator();
1177 while( itrC.hasNext() ) {
1178 ChangeTuple c = itrC.next();
1179 if( edgeE.getBeta().containsIgnorePreds( c.getStateToMatch() )
1182 changesToPass = Canonical.add( changesToPass, c );
1186 RefSrcNode rsn = edgeE.getSrc();
1188 if( !changesToPass.isEmpty() && rsn instanceof HeapRegionNode ) {
1189 HeapRegionNode n = (HeapRegionNode) rsn;
1191 Iterator<RefEdge> referItr = n.iteratorToReferencers();
1192 while( referItr.hasNext() ) {
1193 RefEdge edgeF = referItr.next();
1195 if( !edgePlannedChanges.containsKey( edgeF ) ) {
1196 edgePlannedChanges.put( edgeF,
1201 ChangeSet currentChanges = edgePlannedChanges.get( edgeF );
1203 if( !changesToPass.isSubset( currentChanges ) ) {
1204 todoEdges.add( edgeF );
1205 edgePlannedChanges.put( edgeF,
1206 Canonical.union( currentChanges,
1215 // then apply all of the changes for each edge at once
1216 Iterator itrMap = edgePlannedChanges.entrySet().iterator();
1217 while( itrMap.hasNext() ) {
1218 Map.Entry me = (Map.Entry) itrMap.next();
1219 RefEdge e = (RefEdge) me.getKey();
1220 ChangeSet C = (ChangeSet) me.getValue();
1222 // this propagation step is with respect to one change,
1223 // so we capture the full change from the old beta:
1224 ReachSet localDelta =
1225 Canonical.applyChangeSet( e.getBeta(),
1230 // but this propagation may be only one of many concurrent
1231 // possible changes, so keep a running union with the edge's
1232 // partially updated new beta set
1233 e.setBetaNew( Canonical.unionORpreds( e.getBetaNew(),
1238 edgesWithNewBeta.add( e );
1243 // used in makeCalleeView below to decide if there is
1244 // already an appropriate out-of-context edge in a callee
1245 // view graph for merging, or null if a new one will be added
1247 getOutOfContextReferenceTo( HeapRegionNode hrn,
1248 TypeDescriptor srcType,
1249 TypeDescriptor refType,
1251 assert belongsToThis( hrn );
1253 HeapRegionNode hrnInContext = id2hrn.get( hrn.getID() );
1254 if( hrnInContext == null ) {
1258 Iterator<RefEdge> refItr = hrnInContext.iteratorToReferencers();
1259 while( refItr.hasNext() ) {
1260 RefEdge re = refItr.next();
1262 assert belongsToThis( re.getSrc() );
1263 assert belongsToThis( re.getDst() );
1265 if( !(re.getSrc() instanceof HeapRegionNode) ) {
1269 HeapRegionNode hrnSrc = (HeapRegionNode) re.getSrc();
1270 if( !hrnSrc.isOutOfContext() ) {
1274 if( srcType == null ) {
1275 if( hrnSrc.getType() != null ) {
1279 if( !srcType.equals( hrnSrc.getType() ) ) {
1284 if( !re.typeEquals( refType ) ) {
1288 if( !re.fieldEquals( refField ) ) {
1292 // tada! We found it!
1299 // used below to convert a ReachSet to its callee-context
1300 // equivalent with respect to allocation sites in this graph
1301 protected ReachSet toCalleeContext( ReachSet rs,
1303 Set<HrnIdOoc> oocHrnIdOoc2callee
1305 ReachSet out = ReachSet.factory();
1307 Iterator<ReachState> itr = rs.iterator();
1308 while( itr.hasNext() ) {
1309 ReachState stateCaller = itr.next();
1311 ReachState stateCallee = stateCaller;
1313 Iterator<AllocSite> asItr = allocSites.iterator();
1314 while( asItr.hasNext() ) {
1315 AllocSite as = asItr.next();
1317 ReachState stateNew = ReachState.factory();
1318 Iterator<ReachTuple> rtItr = stateCallee.iterator();
1319 while( rtItr.hasNext() ) {
1320 ReachTuple rt = rtItr.next();
1322 // only translate this tuple if it is
1323 // in the out-callee-context bag
1324 HrnIdOoc hio = new HrnIdOoc( rt.getHrnID(),
1327 if( !oocHrnIdOoc2callee.contains( hio ) ) {
1328 stateNew = Canonical.add( stateNew, rt );
1332 int age = as.getAgeCategory( rt.getHrnID() );
1334 // this is the current mapping, where 0, 1, 2S were allocated
1335 // in the current context, 0?, 1? and 2S? were allocated in a
1336 // previous context, and we're translating to a future context
1348 if( age == AllocSite.AGE_notInThisSite ) {
1349 // things not from the site just go back in
1350 stateNew = Canonical.add( stateNew, rt );
1352 } else if( age == AllocSite.AGE_summary ||
1355 // the in-context summary and all existing out-of-context
1357 stateNew = Canonical.add( stateNew,
1358 ReachTuple.factory( as.getSummary(),
1361 true // out-of-context
1365 // otherwise everything else just goes to an out-of-context
1366 // version, everything else the same
1367 Integer I = as.getAge( rt.getHrnID() );
1370 assert !rt.isMultiObject();
1372 stateNew = Canonical.add( stateNew,
1373 ReachTuple.factory( rt.getHrnID(),
1376 true // out-of-context
1382 stateCallee = stateNew;
1385 // attach the passed in preds
1386 stateCallee = Canonical.attach( stateCallee,
1389 out = Canonical.add( out,
1394 assert out.isCanonical();
1398 // used below to convert a ReachSet to its caller-context
1399 // equivalent with respect to allocation sites in this graph
1401 toCallerContext( ReachSet rs,
1402 Hashtable<ReachState, ExistPredSet> calleeStatesSatisfied
1404 ReachSet out = ReachSet.factory();
1406 Iterator<ReachState> itr = rs.iterator();
1407 while( itr.hasNext() ) {
1408 ReachState stateCallee = itr.next();
1410 if( calleeStatesSatisfied.containsKey( stateCallee ) ) {
1412 // starting from one callee state...
1413 ReachSet rsCaller = ReachSet.factory( stateCallee );
1415 // possibly branch it into many states, which any
1416 // allocation site might do, so lots of derived states
1417 Iterator<AllocSite> asItr = allocSites.iterator();
1418 while( asItr.hasNext() ) {
1419 AllocSite as = asItr.next();
1420 rsCaller = Canonical.toCallerContext( rsCaller, as );
1423 // then before adding each derived, now caller-context
1424 // states to the output, attach the appropriate pred
1425 // based on the source callee state
1426 Iterator<ReachState> stateItr = rsCaller.iterator();
1427 while( stateItr.hasNext() ) {
1428 ReachState stateCaller = stateItr.next();
1429 stateCaller = Canonical.attach( stateCaller,
1430 calleeStatesSatisfied.get( stateCallee )
1432 out = Canonical.add( out,
1439 assert out.isCanonical();
1443 // used below to convert a ReachSet to an equivalent
1444 // version with shadow IDs merged into unshadowed IDs
1445 protected ReachSet unshadow( ReachSet rs ) {
1447 Iterator<AllocSite> asItr = allocSites.iterator();
1448 while( asItr.hasNext() ) {
1449 AllocSite as = asItr.next();
1450 out = Canonical.unshadow( out, as );
1452 assert out.isCanonical();
1457 // use this method to make a new reach graph that is
1458 // what heap the FlatMethod callee from the FlatCall
1459 // would start with reaching from its arguments in
1462 makeCalleeView( FlatCall fc,
1463 FlatMethod fmCallee,
1464 Set<Integer> callerNodeIDsCopiedToCallee,
1465 boolean writeDebugDOTs
1469 // first traverse this context to find nodes and edges
1470 // that will be callee-reachable
1471 Set<HeapRegionNode> reachableCallerNodes =
1472 new HashSet<HeapRegionNode>();
1474 // caller edges between callee-reachable nodes
1475 Set<RefEdge> reachableCallerEdges =
1476 new HashSet<RefEdge>();
1478 // caller edges from arg vars, and the matching param index
1479 // because these become a special edge in callee
1480 Hashtable<RefEdge, Integer> reachableCallerArgEdges2paramIndex =
1481 new Hashtable<RefEdge, Integer>();
1483 // caller edges from local vars or callee-unreachable nodes
1484 // (out-of-context sources) to callee-reachable nodes
1485 Set<RefEdge> oocCallerEdges =
1486 new HashSet<RefEdge>();
1489 for( int i = 0; i < fmCallee.numParameters(); ++i ) {
1491 TempDescriptor tdArg = fc.getArgMatchingParamIndex( fmCallee, i );
1492 VariableNode vnArgCaller = this.getVariableNodeFromTemp( tdArg );
1494 Set<RefSrcNode> toVisitInCaller = new HashSet<RefSrcNode>();
1495 Set<RefSrcNode> visitedInCaller = new HashSet<RefSrcNode>();
1497 toVisitInCaller.add( vnArgCaller );
1499 while( !toVisitInCaller.isEmpty() ) {
1500 RefSrcNode rsnCaller = toVisitInCaller.iterator().next();
1501 toVisitInCaller.remove( rsnCaller );
1502 visitedInCaller.add( rsnCaller );
1504 Iterator<RefEdge> itrRefEdges = rsnCaller.iteratorToReferencees();
1505 while( itrRefEdges.hasNext() ) {
1506 RefEdge reCaller = itrRefEdges.next();
1507 HeapRegionNode hrnCaller = reCaller.getDst();
1509 callerNodeIDsCopiedToCallee.add( hrnCaller.getID() );
1510 reachableCallerNodes.add( hrnCaller );
1512 if( reCaller.getSrc() instanceof HeapRegionNode ) {
1513 reachableCallerEdges.add( reCaller );
1515 if( rsnCaller.equals( vnArgCaller ) ) {
1516 reachableCallerArgEdges2paramIndex.put( reCaller, i );
1518 oocCallerEdges.add( reCaller );
1522 if( !visitedInCaller.contains( hrnCaller ) ) {
1523 toVisitInCaller.add( hrnCaller );
1526 } // end edge iteration
1527 } // end visiting heap nodes in caller
1528 } // end iterating over parameters as starting points
1531 // now collect out-of-callee-context IDs and
1532 // map them to whether the ID is out of the caller
1534 Set<HrnIdOoc> oocHrnIdOoc2callee = new HashSet<HrnIdOoc>();
1536 Iterator<Integer> itrInContext =
1537 callerNodeIDsCopiedToCallee.iterator();
1538 while( itrInContext.hasNext() ) {
1539 Integer hrnID = itrInContext.next();
1540 HeapRegionNode hrnCallerAndInContext = id2hrn.get( hrnID );
1542 Iterator<RefEdge> itrMightCross =
1543 hrnCallerAndInContext.iteratorToReferencers();
1544 while( itrMightCross.hasNext() ) {
1545 RefEdge edgeMightCross = itrMightCross.next();
1547 RefSrcNode rsnCallerAndOutContext =
1548 edgeMightCross.getSrc();
1550 if( rsnCallerAndOutContext instanceof VariableNode ) {
1551 // variables do not have out-of-context reach states,
1553 oocCallerEdges.add( edgeMightCross );
1557 HeapRegionNode hrnCallerAndOutContext =
1558 (HeapRegionNode) rsnCallerAndOutContext;
1560 // is this source node out-of-context?
1561 if( callerNodeIDsCopiedToCallee.contains( hrnCallerAndOutContext.getID() ) ) {
1562 // no, skip this edge
1567 oocCallerEdges.add( edgeMightCross );
1569 // add all reach tuples on the node to list
1570 // of things that are out-of-context: insight
1571 // if this node is reachable from someting that WAS
1572 // in-context, then this node should already be in-context
1573 Iterator<ReachState> stateItr = hrnCallerAndOutContext.getAlpha().iterator();
1574 while( stateItr.hasNext() ) {
1575 ReachState state = stateItr.next();
1577 Iterator<ReachTuple> rtItr = state.iterator();
1578 while( rtItr.hasNext() ) {
1579 ReachTuple rt = rtItr.next();
1581 oocHrnIdOoc2callee.add( new HrnIdOoc( rt.getHrnID(),
1590 // the callee view is a new graph: DON'T MODIFY *THIS* graph
1591 ReachGraph rg = new ReachGraph();
1593 // add nodes to callee graph
1594 Iterator<HeapRegionNode> hrnItr = reachableCallerNodes.iterator();
1595 while( hrnItr.hasNext() ) {
1596 HeapRegionNode hrnCaller = hrnItr.next();
1598 assert callerNodeIDsCopiedToCallee.contains( hrnCaller.getID() );
1599 assert !rg.id2hrn.containsKey( hrnCaller.getID() );
1601 ExistPred pred = ExistPred.factory( hrnCaller.getID(), null );
1602 ExistPredSet preds = ExistPredSet.factory( pred );
1604 rg.createNewHeapRegionNode( hrnCaller.getID(),
1605 hrnCaller.isSingleObject(),
1606 hrnCaller.isNewSummary(),
1607 hrnCaller.isFlagged(),
1608 false, // out-of-context?
1609 hrnCaller.getType(),
1610 hrnCaller.getAllocSite(),
1611 toCalleeContext( hrnCaller.getInherent(),
1615 toCalleeContext( hrnCaller.getAlpha(),
1620 hrnCaller.getDescription()
1624 // add param edges to callee graph
1626 reachableCallerArgEdges2paramIndex.entrySet().iterator();
1627 while( argEdges.hasNext() ) {
1628 Map.Entry me = (Map.Entry) argEdges.next();
1629 RefEdge reArg = (RefEdge) me.getKey();
1630 Integer index = (Integer) me.getValue();
1632 TempDescriptor arg = fmCallee.getParameter( index );
1634 VariableNode vnCallee =
1635 rg.getVariableNodeFromTemp( arg );
1637 HeapRegionNode hrnDstCaller = reArg.getDst();
1638 HeapRegionNode hrnDstCallee = rg.id2hrn.get( hrnDstCaller.getID() );
1639 assert hrnDstCallee != null;
1642 ExistPred.factory( arg,
1644 hrnDstCallee.getID(),
1648 true, // out-of-callee-context
1649 false // out-of-caller-context
1652 ExistPredSet preds =
1653 ExistPredSet.factory( pred );
1656 new RefEdge( vnCallee,
1660 toCalleeContext( reArg.getBeta(),
1667 rg.addRefEdge( vnCallee,
1673 // add in-context edges to callee graph
1674 Iterator<RefEdge> reItr = reachableCallerEdges.iterator();
1675 while( reItr.hasNext() ) {
1676 RefEdge reCaller = reItr.next();
1677 RefSrcNode rsnCaller = reCaller.getSrc();
1678 assert rsnCaller instanceof HeapRegionNode;
1679 HeapRegionNode hrnSrcCaller = (HeapRegionNode) rsnCaller;
1680 HeapRegionNode hrnDstCaller = reCaller.getDst();
1682 HeapRegionNode hrnSrcCallee = rg.id2hrn.get( hrnSrcCaller.getID() );
1683 HeapRegionNode hrnDstCallee = rg.id2hrn.get( hrnDstCaller.getID() );
1684 assert hrnSrcCallee != null;
1685 assert hrnDstCallee != null;
1688 ExistPred.factory( null,
1689 hrnSrcCallee.getID(),
1690 hrnDstCallee.getID(),
1692 reCaller.getField(),
1694 false, // out-of-callee-context
1695 false // out-of-caller-context
1698 ExistPredSet preds =
1699 ExistPredSet.factory( pred );
1702 new RefEdge( hrnSrcCallee,
1705 reCaller.getField(),
1706 toCalleeContext( reCaller.getBeta(),
1713 rg.addRefEdge( hrnSrcCallee,
1719 // add out-of-context edges to callee graph
1720 reItr = oocCallerEdges.iterator();
1721 while( reItr.hasNext() ) {
1722 RefEdge reCaller = reItr.next();
1723 RefSrcNode rsnCaller = reCaller.getSrc();
1724 HeapRegionNode hrnDstCaller = reCaller.getDst();
1725 HeapRegionNode hrnDstCallee = rg.id2hrn.get( hrnDstCaller.getID() );
1726 assert hrnDstCallee != null;
1728 TypeDescriptor oocNodeType;
1730 TempDescriptor oocPredSrcTemp = null;
1731 Integer oocPredSrcID = null;
1732 boolean outOfCalleeContext;
1733 boolean outOfCallerContext;
1735 if( rsnCaller instanceof VariableNode ) {
1736 VariableNode vnCaller = (VariableNode) rsnCaller;
1738 oocReach = rsetEmpty;
1739 oocPredSrcTemp = vnCaller.getTempDescriptor();
1740 outOfCalleeContext = true;
1741 outOfCallerContext = false;
1744 HeapRegionNode hrnSrcCaller = (HeapRegionNode) rsnCaller;
1745 assert !callerNodeIDsCopiedToCallee.contains( hrnSrcCaller.getID() );
1746 oocNodeType = hrnSrcCaller.getType();
1747 oocReach = hrnSrcCaller.getAlpha();
1748 oocPredSrcID = hrnSrcCaller.getID();
1749 if( hrnSrcCaller.isOutOfContext() ) {
1750 outOfCalleeContext = false;
1751 outOfCallerContext = true;
1753 outOfCalleeContext = true;
1754 outOfCallerContext = false;
1759 ExistPred.factory( oocPredSrcTemp,
1761 hrnDstCallee.getID(),
1763 reCaller.getField(),
1769 ExistPredSet preds =
1770 ExistPredSet.factory( pred );
1772 RefEdge oocEdgeExisting =
1773 rg.getOutOfContextReferenceTo( hrnDstCallee,
1779 if( oocEdgeExisting == null ) {
1780 // for consistency, map one out-of-context "identifier"
1781 // to one heap region node id, otherwise no convergence
1782 String oocid = "oocid"+
1784 hrnDstCallee.getIDString()+
1787 reCaller.getField();
1789 Integer oocHrnID = oocid2hrnid.get( oocid );
1791 HeapRegionNode hrnCalleeAndOutContext;
1793 if( oocHrnID == null ) {
1795 hrnCalleeAndOutContext =
1796 rg.createNewHeapRegionNode( null, // ID
1797 false, // single object?
1798 false, // new summary?
1800 true, // out-of-context?
1802 null, // alloc site, shouldn't be used
1803 toCalleeContext( oocReach,
1807 toCalleeContext( oocReach,
1815 oocid2hrnid.put( oocid, hrnCalleeAndOutContext.getID() );
1819 // the mapping already exists, so see if node is there
1820 hrnCalleeAndOutContext = rg.id2hrn.get( oocHrnID );
1822 if( hrnCalleeAndOutContext == null ) {
1824 hrnCalleeAndOutContext =
1825 rg.createNewHeapRegionNode( oocHrnID, // ID
1826 false, // single object?
1827 false, // new summary?
1829 true, // out-of-context?
1831 null, // alloc site, shouldn't be used
1832 toCalleeContext( oocReach,
1836 toCalleeContext( oocReach,
1845 // otherwise it is there, so merge reachability
1846 hrnCalleeAndOutContext.setAlpha( Canonical.unionORpreds( hrnCalleeAndOutContext.getAlpha(),
1847 toCalleeContext( oocReach,
1856 assert hrnCalleeAndOutContext.reachHasOnlyOOC();
1858 rg.addRefEdge( hrnCalleeAndOutContext,
1860 new RefEdge( hrnCalleeAndOutContext,
1863 reCaller.getField(),
1864 toCalleeContext( reCaller.getBeta(),
1873 // the out-of-context edge already exists
1874 oocEdgeExisting.setBeta( Canonical.unionORpreds( oocEdgeExisting.getBeta(),
1875 toCalleeContext( reCaller.getBeta(),
1882 oocEdgeExisting.setPreds( Canonical.join( oocEdgeExisting.getPreds(),
1887 HeapRegionNode hrnCalleeAndOutContext =
1888 (HeapRegionNode) oocEdgeExisting.getSrc();
1889 hrnCalleeAndOutContext.setAlpha( Canonical.unionORpreds( hrnCalleeAndOutContext.getAlpha(),
1890 toCalleeContext( oocReach,
1897 assert hrnCalleeAndOutContext.reachHasOnlyOOC();
1902 if( writeDebugDOTs ) {
1903 debugGraphPrefix = String.format( "call%02d", debugCallSiteVisits );
1904 rg.writeGraph( debugGraphPrefix+"calleeview",
1905 resolveMethodDebugDOTwriteLabels,
1906 resolveMethodDebugDOTselectTemps,
1907 resolveMethodDebugDOTpruneGarbage,
1908 resolveMethodDebugDOThideSubsetReach,
1909 resolveMethodDebugDOThideEdgeTaints );
1915 private static Hashtable<String, Integer> oocid2hrnid =
1916 new Hashtable<String, Integer>();
1919 // useful since many graphs writes in the method call debug code
1920 private static boolean resolveMethodDebugDOTwriteLabels = true;
1921 private static boolean resolveMethodDebugDOTselectTemps = true;
1922 private static boolean resolveMethodDebugDOTpruneGarbage = true;
1923 private static boolean resolveMethodDebugDOThideSubsetReach = false;
1924 private static boolean resolveMethodDebugDOThideEdgeTaints = true;
1926 static String debugGraphPrefix;
1927 static int debugCallSiteVisits = 0;
1928 static int debugCallSiteVisitsUntilExit = 0;
1932 resolveMethodCall( FlatCall fc,
1933 FlatMethod fmCallee,
1934 ReachGraph rgCallee,
1935 Set<Integer> callerNodeIDsCopiedToCallee,
1936 boolean writeDebugDOTs
1939 if( writeDebugDOTs ) {
1940 System.out.println( " Writing out visit "+
1941 debugCallSiteVisits+
1942 " to debug call site" );
1944 debugGraphPrefix = String.format( "call%02d",
1945 debugCallSiteVisits );
1947 rgCallee.writeGraph( debugGraphPrefix+"callee",
1948 resolveMethodDebugDOTwriteLabels,
1949 resolveMethodDebugDOTselectTemps,
1950 resolveMethodDebugDOTpruneGarbage,
1951 resolveMethodDebugDOThideSubsetReach,
1952 resolveMethodDebugDOThideEdgeTaints );
1954 writeGraph( debugGraphPrefix+"caller00In",
1955 resolveMethodDebugDOTwriteLabels,
1956 resolveMethodDebugDOTselectTemps,
1957 resolveMethodDebugDOTpruneGarbage,
1958 resolveMethodDebugDOThideSubsetReach,
1959 resolveMethodDebugDOThideEdgeTaints,
1960 callerNodeIDsCopiedToCallee );
1965 // method call transfer function steps:
1966 // 1. Use current callee-reachable heap (CRH) to test callee
1967 // predicates and mark what will be coming in.
1968 // 2. Wipe CRH out of caller.
1969 // 3. Transplant marked callee parts in:
1970 // a) bring in nodes
1971 // b) bring in callee -> callee edges
1972 // c) resolve out-of-context -> callee edges
1973 // d) assign return value
1974 // 4. Collapse shadow nodes down
1975 // 5. Global sweep it.
1978 // 1. mark what callee elements have satisfied predicates
1979 Hashtable<HeapRegionNode, ExistPredSet> calleeNodesSatisfied =
1980 new Hashtable<HeapRegionNode, ExistPredSet>();
1982 Hashtable<RefEdge, ExistPredSet> calleeEdgesSatisfied =
1983 new Hashtable<RefEdge, ExistPredSet>();
1985 Hashtable<ReachState, ExistPredSet> calleeStatesSatisfied =
1986 new Hashtable<ReachState, ExistPredSet>();
1988 Hashtable< RefEdge, Set<RefSrcNode> > calleeEdges2oocCallerSrcMatches =
1989 new Hashtable< RefEdge, Set<RefSrcNode> >();
1991 Iterator meItr = rgCallee.id2hrn.entrySet().iterator();
1992 while( meItr.hasNext() ) {
1993 Map.Entry me = (Map.Entry) meItr.next();
1994 Integer id = (Integer) me.getKey();
1995 HeapRegionNode hrnCallee = (HeapRegionNode) me.getValue();
1997 // if a callee element's predicates are satisfied then a set
1998 // of CALLER predicates is returned: they are the predicates
1999 // that the callee element moved into the caller context
2000 // should have, and it is inefficient to find this again later
2001 ExistPredSet predsIfSatis =
2002 hrnCallee.getPreds().isSatisfiedBy( this,
2003 callerNodeIDsCopiedToCallee
2006 if( predsIfSatis != null ) {
2007 calleeNodesSatisfied.put( hrnCallee, predsIfSatis );
2009 // otherwise don't bother looking at edges to this node
2013 // since the node is coming over, find out which reach
2014 // states on it should come over, too
2015 Iterator<ReachState> stateItr = hrnCallee.getAlpha().iterator();
2016 while( stateItr.hasNext() ) {
2017 ReachState stateCallee = stateItr.next();
2020 stateCallee.getPreds().isSatisfiedBy( this,
2021 callerNodeIDsCopiedToCallee
2023 if( predsIfSatis != null ) {
2024 calleeStatesSatisfied.put( stateCallee, predsIfSatis );
2028 // then look at edges to the node
2029 Iterator<RefEdge> reItr = hrnCallee.iteratorToReferencers();
2030 while( reItr.hasNext() ) {
2031 RefEdge reCallee = reItr.next();
2032 RefSrcNode rsnCallee = reCallee.getSrc();
2034 // (caller local variables to in-context heap regions)
2035 // have an (out-of-context heap region -> in-context heap region)
2036 // abstraction in the callEE, so its true we never need to
2037 // look at a (var node -> heap region) edge in callee to bring
2038 // those over for the call site transfer. What about (param var->heap region)
2039 // edges in callee? They are dealt with below this loop.
2040 // So, yes, at this point skip (var->region) edges in callee
2041 if( rsnCallee instanceof VariableNode ) {
2045 // first see if the source is out-of-context, and only
2046 // proceed with this edge if we find some caller-context
2048 HeapRegionNode hrnSrcCallee = (HeapRegionNode) rsnCallee;
2049 boolean matchedOutOfContext = false;
2051 if( !hrnSrcCallee.isOutOfContext() ) {
2054 hrnSrcCallee.getPreds().isSatisfiedBy( this,
2055 callerNodeIDsCopiedToCallee
2057 if( predsIfSatis != null ) {
2058 calleeNodesSatisfied.put( hrnSrcCallee, predsIfSatis );
2060 // otherwise forget this edge
2065 // hrnSrcCallee is out-of-context
2067 assert !calleeEdges2oocCallerSrcMatches.containsKey( reCallee );
2069 Set<RefSrcNode> rsnCallers = new HashSet<RefSrcNode>();
2071 // is the target node in the caller?
2072 HeapRegionNode hrnDstCaller = this.id2hrn.get( hrnCallee.getID() );
2073 if( hrnDstCaller == null ) {
2077 Iterator<RefEdge> reDstItr = hrnDstCaller.iteratorToReferencers();
2078 while( reDstItr.hasNext() ) {
2079 // the edge and field (either possibly null) must match
2080 RefEdge reCaller = reDstItr.next();
2082 if( !reCaller.typeEquals ( reCallee.getType() ) ||
2083 !reCaller.fieldEquals( reCallee.getField() )
2088 RefSrcNode rsnCaller = reCaller.getSrc();
2089 if( rsnCaller instanceof VariableNode ) {
2091 // a variable node matches an OOC region with null type
2092 if( hrnSrcCallee.getType() != null ) {
2097 // otherwise types should match
2098 HeapRegionNode hrnCallerSrc = (HeapRegionNode) rsnCaller;
2099 if( hrnSrcCallee.getType() == null ) {
2100 if( hrnCallerSrc.getType() != null ) {
2104 if( !hrnSrcCallee.getType().equals( hrnCallerSrc.getType() ) ) {
2110 rsnCallers.add( rsnCaller );
2111 matchedOutOfContext = true;
2114 if( !rsnCallers.isEmpty() ) {
2115 calleeEdges2oocCallerSrcMatches.put( reCallee, rsnCallers );
2119 if( hrnSrcCallee.isOutOfContext() &&
2120 !matchedOutOfContext ) {
2125 reCallee.getPreds().isSatisfiedBy( this,
2126 callerNodeIDsCopiedToCallee
2129 if( predsIfSatis != null ) {
2130 calleeEdgesSatisfied.put( reCallee, predsIfSatis );
2132 // since the edge is coming over, find out which reach
2133 // states on it should come over, too
2134 stateItr = reCallee.getBeta().iterator();
2135 while( stateItr.hasNext() ) {
2136 ReachState stateCallee = stateItr.next();
2139 stateCallee.getPreds().isSatisfiedBy( this,
2140 callerNodeIDsCopiedToCallee
2142 if( predsIfSatis != null ) {
2143 calleeStatesSatisfied.put( stateCallee, predsIfSatis );
2150 if( writeDebugDOTs ) {
2151 writeGraph( debugGraphPrefix+"caller20BeforeWipe",
2152 resolveMethodDebugDOTwriteLabels,
2153 resolveMethodDebugDOTselectTemps,
2154 resolveMethodDebugDOTpruneGarbage,
2155 resolveMethodDebugDOThideSubsetReach,
2156 resolveMethodDebugDOThideEdgeTaints );
2160 // 2. predicates tested, ok to wipe out caller part
2161 Iterator<Integer> hrnItr = callerNodeIDsCopiedToCallee.iterator();
2162 while( hrnItr.hasNext() ) {
2163 Integer hrnID = hrnItr.next();
2164 HeapRegionNode hrnCaller = id2hrn.get( hrnID );
2165 assert hrnCaller != null;
2167 // when clearing off nodes, also eliminate variable
2169 wipeOut( hrnCaller, true );
2174 if( writeDebugDOTs ) {
2175 writeGraph( debugGraphPrefix+"caller30BeforeAddingNodes",
2176 resolveMethodDebugDOTwriteLabels,
2177 resolveMethodDebugDOTselectTemps,
2178 resolveMethodDebugDOTpruneGarbage,
2179 resolveMethodDebugDOThideSubsetReach,
2180 resolveMethodDebugDOThideEdgeTaints );
2186 // 3. callee elements with satisfied preds come in, note that
2187 // the mapping of elements satisfied to preds is like this:
2188 // A callee element EE has preds EEp that are satisfied by
2189 // some caller element ER. We bring EE into the caller
2190 // context as ERee with the preds of ER, namely ERp, which
2191 // in the following algorithm is the value in the mapping
2194 Iterator satisItr = calleeNodesSatisfied.entrySet().iterator();
2195 while( satisItr.hasNext() ) {
2196 Map.Entry me = (Map.Entry) satisItr.next();
2197 HeapRegionNode hrnCallee = (HeapRegionNode) me.getKey();
2198 ExistPredSet preds = (ExistPredSet) me.getValue();
2200 // TODO: I think its true that the current implementation uses
2201 // the type of the OOC region and the predicates OF THE EDGE from
2202 // it to link everything up in caller context, so that's why we're
2203 // skipping this... maybe that's a sillier way to do it?
2204 if( hrnCallee.isOutOfContext() ) {
2208 AllocSite as = hrnCallee.getAllocSite();
2209 allocSites.add( as );
2211 Integer hrnIDshadow = as.getShadowIDfromID( hrnCallee.getID() );
2213 HeapRegionNode hrnCaller = id2hrn.get( hrnIDshadow );
2214 if( hrnCaller == null ) {
2216 createNewHeapRegionNode( hrnIDshadow, // id or null to generate a new one
2217 hrnCallee.isSingleObject(), // single object?
2218 hrnCallee.isNewSummary(), // summary?
2219 hrnCallee.isFlagged(), // flagged?
2220 false, // out-of-context?
2221 hrnCallee.getType(), // type
2222 hrnCallee.getAllocSite(), // allocation site
2223 toCallerContext( hrnCallee.getInherent(),
2224 calleeStatesSatisfied ), // inherent reach
2225 null, // current reach
2226 predsEmpty, // predicates
2227 hrnCallee.getDescription() // description
2230 assert hrnCaller.isWiped();
2233 hrnCaller.setAlpha( toCallerContext( hrnCallee.getAlpha(),
2234 calleeStatesSatisfied
2238 hrnCaller.setPreds( preds );
2245 if( writeDebugDOTs ) {
2246 writeGraph( debugGraphPrefix+"caller31BeforeAddingEdges",
2247 resolveMethodDebugDOTwriteLabels,
2248 resolveMethodDebugDOTselectTemps,
2249 resolveMethodDebugDOTpruneGarbage,
2250 resolveMethodDebugDOThideSubsetReach,
2251 resolveMethodDebugDOThideEdgeTaints );
2255 // set these up during the next procedure so after
2256 // the caller has all of its nodes and edges put
2257 // back together we can propagate the callee's
2258 // reach changes backwards into the caller graph
2259 HashSet<RefEdge> edgesForPropagation = new HashSet<RefEdge>();
2261 Hashtable<RefEdge, ChangeSet> edgePlannedChanges =
2262 new Hashtable<RefEdge, ChangeSet>();
2265 // 3.b) callee -> callee edges AND out-of-context -> callee
2266 satisItr = calleeEdgesSatisfied.entrySet().iterator();
2267 while( satisItr.hasNext() ) {
2268 Map.Entry me = (Map.Entry) satisItr.next();
2269 RefEdge reCallee = (RefEdge) me.getKey();
2270 ExistPredSet preds = (ExistPredSet) me.getValue();
2272 HeapRegionNode hrnDstCallee = reCallee.getDst();
2273 AllocSite asDst = hrnDstCallee.getAllocSite();
2274 allocSites.add( asDst );
2276 Integer hrnIDDstShadow =
2277 asDst.getShadowIDfromID( hrnDstCallee.getID() );
2279 HeapRegionNode hrnDstCaller = id2hrn.get( hrnIDDstShadow );
2280 assert hrnDstCaller != null;
2283 RefSrcNode rsnCallee = reCallee.getSrc();
2285 Set<RefSrcNode> rsnCallers =
2286 new HashSet<RefSrcNode>();
2288 Set<RefSrcNode> oocCallers =
2289 calleeEdges2oocCallerSrcMatches.get( reCallee );
2291 if( rsnCallee instanceof HeapRegionNode ) {
2292 HeapRegionNode hrnCalleeSrc = (HeapRegionNode) rsnCallee;
2293 if( hrnCalleeSrc.isOutOfContext() ) {
2294 assert oocCallers != null;
2299 if( oocCallers == null ) {
2300 // there are no out-of-context matches, so it's
2301 // either a param/arg var or one in-context heap region
2302 if( rsnCallee instanceof VariableNode ) {
2303 // variable -> node in the callee should only
2304 // come into the caller if its from a param var
2305 VariableNode vnCallee = (VariableNode) rsnCallee;
2306 TempDescriptor tdParam = vnCallee.getTempDescriptor();
2307 TempDescriptor tdArg = fc.getArgMatchingParam( fmCallee,
2309 if( tdArg == null ) {
2310 // this means the variable isn't a parameter, its local
2311 // to the callee so we ignore it in call site transfer
2312 // shouldn't this NEVER HAPPEN?
2316 rsnCallers.add( this.getVariableNodeFromTemp( tdArg ) );
2319 // otherwise source is in context, one region
2321 HeapRegionNode hrnSrcCallee = (HeapRegionNode) rsnCallee;
2323 // translate an in-context node to shadow
2324 AllocSite asSrc = hrnSrcCallee.getAllocSite();
2325 allocSites.add( asSrc );
2327 Integer hrnIDSrcShadow =
2328 asSrc.getShadowIDfromID( hrnSrcCallee.getID() );
2330 HeapRegionNode hrnSrcCallerShadow =
2331 this.id2hrn.get( hrnIDSrcShadow );
2333 assert hrnSrcCallerShadow != null;
2335 rsnCallers.add( hrnSrcCallerShadow );
2339 // otherwise we have a set of out-of-context srcs
2340 // that should NOT be translated to shadow nodes
2341 assert !oocCallers.isEmpty();
2342 rsnCallers.addAll( oocCallers );
2345 // now make all caller edges we've identified from
2346 // this callee edge with a satisfied predicate
2347 assert !rsnCallers.isEmpty();
2348 Iterator<RefSrcNode> rsnItr = rsnCallers.iterator();
2349 while( rsnItr.hasNext() ) {
2350 RefSrcNode rsnCaller = rsnItr.next();
2352 RefEdge reCaller = new RefEdge( rsnCaller,
2355 reCallee.getField(),
2356 toCallerContext( reCallee.getBeta(),
2357 calleeStatesSatisfied ),
2361 ChangeSet cs = ChangeSet.factory();
2362 Iterator<ReachState> rsItr = reCaller.getBeta().iterator();
2363 while( rsItr.hasNext() ) {
2364 ReachState state = rsItr.next();
2365 ExistPredSet predsPreCallee = state.getPreds();
2367 if( state.isEmpty() ) {
2371 Iterator<ExistPred> predItr = predsPreCallee.iterator();
2372 while( predItr.hasNext() ) {
2373 ExistPred pred = predItr.next();
2374 ReachState old = pred.ne_state;
2380 cs = Canonical.add( cs,
2381 ChangeTuple.factory( old,
2389 // look to see if an edge with same field exists
2390 // and merge with it, otherwise just add the edge
2391 RefEdge edgeExisting = rsnCaller.getReferenceTo( hrnDstCaller,
2395 if( edgeExisting != null ) {
2396 edgeExisting.setBeta(
2397 Canonical.unionORpreds( edgeExisting.getBeta(),
2401 edgeExisting.setPreds(
2402 Canonical.join( edgeExisting.getPreds(),
2407 // for reach propagation
2408 if( !cs.isEmpty() ) {
2409 ChangeSet csExisting = edgePlannedChanges.get( edgeExisting );
2410 if( csExisting == null ) {
2411 csExisting = ChangeSet.factory();
2413 edgePlannedChanges.put( edgeExisting,
2414 Canonical.union( csExisting,
2421 addRefEdge( rsnCaller, hrnDstCaller, reCaller );
2423 // for reach propagation
2424 if( !cs.isEmpty() ) {
2425 edgesForPropagation.add( reCaller );
2426 assert !edgePlannedChanges.containsKey( reCaller );
2427 edgePlannedChanges.put( reCaller, cs );
2436 if( writeDebugDOTs ) {
2437 writeGraph( debugGraphPrefix+"caller35BeforeAssignReturnValue",
2438 resolveMethodDebugDOTwriteLabels,
2439 resolveMethodDebugDOTselectTemps,
2440 resolveMethodDebugDOTpruneGarbage,
2441 resolveMethodDebugDOThideSubsetReach,
2442 resolveMethodDebugDOThideEdgeTaints );
2447 // TODO: WAIT! THIS SHOULD BE MERGED INTO OTHER PARTS, BECAUSE
2448 // AS IT IS WE'RE NOT VERIFYING PREDICATES OF RETURN VALUE
2449 // EDGES, JUST BRINGING THEM ALL! It'll work for now, over approximation
2451 // 3.d) handle return value assignment if needed
2452 TempDescriptor returnTemp = fc.getReturnTemp();
2453 if( returnTemp != null &&
2454 DisjointAnalysis.shouldAnalysisTrack( returnTemp.getType() )
2457 VariableNode vnLhsCaller = getVariableNodeFromTemp( returnTemp );
2458 clearRefEdgesFrom( vnLhsCaller, null, null, true );
2460 VariableNode vnReturnCallee = rgCallee.getVariableNodeFromTemp( tdReturn );
2461 Iterator<RefEdge> reCalleeItr = vnReturnCallee.iteratorToReferencees();
2462 while( reCalleeItr.hasNext() ) {
2463 RefEdge reCallee = reCalleeItr.next();
2464 HeapRegionNode hrnDstCallee = reCallee.getDst();
2466 // some edge types are not possible return values when we can
2467 // see what type variable we are assigning it to
2468 if( !isSuperiorType( returnTemp.getType(), reCallee.getType() ) ) {
2469 System.out.println( "*** NOT EXPECTING TO SEE THIS: Throwing out "+
2470 reCallee+" for return temp "+returnTemp );
2475 AllocSite asDst = hrnDstCallee.getAllocSite();
2476 allocSites.add( asDst );
2478 Integer hrnIDDstShadow = asDst.getShadowIDfromID( hrnDstCallee.getID() );
2480 HeapRegionNode hrnDstCaller = id2hrn.get( hrnIDDstShadow );
2481 if( hrnDstCaller == null ) {
2483 createNewHeapRegionNode( hrnIDDstShadow, // id or null to generate a new one
2484 hrnDstCallee.isSingleObject(), // single object?
2485 hrnDstCallee.isNewSummary(), // summary?
2486 hrnDstCallee.isFlagged(), // flagged?
2487 false, // out-of-context?
2488 hrnDstCallee.getType(), // type
2489 hrnDstCallee.getAllocSite(), // allocation site
2490 toCallerContext( hrnDstCallee.getInherent(),
2491 calleeStatesSatisfied ), // inherent reach
2492 toCallerContext( hrnDstCallee.getAlpha(),
2493 calleeStatesSatisfied ), // current reach
2494 predsTrue, // predicates
2495 hrnDstCallee.getDescription() // description
2499 TypeDescriptor tdNewEdge =
2500 mostSpecificType( reCallee.getType(),
2501 hrnDstCallee.getType(),
2502 hrnDstCaller.getType()
2505 RefEdge reCaller = new RefEdge( vnLhsCaller,
2509 toCallerContext( reCallee.getBeta(),
2510 calleeStatesSatisfied ),
2514 addRefEdge( vnLhsCaller, hrnDstCaller, reCaller );
2520 if( writeDebugDOTs ) {
2521 writeGraph( debugGraphPrefix+"caller38propagateReach",
2522 resolveMethodDebugDOTwriteLabels,
2523 resolveMethodDebugDOTselectTemps,
2524 resolveMethodDebugDOTpruneGarbage,
2525 resolveMethodDebugDOThideSubsetReach,
2526 resolveMethodDebugDOThideEdgeTaints );
2529 // propagate callee reachability changes to the rest
2530 // of the caller graph edges
2531 HashSet<RefEdge> edgesUpdated = new HashSet<RefEdge>();
2533 propagateTokensOverEdges( edgesForPropagation, // source edges
2534 edgePlannedChanges, // map src edge to change set
2535 edgesUpdated ); // list of updated edges
2537 // commit beta' (beta<-betaNew)
2538 Iterator<RefEdge> edgeItr = edgesUpdated.iterator();
2539 while( edgeItr.hasNext() ) {
2540 edgeItr.next().applyBetaNew();
2549 if( writeDebugDOTs ) {
2550 writeGraph( debugGraphPrefix+"caller40BeforeShadowMerge",
2551 resolveMethodDebugDOTwriteLabels,
2552 resolveMethodDebugDOTselectTemps,
2553 resolveMethodDebugDOTpruneGarbage,
2554 resolveMethodDebugDOThideSubsetReach,
2555 resolveMethodDebugDOThideEdgeTaints );
2559 // 4) merge shadow nodes so alloc sites are back to k
2560 Iterator<AllocSite> asItr = rgCallee.allocSites.iterator();
2561 while( asItr.hasNext() ) {
2562 // for each allocation site do the following to merge
2563 // shadow nodes (newest from callee) with any existing
2564 // look for the newest normal and newest shadow "slot"
2565 // not being used, transfer normal to shadow. Keep
2566 // doing this until there are no more normal nodes, or
2567 // no empty shadow slots: then merge all remaining normal
2568 // nodes into the shadow summary. Finally, convert all
2569 // shadow to their normal versions.
2570 AllocSite as = asItr.next();
2573 while( ageNorm < allocationDepth &&
2574 ageShad < allocationDepth ) {
2576 // first, are there any normal nodes left?
2577 Integer idNorm = as.getIthOldest( ageNorm );
2578 HeapRegionNode hrnNorm = id2hrn.get( idNorm );
2579 if( hrnNorm == null ) {
2580 // no, this age of normal node not in the caller graph
2585 // yes, a normal node exists, is there an empty shadow
2586 // "slot" to transfer it onto?
2587 HeapRegionNode hrnShad = getIthNode( as, ageShad, true );
2588 if( !hrnShad.isWiped() ) {
2589 // no, this age of shadow node is not empty
2594 // yes, this shadow node is empty
2595 transferOnto( hrnNorm, hrnShad );
2600 // now, while there are still normal nodes but no shadow
2601 // slots, merge normal nodes into the shadow summary
2602 while( ageNorm < allocationDepth ) {
2604 // first, are there any normal nodes left?
2605 Integer idNorm = as.getIthOldest( ageNorm );
2606 HeapRegionNode hrnNorm = id2hrn.get( idNorm );
2607 if( hrnNorm == null ) {
2608 // no, this age of normal node not in the caller graph
2613 // yes, a normal node exists, so get the shadow summary
2614 HeapRegionNode summShad = getSummaryNode( as, true );
2615 mergeIntoSummary( hrnNorm, summShad );
2619 // if there is a normal summary, merge it into shadow summary
2620 Integer idNorm = as.getSummary();
2621 HeapRegionNode summNorm = id2hrn.get( idNorm );
2622 if( summNorm != null ) {
2623 HeapRegionNode summShad = getSummaryNode( as, true );
2624 mergeIntoSummary( summNorm, summShad );
2627 // finally, flip all existing shadow nodes onto the normal
2628 for( int i = 0; i < allocationDepth; ++i ) {
2629 Integer idShad = as.getIthOldestShadow( i );
2630 HeapRegionNode hrnShad = id2hrn.get( idShad );
2631 if( hrnShad != null ) {
2633 HeapRegionNode hrnNorm = getIthNode( as, i, false );
2634 assert hrnNorm.isWiped();
2635 transferOnto( hrnShad, hrnNorm );
2639 Integer idShad = as.getSummaryShadow();
2640 HeapRegionNode summShad = id2hrn.get( idShad );
2641 if( summShad != null ) {
2642 summNorm = getSummaryNode( as, false );
2643 transferOnto( summShad, summNorm );
2652 if( writeDebugDOTs ) {
2653 writeGraph( debugGraphPrefix+"caller45BeforeUnshadow",
2654 resolveMethodDebugDOTwriteLabels,
2655 resolveMethodDebugDOTselectTemps,
2656 resolveMethodDebugDOTpruneGarbage,
2657 resolveMethodDebugDOThideSubsetReach,
2658 resolveMethodDebugDOThideEdgeTaints );
2662 Iterator itrAllHRNodes = id2hrn.entrySet().iterator();
2663 while( itrAllHRNodes.hasNext() ) {
2664 Map.Entry me = (Map.Entry) itrAllHRNodes.next();
2665 HeapRegionNode hrn = (HeapRegionNode) me.getValue();
2667 hrn.setAlpha( unshadow( hrn.getAlpha() ) );
2669 Iterator<RefEdge> itrEdges = hrn.iteratorToReferencers();
2670 while( itrEdges.hasNext() ) {
2671 RefEdge re = itrEdges.next();
2672 re.setBeta( unshadow( re.getBeta() ) );
2679 if( writeDebugDOTs ) {
2680 writeGraph( debugGraphPrefix+"caller50BeforeGlobalSweep",
2681 resolveMethodDebugDOTwriteLabels,
2682 resolveMethodDebugDOTselectTemps,
2683 resolveMethodDebugDOTpruneGarbage,
2684 resolveMethodDebugDOThideSubsetReach,
2685 resolveMethodDebugDOThideEdgeTaints );
2690 if( !DISABLE_GLOBAL_SWEEP ) {
2698 if( writeDebugDOTs ) {
2699 writeGraph( debugGraphPrefix+"caller90AfterTransfer",
2700 resolveMethodDebugDOTwriteLabels,
2701 resolveMethodDebugDOTselectTemps,
2702 resolveMethodDebugDOTpruneGarbage,
2703 resolveMethodDebugDOThideSubsetReach,
2704 resolveMethodDebugDOThideEdgeTaints );
2706 ++debugCallSiteVisits;
2707 if( debugCallSiteVisits >= debugCallSiteVisitsUntilExit ) {
2708 System.out.println( "!!! Exiting after requested visits to call site. !!!" );
2716 ////////////////////////////////////////////////////
2718 // Abstract garbage collection simply removes
2719 // heap region nodes that are not mechanically
2720 // reachable from a root set. This step is
2721 // essential for testing node and edge existence
2722 // predicates efficiently
2724 ////////////////////////////////////////////////////
2725 public void abstractGarbageCollect( Set<TempDescriptor> liveSet ) {
2727 // calculate a root set, will be different for Java
2728 // version of analysis versus Bamboo version
2729 Set<RefSrcNode> toVisit = new HashSet<RefSrcNode>();
2731 // visit every variable in graph while building root
2732 // set, and do iterating on a copy, so we can remove
2733 // dead variables while we're at this
2734 Iterator makeCopyItr = td2vn.entrySet().iterator();
2735 Set entrysCopy = new HashSet();
2736 while( makeCopyItr.hasNext() ) {
2737 entrysCopy.add( makeCopyItr.next() );
2740 Iterator eItr = entrysCopy.iterator();
2741 while( eItr.hasNext() ) {
2742 Map.Entry me = (Map.Entry) eItr.next();
2743 TempDescriptor td = (TempDescriptor) me.getKey();
2744 VariableNode vn = (VariableNode) me.getValue();
2746 if( liveSet.contains( td ) ) {
2750 // dead var, remove completely from graph
2752 clearRefEdgesFrom( vn, null, null, true );
2756 // everything visited in a traversal is
2757 // considered abstractly live
2758 Set<RefSrcNode> visited = new HashSet<RefSrcNode>();
2760 while( !toVisit.isEmpty() ) {
2761 RefSrcNode rsn = toVisit.iterator().next();
2762 toVisit.remove( rsn );
2765 Iterator<RefEdge> hrnItr = rsn.iteratorToReferencees();
2766 while( hrnItr.hasNext() ) {
2767 RefEdge edge = hrnItr.next();
2768 HeapRegionNode hrn = edge.getDst();
2770 if( !visited.contains( hrn ) ) {
2776 // get a copy of the set to iterate over because
2777 // we're going to monkey with the graph when we
2778 // identify a garbage node
2779 Set<HeapRegionNode> hrnAllPrior = new HashSet<HeapRegionNode>();
2780 Iterator<HeapRegionNode> hrnItr = id2hrn.values().iterator();
2781 while( hrnItr.hasNext() ) {
2782 hrnAllPrior.add( hrnItr.next() );
2785 Iterator<HeapRegionNode> hrnAllItr = hrnAllPrior.iterator();
2786 while( hrnAllItr.hasNext() ) {
2787 HeapRegionNode hrn = hrnAllItr.next();
2789 if( !visited.contains( hrn ) ) {
2791 // heap region nodes are compared across ReachGraph
2792 // objects by their integer ID, so when discarding
2793 // garbage nodes we must also discard entries in
2794 // the ID -> heap region hashtable.
2795 id2hrn.remove( hrn.getID() );
2797 // RefEdge objects are two-way linked between
2798 // nodes, so when a node is identified as garbage,
2799 // actively clear references to and from it so
2800 // live nodes won't have dangling RefEdge's
2801 wipeOut( hrn, true );
2803 // if we just removed the last node from an allocation
2804 // site, it should be taken out of the ReachGraph's list
2805 AllocSite as = hrn.getAllocSite();
2806 if( !hasNodesOf( as ) ) {
2807 allocSites.remove( as );
2813 protected boolean hasNodesOf( AllocSite as ) {
2814 if( id2hrn.containsKey( as.getSummary() ) ) {
2818 for( int i = 0; i < allocationDepth; ++i ) {
2819 if( id2hrn.containsKey( as.getIthOldest( i ) ) ) {
2827 ////////////////////////////////////////////////////
2829 // This global sweep is an optional step to prune
2830 // reachability sets that are not internally
2831 // consistent with the global graph. It should be
2832 // invoked after strong updates or method calls.
2834 ////////////////////////////////////////////////////
2835 public void globalSweep() {
2837 // boldB is part of the phase 1 sweep
2838 // it has an in-context table and an out-of-context table
2839 Hashtable< Integer, Hashtable<RefEdge, ReachSet> > boldBic =
2840 new Hashtable< Integer, Hashtable<RefEdge, ReachSet> >();
2842 Hashtable< Integer, Hashtable<RefEdge, ReachSet> > boldBooc =
2843 new Hashtable< Integer, Hashtable<RefEdge, ReachSet> >();
2845 // visit every heap region to initialize alphaNew and betaNew,
2846 // and make a map of every hrnID to the source nodes it should
2847 // propagate forward from. In-context flagged hrnID's propagate
2848 // from only the in-context node they name, but out-of-context
2849 // ID's may propagate from several out-of-context nodes
2850 Hashtable< Integer, Set<HeapRegionNode> > icID2srcs =
2851 new Hashtable< Integer, Set<HeapRegionNode> >();
2853 Hashtable< Integer, Set<HeapRegionNode> > oocID2srcs =
2854 new Hashtable< Integer, Set<HeapRegionNode> >();
2857 Iterator itrHrns = id2hrn.entrySet().iterator();
2858 while( itrHrns.hasNext() ) {
2859 Map.Entry me = (Map.Entry) itrHrns.next();
2860 Integer hrnID = (Integer) me.getKey();
2861 HeapRegionNode hrn = (HeapRegionNode) me.getValue();
2863 // assert that this node and incoming edges have clean alphaNew
2864 // and betaNew sets, respectively
2865 assert rsetEmpty.equals( hrn.getAlphaNew() );
2867 Iterator<RefEdge> itrRers = hrn.iteratorToReferencers();
2868 while( itrRers.hasNext() ) {
2869 RefEdge edge = itrRers.next();
2870 assert rsetEmpty.equals( edge.getBetaNew() );
2873 // make a mapping of IDs to heap regions they propagate from
2874 if( hrn.isFlagged() ) {
2875 assert !hrn.isOutOfContext();
2876 assert !icID2srcs.containsKey( hrn.getID() );
2878 // in-context flagged node IDs simply propagate from the
2880 Set<HeapRegionNode> srcs = new HashSet<HeapRegionNode>();
2882 icID2srcs.put( hrn.getID(), srcs );
2885 if( hrn.isOutOfContext() ) {
2886 assert !hrn.isFlagged();
2888 // the reachability states on an out-of-context
2889 // node are not really important (combinations of
2890 // IDs or arity)--what matters is that the states
2891 // specify which nodes this out-of-context node
2892 // stands in for. For example, if the state [17?, 19*]
2893 // appears on the ooc node, it may serve as a source
2894 // for node 17? and a source for node 19.
2895 Iterator<ReachState> stateItr = hrn.getAlpha().iterator();
2896 while( stateItr.hasNext() ) {
2897 ReachState state = stateItr.next();
2899 Iterator<ReachTuple> rtItr = state.iterator();
2900 while( rtItr.hasNext() ) {
2901 ReachTuple rt = rtItr.next();
2902 assert rt.isOutOfContext();
2904 Set<HeapRegionNode> srcs = oocID2srcs.get( rt.getHrnID() );
2905 if( srcs == null ) {
2906 srcs = new HashSet<HeapRegionNode>();
2909 oocID2srcs.put( rt.getHrnID(), srcs );
2915 // calculate boldB for all hrnIDs identified by the above
2916 // node traversal, propagating from every source
2917 while( !icID2srcs.isEmpty() || !oocID2srcs.isEmpty() ) {
2920 Set<HeapRegionNode> srcs;
2923 if( !icID2srcs.isEmpty() ) {
2924 Map.Entry me = (Map.Entry) icID2srcs.entrySet().iterator().next();
2925 hrnID = (Integer) me.getKey();
2926 srcs = (Set<HeapRegionNode>) me.getValue();
2928 icID2srcs.remove( hrnID );
2931 assert !oocID2srcs.isEmpty();
2933 Map.Entry me = (Map.Entry) oocID2srcs.entrySet().iterator().next();
2934 hrnID = (Integer) me.getKey();
2935 srcs = (Set<HeapRegionNode>) me.getValue();
2937 oocID2srcs.remove( hrnID );
2941 Hashtable<RefEdge, ReachSet> boldB_f =
2942 new Hashtable<RefEdge, ReachSet>();
2944 Set<RefEdge> workSetEdges = new HashSet<RefEdge>();
2946 Iterator<HeapRegionNode> hrnItr = srcs.iterator();
2947 while( hrnItr.hasNext() ) {
2948 HeapRegionNode hrn = hrnItr.next();
2950 assert workSetEdges.isEmpty();
2952 // initial boldB_f constraints
2953 Iterator<RefEdge> itrRees = hrn.iteratorToReferencees();
2954 while( itrRees.hasNext() ) {
2955 RefEdge edge = itrRees.next();
2957 assert !boldB_f.containsKey( edge );
2958 boldB_f.put( edge, edge.getBeta() );
2960 assert !workSetEdges.contains( edge );
2961 workSetEdges.add( edge );
2964 // enforce the boldB_f constraint at edges until we reach a fixed point
2965 while( !workSetEdges.isEmpty() ) {
2966 RefEdge edge = workSetEdges.iterator().next();
2967 workSetEdges.remove( edge );
2969 Iterator<RefEdge> itrPrime = edge.getDst().iteratorToReferencees();
2970 while( itrPrime.hasNext() ) {
2971 RefEdge edgePrime = itrPrime.next();
2973 ReachSet prevResult = boldB_f.get( edgePrime );
2974 ReachSet intersection = Canonical.intersection( boldB_f.get( edge ),
2978 if( prevResult == null ||
2979 Canonical.unionORpreds( prevResult,
2980 intersection ).size()
2984 if( prevResult == null ) {
2985 boldB_f.put( edgePrime,
2986 Canonical.unionORpreds( edgePrime.getBeta(),
2991 boldB_f.put( edgePrime,
2992 Canonical.unionORpreds( prevResult,
2997 workSetEdges.add( edgePrime );
3004 boldBic.put( hrnID, boldB_f );
3006 boldBooc.put( hrnID, boldB_f );
3011 // use boldB to prune hrnIDs from alpha states that are impossible
3012 // and propagate the differences backwards across edges
3013 HashSet<RefEdge> edgesForPropagation = new HashSet<RefEdge>();
3015 Hashtable<RefEdge, ChangeSet> edgePlannedChanges =
3016 new Hashtable<RefEdge, ChangeSet>();
3019 itrHrns = id2hrn.entrySet().iterator();
3020 while( itrHrns.hasNext() ) {
3021 Map.Entry me = (Map.Entry) itrHrns.next();
3022 Integer hrnID = (Integer) me.getKey();
3023 HeapRegionNode hrn = (HeapRegionNode) me.getValue();
3025 // out-of-context nodes don't participate in the
3026 // global sweep, they serve as sources for the pass
3028 if( hrn.isOutOfContext() ) {
3032 // the inherent states of a region are the exception
3033 // to removal as the global sweep prunes
3034 ReachTuple rtException = ReachTuple.factory( hrnID,
3035 !hrn.isSingleObject(),
3036 ReachTuple.ARITY_ONE,
3037 false // out-of-context
3040 ChangeSet cts = ChangeSet.factory();
3042 // mark hrnIDs for removal
3043 Iterator<ReachState> stateItr = hrn.getAlpha().iterator();
3044 while( stateItr.hasNext() ) {
3045 ReachState stateOld = stateItr.next();
3047 ReachState markedHrnIDs = ReachState.factory();
3049 Iterator<ReachTuple> rtItr = stateOld.iterator();
3050 while( rtItr.hasNext() ) {
3051 ReachTuple rtOld = rtItr.next();
3053 // never remove the inherent hrnID from a flagged region
3054 // because it is trivially satisfied
3055 if( hrn.isFlagged() ) {
3056 if( rtOld == rtException ) {
3061 // does boldB allow this hrnID?
3062 boolean foundState = false;
3063 Iterator<RefEdge> incidentEdgeItr = hrn.iteratorToReferencers();
3064 while( incidentEdgeItr.hasNext() ) {
3065 RefEdge incidentEdge = incidentEdgeItr.next();
3067 Hashtable<RefEdge, ReachSet> B;
3068 if( rtOld.isOutOfContext() ) {
3069 B = boldBooc.get( rtOld.getHrnID() );
3072 if( !id2hrn.containsKey( rtOld.getHrnID() ) ) {
3073 // let symbols not in the graph get pruned
3077 B = boldBic.get( rtOld.getHrnID() );
3081 ReachSet boldB_rtOld_incident = B.get( incidentEdge );
3082 if( boldB_rtOld_incident != null &&
3083 boldB_rtOld_incident.containsIgnorePreds( stateOld ) != null
3091 markedHrnIDs = Canonical.add( markedHrnIDs, rtOld );
3095 // if there is nothing marked, just move on
3096 if( markedHrnIDs.isEmpty() ) {
3097 hrn.setAlphaNew( Canonical.add( hrn.getAlphaNew(),
3104 // remove all marked hrnIDs and establish a change set that should
3105 // propagate backwards over edges from this node
3106 ReachState statePruned = ReachState.factory();
3107 rtItr = stateOld.iterator();
3108 while( rtItr.hasNext() ) {
3109 ReachTuple rtOld = rtItr.next();
3111 if( !markedHrnIDs.containsTuple( rtOld ) ) {
3112 statePruned = Canonical.add( statePruned, rtOld );
3115 assert !stateOld.equals( statePruned );
3117 hrn.setAlphaNew( Canonical.add( hrn.getAlphaNew(),
3121 ChangeTuple ct = ChangeTuple.factory( stateOld,
3124 cts = Canonical.add( cts, ct );
3127 // throw change tuple set on all incident edges
3128 if( !cts.isEmpty() ) {
3129 Iterator<RefEdge> incidentEdgeItr = hrn.iteratorToReferencers();
3130 while( incidentEdgeItr.hasNext() ) {
3131 RefEdge incidentEdge = incidentEdgeItr.next();
3133 edgesForPropagation.add( incidentEdge );
3135 if( edgePlannedChanges.get( incidentEdge ) == null ) {
3136 edgePlannedChanges.put( incidentEdge, cts );
3138 edgePlannedChanges.put(
3140 Canonical.union( edgePlannedChanges.get( incidentEdge ),
3149 HashSet<RefEdge> edgesUpdated = new HashSet<RefEdge>();
3151 propagateTokensOverEdges( edgesForPropagation,
3155 // at the end of the 1st phase reference edges have
3156 // beta, betaNew that correspond to beta and betaR
3158 // commit beta<-betaNew, so beta=betaR and betaNew
3159 // will represent the beta' calculation in 2nd phase
3161 // commit alpha<-alphaNew because it won't change
3162 HashSet<RefEdge> res = new HashSet<RefEdge>();
3164 Iterator<HeapRegionNode> nodeItr = id2hrn.values().iterator();
3165 while( nodeItr.hasNext() ) {
3166 HeapRegionNode hrn = nodeItr.next();
3168 // as mentioned above, out-of-context nodes only serve
3169 // as sources of reach states for the sweep, not part
3171 if( hrn.isOutOfContext() ) {
3172 assert hrn.getAlphaNew().equals( rsetEmpty );
3174 hrn.applyAlphaNew();
3177 Iterator<RefEdge> itrRes = hrn.iteratorToReferencers();
3178 while( itrRes.hasNext() ) {
3179 res.add( itrRes.next() );
3185 Iterator<RefEdge> edgeItr = res.iterator();
3186 while( edgeItr.hasNext() ) {
3187 RefEdge edge = edgeItr.next();
3188 HeapRegionNode hrn = edge.getDst();
3190 // commit results of last phase
3191 if( edgesUpdated.contains( edge ) ) {
3192 edge.applyBetaNew();
3195 // compute intial condition of 2nd phase
3196 edge.setBetaNew( Canonical.intersection( edge.getBeta(),
3202 // every edge in the graph is the initial workset
3203 Set<RefEdge> edgeWorkSet = (Set) res.clone();
3204 while( !edgeWorkSet.isEmpty() ) {
3205 RefEdge edgePrime = edgeWorkSet.iterator().next();
3206 edgeWorkSet.remove( edgePrime );
3208 RefSrcNode rsn = edgePrime.getSrc();
3209 if( !(rsn instanceof HeapRegionNode) ) {
3212 HeapRegionNode hrn = (HeapRegionNode) rsn;
3214 Iterator<RefEdge> itrEdge = hrn.iteratorToReferencers();
3215 while( itrEdge.hasNext() ) {
3216 RefEdge edge = itrEdge.next();
3218 ReachSet prevResult = edge.getBetaNew();
3219 assert prevResult != null;
3221 ReachSet intersection =
3222 Canonical.intersection( edge.getBeta(),
3223 edgePrime.getBetaNew()
3226 if( Canonical.unionORpreds( prevResult,
3233 Canonical.unionORpreds( prevResult,
3237 edgeWorkSet.add( edge );
3242 // commit beta' (beta<-betaNew)
3243 edgeItr = res.iterator();
3244 while( edgeItr.hasNext() ) {
3245 edgeItr.next().applyBetaNew();
3250 // a useful assertion for debugging:
3251 // every in-context tuple on any edge or
3252 // any node should name a node that is
3253 // part of the graph
3254 public boolean inContextTuplesInGraph() {
3256 Iterator hrnItr = id2hrn.entrySet().iterator();
3257 while( hrnItr.hasNext() ) {
3258 Map.Entry me = (Map.Entry) hrnItr.next();
3259 HeapRegionNode hrn = (HeapRegionNode) me.getValue();
3262 Iterator<ReachState> stateItr = hrn.getAlpha().iterator();
3263 while( stateItr.hasNext() ) {
3264 ReachState state = stateItr.next();
3266 Iterator<ReachTuple> rtItr = state.iterator();
3267 while( rtItr.hasNext() ) {
3268 ReachTuple rt = rtItr.next();
3270 if( !rt.isOutOfContext() ) {
3271 if( !id2hrn.containsKey( rt.getHrnID() ) ) {
3272 System.out.println( rt.getHrnID()+" is missing" );
3280 Iterator<RefEdge> edgeItr = hrn.iteratorToReferencers();
3281 while( edgeItr.hasNext() ) {
3282 RefEdge edge = edgeItr.next();
3284 Iterator<ReachState> stateItr = edge.getBeta().iterator();
3285 while( stateItr.hasNext() ) {
3286 ReachState state = stateItr.next();
3288 Iterator<ReachTuple> rtItr = state.iterator();
3289 while( rtItr.hasNext() ) {
3290 ReachTuple rt = rtItr.next();
3292 if( !rt.isOutOfContext() ) {
3293 if( !id2hrn.containsKey( rt.getHrnID() ) ) {
3294 System.out.println( rt.getHrnID()+" is missing" );
3307 // another useful assertion for debugging
3308 public boolean noEmptyReachSetsInGraph() {
3310 Iterator hrnItr = id2hrn.entrySet().iterator();
3311 while( hrnItr.hasNext() ) {
3312 Map.Entry me = (Map.Entry) hrnItr.next();
3313 HeapRegionNode hrn = (HeapRegionNode) me.getValue();
3315 if( !hrn.isOutOfContext() &&
3317 hrn.getAlpha().isEmpty()
3319 System.out.println( "!!! "+hrn+" has an empty ReachSet !!!" );
3323 Iterator<RefEdge> edgeItr = hrn.iteratorToReferencers();
3324 while( edgeItr.hasNext() ) {
3325 RefEdge edge = edgeItr.next();
3327 if( edge.getBeta().isEmpty() ) {
3328 System.out.println( "!!! "+edge+" has an empty ReachSet !!!" );
3338 public boolean everyReachStateWTrue() {
3340 Iterator hrnItr = id2hrn.entrySet().iterator();
3341 while( hrnItr.hasNext() ) {
3342 Map.Entry me = (Map.Entry) hrnItr.next();
3343 HeapRegionNode hrn = (HeapRegionNode) me.getValue();
3346 Iterator<ReachState> stateItr = hrn.getAlpha().iterator();
3347 while( stateItr.hasNext() ) {
3348 ReachState state = stateItr.next();
3350 if( !state.getPreds().equals( predsTrue ) ) {
3356 Iterator<RefEdge> edgeItr = hrn.iteratorToReferencers();
3357 while( edgeItr.hasNext() ) {
3358 RefEdge edge = edgeItr.next();
3360 Iterator<ReachState> stateItr = edge.getBeta().iterator();
3361 while( stateItr.hasNext() ) {
3362 ReachState state = stateItr.next();
3364 if( !state.getPreds().equals( predsTrue ) ) {
3377 ////////////////////////////////////////////////////
3378 // in merge() and equals() methods the suffix A
3379 // represents the passed in graph and the suffix
3380 // B refers to the graph in this object
3381 // Merging means to take the incoming graph A and
3382 // merge it into B, so after the operation graph B
3383 // is the final result.
3384 ////////////////////////////////////////////////////
3385 protected void merge( ReachGraph rg ) {
3392 mergeRefEdges ( rg );
3393 mergeAllocSites( rg );
3396 protected void mergeNodes( ReachGraph rg ) {
3398 // start with heap region nodes
3399 Set sA = rg.id2hrn.entrySet();
3400 Iterator iA = sA.iterator();
3401 while( iA.hasNext() ) {
3402 Map.Entry meA = (Map.Entry) iA.next();
3403 Integer idA = (Integer) meA.getKey();
3404 HeapRegionNode hrnA = (HeapRegionNode) meA.getValue();
3406 // if this graph doesn't have a node the
3407 // incoming graph has, allocate it
3408 if( !id2hrn.containsKey( idA ) ) {
3409 HeapRegionNode hrnB = hrnA.copy();
3410 id2hrn.put( idA, hrnB );
3413 // otherwise this is a node present in both graphs
3414 // so make the new reachability set a union of the
3415 // nodes' reachability sets
3416 HeapRegionNode hrnB = id2hrn.get( idA );
3417 hrnB.setAlpha( Canonical.unionORpreds( hrnB.getAlpha(),
3422 hrnB.setPreds( Canonical.join( hrnB.getPreds(),
3429 // now add any variable nodes that are in graph B but
3431 sA = rg.td2vn.entrySet();
3433 while( iA.hasNext() ) {
3434 Map.Entry meA = (Map.Entry) iA.next();
3435 TempDescriptor tdA = (TempDescriptor) meA.getKey();
3436 VariableNode lnA = (VariableNode) meA.getValue();
3438 // if the variable doesn't exist in B, allocate and add it
3439 VariableNode lnB = getVariableNodeFromTemp( tdA );
3443 protected void mergeRefEdges( ReachGraph rg ) {
3445 // between heap regions
3446 Set sA = rg.id2hrn.entrySet();
3447 Iterator iA = sA.iterator();
3448 while( iA.hasNext() ) {
3449 Map.Entry meA = (Map.Entry) iA.next();
3450 Integer idA = (Integer) meA.getKey();
3451 HeapRegionNode hrnA = (HeapRegionNode) meA.getValue();
3453 Iterator<RefEdge> heapRegionsItrA = hrnA.iteratorToReferencees();
3454 while( heapRegionsItrA.hasNext() ) {
3455 RefEdge edgeA = heapRegionsItrA.next();
3456 HeapRegionNode hrnChildA = edgeA.getDst();
3457 Integer idChildA = hrnChildA.getID();
3459 // at this point we know an edge in graph A exists
3460 // idA -> idChildA, does this exist in B?
3461 assert id2hrn.containsKey( idA );
3462 HeapRegionNode hrnB = id2hrn.get( idA );
3463 RefEdge edgeToMerge = null;
3465 Iterator<RefEdge> heapRegionsItrB = hrnB.iteratorToReferencees();
3466 while( heapRegionsItrB.hasNext() &&
3467 edgeToMerge == null ) {
3469 RefEdge edgeB = heapRegionsItrB.next();
3470 HeapRegionNode hrnChildB = edgeB.getDst();
3471 Integer idChildB = hrnChildB.getID();
3473 // don't use the RefEdge.equals() here because
3474 // we're talking about existence between graphs,
3475 // not intragraph equal
3476 if( idChildB.equals( idChildA ) &&
3477 edgeB.typeAndFieldEquals( edgeA ) ) {
3479 edgeToMerge = edgeB;
3483 // if the edge from A was not found in B,
3485 if( edgeToMerge == null ) {
3486 assert id2hrn.containsKey( idChildA );
3487 HeapRegionNode hrnChildB = id2hrn.get( idChildA );
3488 edgeToMerge = edgeA.copy();
3489 edgeToMerge.setSrc( hrnB );
3490 edgeToMerge.setDst( hrnChildB );
3491 addRefEdge( hrnB, hrnChildB, edgeToMerge );
3493 // otherwise, the edge already existed in both graphs
3494 // so merge their reachability sets
3496 // just replace this beta set with the union
3497 assert edgeToMerge != null;
3498 edgeToMerge.setBeta(
3499 Canonical.unionORpreds( edgeToMerge.getBeta(),
3503 edgeToMerge.setPreds(
3504 Canonical.join( edgeToMerge.getPreds(),
3512 // and then again from variable nodes
3513 sA = rg.td2vn.entrySet();
3515 while( iA.hasNext() ) {
3516 Map.Entry meA = (Map.Entry) iA.next();
3517 TempDescriptor tdA = (TempDescriptor) meA.getKey();
3518 VariableNode vnA = (VariableNode) meA.getValue();
3520 Iterator<RefEdge> heapRegionsItrA = vnA.iteratorToReferencees();
3521 while( heapRegionsItrA.hasNext() ) {
3522 RefEdge edgeA = heapRegionsItrA.next();
3523 HeapRegionNode hrnChildA = edgeA.getDst();
3524 Integer idChildA = hrnChildA.getID();
3526 // at this point we know an edge in graph A exists
3527 // tdA -> idChildA, does this exist in B?
3528 assert td2vn.containsKey( tdA );
3529 VariableNode vnB = td2vn.get( tdA );
3530 RefEdge edgeToMerge = null;
3532 Iterator<RefEdge> heapRegionsItrB = vnB.iteratorToReferencees();
3533 while( heapRegionsItrB.hasNext() &&
3534 edgeToMerge == null ) {
3536 RefEdge edgeB = heapRegionsItrB.next();
3537 HeapRegionNode hrnChildB = edgeB.getDst();
3538 Integer idChildB = hrnChildB.getID();
3540 // don't use the RefEdge.equals() here because
3541 // we're talking about existence between graphs
3542 if( idChildB.equals( idChildA ) &&
3543 edgeB.typeAndFieldEquals( edgeA ) ) {
3545 edgeToMerge = edgeB;
3549 // if the edge from A was not found in B,
3551 if( edgeToMerge == null ) {
3552 assert id2hrn.containsKey( idChildA );
3553 HeapRegionNode hrnChildB = id2hrn.get( idChildA );
3554 edgeToMerge = edgeA.copy();
3555 edgeToMerge.setSrc( vnB );
3556 edgeToMerge.setDst( hrnChildB );
3557 addRefEdge( vnB, hrnChildB, edgeToMerge );
3559 // otherwise, the edge already existed in both graphs
3560 // so merge their reachability sets
3562 // just replace this beta set with the union
3563 edgeToMerge.setBeta( Canonical.unionORpreds( edgeToMerge.getBeta(),
3567 edgeToMerge.setPreds( Canonical.join( edgeToMerge.getPreds(),
3576 protected void mergeAllocSites( ReachGraph rg ) {
3577 allocSites.addAll( rg.allocSites );
3582 static boolean dbgEquals = false;
3585 // it is necessary in the equals() member functions
3586 // to "check both ways" when comparing the data
3587 // structures of two graphs. For instance, if all
3588 // edges between heap region nodes in graph A are
3589 // present and equal in graph B it is not sufficient
3590 // to say the graphs are equal. Consider that there
3591 // may be edges in graph B that are not in graph A.
3592 // the only way to know that all edges in both graphs
3593 // are equally present is to iterate over both data
3594 // structures and compare against the other graph.
3595 public boolean equals( ReachGraph rg ) {
3599 System.out.println( "rg is null" );
3604 if( !areHeapRegionNodesEqual( rg ) ) {
3606 System.out.println( "hrn not equal" );
3611 if( !areVariableNodesEqual( rg ) ) {
3613 System.out.println( "vars not equal" );
3618 if( !areRefEdgesEqual( rg ) ) {
3620 System.out.println( "edges not equal" );
3625 // if everything is equal up to this point,
3626 // assert that allocSites is also equal--
3627 // this data is redundant but kept for efficiency
3628 assert allocSites.equals( rg.allocSites );
3634 protected boolean areHeapRegionNodesEqual( ReachGraph rg ) {
3636 if( !areallHRNinAalsoinBandequal( this, rg ) ) {
3640 if( !areallHRNinAalsoinBandequal( rg, this ) ) {
3647 static protected boolean areallHRNinAalsoinBandequal( ReachGraph rgA,
3649 Set sA = rgA.id2hrn.entrySet();
3650 Iterator iA = sA.iterator();
3651 while( iA.hasNext() ) {
3652 Map.Entry meA = (Map.Entry) iA.next();
3653 Integer idA = (Integer) meA.getKey();
3654 HeapRegionNode hrnA = (HeapRegionNode) meA.getValue();
3656 if( !rgB.id2hrn.containsKey( idA ) ) {
3660 HeapRegionNode hrnB = rgB.id2hrn.get( idA );
3661 if( !hrnA.equalsIncludingAlphaAndPreds( hrnB ) ) {
3669 protected boolean areVariableNodesEqual( ReachGraph rg ) {
3671 if( !areallVNinAalsoinBandequal( this, rg ) ) {
3675 if( !areallVNinAalsoinBandequal( rg, this ) ) {
3682 static protected boolean areallVNinAalsoinBandequal( ReachGraph rgA,
3684 Set sA = rgA.td2vn.entrySet();
3685 Iterator iA = sA.iterator();
3686 while( iA.hasNext() ) {
3687 Map.Entry meA = (Map.Entry) iA.next();
3688 TempDescriptor tdA = (TempDescriptor) meA.getKey();
3690 if( !rgB.td2vn.containsKey( tdA ) ) {
3699 protected boolean areRefEdgesEqual( ReachGraph rg ) {
3700 if( !areallREinAandBequal( this, rg ) ) {
3704 if( !areallREinAandBequal( rg, this ) ) {
3711 static protected boolean areallREinAandBequal( ReachGraph rgA,
3714 // check all the heap region->heap region edges
3715 Set sA = rgA.id2hrn.entrySet();
3716 Iterator iA = sA.iterator();
3717 while( iA.hasNext() ) {
3718 Map.Entry meA = (Map.Entry) iA.next();
3719 Integer idA = (Integer) meA.getKey();
3720 HeapRegionNode hrnA = (HeapRegionNode) meA.getValue();
3722 // we should have already checked that the same
3723 // heap regions exist in both graphs
3724 assert rgB.id2hrn.containsKey( idA );
3726 if( !areallREfromAequaltoB( rgA, hrnA, rgB ) ) {
3730 // then check every edge in B for presence in A, starting
3731 // from the same parent HeapRegionNode
3732 HeapRegionNode hrnB = rgB.id2hrn.get( idA );
3734 if( !areallREfromAequaltoB( rgB, hrnB, rgA ) ) {
3739 // then check all the variable->heap region edges
3740 sA = rgA.td2vn.entrySet();
3742 while( iA.hasNext() ) {
3743 Map.Entry meA = (Map.Entry) iA.next();
3744 TempDescriptor tdA = (TempDescriptor) meA.getKey();
3745 VariableNode vnA = (VariableNode) meA.getValue();
3747 // we should have already checked that the same
3748 // label nodes exist in both graphs
3749 assert rgB.td2vn.containsKey( tdA );
3751 if( !areallREfromAequaltoB( rgA, vnA, rgB ) ) {
3755 // then check every edge in B for presence in A, starting
3756 // from the same parent VariableNode
3757 VariableNode vnB = rgB.td2vn.get( tdA );
3759 if( !areallREfromAequaltoB( rgB, vnB, rgA ) ) {
3768 static protected boolean areallREfromAequaltoB( ReachGraph rgA,
3772 Iterator<RefEdge> itrA = rnA.iteratorToReferencees();
3773 while( itrA.hasNext() ) {
3774 RefEdge edgeA = itrA.next();
3775 HeapRegionNode hrnChildA = edgeA.getDst();
3776 Integer idChildA = hrnChildA.getID();
3778 assert rgB.id2hrn.containsKey( idChildA );
3780 // at this point we know an edge in graph A exists
3781 // rnA -> idChildA, does this exact edge exist in B?
3782 boolean edgeFound = false;
3784 RefSrcNode rnB = null;
3785 if( rnA instanceof HeapRegionNode ) {
3786 HeapRegionNode hrnA = (HeapRegionNode) rnA;
3787 rnB = rgB.id2hrn.get( hrnA.getID() );
3789 VariableNode vnA = (VariableNode) rnA;
3790 rnB = rgB.td2vn.get( vnA.getTempDescriptor() );
3793 Iterator<RefEdge> itrB = rnB.iteratorToReferencees();
3794 while( itrB.hasNext() ) {
3795 RefEdge edgeB = itrB.next();
3796 HeapRegionNode hrnChildB = edgeB.getDst();
3797 Integer idChildB = hrnChildB.getID();
3799 if( idChildA.equals( idChildB ) &&
3800 edgeA.typeAndFieldEquals( edgeB ) ) {
3802 // there is an edge in the right place with the right field,
3803 // but do they have the same attributes?
3804 if( edgeA.getBeta().equals( edgeB.getBeta() ) &&
3805 edgeA.equalsPreds( edgeB )
3821 // can be used to assert monotonicity
3822 static public boolean isNoSmallerThan( ReachGraph rgA,
3825 //System.out.println( "*** Asking if A is no smaller than B ***" );
3828 Iterator iA = rgA.id2hrn.entrySet().iterator();
3829 while( iA.hasNext() ) {
3830 Map.Entry meA = (Map.Entry) iA.next();
3831 Integer idA = (Integer) meA.getKey();
3832 HeapRegionNode hrnA = (HeapRegionNode) meA.getValue();
3834 if( !rgB.id2hrn.containsKey( idA ) ) {
3835 System.out.println( " regions smaller" );
3839 //HeapRegionNode hrnB = rgB.id2hrn.get( idA );
3840 /* NOT EQUALS, NO SMALLER THAN!
3841 if( !hrnA.equalsIncludingAlphaAndPreds( hrnB ) ) {
3842 System.out.println( " regions smaller" );
3848 // this works just fine, no smaller than
3849 if( !areallVNinAalsoinBandequal( rgA, rgB ) ) {
3850 System.out.println( " vars smaller:" );
3851 System.out.println( " A:"+rgA.td2vn.keySet() );
3852 System.out.println( " B:"+rgB.td2vn.keySet() );
3857 iA = rgA.id2hrn.entrySet().iterator();
3858 while( iA.hasNext() ) {
3859 Map.Entry meA = (Map.Entry) iA.next();
3860 Integer idA = (Integer) meA.getKey();
3861 HeapRegionNode hrnA = (HeapRegionNode) meA.getValue();
3863 Iterator<RefEdge> reItr = hrnA.iteratorToReferencers();
3864 while( reItr.hasNext() ) {
3865 RefEdge edgeA = reItr.next();
3866 RefSrcNode rsnA = edgeA.getSrc();
3868 // we already checked that nodes were present
3869 HeapRegionNode hrnB = rgB.id2hrn.get( hrnA.getID() );
3870 assert hrnB != null;
3873 if( rsnA instanceof VariableNode ) {
3874 VariableNode vnA = (VariableNode) rsnA;
3875 rsnB = rgB.td2vn.get( vnA.getTempDescriptor() );
3878 HeapRegionNode hrnSrcA = (HeapRegionNode) rsnA;
3879 rsnB = rgB.id2hrn.get( hrnSrcA.getID() );
3881 assert rsnB != null;
3883 RefEdge edgeB = rsnB.getReferenceTo( hrnB,
3887 if( edgeB == null ) {
3888 System.out.println( " edges smaller:" );
3892 // REMEMBER, IS NO SMALLER THAN
3894 System.out.println( " edges smaller" );
3910 // this analysis no longer has the "match anything"
3911 // type which was represented by null
3912 protected TypeDescriptor mostSpecificType( TypeDescriptor td1,
3913 TypeDescriptor td2 ) {
3917 if( td1.isNull() ) {
3920 if( td2.isNull() ) {
3923 return typeUtil.mostSpecific( td1, td2 );
3926 protected TypeDescriptor mostSpecificType( TypeDescriptor td1,
3928 TypeDescriptor td3 ) {
3930 return mostSpecificType( td1,
3931 mostSpecificType( td2, td3 )
3935 protected TypeDescriptor mostSpecificType( TypeDescriptor td1,
3938 TypeDescriptor td4 ) {
3940 return mostSpecificType( mostSpecificType( td1, td2 ),
3941 mostSpecificType( td3, td4 )
3945 protected boolean isSuperiorType( TypeDescriptor possibleSuper,
3946 TypeDescriptor possibleChild ) {
3947 assert possibleSuper != null;
3948 assert possibleChild != null;
3950 if( possibleSuper.isNull() ||
3951 possibleChild.isNull() ) {
3955 return typeUtil.isSuperorType( possibleSuper, possibleChild );
3959 protected boolean hasMatchingField( HeapRegionNode src,
3962 TypeDescriptor tdSrc = src.getType();
3963 assert tdSrc != null;
3965 if( tdSrc.isArray() ) {
3966 TypeDescriptor td = edge.getType();
3969 TypeDescriptor tdSrcDeref = tdSrc.dereference();
3970 assert tdSrcDeref != null;
3972 if( !typeUtil.isSuperorType( tdSrcDeref, td ) ) {
3976 return edge.getField().equals( DisjointAnalysis.arrayElementFieldName );
3979 // if it's not a class, it doesn't have any fields to match
3980 if( !tdSrc.isClass() ) {
3984 ClassDescriptor cd = tdSrc.getClassDesc();
3985 while( cd != null ) {
3986 Iterator fieldItr = cd.getFields();
3988 while( fieldItr.hasNext() ) {
3989 FieldDescriptor fd = (FieldDescriptor) fieldItr.next();
3991 if( fd.getType().equals( edge.getType() ) &&
3992 fd.getSymbol().equals( edge.getField() ) ) {
3997 cd = cd.getSuperDesc();
4000 // otherwise it is a class with fields
4001 // but we didn't find a match
4005 protected boolean hasMatchingType( RefEdge edge,
4006 HeapRegionNode dst ) {
4008 // if the region has no type, matches everything
4009 TypeDescriptor tdDst = dst.getType();
4010 assert tdDst != null;
4012 // if the type is not a class or an array, don't
4013 // match because primitives are copied, no aliases
4014 ClassDescriptor cdDst = tdDst.getClassDesc();
4015 if( cdDst == null && !tdDst.isArray() ) {
4019 // if the edge type is null, it matches everything
4020 TypeDescriptor tdEdge = edge.getType();
4021 assert tdEdge != null;
4023 return typeUtil.isSuperorType( tdEdge, tdDst );
4028 // the default signature for quick-and-dirty debugging
4029 public void writeGraph( String graphName ) {
4030 writeGraph( graphName,
4031 true, // write labels
4032 true, // label select
4033 true, // prune garbage
4034 true, // hide subset reachability
4035 true, // hide edge taints
4036 null // in-context boundary
4040 public void writeGraph( String graphName,
4041 boolean writeLabels,
4042 boolean labelSelect,
4043 boolean pruneGarbage,
4044 boolean hideSubsetReachability,
4045 boolean hideEdgeTaints
4047 writeGraph( graphName,
4051 hideSubsetReachability,
4056 public void writeGraph( String graphName,
4057 boolean writeLabels,
4058 boolean labelSelect,
4059 boolean pruneGarbage,
4060 boolean hideSubsetReachability,
4061 boolean hideEdgeTaints,
4062 Set<Integer> callerNodeIDsCopiedToCallee
4066 // remove all non-word characters from the graph name so
4067 // the filename and identifier in dot don't cause errors
4068 graphName = graphName.replaceAll( "[\\W]", "" );
4071 new BufferedWriter( new FileWriter( graphName+".dot" ) );
4073 bw.write( "digraph "+graphName+" {\n" );
4076 // this is an optional step to form the callee-reachable
4077 // "cut-out" into a DOT cluster for visualization
4078 if( callerNodeIDsCopiedToCallee != null ) {
4080 bw.write( " subgraph cluster0 {\n" );
4081 bw.write( " color=blue;\n" );
4083 Iterator i = id2hrn.entrySet().iterator();
4084 while( i.hasNext() ) {
4085 Map.Entry me = (Map.Entry) i.next();
4086 HeapRegionNode hrn = (HeapRegionNode) me.getValue();
4088 if( callerNodeIDsCopiedToCallee.contains( hrn.getID() ) ) {
4089 bw.write( " "+hrn.toString()+
4090 hrn.toStringDOT( hideSubsetReachability )+
4100 Set<HeapRegionNode> visited = new HashSet<HeapRegionNode>();
4102 // then visit every heap region node
4103 Iterator i = id2hrn.entrySet().iterator();
4104 while( i.hasNext() ) {
4105 Map.Entry me = (Map.Entry) i.next();
4106 HeapRegionNode hrn = (HeapRegionNode) me.getValue();
4108 // only visit nodes worth writing out--for instance
4109 // not every node at an allocation is referenced
4110 // (think of it as garbage-collected), etc.
4111 if( !pruneGarbage ||
4112 hrn.isOutOfContext()
4115 if( !visited.contains( hrn ) ) {
4116 traverseHeapRegionNodes( hrn,
4120 hideSubsetReachability,
4122 callerNodeIDsCopiedToCallee );
4127 bw.write( " graphTitle[label=\""+graphName+"\",shape=box];\n" );
4130 // then visit every label node, useful for debugging
4132 i = td2vn.entrySet().iterator();
4133 while( i.hasNext() ) {
4134 Map.Entry me = (Map.Entry) i.next();
4135 VariableNode vn = (VariableNode) me.getValue();
4138 String labelStr = vn.getTempDescriptorString();
4139 if( labelStr.startsWith( "___temp" ) ||
4140 labelStr.startsWith( "___dst" ) ||
4141 labelStr.startsWith( "___srctmp" ) ||
4142 labelStr.startsWith( "___neverused" )
4148 Iterator<RefEdge> heapRegionsItr = vn.iteratorToReferencees();
4149 while( heapRegionsItr.hasNext() ) {
4150 RefEdge edge = heapRegionsItr.next();
4151 HeapRegionNode hrn = edge.getDst();
4153 if( !visited.contains( hrn ) ) {
4154 traverseHeapRegionNodes( hrn,
4158 hideSubsetReachability,
4160 callerNodeIDsCopiedToCallee );
4163 bw.write( " "+vn.toString()+
4164 " -> "+hrn.toString()+
4165 edge.toStringDOT( hideSubsetReachability, "" )+
4174 } catch( IOException e ) {
4175 throw new Error( "Error writing out DOT graph "+graphName );
4179 protected void traverseHeapRegionNodes( HeapRegionNode hrn,
4182 Set<HeapRegionNode> visited,
4183 boolean hideSubsetReachability,
4184 boolean hideEdgeTaints,
4185 Set<Integer> callerNodeIDsCopiedToCallee
4186 ) throws java.io.IOException {
4188 if( visited.contains( hrn ) ) {
4193 // if we're drawing the callee-view subgraph, only
4194 // write out the node info if it hasn't already been
4196 if( callerNodeIDsCopiedToCallee == null ||
4197 !callerNodeIDsCopiedToCallee.contains( hrn.getID() )
4199 bw.write( " "+hrn.toString()+
4200 hrn.toStringDOT( hideSubsetReachability )+
4204 Iterator<RefEdge> childRegionsItr = hrn.iteratorToReferencees();
4205 while( childRegionsItr.hasNext() ) {
4206 RefEdge edge = childRegionsItr.next();
4207 HeapRegionNode hrnChild = edge.getDst();
4209 if( callerNodeIDsCopiedToCallee != null &&
4210 (edge.getSrc() instanceof HeapRegionNode) ) {
4211 HeapRegionNode hrnSrc = (HeapRegionNode) edge.getSrc();
4212 if( callerNodeIDsCopiedToCallee.contains( hrnSrc.getID() ) &&
4213 callerNodeIDsCopiedToCallee.contains( edge.getDst().getID() )
4215 bw.write( " "+hrn.toString()+
4216 " -> "+hrnChild.toString()+
4217 edge.toStringDOT( hideSubsetReachability, ",color=blue" )+
4219 } else if( !callerNodeIDsCopiedToCallee.contains( hrnSrc.getID() ) &&
4220 callerNodeIDsCopiedToCallee.contains( edge.getDst().getID() )
4222 bw.write( " "+hrn.toString()+
4223 " -> "+hrnChild.toString()+
4224 edge.toStringDOT( hideSubsetReachability, ",color=blue,style=dashed" )+
4227 bw.write( " "+hrn.toString()+
4228 " -> "+hrnChild.toString()+
4229 edge.toStringDOT( hideSubsetReachability, "" )+
4233 bw.write( " "+hrn.toString()+
4234 " -> "+hrnChild.toString()+
4235 edge.toStringDOT( hideSubsetReachability, "" )+
4239 traverseHeapRegionNodes( hrnChild,
4243 hideSubsetReachability,
4245 callerNodeIDsCopiedToCallee );
4253 public Set<HeapRegionNode> findCommonReachableNodes( ReachSet proofOfSharing ) {
4255 Set<HeapRegionNode> exhibitProofState =
4256 new HashSet<HeapRegionNode>();
4258 Iterator hrnItr = id2hrn.entrySet().iterator();
4259 while( hrnItr.hasNext() ) {
4260 Map.Entry me = (Map.Entry) hrnItr.next();
4261 HeapRegionNode hrn = (HeapRegionNode) me.getValue();
4263 ReachSet intersection =
4264 Canonical.intersection( proofOfSharing,
4267 if( !intersection.isEmpty() ) {
4268 assert !hrn.isOutOfContext();
4269 exhibitProofState.add( hrn );
4273 return exhibitProofState;
4277 public Set<HeapRegionNode> mayReachSharedObjects(HeapRegionNode hrn1,
4278 HeapRegionNode hrn2) {
4279 assert hrn1 != null;
4280 assert hrn2 != null;
4282 assert !hrn1.isOutOfContext();
4283 assert !hrn2.isOutOfContext();
4285 assert belongsToThis( hrn1 );
4286 assert belongsToThis( hrn2 );
4288 assert !hrn1.getID().equals( hrn2.getID() );
4291 // then get the various tokens for these heap regions
4293 ReachTuple.factory( hrn1.getID(),
4294 !hrn1.isSingleObject(), // multi?
4295 ReachTuple.ARITY_ONE,
4298 ReachTuple h1star = null;
4299 if( !hrn1.isSingleObject() ) {
4301 ReachTuple.factory( hrn1.getID(),
4302 !hrn1.isSingleObject(),
4303 ReachTuple.ARITY_ZEROORMORE,
4308 ReachTuple.factory( hrn2.getID(),
4309 !hrn2.isSingleObject(),
4310 ReachTuple.ARITY_ONE,
4313 ReachTuple h2star = null;
4314 if( !hrn2.isSingleObject() ) {
4316 ReachTuple.factory( hrn2.getID(),
4317 !hrn2.isSingleObject(),
4318 ReachTuple.ARITY_ZEROORMORE,
4322 // then get the merged beta of all out-going edges from these heap
4325 ReachSet beta1 = ReachSet.factory();
4326 Iterator<RefEdge> itrEdge = hrn1.iteratorToReferencees();
4327 while (itrEdge.hasNext()) {
4328 RefEdge edge = itrEdge.next();
4329 beta1 = Canonical.unionORpreds(beta1, edge.getBeta());
4332 ReachSet beta2 = ReachSet.factory();
4333 itrEdge = hrn2.iteratorToReferencees();
4334 while (itrEdge.hasNext()) {
4335 RefEdge edge = itrEdge.next();
4336 beta2 = Canonical.unionORpreds(beta2, edge.getBeta());
4339 ReachSet proofOfSharing = ReachSet.factory();
4342 Canonical.unionORpreds( proofOfSharing,
4343 beta1.getStatesWithBoth( h1, h2 )
4346 Canonical.unionORpreds( proofOfSharing,
4347 beta2.getStatesWithBoth( h1, h2 )
4350 if( !hrn1.isSingleObject() ) {
4352 Canonical.unionORpreds( proofOfSharing,
4353 beta1.getStatesWithBoth( h1star, h2 )
4356 Canonical.unionORpreds( proofOfSharing,
4357 beta2.getStatesWithBoth( h1star, h2 )
4361 if( !hrn2.isSingleObject() ) {
4363 Canonical.unionORpreds( proofOfSharing,
4364 beta1.getStatesWithBoth( h1, h2star )
4367 Canonical.unionORpreds( proofOfSharing,
4368 beta2.getStatesWithBoth( h1, h2star )
4372 if( !hrn1.isSingleObject() &&
4373 !hrn2.isSingleObject()
4376 Canonical.unionORpreds( proofOfSharing,
4377 beta1.getStatesWithBoth( h1star, h2star )
4380 Canonical.unionORpreds( proofOfSharing,
4381 beta2.getStatesWithBoth( h1star, h2star )
4385 Set<HeapRegionNode> common = new HashSet<HeapRegionNode>();
4386 if( !proofOfSharing.isEmpty() ) {
4387 common = findCommonReachableNodes( proofOfSharing );
4388 if( !DISABLE_STRONG_UPDATES &&
4389 !DISABLE_GLOBAL_SWEEP
4391 assert !common.isEmpty();
4398 // this version of the above method checks whether there is sharing
4399 // among the objects in a summary node
4400 public Set<HeapRegionNode> mayReachSharedObjects(HeapRegionNode hrn) {
4402 assert hrn.isNewSummary();
4403 assert !hrn.isOutOfContext();
4404 assert belongsToThis( hrn );
4407 ReachTuple.factory( hrn.getID(),
4409 ReachTuple.ARITY_ZEROORMORE,
4412 // then get the merged beta of all out-going edges from
4415 ReachSet beta = ReachSet.factory();
4416 Iterator<RefEdge> itrEdge = hrn.iteratorToReferencees();
4417 while (itrEdge.hasNext()) {
4418 RefEdge edge = itrEdge.next();
4419 beta = Canonical.unionORpreds(beta, edge.getBeta());
4422 ReachSet proofOfSharing = ReachSet.factory();
4425 Canonical.unionORpreds( proofOfSharing,
4426 beta.getStatesWithBoth( hstar, hstar )
4429 Set<HeapRegionNode> common = new HashSet<HeapRegionNode>();
4430 if( !proofOfSharing.isEmpty() ) {
4431 common = findCommonReachableNodes( proofOfSharing );
4432 if( !DISABLE_STRONG_UPDATES &&
4433 !DISABLE_GLOBAL_SWEEP
4435 assert !common.isEmpty();
4443 public Set<HeapRegionNode> mayReachSharedObjects(FlatMethod fm,
4444 Integer paramIndex1,
4445 Integer paramIndex2) {
4447 // get parameter's heap regions
4448 TempDescriptor paramTemp1 = fm.getParameter(paramIndex1.intValue());
4449 assert this.hasVariable( paramTemp1 );
4450 VariableNode paramVar1 = getVariableNodeFromTemp(paramTemp1);
4453 if( !(paramVar1.getNumReferencees() == 1) ) {
4454 System.out.println( "\n fm="+fm+"\n param="+paramTemp1 );
4455 writeGraph( "whatup" );
4459 assert paramVar1.getNumReferencees() == 1;
4460 RefEdge paramEdge1 = paramVar1.iteratorToReferencees().next();
4461 HeapRegionNode hrnParam1 = paramEdge1.getDst();
4463 TempDescriptor paramTemp2 = fm.getParameter(paramIndex2.intValue());
4464 assert this.hasVariable( paramTemp2 );
4465 VariableNode paramVar2 = getVariableNodeFromTemp(paramTemp2);
4467 if( !(paramVar2.getNumReferencees() == 1) ) {
4468 System.out.println( "\n fm="+fm+"\n param="+paramTemp2 );
4469 writeGraph( "whatup" );
4472 assert paramVar2.getNumReferencees() == 1;
4473 RefEdge paramEdge2 = paramVar2.iteratorToReferencees().next();
4474 HeapRegionNode hrnParam2 = paramEdge2.getDst();
4476 Set<HeapRegionNode> common = new HashSet<HeapRegionNode>();
4477 common.addAll(mayReachSharedObjects(hrnParam1, hrnParam2));
4482 public Set<HeapRegionNode> mayReachSharedObjects(FlatMethod fm,
4486 // get parameter's heap regions
4487 TempDescriptor paramTemp = fm.getParameter(paramIndex.intValue());
4488 assert this.hasVariable( paramTemp );
4489 VariableNode paramVar = getVariableNodeFromTemp(paramTemp);
4490 assert paramVar.getNumReferencees() == 1;
4491 RefEdge paramEdge = paramVar.iteratorToReferencees().next();
4492 HeapRegionNode hrnParam = paramEdge.getDst();
4495 HeapRegionNode hrnSummary=null;
4496 if(id2hrn.containsKey(as.getSummary())){
4497 // if summary node doesn't exist, ignore this case
4498 hrnSummary = id2hrn.get(as.getSummary());
4499 assert hrnSummary != null;
4502 Set<HeapRegionNode> common = new HashSet<HeapRegionNode>();
4503 if(hrnSummary!=null){
4504 common.addAll( mayReachSharedObjects(hrnParam, hrnSummary) );
4507 // check for other nodes
4508 for (int i = 0; i < as.getAllocationDepth(); ++i) {
4510 assert id2hrn.containsKey(as.getIthOldest(i));
4511 HeapRegionNode hrnIthOldest = id2hrn.get(as.getIthOldest(i));
4512 assert hrnIthOldest != null;
4514 common.addAll(mayReachSharedObjects(hrnParam, hrnIthOldest));
4521 public Set<HeapRegionNode> mayReachSharedObjects(AllocSite as1,
4524 // get summary node 1's alpha
4525 Integer idSum1 = as1.getSummary();
4526 HeapRegionNode hrnSum1=null;
4527 if(id2hrn.containsKey(idSum1)){
4528 hrnSum1 = id2hrn.get(idSum1);
4531 // get summary node 2's alpha
4532 Integer idSum2 = as2.getSummary();
4533 HeapRegionNode hrnSum2=null;
4534 if(id2hrn.containsKey(idSum2)){
4535 hrnSum2 = id2hrn.get(idSum2);
4538 Set<HeapRegionNode> common = new HashSet<HeapRegionNode>();
4539 if(hrnSum1!=null && hrnSum2!=null && hrnSum1!=hrnSum2){
4540 common.addAll(mayReachSharedObjects(hrnSum1, hrnSum2));
4544 // ask if objects from this summary share among each other
4545 common.addAll(mayReachSharedObjects(hrnSum1));
4548 // check sum2 against alloc1 nodes
4550 for (int i = 0; i < as1.getAllocationDepth(); ++i) {
4551 Integer idI1 = as1.getIthOldest(i);
4552 assert id2hrn.containsKey(idI1);
4553 HeapRegionNode hrnI1 = id2hrn.get(idI1);
4554 assert hrnI1 != null;
4555 common.addAll(mayReachSharedObjects(hrnI1, hrnSum2));
4558 // also ask if objects from this summary share among each other
4559 common.addAll(mayReachSharedObjects(hrnSum2));
4562 // check sum1 against alloc2 nodes
4563 for (int i = 0; i < as2.getAllocationDepth(); ++i) {
4564 Integer idI2 = as2.getIthOldest(i);
4565 assert id2hrn.containsKey(idI2);
4566 HeapRegionNode hrnI2 = id2hrn.get(idI2);
4567 assert hrnI2 != null;
4570 common.addAll(mayReachSharedObjects(hrnSum1, hrnI2));
4573 // while we're at it, do an inner loop for alloc2 vs alloc1 nodes
4574 for (int j = 0; j < as1.getAllocationDepth(); ++j) {
4575 Integer idI1 = as1.getIthOldest(j);
4577 // if these are the same site, don't look for the same token, no
4579 // different tokens of the same site could alias together though
4580 if (idI1.equals(idI2)) {
4584 HeapRegionNode hrnI1 = id2hrn.get(idI1);
4586 common.addAll(mayReachSharedObjects(hrnI1, hrnI2));