1 package Analysis.Disjoint;
5 import Util.UtilAlgorithms;
9 public class ReachGraph {
11 protected static final TempDescriptor tdReturn = new TempDescriptor( "_Return___" );
13 // some frequently used reachability constants
14 protected static final ReachState rstateEmpty = new ReachState().makeCanonical();
15 protected static final ReachSet rsetEmpty = new ReachSet().makeCanonical();
16 protected static final ReachSet rsetWithEmptyState = new ReachSet( rstateEmpty ).makeCanonical();
18 public Hashtable<Integer, HeapRegionNode> id2hrn;
19 public Hashtable<TempDescriptor, VariableNode > td2vn;
21 public HashSet<AllocSite> allocSites;
23 // this is kept to allow edges created from variables (a src and dst)
24 // to know the access paths that allowed it, to prune edges when
25 // mapping them back into the caller--an access path must appear
26 public Hashtable< TempDescriptor, Set<AccessPath> > temp2accessPaths;
29 // use to disable improvements for comparison
30 protected static final boolean DISABLE_STRONG_UPDATES = false;
31 protected static final boolean DISABLE_GLOBAL_SWEEP = true;
33 protected static int allocationDepth = -1;
34 protected static TypeUtil typeUtil = null;
35 protected static boolean debugCallMap = false;
36 protected static int debugCallMapCount = 0;
37 protected static String debugCallee = null;
38 protected static String debugCaller = null;
42 id2hrn = new Hashtable<Integer, HeapRegionNode>();
43 td2vn = new Hashtable<TempDescriptor, VariableNode >();
45 allocSites = new HashSet<AllocSite>();
48 new Hashtable< TempDescriptor, Set<AccessPath> >();
52 // temp descriptors are globally unique and maps to
53 // exactly one variable node, easy
54 protected VariableNode getVariableNodeFromTemp( TempDescriptor td ) {
57 if( !td2vn.containsKey( td ) ) {
58 td2vn.put( td, new VariableNode( td ) );
61 return td2vn.get( td );
64 public boolean hasVariable( TempDescriptor td ) {
65 return td2vn.containsKey( td );
69 // the reason for this method is to have the option
70 // of creating new heap regions with specific IDs, or
71 // duplicating heap regions with specific IDs (especially
72 // in the merge() operation) or to create new heap
73 // regions with a new unique ID
74 protected HeapRegionNode
75 createNewHeapRegionNode( Integer id,
76 boolean isSingleObject,
87 boolean markForAnalysis = isFlagged;
89 TypeDescriptor typeToUse = null;
90 if( allocSite != null ) {
91 typeToUse = allocSite.getType();
92 allocSites.add( allocSite );
97 if( allocSite != null && allocSite.getDisjointAnalysisId() != null ) {
98 markForAnalysis = true;
102 id = DisjointAnalysis.generateUniqueHeapRegionNodeID();
105 if( inherent == null ) {
106 if( markForAnalysis ) {
107 inherent = new ReachSet(
114 inherent = rsetWithEmptyState;
118 if( alpha == null ) {
122 HeapRegionNode hrn = new HeapRegionNode( id,
132 id2hrn.put( id, hrn );
138 ////////////////////////////////////////////////
140 // Low-level referencee and referencer methods
142 // These methods provide the lowest level for
143 // creating references between reachability nodes
144 // and handling the details of maintaining both
145 // list of referencers and referencees.
147 ////////////////////////////////////////////////
148 protected void addRefEdge( RefSrcNode referencer,
149 HeapRegionNode referencee,
151 assert referencer != null;
152 assert referencee != null;
154 assert edge.getSrc() == referencer;
155 assert edge.getDst() == referencee;
157 referencer.addReferencee( edge );
158 referencee.addReferencer( edge );
161 protected void removeRefEdge( RefEdge e ) {
162 removeRefEdge( e.getSrc(),
168 protected void removeRefEdge( RefSrcNode referencer,
169 HeapRegionNode referencee,
172 assert referencer != null;
173 assert referencee != null;
175 RefEdge edge = referencer.getReferenceTo( referencee,
179 assert edge == referencee.getReferenceFrom( referencer,
183 referencer.removeReferencee( edge );
184 referencee.removeReferencer( edge );
187 protected void clearRefEdgesFrom( RefSrcNode referencer,
190 boolean removeAll ) {
191 assert referencer != null;
193 // get a copy of the set to iterate over, otherwise
194 // we will be trying to take apart the set as we
195 // are iterating over it, which won't work
196 Iterator<RefEdge> i = referencer.iteratorToReferenceesClone();
197 while( i.hasNext() ) {
198 RefEdge edge = i.next();
201 (edge.typeEquals( type ) && edge.fieldEquals( field ))
204 HeapRegionNode referencee = edge.getDst();
206 removeRefEdge( referencer,
214 protected void clearRefEdgesTo( HeapRegionNode referencee,
217 boolean removeAll ) {
218 assert referencee != null;
220 // get a copy of the set to iterate over, otherwise
221 // we will be trying to take apart the set as we
222 // are iterating over it, which won't work
223 Iterator<RefEdge> i = referencee.iteratorToReferencersClone();
224 while( i.hasNext() ) {
225 RefEdge edge = i.next();
228 (edge.typeEquals( type ) && edge.fieldEquals( field ))
231 RefSrcNode referencer = edge.getSrc();
233 removeRefEdge( referencer,
242 ////////////////////////////////////////////////////
244 // Assignment Operation Methods
246 // These methods are high-level operations for
247 // modeling program assignment statements using
248 // the low-level reference create/remove methods
251 ////////////////////////////////////////////////////
253 public void nullifyDeadVars( Set<TempDescriptor> liveIn ) {
257 // make a set of the temps that are out of scope, don't
258 // consider them when nullifying dead in-scope variables
259 Set<TempDescriptor> outOfScope = new HashSet<TempDescriptor>();
260 outOfScope.add( tdReturn );
261 outOfScope.add( tdAliasBlob );
262 outOfScope.addAll( paramIndex2tdQ.values() );
263 outOfScope.addAll( paramIndex2tdR.values() );
265 Iterator varItr = td2vn.entrySet().iterator();
266 while( varItr.hasNext() ) {
267 Map.Entry me = (Map.Entry) varItr.next();
268 TempDescriptor td = (TempDescriptor) me.getKey();
269 VariableNode ln = (VariableNode) me.getValue();
271 // if this variable is not out-of-scope or live
272 // in graph, nullify its references to anything
273 if( !outOfScope.contains( td ) &&
274 !liveIn.contains( td )
276 clearRefEdgesFrom( ln, null, null, true );
283 public void assignTempXEqualToTempY( TempDescriptor x,
285 assignTempXEqualToCastedTempY( x, y, null );
288 public void assignTempXEqualToCastedTempY( TempDescriptor x,
290 TypeDescriptor tdCast ) {
292 VariableNode lnX = getVariableNodeFromTemp( x );
293 VariableNode lnY = getVariableNodeFromTemp( y );
295 clearRefEdgesFrom( lnX, null, null, true );
297 // note it is possible that the types of temps in the
298 // flat node to analyze will reveal that some typed
299 // edges in the reachability graph are impossible
300 Set<RefEdge> impossibleEdges = new HashSet<RefEdge>();
302 Iterator<RefEdge> itrYhrn = lnY.iteratorToReferencees();
303 while( itrYhrn.hasNext() ) {
304 RefEdge edgeY = itrYhrn.next();
305 HeapRegionNode referencee = edgeY.getDst();
306 RefEdge edgeNew = edgeY.copy();
308 if( !isSuperiorType( x.getType(), edgeY.getType() ) ) {
309 impossibleEdges.add( edgeY );
313 edgeNew.setSrc( lnX );
315 edgeNew.setType( mostSpecificType( y.getType(),
322 edgeNew.setField( null );
324 addRefEdge( lnX, referencee, edgeNew );
327 Iterator<RefEdge> itrImp = impossibleEdges.iterator();
328 while( itrImp.hasNext() ) {
329 RefEdge edgeImp = itrImp.next();
330 removeRefEdge( edgeImp );
335 public void assignTempXEqualToTempYFieldF( TempDescriptor x,
337 FieldDescriptor f ) {
338 VariableNode lnX = getVariableNodeFromTemp( x );
339 VariableNode lnY = getVariableNodeFromTemp( y );
341 clearRefEdgesFrom( lnX, null, null, true );
343 // note it is possible that the types of temps in the
344 // flat node to analyze will reveal that some typed
345 // edges in the reachability graph are impossible
346 Set<RefEdge> impossibleEdges = new HashSet<RefEdge>();
348 Iterator<RefEdge> itrYhrn = lnY.iteratorToReferencees();
349 while( itrYhrn.hasNext() ) {
350 RefEdge edgeY = itrYhrn.next();
351 HeapRegionNode hrnY = edgeY.getDst();
352 ReachSet betaY = edgeY.getBeta();
354 Iterator<RefEdge> itrHrnFhrn = hrnY.iteratorToReferencees();
355 while( itrHrnFhrn.hasNext() ) {
356 RefEdge edgeHrn = itrHrnFhrn.next();
357 HeapRegionNode hrnHrn = edgeHrn.getDst();
358 ReachSet betaHrn = edgeHrn.getBeta();
360 // prune edges that are not a matching field
361 if( edgeHrn.getType() != null &&
362 !edgeHrn.getField().equals( f.getSymbol() )
367 // check for impossible edges
368 if( !isSuperiorType( x.getType(), edgeHrn.getType() ) ) {
369 impossibleEdges.add( edgeHrn );
373 TypeDescriptor tdNewEdge =
374 mostSpecificType( edgeHrn.getType(),
378 RefEdge edgeNew = new RefEdge( lnX,
383 betaY.intersection( betaHrn )
386 addRefEdge( lnX, hrnHrn, edgeNew );
390 Iterator<RefEdge> itrImp = impossibleEdges.iterator();
391 while( itrImp.hasNext() ) {
392 RefEdge edgeImp = itrImp.next();
393 removeRefEdge( edgeImp );
396 // anytime you might remove edges between heap regions
397 // you must global sweep to clean up broken reachability
398 if( !impossibleEdges.isEmpty() ) {
399 if( !DISABLE_GLOBAL_SWEEP ) {
406 public void assignTempXFieldFEqualToTempY( TempDescriptor x,
410 VariableNode lnX = getVariableNodeFromTemp( x );
411 VariableNode lnY = getVariableNodeFromTemp( y );
413 HashSet<HeapRegionNode> nodesWithNewAlpha = new HashSet<HeapRegionNode>();
414 HashSet<RefEdge> edgesWithNewBeta = new HashSet<RefEdge>();
416 // note it is possible that the types of temps in the
417 // flat node to analyze will reveal that some typed
418 // edges in the reachability graph are impossible
419 Set<RefEdge> impossibleEdges = new HashSet<RefEdge>();
421 // first look for possible strong updates and remove those edges
422 boolean strongUpdate = false;
424 Iterator<RefEdge> itrXhrn = lnX.iteratorToReferencees();
425 while( itrXhrn.hasNext() ) {
426 RefEdge edgeX = itrXhrn.next();
427 HeapRegionNode hrnX = edgeX.getDst();
429 // we can do a strong update here if one of two cases holds
431 f != DisjointAnalysis.getArrayField( f.getType() ) &&
432 ( (hrnX.getNumReferencers() == 1) || // case 1
433 (hrnX.isSingleObject() && lnX.getNumReferencees() == 1) // case 2
436 if( !DISABLE_STRONG_UPDATES ) {
438 clearRefEdgesFrom( hrnX, f.getType(), f.getSymbol(), false );
443 // then do all token propagation
444 itrXhrn = lnX.iteratorToReferencees();
445 while( itrXhrn.hasNext() ) {
446 RefEdge edgeX = itrXhrn.next();
447 HeapRegionNode hrnX = edgeX.getDst();
448 ReachSet betaX = edgeX.getBeta();
449 ReachSet R = hrnX.getAlpha().intersection( edgeX.getBeta() );
451 Iterator<RefEdge> itrYhrn = lnY.iteratorToReferencees();
452 while( itrYhrn.hasNext() ) {
453 RefEdge edgeY = itrYhrn.next();
454 HeapRegionNode hrnY = edgeY.getDst();
455 ReachSet O = edgeY.getBeta();
457 // check for impossible edges
458 if( !isSuperiorType( f.getType(), edgeY.getType() ) ) {
459 impossibleEdges.add( edgeY );
463 // propagate tokens over nodes starting from hrnSrc, and it will
464 // take care of propagating back up edges from any touched nodes
465 ChangeSet Cy = O.unionUpArityToChangeSet( R );
466 propagateTokensOverNodes( hrnY, Cy, nodesWithNewAlpha, edgesWithNewBeta );
468 // then propagate back just up the edges from hrn
469 ChangeSet Cx = R.unionUpArityToChangeSet(O);
470 HashSet<RefEdge> todoEdges = new HashSet<RefEdge>();
472 Hashtable<RefEdge, ChangeSet> edgePlannedChanges =
473 new Hashtable<RefEdge, ChangeSet>();
475 Iterator<RefEdge> referItr = hrnX.iteratorToReferencers();
476 while( referItr.hasNext() ) {
477 RefEdge edgeUpstream = referItr.next();
478 todoEdges.add( edgeUpstream );
479 edgePlannedChanges.put( edgeUpstream, Cx );
482 propagateTokensOverEdges( todoEdges,
489 // apply the updates to reachability
490 Iterator<HeapRegionNode> nodeItr = nodesWithNewAlpha.iterator();
491 while( nodeItr.hasNext() ) {
492 nodeItr.next().applyAlphaNew();
495 Iterator<RefEdge> edgeItr = edgesWithNewBeta.iterator();
496 while( edgeItr.hasNext() ) {
497 edgeItr.next().applyBetaNew();
501 // then go back through and add the new edges
502 itrXhrn = lnX.iteratorToReferencees();
503 while( itrXhrn.hasNext() ) {
504 RefEdge edgeX = itrXhrn.next();
505 HeapRegionNode hrnX = edgeX.getDst();
507 Iterator<RefEdge> itrYhrn = lnY.iteratorToReferencees();
508 while( itrYhrn.hasNext() ) {
509 RefEdge edgeY = itrYhrn.next();
510 HeapRegionNode hrnY = edgeY.getDst();
512 // skip impossible edges here, we already marked them
513 // when computing reachability propagations above
514 if( !isSuperiorType( f.getType(), edgeY.getType() ) ) {
518 // prepare the new reference edge hrnX.f -> hrnY
519 TypeDescriptor tdNewEdge =
520 mostSpecificType( y.getType(),
525 RefEdge edgeNew = new RefEdge( hrnX,
530 edgeY.getBeta().pruneBy( hrnX.getAlpha() )
533 // look to see if an edge with same field exists
534 // and merge with it, otherwise just add the edge
535 RefEdge edgeExisting = hrnX.getReferenceTo( hrnY,
539 if( edgeExisting != null ) {
540 edgeExisting.setBeta(
541 edgeExisting.getBeta().union( edgeNew.getBeta() )
543 // we touched this edge in the current context
545 edgeExisting.setIsClean( false );
548 addRefEdge( hrnX, hrnY, edgeNew );
553 Iterator<RefEdge> itrImp = impossibleEdges.iterator();
554 while( itrImp.hasNext() ) {
555 RefEdge edgeImp = itrImp.next();
556 removeRefEdge( edgeImp );
559 // if there was a strong update, make sure to improve
560 // reachability with a global sweep
561 if( strongUpdate || !impossibleEdges.isEmpty() ) {
562 if( !DISABLE_GLOBAL_SWEEP ) {
569 public void assignReturnEqualToTemp( TempDescriptor x ) {
571 VariableNode lnR = getVariableNodeFromTemp( tdReturn );
572 VariableNode lnX = getVariableNodeFromTemp( x );
574 clearRefEdgesFrom( lnR, null, null, true );
576 Iterator<RefEdge> itrXhrn = lnX.iteratorToReferencees();
577 while( itrXhrn.hasNext() ) {
578 RefEdge edgeX = itrXhrn.next();
579 HeapRegionNode referencee = edgeX.getDst();
580 RefEdge edgeNew = edgeX.copy();
581 edgeNew.setSrc( lnR );
583 addRefEdge( lnR, referencee, edgeNew );
588 public void assignTempEqualToNewAlloc( TempDescriptor x,
595 // after the age operation the newest (or zero-ith oldest)
596 // node associated with the allocation site should have
597 // no references to it as if it were a newly allocated
599 Integer idNewest = as.getIthOldest( 0 );
600 HeapRegionNode hrnNewest = id2hrn.get( idNewest );
601 assert hrnNewest != null;
603 VariableNode lnX = getVariableNodeFromTemp( x );
604 clearRefEdgesFrom( lnX, null, null, true );
606 // make a new reference to allocated node
607 TypeDescriptor type = as.getType();
610 new RefEdge( lnX, // source
614 false, // is initial param
615 hrnNewest.getAlpha() // beta
618 addRefEdge( lnX, hrnNewest, edgeNew );
622 // use the allocation site (unique to entire analysis) to
623 // locate the heap region nodes in this reachability graph
624 // that should be aged. The process models the allocation
625 // of new objects and collects all the oldest allocations
626 // in a summary node to allow for a finite analysis
628 // There is an additional property of this method. After
629 // running it on a particular reachability graph (many graphs
630 // may have heap regions related to the same allocation site)
631 // the heap region node objects in this reachability graph will be
632 // allocated. Therefore, after aging a graph for an allocation
633 // site, attempts to retrieve the heap region nodes using the
634 // integer id's contained in the allocation site should always
635 // return non-null heap regions.
636 public void age( AllocSite as ) {
638 // aging adds this allocation site to the graph's
639 // list of sites that exist in the graph, or does
640 // nothing if the site is already in the list
641 allocSites.add( as );
643 // get the summary node for the allocation site in the context
644 // of this particular reachability graph
645 HeapRegionNode hrnSummary = getSummaryNode( as );
647 // merge oldest node into summary
648 Integer idK = as.getOldest();
649 HeapRegionNode hrnK = id2hrn.get( idK );
650 mergeIntoSummary( hrnK, hrnSummary );
652 // move down the line of heap region nodes
653 // clobbering the ith and transferring all references
654 // to and from i-1 to node i. Note that this clobbers
655 // the oldest node (hrnK) that was just merged into
657 for( int i = allocationDepth - 1; i > 0; --i ) {
659 // move references from the i-1 oldest to the ith oldest
660 Integer idIth = as.getIthOldest( i );
661 HeapRegionNode hrnI = id2hrn.get( idIth );
662 Integer idImin1th = as.getIthOldest( i - 1 );
663 HeapRegionNode hrnImin1 = id2hrn.get( idImin1th );
665 transferOnto( hrnImin1, hrnI );
668 // as stated above, the newest node should have had its
669 // references moved over to the second oldest, so we wipe newest
670 // in preparation for being the new object to assign something to
671 Integer id0th = as.getIthOldest( 0 );
672 HeapRegionNode hrn0 = id2hrn.get( id0th );
675 // clear all references in and out of newest node
676 clearRefEdgesFrom( hrn0, null, null, true );
677 clearRefEdgesTo ( hrn0, null, null, true );
680 // now tokens in reachability sets need to "age" also
681 Iterator itrAllVariableNodes = td2vn.entrySet().iterator();
682 while( itrAllVariableNodes.hasNext() ) {
683 Map.Entry me = (Map.Entry) itrAllVariableNodes.next();
684 VariableNode ln = (VariableNode) me.getValue();
686 Iterator<RefEdge> itrEdges = ln.iteratorToReferencees();
687 while( itrEdges.hasNext() ) {
688 ageTokens(as, itrEdges.next() );
692 Iterator itrAllHRNodes = id2hrn.entrySet().iterator();
693 while( itrAllHRNodes.hasNext() ) {
694 Map.Entry me = (Map.Entry) itrAllHRNodes.next();
695 HeapRegionNode hrnToAge = (HeapRegionNode) me.getValue();
697 ageTokens( as, hrnToAge );
699 Iterator<RefEdge> itrEdges = hrnToAge.iteratorToReferencees();
700 while( itrEdges.hasNext() ) {
701 ageTokens( as, itrEdges.next() );
706 // after tokens have been aged, reset newest node's reachability
707 if( hrn0.isFlagged() ) {
708 hrn0.setAlpha( new ReachSet(
710 new ReachTuple( hrn0 ).makeCanonical()
715 hrn0.setAlpha( new ReachSet(
716 new ReachState().makeCanonical()
723 protected HeapRegionNode getSummaryNode( AllocSite as ) {
725 Integer idSummary = as.getSummary();
726 HeapRegionNode hrnSummary = id2hrn.get( idSummary );
728 // If this is null then we haven't touched this allocation site
729 // in the context of the current reachability graph, so allocate
730 // heap region nodes appropriate for the entire allocation site.
731 // This should only happen once per reachability graph per allocation site,
732 // and a particular integer id can be used to locate the heap region
733 // in different reachability graphs that represents the same part of an
735 if( hrnSummary == null ) {
737 boolean hasFlags = false;
738 if( as.getType().isClass() ) {
739 hasFlags = as.getType().getClassDesc().hasFlags();
743 hasFlags = as.getFlag();
746 String strDesc = as.toStringForDOT()+"\\nsummary";
748 createNewHeapRegionNode( idSummary, // id or null to generate a new one
749 false, // single object?
751 hasFlags, // flagged?
753 as.getType(), // type
754 as, // allocation site
755 null, // inherent reach
756 null, // current reach
757 strDesc // description
760 for( int i = 0; i < as.getAllocationDepth(); ++i ) {
761 Integer idIth = as.getIthOldest( i );
762 assert !id2hrn.containsKey( idIth );
763 strDesc = as.toStringForDOT()+"\\n"+i+" oldest";
764 createNewHeapRegionNode( idIth, // id or null to generate a new one
765 true, // single object?
767 hasFlags, // flagged?
769 as.getType(), // type
770 as, // allocation site
771 null, // inherent reach
772 null, // current reach
773 strDesc // description
782 protected HeapRegionNode getShadowSummaryNode( AllocSite as ) {
784 Integer idShadowSummary = as.getSummaryShadow();
785 HeapRegionNode hrnShadowSummary = id2hrn.get( idShadowSummary );
787 if( hrnShadowSummary == null ) {
789 boolean hasFlags = false;
790 if( as.getType().isClass() ) {
791 hasFlags = as.getType().getClassDesc().hasFlags();
795 hasFlags = as.getFlag();
798 String strDesc = as+"\\n"+as.getType()+"\\nshadowSum";
800 createNewHeapRegionNode( idShadowSummary, // id or null to generate a new one
801 false, // single object?
803 hasFlags, // flagged?
805 as.getType(), // type
806 as, // allocation site
807 null, // inherent reach
808 null, // current reach
809 strDesc // description
812 for( int i = 0; i < as.getAllocationDepth(); ++i ) {
813 Integer idShadowIth = as.getIthOldestShadow( i );
814 assert !id2hrn.containsKey( idShadowIth );
815 strDesc = as+"\\n"+as.getType()+"\\n"+i+" shadow";
816 createNewHeapRegionNode( idShadowIth, // id or null to generate a new one
817 true, // single object?
819 hasFlags, // flagged?
821 as.getType(), // type
822 as, // allocation site
823 null, // inherent reach
824 null, // current reach
825 strDesc // description
830 return hrnShadowSummary;
834 protected void mergeIntoSummary(HeapRegionNode hrn, HeapRegionNode hrnSummary) {
835 assert hrnSummary.isNewSummary();
837 // transfer references _from_ hrn over to hrnSummary
838 Iterator<RefEdge> itrReferencee = hrn.iteratorToReferencees();
839 while( itrReferencee.hasNext() ) {
840 RefEdge edge = itrReferencee.next();
841 RefEdge edgeMerged = edge.copy();
842 edgeMerged.setSrc(hrnSummary);
844 HeapRegionNode hrnReferencee = edge.getDst();
845 RefEdge edgeSummary = hrnSummary.getReferenceTo(hrnReferencee,
849 if( edgeSummary == null ) {
850 // the merge is trivial, nothing to be done
852 // otherwise an edge from the referencer to hrnSummary exists already
853 // and the edge referencer->hrn should be merged with it
854 edgeMerged.setBeta(edgeMerged.getBeta().union(edgeSummary.getBeta() ) );
857 addRefEdge(hrnSummary, hrnReferencee, edgeMerged);
860 // next transfer references _to_ hrn over to hrnSummary
861 Iterator<RefEdge> itrReferencer = hrn.iteratorToReferencers();
862 while( itrReferencer.hasNext() ) {
863 RefEdge edge = itrReferencer.next();
864 RefEdge edgeMerged = edge.copy();
865 edgeMerged.setDst(hrnSummary);
867 RefSrcNode onReferencer = edge.getSrc();
868 RefEdge edgeSummary = onReferencer.getReferenceTo(hrnSummary,
872 if( edgeSummary == null ) {
873 // the merge is trivial, nothing to be done
875 // otherwise an edge from the referencer to alpha_S exists already
876 // and the edge referencer->alpha_K should be merged with it
877 edgeMerged.setBeta(edgeMerged.getBeta().union(edgeSummary.getBeta() ) );
880 addRefEdge(onReferencer, hrnSummary, edgeMerged);
883 // then merge hrn reachability into hrnSummary
884 hrnSummary.setAlpha(hrnSummary.getAlpha().union(hrn.getAlpha() ) );
888 protected void transferOnto(HeapRegionNode hrnA, HeapRegionNode hrnB) {
890 // clear references in and out of node b
891 clearRefEdgesFrom(hrnB, null, null, true);
892 clearRefEdgesTo(hrnB, null, null, true);
894 // copy each edge in and out of A to B
895 Iterator<RefEdge> itrReferencee = hrnA.iteratorToReferencees();
896 while( itrReferencee.hasNext() ) {
897 RefEdge edge = itrReferencee.next();
898 HeapRegionNode hrnReferencee = edge.getDst();
899 RefEdge edgeNew = edge.copy();
900 edgeNew.setSrc(hrnB);
902 addRefEdge(hrnB, hrnReferencee, edgeNew);
905 Iterator<RefEdge> itrReferencer = hrnA.iteratorToReferencers();
906 while( itrReferencer.hasNext() ) {
907 RefEdge edge = itrReferencer.next();
908 RefSrcNode onReferencer = edge.getSrc();
909 RefEdge edgeNew = edge.copy();
910 edgeNew.setDst(hrnB);
912 addRefEdge(onReferencer, hrnB, edgeNew);
915 // replace hrnB reachability with hrnA's
916 hrnB.setAlpha(hrnA.getAlpha() );
920 protected void ageTokens(AllocSite as, RefEdge edge) {
921 edge.setBeta(edge.getBeta().ageTokens(as) );
924 protected void ageTokens(AllocSite as, HeapRegionNode hrn) {
925 hrn.setAlpha(hrn.getAlpha().ageTokens(as) );
930 protected void propagateTokensOverNodes(HeapRegionNode nPrime,
932 HashSet<HeapRegionNode> nodesWithNewAlpha,
933 HashSet<RefEdge> edgesWithNewBeta) {
935 HashSet<HeapRegionNode> todoNodes
936 = new HashSet<HeapRegionNode>();
937 todoNodes.add(nPrime);
939 HashSet<RefEdge> todoEdges
940 = new HashSet<RefEdge>();
942 Hashtable<HeapRegionNode, ChangeSet> nodePlannedChanges
943 = new Hashtable<HeapRegionNode, ChangeSet>();
944 nodePlannedChanges.put(nPrime, c0);
946 Hashtable<RefEdge, ChangeSet> edgePlannedChanges
947 = new Hashtable<RefEdge, ChangeSet>();
949 // first propagate change sets everywhere they can go
950 while( !todoNodes.isEmpty() ) {
951 HeapRegionNode n = todoNodes.iterator().next();
952 ChangeSet C = nodePlannedChanges.get(n);
954 Iterator<RefEdge> referItr = n.iteratorToReferencers();
955 while( referItr.hasNext() ) {
956 RefEdge edge = referItr.next();
959 if( !edgePlannedChanges.containsKey(edge) ) {
960 edgePlannedChanges.put(edge, new ChangeSet().makeCanonical() );
963 edgePlannedChanges.put(edge, edgePlannedChanges.get(edge).union(C) );
966 Iterator<RefEdge> refeeItr = n.iteratorToReferencees();
967 while( refeeItr.hasNext() ) {
968 RefEdge edgeF = refeeItr.next();
969 HeapRegionNode m = edgeF.getDst();
971 ChangeSet changesToPass = new ChangeSet().makeCanonical();
973 Iterator<ChangeTuple> itrCprime = C.iterator();
974 while( itrCprime.hasNext() ) {
975 ChangeTuple c = itrCprime.next();
976 if( edgeF.getBeta().contains( c.getSetToMatch() ) ) {
977 changesToPass = changesToPass.union(c);
981 if( !changesToPass.isEmpty() ) {
982 if( !nodePlannedChanges.containsKey(m) ) {
983 nodePlannedChanges.put(m, new ChangeSet().makeCanonical() );
986 ChangeSet currentChanges = nodePlannedChanges.get(m);
988 if( !changesToPass.isSubset(currentChanges) ) {
990 nodePlannedChanges.put(m, currentChanges.union(changesToPass) );
999 // then apply all of the changes for each node at once
1000 Iterator itrMap = nodePlannedChanges.entrySet().iterator();
1001 while( itrMap.hasNext() ) {
1002 Map.Entry me = (Map.Entry) itrMap.next();
1003 HeapRegionNode n = (HeapRegionNode) me.getKey();
1004 ChangeSet C = (ChangeSet) me.getValue();
1006 // this propagation step is with respect to one change,
1007 // so we capture the full change from the old alpha:
1008 ReachSet localDelta = n.getAlpha().applyChangeSet( C, true );
1010 // but this propagation may be only one of many concurrent
1011 // possible changes, so keep a running union with the node's
1012 // partially updated new alpha set
1013 n.setAlphaNew( n.getAlphaNew().union( localDelta ) );
1015 nodesWithNewAlpha.add( n );
1018 propagateTokensOverEdges(todoEdges, edgePlannedChanges, edgesWithNewBeta);
1022 protected void propagateTokensOverEdges(
1023 HashSet<RefEdge> todoEdges,
1024 Hashtable<RefEdge, ChangeSet> edgePlannedChanges,
1025 HashSet<RefEdge> edgesWithNewBeta) {
1027 // first propagate all change tuples everywhere they can go
1028 while( !todoEdges.isEmpty() ) {
1029 RefEdge edgeE = todoEdges.iterator().next();
1030 todoEdges.remove(edgeE);
1032 if( !edgePlannedChanges.containsKey(edgeE) ) {
1033 edgePlannedChanges.put(edgeE, new ChangeSet().makeCanonical() );
1036 ChangeSet C = edgePlannedChanges.get(edgeE);
1038 ChangeSet changesToPass = new ChangeSet().makeCanonical();
1040 Iterator<ChangeTuple> itrC = C.iterator();
1041 while( itrC.hasNext() ) {
1042 ChangeTuple c = itrC.next();
1043 if( edgeE.getBeta().contains( c.getSetToMatch() ) ) {
1044 changesToPass = changesToPass.union(c);
1048 RefSrcNode onSrc = edgeE.getSrc();
1050 if( !changesToPass.isEmpty() && onSrc instanceof HeapRegionNode ) {
1051 HeapRegionNode n = (HeapRegionNode) onSrc;
1053 Iterator<RefEdge> referItr = n.iteratorToReferencers();
1054 while( referItr.hasNext() ) {
1055 RefEdge edgeF = referItr.next();
1057 if( !edgePlannedChanges.containsKey(edgeF) ) {
1058 edgePlannedChanges.put(edgeF, new ChangeSet().makeCanonical() );
1061 ChangeSet currentChanges = edgePlannedChanges.get(edgeF);
1063 if( !changesToPass.isSubset(currentChanges) ) {
1064 todoEdges.add(edgeF);
1065 edgePlannedChanges.put(edgeF, currentChanges.union(changesToPass) );
1071 // then apply all of the changes for each edge at once
1072 Iterator itrMap = edgePlannedChanges.entrySet().iterator();
1073 while( itrMap.hasNext() ) {
1074 Map.Entry me = (Map.Entry) itrMap.next();
1075 RefEdge e = (RefEdge) me.getKey();
1076 ChangeSet C = (ChangeSet) me.getValue();
1078 // this propagation step is with respect to one change,
1079 // so we capture the full change from the old beta:
1080 ReachSet localDelta = e.getBeta().applyChangeSet( C, true );
1082 // but this propagation may be only one of many concurrent
1083 // possible changes, so keep a running union with the edge's
1084 // partially updated new beta set
1085 e.setBetaNew( e.getBetaNew().union( localDelta ) );
1087 edgesWithNewBeta.add( e );
1093 // resolveMethodCall() is used to incorporate a callee graph's effects into
1094 // *this* graph, which is the caller. This method can also be used, after
1095 // the entire analysis is complete, to perform parameter decomposition for
1096 // a given call chain.
1097 public void resolveMethodCall(FlatCall fc, // call site in caller method
1098 boolean isStatic, // whether it is a static method
1099 FlatMethod fm, // the callee method (when virtual, can be many)
1100 ReachGraph ogCallee, // the callee's current reachability graph
1101 MethodContext mc, // the aliasing context for this call
1102 ParameterDecomposition pd // if this is not null, we're calling after analysis
1106 mc.getDescriptor().getSymbol().equals( debugCaller ) &&
1107 fm.getMethod().getSymbol().equals( debugCallee )
1111 writeGraph("debug1BeforeCall",
1112 true, // write labels (variables)
1113 true, // selectively hide intermediate temp vars
1114 true, // prune unreachable heap regions
1115 false, // show back edges to confirm graph validity
1116 false, // show parameter indices (unmaintained!)
1117 true, // hide subset reachability states
1118 true); // hide edge taints
1120 ogCallee.writeGraph("debug0Callee",
1121 true, // write labels (variables)
1122 true, // selectively hide intermediate temp vars
1123 true, // prune unreachable heap regions
1124 false, // show back edges to confirm graph validity
1125 false, // show parameter indices (unmaintained!)
1126 true, // hide subset reachability states
1127 true); // hide edge taints
1128 } catch( IOException e ) {}
1130 System.out.println( " "+mc+" is calling "+fm );
1135 // define rewrite rules and other structures to organize data by parameter/argument index
1136 Hashtable<Integer, ReachSet> paramIndex2rewriteH_p = new Hashtable<Integer, ReachSet>();
1137 Hashtable<Integer, ReachSet> paramIndex2rewriteH_s = new Hashtable<Integer, ReachSet>();
1139 Hashtable<String, ReachSet> paramIndex2rewriteJ_p2p = new Hashtable<String, ReachSet>(); // select( i, j, f )
1140 Hashtable<String, ReachSet> paramIndex2rewriteJ_p2s = new Hashtable<String, ReachSet>(); // select( i, f )
1141 Hashtable<Integer, ReachSet> paramIndex2rewriteJ_s2p = new Hashtable<Integer, ReachSet>();
1142 Hashtable<Integer, ReachSet> paramIndex2rewriteJ_s2s = new Hashtable<Integer, ReachSet>();
1144 Hashtable<Integer, ReachSet> paramIndex2rewriteK_p = new Hashtable<Integer, ReachSet>();
1145 Hashtable<Integer, ReachSet> paramIndex2rewriteK_p2 = new Hashtable<Integer, ReachSet>();
1146 Hashtable<Integer, ReachSet> paramIndex2rewriteK_s = new Hashtable<Integer, ReachSet>();
1148 Hashtable<Integer, ReachSet> paramIndex2rewrite_d_p = new Hashtable<Integer, ReachSet>();
1149 Hashtable<Integer, ReachSet> paramIndex2rewrite_d_s = new Hashtable<Integer, ReachSet>();
1151 Hashtable<Integer, ReachSet> paramIndex2rewriteD = new Hashtable<Integer, ReachSet>();
1154 Hashtable<Integer, VariableNode> paramIndex2ln = new Hashtable<Integer, VariableNode>();
1157 paramIndex2rewriteH_p.put( bogusIndex, rsIdentity );
1158 paramIndex2rewriteH_s.put( bogusIndex, rsIdentity );
1160 paramIndex2rewriteJ_p2p.put( bogusIndex.toString(), rsIdentity );
1161 paramIndex2rewriteJ_p2s.put( bogusIndex.toString(), rsIdentity );
1162 paramIndex2rewriteJ_s2p.put( bogusIndex, rsIdentity );
1163 paramIndex2rewriteJ_s2s.put( bogusIndex, rsIdentity );
1166 for( int i = 0; i < fm.numParameters(); ++i ) {
1167 Integer paramIndex = new Integer(i);
1169 if( !ogCallee.paramIndex2idPrimary.containsKey( paramIndex ) ) {
1170 // skip this immutable parameter
1174 // setup H (primary)
1175 Integer idPrimary = ogCallee.paramIndex2idPrimary.get( paramIndex );
1176 assert ogCallee.id2hrn.containsKey( idPrimary );
1177 HeapRegionNode hrnPrimary = ogCallee.id2hrn.get( idPrimary );
1178 assert hrnPrimary != null;
1179 paramIndex2rewriteH_p.put( paramIndex, toShadowTokens( ogCallee, hrnPrimary.getAlpha() ) );
1181 // setup J (primary->X)
1182 Iterator<RefEdge> p2xItr = hrnPrimary.iteratorToReferencees();
1183 while( p2xItr.hasNext() ) {
1184 RefEdge p2xEdge = p2xItr.next();
1186 // we only care about initial parameter edges here
1187 if( !p2xEdge.isInitialParam() ) { continue; }
1189 HeapRegionNode hrnDst = p2xEdge.getDst();
1191 if( ogCallee.idPrimary2paramIndexSet.containsKey( hrnDst.getID() ) ) {
1192 Iterator<Integer> jItr = ogCallee.idPrimary2paramIndexSet.get( hrnDst.getID() ).iterator();
1193 while( jItr.hasNext() ) {
1194 Integer j = jItr.next();
1195 paramIndex2rewriteJ_p2p.put( makeMapKey( i, j, p2xEdge.getField() ),
1196 toShadowTokens( ogCallee, p2xEdge.getBeta() ) );
1200 assert ogCallee.idSecondary2paramIndexSet.containsKey( hrnDst.getID() );
1201 paramIndex2rewriteJ_p2s.put( makeMapKey( i, p2xEdge.getField() ),
1202 toShadowTokens( ogCallee, p2xEdge.getBeta() ) );
1206 // setup K (primary)
1207 TempDescriptor tdParamQ = ogCallee.paramIndex2tdQ.get( paramIndex );
1208 assert tdParamQ != null;
1209 VariableNode lnParamQ = ogCallee.td2vn.get( tdParamQ );
1210 assert lnParamQ != null;
1211 RefEdge edgeSpecialQ_i = lnParamQ.getReferenceTo( hrnPrimary, null, null );
1212 assert edgeSpecialQ_i != null;
1213 ReachSet qBeta = toShadowTokens( ogCallee, edgeSpecialQ_i.getBeta() );
1215 ReachTuple p_i = ogCallee.paramIndex2paramTokenPrimary .get( paramIndex );
1216 ReachTuple s_i = ogCallee.paramIndex2paramTokenSecondary.get( paramIndex );
1218 ReachSet K_p = new ReachSet().makeCanonical();
1219 ReachSet K_p2 = new ReachSet().makeCanonical();
1223 // sort qBeta into K_p1 and K_p2
1224 Iterator<ReachState> ttsItr = qBeta.iterator();
1225 while( ttsItr.hasNext() ) {
1226 ReachState tts = ttsItr.next();
1227 if( s_i != null && tts.containsBoth( p_i, s_i ) ) {
1228 K_p2 = K_p2.union( tts );
1230 K_p = K_p.union( tts );
1234 paramIndex2rewriteK_p .put( paramIndex, K_p );
1235 paramIndex2rewriteK_p2.put( paramIndex, K_p2 );
1238 // if there is a secondary node, compute the rest of the rewrite rules
1239 if( ogCallee.paramIndex2idSecondary.containsKey( paramIndex ) ) {
1241 // setup H (secondary)
1242 Integer idSecondary = ogCallee.paramIndex2idSecondary.get( paramIndex );
1243 assert ogCallee.id2hrn.containsKey( idSecondary );
1244 HeapRegionNode hrnSecondary = ogCallee.id2hrn.get( idSecondary );
1245 assert hrnSecondary != null;
1246 paramIndex2rewriteH_s.put( paramIndex, toShadowTokens( ogCallee, hrnSecondary.getAlpha() ) );
1248 // setup J (secondary->X)
1249 Iterator<RefEdge> s2xItr = hrnSecondary.iteratorToReferencees();
1250 while( s2xItr.hasNext() ) {
1251 RefEdge s2xEdge = s2xItr.next();
1253 if( !s2xEdge.isInitialParam() ) { continue; }
1255 HeapRegionNode hrnDst = s2xEdge.getDst();
1257 if( ogCallee.idPrimary2paramIndexSet.containsKey( hrnDst.getID() ) ) {
1258 Iterator<Integer> jItr = ogCallee.idPrimary2paramIndexSet.get( hrnDst.getID() ).iterator();
1259 while( jItr.hasNext() ) {
1260 Integer j = jItr.next();
1261 paramIndex2rewriteJ_s2p.put( i, toShadowTokens( ogCallee, s2xEdge.getBeta() ) );
1265 assert ogCallee.idSecondary2paramIndexSet.containsKey( hrnDst.getID() );
1266 paramIndex2rewriteJ_s2s.put( i, toShadowTokens( ogCallee, s2xEdge.getBeta() ) );
1270 // setup K (secondary)
1271 TempDescriptor tdParamR = ogCallee.paramIndex2tdR.get( paramIndex );
1272 assert tdParamR != null;
1273 VariableNode lnParamR = ogCallee.td2vn.get( tdParamR );
1274 assert lnParamR != null;
1275 RefEdge edgeSpecialR_i = lnParamR.getReferenceTo( hrnSecondary, null, null );
1276 assert edgeSpecialR_i != null;
1277 paramIndex2rewriteK_s.put( paramIndex,
1278 toShadowTokens( ogCallee, edgeSpecialR_i.getBeta() ) );
1282 // now depending on whether the callee is static or not
1283 // we need to account for a "this" argument in order to
1284 // find the matching argument in the caller context
1285 TempDescriptor argTemp_i = fc.getArgMatchingParamIndex( fm, paramIndex );
1287 // remember which caller arg label maps to param index
1288 VariableNode argLabel_i = getVariableNodeFromTemp( argTemp_i );
1289 paramIndex2ln.put( paramIndex, argLabel_i );
1291 // do a callee-effect strong update pre-pass here
1292 if( argTemp_i.getType().isClass() ) {
1294 Iterator<RefEdge> edgeItr = argLabel_i.iteratorToReferencees();
1295 while( edgeItr.hasNext() ) {
1296 RefEdge edge = edgeItr.next();
1297 HeapRegionNode hrn = edge.getDst();
1299 if( (hrn.getNumReferencers() == 1) || // case 1
1300 (hrn.isSingleObject() && argLabel_i.getNumReferencees() == 1) // case 2
1302 if( !DISABLE_STRONG_UPDATES ) {
1303 effectCalleeStrongUpdates( paramIndex, ogCallee, hrn );
1309 // then calculate the d and D rewrite rules
1310 ReachSet d_i_p = new ReachSet().makeCanonical();
1311 ReachSet d_i_s = new ReachSet().makeCanonical();
1312 Iterator<RefEdge> edgeItr = argLabel_i.iteratorToReferencees();
1313 while( edgeItr.hasNext() ) {
1314 RefEdge edge = edgeItr.next();
1316 d_i_p = d_i_p.union( edge.getBeta().intersection( edge.getDst().getAlpha() ) );
1317 d_i_s = d_i_s.union( edge.getBeta() );
1319 paramIndex2rewrite_d_p.put( paramIndex, d_i_p );
1320 paramIndex2rewrite_d_s.put( paramIndex, d_i_s );
1322 // TODO: we should only do this when we need it, and then
1323 // memoize it for the rest of the mapping procedure
1324 ReachSet D_i = d_i_s.exhaustiveArityCombinations();
1325 paramIndex2rewriteD.put( paramIndex, D_i );
1329 // with respect to each argument, map parameter effects into caller
1330 HashSet<HeapRegionNode> nodesWithNewAlpha = new HashSet<HeapRegionNode>();
1331 HashSet<RefEdge> edgesWithNewBeta = new HashSet<RefEdge>();
1333 Hashtable<Integer, Set<HeapRegionNode> > pi2dr =
1334 new Hashtable<Integer, Set<HeapRegionNode> >();
1336 Hashtable<Integer, Set<HeapRegionNode> > pi2r =
1337 new Hashtable<Integer, Set<HeapRegionNode> >();
1339 Set<HeapRegionNode> defParamObj = new HashSet<HeapRegionNode>();
1341 Iterator lnArgItr = paramIndex2ln.entrySet().iterator();
1342 while( lnArgItr.hasNext() ) {
1343 Map.Entry me = (Map.Entry) lnArgItr.next();
1344 Integer index = (Integer) me.getKey();
1345 VariableNode lnArg_i = (VariableNode) me.getValue();
1347 Set<HeapRegionNode> dr = new HashSet<HeapRegionNode>();
1348 Set<HeapRegionNode> r = new HashSet<HeapRegionNode>();
1349 Set<HeapRegionNode> todo = new HashSet<HeapRegionNode>();
1351 // find all reachable nodes starting with label referencees
1352 Iterator<RefEdge> edgeArgItr = lnArg_i.iteratorToReferencees();
1353 while( edgeArgItr.hasNext() ) {
1354 RefEdge edge = edgeArgItr.next();
1355 HeapRegionNode hrn = edge.getDst();
1359 if( lnArg_i.getNumReferencees() == 1 && hrn.isSingleObject() ) {
1360 defParamObj.add( hrn );
1363 Iterator<RefEdge> edgeHrnItr = hrn.iteratorToReferencees();
1364 while( edgeHrnItr.hasNext() ) {
1365 RefEdge edger = edgeHrnItr.next();
1366 todo.add( edger.getDst() );
1369 // then follow links until all reachable nodes have been found
1370 while( !todo.isEmpty() ) {
1371 HeapRegionNode hrnr = todo.iterator().next();
1372 todo.remove( hrnr );
1376 Iterator<RefEdge> edgeItr = hrnr.iteratorToReferencees();
1377 while( edgeItr.hasNext() ) {
1378 RefEdge edger = edgeItr.next();
1379 if( !r.contains( edger.getDst() ) ) {
1380 todo.add( edger.getDst() );
1385 if( hrn.isSingleObject() ) {
1390 pi2dr.put( index, dr );
1391 pi2r .put( index, r );
1394 assert defParamObj.size() <= fm.numParameters();
1396 // if we're in parameter decomposition mode, report some results here
1400 // report primary parameter object mappings
1401 mapItr = pi2dr.entrySet().iterator();
1402 while( mapItr.hasNext() ) {
1403 Map.Entry me = (Map.Entry) mapItr.next();
1404 Integer paramIndex = (Integer) me.getKey();
1405 Set<HeapRegionNode> hrnAset = (Set<HeapRegionNode>) me.getValue();
1407 Iterator<HeapRegionNode> hrnItr = hrnAset.iterator();
1408 while( hrnItr.hasNext() ) {
1409 HeapRegionNode hrnA = hrnItr.next();
1410 pd.mapRegionToParamObject( hrnA, paramIndex );
1414 // report parameter-reachable mappings
1415 mapItr = pi2r.entrySet().iterator();
1416 while( mapItr.hasNext() ) {
1417 Map.Entry me = (Map.Entry) mapItr.next();
1418 Integer paramIndex = (Integer) me.getKey();
1419 Set<HeapRegionNode> hrnRset = (Set<HeapRegionNode>) me.getValue();
1421 Iterator<HeapRegionNode> hrnItr = hrnRset.iterator();
1422 while( hrnItr.hasNext() ) {
1423 HeapRegionNode hrnR = hrnItr.next();
1424 pd.mapRegionToParamReachable( hrnR, paramIndex );
1428 // and we're done in this method for special param decomp mode
1433 // now iterate over reachable nodes to rewrite their alpha, and
1434 // classify edges found for beta rewrite
1435 Hashtable<ReachTuple, ReachSet> tokens2states = new Hashtable<ReachTuple, ReachSet>();
1437 Hashtable< Integer, Set<Vector> > edges_p2p = new Hashtable< Integer, Set<Vector> >();
1438 Hashtable< Integer, Set<Vector> > edges_p2s = new Hashtable< Integer, Set<Vector> >();
1439 Hashtable< Integer, Set<Vector> > edges_s2p = new Hashtable< Integer, Set<Vector> >();
1440 Hashtable< Integer, Set<Vector> > edges_s2s = new Hashtable< Integer, Set<Vector> >();
1441 Hashtable< Integer, Set<Vector> > edges_up_dr = new Hashtable< Integer, Set<Vector> >();
1442 Hashtable< Integer, Set<Vector> > edges_up_r = new Hashtable< Integer, Set<Vector> >();
1444 // so again, with respect to some arg i...
1445 lnArgItr = paramIndex2ln.entrySet().iterator();
1446 while( lnArgItr.hasNext() ) {
1447 Map.Entry me = (Map.Entry) lnArgItr.next();
1448 Integer index = (Integer) me.getKey();
1449 VariableNode lnArg_i = (VariableNode) me.getValue();
1451 ReachTuple p_i = ogCallee.paramIndex2paramTokenPrimary.get( index );
1452 ReachTuple s_i = ogCallee.paramIndex2paramTokenSecondary.get( index );
1455 ensureEmptyEdgeIndexPair( edges_p2p, index );
1456 ensureEmptyEdgeIndexPair( edges_p2s, index );
1457 ensureEmptyEdgeIndexPair( edges_s2p, index );
1458 ensureEmptyEdgeIndexPair( edges_s2s, index );
1459 ensureEmptyEdgeIndexPair( edges_up_dr, index );
1460 ensureEmptyEdgeIndexPair( edges_up_r, index );
1462 Set<HeapRegionNode> dr = pi2dr.get( index );
1463 Iterator<HeapRegionNode> hrnItr = dr.iterator();
1464 while( hrnItr.hasNext() ) {
1465 // this heap region is definitely an "a_i" or primary by virtue of being in dr
1466 HeapRegionNode hrn = hrnItr.next();
1468 tokens2states.clear();
1469 tokens2states.put( p_i, hrn.getAlpha() );
1471 rewriteCallerReachability( index,
1474 paramIndex2rewriteH_p.get( index ),
1476 paramIndex2rewrite_d_p,
1477 paramIndex2rewrite_d_s,
1478 paramIndex2rewriteD,
1483 nodesWithNewAlpha.add( hrn );
1486 Iterator<RefEdge> edgeItr = hrn.iteratorToReferencers();
1487 while( edgeItr.hasNext() ) {
1488 RefEdge edge = edgeItr.next();
1489 RefSrcNode on = edge.getSrc();
1491 boolean edge_classified = false;
1494 if( on instanceof HeapRegionNode ) {
1495 // hrn0 may be "a_j" and/or "r_j" or even neither
1496 HeapRegionNode hrn0 = (HeapRegionNode) on;
1498 Iterator itr = pi2dr.entrySet().iterator();
1499 while( itr.hasNext() ) {
1500 Map.Entry mo = (Map.Entry) itr.next();
1501 Integer pi = (Integer) mo.getKey();
1502 Set<HeapRegionNode> dr_i = (Set<HeapRegionNode>) mo.getValue();
1504 if( dr_i.contains( hrn0 ) ) {
1505 addEdgeIndexPair( edges_p2p, pi, edge, index );
1506 edge_classified = true;
1510 itr = pi2r.entrySet().iterator();
1511 while( itr.hasNext() ) {
1512 Map.Entry mo = (Map.Entry) itr.next();
1513 Integer pi = (Integer) mo.getKey();
1514 Set<HeapRegionNode> r_i = (Set<HeapRegionNode>) mo.getValue();
1516 if( r_i.contains( hrn0 ) ) {
1517 addEdgeIndexPair( edges_s2p, pi, edge, index );
1518 edge_classified = true;
1523 // all of these edges are upstream of directly reachable objects
1524 if( !edge_classified ) {
1525 addEdgeIndexPair( edges_up_dr, index, edge, index );
1531 Set<HeapRegionNode> r = pi2r.get( index );
1532 hrnItr = r.iterator();
1533 while( hrnItr.hasNext() ) {
1534 // this heap region is definitely an "r_i" or secondary by virtue of being in r
1535 HeapRegionNode hrn = hrnItr.next();
1537 if( paramIndex2rewriteH_s.containsKey( index ) ) {
1539 tokens2states.clear();
1540 tokens2states.put( p_i, new ReachSet().makeCanonical() );
1541 tokens2states.put( s_i, hrn.getAlpha() );
1543 rewriteCallerReachability( index,
1546 paramIndex2rewriteH_s.get( index ),
1548 paramIndex2rewrite_d_p,
1549 paramIndex2rewrite_d_s,
1550 paramIndex2rewriteD,
1555 nodesWithNewAlpha.add( hrn );
1559 Iterator<RefEdge> edgeItr = hrn.iteratorToReferencers();
1560 while( edgeItr.hasNext() ) {
1561 RefEdge edge = edgeItr.next();
1562 RefSrcNode on = edge.getSrc();
1564 boolean edge_classified = false;
1566 if( on instanceof HeapRegionNode ) {
1567 // hrn0 may be "a_j" and/or "r_j" or even neither
1568 HeapRegionNode hrn0 = (HeapRegionNode) on;
1570 Iterator itr = pi2dr.entrySet().iterator();
1571 while( itr.hasNext() ) {
1572 Map.Entry mo = (Map.Entry) itr.next();
1573 Integer pi = (Integer) mo.getKey();
1574 Set<HeapRegionNode> dr_i = (Set<HeapRegionNode>) mo.getValue();
1576 if( dr_i.contains( hrn0 ) ) {
1577 addEdgeIndexPair( edges_p2s, pi, edge, index );
1578 edge_classified = true;
1582 itr = pi2r.entrySet().iterator();
1583 while( itr.hasNext() ) {
1584 Map.Entry mo = (Map.Entry) itr.next();
1585 Integer pi = (Integer) mo.getKey();
1586 Set<HeapRegionNode> r_i = (Set<HeapRegionNode>) mo.getValue();
1588 if( r_i.contains( hrn0 ) ) {
1589 addEdgeIndexPair( edges_s2s, pi, edge, index );
1590 edge_classified = true;
1595 // these edges are all upstream of some reachable node
1596 if( !edge_classified ) {
1597 addEdgeIndexPair( edges_up_r, index, edge, index );
1604 // and again, with respect to some arg i...
1605 lnArgItr = paramIndex2ln.entrySet().iterator();
1606 while( lnArgItr.hasNext() ) {
1607 Map.Entry me = (Map.Entry) lnArgItr.next();
1608 Integer index = (Integer) me.getKey();
1609 VariableNode lnArg_i = (VariableNode) me.getValue();
1612 // update reachable edges
1613 Iterator edgeItr = edges_p2p.get( index ).iterator();
1614 while( edgeItr.hasNext() ) {
1615 Vector mo = (Vector) edgeItr.next();
1616 RefEdge edge = (RefEdge) mo.get( 0 );
1617 Integer indexJ = (Integer) mo.get( 1 );
1619 if( !paramIndex2rewriteJ_p2p.containsKey( makeMapKey( index,
1621 edge.getField() ) ) ) {
1625 ReachTuple p_j = ogCallee.paramIndex2paramTokenPrimary.get( indexJ );
1628 tokens2states.clear();
1629 tokens2states.put( p_j, edge.getBeta() );
1631 rewriteCallerReachability( index,
1634 paramIndex2rewriteJ_p2p.get( makeMapKey( index,
1636 edge.getField() ) ),
1638 paramIndex2rewrite_d_p,
1639 paramIndex2rewrite_d_s,
1640 paramIndex2rewriteD,
1645 edgesWithNewBeta.add( edge );
1649 edgeItr = edges_p2s.get( index ).iterator();
1650 while( edgeItr.hasNext() ) {
1651 Vector mo = (Vector) edgeItr.next();
1652 RefEdge edge = (RefEdge) mo.get( 0 );
1653 Integer indexJ = (Integer) mo.get( 1 );
1655 if( !paramIndex2rewriteJ_p2s.containsKey( makeMapKey( index,
1656 edge.getField() ) ) ) {
1660 ReachTuple s_j = ogCallee.paramIndex2paramTokenSecondary.get( indexJ );
1663 tokens2states.clear();
1664 tokens2states.put( s_j, edge.getBeta() );
1666 rewriteCallerReachability( index,
1669 paramIndex2rewriteJ_p2s.get( makeMapKey( index,
1670 edge.getField() ) ),
1672 paramIndex2rewrite_d_p,
1673 paramIndex2rewrite_d_s,
1674 paramIndex2rewriteD,
1679 edgesWithNewBeta.add( edge );
1683 edgeItr = edges_s2p.get( index ).iterator();
1684 while( edgeItr.hasNext() ) {
1685 Vector mo = (Vector) edgeItr.next();
1686 RefEdge edge = (RefEdge) mo.get( 0 );
1687 Integer indexJ = (Integer) mo.get( 1 );
1689 if( !paramIndex2rewriteJ_s2p.containsKey( index ) ) {
1693 ReachTuple p_j = ogCallee.paramIndex2paramTokenPrimary.get( indexJ );
1696 tokens2states.clear();
1697 tokens2states.put( p_j, edge.getBeta() );
1699 rewriteCallerReachability( index,
1702 paramIndex2rewriteJ_s2p.get( index ),
1704 paramIndex2rewrite_d_p,
1705 paramIndex2rewrite_d_s,
1706 paramIndex2rewriteD,
1711 edgesWithNewBeta.add( edge );
1715 edgeItr = edges_s2s.get( index ).iterator();
1716 while( edgeItr.hasNext() ) {
1717 Vector mo = (Vector) edgeItr.next();
1718 RefEdge edge = (RefEdge) mo.get( 0 );
1719 Integer indexJ = (Integer) mo.get( 1 );
1721 if( !paramIndex2rewriteJ_s2s.containsKey( index ) ) {
1725 ReachTuple s_j = ogCallee.paramIndex2paramTokenSecondary.get( indexJ );
1728 tokens2states.clear();
1729 tokens2states.put( s_j, edge.getBeta() );
1731 rewriteCallerReachability( index,
1734 paramIndex2rewriteJ_s2s.get( index ),
1736 paramIndex2rewrite_d_p,
1737 paramIndex2rewrite_d_s,
1738 paramIndex2rewriteD,
1743 edgesWithNewBeta.add( edge );
1747 // update directly upstream edges
1748 Hashtable<RefEdge, ChangeSet> edgeUpstreamPlannedChanges =
1749 new Hashtable<RefEdge, ChangeSet>();
1751 HashSet<RefEdge> edgesDirectlyUpstream =
1752 new HashSet<RefEdge>();
1754 edgeItr = edges_up_dr.get( index ).iterator();
1755 while( edgeItr.hasNext() ) {
1756 Vector mo = (Vector) edgeItr.next();
1757 RefEdge edge = (RefEdge) mo.get( 0 );
1758 Integer indexJ = (Integer) mo.get( 1 );
1760 edgesDirectlyUpstream.add( edge );
1762 ReachTuple p_j = ogCallee.paramIndex2paramTokenPrimary.get( indexJ );
1765 // start with K_p2 and p_j
1766 tokens2states.clear();
1767 tokens2states.put( p_j, edge.getBeta() );
1769 rewriteCallerReachability( index,
1772 paramIndex2rewriteK_p2.get( index ),
1774 paramIndex2rewrite_d_p,
1775 paramIndex2rewrite_d_s,
1776 paramIndex2rewriteD,
1779 edgeUpstreamPlannedChanges );
1781 // and add in s_j, if required, and do K_p
1782 ReachTuple s_j = ogCallee.paramIndex2paramTokenSecondary.get( indexJ );
1784 tokens2states.put( s_j, edge.getBeta() );
1787 rewriteCallerReachability( index,
1790 paramIndex2rewriteK_p.get( index ),
1792 paramIndex2rewrite_d_p,
1793 paramIndex2rewrite_d_s,
1794 paramIndex2rewriteD,
1797 edgeUpstreamPlannedChanges );
1799 edgesWithNewBeta.add( edge );
1802 propagateTokensOverEdges( edgesDirectlyUpstream,
1803 edgeUpstreamPlannedChanges,
1807 // update upstream edges
1808 edgeUpstreamPlannedChanges =
1809 new Hashtable<RefEdge, ChangeSet>();
1811 HashSet<RefEdge> edgesUpstream =
1812 new HashSet<RefEdge>();
1814 edgeItr = edges_up_r.get( index ).iterator();
1815 while( edgeItr.hasNext() ) {
1816 Vector mo = (Vector) edgeItr.next();
1817 RefEdge edge = (RefEdge) mo.get( 0 );
1818 Integer indexJ = (Integer) mo.get( 1 );
1820 if( !paramIndex2rewriteK_s.containsKey( index ) ) {
1824 edgesUpstream.add( edge );
1826 ReachTuple p_j = ogCallee.paramIndex2paramTokenPrimary.get( indexJ );
1829 ReachTuple s_j = ogCallee.paramIndex2paramTokenSecondary.get( indexJ );
1832 tokens2states.clear();
1833 tokens2states.put( p_j, rsWttsEmpty );
1834 tokens2states.put( s_j, edge.getBeta() );
1836 rewriteCallerReachability( index,
1839 paramIndex2rewriteK_s.get( index ),
1841 paramIndex2rewrite_d_p,
1842 paramIndex2rewrite_d_s,
1843 paramIndex2rewriteD,
1846 edgeUpstreamPlannedChanges );
1848 edgesWithNewBeta.add( edge );
1851 propagateTokensOverEdges( edgesUpstream,
1852 edgeUpstreamPlannedChanges,
1855 } // end effects per argument/parameter map
1858 // commit changes to alpha and beta
1859 Iterator<HeapRegionNode> nodeItr = nodesWithNewAlpha.iterator();
1860 while( nodeItr.hasNext() ) {
1861 nodeItr.next().applyAlphaNew();
1864 Iterator<RefEdge> edgeItr = edgesWithNewBeta.iterator();
1865 while( edgeItr.hasNext() ) {
1866 edgeItr.next().applyBetaNew();
1870 // verify the existence of allocation sites and their
1871 // shadows from the callee in the context of this caller graph
1872 // then map allocated nodes of callee onto the caller shadows
1874 Hashtable<ReachTuple, ReachSet> tokens2statesEmpty = new Hashtable<ReachTuple, ReachSet>();
1876 Iterator<AllocSite> asItr = ogCallee.allocSites.iterator();
1877 while( asItr.hasNext() ) {
1878 AllocSite allocSite = asItr.next();
1880 // grab the summary in the caller just to make sure
1881 // the allocation site has nodes in the caller
1882 HeapRegionNode hrnSummary = getSummaryNode( allocSite );
1884 // assert that the shadow nodes have no reference edges
1885 // because they're brand new to the graph, or last time
1886 // they were used they should have been cleared of edges
1887 HeapRegionNode hrnShadowSummary = getShadowSummaryNode( allocSite );
1888 assert hrnShadowSummary.getNumReferencers() == 0;
1889 assert hrnShadowSummary.getNumReferencees() == 0;
1891 // then bring g_ij onto g'_ij and rewrite
1892 HeapRegionNode hrnSummaryCallee = ogCallee.getSummaryNode( allocSite );
1893 hrnShadowSummary.setAlpha( toShadowTokens( ogCallee, hrnSummaryCallee.getAlpha() ) );
1895 // shadow nodes only are touched by a rewrite one time,
1896 // so rewrite and immediately commit--and they don't belong
1897 // to a particular parameter, so use a bogus param index
1898 // that pulls a self-rewrite out of H
1899 rewriteCallerReachability( bogusIndex,
1902 funcScriptR( hrnShadowSummary.getAlpha(), ogCallee, mc ),
1904 paramIndex2rewrite_d_p,
1905 paramIndex2rewrite_d_s,
1906 paramIndex2rewriteD,
1911 hrnShadowSummary.applyAlphaNew();
1914 for( int i = 0; i < allocSite.getAllocationDepth(); ++i ) {
1915 Integer idIth = allocSite.getIthOldest(i);
1916 assert id2hrn.containsKey(idIth);
1917 HeapRegionNode hrnIth = id2hrn.get(idIth);
1919 Integer idShadowIth = -(allocSite.getIthOldest(i));
1920 assert id2hrn.containsKey(idShadowIth);
1921 HeapRegionNode hrnIthShadow = id2hrn.get(idShadowIth);
1922 assert hrnIthShadow.getNumReferencers() == 0;
1923 assert hrnIthShadow.getNumReferencees() == 0;
1925 assert ogCallee.id2hrn.containsKey(idIth);
1926 HeapRegionNode hrnIthCallee = ogCallee.id2hrn.get(idIth);
1927 hrnIthShadow.setAlpha(toShadowTokens(ogCallee, hrnIthCallee.getAlpha() ) );
1929 rewriteCallerReachability( bogusIndex,
1932 funcScriptR( hrnIthShadow.getAlpha(), ogCallee, mc ),
1934 paramIndex2rewrite_d_p,
1935 paramIndex2rewrite_d_s,
1936 paramIndex2rewriteD,
1941 hrnIthShadow.applyAlphaNew();
1946 // for every heap region->heap region edge in the
1947 // callee graph, create the matching edge or edges
1948 // in the caller graph
1949 Set sCallee = ogCallee.id2hrn.entrySet();
1950 Iterator iCallee = sCallee.iterator();
1952 while( iCallee.hasNext() ) {
1953 Map.Entry meCallee = (Map.Entry) iCallee.next();
1954 Integer idCallee = (Integer) meCallee.getKey();
1955 HeapRegionNode hrnCallee = (HeapRegionNode) meCallee.getValue();
1957 Iterator<RefEdge> heapRegionsItrCallee = hrnCallee.iteratorToReferencees();
1958 while( heapRegionsItrCallee.hasNext() ) {
1959 RefEdge edgeCallee = heapRegionsItrCallee.next();
1960 HeapRegionNode hrnChildCallee = edgeCallee.getDst();
1961 Integer idChildCallee = hrnChildCallee.getID();
1963 // only address this edge if it is not a special initial edge
1964 if( !edgeCallee.isInitialParam() ) {
1966 // now we know that in the callee method's reachability graph
1967 // there is a heap region->heap region reference edge given
1968 // by heap region pointers:
1969 // hrnCallee -> heapChildCallee
1971 // or by the reachability-graph independent ID's:
1972 // idCallee -> idChildCallee
1974 // make the edge with src and dst so beta info is
1975 // calculated once, then copy it for each new edge in caller
1977 RefEdge edgeNewInCallerTemplate = new RefEdge( null,
1979 edgeCallee.getType(),
1980 edgeCallee.getField(),
1982 funcScriptR( toShadowTokens( ogCallee,
1983 edgeCallee.getBeta()
1989 rewriteCallerReachability( bogusIndex,
1991 edgeNewInCallerTemplate,
1992 edgeNewInCallerTemplate.getBeta(),
1994 paramIndex2rewrite_d_p,
1995 paramIndex2rewrite_d_s,
1996 paramIndex2rewriteD,
2001 edgeNewInCallerTemplate.applyBetaNew();
2004 // So now make a set of possible source heaps in the caller graph
2005 // and a set of destination heaps in the caller graph, and make
2006 // a reference edge in the caller for every possible (src,dst) pair
2007 HashSet<HeapRegionNode> possibleCallerSrcs =
2008 getHRNSetThatPossiblyMapToCalleeHRN( ogCallee,
2009 (HeapRegionNode) edgeCallee.getSrc(),
2013 HashSet<HeapRegionNode> possibleCallerDsts =
2014 getHRNSetThatPossiblyMapToCalleeHRN( ogCallee,
2015 edgeCallee.getDst(),
2019 // make every possible pair of {srcSet} -> {dstSet} edges in the caller
2020 Iterator srcItr = possibleCallerSrcs.iterator();
2021 while( srcItr.hasNext() ) {
2022 HeapRegionNode src = (HeapRegionNode) srcItr.next();
2024 if( !hasMatchingField( src, edgeCallee ) ) {
2025 // prune this source node possibility
2029 Iterator dstItr = possibleCallerDsts.iterator();
2030 while( dstItr.hasNext() ) {
2031 HeapRegionNode dst = (HeapRegionNode) dstItr.next();
2033 if( !hasMatchingType( edgeCallee, dst ) ) {
2042 // otherwise the caller src and dst pair can match the edge, so make it
2043 TypeDescriptor tdNewEdge =
2044 mostSpecificType( edgeCallee.getType(),
2045 hrnChildCallee.getType(),
2049 RefEdge edgeNewInCaller = edgeNewInCallerTemplate.copy();
2050 edgeNewInCaller.setSrc( src );
2051 edgeNewInCaller.setDst( dst );
2052 edgeNewInCaller.setType( tdNewEdge );
2055 // handle taint info if callee created this edge
2057 Set<Integer> pParamSet=idPrimary2paramIndexSet.get(dst.getID());
2058 Set<Integer> sParamSet=idSecondary2paramIndexSet.get(dst.getID());
2059 HashSet<Integer> paramSet=new HashSet<Integer>();
2060 if(pParamSet!=null){
2061 paramSet.addAll(pParamSet);
2063 if(sParamSet!=null){
2064 paramSet.addAll(sParamSet);
2066 Iterator<Integer> paramIter=paramSet.iterator();
2067 int newTaintIdentifier=0;
2068 while(paramIter.hasNext()){
2069 Integer paramIdx=paramIter.next();
2070 edgeNewInCaller.tainedBy(paramIdx);
2073 RefEdge edgeExisting = src.getReferenceTo( dst,
2074 edgeNewInCaller.getType(),
2075 edgeNewInCaller.getField() );
2076 if( edgeExisting == null ) {
2077 // if this edge doesn't exist in the caller, create it
2078 addRefEdge( src, dst, edgeNewInCaller );
2081 // if it already exists, merge with it
2082 edgeExisting.setBeta( edgeExisting.getBeta().union( edgeNewInCaller.getBeta() ) );
2092 // return value may need to be assigned in caller
2093 TempDescriptor returnTemp = fc.getReturnTemp();
2094 if( returnTemp != null && !returnTemp.getType().isImmutable() ) {
2096 VariableNode lnLhsCaller = getVariableNodeFromTemp( returnTemp );
2097 clearRefEdgesFrom( lnLhsCaller, null, null, true );
2099 VariableNode lnReturnCallee = ogCallee.getVariableNodeFromTemp( tdReturn );
2100 Iterator<RefEdge> edgeCalleeItr = lnReturnCallee.iteratorToReferencees();
2101 while( edgeCalleeItr.hasNext() ) {
2102 RefEdge edgeCallee = edgeCalleeItr.next();
2103 HeapRegionNode hrnChildCallee = edgeCallee.getDst();
2105 // some edge types are not possible return values when we can
2106 // see what type variable we are assigning it to
2107 if( !isSuperiorType( returnTemp.getType(), edgeCallee.getType() ) ) {
2108 System.out.println( "*** NOT EXPECTING TO SEE THIS: Throwing out "+edgeCallee+" for return temp "+returnTemp );
2113 RefEdge edgeNewInCallerTemplate = new RefEdge( null,
2115 edgeCallee.getType(),
2116 edgeCallee.getField(),
2118 funcScriptR( toShadowTokens(ogCallee,
2119 edgeCallee.getBeta() ),
2123 rewriteCallerReachability( bogusIndex,
2125 edgeNewInCallerTemplate,
2126 edgeNewInCallerTemplate.getBeta(),
2128 paramIndex2rewrite_d_p,
2129 paramIndex2rewrite_d_s,
2130 paramIndex2rewriteD,
2135 edgeNewInCallerTemplate.applyBetaNew();
2138 HashSet<HeapRegionNode> assignCallerRhs =
2139 getHRNSetThatPossiblyMapToCalleeHRN( ogCallee,
2140 edgeCallee.getDst(),
2144 Iterator<HeapRegionNode> itrHrn = assignCallerRhs.iterator();
2145 while( itrHrn.hasNext() ) {
2146 HeapRegionNode hrnCaller = itrHrn.next();
2148 // don't make edge in caller if it is disallowed by types
2149 if( !isSuperiorType( returnTemp.getType(), hrnCaller.getType() ) ) {
2154 if( !isSuperiorType( returnTemp.getType(), hrnChildCallee.getType() ) ) {
2159 if( !isSuperiorType( edgeCallee.getType(), hrnCaller.getType() ) ) {
2164 TypeDescriptor tdNewEdge =
2165 mostSpecificType( edgeCallee.getType(),
2166 hrnChildCallee.getType(),
2170 // otherwise caller node can match callee edge, so make it
2171 RefEdge edgeNewInCaller = edgeNewInCallerTemplate.copy();
2172 edgeNewInCaller.setSrc( lnLhsCaller );
2173 edgeNewInCaller.setDst( hrnCaller );
2174 edgeNewInCaller.setType( tdNewEdge );
2176 RefEdge edgeExisting = lnLhsCaller.getReferenceTo( hrnCaller,
2178 edgeNewInCaller.getField() );
2179 if( edgeExisting == null ) {
2181 // if this edge doesn't exist in the caller, create it
2182 addRefEdge( lnLhsCaller, hrnCaller, edgeNewInCaller );
2184 // if it already exists, merge with it
2185 edgeExisting.setBeta( edgeExisting.getBeta().union( edgeNewInCaller.getBeta() ) );
2193 // merge the shadow nodes of allocation sites back down to normal capacity
2194 Iterator<AllocSite> allocItr = ogCallee.allocSites.iterator();
2195 while( allocItr.hasNext() ) {
2196 AllocSite as = allocItr.next();
2198 // first age each allocation site enough times to make room for the shadow nodes
2199 for( int i = 0; i < as.getAllocationDepth(); ++i ) {
2203 // then merge the shadow summary into the normal summary
2204 HeapRegionNode hrnSummary = getSummaryNode( as );
2205 assert hrnSummary != null;
2207 HeapRegionNode hrnSummaryShadow = getShadowSummaryNode( as );
2208 assert hrnSummaryShadow != null;
2210 mergeIntoSummary( hrnSummaryShadow, hrnSummary );
2212 // then clear off after merge
2213 clearRefEdgesFrom( hrnSummaryShadow, null, null, true );
2214 clearRefEdgesTo ( hrnSummaryShadow, null, null, true );
2215 hrnSummaryShadow.setAlpha( new ReachSet().makeCanonical() );
2217 // then transplant shadow nodes onto the now clean normal nodes
2218 for( int i = 0; i < as.getAllocationDepth(); ++i ) {
2220 Integer idIth = as.getIthOldest( i );
2221 HeapRegionNode hrnIth = id2hrn.get( idIth );
2222 Integer idIthShadow = as.getIthOldestShadow( i );
2223 HeapRegionNode hrnIthShadow = id2hrn.get( idIthShadow );
2225 transferOnto( hrnIthShadow, hrnIth );
2227 // clear off shadow nodes after transfer
2228 clearRefEdgesFrom( hrnIthShadow, null, null, true );
2229 clearRefEdgesTo ( hrnIthShadow, null, null, true );
2230 hrnIthShadow.setAlpha( new ReachSet().makeCanonical() );
2233 // finally, globally change shadow tokens into normal tokens
2234 Iterator itrAllVariableNodes = td2vn.entrySet().iterator();
2235 while( itrAllVariableNodes.hasNext() ) {
2236 Map.Entry me = (Map.Entry) itrAllVariableNodes.next();
2237 VariableNode ln = (VariableNode) me.getValue();
2239 Iterator<RefEdge> itrEdges = ln.iteratorToReferencees();
2240 while( itrEdges.hasNext() ) {
2241 unshadowTokens( as, itrEdges.next() );
2245 Iterator itrAllHRNodes = id2hrn.entrySet().iterator();
2246 while( itrAllHRNodes.hasNext() ) {
2247 Map.Entry me = (Map.Entry) itrAllHRNodes.next();
2248 HeapRegionNode hrnToAge = (HeapRegionNode) me.getValue();
2250 unshadowTokens( as, hrnToAge );
2252 Iterator<RefEdge> itrEdges = hrnToAge.iteratorToReferencees();
2253 while( itrEdges.hasNext() ) {
2254 unshadowTokens( as, itrEdges.next() );
2261 // improve reachability as much as possible
2262 if( !DISABLE_GLOBAL_SWEEP ) {
2268 mc.getDescriptor().getSymbol().equals( debugCaller ) &&
2269 fm.getMethod().getSymbol().equals( debugCallee )
2273 writeGraph( "debug9endResolveCall",
2274 true, // write labels (variables)
2275 true, // selectively hide intermediate temp vars
2276 true, // prune unreachable heap regions
2277 false, // show back edges to confirm graph validity
2278 false, // show parameter indices (unmaintained!)
2279 true, // hide subset reachability states
2280 true); // hide edge taints
2281 } catch( IOException e ) {}
2282 System.out.println( " "+mc+" done calling "+fm );
2284 if( x == debugCallMapCount ) {
2294 protected boolean hasMatchingField(HeapRegionNode src, RefEdge edge) {
2296 // if no type, then it's a match-everything region
2297 TypeDescriptor tdSrc = src.getType();
2298 if( tdSrc == null ) {
2302 if( tdSrc.isArray() ) {
2303 TypeDescriptor td = edge.getType();
2306 TypeDescriptor tdSrcDeref = tdSrc.dereference();
2307 assert tdSrcDeref != null;
2309 if( !typeUtil.isSuperorType( tdSrcDeref, td ) ) {
2313 return edge.getField().equals( DisjointAnalysis.arrayElementFieldName );
2316 // if it's not a class, it doesn't have any fields to match
2317 if( !tdSrc.isClass() ) {
2321 ClassDescriptor cd = tdSrc.getClassDesc();
2322 while( cd != null ) {
2323 Iterator fieldItr = cd.getFields();
2325 while( fieldItr.hasNext() ) {
2326 FieldDescriptor fd = (FieldDescriptor) fieldItr.next();
2328 if( fd.getType().equals( edge.getType() ) &&
2329 fd.getSymbol().equals( edge.getField() ) ) {
2334 cd = cd.getSuperDesc();
2337 // otherwise it is a class with fields
2338 // but we didn't find a match
2343 protected boolean hasMatchingType(RefEdge edge, HeapRegionNode dst) {
2345 // if the region has no type, matches everything
2346 TypeDescriptor tdDst = dst.getType();
2347 if( tdDst == null ) {
2351 // if the type is not a class or an array, don't
2352 // match because primitives are copied, no aliases
2353 ClassDescriptor cdDst = tdDst.getClassDesc();
2354 if( cdDst == null && !tdDst.isArray() ) {
2358 // if the edge type is null, it matches everything
2359 TypeDescriptor tdEdge = edge.getType();
2360 if( tdEdge == null ) {
2364 return typeUtil.isSuperorType(tdEdge, tdDst);
2368 protected void unshadowTokens(AllocSite as, RefEdge edge) {
2369 edge.setBeta(edge.getBeta().unshadowTokens(as) );
2372 protected void unshadowTokens(AllocSite as, HeapRegionNode hrn) {
2373 hrn.setAlpha(hrn.getAlpha().unshadowTokens(as) );
2377 private ReachSet toShadowTokens(ReachGraph ogCallee,
2380 ReachSet rsOut = new ReachSet(rsIn).makeCanonical();
2382 Iterator<AllocSite> allocItr = ogCallee.allocSites.iterator();
2383 while( allocItr.hasNext() ) {
2384 AllocSite as = allocItr.next();
2386 rsOut = rsOut.toShadowTokens(as);
2389 return rsOut.makeCanonical();
2393 private void rewriteCallerReachability(Integer paramIndex,
2397 Hashtable<ReachTuple, ReachSet> tokens2states,
2398 Hashtable<Integer, ReachSet> paramIndex2rewrite_d_p,
2399 Hashtable<Integer, ReachSet> paramIndex2rewrite_d_s,
2400 Hashtable<Integer, ReachSet> paramIndex2rewriteD,
2401 ReachGraph ogCallee,
2402 boolean makeChangeSet,
2403 Hashtable<RefEdge, ChangeSet> edgePlannedChanges) {
2405 assert(hrn == null && edge != null) ||
2406 (hrn != null && edge == null);
2408 assert rules != null;
2409 assert tokens2states != null;
2411 ReachSet callerReachabilityNew = new ReachSet().makeCanonical();
2413 // for initializing structures in this method
2414 ReachState ttsEmpty = new ReachState().makeCanonical();
2416 // use this to construct a change set if required; the idea is to
2417 // map every partially rewritten token tuple set to the set of
2418 // caller-context token tuple sets that were used to generate it
2419 Hashtable<ReachState, HashSet<ReachState> > rewritten2source =
2420 new Hashtable<ReachState, HashSet<ReachState> >();
2421 rewritten2source.put( ttsEmpty, new HashSet<ReachState>() );
2424 Iterator<ReachState> rulesItr = rules.iterator();
2425 while(rulesItr.hasNext()) {
2426 ReachState rule = rulesItr.next();
2428 ReachSet rewrittenRule = new ReachSet(ttsEmpty).makeCanonical();
2430 Iterator<ReachTuple> ruleItr = rule.iterator();
2431 while(ruleItr.hasNext()) {
2432 ReachTuple ttCallee = ruleItr.next();
2434 // compute the possibilities for rewriting this callee token
2435 ReachSet ttCalleeRewrites = null;
2436 boolean callerSourceUsed = false;
2438 if( tokens2states.containsKey( ttCallee ) ) {
2439 callerSourceUsed = true;
2440 ttCalleeRewrites = tokens2states.get( ttCallee );
2441 assert ttCalleeRewrites != null;
2443 } else if( ogCallee.paramTokenPrimary2paramIndex.containsKey( ttCallee ) ) {
2445 Integer paramIndex_j = ogCallee.paramTokenPrimary2paramIndex.get( ttCallee );
2446 assert paramIndex_j != null;
2447 ttCalleeRewrites = paramIndex2rewrite_d_p.get( paramIndex_j );
2448 assert ttCalleeRewrites != null;
2450 } else if( ogCallee.paramTokenSecondary2paramIndex.containsKey( ttCallee ) ) {
2452 Integer paramIndex_j = ogCallee.paramTokenSecondary2paramIndex.get( ttCallee );
2453 assert paramIndex_j != null;
2454 ttCalleeRewrites = paramIndex2rewrite_d_s.get( paramIndex_j );
2455 assert ttCalleeRewrites != null;
2457 } else if( ogCallee.paramTokenSecondaryPlus2paramIndex.containsKey( ttCallee ) ) {
2459 Integer paramIndex_j = ogCallee.paramTokenSecondaryPlus2paramIndex.get( ttCallee );
2460 assert paramIndex_j != null;
2461 ttCalleeRewrites = paramIndex2rewriteD.get( paramIndex_j );
2462 assert ttCalleeRewrites != null;
2464 } else if( ogCallee.paramTokenSecondaryStar2paramIndex.containsKey( ttCallee ) ) {
2466 Integer paramIndex_j = ogCallee.paramTokenSecondaryStar2paramIndex.get( ttCallee );
2467 assert paramIndex_j != null;
2468 ttCalleeRewrites = paramIndex2rewriteD.get( paramIndex_j );
2469 assert ttCalleeRewrites != null;
2472 // otherwise there's no need for a rewrite, just pass this one on
2473 ReachState ttsCaller = new ReachState( ttCallee ).makeCanonical();
2474 ttCalleeRewrites = new ReachSet( ttsCaller ).makeCanonical();
2477 // branch every version of the working rewritten rule with
2478 // the possibilities for rewriting the current callee token
2479 ReachSet rewrittenRuleWithTTCallee = new ReachSet().makeCanonical();
2481 Iterator<ReachState> rewrittenRuleItr = rewrittenRule.iterator();
2482 while( rewrittenRuleItr.hasNext() ) {
2483 ReachState ttsRewritten = rewrittenRuleItr.next();
2485 Iterator<ReachState> ttCalleeRewritesItr = ttCalleeRewrites.iterator();
2486 while( ttCalleeRewritesItr.hasNext() ) {
2487 ReachState ttsBranch = ttCalleeRewritesItr.next();
2489 ReachState ttsRewrittenNext = ttsRewritten.unionUpArity( ttsBranch );
2491 if( makeChangeSet ) {
2492 // in order to keep the list of source token tuple sets
2493 // start with the sets used to make the partially rewritten
2494 // rule up to this point
2495 HashSet<ReachState> sourceSets = rewritten2source.get( ttsRewritten );
2496 assert sourceSets != null;
2498 // make a shallow copy for possible modification
2499 sourceSets = (HashSet<ReachState>) sourceSets.clone();
2501 // if we used something from the caller to rewrite it, remember
2502 if( callerSourceUsed ) {
2503 sourceSets.add( ttsBranch );
2506 // set mapping for the further rewritten rule
2507 rewritten2source.put( ttsRewrittenNext, sourceSets );
2510 rewrittenRuleWithTTCallee =
2511 rewrittenRuleWithTTCallee.union( ttsRewrittenNext );
2515 // now the rewritten rule's possibilities have been extended by
2516 // rewriting the current callee token, remember result
2517 rewrittenRule = rewrittenRuleWithTTCallee;
2520 // the rule has been entirely rewritten into the caller context
2521 // now, so add it to the new reachability information
2522 callerReachabilityNew =
2523 callerReachabilityNew.union( rewrittenRule );
2526 if( makeChangeSet ) {
2527 ChangeSet callerChangeSet = new ChangeSet().makeCanonical();
2529 // each possibility for the final reachability should have a set of
2530 // caller sources mapped to it, use to create the change set
2531 Iterator<ReachState> callerReachabilityItr = callerReachabilityNew.iterator();
2532 while( callerReachabilityItr.hasNext() ) {
2533 ReachState ttsRewrittenFinal = callerReachabilityItr.next();
2534 HashSet<ReachState> sourceSets = rewritten2source.get( ttsRewrittenFinal );
2535 assert sourceSets != null;
2537 Iterator<ReachState> sourceSetsItr = sourceSets.iterator();
2538 while( sourceSetsItr.hasNext() ) {
2539 ReachState ttsSource = sourceSetsItr.next();
2542 callerChangeSet.union( new ChangeTuple( ttsSource, ttsRewrittenFinal ) );
2546 assert edgePlannedChanges != null;
2547 edgePlannedChanges.put( edge, callerChangeSet );
2551 edge.setBetaNew( edge.getBetaNew().union( callerReachabilityNew ) );
2553 hrn.setAlphaNew( hrn.getAlphaNew().union( callerReachabilityNew ) );
2559 private HashSet<HeapRegionNode>
2560 getHRNSetThatPossiblyMapToCalleeHRN( ReachGraph ogCallee,
2561 HeapRegionNode hrnCallee,
2562 Hashtable<Integer, Set<HeapRegionNode> > pi2dr,
2563 Hashtable<Integer, Set<HeapRegionNode> > pi2r
2566 HashSet<HeapRegionNode> possibleCallerHRNs = new HashSet<HeapRegionNode>();
2568 Set<Integer> paramIndicesCallee_p = ogCallee.idPrimary2paramIndexSet .get( hrnCallee.getID() );
2569 Set<Integer> paramIndicesCallee_s = ogCallee.idSecondary2paramIndexSet.get( hrnCallee.getID() );
2571 if( paramIndicesCallee_p == null &&
2572 paramIndicesCallee_s == null ) {
2573 // this is a node allocated in the callee and it has
2574 // exactly one shadow node in the caller to map to
2575 AllocSite as = hrnCallee.getAllocSite();
2578 int age = as.getAgeCategory( hrnCallee.getID() );
2579 assert age != AllocSite.AGE_notInThisSite;
2582 if( age == AllocSite.AGE_summary ) {
2583 idCaller = as.getSummaryShadow();
2585 } else if( age == AllocSite.AGE_oldest ) {
2586 idCaller = as.getOldestShadow();
2589 assert age == AllocSite.AGE_in_I;
2591 Integer I = as.getAge( hrnCallee.getID() );
2594 idCaller = as.getIthOldestShadow( I );
2597 assert id2hrn.containsKey( idCaller );
2598 possibleCallerHRNs.add( id2hrn.get( idCaller ) );
2600 return possibleCallerHRNs;
2603 // find out what primary objects this might be
2604 if( paramIndicesCallee_p != null ) {
2605 // this is a node that was created to represent a parameter
2606 // so it maps to some regions directly reachable from the arg labels
2607 Iterator<Integer> itrIndex = paramIndicesCallee_p.iterator();
2608 while( itrIndex.hasNext() ) {
2609 Integer paramIndexCallee = itrIndex.next();
2610 assert pi2dr.containsKey( paramIndexCallee );
2611 possibleCallerHRNs.addAll( pi2dr.get( paramIndexCallee ) );
2615 // find out what secondary objects this might be
2616 if( paramIndicesCallee_s != null ) {
2617 // this is a node that was created to represent objs reachable from
2618 // some parameter, so it maps to regions reachable from the arg labels
2619 Iterator<Integer> itrIndex = paramIndicesCallee_s.iterator();
2620 while( itrIndex.hasNext() ) {
2621 Integer paramIndexCallee = itrIndex.next();
2622 assert pi2r.containsKey( paramIndexCallee );
2623 possibleCallerHRNs.addAll( pi2r.get( paramIndexCallee ) );
2627 // TODO: is this true?
2628 // one of the two cases above should have put something in here
2629 //assert !possibleCallerHRNs.isEmpty();
2631 return possibleCallerHRNs;
2636 ////////////////////////////////////////////////////
2638 // This global sweep is an optional step to prune
2639 // reachability sets that are not internally
2640 // consistent with the global graph. It should be
2641 // invoked after strong updates or method calls.
2643 ////////////////////////////////////////////////////
2644 public void globalSweep() {
2646 // boldB is part of the phase 1 sweep
2647 Hashtable< Integer, Hashtable<RefEdge, ReachSet> > boldB =
2648 new Hashtable< Integer, Hashtable<RefEdge, ReachSet> >();
2650 // visit every heap region to initialize alphaNew and calculate boldB
2651 Set hrns = id2hrn.entrySet();
2652 Iterator itrHrns = hrns.iterator();
2653 while( itrHrns.hasNext() ) {
2654 Map.Entry me = (Map.Entry)itrHrns.next();
2655 Integer token = (Integer) me.getKey();
2656 HeapRegionNode hrn = (HeapRegionNode) me.getValue();
2658 // assert that this node and incoming edges have clean alphaNew
2659 // and betaNew sets, respectively
2660 assert rstateEmpty.equals( hrn.getAlphaNew() );
2662 Iterator<RefEdge> itrRers = hrn.iteratorToReferencers();
2663 while( itrRers.hasNext() ) {
2664 RefEdge edge = itrRers.next();
2665 assert rstateEmpty.equals( edge.getBetaNew() );
2668 // calculate boldB for this flagged node
2669 if( hrn.isFlagged() ) {
2671 Hashtable<RefEdge, ReachSet> boldB_f =
2672 new Hashtable<RefEdge, ReachSet>();
2674 Set<RefEdge> workSetEdges = new HashSet<RefEdge>();
2676 // initial boldB_f constraints
2677 Iterator<RefEdge> itrRees = hrn.iteratorToReferencees();
2678 while( itrRees.hasNext() ) {
2679 RefEdge edge = itrRees.next();
2681 assert !boldB.containsKey( edge );
2682 boldB_f.put( edge, edge.getBeta() );
2684 assert !workSetEdges.contains( edge );
2685 workSetEdges.add( edge );
2688 // enforce the boldB_f constraint at edges until we reach a fixed point
2689 while( !workSetEdges.isEmpty() ) {
2690 RefEdge edge = workSetEdges.iterator().next();
2691 workSetEdges.remove( edge );
2693 Iterator<RefEdge> itrPrime = edge.getDst().iteratorToReferencees();
2694 while( itrPrime.hasNext() ) {
2695 RefEdge edgePrime = itrPrime.next();
2697 ReachSet prevResult = boldB_f.get( edgePrime );
2698 ReachSet intersection = boldB_f.get( edge ).intersection( edgePrime.getBeta() );
2700 if( prevResult == null ||
2701 prevResult.union( intersection ).size() > prevResult.size() ) {
2703 if( prevResult == null ) {
2704 boldB_f.put( edgePrime, edgePrime.getBeta().union( intersection ) );
2706 boldB_f.put( edgePrime, prevResult .union( intersection ) );
2708 workSetEdges.add( edgePrime );
2713 boldB.put( token, boldB_f );
2718 // use boldB to prune tokens from alpha states that are impossible
2719 // and propagate the differences backwards across edges
2720 HashSet<RefEdge> edgesForPropagation = new HashSet<RefEdge>();
2722 Hashtable<RefEdge, ChangeSet> edgePlannedChanges =
2723 new Hashtable<RefEdge, ChangeSet>();
2725 hrns = id2hrn.entrySet();
2726 itrHrns = hrns.iterator();
2727 while( itrHrns.hasNext() ) {
2728 Map.Entry me = (Map.Entry)itrHrns.next();
2729 Integer token = (Integer) me.getKey();
2730 HeapRegionNode hrn = (HeapRegionNode) me.getValue();
2732 // never remove the identity token from a flagged region
2733 // because it is trivially satisfied
2734 ReachTuple ttException = new ReachTuple( token,
2735 !hrn.isSingleObject(),
2736 ReachTuple.ARITY_ONE ).makeCanonical();
2738 ChangeSet cts = new ChangeSet().makeCanonical();
2740 // mark tokens for removal
2741 Iterator<ReachState> stateItr = hrn.getAlpha().iterator();
2742 while( stateItr.hasNext() ) {
2743 ReachState ttsOld = stateItr.next();
2745 ReachState markedTokens = new ReachState().makeCanonical();
2747 Iterator<ReachTuple> ttItr = ttsOld.iterator();
2748 while( ttItr.hasNext() ) {
2749 ReachTuple ttOld = ttItr.next();
2751 // never remove the identity token from a flagged region
2752 // because it is trivially satisfied
2753 if( hrn.isFlagged() ) {
2754 if( ttOld == ttException ) {
2759 // does boldB_ttOld allow this token?
2760 boolean foundState = false;
2761 Iterator<RefEdge> incidentEdgeItr = hrn.iteratorToReferencers();
2762 while( incidentEdgeItr.hasNext() ) {
2763 RefEdge incidentEdge = incidentEdgeItr.next();
2765 // if it isn't allowed, mark for removal
2766 Integer idOld = ttOld.getToken();
2767 assert id2hrn.containsKey( idOld );
2768 Hashtable<RefEdge, ReachSet> B = boldB.get( idOld );
2769 ReachSet boldB_ttOld_incident = B.get( incidentEdge );// B is NULL!
2770 if( boldB_ttOld_incident != null &&
2771 boldB_ttOld_incident.contains( ttsOld ) ) {
2777 markedTokens = markedTokens.add( ttOld );
2781 // if there is nothing marked, just move on
2782 if( markedTokens.isEmpty() ) {
2783 hrn.setAlphaNew( hrn.getAlphaNew().union( ttsOld ) );
2787 // remove all marked tokens and establish a change set that should
2788 // propagate backwards over edges from this node
2789 ReachState ttsPruned = new ReachState().makeCanonical();
2790 ttItr = ttsOld.iterator();
2791 while( ttItr.hasNext() ) {
2792 ReachTuple ttOld = ttItr.next();
2794 if( !markedTokens.containsTuple( ttOld ) ) {
2795 ttsPruned = ttsPruned.union( ttOld );
2798 assert !ttsOld.equals( ttsPruned );
2800 hrn.setAlphaNew( hrn.getAlphaNew().union( ttsPruned ) );
2801 ChangeTuple ct = new ChangeTuple( ttsOld, ttsPruned ).makeCanonical();
2802 cts = cts.union( ct );
2805 // throw change tuple set on all incident edges
2806 if( !cts.isEmpty() ) {
2807 Iterator<RefEdge> incidentEdgeItr = hrn.iteratorToReferencers();
2808 while( incidentEdgeItr.hasNext() ) {
2809 RefEdge incidentEdge = incidentEdgeItr.next();
2811 edgesForPropagation.add( incidentEdge );
2813 if( edgePlannedChanges.get( incidentEdge ) == null ) {
2814 edgePlannedChanges.put( incidentEdge, cts );
2816 edgePlannedChanges.put(
2818 edgePlannedChanges.get( incidentEdge ).union( cts )
2825 HashSet<RefEdge> edgesUpdated = new HashSet<RefEdge>();
2827 propagateTokensOverEdges( edgesForPropagation,
2831 // at the end of the 1st phase reference edges have
2832 // beta, betaNew that correspond to beta and betaR
2834 // commit beta<-betaNew, so beta=betaR and betaNew
2835 // will represent the beta' calculation in 2nd phase
2837 // commit alpha<-alphaNew because it won't change
2838 HashSet<RefEdge> res = new HashSet<RefEdge>();
2840 Iterator<HeapRegionNode> nodeItr = id2hrn.values().iterator();
2841 while( nodeItr.hasNext() ) {
2842 HeapRegionNode hrn = nodeItr.next();
2843 hrn.applyAlphaNew();
2844 Iterator<RefEdge> itrRes = hrn.iteratorToReferencers();
2845 while( itrRes.hasNext() ) {
2846 res.add( itrRes.next() );
2852 Iterator<RefEdge> edgeItr = res.iterator();
2853 while( edgeItr.hasNext() ) {
2854 RefEdge edge = edgeItr.next();
2855 HeapRegionNode hrn = edge.getDst();
2857 // commit results of last phase
2858 if( edgesUpdated.contains( edge ) ) {
2859 edge.applyBetaNew();
2862 // compute intial condition of 2nd phase
2863 edge.setBetaNew( edge.getBeta().intersection( hrn.getAlpha() ) );
2866 // every edge in the graph is the initial workset
2867 Set<RefEdge> edgeWorkSet = (Set) res.clone();
2868 while( !edgeWorkSet.isEmpty() ) {
2869 RefEdge edgePrime = edgeWorkSet.iterator().next();
2870 edgeWorkSet.remove( edgePrime );
2872 RefSrcNode on = edgePrime.getSrc();
2873 if( !(on instanceof HeapRegionNode) ) {
2876 HeapRegionNode hrn = (HeapRegionNode) on;
2878 Iterator<RefEdge> itrEdge = hrn.iteratorToReferencers();
2879 while( itrEdge.hasNext() ) {
2880 RefEdge edge = itrEdge.next();
2882 ReachSet prevResult = edge.getBetaNew();
2883 assert prevResult != null;
2885 ReachSet intersection = edge.getBeta().intersection( edgePrime.getBetaNew() );
2887 if( prevResult.union( intersection ).size() > prevResult.size() ) {
2888 edge.setBetaNew( prevResult.union( intersection ) );
2889 edgeWorkSet.add( edge );
2894 // commit beta' (beta<-betaNew)
2895 edgeItr = res.iterator();
2896 while( edgeItr.hasNext() ) {
2897 edgeItr.next().applyBetaNew();
2903 ////////////////////////////////////////////////////
2904 // high-level merge operations
2905 ////////////////////////////////////////////////////
2906 public void merge_sameMethodContext( ReachGraph rg ) {
2907 // when merging two graphs that abstract the heap
2908 // of the same method context, we just call the
2909 // basic merge operation
2913 public void merge_diffMethodContext( ReachGraph rg ) {
2914 // when merging graphs for abstract heaps in
2915 // different method contexts we should:
2916 // 1) age the allocation sites?
2920 ////////////////////////////////////////////////////
2921 // in merge() and equals() methods the suffix A
2922 // represents the passed in graph and the suffix
2923 // B refers to the graph in this object
2924 // Merging means to take the incoming graph A and
2925 // merge it into B, so after the operation graph B
2926 // is the final result.
2927 ////////////////////////////////////////////////////
2928 protected void merge( ReachGraph rg ) {
2935 mergeRefEdges ( rg );
2936 mergeAllocSites ( rg );
2937 mergeAccessPaths( rg );
2940 protected void mergeNodes( ReachGraph rg ) {
2942 // start with heap region nodes
2943 Set sA = rg.id2hrn.entrySet();
2944 Iterator iA = sA.iterator();
2945 while( iA.hasNext() ) {
2946 Map.Entry meA = (Map.Entry) iA.next();
2947 Integer idA = (Integer) meA.getKey();
2948 HeapRegionNode hrnA = (HeapRegionNode) meA.getValue();
2950 // if this graph doesn't have a node the
2951 // incoming graph has, allocate it
2952 if( !id2hrn.containsKey( idA ) ) {
2953 HeapRegionNode hrnB = hrnA.copy();
2954 id2hrn.put( idA, hrnB );
2957 // otherwise this is a node present in both graphs
2958 // so make the new reachability set a union of the
2959 // nodes' reachability sets
2960 HeapRegionNode hrnB = id2hrn.get( idA );
2961 hrnB.setAlpha( hrnB.getAlpha().union( hrnA.getAlpha() ) );
2963 // if hrnB is already dirty or hrnA is dirty,
2964 // the hrnB should end up dirty
2965 if( !hrnA.isClean() ) {
2966 hrnB.setIsClean( false );
2971 // now add any variable nodes that are in graph B but
2973 sA = rg.td2vn.entrySet();
2975 while( iA.hasNext() ) {
2976 Map.Entry meA = (Map.Entry) iA.next();
2977 TempDescriptor tdA = (TempDescriptor) meA.getKey();
2978 VariableNode lnA = (VariableNode) meA.getValue();
2980 // if the variable doesn't exist in B, allocate and add it
2981 VariableNode lnB = getVariableNodeFromTemp( tdA );
2985 protected void mergeRefEdges( ReachGraph rg ) {
2987 // between heap regions
2988 Set sA = rg.id2hrn.entrySet();
2989 Iterator iA = sA.iterator();
2990 while( iA.hasNext() ) {
2991 Map.Entry meA = (Map.Entry) iA.next();
2992 Integer idA = (Integer) meA.getKey();
2993 HeapRegionNode hrnA = (HeapRegionNode) meA.getValue();
2995 Iterator<RefEdge> heapRegionsItrA = hrnA.iteratorToReferencees();
2996 while( heapRegionsItrA.hasNext() ) {
2997 RefEdge edgeA = heapRegionsItrA.next();
2998 HeapRegionNode hrnChildA = edgeA.getDst();
2999 Integer idChildA = hrnChildA.getID();
3001 // at this point we know an edge in graph A exists
3002 // idA -> idChildA, does this exist in B?
3003 assert id2hrn.containsKey( idA );
3004 HeapRegionNode hrnB = id2hrn.get( idA );
3005 RefEdge edgeToMerge = null;
3007 Iterator<RefEdge> heapRegionsItrB = hrnB.iteratorToReferencees();
3008 while( heapRegionsItrB.hasNext() &&
3009 edgeToMerge == null ) {
3011 RefEdge edgeB = heapRegionsItrB.next();
3012 HeapRegionNode hrnChildB = edgeB.getDst();
3013 Integer idChildB = hrnChildB.getID();
3015 // don't use the RefEdge.equals() here because
3016 // we're talking about existence between graphs,
3017 // not intragraph equal
3018 if( idChildB.equals( idChildA ) &&
3019 edgeB.typeAndFieldEquals( edgeA ) ) {
3021 edgeToMerge = edgeB;
3025 // if the edge from A was not found in B,
3027 if( edgeToMerge == null ) {
3028 assert id2hrn.containsKey( idChildA );
3029 HeapRegionNode hrnChildB = id2hrn.get( idChildA );
3030 edgeToMerge = edgeA.copy();
3031 edgeToMerge.setSrc( hrnB );
3032 edgeToMerge.setDst( hrnChildB );
3033 addRefEdge( hrnB, hrnChildB, edgeToMerge );
3035 // otherwise, the edge already existed in both graphs
3036 // so merge their reachability sets
3038 // just replace this beta set with the union
3039 assert edgeToMerge != null;
3040 edgeToMerge.setBeta(
3041 edgeToMerge.getBeta().union( edgeA.getBeta() )
3043 if( !edgeA.isClean() ) {
3044 edgeToMerge.setIsClean( false );
3050 // and then again from variable nodes
3051 sA = rg.td2vn.entrySet();
3053 while( iA.hasNext() ) {
3054 Map.Entry meA = (Map.Entry) iA.next();
3055 TempDescriptor tdA = (TempDescriptor) meA.getKey();
3056 VariableNode vnA = (VariableNode) meA.getValue();
3058 Iterator<RefEdge> heapRegionsItrA = vnA.iteratorToReferencees();
3059 while( heapRegionsItrA.hasNext() ) {
3060 RefEdge edgeA = heapRegionsItrA.next();
3061 HeapRegionNode hrnChildA = edgeA.getDst();
3062 Integer idChildA = hrnChildA.getID();
3064 // at this point we know an edge in graph A exists
3065 // tdA -> idChildA, does this exist in B?
3066 assert td2vn.containsKey( tdA );
3067 VariableNode vnB = td2vn.get( tdA );
3068 RefEdge edgeToMerge = null;
3070 Iterator<RefEdge> heapRegionsItrB = vnB.iteratorToReferencees();
3071 while( heapRegionsItrB.hasNext() &&
3072 edgeToMerge == null ) {
3074 RefEdge edgeB = heapRegionsItrB.next();
3075 HeapRegionNode hrnChildB = edgeB.getDst();
3076 Integer idChildB = hrnChildB.getID();
3078 // don't use the RefEdge.equals() here because
3079 // we're talking about existence between graphs
3080 if( idChildB.equals( idChildA ) &&
3081 edgeB.typeAndFieldEquals( edgeA ) ) {
3083 edgeToMerge = edgeB;
3087 // if the edge from A was not found in B,
3089 if( edgeToMerge == null ) {
3090 assert id2hrn.containsKey( idChildA );
3091 HeapRegionNode hrnChildB = id2hrn.get( idChildA );
3092 edgeToMerge = edgeA.copy();
3093 edgeToMerge.setSrc( vnB );
3094 edgeToMerge.setDst( hrnChildB );
3095 addRefEdge( vnB, hrnChildB, edgeToMerge );
3097 // otherwise, the edge already existed in both graphs
3098 // so merge their reachability sets
3100 // just replace this beta set with the union
3101 edgeToMerge.setBeta(
3102 edgeToMerge.getBeta().union( edgeA.getBeta() )
3104 if( !edgeA.isClean() ) {
3105 edgeToMerge.setIsClean( false );
3112 protected void mergeAllocSites( ReachGraph rg ) {
3113 allocSites.addAll( rg.allocSites );
3116 protected void mergeAccessPaths( ReachGraph rg ) {
3117 UtilAlgorithms.mergeHashtablesWithHashSetValues( temp2accessPaths,
3118 rg.temp2accessPaths );
3122 // it is necessary in the equals() member functions
3123 // to "check both ways" when comparing the data
3124 // structures of two graphs. For instance, if all
3125 // edges between heap region nodes in graph A are
3126 // present and equal in graph B it is not sufficient
3127 // to say the graphs are equal. Consider that there
3128 // may be edges in graph B that are not in graph A.
3129 // the only way to know that all edges in both graphs
3130 // are equally present is to iterate over both data
3131 // structures and compare against the other graph.
3132 public boolean equals( ReachGraph rg ) {
3138 if( !areHeapRegionNodesEqual( rg ) ) {
3142 if( !areVariableNodesEqual( rg ) ) {
3146 if( !areRefEdgesEqual( rg ) ) {
3150 if( !areAccessPathsEqual( rg ) ) {
3154 // if everything is equal up to this point,
3155 // assert that allocSites is also equal--
3156 // this data is redundant but kept for efficiency
3157 assert allocSites.equals( rg.allocSites );
3163 protected boolean areHeapRegionNodesEqual( ReachGraph rg ) {
3165 if( !areallHRNinAalsoinBandequal( this, rg ) ) {
3169 if( !areallHRNinAalsoinBandequal( rg, this ) ) {
3176 static protected boolean areallHRNinAalsoinBandequal( ReachGraph rgA,
3178 Set sA = rgA.id2hrn.entrySet();
3179 Iterator iA = sA.iterator();
3180 while( iA.hasNext() ) {
3181 Map.Entry meA = (Map.Entry) iA.next();
3182 Integer idA = (Integer) meA.getKey();
3183 HeapRegionNode hrnA = (HeapRegionNode) meA.getValue();
3185 if( !rgB.id2hrn.containsKey( idA ) ) {
3189 HeapRegionNode hrnB = rgB.id2hrn.get( idA );
3190 if( !hrnA.equalsIncludingAlpha( hrnB ) ) {
3199 protected boolean areVariableNodesEqual( ReachGraph rg ) {
3201 if( !areallVNinAalsoinBandequal( this, rg ) ) {
3205 if( !areallVNinAalsoinBandequal( rg, this ) ) {
3212 static protected boolean areallVNinAalsoinBandequal( ReachGraph rgA,
3214 Set sA = rgA.td2vn.entrySet();
3215 Iterator iA = sA.iterator();
3216 while( iA.hasNext() ) {
3217 Map.Entry meA = (Map.Entry) iA.next();
3218 TempDescriptor tdA = (TempDescriptor) meA.getKey();
3220 if( !rgB.td2vn.containsKey( tdA ) ) {
3229 protected boolean areRefEdgesEqual( ReachGraph rg ) {
3230 if( !areallREinAandBequal( this, rg ) ) {
3237 static protected boolean areallREinAandBequal( ReachGraph rgA,
3240 // check all the heap region->heap region edges
3241 Set sA = rgA.id2hrn.entrySet();
3242 Iterator iA = sA.iterator();
3243 while( iA.hasNext() ) {
3244 Map.Entry meA = (Map.Entry) iA.next();
3245 Integer idA = (Integer) meA.getKey();
3246 HeapRegionNode hrnA = (HeapRegionNode) meA.getValue();
3248 // we should have already checked that the same
3249 // heap regions exist in both graphs
3250 assert rgB.id2hrn.containsKey( idA );
3252 if( !areallREfromAequaltoB( rgA, hrnA, rgB ) ) {
3256 // then check every edge in B for presence in A, starting
3257 // from the same parent HeapRegionNode
3258 HeapRegionNode hrnB = rgB.id2hrn.get( idA );
3260 if( !areallREfromAequaltoB( rgB, hrnB, rgA ) ) {
3265 // then check all the variable->heap region edges
3266 sA = rgA.td2vn.entrySet();
3268 while( iA.hasNext() ) {
3269 Map.Entry meA = (Map.Entry) iA.next();
3270 TempDescriptor tdA = (TempDescriptor) meA.getKey();
3271 VariableNode vnA = (VariableNode) meA.getValue();
3273 // we should have already checked that the same
3274 // label nodes exist in both graphs
3275 assert rgB.td2vn.containsKey( tdA );
3277 if( !areallREfromAequaltoB( rgA, vnA, rgB ) ) {
3281 // then check every edge in B for presence in A, starting
3282 // from the same parent VariableNode
3283 VariableNode vnB = rgB.td2vn.get( tdA );
3285 if( !areallREfromAequaltoB( rgB, vnB, rgA ) ) {
3294 static protected boolean areallREfromAequaltoB( ReachGraph rgA,
3298 Iterator<RefEdge> itrA = rnA.iteratorToReferencees();
3299 while( itrA.hasNext() ) {
3300 RefEdge edgeA = itrA.next();
3301 HeapRegionNode hrnChildA = edgeA.getDst();
3302 Integer idChildA = hrnChildA.getID();
3304 assert rgB.id2hrn.containsKey( idChildA );
3306 // at this point we know an edge in graph A exists
3307 // rnA -> idChildA, does this exact edge exist in B?
3308 boolean edgeFound = false;
3310 RefSrcNode rnB = null;
3311 if( rnA instanceof HeapRegionNode ) {
3312 HeapRegionNode hrnA = (HeapRegionNode) rnA;
3313 rnB = rgB.id2hrn.get( hrnA.getID() );
3315 VariableNode vnA = (VariableNode) rnA;
3316 rnB = rgB.td2vn.get( vnA.getTempDescriptor() );
3319 Iterator<RefEdge> itrB = rnB.iteratorToReferencees();
3320 while( itrB.hasNext() ) {
3321 RefEdge edgeB = itrB.next();
3322 HeapRegionNode hrnChildB = edgeB.getDst();
3323 Integer idChildB = hrnChildB.getID();
3325 if( idChildA.equals( idChildB ) &&
3326 edgeA.typeAndFieldEquals( edgeB ) ) {
3328 // there is an edge in the right place with the right field,
3329 // but do they have the same attributes?
3330 if( edgeA.getBeta().equals( edgeB.getBeta() ) ) {
3345 protected boolean areAccessPathsEqual( ReachGraph rg ) {
3346 return temp2accessPaths.equals( rg.temp2accessPaths );
3350 // use this method to make a new reach graph that is
3351 // what heap the FlatMethod callee from the FlatCall
3352 // would start with reaching from its arguments in
3354 public ReachGraph makeCalleeView( FlatCall fc,
3357 // the callee view is a new graph: DON'T MODIFY
3359 ReachGraph rg = new ReachGraph();
3361 // track what parts of this graph have already been
3362 // added to callee view, variables not needed.
3363 // Note that we need this because when we traverse
3364 // this caller graph for each parameter we may find
3365 // nodes and edges more than once (which the per-param
3366 // "visit" sets won't show) and we only want to create
3367 // an element in the new callee view one time
3368 Set callerNodesCopiedToCallee = new HashSet<HeapRegionNode>();
3369 Set callerEdgesCopiedToCallee = new HashSet<RefEdge>();
3371 // a conservative starting point is to take the
3372 // mechanically-reachable-from-arguments graph
3373 // as opposed to using reachability information
3374 // to prune the graph further
3375 for( int i = 0; i < fm.numParameters(); ++i ) {
3377 // for each parameter index, get the symbol in the
3378 // caller view and callee view
3380 // argument defined here is the symbol in the caller
3381 TempDescriptor tdArg = fc.getArgMatchingParamIndex( fm, i );
3383 // parameter defined here is the symbol in the callee
3384 TempDescriptor tdParam = fm.getParameter( i );
3386 // use these two VariableNode objects to translate
3387 // between caller and callee--its easy to compare
3388 // a HeapRegionNode across callee and caller because
3389 // they will have the same heap region ID
3390 VariableNode vnCaller = this.getVariableNodeFromTemp( tdArg );
3391 VariableNode vnCallee = rg.getVariableNodeFromTemp( tdParam );
3393 // now traverse the caller view using the argument to
3394 // build the callee view which has the parameter symbol
3395 Set<RefSrcNode> toVisitInCaller = new HashSet<RefSrcNode>();
3396 Set<RefSrcNode> visitedInCaller = new HashSet<RefSrcNode>();
3397 toVisitInCaller.add( vnCaller );
3399 while( !toVisitInCaller.isEmpty() ) {
3400 RefSrcNode rsnCaller = toVisitInCaller.iterator().next();
3401 RefSrcNode rsnCallee;
3403 toVisitInCaller.remove( rsnCaller );
3404 visitedInCaller.add( rsnCaller );
3406 // FIRST - setup the source end of an edge
3408 if( rsnCaller == vnCaller ) {
3409 // if the caller node is the param symbol, we
3410 // have to do this translation for the callee
3411 rsnCallee = vnCallee;
3413 // otherwise the callee-view node is a heap
3414 // region with the same ID, that may or may
3415 // not have been created already
3416 assert rsnCaller instanceof HeapRegionNode;
3418 HeapRegionNode hrnSrcCaller = (HeapRegionNode) rsnCaller;
3419 if( !callerNodesCopiedToCallee.contains( rsnCaller ) ) {
3421 rg.createNewHeapRegionNode( hrnSrcCaller.getID(),
3422 hrnSrcCaller.isSingleObject(),
3423 hrnSrcCaller.isNewSummary(),
3424 hrnSrcCaller.isFlagged(),
3426 hrnSrcCaller.getType(),
3427 hrnSrcCaller.getAllocSite(),
3428 hrnSrcCaller.getInherent(),
3429 hrnSrcCaller.getAlpha(),
3430 hrnSrcCaller.getDescription()
3432 callerNodesCopiedToCallee.add( rsnCaller );
3434 rsnCallee = rg.id2hrn.get( hrnSrcCaller.getID() );
3438 // SECOND - go over all edges from that source
3440 Iterator<RefEdge> itrRefEdges = rsnCaller.iteratorToReferencees();
3441 while( itrRefEdges.hasNext() ) {
3442 RefEdge reCaller = itrRefEdges.next();
3443 HeapRegionNode hrnCaller = reCaller.getDst();
3444 HeapRegionNode hrnCallee;
3446 // THIRD - setup destination ends of edges
3448 if( !callerNodesCopiedToCallee.contains( hrnCaller ) ) {
3450 rg.createNewHeapRegionNode( hrnCaller.getID(),
3451 hrnCaller.isSingleObject(),
3452 hrnCaller.isNewSummary(),
3453 hrnCaller.isFlagged(),
3455 hrnCaller.getType(),
3456 hrnCaller.getAllocSite(),
3457 hrnCaller.getInherent(),
3458 hrnCaller.getAlpha(),
3459 hrnCaller.getDescription()
3461 callerNodesCopiedToCallee.add( hrnCaller );
3463 hrnCallee = rg.id2hrn.get( hrnCaller.getID() );
3466 // FOURTH - copy edge over if needed
3467 if( !callerEdgesCopiedToCallee.contains( reCaller ) ) {
3468 rg.addRefEdge( rsnCallee,
3470 new RefEdge( rsnCallee,
3473 reCaller.getField(),
3474 true, // isInitialParam
3478 callerEdgesCopiedToCallee.add( reCaller );
3481 // keep traversing nodes reachable from param i
3482 // that we haven't visited yet
3483 if( !visitedInCaller.contains( hrnCaller ) ) {
3484 toVisitInCaller.add( hrnCaller );
3487 } // end edge iteration
3488 } // end visiting heap nodes in caller
3489 } // end iterating over parameters as starting points
3491 // Now take the callee view graph we've built from the
3492 // caller and look backwards: for every node in the callee
3493 // look back in the caller for "upstream" reference edges.
3494 // We need to add special elements to the callee view that
3495 // capture relevant effects for mapping back
3498 rg.writeGraph( "calleeview", true, true, true, false, true, true );
3499 } catch( IOException e ) {}
3501 if( fc.getMethod().getSymbol().equals( "f1" ) ) {
3510 public Set<HeapRegionNode> findCommonReachableNodes( HeapRegionNode hrn1,
3511 HeapRegionNode hrn2 ) {
3513 Set<HeapRegionNode> reachableNodes1 = new HashSet<HeapRegionNode>();
3514 Set<HeapRegionNode> reachableNodes2 = new HashSet<HeapRegionNode>();
3516 Set<HeapRegionNode> todoNodes1 = new HashSet<HeapRegionNode>();
3517 todoNodes1.add( hrn1 );
3519 Set<HeapRegionNode> todoNodes2 = new HashSet<HeapRegionNode>();
3520 todoNodes2.add( hrn2 );
3522 // follow links until all reachable nodes have been found
3523 while( !todoNodes1.isEmpty() ) {
3524 HeapRegionNode hrn = todoNodes1.iterator().next();
3525 todoNodes1.remove( hrn );
3526 reachableNodes1.add(hrn);
3528 Iterator<RefEdge> edgeItr = hrn.iteratorToReferencees();
3529 while( edgeItr.hasNext() ) {
3530 RefEdge edge = edgeItr.next();
3532 if( !reachableNodes1.contains( edge.getDst() ) ) {
3533 todoNodes1.add( edge.getDst() );
3538 while( !todoNodes2.isEmpty() ) {
3539 HeapRegionNode hrn = todoNodes2.iterator().next();
3540 todoNodes2.remove( hrn );
3541 reachableNodes2.add(hrn);
3543 Iterator<RefEdge> edgeItr = hrn.iteratorToReferencees();
3544 while( edgeItr.hasNext() ) {
3545 RefEdge edge = edgeItr.next();
3547 if( !reachableNodes2.contains( edge.getDst() ) ) {
3548 todoNodes2.add( edge.getDst() );
3553 Set<HeapRegionNode> intersection =
3554 new HashSet<HeapRegionNode>( reachableNodes1 );
3556 intersection.retainAll( reachableNodes2 );
3558 return intersection;
3563 public void writeGraph( String graphName,
3564 boolean writeLabels,
3565 boolean labelSelect,
3566 boolean pruneGarbage,
3567 boolean writeReferencers,
3568 boolean hideSubsetReachability,
3569 boolean hideEdgeTaints
3570 ) throws java.io.IOException {
3572 // remove all non-word characters from the graph name so
3573 // the filename and identifier in dot don't cause errors
3574 graphName = graphName.replaceAll( "[\\W]", "" );
3577 new BufferedWriter( new FileWriter( graphName+".dot" ) );
3579 bw.write( "digraph "+graphName+" {\n" );
3581 Set<HeapRegionNode> visited = new HashSet<HeapRegionNode>();
3583 // then visit every heap region node
3584 Set s = id2hrn.entrySet();
3585 Iterator i = s.iterator();
3586 while( i.hasNext() ) {
3587 Map.Entry me = (Map.Entry) i.next();
3588 HeapRegionNode hrn = (HeapRegionNode) me.getValue();
3590 if( !pruneGarbage ||
3591 (hrn.isFlagged() && hrn.getID() > 0) ||
3592 hrn.getDescription().startsWith( "param" )
3595 if( !visited.contains( hrn ) ) {
3596 traverseHeapRegionNodes( hrn,
3601 hideSubsetReachability,
3607 bw.write( " graphTitle[label=\""+graphName+"\",shape=box];\n" );
3610 // then visit every label node, useful for debugging
3612 s = td2vn.entrySet();
3614 while( i.hasNext() ) {
3615 Map.Entry me = (Map.Entry) i.next();
3616 VariableNode vn = (VariableNode) me.getValue();
3619 String labelStr = vn.getTempDescriptorString();
3620 if( labelStr.startsWith("___temp") ||
3621 labelStr.startsWith("___dst") ||
3622 labelStr.startsWith("___srctmp") ||
3623 labelStr.startsWith("___neverused")
3629 //bw.write(" "+vn.toString() + ";\n");
3631 Iterator<RefEdge> heapRegionsItr = vn.iteratorToReferencees();
3632 while( heapRegionsItr.hasNext() ) {
3633 RefEdge edge = heapRegionsItr.next();
3634 HeapRegionNode hrn = edge.getDst();
3636 if( pruneGarbage && !visited.contains( hrn ) ) {
3637 traverseHeapRegionNodes( hrn,
3642 hideSubsetReachability,
3646 bw.write( " " + vn.toString() +
3647 " -> " + hrn.toString() +
3648 "[label=\"" + edge.toGraphEdgeString( hideSubsetReachability ) +
3649 "\",decorate];\n" );
3658 protected void traverseHeapRegionNodes( HeapRegionNode hrn,
3661 Set<HeapRegionNode> visited,
3662 boolean writeReferencers,
3663 boolean hideSubsetReachability,
3664 boolean hideEdgeTaints
3665 ) throws java.io.IOException {
3667 if( visited.contains( hrn ) ) {
3672 String attributes = "[";
3674 if( hrn.isSingleObject() ) {
3675 attributes += "shape=box";
3677 attributes += "shape=Msquare";
3680 if( hrn.isFlagged() ) {
3681 attributes += ",style=filled,fillcolor=lightgrey";
3684 attributes += ",label=\"ID" +
3688 if( hrn.getType() != null ) {
3689 attributes += hrn.getType().toPrettyString() + "\\n";
3692 attributes += hrn.getDescription() +
3694 hrn.getAlphaString( hideSubsetReachability ) +
3697 bw.write( " "+hrn.toString()+attributes+";\n" );
3700 Iterator<RefEdge> childRegionsItr = hrn.iteratorToReferencees();
3701 while( childRegionsItr.hasNext() ) {
3702 RefEdge edge = childRegionsItr.next();
3703 HeapRegionNode hrnChild = edge.getDst();
3705 bw.write( " " +hrn.toString()+
3706 " -> " +hrnChild.toString()+
3707 "[label=\""+edge.toGraphEdgeString( hideSubsetReachability )+
3710 traverseHeapRegionNodes( hrnChild,
3715 hideSubsetReachability,
3721 // in this analysis specifically:
3722 // we have a notion that a null type is the "match any" type,
3723 // so wrap calls to the utility methods that deal with null
3724 public TypeDescriptor mostSpecificType( TypeDescriptor td1,
3725 TypeDescriptor td2 ) {
3732 if( td1.isNull() ) {
3735 if( td2.isNull() ) {
3738 return typeUtil.mostSpecific( td1, td2 );
3741 public TypeDescriptor mostSpecificType( TypeDescriptor td1,
3743 TypeDescriptor td3 ) {
3745 return mostSpecificType( td1,
3746 mostSpecificType( td2, td3 )
3750 public TypeDescriptor mostSpecificType( TypeDescriptor td1,
3753 TypeDescriptor td4 ) {
3755 return mostSpecificType( mostSpecificType( td1, td2 ),
3756 mostSpecificType( td3, td4 )
3760 // remember, in this analysis a null type means "any type"
3761 public boolean isSuperiorType( TypeDescriptor possibleSuper,
3762 TypeDescriptor possibleChild ) {
3763 if( possibleSuper == null ||
3764 possibleChild == null ) {
3768 if( possibleSuper.isNull() ||
3769 possibleChild.isNull() ) {
3773 return typeUtil.isSuperorType( possibleSuper, possibleChild );
3777 public String generateUniqueIdentifier(FlatMethod fm, int paramIdx, String type){
3779 //type: A->aliapsed parameter heap region
3780 // P -> primary paramter heap region
3781 // S -> secondary paramter heap region
3784 if(type.equals("A")){
3786 identifier="FM"+fm.hashCode()+".A";
3788 identifier="FM"+fm.hashCode()+"."+paramIdx+"."+type;
3794 public String generateUniqueIdentifier(AllocSite as, int age, boolean isSummary){
3798 FlatNew fn=as.getFlatNew();
3801 identifier="FN"+fn.hashCode()+".S";
3803 identifier="FN"+fn.hashCode()+"."+age;