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 = 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;
84 // the reason for this method is to have the option
85 // of creating new heap regions with specific IDs, or
86 // duplicating heap regions with specific IDs (especially
87 // in the merge() operation) or to create new heap
88 // regions with a new unique ID
89 protected HeapRegionNode
90 createNewHeapRegionNode( Integer id,
91 boolean isSingleObject,
94 boolean isOutOfContext,
103 boolean markForAnalysis = isFlagged;
105 TypeDescriptor typeToUse = null;
106 if( allocSite != null ) {
107 typeToUse = allocSite.getType();
108 allocSites.add( allocSite );
113 if( allocSite != null && allocSite.getDisjointAnalysisId() != null ) {
114 markForAnalysis = true;
118 id = DisjointAnalysis.generateUniqueHeapRegionNodeID();
121 if( inherent == null ) {
122 if( markForAnalysis ) {
126 ReachTuple.factory( id,
128 ReachTuple.ARITY_ONE,
129 false // out-of-context
134 inherent = rsetWithEmptyState;
138 if( alpha == null ) {
142 assert preds != null;
144 HeapRegionNode hrn = new HeapRegionNode( id,
155 id2hrn.put( id, hrn );
161 ////////////////////////////////////////////////
163 // Low-level referencee and referencer methods
165 // These methods provide the lowest level for
166 // creating references between reachability nodes
167 // and handling the details of maintaining both
168 // list of referencers and referencees.
170 ////////////////////////////////////////////////
171 protected void addRefEdge( RefSrcNode referencer,
172 HeapRegionNode referencee,
174 assert referencer != null;
175 assert referencee != null;
177 assert edge.getSrc() == referencer;
178 assert edge.getDst() == referencee;
179 assert belongsToThis( referencer );
180 assert belongsToThis( referencee );
182 // edges are getting added twice to graphs now, the
183 // kind that should have abstract facts merged--use
184 // this check to prevent that
185 assert referencer.getReferenceTo( referencee,
190 referencer.addReferencee( edge );
191 referencee.addReferencer( edge );
194 protected void removeRefEdge( RefEdge e ) {
195 removeRefEdge( e.getSrc(),
201 protected void removeRefEdge( RefSrcNode referencer,
202 HeapRegionNode referencee,
205 assert referencer != null;
206 assert referencee != null;
208 RefEdge edge = referencer.getReferenceTo( referencee,
212 assert edge == referencee.getReferenceFrom( referencer,
216 referencer.removeReferencee( edge );
217 referencee.removeReferencer( edge );
220 protected void clearRefEdgesFrom( RefSrcNode referencer,
223 boolean removeAll ) {
224 assert referencer != null;
226 // get a copy of the set to iterate over, otherwise
227 // we will be trying to take apart the set as we
228 // are iterating over it, which won't work
229 Iterator<RefEdge> i = referencer.iteratorToReferenceesClone();
230 while( i.hasNext() ) {
231 RefEdge edge = i.next();
234 (edge.typeEquals( type ) && edge.fieldEquals( field ))
237 HeapRegionNode referencee = edge.getDst();
239 removeRefEdge( referencer,
247 protected void clearRefEdgesTo( HeapRegionNode referencee,
250 boolean removeAll ) {
251 assert referencee != null;
253 // get a copy of the set to iterate over, otherwise
254 // we will be trying to take apart the set as we
255 // are iterating over it, which won't work
256 Iterator<RefEdge> i = referencee.iteratorToReferencersClone();
257 while( i.hasNext() ) {
258 RefEdge edge = i.next();
261 (edge.typeEquals( type ) && edge.fieldEquals( field ))
264 RefSrcNode referencer = edge.getSrc();
266 removeRefEdge( referencer,
274 protected void clearNonVarRefEdgesTo( HeapRegionNode referencee ) {
275 assert referencee != null;
277 // get a copy of the set to iterate over, otherwise
278 // we will be trying to take apart the set as we
279 // are iterating over it, which won't work
280 Iterator<RefEdge> i = referencee.iteratorToReferencersClone();
281 while( i.hasNext() ) {
282 RefEdge edge = i.next();
283 RefSrcNode referencer = edge.getSrc();
284 if( !(referencer instanceof VariableNode) ) {
285 removeRefEdge( referencer,
294 ////////////////////////////////////////////////////
296 // Assignment Operation Methods
298 // These methods are high-level operations for
299 // modeling program assignment statements using
300 // the low-level reference create/remove methods
303 ////////////////////////////////////////////////////
305 public void assignTempXEqualToTempY( TempDescriptor x,
307 assignTempXEqualToCastedTempY( x, y, null );
310 public void assignTempXEqualToCastedTempY( TempDescriptor x,
312 TypeDescriptor tdCast ) {
314 VariableNode lnX = getVariableNodeFromTemp( x );
315 VariableNode lnY = getVariableNodeFromTemp( y );
317 clearRefEdgesFrom( lnX, null, null, true );
319 // note it is possible that the types of temps in the
320 // flat node to analyze will reveal that some typed
321 // edges in the reachability graph are impossible
322 Set<RefEdge> impossibleEdges = new HashSet<RefEdge>();
324 Iterator<RefEdge> itrYhrn = lnY.iteratorToReferencees();
325 while( itrYhrn.hasNext() ) {
326 RefEdge edgeY = itrYhrn.next();
327 HeapRegionNode referencee = edgeY.getDst();
328 RefEdge edgeNew = edgeY.copy();
330 if( !isSuperiorType( x.getType(), edgeY.getType() ) ) {
331 impossibleEdges.add( edgeY );
335 edgeNew.setSrc( lnX );
337 if( tdCast == null ) {
338 edgeNew.setType( mostSpecificType( y.getType(),
344 edgeNew.setType( mostSpecificType( y.getType(),
346 referencee.getType(),
352 edgeNew.setField( null );
354 addRefEdge( lnX, referencee, edgeNew );
357 Iterator<RefEdge> itrImp = impossibleEdges.iterator();
358 while( itrImp.hasNext() ) {
359 RefEdge edgeImp = itrImp.next();
360 removeRefEdge( edgeImp );
365 public void assignTempXEqualToTempYFieldF( TempDescriptor x,
367 FieldDescriptor f ) {
368 VariableNode lnX = getVariableNodeFromTemp( x );
369 VariableNode lnY = getVariableNodeFromTemp( y );
371 clearRefEdgesFrom( lnX, null, null, true );
373 // note it is possible that the types of temps in the
374 // flat node to analyze will reveal that some typed
375 // edges in the reachability graph are impossible
376 Set<RefEdge> impossibleEdges = new HashSet<RefEdge>();
378 Iterator<RefEdge> itrYhrn = lnY.iteratorToReferencees();
379 while( itrYhrn.hasNext() ) {
380 RefEdge edgeY = itrYhrn.next();
381 HeapRegionNode hrnY = edgeY.getDst();
382 ReachSet betaY = edgeY.getBeta();
384 Iterator<RefEdge> itrHrnFhrn = hrnY.iteratorToReferencees();
385 while( itrHrnFhrn.hasNext() ) {
386 RefEdge edgeHrn = itrHrnFhrn.next();
387 HeapRegionNode hrnHrn = edgeHrn.getDst();
388 ReachSet betaHrn = edgeHrn.getBeta();
390 // prune edges that are not a matching field
391 if( edgeHrn.getType() != null &&
392 !edgeHrn.getField().equals( f.getSymbol() )
397 // check for impossible edges
398 if( !isSuperiorType( x.getType(), edgeHrn.getType() ) ) {
399 impossibleEdges.add( edgeHrn );
403 TypeDescriptor tdNewEdge =
404 mostSpecificType( edgeHrn.getType(),
408 RefEdge edgeNew = new RefEdge( lnX,
412 Canonical.intersection( betaY, betaHrn ),
416 addRefEdge( lnX, hrnHrn, edgeNew );
420 Iterator<RefEdge> itrImp = impossibleEdges.iterator();
421 while( itrImp.hasNext() ) {
422 RefEdge edgeImp = itrImp.next();
423 removeRefEdge( edgeImp );
426 // anytime you might remove edges between heap regions
427 // you must global sweep to clean up broken reachability
428 if( !impossibleEdges.isEmpty() ) {
429 if( !DISABLE_GLOBAL_SWEEP ) {
436 public void assignTempXFieldFEqualToTempY( TempDescriptor x,
440 VariableNode lnX = getVariableNodeFromTemp( x );
441 VariableNode lnY = getVariableNodeFromTemp( y );
443 HashSet<HeapRegionNode> nodesWithNewAlpha = new HashSet<HeapRegionNode>();
444 HashSet<RefEdge> edgesWithNewBeta = new HashSet<RefEdge>();
446 // note it is possible that the types of temps in the
447 // flat node to analyze will reveal that some typed
448 // edges in the reachability graph are impossible
449 Set<RefEdge> impossibleEdges = new HashSet<RefEdge>();
451 // first look for possible strong updates and remove those edges
452 boolean strongUpdate = false;
454 Iterator<RefEdge> itrXhrn = lnX.iteratorToReferencees();
455 while( itrXhrn.hasNext() ) {
456 RefEdge edgeX = itrXhrn.next();
457 HeapRegionNode hrnX = edgeX.getDst();
459 // we can do a strong update here if one of two cases holds
461 f != DisjointAnalysis.getArrayField( f.getType() ) &&
462 ( (hrnX.getNumReferencers() == 1) || // case 1
463 (hrnX.isSingleObject() && lnX.getNumReferencees() == 1) // case 2
466 if( !DISABLE_STRONG_UPDATES ) {
468 clearRefEdgesFrom( hrnX, f.getType(), f.getSymbol(), false );
473 // then do all token propagation
474 itrXhrn = lnX.iteratorToReferencees();
475 while( itrXhrn.hasNext() ) {
476 RefEdge edgeX = itrXhrn.next();
477 HeapRegionNode hrnX = edgeX.getDst();
478 ReachSet betaX = edgeX.getBeta();
479 ReachSet R = Canonical.intersection( hrnX.getAlpha(),
483 Iterator<RefEdge> itrYhrn = lnY.iteratorToReferencees();
484 while( itrYhrn.hasNext() ) {
485 RefEdge edgeY = itrYhrn.next();
486 HeapRegionNode hrnY = edgeY.getDst();
487 ReachSet O = edgeY.getBeta();
489 // check for impossible edges
490 if( !isSuperiorType( f.getType(), edgeY.getType() ) ) {
491 impossibleEdges.add( edgeY );
495 // propagate tokens over nodes starting from hrnSrc, and it will
496 // take care of propagating back up edges from any touched nodes
497 ChangeSet Cy = Canonical.unionUpArityToChangeSet( O, R );
498 propagateTokensOverNodes( hrnY, Cy, nodesWithNewAlpha, edgesWithNewBeta );
500 // then propagate back just up the edges from hrn
501 ChangeSet Cx = Canonical.unionUpArityToChangeSet( R, O );
502 HashSet<RefEdge> todoEdges = new HashSet<RefEdge>();
504 Hashtable<RefEdge, ChangeSet> edgePlannedChanges =
505 new Hashtable<RefEdge, ChangeSet>();
507 Iterator<RefEdge> referItr = hrnX.iteratorToReferencers();
508 while( referItr.hasNext() ) {
509 RefEdge edgeUpstream = referItr.next();
510 todoEdges.add( edgeUpstream );
511 edgePlannedChanges.put( edgeUpstream, Cx );
514 propagateTokensOverEdges( todoEdges,
521 // apply the updates to reachability
522 Iterator<HeapRegionNode> nodeItr = nodesWithNewAlpha.iterator();
523 while( nodeItr.hasNext() ) {
524 nodeItr.next().applyAlphaNew();
527 Iterator<RefEdge> edgeItr = edgesWithNewBeta.iterator();
528 while( edgeItr.hasNext() ) {
529 edgeItr.next().applyBetaNew();
533 // then go back through and add the new edges
534 itrXhrn = lnX.iteratorToReferencees();
535 while( itrXhrn.hasNext() ) {
536 RefEdge edgeX = itrXhrn.next();
537 HeapRegionNode hrnX = edgeX.getDst();
539 Iterator<RefEdge> itrYhrn = lnY.iteratorToReferencees();
540 while( itrYhrn.hasNext() ) {
541 RefEdge edgeY = itrYhrn.next();
542 HeapRegionNode hrnY = edgeY.getDst();
544 // skip impossible edges here, we already marked them
545 // when computing reachability propagations above
546 if( !isSuperiorType( f.getType(), edgeY.getType() ) ) {
550 // prepare the new reference edge hrnX.f -> hrnY
551 TypeDescriptor tdNewEdge =
552 mostSpecificType( y.getType(),
557 RefEdge edgeNew = new RefEdge( hrnX,
561 Canonical.pruneBy( edgeY.getBeta(),
567 // look to see if an edge with same field exists
568 // and merge with it, otherwise just add the edge
569 RefEdge edgeExisting = hrnX.getReferenceTo( hrnY,
573 if( edgeExisting != null ) {
574 edgeExisting.setBeta(
575 Canonical.unionORpreds( edgeExisting.getBeta(),
579 edgeExisting.setPreds(
580 Canonical.join( edgeExisting.getPreds(),
586 addRefEdge( hrnX, hrnY, edgeNew );
591 Iterator<RefEdge> itrImp = impossibleEdges.iterator();
592 while( itrImp.hasNext() ) {
593 RefEdge edgeImp = itrImp.next();
594 removeRefEdge( edgeImp );
597 // if there was a strong update, make sure to improve
598 // reachability with a global sweep
599 if( strongUpdate || !impossibleEdges.isEmpty() ) {
600 if( !DISABLE_GLOBAL_SWEEP ) {
607 public void assignReturnEqualToTemp( TempDescriptor x ) {
609 VariableNode lnR = getVariableNodeFromTemp( tdReturn );
610 VariableNode lnX = getVariableNodeFromTemp( x );
612 clearRefEdgesFrom( lnR, null, null, true );
614 Iterator<RefEdge> itrXhrn = lnX.iteratorToReferencees();
615 while( itrXhrn.hasNext() ) {
616 RefEdge edgeX = itrXhrn.next();
617 HeapRegionNode referencee = edgeX.getDst();
618 RefEdge edgeNew = edgeX.copy();
619 edgeNew.setSrc( lnR );
621 addRefEdge( lnR, referencee, edgeNew );
626 public void assignTempEqualToNewAlloc( TempDescriptor x,
633 // after the age operation the newest (or zero-ith oldest)
634 // node associated with the allocation site should have
635 // no references to it as if it were a newly allocated
637 Integer idNewest = as.getIthOldest( 0 );
638 HeapRegionNode hrnNewest = id2hrn.get( idNewest );
639 assert hrnNewest != null;
641 VariableNode lnX = getVariableNodeFromTemp( x );
642 clearRefEdgesFrom( lnX, null, null, true );
644 // make a new reference to allocated node
645 TypeDescriptor type = as.getType();
648 new RefEdge( lnX, // source
652 hrnNewest.getAlpha(), // beta
653 predsTrue // predicates
656 addRefEdge( lnX, hrnNewest, edgeNew );
660 // use the allocation site (unique to entire analysis) to
661 // locate the heap region nodes in this reachability graph
662 // that should be aged. The process models the allocation
663 // of new objects and collects all the oldest allocations
664 // in a summary node to allow for a finite analysis
666 // There is an additional property of this method. After
667 // running it on a particular reachability graph (many graphs
668 // may have heap regions related to the same allocation site)
669 // the heap region node objects in this reachability graph will be
670 // allocated. Therefore, after aging a graph for an allocation
671 // site, attempts to retrieve the heap region nodes using the
672 // integer id's contained in the allocation site should always
673 // return non-null heap regions.
674 public void age( AllocSite as ) {
676 // keep track of allocation sites that are represented
677 // in this graph for efficiency with other operations
678 allocSites.add( as );
680 // if there is a k-th oldest node, it merges into
682 Integer idK = as.getOldest();
683 if( id2hrn.containsKey( idK ) ) {
684 HeapRegionNode hrnK = id2hrn.get( idK );
686 // retrieve the summary node, or make it
688 HeapRegionNode hrnSummary = getSummaryNode( as, false );
690 mergeIntoSummary( hrnK, hrnSummary );
693 // move down the line of heap region nodes
694 // clobbering the ith and transferring all references
695 // to and from i-1 to node i.
696 for( int i = allocationDepth - 1; i > 0; --i ) {
698 // only do the transfer if the i-1 node exists
699 Integer idImin1th = as.getIthOldest( i - 1 );
700 if( id2hrn.containsKey( idImin1th ) ) {
701 HeapRegionNode hrnImin1 = id2hrn.get( idImin1th );
702 if( hrnImin1.isWiped() ) {
703 // there is no info on this node, just skip
707 // either retrieve or make target of transfer
708 HeapRegionNode hrnI = getIthNode( as, i, false );
710 transferOnto( hrnImin1, hrnI );
715 // as stated above, the newest node should have had its
716 // references moved over to the second oldest, so we wipe newest
717 // in preparation for being the new object to assign something to
718 HeapRegionNode hrn0 = getIthNode( as, 0, false );
719 wipeOut( hrn0, true );
721 // now tokens in reachability sets need to "age" also
722 Iterator itrAllVariableNodes = td2vn.entrySet().iterator();
723 while( itrAllVariableNodes.hasNext() ) {
724 Map.Entry me = (Map.Entry) itrAllVariableNodes.next();
725 VariableNode ln = (VariableNode) me.getValue();
727 Iterator<RefEdge> itrEdges = ln.iteratorToReferencees();
728 while( itrEdges.hasNext() ) {
729 ageTuplesFrom( as, itrEdges.next() );
733 Iterator itrAllHRNodes = id2hrn.entrySet().iterator();
734 while( itrAllHRNodes.hasNext() ) {
735 Map.Entry me = (Map.Entry) itrAllHRNodes.next();
736 HeapRegionNode hrnToAge = (HeapRegionNode) me.getValue();
738 ageTuplesFrom( as, hrnToAge );
740 Iterator<RefEdge> itrEdges = hrnToAge.iteratorToReferencees();
741 while( itrEdges.hasNext() ) {
742 ageTuplesFrom( as, itrEdges.next() );
747 // after tokens have been aged, reset newest node's reachability
748 // and a brand new node has a "true" predicate
749 hrn0.setAlpha( hrn0.getInherent() );
750 hrn0.setPreds( predsTrue );
754 // either retrieve or create the needed heap region node
755 protected HeapRegionNode getSummaryNode( AllocSite as,
760 idSummary = as.getSummaryShadow();
762 idSummary = as.getSummary();
765 HeapRegionNode hrnSummary = id2hrn.get( idSummary );
767 if( hrnSummary == null ) {
769 boolean hasFlags = false;
770 if( as.getType().isClass() ) {
771 hasFlags = as.getType().getClassDesc().hasFlags();
775 hasFlags = as.getFlag();
778 String strDesc = as.toStringForDOT()+"\\nsummary";
780 strDesc += " shadow";
784 createNewHeapRegionNode( idSummary, // id or null to generate a new one
785 false, // single object?
787 hasFlags, // flagged?
788 false, // out-of-context?
789 as.getType(), // type
790 as, // allocation site
791 null, // inherent reach
792 null, // current reach
793 predsEmpty, // predicates
794 strDesc // description
801 // either retrieve or create the needed heap region node
802 protected HeapRegionNode getIthNode( AllocSite as,
808 idIth = as.getIthOldestShadow( i );
810 idIth = as.getIthOldest( i );
813 HeapRegionNode hrnIth = id2hrn.get( idIth );
815 if( hrnIth == null ) {
817 boolean hasFlags = false;
818 if( as.getType().isClass() ) {
819 hasFlags = as.getType().getClassDesc().hasFlags();
823 hasFlags = as.getFlag();
826 String strDesc = as.toStringForDOT()+"\\n"+i+" oldest";
828 strDesc += " shadow";
831 hrnIth = createNewHeapRegionNode( idIth, // id or null to generate a new one
832 true, // single object?
834 hasFlags, // flagged?
835 false, // out-of-context?
836 as.getType(), // type
837 as, // allocation site
838 null, // inherent reach
839 null, // current reach
840 predsEmpty, // predicates
841 strDesc // description
849 protected void mergeIntoSummary( HeapRegionNode hrn,
850 HeapRegionNode hrnSummary ) {
851 assert hrnSummary.isNewSummary();
853 // assert that these nodes belong to THIS graph
854 assert belongsToThis( hrn );
855 assert belongsToThis( hrnSummary );
857 assert hrn != hrnSummary;
859 // transfer references _from_ hrn over to hrnSummary
860 Iterator<RefEdge> itrReferencee = hrn.iteratorToReferencees();
861 while( itrReferencee.hasNext() ) {
862 RefEdge edge = itrReferencee.next();
863 RefEdge edgeMerged = edge.copy();
864 edgeMerged.setSrc( hrnSummary );
866 HeapRegionNode hrnReferencee = edge.getDst();
867 RefEdge edgeSummary =
868 hrnSummary.getReferenceTo( hrnReferencee,
873 if( edgeSummary == null ) {
874 // the merge is trivial, nothing to be done
875 addRefEdge( hrnSummary, hrnReferencee, edgeMerged );
878 // otherwise an edge from the referencer to hrnSummary exists already
879 // and the edge referencer->hrn should be merged with it
881 Canonical.unionORpreds( edgeMerged.getBeta(),
882 edgeSummary.getBeta()
885 edgeSummary.setPreds(
886 Canonical.join( edgeMerged.getPreds(),
887 edgeSummary.getPreds()
893 // next transfer references _to_ hrn over to hrnSummary
894 Iterator<RefEdge> itrReferencer = hrn.iteratorToReferencers();
895 while( itrReferencer.hasNext() ) {
896 RefEdge edge = itrReferencer.next();
897 RefEdge edgeMerged = edge.copy();
898 edgeMerged.setDst( hrnSummary );
900 RefSrcNode onReferencer = edge.getSrc();
901 RefEdge edgeSummary =
902 onReferencer.getReferenceTo( hrnSummary,
907 if( edgeSummary == null ) {
908 // the merge is trivial, nothing to be done
909 addRefEdge( onReferencer, hrnSummary, edgeMerged );
912 // otherwise an edge from the referencer to alpha_S exists already
913 // and the edge referencer->alpha_K should be merged with it
915 Canonical.unionORpreds( edgeMerged.getBeta(),
916 edgeSummary.getBeta()
919 edgeSummary.setPreds(
920 Canonical.join( edgeMerged.getPreds(),
921 edgeSummary.getPreds()
927 // then merge hrn reachability into hrnSummary
929 Canonical.unionORpreds( hrnSummary.getAlpha(),
935 Canonical.join( hrnSummary.getPreds(),
940 // and afterward, this node is gone
941 wipeOut( hrn, true );
945 protected void transferOnto( HeapRegionNode hrnA,
946 HeapRegionNode hrnB ) {
948 assert belongsToThis( hrnA );
949 assert belongsToThis( hrnB );
952 // clear references in and out of node b?
953 assert hrnB.isWiped();
955 // copy each: (edge in and out of A) to B
956 Iterator<RefEdge> itrReferencee = hrnA.iteratorToReferencees();
957 while( itrReferencee.hasNext() ) {
958 RefEdge edge = itrReferencee.next();
959 HeapRegionNode hrnReferencee = edge.getDst();
960 RefEdge edgeNew = edge.copy();
961 edgeNew.setSrc( hrnB );
962 edgeNew.setDst( hrnReferencee );
964 addRefEdge( hrnB, hrnReferencee, edgeNew );
967 Iterator<RefEdge> itrReferencer = hrnA.iteratorToReferencers();
968 while( itrReferencer.hasNext() ) {
969 RefEdge edge = itrReferencer.next();
970 RefSrcNode rsnReferencer = edge.getSrc();
971 RefEdge edgeNew = edge.copy();
972 edgeNew.setSrc( rsnReferencer );
973 edgeNew.setDst( hrnB );
975 addRefEdge( rsnReferencer, hrnB, edgeNew );
978 // replace hrnB reachability and preds with hrnA's
979 hrnB.setAlpha( hrnA.getAlpha() );
980 hrnB.setPreds( hrnA.getPreds() );
982 // after transfer, wipe out source
983 wipeOut( hrnA, true );
987 // the purpose of this method is to conceptually "wipe out"
988 // a heap region from the graph--purposefully not called REMOVE
989 // because the node is still hanging around in the graph, just
990 // not mechanically connected or have any reach or predicate
991 // information on it anymore--lots of ops can use this
992 protected void wipeOut( HeapRegionNode hrn,
993 boolean wipeVariableReferences ) {
995 assert belongsToThis( hrn );
997 clearRefEdgesFrom( hrn, null, null, true );
999 if( wipeVariableReferences ) {
1000 clearRefEdgesTo( hrn, null, null, true );
1002 clearNonVarRefEdgesTo( hrn );
1005 hrn.setAlpha( rsetEmpty );
1006 hrn.setPreds( predsEmpty );
1010 protected void ageTuplesFrom( AllocSite as, RefEdge edge ) {
1012 Canonical.ageTuplesFrom( edge.getBeta(),
1018 protected void ageTuplesFrom( AllocSite as, HeapRegionNode hrn ) {
1020 Canonical.ageTuplesFrom( hrn.getAlpha(),
1028 protected void propagateTokensOverNodes( HeapRegionNode nPrime,
1030 HashSet<HeapRegionNode> nodesWithNewAlpha,
1031 HashSet<RefEdge> edgesWithNewBeta ) {
1033 HashSet<HeapRegionNode> todoNodes
1034 = new HashSet<HeapRegionNode>();
1035 todoNodes.add( nPrime );
1037 HashSet<RefEdge> todoEdges
1038 = new HashSet<RefEdge>();
1040 Hashtable<HeapRegionNode, ChangeSet> nodePlannedChanges
1041 = new Hashtable<HeapRegionNode, ChangeSet>();
1042 nodePlannedChanges.put( nPrime, c0 );
1044 Hashtable<RefEdge, ChangeSet> edgePlannedChanges
1045 = new Hashtable<RefEdge, ChangeSet>();
1047 // first propagate change sets everywhere they can go
1048 while( !todoNodes.isEmpty() ) {
1049 HeapRegionNode n = todoNodes.iterator().next();
1050 ChangeSet C = nodePlannedChanges.get( n );
1052 Iterator<RefEdge> referItr = n.iteratorToReferencers();
1053 while( referItr.hasNext() ) {
1054 RefEdge edge = referItr.next();
1055 todoEdges.add( edge );
1057 if( !edgePlannedChanges.containsKey( edge ) ) {
1058 edgePlannedChanges.put( edge,
1063 edgePlannedChanges.put( edge,
1064 Canonical.union( edgePlannedChanges.get( edge ),
1070 Iterator<RefEdge> refeeItr = n.iteratorToReferencees();
1071 while( refeeItr.hasNext() ) {
1072 RefEdge edgeF = refeeItr.next();
1073 HeapRegionNode m = edgeF.getDst();
1075 ChangeSet changesToPass = ChangeSet.factory();
1077 Iterator<ChangeTuple> itrCprime = C.iterator();
1078 while( itrCprime.hasNext() ) {
1079 ChangeTuple c = itrCprime.next();
1080 if( edgeF.getBeta().containsIgnorePreds( c.getStateToMatch() )
1083 changesToPass = Canonical.add( changesToPass, c );
1087 if( !changesToPass.isEmpty() ) {
1088 if( !nodePlannedChanges.containsKey( m ) ) {
1089 nodePlannedChanges.put( m, ChangeSet.factory() );
1092 ChangeSet currentChanges = nodePlannedChanges.get( m );
1094 if( !changesToPass.isSubset( currentChanges ) ) {
1096 nodePlannedChanges.put( m,
1097 Canonical.union( currentChanges,
1106 todoNodes.remove( n );
1109 // then apply all of the changes for each node at once
1110 Iterator itrMap = nodePlannedChanges.entrySet().iterator();
1111 while( itrMap.hasNext() ) {
1112 Map.Entry me = (Map.Entry) itrMap.next();
1113 HeapRegionNode n = (HeapRegionNode) me.getKey();
1114 ChangeSet C = (ChangeSet) me.getValue();
1116 // this propagation step is with respect to one change,
1117 // so we capture the full change from the old alpha:
1118 ReachSet localDelta = Canonical.applyChangeSet( n.getAlpha(),
1122 // but this propagation may be only one of many concurrent
1123 // possible changes, so keep a running union with the node's
1124 // partially updated new alpha set
1125 n.setAlphaNew( Canonical.unionORpreds( n.getAlphaNew(),
1130 nodesWithNewAlpha.add( n );
1133 propagateTokensOverEdges( todoEdges,
1140 protected void propagateTokensOverEdges( HashSet <RefEdge> todoEdges,
1141 Hashtable<RefEdge, ChangeSet> edgePlannedChanges,
1142 HashSet <RefEdge> edgesWithNewBeta ) {
1144 // first propagate all change tuples everywhere they can go
1145 while( !todoEdges.isEmpty() ) {
1146 RefEdge edgeE = todoEdges.iterator().next();
1147 todoEdges.remove( edgeE );
1149 if( !edgePlannedChanges.containsKey( edgeE ) ) {
1150 edgePlannedChanges.put( edgeE,
1155 ChangeSet C = edgePlannedChanges.get( edgeE );
1157 ChangeSet changesToPass = ChangeSet.factory();
1159 Iterator<ChangeTuple> itrC = C.iterator();
1160 while( itrC.hasNext() ) {
1161 ChangeTuple c = itrC.next();
1162 if( edgeE.getBeta().containsIgnorePreds( c.getStateToMatch() )
1165 changesToPass = Canonical.add( changesToPass, c );
1169 RefSrcNode rsn = edgeE.getSrc();
1171 if( !changesToPass.isEmpty() && rsn instanceof HeapRegionNode ) {
1172 HeapRegionNode n = (HeapRegionNode) rsn;
1174 Iterator<RefEdge> referItr = n.iteratorToReferencers();
1175 while( referItr.hasNext() ) {
1176 RefEdge edgeF = referItr.next();
1178 if( !edgePlannedChanges.containsKey( edgeF ) ) {
1179 edgePlannedChanges.put( edgeF,
1184 ChangeSet currentChanges = edgePlannedChanges.get( edgeF );
1186 if( !changesToPass.isSubset( currentChanges ) ) {
1187 todoEdges.add( edgeF );
1188 edgePlannedChanges.put( edgeF,
1189 Canonical.union( currentChanges,
1198 // then apply all of the changes for each edge at once
1199 Iterator itrMap = edgePlannedChanges.entrySet().iterator();
1200 while( itrMap.hasNext() ) {
1201 Map.Entry me = (Map.Entry) itrMap.next();
1202 RefEdge e = (RefEdge) me.getKey();
1203 ChangeSet C = (ChangeSet) me.getValue();
1205 // this propagation step is with respect to one change,
1206 // so we capture the full change from the old beta:
1207 ReachSet localDelta =
1208 Canonical.applyChangeSet( e.getBeta(),
1213 // but this propagation may be only one of many concurrent
1214 // possible changes, so keep a running union with the edge's
1215 // partially updated new beta set
1216 e.setBetaNew( Canonical.unionORpreds( e.getBetaNew(),
1221 edgesWithNewBeta.add( e );
1226 // used in makeCalleeView below to decide if there is
1227 // already an appropriate out-of-context edge in a callee
1228 // view graph for merging, or null if a new one will be added
1230 getOutOfContextReferenceTo( HeapRegionNode hrn,
1231 TypeDescriptor srcType,
1232 TypeDescriptor refType,
1234 assert belongsToThis( hrn );
1236 HeapRegionNode hrnInContext = id2hrn.get( hrn.getID() );
1237 if( hrnInContext == null ) {
1241 Iterator<RefEdge> refItr = hrnInContext.iteratorToReferencers();
1242 while( refItr.hasNext() ) {
1243 RefEdge re = refItr.next();
1245 assert belongsToThis( re.getSrc() );
1246 assert belongsToThis( re.getDst() );
1248 if( !(re.getSrc() instanceof HeapRegionNode) ) {
1252 HeapRegionNode hrnSrc = (HeapRegionNode) re.getSrc();
1253 if( !hrnSrc.isOutOfContext() ) {
1257 if( srcType == null ) {
1258 if( hrnSrc.getType() != null ) {
1262 if( !srcType.equals( hrnSrc.getType() ) ) {
1267 if( !re.typeEquals( refType ) ) {
1271 if( !re.fieldEquals( refField ) ) {
1275 // tada! We found it!
1282 // used below to convert a ReachSet to its callee-context
1283 // equivalent with respect to allocation sites in this graph
1284 protected ReachSet toCalleeContext( ReachSet rs,
1286 Set<ReachTuple> oocTuples
1288 ReachSet out = ReachSet.factory();
1290 Iterator<ReachState> itr = rs.iterator();
1291 while( itr.hasNext() ) {
1292 ReachState stateCaller = itr.next();
1294 ReachState stateCallee = stateCaller;
1296 Iterator<AllocSite> asItr = allocSites.iterator();
1297 while( asItr.hasNext() ) {
1298 AllocSite as = asItr.next();
1300 ReachState stateNew = ReachState.factory();
1301 Iterator<ReachTuple> rtItr = stateCallee.iterator();
1302 while( rtItr.hasNext() ) {
1303 ReachTuple rt = rtItr.next();
1305 // only translate this tuple if it is
1306 // in the out-callee-context bag
1307 if( !oocTuples.contains( rt ) ) {
1308 stateNew = Canonical.add( stateNew, rt );
1312 int age = as.getAgeCategory( rt.getHrnID() );
1314 // this is the current mapping, where 0, 1, 2S were allocated
1315 // in the current context, 0?, 1? and 2S? were allocated in a
1316 // previous context, and we're translating to a future context
1328 if( age == AllocSite.AGE_notInThisSite ) {
1329 // things not from the site just go back in
1330 stateNew = Canonical.add( stateNew, rt );
1332 } else if( age == AllocSite.AGE_summary ||
1335 // the in-context summary and all existing out-of-context
1337 stateNew = Canonical.add( stateNew,
1338 ReachTuple.factory( as.getSummary(),
1341 true // out-of-context
1345 // otherwise everything else just goes to an out-of-context
1346 // version, everything else the same
1347 Integer I = as.getAge( rt.getHrnID() );
1350 assert !rt.isMultiObject();
1352 stateNew = Canonical.add( stateNew,
1353 ReachTuple.factory( rt.getHrnID(),
1356 true // out-of-context
1362 stateCallee = stateNew;
1365 // attach the passed in preds
1366 stateCallee = Canonical.attach( stateCallee,
1369 out = Canonical.add( out,
1374 assert out.isCanonical();
1378 // used below to convert a ReachSet to its caller-context
1379 // equivalent with respect to allocation sites in this graph
1381 toCallerContext( ReachSet rs,
1382 Hashtable<ReachState, ExistPredSet> calleeStatesSatisfied
1384 ReachSet out = ReachSet.factory();
1386 Iterator<ReachState> itr = rs.iterator();
1387 while( itr.hasNext() ) {
1388 ReachState stateCallee = itr.next();
1390 if( calleeStatesSatisfied.containsKey( stateCallee ) ) {
1392 // starting from one callee state...
1393 ReachSet rsCaller = ReachSet.factory( stateCallee );
1395 // possibly branch it into many states, which any
1396 // allocation site might do, so lots of derived states
1397 Iterator<AllocSite> asItr = allocSites.iterator();
1398 while( asItr.hasNext() ) {
1399 AllocSite as = asItr.next();
1400 rsCaller = Canonical.toCallerContext( rsCaller, as );
1403 // then before adding each derived, now caller-context
1404 // states to the output, attach the appropriate pred
1405 // based on the source callee state
1406 Iterator<ReachState> stateItr = rsCaller.iterator();
1407 while( stateItr.hasNext() ) {
1408 ReachState stateCaller = stateItr.next();
1409 stateCaller = Canonical.attach( stateCaller,
1410 calleeStatesSatisfied.get( stateCallee )
1412 out = Canonical.add( out,
1419 assert out.isCanonical();
1423 // used below to convert a ReachSet to an equivalent
1424 // version with shadow IDs merged into unshadowed IDs
1425 protected ReachSet unshadow( ReachSet rs ) {
1427 Iterator<AllocSite> asItr = allocSites.iterator();
1428 while( asItr.hasNext() ) {
1429 AllocSite as = asItr.next();
1430 out = Canonical.unshadow( out, as );
1432 assert out.isCanonical();
1437 // use this method to make a new reach graph that is
1438 // what heap the FlatMethod callee from the FlatCall
1439 // would start with reaching from its arguments in
1442 makeCalleeView( FlatCall fc,
1443 FlatMethod fmCallee,
1444 Set<Integer> callerNodeIDsCopiedToCallee,
1445 boolean writeDebugDOTs
1449 // first traverse this context to find nodes and edges
1450 // that will be callee-reachable
1451 Set<HeapRegionNode> reachableCallerNodes =
1452 new HashSet<HeapRegionNode>();
1454 // caller edges between callee-reachable nodes
1455 Set<RefEdge> reachableCallerEdges =
1456 new HashSet<RefEdge>();
1458 // caller edges from arg vars, and the matching param index
1459 // because these become a special edge in callee
1460 Hashtable<RefEdge, Integer> reachableCallerArgEdges2paramIndex =
1461 new Hashtable<RefEdge, Integer>();
1463 // caller edges from local vars or callee-unreachable nodes
1464 // (out-of-context sources) to callee-reachable nodes
1465 Set<RefEdge> oocCallerEdges =
1466 new HashSet<RefEdge>();
1469 for( int i = 0; i < fmCallee.numParameters(); ++i ) {
1471 TempDescriptor tdArg = fc.getArgMatchingParamIndex( fmCallee, i );
1472 VariableNode vnArgCaller = this.getVariableNodeFromTemp( tdArg );
1474 Set<RefSrcNode> toVisitInCaller = new HashSet<RefSrcNode>();
1475 Set<RefSrcNode> visitedInCaller = new HashSet<RefSrcNode>();
1477 toVisitInCaller.add( vnArgCaller );
1479 while( !toVisitInCaller.isEmpty() ) {
1480 RefSrcNode rsnCaller = toVisitInCaller.iterator().next();
1481 toVisitInCaller.remove( rsnCaller );
1482 visitedInCaller.add( rsnCaller );
1484 Iterator<RefEdge> itrRefEdges = rsnCaller.iteratorToReferencees();
1485 while( itrRefEdges.hasNext() ) {
1486 RefEdge reCaller = itrRefEdges.next();
1487 HeapRegionNode hrnCaller = reCaller.getDst();
1489 callerNodeIDsCopiedToCallee.add( hrnCaller.getID() );
1490 reachableCallerNodes.add( hrnCaller );
1492 if( reCaller.getSrc() instanceof HeapRegionNode ) {
1493 reachableCallerEdges.add( reCaller );
1495 if( rsnCaller.equals( vnArgCaller ) ) {
1496 reachableCallerArgEdges2paramIndex.put( reCaller, i );
1498 oocCallerEdges.add( reCaller );
1502 if( !visitedInCaller.contains( hrnCaller ) ) {
1503 toVisitInCaller.add( hrnCaller );
1506 } // end edge iteration
1507 } // end visiting heap nodes in caller
1508 } // end iterating over parameters as starting points
1511 // now collect out-of-context reach tuples and
1512 // more out-of-context edges
1513 Set<ReachTuple> oocTuples = new HashSet<ReachTuple>();
1515 Iterator<Integer> itrInContext =
1516 callerNodeIDsCopiedToCallee.iterator();
1517 while( itrInContext.hasNext() ) {
1518 Integer hrnID = itrInContext.next();
1519 HeapRegionNode hrnCallerAndInContext = id2hrn.get( hrnID );
1521 Iterator<RefEdge> itrMightCross =
1522 hrnCallerAndInContext.iteratorToReferencers();
1523 while( itrMightCross.hasNext() ) {
1524 RefEdge edgeMightCross = itrMightCross.next();
1526 RefSrcNode rsnCallerAndOutContext =
1527 edgeMightCross.getSrc();
1529 if( rsnCallerAndOutContext instanceof VariableNode ) {
1530 // variables do not have out-of-context reach states,
1532 oocCallerEdges.add( edgeMightCross );
1536 HeapRegionNode hrnCallerAndOutContext =
1537 (HeapRegionNode) rsnCallerAndOutContext;
1539 // is this source node out-of-context?
1540 if( callerNodeIDsCopiedToCallee.contains( hrnCallerAndOutContext.getID() ) ) {
1541 // no, skip this edge
1546 oocCallerEdges.add( edgeMightCross );
1548 // add all reach tuples on the node to list
1549 // of things that are out-of-context: insight
1550 // if this node is reachable from someting that WAS
1551 // in-context, then this node should already be in-context
1552 Iterator<ReachState> stateItr = hrnCallerAndOutContext.getAlpha().iterator();
1553 while( stateItr.hasNext() ) {
1554 ReachState state = stateItr.next();
1556 Iterator<ReachTuple> rtItr = state.iterator();
1557 while( rtItr.hasNext() ) {
1558 ReachTuple rt = rtItr.next();
1560 oocTuples.add( rt );
1567 // the callee view is a new graph: DON'T MODIFY *THIS* graph
1568 ReachGraph rg = new ReachGraph();
1570 // add nodes to callee graph
1571 Iterator<HeapRegionNode> hrnItr = reachableCallerNodes.iterator();
1572 while( hrnItr.hasNext() ) {
1573 HeapRegionNode hrnCaller = hrnItr.next();
1575 assert callerNodeIDsCopiedToCallee.contains( hrnCaller.getID() );
1576 assert !rg.id2hrn.containsKey( hrnCaller.getID() );
1578 ExistPred pred = ExistPred.factory( hrnCaller.getID(), null );
1579 ExistPredSet preds = ExistPredSet.factory( pred );
1581 rg.createNewHeapRegionNode( hrnCaller.getID(),
1582 hrnCaller.isSingleObject(),
1583 hrnCaller.isNewSummary(),
1584 hrnCaller.isFlagged(),
1585 false, // out-of-context?
1586 hrnCaller.getType(),
1587 hrnCaller.getAllocSite(),
1588 toCalleeContext( hrnCaller.getInherent(),
1592 toCalleeContext( hrnCaller.getAlpha(),
1597 hrnCaller.getDescription()
1601 // add param edges to callee graph
1603 reachableCallerArgEdges2paramIndex.entrySet().iterator();
1604 while( argEdges.hasNext() ) {
1605 Map.Entry me = (Map.Entry) argEdges.next();
1606 RefEdge reArg = (RefEdge) me.getKey();
1607 Integer index = (Integer) me.getValue();
1609 TempDescriptor arg = fmCallee.getParameter( index );
1611 VariableNode vnCallee =
1612 rg.getVariableNodeFromTemp( arg );
1614 HeapRegionNode hrnDstCaller = reArg.getDst();
1615 HeapRegionNode hrnDstCallee = rg.id2hrn.get( hrnDstCaller.getID() );
1616 assert hrnDstCallee != null;
1619 ExistPred.factory( arg,
1621 hrnDstCallee.getID(),
1625 true, // out-of-callee-context
1626 false // out-of-caller-context
1629 ExistPredSet preds =
1630 ExistPredSet.factory( pred );
1633 new RefEdge( vnCallee,
1637 toCalleeContext( reArg.getBeta(),
1644 rg.addRefEdge( vnCallee,
1650 // add in-context edges to callee graph
1651 Iterator<RefEdge> reItr = reachableCallerEdges.iterator();
1652 while( reItr.hasNext() ) {
1653 RefEdge reCaller = reItr.next();
1654 RefSrcNode rsnCaller = reCaller.getSrc();
1655 assert rsnCaller instanceof HeapRegionNode;
1656 HeapRegionNode hrnSrcCaller = (HeapRegionNode) rsnCaller;
1657 HeapRegionNode hrnDstCaller = reCaller.getDst();
1659 HeapRegionNode hrnSrcCallee = rg.id2hrn.get( hrnSrcCaller.getID() );
1660 HeapRegionNode hrnDstCallee = rg.id2hrn.get( hrnDstCaller.getID() );
1661 assert hrnSrcCallee != null;
1662 assert hrnDstCallee != null;
1665 ExistPred.factory( null,
1666 hrnSrcCallee.getID(),
1667 hrnDstCallee.getID(),
1669 reCaller.getField(),
1671 false, // out-of-callee-context
1672 false // out-of-caller-context
1675 ExistPredSet preds =
1676 ExistPredSet.factory( pred );
1679 new RefEdge( hrnSrcCallee,
1682 reCaller.getField(),
1683 toCalleeContext( reCaller.getBeta(),
1690 rg.addRefEdge( hrnSrcCallee,
1696 // add out-of-context edges to callee graph
1697 reItr = oocCallerEdges.iterator();
1698 while( reItr.hasNext() ) {
1699 RefEdge reCaller = reItr.next();
1700 RefSrcNode rsnCaller = reCaller.getSrc();
1701 HeapRegionNode hrnDstCaller = reCaller.getDst();
1702 HeapRegionNode hrnDstCallee = rg.id2hrn.get( hrnDstCaller.getID() );
1703 assert hrnDstCallee != null;
1705 TypeDescriptor oocNodeType;
1707 TempDescriptor oocPredSrcTemp = null;
1708 Integer oocPredSrcID = null;
1709 boolean outOfCalleeContext;
1710 boolean outOfCallerContext;
1712 if( rsnCaller instanceof VariableNode ) {
1713 VariableNode vnCaller = (VariableNode) rsnCaller;
1715 oocReach = rsetEmpty;
1716 oocPredSrcTemp = vnCaller.getTempDescriptor();
1717 outOfCalleeContext = true;
1718 outOfCallerContext = false;
1721 HeapRegionNode hrnSrcCaller = (HeapRegionNode) rsnCaller;
1722 assert !callerNodeIDsCopiedToCallee.contains( hrnSrcCaller.getID() );
1723 oocNodeType = hrnSrcCaller.getType();
1724 oocReach = hrnSrcCaller.getAlpha();
1725 oocPredSrcID = hrnSrcCaller.getID();
1726 if( hrnSrcCaller.isOutOfContext() ) {
1727 outOfCalleeContext = false;
1728 outOfCallerContext = true;
1730 outOfCalleeContext = true;
1731 outOfCallerContext = false;
1736 ExistPred.factory( oocPredSrcTemp,
1738 hrnDstCallee.getID(),
1740 reCaller.getField(),
1746 ExistPredSet preds =
1747 ExistPredSet.factory( pred );
1749 RefEdge oocEdgeExisting =
1750 rg.getOutOfContextReferenceTo( hrnDstCallee,
1756 if( oocEdgeExisting == null ) {
1757 // for consistency, map one out-of-context "identifier"
1758 // to one heap region node id, otherwise no convergence
1759 String oocid = "oocid"+
1761 hrnDstCallee.getIDString()+
1764 reCaller.getField();
1766 Integer oocHrnID = oocid2hrnid.get( oocid );
1768 HeapRegionNode hrnCalleeAndOutContext;
1770 if( oocHrnID == null ) {
1772 hrnCalleeAndOutContext =
1773 rg.createNewHeapRegionNode( null, // ID
1774 false, // single object?
1775 false, // new summary?
1777 true, // out-of-context?
1779 null, // alloc site, shouldn't be used
1780 toCalleeContext( oocReach,
1784 toCalleeContext( oocReach,
1792 oocid2hrnid.put( oocid, hrnCalleeAndOutContext.getID() );
1796 // the mapping already exists, so see if node is there
1797 hrnCalleeAndOutContext = rg.id2hrn.get( oocHrnID );
1799 if( hrnCalleeAndOutContext == null ) {
1801 hrnCalleeAndOutContext =
1802 rg.createNewHeapRegionNode( oocHrnID, // ID
1803 false, // single object?
1804 false, // new summary?
1806 true, // out-of-context?
1808 null, // alloc site, shouldn't be used
1809 toCalleeContext( oocReach,
1813 toCalleeContext( oocReach,
1821 // otherwise it is there, so merge reachability
1822 hrnCalleeAndOutContext.setAlpha( Canonical.unionORpreds( hrnCalleeAndOutContext.getAlpha(),
1823 toCalleeContext( oocReach,
1832 rg.addRefEdge( hrnCalleeAndOutContext,
1834 new RefEdge( hrnCalleeAndOutContext,
1837 reCaller.getField(),
1838 toCalleeContext( reCaller.getBeta(),
1847 // the out-of-context edge already exists
1848 oocEdgeExisting.setBeta( Canonical.unionORpreds( oocEdgeExisting.getBeta(),
1849 toCalleeContext( reCaller.getBeta(),
1856 oocEdgeExisting.setPreds( Canonical.join( oocEdgeExisting.getPreds(),
1861 HeapRegionNode hrnCalleeAndOutContext =
1862 (HeapRegionNode) oocEdgeExisting.getSrc();
1863 hrnCalleeAndOutContext.setAlpha( Canonical.unionORpreds( hrnCalleeAndOutContext.getAlpha(),
1864 toCalleeContext( oocReach,
1876 if( writeDebugDOTs ) {
1878 rg.writeGraph( "calleeview",
1879 resolveMethodDebugDOTwriteLabels,
1880 resolveMethodDebugDOTselectTemps,
1881 resolveMethodDebugDOTpruneGarbage,
1882 resolveMethodDebugDOThideSubsetReach,
1883 resolveMethodDebugDOThideEdgeTaints );
1884 } catch( IOException e ) {}
1890 private static Hashtable<String, Integer> oocid2hrnid =
1891 new Hashtable<String, Integer>();
1894 // useful since many graphs writes in the method call debug code
1895 private static boolean resolveMethodDebugDOTwriteLabels = true;
1896 private static boolean resolveMethodDebugDOTselectTemps = true;
1897 private static boolean resolveMethodDebugDOTpruneGarbage = true;
1898 private static boolean resolveMethodDebugDOThideSubsetReach = false;
1899 private static boolean resolveMethodDebugDOThideEdgeTaints = true;
1904 resolveMethodCall( FlatCall fc,
1905 FlatMethod fmCallee,
1906 ReachGraph rgCallee,
1907 Set<Integer> callerNodeIDsCopiedToCallee,
1908 boolean writeDebugDOTs
1912 if( writeDebugDOTs ) {
1914 rgCallee.writeGraph( "callee",
1915 resolveMethodDebugDOTwriteLabels,
1916 resolveMethodDebugDOTselectTemps,
1917 resolveMethodDebugDOTpruneGarbage,
1918 resolveMethodDebugDOThideSubsetReach,
1919 resolveMethodDebugDOThideEdgeTaints );
1921 writeGraph( "caller00In",
1922 resolveMethodDebugDOTwriteLabels,
1923 resolveMethodDebugDOTselectTemps,
1924 resolveMethodDebugDOTpruneGarbage,
1925 resolveMethodDebugDOThideSubsetReach,
1926 resolveMethodDebugDOThideEdgeTaints,
1927 callerNodeIDsCopiedToCallee );
1928 } catch( IOException e ) {}
1932 // method call transfer function steps:
1933 // 1. Use current callee-reachable heap (CRH) to test callee
1934 // predicates and mark what will be coming in.
1935 // 2. Wipe CRH out of caller.
1936 // 3. Transplant marked callee parts in:
1937 // a) bring in nodes
1938 // b) bring in callee -> callee edges
1939 // c) resolve out-of-context -> callee edges
1940 // d) assign return value
1941 // 4. Collapse shadow nodes down
1942 // 5. Global sweep it.
1946 // 1. mark what callee elements have satisfied predicates
1947 Hashtable<HeapRegionNode, ExistPredSet> calleeNodesSatisfied =
1948 new Hashtable<HeapRegionNode, ExistPredSet>();
1950 Hashtable<RefEdge, ExistPredSet> calleeEdgesSatisfied =
1951 new Hashtable<RefEdge, ExistPredSet>();
1953 Hashtable<ReachState, ExistPredSet> calleeStatesSatisfied =
1954 new Hashtable<ReachState, ExistPredSet>();
1956 Hashtable< RefEdge, Set<RefSrcNode> > calleeEdges2oocCallerSrcMatches =
1957 new Hashtable< RefEdge, Set<RefSrcNode> >();
1959 Iterator meItr = rgCallee.id2hrn.entrySet().iterator();
1960 while( meItr.hasNext() ) {
1961 Map.Entry me = (Map.Entry) meItr.next();
1962 Integer id = (Integer) me.getKey();
1963 HeapRegionNode hrnCallee = (HeapRegionNode) me.getValue();
1965 // if a callee element's predicates are satisfied then a set
1966 // of CALLER predicates is returned: they are the predicates
1967 // that the callee element moved into the caller context
1968 // should have, and it is inefficient to find this again later
1969 ExistPredSet predsIfSatis =
1970 hrnCallee.getPreds().isSatisfiedBy( this,
1971 callerNodeIDsCopiedToCallee
1973 if( predsIfSatis != null ) {
1974 calleeNodesSatisfied.put( hrnCallee, predsIfSatis );
1976 // otherwise don't bother looking at edges to this node
1980 // since the node is coming over, find out which reach
1981 // states on it should come over, too
1982 Iterator<ReachState> stateItr = hrnCallee.getAlpha().iterator();
1983 while( stateItr.hasNext() ) {
1984 ReachState stateCallee = stateItr.next();
1987 stateCallee.getPreds().isSatisfiedBy( this,
1988 callerNodeIDsCopiedToCallee
1990 if( predsIfSatis != null ) {
1991 calleeStatesSatisfied.put( stateCallee, predsIfSatis );
1995 // then look at edges to the node
1996 Iterator<RefEdge> reItr = hrnCallee.iteratorToReferencers();
1997 while( reItr.hasNext() ) {
1998 RefEdge reCallee = reItr.next();
1999 RefSrcNode rsnCallee = reCallee.getSrc();
2001 // (caller local variables to in-context heap regions)
2002 // have an (out-of-context heap region -> in-context heap region)
2003 // abstraction in the callEE, so its true we never need to
2004 // look at a (var node -> heap region) edge in callee to bring
2005 // those over for the call site transfer. What about (param var->heap region)
2006 // edges in callee? They are dealt with below this loop.
2007 // So, yes, at this point skip (var->region) edges in callee
2008 if( rsnCallee instanceof VariableNode ) {
2012 // first see if the source is out-of-context, and only
2013 // proceed with this edge if we find some caller-context
2015 HeapRegionNode hrnSrcCallee = (HeapRegionNode) rsnCallee;
2016 boolean matchedOutOfContext = false;
2018 if( hrnSrcCallee.isOutOfContext() ) {
2020 assert !calleeEdges2oocCallerSrcMatches.containsKey( reCallee );
2021 Set<RefSrcNode> rsnCallers = new HashSet<RefSrcNode>();
2023 HeapRegionNode hrnDstCaller = this.id2hrn.get( hrnCallee.getID() );
2024 Iterator<RefEdge> reDstItr = hrnDstCaller.iteratorToReferencers();
2025 while( reDstItr.hasNext() ) {
2026 // the edge and field (either possibly null) must match
2027 RefEdge reCaller = reDstItr.next();
2029 if( !reCaller.typeEquals ( reCallee.getType() ) ||
2030 !reCaller.fieldEquals( reCallee.getField() )
2035 RefSrcNode rsnCaller = reCaller.getSrc();
2036 if( rsnCaller instanceof VariableNode ) {
2037 // a variable node matches an OOC region with null type
2038 if( hrnSrcCallee.getType() != null ) {
2043 // otherwise types should match
2044 HeapRegionNode hrnCallerSrc = (HeapRegionNode) rsnCaller;
2045 if( hrnSrcCallee.getType() == null ) {
2046 if( hrnCallerSrc.getType() != null ) {
2050 if( !hrnSrcCallee.getType().equals( hrnCallerSrc.getType() ) ) {
2056 rsnCallers.add( rsnCaller );
2057 matchedOutOfContext = true;
2060 if( !rsnCallers.isEmpty() ) {
2061 calleeEdges2oocCallerSrcMatches.put( reCallee, rsnCallers );
2065 if( hrnSrcCallee.isOutOfContext() &&
2066 !matchedOutOfContext ) {
2071 reCallee.getPreds().isSatisfiedBy( this,
2072 callerNodeIDsCopiedToCallee
2074 if( predsIfSatis != null ) {
2075 calleeEdgesSatisfied.put( reCallee, predsIfSatis );
2077 // since the edge is coming over, find out which reach
2078 // states on it should come over, too
2079 stateItr = reCallee.getBeta().iterator();
2080 while( stateItr.hasNext() ) {
2081 ReachState stateCallee = stateItr.next();
2084 stateCallee.getPreds().isSatisfiedBy( this,
2085 callerNodeIDsCopiedToCallee
2087 if( predsIfSatis != null ) {
2088 calleeStatesSatisfied.put( stateCallee, predsIfSatis );
2095 // test param -> HRN edges, also
2096 for( int i = 0; i < fmCallee.numParameters(); ++i ) {
2098 // parameter defined here is the symbol in the callee
2099 TempDescriptor tdParam = fmCallee.getParameter( i );
2100 VariableNode vnCallee = rgCallee.getVariableNodeFromTemp( tdParam );
2102 Iterator<RefEdge> reItr = vnCallee.iteratorToReferencees();
2103 while( reItr.hasNext() ) {
2104 RefEdge reCallee = reItr.next();
2106 ExistPredSet ifDst =
2107 reCallee.getDst().getPreds().isSatisfiedBy( this,
2108 callerNodeIDsCopiedToCallee
2110 if( ifDst == null ) {
2114 ExistPredSet predsIfSatis =
2115 reCallee.getPreds().isSatisfiedBy( this,
2116 callerNodeIDsCopiedToCallee
2118 if( predsIfSatis != null ) {
2119 calleeEdgesSatisfied.put( reCallee, predsIfSatis );
2121 // since the edge is coming over, find out which reach
2122 // states on it should come over, too
2123 Iterator<ReachState> stateItr = reCallee.getBeta().iterator();
2124 while( stateItr.hasNext() ) {
2125 ReachState stateCallee = stateItr.next();
2128 stateCallee.getPreds().isSatisfiedBy( this,
2129 callerNodeIDsCopiedToCallee
2131 if( predsIfSatis != null ) {
2132 calleeStatesSatisfied.put( stateCallee, predsIfSatis );
2143 if( writeDebugDOTs ) {
2145 writeGraph( "caller20BeforeWipe",
2146 resolveMethodDebugDOTwriteLabels,
2147 resolveMethodDebugDOTselectTemps,
2148 resolveMethodDebugDOTpruneGarbage,
2149 resolveMethodDebugDOThideSubsetReach,
2150 resolveMethodDebugDOThideEdgeTaints );
2151 } catch( IOException e ) {}
2155 // 2. predicates tested, ok to wipe out caller part
2156 Iterator<Integer> hrnItr = callerNodeIDsCopiedToCallee.iterator();
2157 while( hrnItr.hasNext() ) {
2158 Integer hrnID = hrnItr.next();
2159 HeapRegionNode hrnCaller = id2hrn.get( hrnID );
2160 assert hrnCaller != null;
2162 // when clearing off nodes, also eliminate variable
2164 wipeOut( hrnCaller, true );
2169 if( writeDebugDOTs ) {
2171 writeGraph( "caller30BeforeAddingNodes",
2172 resolveMethodDebugDOTwriteLabels,
2173 resolveMethodDebugDOTselectTemps,
2174 resolveMethodDebugDOTpruneGarbage,
2175 resolveMethodDebugDOThideSubsetReach,
2176 resolveMethodDebugDOThideEdgeTaints );
2177 } catch( IOException e ) {}
2181 // 3. callee elements with satisfied preds come in, note that
2182 // the mapping of elements satisfied to preds is like this:
2183 // A callee element EE has preds EEp that are satisfied by
2184 // some caller element ER. We bring EE into the caller
2185 // context as ERee with the preds of ER, namely ERp, which
2186 // in the following algorithm is the value in the mapping
2189 Iterator satisItr = calleeNodesSatisfied.entrySet().iterator();
2190 while( satisItr.hasNext() ) {
2191 Map.Entry me = (Map.Entry) satisItr.next();
2192 HeapRegionNode hrnCallee = (HeapRegionNode) me.getKey();
2193 ExistPredSet preds = (ExistPredSet) me.getValue();
2195 // TODO: I think its true that the current implementation uses
2196 // the type of the OOC region and the predicates OF THE EDGE from
2197 // it to link everything up in caller context, so that's why we're
2198 // skipping this... maybe that's a sillier way to do it?
2199 if( hrnCallee.isOutOfContext() ) {
2203 AllocSite as = hrnCallee.getAllocSite();
2204 allocSites.add( as );
2206 Integer hrnIDshadow = as.getShadowIDfromID( hrnCallee.getID() );
2208 HeapRegionNode hrnCaller = id2hrn.get( hrnIDshadow );
2209 if( hrnCaller == null ) {
2211 createNewHeapRegionNode( hrnIDshadow, // id or null to generate a new one
2212 hrnCallee.isSingleObject(), // single object?
2213 hrnCallee.isNewSummary(), // summary?
2214 hrnCallee.isFlagged(), // flagged?
2215 false, // out-of-context?
2216 hrnCallee.getType(), // type
2217 hrnCallee.getAllocSite(), // allocation site
2218 toCallerContext( hrnCallee.getInherent(),
2219 calleeStatesSatisfied ), // inherent reach
2220 null, // current reach
2221 predsEmpty, // predicates
2222 hrnCallee.getDescription() // description
2225 assert hrnCaller.isWiped();
2228 hrnCaller.setAlpha( toCallerContext( hrnCallee.getAlpha(),
2229 calleeStatesSatisfied
2233 hrnCaller.setPreds( preds );
2238 if( writeDebugDOTs ) {
2240 writeGraph( "caller31BeforeAddingEdges",
2241 resolveMethodDebugDOTwriteLabels,
2242 resolveMethodDebugDOTselectTemps,
2243 resolveMethodDebugDOTpruneGarbage,
2244 resolveMethodDebugDOThideSubsetReach,
2245 resolveMethodDebugDOThideEdgeTaints );
2246 } catch( IOException e ) {}
2250 // set these up during the next procedure so after
2251 // the caller has all of its nodes and edges put
2252 // back together we can propagate the callee's
2253 // reach changes backwards into the caller graph
2254 HashSet<RefEdge> edgesForPropagation = new HashSet<RefEdge>();
2256 Hashtable<RefEdge, ChangeSet> edgePlannedChanges =
2257 new Hashtable<RefEdge, ChangeSet>();
2260 // 3.b) callee -> callee edges AND out-of-context -> callee
2261 satisItr = calleeEdgesSatisfied.entrySet().iterator();
2262 while( satisItr.hasNext() ) {
2263 Map.Entry me = (Map.Entry) satisItr.next();
2264 RefEdge reCallee = (RefEdge) me.getKey();
2265 ExistPredSet preds = (ExistPredSet) me.getValue();
2267 HeapRegionNode hrnDstCallee = reCallee.getDst();
2268 AllocSite asDst = hrnDstCallee.getAllocSite();
2269 allocSites.add( asDst );
2271 Integer hrnIDDstShadow =
2272 asDst.getShadowIDfromID( hrnDstCallee.getID() );
2274 HeapRegionNode hrnDstCaller = id2hrn.get( hrnIDDstShadow );
2275 assert hrnDstCaller != null;
2278 RefSrcNode rsnCallee = reCallee.getSrc();
2280 Set<RefSrcNode> rsnCallers =
2281 new HashSet<RefSrcNode>();
2283 Set<RefSrcNode> oocCallers =
2284 calleeEdges2oocCallerSrcMatches.get( reCallee );
2286 boolean oocEdges = false;
2288 if( oocCallers == null ) {
2289 // there are no out-of-context matches, so it's
2290 // either a param/arg var or one in-context heap region
2291 if( rsnCallee instanceof VariableNode ) {
2292 // variable -> node in the callee should only
2293 // come into the caller if its from a param var
2294 VariableNode vnCallee = (VariableNode) rsnCallee;
2295 TempDescriptor tdParam = vnCallee.getTempDescriptor();
2296 TempDescriptor tdArg = fc.getArgMatchingParam( fmCallee,
2298 if( tdArg == null ) {
2299 // this means the variable isn't a parameter, its local
2300 // to the callee so we ignore it in call site transfer
2301 // shouldn't this NEVER HAPPEN?
2304 rsnCallers.add( this.getVariableNodeFromTemp( tdArg ) );
2308 // otherwise source is in context, one region
2309 HeapRegionNode hrnSrcCallee = (HeapRegionNode) rsnCallee;
2311 // translate an in-context node to shadow
2312 AllocSite asSrc = hrnSrcCallee.getAllocSite();
2313 allocSites.add( asSrc );
2315 Integer hrnIDSrcShadow =
2316 asSrc.getShadowIDfromID( hrnSrcCallee.getID() );
2318 HeapRegionNode hrnSrcCallerShadow =
2319 this.id2hrn.get( hrnIDSrcShadow );
2321 if( hrnSrcCallerShadow == null ) {
2322 hrnSrcCallerShadow =
2323 createNewHeapRegionNode( hrnIDSrcShadow, // id or null to generate a new one
2324 hrnSrcCallee.isSingleObject(), // single object?
2325 hrnSrcCallee.isNewSummary(), // summary?
2326 hrnSrcCallee.isFlagged(), // flagged?
2327 false, // out-of-context?
2328 hrnSrcCallee.getType(), // type
2329 hrnSrcCallee.getAllocSite(), // allocation site
2330 toCallerContext( hrnSrcCallee.getInherent(),
2331 calleeStatesSatisfied ), // inherent reach
2332 toCallerContext( hrnSrcCallee.getAlpha(),
2333 calleeStatesSatisfied ), // current reach
2334 predsEmpty, // predicates
2335 hrnSrcCallee.getDescription() // description
2339 rsnCallers.add( hrnSrcCallerShadow );
2343 // otherwise we have a set of out-of-context srcs
2344 // that should NOT be translated to shadow nodes
2345 assert !oocCallers.isEmpty();
2346 rsnCallers.addAll( oocCallers );
2350 // now make all caller edges we've identified from
2351 // this callee edge with a satisfied predicate
2352 assert !rsnCallers.isEmpty();
2353 Iterator<RefSrcNode> rsnItr = rsnCallers.iterator();
2354 while( rsnItr.hasNext() ) {
2355 RefSrcNode rsnCaller = rsnItr.next();
2357 RefEdge reCaller = new RefEdge( rsnCaller,
2360 reCallee.getField(),
2361 toCallerContext( reCallee.getBeta(),
2362 calleeStatesSatisfied ),
2366 ChangeSet cs = ChangeSet.factory();
2367 Iterator<ReachState> rsItr = reCaller.getBeta().iterator();
2368 while( rsItr.hasNext() ) {
2369 ReachState state = rsItr.next();
2370 ExistPredSet predsPreCallee = state.getPreds();
2372 if( state.isEmpty() ) {
2376 Iterator<ExistPred> predItr = predsPreCallee.iterator();
2377 while( predItr.hasNext() ) {
2378 ExistPred pred = predItr.next();
2379 ReachState old = pred.ne_state;
2385 cs = Canonical.add( cs,
2386 ChangeTuple.factory( old,
2394 // look to see if an edge with same field exists
2395 // and merge with it, otherwise just add the edge
2396 RefEdge edgeExisting = rsnCaller.getReferenceTo( hrnDstCaller,
2400 if( edgeExisting != null ) {
2401 edgeExisting.setBeta(
2402 Canonical.unionORpreds( edgeExisting.getBeta(),
2406 edgeExisting.setPreds(
2407 Canonical.join( edgeExisting.getPreds(),
2412 // for reach propagation
2413 if( !cs.isEmpty() ) {
2414 edgePlannedChanges.put(
2416 Canonical.union( edgePlannedChanges.get( edgeExisting ),
2423 addRefEdge( rsnCaller, hrnDstCaller, reCaller );
2425 // for reach propagation
2426 if( !cs.isEmpty() ) {
2427 edgesForPropagation.add( reCaller );
2428 assert !edgePlannedChanges.containsKey( reCaller );
2429 edgePlannedChanges.put( reCaller, cs );
2439 if( writeDebugDOTs ) {
2441 writeGraph( "caller35BeforeAssignReturnValue",
2442 resolveMethodDebugDOTwriteLabels,
2443 resolveMethodDebugDOTselectTemps,
2444 resolveMethodDebugDOTpruneGarbage,
2445 resolveMethodDebugDOThideSubsetReach,
2446 resolveMethodDebugDOThideEdgeTaints );
2447 } catch( IOException e ) {}
2452 // TODO: WAIT! THIS SHOULD BE MERGED INTO OTHER PARTS, BECAUSE
2453 // AS IT IS WE'RE NOT VERIFYING PREDICATES OF RETURN VALUE
2454 // EDGES, JUST BRINGING THEM ALL! It'll work for now, over approximation
2456 // 3.d) handle return value assignment if needed
2457 TempDescriptor returnTemp = fc.getReturnTemp();
2458 if( returnTemp != null && !returnTemp.getType().isImmutable() ) {
2460 VariableNode vnLhsCaller = getVariableNodeFromTemp( returnTemp );
2461 clearRefEdgesFrom( vnLhsCaller, null, null, true );
2463 VariableNode vnReturnCallee = rgCallee.getVariableNodeFromTemp( tdReturn );
2464 Iterator<RefEdge> reCalleeItr = vnReturnCallee.iteratorToReferencees();
2465 while( reCalleeItr.hasNext() ) {
2466 RefEdge reCallee = reCalleeItr.next();
2467 HeapRegionNode hrnDstCallee = reCallee.getDst();
2469 // some edge types are not possible return values when we can
2470 // see what type variable we are assigning it to
2471 if( !isSuperiorType( returnTemp.getType(), reCallee.getType() ) ) {
2472 System.out.println( "*** NOT EXPECTING TO SEE THIS: Throwing out "+
2473 reCallee+" for return temp "+returnTemp );
2478 AllocSite asDst = hrnDstCallee.getAllocSite();
2479 allocSites.add( asDst );
2481 Integer hrnIDDstShadow = asDst.getShadowIDfromID( hrnDstCallee.getID() );
2483 HeapRegionNode hrnDstCaller = id2hrn.get( hrnIDDstShadow );
2484 if( hrnDstCaller == null ) {
2486 createNewHeapRegionNode( hrnIDDstShadow, // id or null to generate a new one
2487 hrnDstCallee.isSingleObject(), // single object?
2488 hrnDstCallee.isNewSummary(), // summary?
2489 hrnDstCallee.isFlagged(), // flagged?
2490 false, // out-of-context?
2491 hrnDstCallee.getType(), // type
2492 hrnDstCallee.getAllocSite(), // allocation site
2493 toCallerContext( hrnDstCallee.getInherent(),
2494 calleeStatesSatisfied ), // inherent reach
2495 toCallerContext( hrnDstCallee.getAlpha(),
2496 calleeStatesSatisfied ), // current reach
2497 predsTrue, // predicates
2498 hrnDstCallee.getDescription() // description
2501 assert hrnDstCaller.isWiped();
2504 TypeDescriptor tdNewEdge =
2505 mostSpecificType( reCallee.getType(),
2506 hrnDstCallee.getType(),
2507 hrnDstCaller.getType()
2510 RefEdge reCaller = new RefEdge( vnLhsCaller,
2514 toCallerContext( reCallee.getBeta(),
2515 calleeStatesSatisfied ),
2519 addRefEdge( vnLhsCaller, hrnDstCaller, reCaller );
2525 if( writeDebugDOTs ) {
2527 writeGraph( "caller38propagateReach",
2528 resolveMethodDebugDOTwriteLabels,
2529 resolveMethodDebugDOTselectTemps,
2530 resolveMethodDebugDOTpruneGarbage,
2531 resolveMethodDebugDOThideSubsetReach,
2532 resolveMethodDebugDOThideEdgeTaints );
2533 } catch( IOException e ) {}
2536 // propagate callee reachability changes to the rest
2537 // of the caller graph edges
2538 HashSet<RefEdge> edgesUpdated = new HashSet<RefEdge>();
2540 propagateTokensOverEdges( edgesForPropagation, // source edges
2541 edgePlannedChanges, // map src edge to change set
2542 edgesUpdated ); // list of updated edges
2544 // commit beta' (beta<-betaNew)
2545 Iterator<RefEdge> edgeItr = edgesUpdated.iterator();
2546 while( edgeItr.hasNext() ) {
2547 edgeItr.next().applyBetaNew();
2555 if( writeDebugDOTs ) {
2557 writeGraph( "caller40BeforeShadowMerge",
2558 resolveMethodDebugDOTwriteLabels,
2559 resolveMethodDebugDOTselectTemps,
2560 resolveMethodDebugDOTpruneGarbage,
2561 resolveMethodDebugDOThideSubsetReach,
2562 resolveMethodDebugDOThideEdgeTaints );
2563 } catch( IOException e ) {}
2567 // 4) merge shadow nodes so alloc sites are back to k
2568 Iterator<AllocSite> asItr = rgCallee.allocSites.iterator();
2569 while( asItr.hasNext() ) {
2570 // for each allocation site do the following to merge
2571 // shadow nodes (newest from callee) with any existing
2572 // look for the newest normal and newest shadow "slot"
2573 // not being used, transfer normal to shadow. Keep
2574 // doing this until there are no more normal nodes, or
2575 // no empty shadow slots: then merge all remaining normal
2576 // nodes into the shadow summary. Finally, convert all
2577 // shadow to their normal versions.
2578 AllocSite as = asItr.next();
2581 while( ageNorm < allocationDepth &&
2582 ageShad < allocationDepth ) {
2584 // first, are there any normal nodes left?
2585 Integer idNorm = as.getIthOldest( ageNorm );
2586 HeapRegionNode hrnNorm = id2hrn.get( idNorm );
2587 if( hrnNorm == null ) {
2588 // no, this age of normal node not in the caller graph
2593 // yes, a normal node exists, is there an empty shadow
2594 // "slot" to transfer it onto?
2595 HeapRegionNode hrnShad = getIthNode( as, ageShad, true );
2596 if( !hrnShad.isWiped() ) {
2597 // no, this age of shadow node is not empty
2602 // yes, this shadow node is empty
2603 transferOnto( hrnNorm, hrnShad );
2608 // now, while there are still normal nodes but no shadow
2609 // slots, merge normal nodes into the shadow summary
2610 while( ageNorm < allocationDepth ) {
2612 // first, are there any normal nodes left?
2613 Integer idNorm = as.getIthOldest( ageNorm );
2614 HeapRegionNode hrnNorm = id2hrn.get( idNorm );
2615 if( hrnNorm == null ) {
2616 // no, this age of normal node not in the caller graph
2621 // yes, a normal node exists, so get the shadow summary
2622 HeapRegionNode summShad = getSummaryNode( as, true );
2623 mergeIntoSummary( hrnNorm, summShad );
2627 // if there is a normal summary, merge it into shadow summary
2628 Integer idNorm = as.getSummary();
2629 HeapRegionNode summNorm = id2hrn.get( idNorm );
2630 if( summNorm != null ) {
2631 HeapRegionNode summShad = getSummaryNode( as, true );
2632 mergeIntoSummary( summNorm, summShad );
2635 // finally, flip all existing shadow nodes onto the normal
2636 for( int i = 0; i < allocationDepth; ++i ) {
2637 Integer idShad = as.getIthOldestShadow( i );
2638 HeapRegionNode hrnShad = id2hrn.get( idShad );
2639 if( hrnShad != null ) {
2641 HeapRegionNode hrnNorm = getIthNode( as, i, false );
2642 assert hrnNorm.isWiped();
2643 transferOnto( hrnShad, hrnNorm );
2647 Integer idShad = as.getSummaryShadow();
2648 HeapRegionNode summShad = id2hrn.get( idShad );
2649 if( summShad != null ) {
2650 summNorm = getSummaryNode( as, false );
2651 transferOnto( summShad, summNorm );
2656 if( writeDebugDOTs ) {
2658 writeGraph( "caller45BeforeUnshadow",
2659 resolveMethodDebugDOTwriteLabels,
2660 resolveMethodDebugDOTselectTemps,
2661 resolveMethodDebugDOTpruneGarbage,
2662 resolveMethodDebugDOThideSubsetReach,
2663 resolveMethodDebugDOThideEdgeTaints );
2664 } catch( IOException e ) {}
2668 Iterator itrAllHRNodes = id2hrn.entrySet().iterator();
2669 while( itrAllHRNodes.hasNext() ) {
2670 Map.Entry me = (Map.Entry) itrAllHRNodes.next();
2671 HeapRegionNode hrn = (HeapRegionNode) me.getValue();
2673 hrn.setAlpha( unshadow( hrn.getAlpha() ) );
2675 Iterator<RefEdge> itrEdges = hrn.iteratorToReferencers();
2676 while( itrEdges.hasNext() ) {
2677 RefEdge re = itrEdges.next();
2678 re.setBeta( unshadow( re.getBeta() ) );
2684 if( writeDebugDOTs ) {
2686 writeGraph( "caller50BeforeGlobalSweep",
2687 resolveMethodDebugDOTwriteLabels,
2688 resolveMethodDebugDOTselectTemps,
2689 resolveMethodDebugDOTpruneGarbage,
2690 resolveMethodDebugDOThideSubsetReach,
2691 resolveMethodDebugDOThideEdgeTaints );
2692 } catch( IOException e ) {}
2697 if( !DISABLE_GLOBAL_SWEEP ) {
2703 if( writeDebugDOTs ) {
2705 writeGraph( "caller90AfterTransfer",
2706 resolveMethodDebugDOTwriteLabels,
2707 resolveMethodDebugDOTselectTemps,
2708 resolveMethodDebugDOTpruneGarbage,
2709 resolveMethodDebugDOThideSubsetReach,
2710 resolveMethodDebugDOThideEdgeTaints );
2711 } catch( IOException e ) {}
2717 ////////////////////////////////////////////////////
2719 // Abstract garbage collection simply removes
2720 // heap region nodes that are not mechanically
2721 // reachable from a root set. This step is
2722 // essential for testing node and edge existence
2723 // predicates efficiently
2725 ////////////////////////////////////////////////////
2726 public void abstractGarbageCollect( Set<TempDescriptor> liveSet ) {
2728 // calculate a root set, will be different for Java
2729 // version of analysis versus Bamboo version
2730 Set<RefSrcNode> toVisit = new HashSet<RefSrcNode>();
2732 // visit every variable in graph while building root
2733 // set, and do iterating on a copy, so we can remove
2734 // dead variables while we're at this
2735 Iterator makeCopyItr = td2vn.entrySet().iterator();
2736 Set entrysCopy = new HashSet();
2737 while( makeCopyItr.hasNext() ) {
2738 entrysCopy.add( makeCopyItr.next() );
2741 Iterator eItr = entrysCopy.iterator();
2742 while( eItr.hasNext() ) {
2743 Map.Entry me = (Map.Entry) eItr.next();
2744 TempDescriptor td = (TempDescriptor) me.getKey();
2745 VariableNode vn = (VariableNode) me.getValue();
2747 if( liveSet.contains( td ) ) {
2751 // dead var, remove completely from graph
2753 clearRefEdgesFrom( vn, null, null, true );
2757 // everything visited in a traversal is
2758 // considered abstractly live
2759 Set<RefSrcNode> visited = new HashSet<RefSrcNode>();
2761 while( !toVisit.isEmpty() ) {
2762 RefSrcNode rsn = toVisit.iterator().next();
2763 toVisit.remove( rsn );
2766 Iterator<RefEdge> hrnItr = rsn.iteratorToReferencees();
2767 while( hrnItr.hasNext() ) {
2768 RefEdge edge = hrnItr.next();
2769 HeapRegionNode hrn = edge.getDst();
2771 if( !visited.contains( hrn ) ) {
2777 // get a copy of the set to iterate over because
2778 // we're going to monkey with the graph when we
2779 // identify a garbage node
2780 Set<HeapRegionNode> hrnAllPrior = new HashSet<HeapRegionNode>();
2781 Iterator<HeapRegionNode> hrnItr = id2hrn.values().iterator();
2782 while( hrnItr.hasNext() ) {
2783 hrnAllPrior.add( hrnItr.next() );
2786 Iterator<HeapRegionNode> hrnAllItr = hrnAllPrior.iterator();
2787 while( hrnAllItr.hasNext() ) {
2788 HeapRegionNode hrn = hrnAllItr.next();
2790 if( !visited.contains( hrn ) ) {
2792 // heap region nodes are compared across ReachGraph
2793 // objects by their integer ID, so when discarding
2794 // garbage nodes we must also discard entries in
2795 // the ID -> heap region hashtable.
2796 id2hrn.remove( hrn.getID() );
2798 // RefEdge objects are two-way linked between
2799 // nodes, so when a node is identified as garbage,
2800 // actively clear references to and from it so
2801 // live nodes won't have dangling RefEdge's
2802 wipeOut( hrn, true );
2804 // if we just removed the last node from an allocation
2805 // site, it should be taken out of the ReachGraph's list
2806 AllocSite as = hrn.getAllocSite();
2807 if( !hasNodesOf( as ) ) {
2808 allocSites.remove( as );
2814 protected boolean hasNodesOf( AllocSite as ) {
2815 if( id2hrn.containsKey( as.getSummary() ) ) {
2819 for( int i = 0; i < allocationDepth; ++i ) {
2820 if( id2hrn.containsKey( as.getIthOldest( i ) ) ) {
2828 ////////////////////////////////////////////////////
2830 // This global sweep is an optional step to prune
2831 // reachability sets that are not internally
2832 // consistent with the global graph. It should be
2833 // invoked after strong updates or method calls.
2835 ////////////////////////////////////////////////////
2836 public void globalSweep() {
2838 // boldB is part of the phase 1 sweep
2839 // it has an in-context table and an out-of-context table
2840 Hashtable< Integer, Hashtable<RefEdge, ReachSet> > boldBic =
2841 new Hashtable< Integer, Hashtable<RefEdge, ReachSet> >();
2843 Hashtable< Integer, Hashtable<RefEdge, ReachSet> > boldBooc =
2844 new Hashtable< Integer, Hashtable<RefEdge, ReachSet> >();
2846 // visit every heap region to initialize alphaNew and betaNew,
2847 // and make a map of every hrnID to the source nodes it should
2848 // propagate forward from. In-context flagged hrnID's propagate
2849 // from only the in-context node they name, but out-of-context
2850 // ID's may propagate from several out-of-context nodes
2851 Hashtable< Integer, Set<HeapRegionNode> > icID2srcs =
2852 new Hashtable< Integer, Set<HeapRegionNode> >();
2854 Hashtable< Integer, Set<HeapRegionNode> > oocID2srcs =
2855 new Hashtable< Integer, Set<HeapRegionNode> >();
2858 Iterator itrHrns = id2hrn.entrySet().iterator();
2859 while( itrHrns.hasNext() ) {
2860 Map.Entry me = (Map.Entry) itrHrns.next();
2861 Integer hrnID = (Integer) me.getKey();
2862 HeapRegionNode hrn = (HeapRegionNode) me.getValue();
2864 // assert that this node and incoming edges have clean alphaNew
2865 // and betaNew sets, respectively
2866 assert rsetEmpty.equals( hrn.getAlphaNew() );
2868 Iterator<RefEdge> itrRers = hrn.iteratorToReferencers();
2869 while( itrRers.hasNext() ) {
2870 RefEdge edge = itrRers.next();
2871 assert rsetEmpty.equals( edge.getBetaNew() );
2874 // calculate boldB for this flagged node, or out-of-context node
2875 if( hrn.isFlagged() ) {
2876 assert !hrn.isOutOfContext();
2877 assert !icID2srcs.containsKey( hrn.getID() );
2878 Set<HeapRegionNode> srcs = new HashSet<HeapRegionNode>();
2880 icID2srcs.put( hrn.getID(), srcs );
2883 if( hrn.isOutOfContext() ) {
2884 assert !hrn.isFlagged();
2886 Iterator<ReachState> stateItr = hrn.getAlpha().iterator();
2887 while( stateItr.hasNext() ) {
2888 ReachState state = stateItr.next();
2890 Iterator<ReachTuple> rtItr = state.iterator();
2891 while( rtItr.hasNext() ) {
2892 ReachTuple rt = rtItr.next();
2893 assert rt.isOutOfContext();
2895 Set<HeapRegionNode> srcs = oocID2srcs.get( rt.getHrnID() );
2896 if( srcs == null ) {
2897 srcs = new HashSet<HeapRegionNode>();
2900 oocID2srcs.put( rt.getHrnID(), srcs );
2906 // calculate boldB for all hrnIDs identified by the above
2907 // node traversal, propagating from every source
2908 while( !icID2srcs.isEmpty() || !oocID2srcs.isEmpty() ) {
2911 Set<HeapRegionNode> srcs;
2914 if( !icID2srcs.isEmpty() ) {
2915 Map.Entry me = (Map.Entry) icID2srcs.entrySet().iterator().next();
2916 hrnID = (Integer) me.getKey();
2917 srcs = (Set<HeapRegionNode>) me.getValue();
2919 icID2srcs.remove( hrnID );
2922 assert !oocID2srcs.isEmpty();
2924 Map.Entry me = (Map.Entry) oocID2srcs.entrySet().iterator().next();
2925 hrnID = (Integer) me.getKey();
2926 srcs = (Set<HeapRegionNode>) me.getValue();
2928 oocID2srcs.remove( hrnID );
2932 Hashtable<RefEdge, ReachSet> boldB_f =
2933 new Hashtable<RefEdge, ReachSet>();
2935 Set<RefEdge> workSetEdges = new HashSet<RefEdge>();
2937 Iterator<HeapRegionNode> hrnItr = srcs.iterator();
2938 while( hrnItr.hasNext() ) {
2939 HeapRegionNode hrn = hrnItr.next();
2941 assert workSetEdges.isEmpty();
2943 // initial boldB_f constraints
2944 Iterator<RefEdge> itrRees = hrn.iteratorToReferencees();
2945 while( itrRees.hasNext() ) {
2946 RefEdge edge = itrRees.next();
2948 assert !boldB_f.containsKey( edge );
2949 boldB_f.put( edge, edge.getBeta() );
2951 assert !workSetEdges.contains( edge );
2952 workSetEdges.add( edge );
2955 // enforce the boldB_f constraint at edges until we reach a fixed point
2956 while( !workSetEdges.isEmpty() ) {
2957 RefEdge edge = workSetEdges.iterator().next();
2958 workSetEdges.remove( edge );
2960 Iterator<RefEdge> itrPrime = edge.getDst().iteratorToReferencees();
2961 while( itrPrime.hasNext() ) {
2962 RefEdge edgePrime = itrPrime.next();
2964 ReachSet prevResult = boldB_f.get( edgePrime );
2965 ReachSet intersection = Canonical.intersection( boldB_f.get( edge ),
2969 if( prevResult == null ||
2970 Canonical.unionORpreds( prevResult,
2971 intersection ).size()
2975 if( prevResult == null ) {
2976 boldB_f.put( edgePrime,
2977 Canonical.unionORpreds( edgePrime.getBeta(),
2982 boldB_f.put( edgePrime,
2983 Canonical.unionORpreds( prevResult,
2988 workSetEdges.add( edgePrime );
2995 boldBic.put( hrnID, boldB_f );
2997 boldBooc.put( hrnID, boldB_f );
3002 // use boldB to prune hrnIDs from alpha states that are impossible
3003 // and propagate the differences backwards across edges
3004 HashSet<RefEdge> edgesForPropagation = new HashSet<RefEdge>();
3006 Hashtable<RefEdge, ChangeSet> edgePlannedChanges =
3007 new Hashtable<RefEdge, ChangeSet>();
3010 itrHrns = id2hrn.entrySet().iterator();
3011 while( itrHrns.hasNext() ) {
3012 Map.Entry me = (Map.Entry) itrHrns.next();
3013 Integer hrnID = (Integer) me.getKey();
3014 HeapRegionNode hrn = (HeapRegionNode) me.getValue();
3016 // out-of-context nodes don't participate in the
3017 // global sweep, they serve as sources for the pass
3019 if( hrn.isOutOfContext() ) {
3023 // the inherent states of a region are the exception
3024 // to removal as the global sweep prunes
3025 ReachTuple rtException = ReachTuple.factory( hrnID,
3026 !hrn.isSingleObject(),
3027 ReachTuple.ARITY_ONE,
3028 false // out-of-context
3031 ChangeSet cts = ChangeSet.factory();
3033 // mark hrnIDs for removal
3034 Iterator<ReachState> stateItr = hrn.getAlpha().iterator();
3035 while( stateItr.hasNext() ) {
3036 ReachState stateOld = stateItr.next();
3038 ReachState markedHrnIDs = ReachState.factory();
3040 Iterator<ReachTuple> rtItr = stateOld.iterator();
3041 while( rtItr.hasNext() ) {
3042 ReachTuple rtOld = rtItr.next();
3044 // never remove the inherent hrnID from a flagged region
3045 // because it is trivially satisfied
3046 if( hrn.isFlagged() ) {
3047 if( rtOld == rtException ) {
3052 // does boldB allow this hrnID?
3053 boolean foundState = false;
3054 Iterator<RefEdge> incidentEdgeItr = hrn.iteratorToReferencers();
3055 while( incidentEdgeItr.hasNext() ) {
3056 RefEdge incidentEdge = incidentEdgeItr.next();
3058 Hashtable<RefEdge, ReachSet> B;
3059 if( rtOld.isOutOfContext() ) {
3060 B = boldBooc.get( rtOld.getHrnID() );
3062 assert id2hrn.containsKey( rtOld.getHrnID() );
3063 B = boldBic.get( rtOld.getHrnID() );
3067 ReachSet boldB_rtOld_incident = B.get( incidentEdge );
3068 if( boldB_rtOld_incident != null &&
3069 boldB_rtOld_incident.containsIgnorePreds( stateOld ) != null
3077 markedHrnIDs = Canonical.add( markedHrnIDs, rtOld );
3081 // if there is nothing marked, just move on
3082 if( markedHrnIDs.isEmpty() ) {
3083 hrn.setAlphaNew( Canonical.add( hrn.getAlphaNew(),
3090 // remove all marked hrnIDs and establish a change set that should
3091 // propagate backwards over edges from this node
3092 ReachState statePruned = ReachState.factory();
3093 rtItr = stateOld.iterator();
3094 while( rtItr.hasNext() ) {
3095 ReachTuple rtOld = rtItr.next();
3097 if( !markedHrnIDs.containsTuple( rtOld ) ) {
3098 statePruned = Canonical.add( statePruned, rtOld );
3101 assert !stateOld.equals( statePruned );
3103 hrn.setAlphaNew( Canonical.add( hrn.getAlphaNew(),
3107 ChangeTuple ct = ChangeTuple.factory( stateOld,
3110 cts = Canonical.add( cts, ct );
3113 // throw change tuple set on all incident edges
3114 if( !cts.isEmpty() ) {
3115 Iterator<RefEdge> incidentEdgeItr = hrn.iteratorToReferencers();
3116 while( incidentEdgeItr.hasNext() ) {
3117 RefEdge incidentEdge = incidentEdgeItr.next();
3119 edgesForPropagation.add( incidentEdge );
3121 if( edgePlannedChanges.get( incidentEdge ) == null ) {
3122 edgePlannedChanges.put( incidentEdge, cts );
3124 edgePlannedChanges.put(
3126 Canonical.union( edgePlannedChanges.get( incidentEdge ),
3135 HashSet<RefEdge> edgesUpdated = new HashSet<RefEdge>();
3137 propagateTokensOverEdges( edgesForPropagation,
3141 // at the end of the 1st phase reference edges have
3142 // beta, betaNew that correspond to beta and betaR
3144 // commit beta<-betaNew, so beta=betaR and betaNew
3145 // will represent the beta' calculation in 2nd phase
3147 // commit alpha<-alphaNew because it won't change
3148 HashSet<RefEdge> res = new HashSet<RefEdge>();
3150 Iterator<HeapRegionNode> nodeItr = id2hrn.values().iterator();
3151 while( nodeItr.hasNext() ) {
3152 HeapRegionNode hrn = nodeItr.next();
3154 // as mentioned above, out-of-context nodes only serve
3155 // as sources of reach states for the sweep, not part
3157 if( hrn.isOutOfContext() ) {
3158 assert hrn.getAlphaNew().equals( rsetEmpty );
3160 hrn.applyAlphaNew();
3163 Iterator<RefEdge> itrRes = hrn.iteratorToReferencers();
3164 while( itrRes.hasNext() ) {
3165 res.add( itrRes.next() );
3171 Iterator<RefEdge> edgeItr = res.iterator();
3172 while( edgeItr.hasNext() ) {
3173 RefEdge edge = edgeItr.next();
3174 HeapRegionNode hrn = edge.getDst();
3176 // commit results of last phase
3177 if( edgesUpdated.contains( edge ) ) {
3178 edge.applyBetaNew();
3181 // compute intial condition of 2nd phase
3182 edge.setBetaNew( Canonical.intersection( edge.getBeta(),
3188 // every edge in the graph is the initial workset
3189 Set<RefEdge> edgeWorkSet = (Set) res.clone();
3190 while( !edgeWorkSet.isEmpty() ) {
3191 RefEdge edgePrime = edgeWorkSet.iterator().next();
3192 edgeWorkSet.remove( edgePrime );
3194 RefSrcNode rsn = edgePrime.getSrc();
3195 if( !(rsn instanceof HeapRegionNode) ) {
3198 HeapRegionNode hrn = (HeapRegionNode) rsn;
3200 Iterator<RefEdge> itrEdge = hrn.iteratorToReferencers();
3201 while( itrEdge.hasNext() ) {
3202 RefEdge edge = itrEdge.next();
3204 ReachSet prevResult = edge.getBetaNew();
3205 assert prevResult != null;
3207 ReachSet intersection =
3208 Canonical.intersection( edge.getBeta(),
3209 edgePrime.getBetaNew()
3212 if( Canonical.unionORpreds( prevResult,
3219 Canonical.unionORpreds( prevResult,
3223 edgeWorkSet.add( edge );
3228 // commit beta' (beta<-betaNew)
3229 edgeItr = res.iterator();
3230 while( edgeItr.hasNext() ) {
3231 edgeItr.next().applyBetaNew();
3237 ////////////////////////////////////////////////////
3238 // high-level merge operations
3239 ////////////////////////////////////////////////////
3240 public void merge_sameMethodContext( ReachGraph rg ) {
3241 // when merging two graphs that abstract the heap
3242 // of the same method context, we just call the
3243 // basic merge operation
3247 public void merge_diffMethodContext( ReachGraph rg ) {
3248 // when merging graphs for abstract heaps in
3249 // different method contexts we should:
3250 // 1) age the allocation sites?
3254 ////////////////////////////////////////////////////
3255 // in merge() and equals() methods the suffix A
3256 // represents the passed in graph and the suffix
3257 // B refers to the graph in this object
3258 // Merging means to take the incoming graph A and
3259 // merge it into B, so after the operation graph B
3260 // is the final result.
3261 ////////////////////////////////////////////////////
3262 protected void merge( ReachGraph rg ) {
3269 mergeRefEdges ( rg );
3270 mergeAllocSites( rg );
3273 protected void mergeNodes( ReachGraph rg ) {
3275 // start with heap region nodes
3276 Set sA = rg.id2hrn.entrySet();
3277 Iterator iA = sA.iterator();
3278 while( iA.hasNext() ) {
3279 Map.Entry meA = (Map.Entry) iA.next();
3280 Integer idA = (Integer) meA.getKey();
3281 HeapRegionNode hrnA = (HeapRegionNode) meA.getValue();
3283 // if this graph doesn't have a node the
3284 // incoming graph has, allocate it
3285 if( !id2hrn.containsKey( idA ) ) {
3286 HeapRegionNode hrnB = hrnA.copy();
3287 id2hrn.put( idA, hrnB );
3290 // otherwise this is a node present in both graphs
3291 // so make the new reachability set a union of the
3292 // nodes' reachability sets
3293 HeapRegionNode hrnB = id2hrn.get( idA );
3294 hrnB.setAlpha( Canonical.unionORpreds( hrnB.getAlpha(),
3299 hrnB.setPreds( Canonical.join( hrnB.getPreds(),
3306 // now add any variable nodes that are in graph B but
3308 sA = rg.td2vn.entrySet();
3310 while( iA.hasNext() ) {
3311 Map.Entry meA = (Map.Entry) iA.next();
3312 TempDescriptor tdA = (TempDescriptor) meA.getKey();
3313 VariableNode lnA = (VariableNode) meA.getValue();
3315 // if the variable doesn't exist in B, allocate and add it
3316 VariableNode lnB = getVariableNodeFromTemp( tdA );
3320 protected void mergeRefEdges( ReachGraph rg ) {
3322 // between heap regions
3323 Set sA = rg.id2hrn.entrySet();
3324 Iterator iA = sA.iterator();
3325 while( iA.hasNext() ) {
3326 Map.Entry meA = (Map.Entry) iA.next();
3327 Integer idA = (Integer) meA.getKey();
3328 HeapRegionNode hrnA = (HeapRegionNode) meA.getValue();
3330 Iterator<RefEdge> heapRegionsItrA = hrnA.iteratorToReferencees();
3331 while( heapRegionsItrA.hasNext() ) {
3332 RefEdge edgeA = heapRegionsItrA.next();
3333 HeapRegionNode hrnChildA = edgeA.getDst();
3334 Integer idChildA = hrnChildA.getID();
3336 // at this point we know an edge in graph A exists
3337 // idA -> idChildA, does this exist in B?
3338 assert id2hrn.containsKey( idA );
3339 HeapRegionNode hrnB = id2hrn.get( idA );
3340 RefEdge edgeToMerge = null;
3342 Iterator<RefEdge> heapRegionsItrB = hrnB.iteratorToReferencees();
3343 while( heapRegionsItrB.hasNext() &&
3344 edgeToMerge == null ) {
3346 RefEdge edgeB = heapRegionsItrB.next();
3347 HeapRegionNode hrnChildB = edgeB.getDst();
3348 Integer idChildB = hrnChildB.getID();
3350 // don't use the RefEdge.equals() here because
3351 // we're talking about existence between graphs,
3352 // not intragraph equal
3353 if( idChildB.equals( idChildA ) &&
3354 edgeB.typeAndFieldEquals( edgeA ) ) {
3356 edgeToMerge = edgeB;
3360 // if the edge from A was not found in B,
3362 if( edgeToMerge == null ) {
3363 assert id2hrn.containsKey( idChildA );
3364 HeapRegionNode hrnChildB = id2hrn.get( idChildA );
3365 edgeToMerge = edgeA.copy();
3366 edgeToMerge.setSrc( hrnB );
3367 edgeToMerge.setDst( hrnChildB );
3368 addRefEdge( hrnB, hrnChildB, edgeToMerge );
3370 // otherwise, the edge already existed in both graphs
3371 // so merge their reachability sets
3373 // just replace this beta set with the union
3374 assert edgeToMerge != null;
3375 edgeToMerge.setBeta(
3376 Canonical.unionORpreds( edgeToMerge.getBeta(),
3380 edgeToMerge.setPreds(
3381 Canonical.join( edgeToMerge.getPreds(),
3389 // and then again from variable nodes
3390 sA = rg.td2vn.entrySet();
3392 while( iA.hasNext() ) {
3393 Map.Entry meA = (Map.Entry) iA.next();
3394 TempDescriptor tdA = (TempDescriptor) meA.getKey();
3395 VariableNode vnA = (VariableNode) meA.getValue();
3397 Iterator<RefEdge> heapRegionsItrA = vnA.iteratorToReferencees();
3398 while( heapRegionsItrA.hasNext() ) {
3399 RefEdge edgeA = heapRegionsItrA.next();
3400 HeapRegionNode hrnChildA = edgeA.getDst();
3401 Integer idChildA = hrnChildA.getID();
3403 // at this point we know an edge in graph A exists
3404 // tdA -> idChildA, does this exist in B?
3405 assert td2vn.containsKey( tdA );
3406 VariableNode vnB = td2vn.get( tdA );
3407 RefEdge edgeToMerge = null;
3409 Iterator<RefEdge> heapRegionsItrB = vnB.iteratorToReferencees();
3410 while( heapRegionsItrB.hasNext() &&
3411 edgeToMerge == null ) {
3413 RefEdge edgeB = heapRegionsItrB.next();
3414 HeapRegionNode hrnChildB = edgeB.getDst();
3415 Integer idChildB = hrnChildB.getID();
3417 // don't use the RefEdge.equals() here because
3418 // we're talking about existence between graphs
3419 if( idChildB.equals( idChildA ) &&
3420 edgeB.typeAndFieldEquals( edgeA ) ) {
3422 edgeToMerge = edgeB;
3426 // if the edge from A was not found in B,
3428 if( edgeToMerge == null ) {
3429 assert id2hrn.containsKey( idChildA );
3430 HeapRegionNode hrnChildB = id2hrn.get( idChildA );
3431 edgeToMerge = edgeA.copy();
3432 edgeToMerge.setSrc( vnB );
3433 edgeToMerge.setDst( hrnChildB );
3434 addRefEdge( vnB, hrnChildB, edgeToMerge );
3436 // otherwise, the edge already existed in both graphs
3437 // so merge their reachability sets
3439 // just replace this beta set with the union
3440 edgeToMerge.setBeta( Canonical.unionORpreds( edgeToMerge.getBeta(),
3444 edgeToMerge.setPreds( Canonical.join( edgeToMerge.getPreds(),
3453 protected void mergeAllocSites( ReachGraph rg ) {
3454 allocSites.addAll( rg.allocSites );
3458 // it is necessary in the equals() member functions
3459 // to "check both ways" when comparing the data
3460 // structures of two graphs. For instance, if all
3461 // edges between heap region nodes in graph A are
3462 // present and equal in graph B it is not sufficient
3463 // to say the graphs are equal. Consider that there
3464 // may be edges in graph B that are not in graph A.
3465 // the only way to know that all edges in both graphs
3466 // are equally present is to iterate over both data
3467 // structures and compare against the other graph.
3468 public boolean equals( ReachGraph rg ) {
3474 if( !areHeapRegionNodesEqual( rg ) ) {
3478 if( !areVariableNodesEqual( rg ) ) {
3482 if( !areRefEdgesEqual( rg ) ) {
3486 // if everything is equal up to this point,
3487 // assert that allocSites is also equal--
3488 // this data is redundant but kept for efficiency
3489 assert allocSites.equals( rg.allocSites );
3495 protected boolean areHeapRegionNodesEqual( ReachGraph rg ) {
3497 if( !areallHRNinAalsoinBandequal( this, rg ) ) {
3501 if( !areallHRNinAalsoinBandequal( rg, this ) ) {
3508 static protected boolean areallHRNinAalsoinBandequal( ReachGraph rgA,
3510 Set sA = rgA.id2hrn.entrySet();
3511 Iterator iA = sA.iterator();
3512 while( iA.hasNext() ) {
3513 Map.Entry meA = (Map.Entry) iA.next();
3514 Integer idA = (Integer) meA.getKey();
3515 HeapRegionNode hrnA = (HeapRegionNode) meA.getValue();
3517 if( !rgB.id2hrn.containsKey( idA ) ) {
3521 HeapRegionNode hrnB = rgB.id2hrn.get( idA );
3522 if( !hrnA.equalsIncludingAlphaAndPreds( hrnB ) ) {
3531 protected boolean areVariableNodesEqual( ReachGraph rg ) {
3533 if( !areallVNinAalsoinBandequal( this, rg ) ) {
3537 if( !areallVNinAalsoinBandequal( rg, this ) ) {
3544 static protected boolean areallVNinAalsoinBandequal( ReachGraph rgA,
3546 Set sA = rgA.td2vn.entrySet();
3547 Iterator iA = sA.iterator();
3548 while( iA.hasNext() ) {
3549 Map.Entry meA = (Map.Entry) iA.next();
3550 TempDescriptor tdA = (TempDescriptor) meA.getKey();
3552 if( !rgB.td2vn.containsKey( tdA ) ) {
3561 protected boolean areRefEdgesEqual( ReachGraph rg ) {
3562 if( !areallREinAandBequal( this, rg ) ) {
3569 static protected boolean areallREinAandBequal( ReachGraph rgA,
3572 // check all the heap region->heap region edges
3573 Set sA = rgA.id2hrn.entrySet();
3574 Iterator iA = sA.iterator();
3575 while( iA.hasNext() ) {
3576 Map.Entry meA = (Map.Entry) iA.next();
3577 Integer idA = (Integer) meA.getKey();
3578 HeapRegionNode hrnA = (HeapRegionNode) meA.getValue();
3580 // we should have already checked that the same
3581 // heap regions exist in both graphs
3582 assert rgB.id2hrn.containsKey( idA );
3584 if( !areallREfromAequaltoB( rgA, hrnA, rgB ) ) {
3588 // then check every edge in B for presence in A, starting
3589 // from the same parent HeapRegionNode
3590 HeapRegionNode hrnB = rgB.id2hrn.get( idA );
3592 if( !areallREfromAequaltoB( rgB, hrnB, rgA ) ) {
3597 // then check all the variable->heap region edges
3598 sA = rgA.td2vn.entrySet();
3600 while( iA.hasNext() ) {
3601 Map.Entry meA = (Map.Entry) iA.next();
3602 TempDescriptor tdA = (TempDescriptor) meA.getKey();
3603 VariableNode vnA = (VariableNode) meA.getValue();
3605 // we should have already checked that the same
3606 // label nodes exist in both graphs
3607 assert rgB.td2vn.containsKey( tdA );
3609 if( !areallREfromAequaltoB( rgA, vnA, rgB ) ) {
3613 // then check every edge in B for presence in A, starting
3614 // from the same parent VariableNode
3615 VariableNode vnB = rgB.td2vn.get( tdA );
3617 if( !areallREfromAequaltoB( rgB, vnB, rgA ) ) {
3626 static protected boolean areallREfromAequaltoB( ReachGraph rgA,
3630 Iterator<RefEdge> itrA = rnA.iteratorToReferencees();
3631 while( itrA.hasNext() ) {
3632 RefEdge edgeA = itrA.next();
3633 HeapRegionNode hrnChildA = edgeA.getDst();
3634 Integer idChildA = hrnChildA.getID();
3636 assert rgB.id2hrn.containsKey( idChildA );
3638 // at this point we know an edge in graph A exists
3639 // rnA -> idChildA, does this exact edge exist in B?
3640 boolean edgeFound = false;
3642 RefSrcNode rnB = null;
3643 if( rnA instanceof HeapRegionNode ) {
3644 HeapRegionNode hrnA = (HeapRegionNode) rnA;
3645 rnB = rgB.id2hrn.get( hrnA.getID() );
3647 VariableNode vnA = (VariableNode) rnA;
3648 rnB = rgB.td2vn.get( vnA.getTempDescriptor() );
3651 Iterator<RefEdge> itrB = rnB.iteratorToReferencees();
3652 while( itrB.hasNext() ) {
3653 RefEdge edgeB = itrB.next();
3654 HeapRegionNode hrnChildB = edgeB.getDst();
3655 Integer idChildB = hrnChildB.getID();
3657 if( idChildA.equals( idChildB ) &&
3658 edgeA.typeAndFieldEquals( edgeB ) ) {
3660 // there is an edge in the right place with the right field,
3661 // but do they have the same attributes?
3662 if( edgeA.getBeta().equals( edgeB.getBeta() ) &&
3663 edgeA.equalsPreds( edgeB )
3680 // this analysis no longer has the "match anything"
3681 // type which was represented by null
3682 protected TypeDescriptor mostSpecificType( TypeDescriptor td1,
3683 TypeDescriptor td2 ) {
3687 if( td1.isNull() ) {
3690 if( td2.isNull() ) {
3693 return typeUtil.mostSpecific( td1, td2 );
3696 protected TypeDescriptor mostSpecificType( TypeDescriptor td1,
3698 TypeDescriptor td3 ) {
3700 return mostSpecificType( td1,
3701 mostSpecificType( td2, td3 )
3705 protected TypeDescriptor mostSpecificType( TypeDescriptor td1,
3708 TypeDescriptor td4 ) {
3710 return mostSpecificType( mostSpecificType( td1, td2 ),
3711 mostSpecificType( td3, td4 )
3715 protected boolean isSuperiorType( TypeDescriptor possibleSuper,
3716 TypeDescriptor possibleChild ) {
3717 assert possibleSuper != null;
3718 assert possibleChild != null;
3720 if( possibleSuper.isNull() ||
3721 possibleChild.isNull() ) {
3725 return typeUtil.isSuperorType( possibleSuper, possibleChild );
3729 protected boolean hasMatchingField( HeapRegionNode src,
3732 TypeDescriptor tdSrc = src.getType();
3733 assert tdSrc != null;
3735 if( tdSrc.isArray() ) {
3736 TypeDescriptor td = edge.getType();
3739 TypeDescriptor tdSrcDeref = tdSrc.dereference();
3740 assert tdSrcDeref != null;
3742 if( !typeUtil.isSuperorType( tdSrcDeref, td ) ) {
3746 return edge.getField().equals( DisjointAnalysis.arrayElementFieldName );
3749 // if it's not a class, it doesn't have any fields to match
3750 if( !tdSrc.isClass() ) {
3754 ClassDescriptor cd = tdSrc.getClassDesc();
3755 while( cd != null ) {
3756 Iterator fieldItr = cd.getFields();
3758 while( fieldItr.hasNext() ) {
3759 FieldDescriptor fd = (FieldDescriptor) fieldItr.next();
3761 if( fd.getType().equals( edge.getType() ) &&
3762 fd.getSymbol().equals( edge.getField() ) ) {
3767 cd = cd.getSuperDesc();
3770 // otherwise it is a class with fields
3771 // but we didn't find a match
3775 protected boolean hasMatchingType( RefEdge edge,
3776 HeapRegionNode dst ) {
3778 // if the region has no type, matches everything
3779 TypeDescriptor tdDst = dst.getType();
3780 assert tdDst != null;
3782 // if the type is not a class or an array, don't
3783 // match because primitives are copied, no aliases
3784 ClassDescriptor cdDst = tdDst.getClassDesc();
3785 if( cdDst == null && !tdDst.isArray() ) {
3789 // if the edge type is null, it matches everything
3790 TypeDescriptor tdEdge = edge.getType();
3791 assert tdEdge != null;
3793 return typeUtil.isSuperorType( tdEdge, tdDst );
3798 public void writeGraph( String graphName,
3799 boolean writeLabels,
3800 boolean labelSelect,
3801 boolean pruneGarbage,
3802 boolean hideSubsetReachability,
3803 boolean hideEdgeTaints
3804 ) throws java.io.IOException {
3805 writeGraph( graphName,
3809 hideSubsetReachability,
3814 public void writeGraph( String graphName,
3815 boolean writeLabels,
3816 boolean labelSelect,
3817 boolean pruneGarbage,
3818 boolean hideSubsetReachability,
3819 boolean hideEdgeTaints,
3820 Set<Integer> callerNodeIDsCopiedToCallee
3821 ) throws java.io.IOException {
3823 // remove all non-word characters from the graph name so
3824 // the filename and identifier in dot don't cause errors
3825 graphName = graphName.replaceAll( "[\\W]", "" );
3828 new BufferedWriter( new FileWriter( graphName+".dot" ) );
3830 bw.write( "digraph "+graphName+" {\n" );
3833 // this is an optional step to form the callee-reachable
3834 // "cut-out" into a DOT cluster for visualization
3835 if( callerNodeIDsCopiedToCallee != null ) {
3837 bw.write( " subgraph cluster0 {\n" );
3838 bw.write( " color=blue;\n" );
3840 Iterator i = id2hrn.entrySet().iterator();
3841 while( i.hasNext() ) {
3842 Map.Entry me = (Map.Entry) i.next();
3843 HeapRegionNode hrn = (HeapRegionNode) me.getValue();
3845 if( callerNodeIDsCopiedToCallee.contains( hrn.getID() ) ) {
3846 bw.write( " "+hrn.toString()+
3847 hrn.toStringDOT( hideSubsetReachability )+
3857 Set<HeapRegionNode> visited = new HashSet<HeapRegionNode>();
3859 // then visit every heap region node
3860 Iterator i = id2hrn.entrySet().iterator();
3861 while( i.hasNext() ) {
3862 Map.Entry me = (Map.Entry) i.next();
3863 HeapRegionNode hrn = (HeapRegionNode) me.getValue();
3865 // only visit nodes worth writing out--for instance
3866 // not every node at an allocation is referenced
3867 // (think of it as garbage-collected), etc.
3868 if( !pruneGarbage ||
3869 hrn.isOutOfContext()
3872 if( !visited.contains( hrn ) ) {
3873 traverseHeapRegionNodes( hrn,
3877 hideSubsetReachability,
3879 callerNodeIDsCopiedToCallee );
3884 bw.write( " graphTitle[label=\""+graphName+"\",shape=box];\n" );
3887 // then visit every label node, useful for debugging
3889 i = td2vn.entrySet().iterator();
3890 while( i.hasNext() ) {
3891 Map.Entry me = (Map.Entry) i.next();
3892 VariableNode vn = (VariableNode) me.getValue();
3895 String labelStr = vn.getTempDescriptorString();
3896 if( labelStr.startsWith( "___temp" ) ||
3897 labelStr.startsWith( "___dst" ) ||
3898 labelStr.startsWith( "___srctmp" ) ||
3899 labelStr.startsWith( "___neverused" )
3905 Iterator<RefEdge> heapRegionsItr = vn.iteratorToReferencees();
3906 while( heapRegionsItr.hasNext() ) {
3907 RefEdge edge = heapRegionsItr.next();
3908 HeapRegionNode hrn = edge.getDst();
3910 if( !visited.contains( hrn ) ) {
3911 traverseHeapRegionNodes( hrn,
3915 hideSubsetReachability,
3917 callerNodeIDsCopiedToCallee );
3920 bw.write( " "+vn.toString()+
3921 " -> "+hrn.toString()+
3922 edge.toStringDOT( hideSubsetReachability, "" )+
3932 protected void traverseHeapRegionNodes( HeapRegionNode hrn,
3935 Set<HeapRegionNode> visited,
3936 boolean hideSubsetReachability,
3937 boolean hideEdgeTaints,
3938 Set<Integer> callerNodeIDsCopiedToCallee
3939 ) throws java.io.IOException {
3941 if( visited.contains( hrn ) ) {
3946 // if we're drawing the callee-view subgraph, only
3947 // write out the node info if it hasn't already been
3949 if( callerNodeIDsCopiedToCallee == null ||
3950 !callerNodeIDsCopiedToCallee.contains( hrn.getID() )
3952 bw.write( " "+hrn.toString()+
3953 hrn.toStringDOT( hideSubsetReachability )+
3957 Iterator<RefEdge> childRegionsItr = hrn.iteratorToReferencees();
3958 while( childRegionsItr.hasNext() ) {
3959 RefEdge edge = childRegionsItr.next();
3960 HeapRegionNode hrnChild = edge.getDst();
3962 if( callerNodeIDsCopiedToCallee != null &&
3963 (edge.getSrc() instanceof HeapRegionNode) ) {
3964 HeapRegionNode hrnSrc = (HeapRegionNode) edge.getSrc();
3965 if( callerNodeIDsCopiedToCallee.contains( hrnSrc.getID() ) &&
3966 callerNodeIDsCopiedToCallee.contains( edge.getDst().getID() )
3968 bw.write( " "+hrn.toString()+
3969 " -> "+hrnChild.toString()+
3970 edge.toStringDOT( hideSubsetReachability, ",color=blue" )+
3972 } else if( !callerNodeIDsCopiedToCallee.contains( hrnSrc.getID() ) &&
3973 callerNodeIDsCopiedToCallee.contains( edge.getDst().getID() )
3975 bw.write( " "+hrn.toString()+
3976 " -> "+hrnChild.toString()+
3977 edge.toStringDOT( hideSubsetReachability, ",color=blue,style=dashed" )+
3980 bw.write( " "+hrn.toString()+
3981 " -> "+hrnChild.toString()+
3982 edge.toStringDOT( hideSubsetReachability, "" )+
3986 bw.write( " "+hrn.toString()+
3987 " -> "+hrnChild.toString()+
3988 edge.toStringDOT( hideSubsetReachability, "" )+
3992 traverseHeapRegionNodes( hrnChild,
3996 hideSubsetReachability,
3998 callerNodeIDsCopiedToCallee );
4002 public Set<HeapRegionNode> findCommonReachableNodes(HeapRegionNode hrn1,
4003 HeapRegionNode hrn2) {
4005 Set<HeapRegionNode> reachableNodes1 = new HashSet<HeapRegionNode>();
4006 Set<HeapRegionNode> reachableNodes2 = new HashSet<HeapRegionNode>();
4008 Set<HeapRegionNode> todoNodes1 = new HashSet<HeapRegionNode>();
4009 todoNodes1.add(hrn1);
4011 Set<HeapRegionNode> todoNodes2 = new HashSet<HeapRegionNode>();
4012 todoNodes2.add(hrn2);
4014 // follow links until all reachable nodes have been found
4015 while (!todoNodes1.isEmpty()) {
4016 HeapRegionNode hrn = todoNodes1.iterator().next();
4017 todoNodes1.remove(hrn);
4018 reachableNodes1.add(hrn);
4020 Iterator<RefEdge> edgeItr = hrn.iteratorToReferencees();
4021 while (edgeItr.hasNext()) {
4022 RefEdge edge = edgeItr.next();
4024 if (!reachableNodes1.contains(edge.getDst())) {
4025 todoNodes1.add(edge.getDst());
4030 while (!todoNodes2.isEmpty()) {
4031 HeapRegionNode hrn = todoNodes2.iterator().next();
4032 todoNodes2.remove(hrn);
4033 reachableNodes2.add(hrn);
4035 Iterator<RefEdge> edgeItr = hrn.iteratorToReferencees();
4036 while (edgeItr.hasNext()) {
4037 RefEdge edge = edgeItr.next();
4039 if (!reachableNodes2.contains(edge.getDst())) {
4040 todoNodes2.add(edge.getDst());
4045 Set<HeapRegionNode> intersection =
4046 new HashSet<HeapRegionNode>( reachableNodes1 );
4048 intersection.retainAll( reachableNodes2 );
4050 return intersection;
4053 public Set<HeapRegionNode> mayReachSharedObjects(HeapRegionNode hrn1,
4054 HeapRegionNode hrn2) {
4055 assert hrn1 != null;
4056 assert hrn2 != null;
4058 // then get the various tokens for these heap regions
4059 ReachTuple h1 = ReachTuple.factory(hrn1.getID(),
4060 !hrn1.isSingleObject(), ReachTuple.ARITY_ONE, false);
4063 if(hrn1.isSingleObject){
4064 arity=ReachTuple.ARITY_ONE;
4066 arity=ReachTuple.ARITY_ZEROORMORE;
4068 ReachTuple h1star = ReachTuple.factory(hrn1.getID(), !hrn1
4069 .isSingleObject(), arity, false);
4071 ReachTuple h2 = ReachTuple.factory(hrn2.getID(),
4072 !hrn2.isSingleObject(), ReachTuple.ARITY_ONE, false);
4074 if(hrn2.isSingleObject){
4075 arity=ReachTuple.ARITY_ONE;
4077 arity=ReachTuple.ARITY_ZEROORMORE;
4080 ReachTuple h2star = ReachTuple.factory(hrn2.getID(), !hrn2
4081 .isSingleObject(), arity, false);
4083 // then get the merged beta of all out-going edges from these heap
4086 ReachSet beta1 = ReachSet.factory();
4087 Iterator<RefEdge> itrEdge = hrn1.iteratorToReferencees();
4088 while (itrEdge.hasNext()) {
4089 RefEdge edge = itrEdge.next();
4090 beta1 = Canonical.unionORpreds(beta1, edge.getBeta());
4093 ReachSet beta2 = ReachSet.factory();
4094 itrEdge = hrn2.iteratorToReferencees();
4095 while (itrEdge.hasNext()) {
4096 RefEdge edge = itrEdge.next();
4097 beta2 = Canonical.unionORpreds(beta2, edge.getBeta());
4100 boolean aliasDetected = false;
4102 // only do this one if they are different tokens
4103 if (h1 != h2 && beta1.containsStateWithBoth(h1, h2)) {
4104 aliasDetected = true;
4106 // if (beta1.containsStateWithBoth(h1plus, h2)) {
4107 // aliasDetected = true;
4109 if (beta1.containsStateWithBoth(h1star, h2)) {
4110 aliasDetected = true;
4112 // if (beta1.containsStateWithBoth(h1, h2plus)) {
4113 // aliasDetected = true;
4115 // if (beta1.containsStateWithBoth(h1plus, h2plus)) {
4116 // aliasDetected = true;
4118 // if (beta1.containsStateWithBoth(h1star, h2plus)) {
4119 // aliasDetected = true;
4121 if (beta1.containsStateWithBoth(h1, h2star)) {
4122 aliasDetected = true;
4124 // if (beta1.containsStateWithBoth(h1plus, h2star)) {
4125 // aliasDetected = true;
4127 if (beta1.containsStateWithBoth(h1star, h2star)) {
4128 aliasDetected = true;
4131 if (h1 != h2 && beta2.containsStateWithBoth(h1, h2)) {
4132 aliasDetected = true;
4134 // if (beta2.containsStateWithBoth(h1plus, h2)) {
4135 // aliasDetected = true;
4137 if (beta2.containsStateWithBoth(h1star, h2)) {
4138 aliasDetected = true;
4140 // if (beta2.containsStateWithBoth(h1, h2plus)) {
4141 // aliasDetected = true;
4143 // if (beta2.containsStateWithBoth(h1plus, h2plus)) {
4144 // aliasDetected = true;
4146 // if (beta2.containsStateWithBoth(h1star, h2plus)) {
4147 // aliasDetected = true;
4149 if (beta2.containsStateWithBoth(h1, h2star)) {
4150 aliasDetected = true;
4152 // if (beta2.containsStateWithBoth(h1plus, h2star)) {
4153 // aliasDetected = true;
4155 if (beta2.containsStateWithBoth(h1star, h2star)) {
4156 aliasDetected = true;
4159 Set<HeapRegionNode> common = new HashSet<HeapRegionNode>();
4160 if (aliasDetected) {
4161 common = findCommonReachableNodes(hrn1, hrn2);
4162 if (!(DISABLE_STRONG_UPDATES || DISABLE_GLOBAL_SWEEP)) {
4163 assert !common.isEmpty();
4170 public Set<HeapRegionNode> mayReachSharedObjects(FlatMethod fm,
4171 Integer paramIndex1, Integer paramIndex2) {
4173 // get parameter's heap regions
4174 TempDescriptor paramTemp1 = fm.getParameter(paramIndex1.intValue());
4175 VariableNode argVar1 = getVariableNodeFromTemp(paramTemp1);
4176 RefEdge argEdge1 = argVar1.iteratorToReferencees().next();
4177 HeapRegionNode hrnParam1 = argEdge1.getDst();
4179 TempDescriptor paramTemp2 = fm.getParameter(paramIndex2.intValue());
4180 VariableNode argVar2 = getVariableNodeFromTemp(paramTemp2);
4181 RefEdge argEdge2 = argVar2.iteratorToReferencees().next();
4182 HeapRegionNode hrnParam2 = argEdge2.getDst();
4184 Set<HeapRegionNode> common = new HashSet<HeapRegionNode>();
4185 common.addAll(mayReachSharedObjects(hrnParam1, hrnParam2));
4190 public Set<HeapRegionNode> mayReachSharedObjects(FlatMethod fm,
4191 Integer paramIndex, AllocSite as) {
4193 // get parameter's heap regions
4194 TempDescriptor paramTemp = fm.getParameter(paramIndex.intValue());
4195 VariableNode argVar = getVariableNodeFromTemp(paramTemp);
4196 RefEdge argEdge = argVar.iteratorToReferencees().next();
4197 HeapRegionNode hrnParam = argEdge.getDst();
4200 HeapRegionNode hrnSummary=null;
4201 if(id2hrn.containsKey(as.getSummary())){
4202 // if summary node doesn't exist, ignore this case
4203 hrnSummary = id2hrn.get(as.getSummary());
4204 assert hrnSummary != null;
4207 Set<HeapRegionNode> common = new HashSet<HeapRegionNode>();
4208 if(hrnSummary!=null){
4209 common.addAll( mayReachSharedObjects(hrnParam, hrnSummary) );
4212 // check for other nodes
4213 for (int i = 0; i < as.getAllocationDepth(); ++i) {
4215 assert id2hrn.containsKey(as.getIthOldest(i));
4216 HeapRegionNode hrnIthOldest = id2hrn.get(as.getIthOldest(i));
4217 assert hrnIthOldest != null;
4219 common.addAll(mayReachSharedObjects(hrnParam, hrnIthOldest));
4226 public Set<HeapRegionNode> mayReachSharedObjects(AllocSite as1,
4229 // get summary node 1's alpha
4230 Integer idSum1 = as1.getSummary();
4231 HeapRegionNode hrnSum1=null;
4232 if(id2hrn.containsKey(idSum1)){
4233 hrnSum1 = id2hrn.get(idSum1);
4236 // get summary node 2's alpha
4237 Integer idSum2 = as2.getSummary();
4238 HeapRegionNode hrnSum2=null;
4239 if(id2hrn.containsKey(idSum2)){
4240 hrnSum2 = id2hrn.get(idSum2);
4243 Set<HeapRegionNode> common = new HashSet<HeapRegionNode>();
4244 if(hrnSum1!=null && hrnSum2!=null){
4245 common.addAll(mayReachSharedObjects(hrnSum1, hrnSum2));
4248 // check sum2 against alloc1 nodes
4250 for (int i = 0; i < as1.getAllocationDepth(); ++i) {
4251 Integer idI1 = as1.getIthOldest(i);
4252 assert id2hrn.containsKey(idI1);
4253 HeapRegionNode hrnI1 = id2hrn.get(idI1);
4254 assert hrnI1 != null;
4255 common.addAll(mayReachSharedObjects(hrnI1, hrnSum2));
4259 // check sum1 against alloc2 nodes
4260 for (int i = 0; i < as2.getAllocationDepth(); ++i) {
4261 Integer idI2 = as2.getIthOldest(i);
4262 assert id2hrn.containsKey(idI2);
4263 HeapRegionNode hrnI2 = id2hrn.get(idI2);
4264 assert hrnI2 != null;
4267 common.addAll(mayReachSharedObjects(hrnSum1, hrnI2));
4270 // while we're at it, do an inner loop for alloc2 vs alloc1 nodes
4271 for (int j = 0; j < as1.getAllocationDepth(); ++j) {
4272 Integer idI1 = as1.getIthOldest(j);
4274 // if these are the same site, don't look for the same token, no
4276 // different tokens of the same site could alias together though
4277 if (idI1.equals(idI2)) {
4281 HeapRegionNode hrnI1 = id2hrn.get(idI1);
4283 common.addAll(mayReachSharedObjects(hrnI1, hrnI2));