1 package Analysis.OwnershipAnalysis;
5 import Util.UtilAlgorithms;
9 public class OwnershipGraph {
11 // use to disable improvements for comparison
12 protected static final boolean DISABLE_STRONG_UPDATES = false;
13 protected static final boolean DISABLE_GLOBAL_SWEEP = false;
15 protected static int allocationDepth = -1;
16 protected static TypeUtil typeUtil = null;
17 protected static boolean debugCallMap = false;
18 protected static int debugCallMapCount = 0;
19 protected static String debugCallee = null;
20 protected static String debugCaller = null;
22 // there was already one other very similar reason
23 // for traversing heap nodes that is no longer needed
24 // instead of writing a new heap region visitor, use
25 // the existing method with a new mode to describe what
26 // actions to take during the traversal
27 protected static final int VISIT_HRN_WRITE_FULL = 0;
29 protected static final String qString = new String( "Q_spec_" );
30 protected static final String rString = new String( "R_spec_" );
31 protected static final String blobString = new String( "_AliasBlob___" );
33 protected static final TempDescriptor tdReturn = new TempDescriptor( "_Return___" );
34 protected static final TempDescriptor tdAliasBlob = new TempDescriptor( blobString );
36 protected static final TokenTupleSet ttsEmpty = new TokenTupleSet().makeCanonical();
37 protected static final ReachabilitySet rsEmpty = new ReachabilitySet().makeCanonical();
38 protected static final ReachabilitySet rsWttsEmpty = new ReachabilitySet( ttsEmpty ).makeCanonical();
40 // add a bogus entry with the identity rule for easy rewrite
41 // of new callee nodes and edges, doesn't belong to any parameter
42 protected static final int bogusParamIndexInt = -2;
43 protected static final Integer bogusID = new Integer( bogusParamIndexInt );
44 protected static final Integer bogusIndex = new Integer( bogusParamIndexInt );
45 protected static final TokenTuple bogusToken = new TokenTuple( bogusID, true, TokenTuple.ARITY_ONE ).makeCanonical();
46 protected static final TokenTuple bogusTokenPlus = new TokenTuple( bogusID, true, TokenTuple.ARITY_ONEORMORE ).makeCanonical();
47 protected static final TokenTuple bogusTokenStar = new TokenTuple( bogusID, true, TokenTuple.ARITY_ZEROORMORE ).makeCanonical();
48 protected static final ReachabilitySet rsIdentity =
49 new ReachabilitySet( new TokenTupleSet( bogusToken ).makeCanonical() ).makeCanonical();
52 public Hashtable<Integer, HeapRegionNode> id2hrn;
53 public Hashtable<TempDescriptor, LabelNode > td2ln;
55 public Hashtable<Integer, Set<Integer> > idPrimary2paramIndexSet;
56 public Hashtable<Integer, Integer > paramIndex2idPrimary;
58 public Hashtable<Integer, Set<Integer> > idSecondary2paramIndexSet;
59 public Hashtable<Integer, Integer > paramIndex2idSecondary;
61 public Hashtable<Integer, TempDescriptor> paramIndex2tdQ;
62 public Hashtable<Integer, TempDescriptor> paramIndex2tdR;
65 public HashSet<AllocationSite> allocationSites;
68 public Hashtable<TokenTuple, Integer> paramTokenPrimary2paramIndex;
69 public Hashtable<Integer, TokenTuple> paramIndex2paramTokenPrimary;
71 public Hashtable<TokenTuple, Integer> paramTokenSecondary2paramIndex;
72 public Hashtable<Integer, TokenTuple> paramIndex2paramTokenSecondary;
73 public Hashtable<TokenTuple, Integer> paramTokenSecondaryPlus2paramIndex;
74 public Hashtable<Integer, TokenTuple> paramIndex2paramTokenSecondaryPlus;
75 public Hashtable<TokenTuple, Integer> paramTokenSecondaryStar2paramIndex;
76 public Hashtable<Integer, TokenTuple> paramIndex2paramTokenSecondaryStar;
79 // consult these sets in algorithms when considering what
80 // to do with temps or their label nodes found in the graph
81 public Set<TempDescriptor> outOfScopeTemps;
82 public Set<LabelNode> outOfScopeLabels;
83 public Set<TempDescriptor> parameterTemps;
84 public Set<LabelNode> parameterLabels;
86 // this is kept to allow edges created from variables (a src and dst)
87 // to know the access paths that allowed it, to prune edges when
88 // mapping them back into the caller--an access path must appear
89 public Hashtable< TempDescriptor, Set<AccessPath> > temp2accessPaths;
91 public Hashtable< String, HeapRegionNode > gid2hrn;
94 public OwnershipGraph() {
96 id2hrn = new Hashtable<Integer, HeapRegionNode>();
97 td2ln = new Hashtable<TempDescriptor, LabelNode >();
98 idPrimary2paramIndexSet = new Hashtable<Integer, Set<Integer> >();
99 paramIndex2idPrimary = new Hashtable<Integer, Integer >();
100 idSecondary2paramIndexSet = new Hashtable<Integer, Set<Integer> >();
101 paramIndex2idSecondary = new Hashtable<Integer, Integer >();
102 paramIndex2tdQ = new Hashtable<Integer, TempDescriptor>();
103 paramIndex2tdR = new Hashtable<Integer, TempDescriptor>();
105 paramTokenPrimary2paramIndex = new Hashtable<TokenTuple, Integer >();
106 paramIndex2paramTokenPrimary = new Hashtable<Integer, TokenTuple >();
108 paramTokenSecondary2paramIndex = new Hashtable<TokenTuple, Integer >();
109 paramIndex2paramTokenSecondary = new Hashtable<Integer, TokenTuple >();
110 paramTokenSecondaryPlus2paramIndex = new Hashtable<TokenTuple, Integer >();
111 paramIndex2paramTokenSecondaryPlus = new Hashtable<Integer, TokenTuple >();
112 paramTokenSecondaryStar2paramIndex = new Hashtable<TokenTuple, Integer >();
113 paramIndex2paramTokenSecondaryStar = new Hashtable<Integer, TokenTuple >();
115 allocationSites = new HashSet <AllocationSite>();
117 outOfScopeTemps = new HashSet<TempDescriptor>();
118 outOfScopeLabels = new HashSet<LabelNode>();
119 parameterTemps = new HashSet<TempDescriptor>();
120 parameterLabels = new HashSet<LabelNode>();
122 outOfScopeTemps.add( tdReturn );
123 outOfScopeLabels.add( getLabelNodeFromTemp( tdReturn ) );
125 temp2accessPaths = new Hashtable< TempDescriptor, Set<AccessPath> >();
127 gid2hrn =new Hashtable< String, HeapRegionNode >();
131 // label nodes are much easier to deal with than
132 // heap region nodes. Whenever there is a request
133 // for the label node that is associated with a
134 // temp descriptor we can either find it or make a
135 // new one and return it. This is because temp
136 // descriptors are globally unique and every label
137 // node is mapped to exactly one temp descriptor.
138 protected LabelNode getLabelNodeFromTemp(TempDescriptor td) {
141 if( !td2ln.containsKey(td) ) {
142 td2ln.put(td, new LabelNode(td) );
145 return td2ln.get(td);
149 // the reason for this method is to have the option
150 // creating new heap regions with specific IDs, or
151 // duplicating heap regions with specific IDs (especially
152 // in the merge() operation) or to create new heap
153 // regions with a new unique ID.
154 protected HeapRegionNode
155 createNewHeapRegionNode(Integer id,
156 boolean isSingleObject,
157 boolean isNewSummary,
161 AllocationSite allocSite,
162 ReachabilitySet alpha,
164 String globalIdentifier) {
166 boolean markForAnalysis = isFlagged || isParameter;
168 TypeDescriptor typeToUse = null;
169 if( allocSite != null ) {
170 typeToUse = allocSite.getType();
175 if( allocSite != null && allocSite.getDisjointId() != null ) {
176 markForAnalysis = true;
180 id = OwnershipAnalysis.generateUniqueHeapRegionNodeID();
183 if( alpha == null ) {
184 if( markForAnalysis ) {
185 alpha = new ReachabilitySet(
192 alpha = new ReachabilitySet(
193 new TokenTupleSet().makeCanonical()
198 HeapRegionNode hrn = new HeapRegionNode(id,
209 gid2hrn.put(globalIdentifier, hrn);
215 ////////////////////////////////////////////////
217 // Low-level referencee and referencer methods
219 // These methods provide the lowest level for
220 // creating references between ownership nodes
221 // and handling the details of maintaining both
222 // list of referencers and referencees.
224 ////////////////////////////////////////////////
225 protected void addReferenceEdge(OwnershipNode referencer,
226 HeapRegionNode referencee,
227 ReferenceEdge edge) {
228 assert referencer != null;
229 assert referencee != null;
231 assert edge.getSrc() == referencer;
232 assert edge.getDst() == referencee;
234 referencer.addReferencee(edge);
235 referencee.addReferencer(edge);
238 protected void removeReferenceEdge(ReferenceEdge e) {
239 removeReferenceEdge(e.getSrc(),
245 protected void removeReferenceEdge(OwnershipNode referencer,
246 HeapRegionNode referencee,
249 assert referencer != null;
250 assert referencee != null;
252 ReferenceEdge edge = referencer.getReferenceTo(referencee,
256 assert edge == referencee.getReferenceFrom(referencer,
260 // int oldTaint=edge.getTaintIdentifier();
261 // if(referencer instanceof HeapRegionNode){
262 // depropagateTaintIdentifier((HeapRegionNode)referencer,oldTaint,new HashSet<HeapRegionNode>());
265 referencer.removeReferencee(edge);
266 referencee.removeReferencer(edge);
269 protected void clearReferenceEdgesFrom(OwnershipNode referencer,
273 assert referencer != null;
275 // get a copy of the set to iterate over, otherwise
276 // we will be trying to take apart the set as we
277 // are iterating over it, which won't work
278 Iterator<ReferenceEdge> i = referencer.iteratorToReferenceesClone();
279 while( i.hasNext() ) {
280 ReferenceEdge edge = i.next();
283 (edge.typeEquals( type ) && edge.fieldEquals( field ))
286 HeapRegionNode referencee = edge.getDst();
288 removeReferenceEdge(referencer,
296 protected void clearReferenceEdgesTo(HeapRegionNode referencee,
300 assert referencee != null;
302 // get a copy of the set to iterate over, otherwise
303 // we will be trying to take apart the set as we
304 // are iterating over it, which won't work
305 Iterator<ReferenceEdge> i = referencee.iteratorToReferencersClone();
306 while( i.hasNext() ) {
307 ReferenceEdge edge = i.next();
310 (edge.typeEquals( type ) && edge.fieldEquals( field ))
313 OwnershipNode referencer = edge.getSrc();
315 removeReferenceEdge(referencer,
324 ////////////////////////////////////////////////////
326 // Assignment Operation Methods
328 // These methods are high-level operations for
329 // modeling program assignment statements using
330 // the low-level reference create/remove methods
333 // The destination in an assignment statement is
334 // going to have new references. The method of
335 // determining the references depends on the type
336 // of the FlatNode assignment and the predicates
337 // of the nodes and edges involved.
339 ////////////////////////////////////////////////////
341 public void nullifyDeadVars( Set<TempDescriptor> liveIn ) {
343 // make a set of the temps that are out of scope, don't
344 // consider them when nullifying dead in-scope variables
345 Set<TempDescriptor> outOfScope = new HashSet<TempDescriptor>();
346 outOfScope.add( tdReturn );
347 outOfScope.add( tdAliasBlob );
348 outOfScope.addAll( paramIndex2tdQ.values() );
349 outOfScope.addAll( paramIndex2tdR.values() );
351 Iterator varItr = td2ln.entrySet().iterator();
352 while( varItr.hasNext() ) {
353 Map.Entry me = (Map.Entry) varItr.next();
354 TempDescriptor td = (TempDescriptor) me.getKey();
355 LabelNode ln = (LabelNode) me.getValue();
357 // if this variable is not out-of-scope or live
358 // in graph, nullify its references to anything
359 if( !outOfScope.contains( td ) &&
360 !liveIn.contains( td )
362 clearReferenceEdgesFrom( ln, null, null, true );
368 public void assignTempXEqualToTempY( TempDescriptor x,
370 assignTempXEqualToCastedTempY( x, y, null );
373 public void assignTempXEqualToCastedTempY( TempDescriptor x,
375 TypeDescriptor tdCast ) {
377 LabelNode lnX = getLabelNodeFromTemp( x );
378 LabelNode lnY = getLabelNodeFromTemp( y );
380 clearReferenceEdgesFrom( lnX, null, null, true );
382 // note it is possible that the types of temps in the
383 // flat node to analyze will reveal that some typed
384 // edges in the reachability graph are impossible
385 Set<ReferenceEdge> impossibleEdges = new HashSet<ReferenceEdge>();
387 Iterator<ReferenceEdge> itrYhrn = lnY.iteratorToReferencees();
388 while( itrYhrn.hasNext() ) {
389 ReferenceEdge edgeY = itrYhrn.next();
390 HeapRegionNode referencee = edgeY.getDst();
391 ReferenceEdge edgeNew = edgeY.copy();
393 if( !isSuperiorType( x.getType(), edgeY.getType() ) ) {
394 impossibleEdges.add( edgeY );
398 edgeNew.setSrc( lnX );
400 edgeNew.setType( mostSpecificType( y.getType(),
407 edgeNew.setField( null );
409 addReferenceEdge( lnX, referencee, edgeNew );
412 Iterator<ReferenceEdge> itrImp = impossibleEdges.iterator();
413 while( itrImp.hasNext() ) {
414 ReferenceEdge edgeImp = itrImp.next();
415 removeReferenceEdge( edgeImp );
420 public void assignTempXEqualToTempYFieldF( TempDescriptor x,
422 FieldDescriptor f ) {
423 LabelNode lnX = getLabelNodeFromTemp( x );
424 LabelNode lnY = getLabelNodeFromTemp( y );
426 clearReferenceEdgesFrom( lnX, null, null, true );
428 // note it is possible that the types of temps in the
429 // flat node to analyze will reveal that some typed
430 // edges in the reachability graph are impossible
431 Set<ReferenceEdge> impossibleEdges = new HashSet<ReferenceEdge>();
433 Iterator<ReferenceEdge> itrYhrn = lnY.iteratorToReferencees();
434 while( itrYhrn.hasNext() ) {
435 ReferenceEdge edgeY = itrYhrn.next();
436 HeapRegionNode hrnY = edgeY.getDst();
437 ReachabilitySet betaY = edgeY.getBeta();
439 Iterator<ReferenceEdge> itrHrnFhrn = hrnY.iteratorToReferencees();
440 while( itrHrnFhrn.hasNext() ) {
441 ReferenceEdge edgeHrn = itrHrnFhrn.next();
442 HeapRegionNode hrnHrn = edgeHrn.getDst();
443 ReachabilitySet betaHrn = edgeHrn.getBeta();
445 // prune edges that are not a matching field
446 if( edgeHrn.getType() != null &&
447 !edgeHrn.getField().equals( f.getSymbol() )
452 // check for impossible edges
453 if( !isSuperiorType( x.getType(), edgeHrn.getType() ) ) {
454 impossibleEdges.add( edgeHrn );
458 TypeDescriptor tdNewEdge =
459 mostSpecificType( edgeHrn.getType(),
463 ReferenceEdge edgeNew = new ReferenceEdge( lnX,
468 betaY.intersection( betaHrn )
471 int newTaintIdentifier=getTaintIdentifierFromHRN(hrnHrn);
472 edgeNew.setTaintIdentifier(newTaintIdentifier);
474 addReferenceEdge( lnX, hrnHrn, edgeNew );
478 Iterator<ReferenceEdge> itrImp = impossibleEdges.iterator();
479 while( itrImp.hasNext() ) {
480 ReferenceEdge edgeImp = itrImp.next();
481 removeReferenceEdge( edgeImp );
484 // anytime you might remove edges between heap regions
485 // you must global sweep to clean up broken reachability
486 if( !impossibleEdges.isEmpty() ) {
487 if( !DISABLE_GLOBAL_SWEEP ) {
494 public void assignTempXFieldFEqualToTempY( TempDescriptor x,
498 LabelNode lnX = getLabelNodeFromTemp( x );
499 LabelNode lnY = getLabelNodeFromTemp( y );
501 HashSet<HeapRegionNode> nodesWithNewAlpha = new HashSet<HeapRegionNode>();
502 HashSet<ReferenceEdge> edgesWithNewBeta = new HashSet<ReferenceEdge>();
504 // note it is possible that the types of temps in the
505 // flat node to analyze will reveal that some typed
506 // edges in the reachability graph are impossible
507 Set<ReferenceEdge> impossibleEdges = new HashSet<ReferenceEdge>();
509 // first look for possible strong updates and remove those edges
510 boolean strongUpdate = false;
512 Iterator<ReferenceEdge> itrXhrn = lnX.iteratorToReferencees();
513 while( itrXhrn.hasNext() ) {
514 ReferenceEdge edgeX = itrXhrn.next();
515 HeapRegionNode hrnX = edgeX.getDst();
517 // we can do a strong update here if one of two cases holds
519 f != OwnershipAnalysis.getArrayField( f.getType() ) &&
520 ( (hrnX.getNumReferencers() == 1) || // case 1
521 (hrnX.isSingleObject() && lnX.getNumReferencees() == 1) // case 2
524 if( !DISABLE_STRONG_UPDATES ) {
526 clearReferenceEdgesFrom( hrnX, f.getType(), f.getSymbol(), false );
531 // then do all token propagation
532 itrXhrn = lnX.iteratorToReferencees();
533 while( itrXhrn.hasNext() ) {
534 ReferenceEdge edgeX = itrXhrn.next();
535 HeapRegionNode hrnX = edgeX.getDst();
536 ReachabilitySet betaX = edgeX.getBeta();
537 ReachabilitySet R = hrnX.getAlpha().intersection( edgeX.getBeta() );
539 Iterator<ReferenceEdge> itrYhrn = lnY.iteratorToReferencees();
540 while( itrYhrn.hasNext() ) {
541 ReferenceEdge edgeY = itrYhrn.next();
542 HeapRegionNode hrnY = edgeY.getDst();
543 ReachabilitySet O = edgeY.getBeta();
545 // check for impossible edges
546 if( !isSuperiorType( f.getType(), edgeY.getType() ) ) {
547 impossibleEdges.add( edgeY );
551 // propagate tokens over nodes starting from hrnSrc, and it will
552 // take care of propagating back up edges from any touched nodes
553 ChangeTupleSet Cy = O.unionUpArityToChangeSet( R );
554 propagateTokensOverNodes( hrnY, Cy, nodesWithNewAlpha, edgesWithNewBeta );
557 // then propagate back just up the edges from hrn
558 ChangeTupleSet Cx = R.unionUpArityToChangeSet(O);
559 HashSet<ReferenceEdge> todoEdges = new HashSet<ReferenceEdge>();
561 Hashtable<ReferenceEdge, ChangeTupleSet> edgePlannedChanges =
562 new Hashtable<ReferenceEdge, ChangeTupleSet>();
564 Iterator<ReferenceEdge> referItr = hrnX.iteratorToReferencers();
565 while( referItr.hasNext() ) {
566 ReferenceEdge edgeUpstream = referItr.next();
567 todoEdges.add( edgeUpstream );
568 edgePlannedChanges.put( edgeUpstream, Cx );
571 propagateTokensOverEdges( todoEdges,
578 // apply the updates to reachability
579 Iterator<HeapRegionNode> nodeItr = nodesWithNewAlpha.iterator();
580 while( nodeItr.hasNext() ) {
581 nodeItr.next().applyAlphaNew();
584 Iterator<ReferenceEdge> edgeItr = edgesWithNewBeta.iterator();
585 while( edgeItr.hasNext() ) {
586 edgeItr.next().applyBetaNew();
590 // then go back through and add the new edges
591 itrXhrn = lnX.iteratorToReferencees();
592 while( itrXhrn.hasNext() ) {
593 ReferenceEdge edgeX = itrXhrn.next();
594 HeapRegionNode hrnX = edgeX.getDst();
596 Iterator<ReferenceEdge> itrYhrn = lnY.iteratorToReferencees();
597 while( itrYhrn.hasNext() ) {
598 ReferenceEdge edgeY = itrYhrn.next();
599 HeapRegionNode hrnY = edgeY.getDst();
601 // skip impossible edges here, we already marked them
602 // when computing reachability propagations above
603 if( !isSuperiorType( f.getType(), edgeY.getType() ) ) {
607 // prepare the new reference edge hrnX.f -> hrnY
608 TypeDescriptor tdNewEdge =
609 mostSpecificType( y.getType(),
614 ReferenceEdge edgeNew = new ReferenceEdge( hrnX,
619 edgeY.getBeta().pruneBy( hrnX.getAlpha() )
622 // look to see if an edge with same field exists
623 // and merge with it, otherwise just add the edge
624 ReferenceEdge edgeExisting = hrnX.getReferenceTo( hrnY,
628 if( edgeExisting != null ) {
629 edgeExisting.setBeta(
630 edgeExisting.getBeta().union( edgeNew.getBeta() )
633 if((!hrnX.isParameter() && hrnY.isParameter()) || ( hrnX.isParameter() && hrnY.isParameter())){
634 int newTaintIdentifier=getTaintIdentifierFromHRN(hrnY);
635 edgeExisting.unionTaintIdentifier(newTaintIdentifier);
637 // a new edge here cannot be reflexive, so existing will
638 // always be also not reflexive anymore
639 edgeExisting.setIsInitialParam( false );
642 if((!hrnX.isParameter() && hrnY.isParameter()) || ( hrnX.isParameter() && hrnY.isParameter())){
643 int newTaintIdentifier=getTaintIdentifierFromHRN(hrnY);
644 edgeNew.setTaintIdentifier(newTaintIdentifier);
646 //currently, taint isn't propagated through the chain of refrences
647 //propagateTaintIdentifier(hrnX,newTaintIdentifier,new HashSet<HeapRegionNode>());
649 addReferenceEdge( hrnX, hrnY, edgeNew );
654 Iterator<ReferenceEdge> itrImp = impossibleEdges.iterator();
655 while( itrImp.hasNext() ) {
656 ReferenceEdge edgeImp = itrImp.next();
657 removeReferenceEdge( edgeImp );
660 // if there was a strong update, make sure to improve
661 // reachability with a global sweep
662 if( strongUpdate || !impossibleEdges.isEmpty() ) {
663 if( !DISABLE_GLOBAL_SWEEP ) {
670 // the parameter model is to use a single-object heap region
671 // for the primary parameter, and a multiple-object heap
672 // region for the secondary objects reachable through the
673 // primary object, if necessary
674 public void assignTempEqualToParamAlloc( TempDescriptor td,
676 Integer paramIndex, FlatMethod fm ) {
679 TypeDescriptor typeParam = td.getType();
680 assert typeParam != null;
682 // either the parameter is an array or a class to be in this method
683 assert typeParam.isArray() || typeParam.isClass();
685 // discover some info from the param type and use it below
686 // to get parameter model as precise as we can
687 boolean createSecondaryRegion = false;
688 Set<FieldDescriptor> primary2primaryFields = new HashSet<FieldDescriptor>();
689 Set<FieldDescriptor> primary2secondaryFields = new HashSet<FieldDescriptor>();
691 // there might be an element reference for array types
692 if( typeParam.isArray() ) {
693 // only bother with this if the dereferenced type can
694 // affect reachability
695 TypeDescriptor typeDeref = typeParam.dereference();
696 if( !typeDeref.isImmutable() || typeDeref.isArray() ) {
697 primary2secondaryFields.add(
698 OwnershipAnalysis.getArrayField( typeDeref )
700 createSecondaryRegion = true;
702 // also handle a special case where an array of objects
703 // can point back to the array, which is an object!
704 if( typeParam.toPrettyString().equals( "Object[]" ) &&
705 typeDeref.toPrettyString().equals( "Object" ) ) {
707 primary2primaryFields.add(
708 OwnershipAnalysis.getArrayField( typeDeref )
714 // there might be member references for class types
715 if( typeParam.isClass() ) {
716 ClassDescriptor cd = typeParam.getClassDesc();
717 while( cd != null ) {
719 Iterator fieldItr = cd.getFields();
720 while( fieldItr.hasNext() ) {
722 FieldDescriptor fd = (FieldDescriptor) fieldItr.next();
723 TypeDescriptor typeField = fd.getType();
724 assert typeField != null;
726 if( !typeField.isImmutable() || typeField.isArray() ) {
727 primary2secondaryFields.add( fd );
728 createSecondaryRegion = true;
731 if( typeUtil.isSuperorType( typeField, typeParam ) ) {
732 primary2primaryFields.add( fd );
736 cd = cd.getSuperDesc();
741 // now build everything we need
742 LabelNode lnParam = getLabelNodeFromTemp( td );
743 HeapRegionNode hrnPrimary = createNewHeapRegionNode( null, // id or null to generate a new one
744 true, // single object?
747 true, // is a parameter?
749 null, // allocation site
750 null, // reachability set
751 "param"+paramIndex+" obj",
752 generateUniqueIdentifier(fm,paramIndex,"P"));
754 parameterTemps.add( td );
755 parameterLabels.add( lnParam );
758 // this is a non-program-accessible label that picks up beta
759 // info to be used for fixing a caller of this method
760 TempDescriptor tdParamQ = new TempDescriptor( td+qString );
761 paramIndex2tdQ.put( paramIndex, tdParamQ );
762 LabelNode lnParamQ = getLabelNodeFromTemp( tdParamQ );
764 outOfScopeTemps.add( tdParamQ );
765 outOfScopeLabels.add( lnParamQ );
767 // keep track of heap regions that were created for
768 // parameter labels, the index of the parameter they
769 // are for is important when resolving method calls
770 Integer newPrimaryID = hrnPrimary.getID();
771 assert !idPrimary2paramIndexSet.containsKey( newPrimaryID );
772 Set<Integer> s = new HashSet<Integer>();
774 idPrimary2paramIndexSet.put( newPrimaryID, s );
775 paramIndex2idPrimary.put( paramIndex, newPrimaryID );
777 TokenTuple ttPrimary = new TokenTuple( newPrimaryID,
778 false, // multi-object
779 TokenTuple.ARITY_ONE ).makeCanonical();
782 HeapRegionNode hrnSecondary = null;
783 Integer newSecondaryID = null;
784 TokenTuple ttSecondary = null;
785 TempDescriptor tdParamR = null;
786 LabelNode lnParamR = null;
788 if( createSecondaryRegion ) {
789 tdParamR = new TempDescriptor( td+rString );
790 paramIndex2tdR.put( paramIndex, tdParamR );
791 lnParamR = getLabelNodeFromTemp( tdParamR );
793 outOfScopeTemps.add( tdParamR );
794 outOfScopeLabels.add( lnParamR );
796 hrnSecondary = createNewHeapRegionNode( null, // id or null to generate a new one
797 false, // single object?
800 true, // is a parameter?
802 null, // allocation site
803 null, // reachability set
804 "param"+paramIndex+" reachable",
805 generateUniqueIdentifier(fm,paramIndex,"S"));
807 newSecondaryID = hrnSecondary.getID();
808 assert !idSecondary2paramIndexSet.containsKey( newSecondaryID );
809 Set<Integer> s2 = new HashSet<Integer>();
810 s2.add( paramIndex );
811 idSecondary2paramIndexSet.put( newSecondaryID, s2 );
812 paramIndex2idSecondary.put( paramIndex, newSecondaryID );
815 ttSecondary = new TokenTuple( newSecondaryID,
816 true, // multi-object
817 TokenTuple.ARITY_ONE ).makeCanonical();
820 // use a beta that has everything and put it all over the
821 // parameter model, then use a global sweep later to fix
822 // it up, since parameters can have different shapes
823 TokenTupleSet tts0 = new TokenTupleSet( ttPrimary ).makeCanonical();
824 ReachabilitySet betaSoup;
825 if( createSecondaryRegion ) {
826 TokenTupleSet tts1 = new TokenTupleSet( ttSecondary ).makeCanonical();
827 TokenTupleSet tts2 = new TokenTupleSet( ttPrimary ).makeCanonical().union( ttSecondary );
828 betaSoup = ReachabilitySet.factory( tts0 ).union( tts1 ).union( tts2 );
830 betaSoup = ReachabilitySet.factory( tts0 );
833 ReferenceEdge edgeFromLabel =
834 new ReferenceEdge( lnParam, // src
838 false, // special param initial (not needed on label->node)
839 betaSoup ); // reachability
840 edgeFromLabel.tainedBy(paramIndex);
841 addReferenceEdge( lnParam, hrnPrimary, edgeFromLabel );
843 ReferenceEdge edgeFromLabelQ =
844 new ReferenceEdge( lnParamQ, // src
848 false, // special param initial (not needed on label->node)
849 betaSoup ); // reachability
850 edgeFromLabelQ.tainedBy(paramIndex);
851 addReferenceEdge( lnParamQ, hrnPrimary, edgeFromLabelQ );
853 ReferenceEdge edgeSecondaryReflexive;
854 if( createSecondaryRegion ) {
855 edgeSecondaryReflexive =
856 new ReferenceEdge( hrnSecondary, // src
858 null, // match all types
859 null, // match all fields
860 true, // special param initial
861 betaSoup ); // reachability
862 addReferenceEdge( hrnSecondary, hrnSecondary, edgeSecondaryReflexive );
864 ReferenceEdge edgeSecondary2Primary =
865 new ReferenceEdge( hrnSecondary, // src
867 null, // match all types
868 null, // match all fields
869 true, // special param initial
870 betaSoup ); // reachability
871 addReferenceEdge( hrnSecondary, hrnPrimary, edgeSecondary2Primary );
873 ReferenceEdge edgeFromLabelR =
874 new ReferenceEdge( lnParamR, // src
878 false, // special param initial (not needed on label->node)
879 betaSoup ); // reachability
880 edgeFromLabelR.tainedBy(paramIndex);
881 addReferenceEdge( lnParamR, hrnSecondary, edgeFromLabelR );
884 Iterator<FieldDescriptor> fieldItr = primary2primaryFields.iterator();
885 while( fieldItr.hasNext() ) {
886 FieldDescriptor fd = fieldItr.next();
888 ReferenceEdge edgePrimaryReflexive =
889 new ReferenceEdge( hrnPrimary, // src
891 fd.getType(), // type
892 fd.getSymbol(), // field
893 true, // special param initial
894 betaSoup ); // reachability
895 addReferenceEdge( hrnPrimary, hrnPrimary, edgePrimaryReflexive );
898 fieldItr = primary2secondaryFields.iterator();
899 while( fieldItr.hasNext() ) {
900 FieldDescriptor fd = fieldItr.next();
902 ReferenceEdge edgePrimary2Secondary =
903 new ReferenceEdge( hrnPrimary, // src
905 fd.getType(), // type
906 fd.getSymbol(), // field
907 true, // special param initial
908 betaSoup ); // reachability
909 addReferenceEdge( hrnPrimary, hrnSecondary, edgePrimary2Secondary );
914 public void makeAliasedParamHeapRegionNode(FlatMethod fm) {
916 LabelNode lnBlob = getLabelNodeFromTemp( tdAliasBlob );
918 outOfScopeTemps.add( tdAliasBlob );
919 outOfScopeLabels.add( lnBlob );
921 HeapRegionNode hrn = createNewHeapRegionNode( null, // id or null to generate a new one
922 false, // single object?
925 true, // is a parameter?
927 null, // allocation site
928 null, // reachability set
930 generateUniqueIdentifier(fm,0,"A"));
933 ReachabilitySet beta = new ReachabilitySet( new TokenTuple( hrn.getID(),
935 TokenTuple.ARITY_ONE).makeCanonical()
938 ReferenceEdge edgeFromLabel =
939 new ReferenceEdge( lnBlob, hrn, null, null, false, beta );
941 ReferenceEdge edgeReflexive =
942 new ReferenceEdge( hrn, hrn, null, null, true, beta );
944 addReferenceEdge( lnBlob, hrn, edgeFromLabel );
945 addReferenceEdge( hrn, hrn, edgeReflexive );
949 public void assignTempEqualToAliasedParam( TempDescriptor tdParam,
950 Integer paramIndex, FlatMethod fm ) {
951 assert tdParam != null;
953 TypeDescriptor typeParam = tdParam.getType();
954 assert typeParam != null;
956 LabelNode lnParam = getLabelNodeFromTemp( tdParam );
957 LabelNode lnAliased = getLabelNodeFromTemp( tdAliasBlob );
959 parameterTemps.add( tdParam );
960 parameterLabels.add( lnParam );
962 // this is a non-program-accessible label that picks up beta
963 // info to be used for fixing a caller of this method
964 TempDescriptor tdParamQ = new TempDescriptor( tdParam+qString );
965 TempDescriptor tdParamR = new TempDescriptor( tdParam+rString );
967 paramIndex2tdQ.put( paramIndex, tdParamQ );
968 paramIndex2tdR.put( paramIndex, tdParamR );
970 LabelNode lnParamQ = getLabelNodeFromTemp( tdParamQ );
971 LabelNode lnParamR = getLabelNodeFromTemp( tdParamR );
973 outOfScopeTemps.add( tdParamR );
974 outOfScopeLabels.add( lnParamR );
975 outOfScopeTemps.add( tdParamQ );
976 outOfScopeLabels.add( lnParamQ );
978 // the lnAliased should always only reference one node, and that
979 // heap region node is the aliased param blob
980 assert lnAliased.getNumReferencees() == 1;
981 HeapRegionNode hrnAliasBlob = lnAliased.iteratorToReferencees().next().getDst();
982 Integer idAliased = hrnAliasBlob.getID();
985 TokenTuple ttAliased = new TokenTuple( idAliased,
986 true, // multi-object
987 TokenTuple.ARITY_ONE ).makeCanonical();
990 HeapRegionNode hrnPrimary = createNewHeapRegionNode( null, // id or null to generate a new one
991 true, // single object?
994 true, // is a parameter?
996 null, // allocation site
997 null, // reachability set
998 "param"+paramIndex+" obj",
999 generateUniqueIdentifier(fm, paramIndex.intValue(), "P"));
1001 Integer newPrimaryID = hrnPrimary.getID();
1002 assert !idPrimary2paramIndexSet.containsKey( newPrimaryID );
1003 Set<Integer> s1 = new HashSet<Integer>();
1004 s1.add( paramIndex );
1005 idPrimary2paramIndexSet.put( newPrimaryID, s1 );
1006 paramIndex2idPrimary.put( paramIndex, newPrimaryID );
1008 Set<Integer> s2 = idSecondary2paramIndexSet.get( idAliased );
1010 s2 = new HashSet<Integer>();
1012 s2.add( paramIndex );
1013 idSecondary2paramIndexSet.put( idAliased, s2 );
1014 paramIndex2idSecondary.put( paramIndex, idAliased );
1018 TokenTuple ttPrimary = new TokenTuple( newPrimaryID,
1019 false, // multi-object
1020 TokenTuple.ARITY_ONE ).makeCanonical();
1023 TokenTupleSet tts0 = new TokenTupleSet( ttPrimary ).makeCanonical();
1024 TokenTupleSet tts1 = new TokenTupleSet( ttAliased ).makeCanonical();
1025 TokenTupleSet tts2 = new TokenTupleSet( ttPrimary ).makeCanonical().union( ttAliased );
1026 ReachabilitySet betaSoup = ReachabilitySet.factory( tts0 ).union( tts1 ).union( tts2 );
1029 ReferenceEdge edgeFromLabel =
1030 new ReferenceEdge( lnParam, // src
1034 false, // special param initial (not needed on label->node)
1035 betaSoup ); // reachability
1036 edgeFromLabel.tainedBy(paramIndex);
1037 addReferenceEdge( lnParam, hrnPrimary, edgeFromLabel );
1039 ReferenceEdge edgeFromLabelQ =
1040 new ReferenceEdge( lnParamQ, // src
1044 false, // special param initial (not needed on label->node)
1045 betaSoup ); // reachability
1046 edgeFromLabelQ.tainedBy(paramIndex);
1047 addReferenceEdge( lnParamQ, hrnPrimary, edgeFromLabelQ );
1049 ReferenceEdge edgeAliased2Primary =
1050 new ReferenceEdge( hrnAliasBlob, // src
1052 null, // match all types
1053 null, // match all fields
1054 true, // special param initial
1055 betaSoup ); // reachability
1056 addReferenceEdge( hrnAliasBlob, hrnPrimary, edgeAliased2Primary );
1058 ReferenceEdge edgeFromLabelR =
1059 new ReferenceEdge( lnParamR, // src
1060 hrnAliasBlob, // dst
1063 false, // special param initial (not needed on label->node)
1064 betaSoup ); // reachability
1065 edgeFromLabelR.tainedBy(paramIndex);
1066 addReferenceEdge( lnParamR, hrnAliasBlob, edgeFromLabelR );
1070 public void addParam2ParamAliasEdges( FlatMethod fm,
1071 Set<Integer> aliasedParamIndices ) {
1073 LabelNode lnAliased = getLabelNodeFromTemp( tdAliasBlob );
1075 // the lnAliased should always only reference one node, and that
1076 // heap region node is the aliased param blob
1077 assert lnAliased.getNumReferencees() == 1;
1078 HeapRegionNode hrnAliasBlob = lnAliased.iteratorToReferencees().next().getDst();
1079 Integer idAliased = hrnAliasBlob.getID();
1082 TokenTuple ttAliased = new TokenTuple( idAliased,
1083 true, // multi-object
1084 TokenTuple.ARITY_ONE ).makeCanonical();
1087 Iterator<Integer> apItrI = aliasedParamIndices.iterator();
1088 while( apItrI.hasNext() ) {
1089 Integer i = apItrI.next();
1090 TempDescriptor tdParamI = fm.getParameter( i );
1091 TypeDescriptor typeI = tdParamI.getType();
1092 LabelNode lnParamI = getLabelNodeFromTemp( tdParamI );
1094 Integer idPrimaryI = paramIndex2idPrimary.get( i );
1095 assert idPrimaryI != null;
1096 HeapRegionNode primaryI = id2hrn.get( idPrimaryI );
1097 assert primaryI != null;
1099 TokenTuple ttPrimaryI = new TokenTuple( idPrimaryI,
1100 false, // multi-object
1101 TokenTuple.ARITY_ONE ).makeCanonical();
1103 TokenTupleSet ttsI = new TokenTupleSet( ttPrimaryI ).makeCanonical();
1104 TokenTupleSet ttsA = new TokenTupleSet( ttAliased ).makeCanonical();
1105 TokenTupleSet ttsIA = new TokenTupleSet( ttPrimaryI ).makeCanonical().union( ttAliased );
1106 ReachabilitySet betaSoup = ReachabilitySet.factory( ttsI ).union( ttsA ).union( ttsIA );
1109 // calculate whether fields of this aliased parameter are able to
1110 // reference its own primary object, the blob, or other parameter's
1112 Set<FieldDescriptor> primary2primaryFields = new HashSet<FieldDescriptor>();
1113 Set<FieldDescriptor> primary2secondaryFields = new HashSet<FieldDescriptor>();
1115 // there might be an element reference for array types
1116 if( typeI.isArray() ) {
1117 // only bother with this if the dereferenced type can
1118 // affect reachability
1119 TypeDescriptor typeDeref = typeI.dereference();
1123 /////////////////////////////////////////////////////////////
1124 // NOTE! For the KMeans benchmark a parameter of type float
1125 // array, which has an immutable dereferenced type, is causing
1126 // this assertion to fail. I'm commenting it out for now which
1127 // is safe, because it allows aliasing where no aliasing can occur,
1128 // so it can only get a worse-but-not-wrong answer. FIX!
1129 /////////////////////////////////////////////////////////////
1130 // for this parameter to be aliased the following must be true
1131 //assert !typeDeref.isImmutable() || typeDeref.isArray();
1135 primary2secondaryFields.add(
1136 OwnershipAnalysis.getArrayField( typeDeref )
1139 // also handle a special case where an array of objects
1140 // can point back to the array, which is an object!
1141 if( typeI .toPrettyString().equals( "Object[]" ) &&
1142 typeDeref.toPrettyString().equals( "Object" ) ) {
1143 primary2primaryFields.add(
1144 OwnershipAnalysis.getArrayField( typeDeref )
1149 // there might be member references for class types
1150 if( typeI.isClass() ) {
1151 ClassDescriptor cd = typeI.getClassDesc();
1152 while( cd != null ) {
1154 Iterator fieldItr = cd.getFields();
1155 while( fieldItr.hasNext() ) {
1157 FieldDescriptor fd = (FieldDescriptor) fieldItr.next();
1158 TypeDescriptor typeField = fd.getType();
1159 assert typeField != null;
1161 if( !typeField.isImmutable() || typeField.isArray() ) {
1162 primary2secondaryFields.add( fd );
1165 if( typeUtil.isSuperorType( typeField, typeI ) ) {
1166 primary2primaryFields.add( fd );
1170 cd = cd.getSuperDesc();
1174 Iterator<FieldDescriptor> fieldItr = primary2primaryFields.iterator();
1175 while( fieldItr.hasNext() ) {
1176 FieldDescriptor fd = fieldItr.next();
1178 ReferenceEdge edgePrimaryReflexive =
1179 new ReferenceEdge( primaryI, // src
1181 fd.getType(), // type
1182 fd.getSymbol(), // field
1183 true, // special param initial
1184 betaSoup ); // reachability
1185 addReferenceEdge( primaryI, primaryI, edgePrimaryReflexive );
1188 fieldItr = primary2secondaryFields.iterator();
1189 while( fieldItr.hasNext() ) {
1190 FieldDescriptor fd = fieldItr.next();
1191 TypeDescriptor typeField = fd.getType();
1192 assert typeField != null;
1194 ReferenceEdge edgePrimary2Secondary =
1195 new ReferenceEdge( primaryI, // src
1196 hrnAliasBlob, // dst
1197 fd.getType(), // type
1198 fd.getSymbol(), // field
1199 true, // special param initial
1200 betaSoup ); // reachability
1201 addReferenceEdge( primaryI, hrnAliasBlob, edgePrimary2Secondary );
1203 // ask whether these fields might match any of the other aliased
1204 // parameters and make those edges too
1205 Iterator<Integer> apItrJ = aliasedParamIndices.iterator();
1206 while( apItrJ.hasNext() ) {
1207 Integer j = apItrJ.next();
1208 TempDescriptor tdParamJ = fm.getParameter( j );
1209 TypeDescriptor typeJ = tdParamJ.getType();
1211 if( !i.equals( j ) && typeUtil.isSuperorType( typeField, typeJ ) ) {
1213 Integer idPrimaryJ = paramIndex2idPrimary.get( j );
1214 assert idPrimaryJ != null;
1215 HeapRegionNode primaryJ = id2hrn.get( idPrimaryJ );
1216 assert primaryJ != null;
1218 TokenTuple ttPrimaryJ = new TokenTuple( idPrimaryJ,
1219 false, // multi-object
1220 TokenTuple.ARITY_ONE ).makeCanonical();
1222 TokenTupleSet ttsJ = new TokenTupleSet( ttPrimaryJ ).makeCanonical();
1223 TokenTupleSet ttsIJ = ttsI.union( ttsJ );
1224 TokenTupleSet ttsAJ = ttsA.union( ttsJ );
1225 TokenTupleSet ttsIAJ = ttsIA.union( ttsJ );
1226 ReachabilitySet betaSoupWJ = ReachabilitySet.factory( ttsJ ).union( ttsIJ ).union( ttsAJ ).union( ttsIAJ );
1228 ReferenceEdge edgePrimaryI2PrimaryJ =
1229 new ReferenceEdge( primaryI, // src
1231 fd.getType(), // type
1232 fd.getSymbol(), // field
1233 true, // special param initial
1234 betaSoupWJ ); // reachability
1235 addReferenceEdge( primaryI, primaryJ, edgePrimaryI2PrimaryJ );
1241 // look at whether aliased parameters i and j can
1242 // possibly be the same primary object, add edges
1243 Iterator<Integer> apItrJ = aliasedParamIndices.iterator();
1244 while( apItrJ.hasNext() ) {
1245 Integer j = apItrJ.next();
1246 TempDescriptor tdParamJ = fm.getParameter( j );
1247 TypeDescriptor typeJ = tdParamJ.getType();
1248 LabelNode lnParamJ = getLabelNodeFromTemp( tdParamJ );
1250 if( !i.equals( j ) && typeUtil.isSuperorType( typeI, typeJ ) ) {
1252 Integer idPrimaryJ = paramIndex2idPrimary.get( j );
1253 assert idPrimaryJ != null;
1254 HeapRegionNode primaryJ = id2hrn.get( idPrimaryJ );
1255 assert primaryJ != null;
1257 ReferenceEdge lnJ2PrimaryJ = lnParamJ.getReferenceTo( primaryJ,
1260 assert lnJ2PrimaryJ != null;
1262 ReferenceEdge lnI2PrimaryJ = lnJ2PrimaryJ.copy();
1263 lnI2PrimaryJ.setSrc( lnParamI );
1264 lnI2PrimaryJ.setType( tdParamI.getType() );
1265 lnI2PrimaryJ.tainedBy(new Integer(j));
1266 addReferenceEdge( lnParamI, primaryJ, lnI2PrimaryJ );
1272 public void prepareParamTokenMaps( FlatMethod fm ) {
1274 // always add the bogus mappings that are used to
1275 // rewrite "with respect to no parameter"
1276 paramTokenPrimary2paramIndex.put( bogusToken, bogusIndex );
1277 paramIndex2paramTokenPrimary.put( bogusIndex, bogusToken );
1279 paramTokenSecondary2paramIndex.put( bogusToken, bogusIndex );
1280 paramIndex2paramTokenSecondary.put( bogusIndex, bogusToken );
1281 paramTokenSecondaryPlus2paramIndex.put( bogusTokenPlus, bogusIndex );
1282 paramIndex2paramTokenSecondaryPlus.put( bogusIndex, bogusTokenPlus );
1283 paramTokenSecondaryStar2paramIndex.put( bogusTokenStar, bogusIndex );
1284 paramIndex2paramTokenSecondaryStar.put( bogusIndex, bogusTokenStar );
1286 for( int i = 0; i < fm.numParameters(); ++i ) {
1287 Integer paramIndex = new Integer( i );
1289 // immutable objects have no primary regions
1290 if( paramIndex2idPrimary.containsKey( paramIndex ) ) {
1291 Integer idPrimary = paramIndex2idPrimary.get( paramIndex );
1293 assert id2hrn.containsKey( idPrimary );
1294 HeapRegionNode hrnPrimary = id2hrn.get( idPrimary );
1296 TokenTuple p_i = new TokenTuple( hrnPrimary.getID(),
1297 false, // multiple-object?
1298 TokenTuple.ARITY_ONE ).makeCanonical();
1299 paramTokenPrimary2paramIndex.put( p_i, paramIndex );
1300 paramIndex2paramTokenPrimary.put( paramIndex, p_i );
1303 // any parameter object, by type, may have no secondary region
1304 if( paramIndex2idSecondary.containsKey( paramIndex ) ) {
1305 Integer idSecondary = paramIndex2idSecondary.get( paramIndex );
1307 assert id2hrn.containsKey( idSecondary );
1308 HeapRegionNode hrnSecondary = id2hrn.get( idSecondary );
1310 TokenTuple s_i = new TokenTuple( hrnSecondary.getID(),
1311 true, // multiple-object?
1312 TokenTuple.ARITY_ONE ).makeCanonical();
1313 paramTokenSecondary2paramIndex.put( s_i, paramIndex );
1314 paramIndex2paramTokenSecondary.put( paramIndex, s_i );
1316 TokenTuple s_i_plus = new TokenTuple( hrnSecondary.getID(),
1317 true, // multiple-object?
1318 TokenTuple.ARITY_ONEORMORE ).makeCanonical();
1319 paramTokenSecondaryPlus2paramIndex.put( s_i_plus, paramIndex );
1320 paramIndex2paramTokenSecondaryPlus.put( paramIndex, s_i_plus );
1322 TokenTuple s_i_star = new TokenTuple( hrnSecondary.getID(),
1323 true, // multiple-object?
1324 TokenTuple.ARITY_ZEROORMORE ).makeCanonical();
1325 paramTokenSecondaryStar2paramIndex.put( s_i_star, paramIndex );
1326 paramIndex2paramTokenSecondaryStar.put( paramIndex, s_i_star );
1333 public void assignReturnEqualToTemp(TempDescriptor x) {
1335 LabelNode lnR = getLabelNodeFromTemp(tdReturn);
1336 LabelNode lnX = getLabelNodeFromTemp(x);
1338 clearReferenceEdgesFrom(lnR, null, null, true);
1340 Iterator<ReferenceEdge> itrXhrn = lnX.iteratorToReferencees();
1341 while( itrXhrn.hasNext() ) {
1342 ReferenceEdge edgeX = itrXhrn.next();
1343 HeapRegionNode referencee = edgeX.getDst();
1344 ReferenceEdge edgeNew = edgeX.copy();
1345 edgeNew.setSrc(lnR);
1347 addReferenceEdge(lnR, referencee, edgeNew);
1352 public void assignTempEqualToNewAlloc(TempDescriptor x,
1353 AllocationSite as) {
1359 // after the age operation the newest (or zero-ith oldest)
1360 // node associated with the allocation site should have
1361 // no references to it as if it were a newly allocated
1363 Integer idNewest = as.getIthOldest( 0 );
1364 HeapRegionNode hrnNewest = id2hrn.get( idNewest );
1365 assert hrnNewest != null;
1367 LabelNode lnX = getLabelNodeFromTemp( x );
1368 clearReferenceEdgesFrom( lnX, null, null, true );
1370 // make a new reference to allocated node
1371 TypeDescriptor type = as.getType();
1372 ReferenceEdge edgeNew =
1373 new ReferenceEdge( lnX, // source
1377 false, // is initial param
1378 hrnNewest.getAlpha() // beta
1381 addReferenceEdge( lnX, hrnNewest, edgeNew );
1385 // use the allocation site (unique to entire analysis) to
1386 // locate the heap region nodes in this ownership graph
1387 // that should be aged. The process models the allocation
1388 // of new objects and collects all the oldest allocations
1389 // in a summary node to allow for a finite analysis
1391 // There is an additional property of this method. After
1392 // running it on a particular ownership graph (many graphs
1393 // may have heap regions related to the same allocation site)
1394 // the heap region node objects in this ownership graph will be
1395 // allocated. Therefore, after aging a graph for an allocation
1396 // site, attempts to retrieve the heap region nodes using the
1397 // integer id's contained in the allocation site should always
1398 // return non-null heap regions.
1399 public void age(AllocationSite as) {
1401 // aging adds this allocation site to the graph's
1402 // list of sites that exist in the graph, or does
1403 // nothing if the site is already in the list
1404 allocationSites.add(as);
1406 // get the summary node for the allocation site in the context
1407 // of this particular ownership graph
1408 HeapRegionNode hrnSummary = getSummaryNode(as);
1410 // merge oldest node into summary
1411 Integer idK = as.getOldest();
1412 HeapRegionNode hrnK = id2hrn.get(idK);
1413 mergeIntoSummary(hrnK, hrnSummary);
1415 // move down the line of heap region nodes
1416 // clobbering the ith and transferring all references
1417 // to and from i-1 to node i. Note that this clobbers
1418 // the oldest node (hrnK) that was just merged into
1420 for( int i = allocationDepth - 1; i > 0; --i ) {
1422 // move references from the i-1 oldest to the ith oldest
1423 Integer idIth = as.getIthOldest(i);
1424 HeapRegionNode hrnI = id2hrn.get(idIth);
1425 Integer idImin1th = as.getIthOldest(i - 1);
1426 HeapRegionNode hrnImin1 = id2hrn.get(idImin1th);
1428 transferOnto(hrnImin1, hrnI);
1431 // as stated above, the newest node should have had its
1432 // references moved over to the second oldest, so we wipe newest
1433 // in preparation for being the new object to assign something to
1434 Integer id0th = as.getIthOldest(0);
1435 HeapRegionNode hrn0 = id2hrn.get(id0th);
1436 assert hrn0 != null;
1438 // clear all references in and out of newest node
1439 clearReferenceEdgesFrom(hrn0, null, null, true);
1440 clearReferenceEdgesTo(hrn0, null, null, true);
1443 // now tokens in reachability sets need to "age" also
1444 Iterator itrAllLabelNodes = td2ln.entrySet().iterator();
1445 while( itrAllLabelNodes.hasNext() ) {
1446 Map.Entry me = (Map.Entry)itrAllLabelNodes.next();
1447 LabelNode ln = (LabelNode) me.getValue();
1449 Iterator<ReferenceEdge> itrEdges = ln.iteratorToReferencees();
1450 while( itrEdges.hasNext() ) {
1451 ageTokens(as, itrEdges.next() );
1455 Iterator itrAllHRNodes = id2hrn.entrySet().iterator();
1456 while( itrAllHRNodes.hasNext() ) {
1457 Map.Entry me = (Map.Entry)itrAllHRNodes.next();
1458 HeapRegionNode hrnToAge = (HeapRegionNode) me.getValue();
1460 ageTokens(as, hrnToAge);
1462 Iterator<ReferenceEdge> itrEdges = hrnToAge.iteratorToReferencees();
1463 while( itrEdges.hasNext() ) {
1464 ageTokens(as, itrEdges.next() );
1469 // after tokens have been aged, reset newest node's reachability
1470 if( hrn0.isFlagged() ) {
1471 hrn0.setAlpha(new ReachabilitySet(
1473 new TokenTuple(hrn0).makeCanonical()
1478 hrn0.setAlpha(new ReachabilitySet(
1479 new TokenTupleSet().makeCanonical()
1486 protected HeapRegionNode getSummaryNode(AllocationSite as) {
1488 Integer idSummary = as.getSummary();
1489 HeapRegionNode hrnSummary = id2hrn.get(idSummary);
1491 // If this is null then we haven't touched this allocation site
1492 // in the context of the current ownership graph, so allocate
1493 // heap region nodes appropriate for the entire allocation site.
1494 // This should only happen once per ownership graph per allocation site,
1495 // and a particular integer id can be used to locate the heap region
1496 // in different ownership graphs that represents the same part of an
1498 if( hrnSummary == null ) {
1500 boolean hasFlags = false;
1501 if( as.getType().isClass() ) {
1502 hasFlags = as.getType().getClassDesc().hasFlags();
1506 hasFlags=as.getFlag();
1509 hrnSummary = createNewHeapRegionNode(idSummary, // id or null to generate a new one
1510 false, // single object?
1512 hasFlags, // flagged?
1513 false, // is a parameter?
1514 as.getType(), // type
1515 as, // allocation site
1516 null, // reachability set
1517 as.toStringForDOT() + "\\nsummary",
1518 generateUniqueIdentifier(as,0,true));
1520 for( int i = 0; i < as.getAllocationDepth(); ++i ) {
1521 Integer idIth = as.getIthOldest(i);
1522 assert !id2hrn.containsKey(idIth);
1523 createNewHeapRegionNode(idIth, // id or null to generate a new one
1524 true, // single object?
1526 hasFlags, // flagged?
1527 false, // is a parameter?
1528 as.getType(), // type
1529 as, // allocation site
1530 null, // reachability set
1531 as.toStringForDOT() + "\\n" + i + " oldest",
1532 generateUniqueIdentifier(as,i,false));
1540 protected HeapRegionNode getShadowSummaryNode(AllocationSite as) {
1542 Integer idShadowSummary = as.getSummaryShadow();
1543 HeapRegionNode hrnShadowSummary = id2hrn.get(idShadowSummary);
1545 if( hrnShadowSummary == null ) {
1547 boolean hasFlags = false;
1548 if( as.getType().isClass() ) {
1549 hasFlags = as.getType().getClassDesc().hasFlags();
1552 hrnShadowSummary = createNewHeapRegionNode(idShadowSummary, // id or null to generate a new one
1553 false, // single object?
1555 hasFlags, // flagged?
1556 false, // is a parameter?
1557 as.getType(), // type
1558 as, // allocation site
1559 null, // reachability set
1560 as + "\\n" + as.getType() + "\\nshadowSum",
1563 for( int i = 0; i < as.getAllocationDepth(); ++i ) {
1564 Integer idShadowIth = as.getIthOldestShadow(i);
1565 assert !id2hrn.containsKey(idShadowIth);
1566 createNewHeapRegionNode(idShadowIth, // id or null to generate a new one
1567 true, // single object?
1569 hasFlags, // flagged?
1570 false, // is a parameter?
1571 as.getType(), // type
1572 as, // allocation site
1573 null, // reachability set
1574 as + "\\n" + as.getType() + "\\n" + i + " shadow",
1579 return hrnShadowSummary;
1583 protected void mergeIntoSummary(HeapRegionNode hrn, HeapRegionNode hrnSummary) {
1584 assert hrnSummary.isNewSummary();
1586 // transfer references _from_ hrn over to hrnSummary
1587 Iterator<ReferenceEdge> itrReferencee = hrn.iteratorToReferencees();
1588 while( itrReferencee.hasNext() ) {
1589 ReferenceEdge edge = itrReferencee.next();
1590 ReferenceEdge edgeMerged = edge.copy();
1591 edgeMerged.setSrc(hrnSummary);
1593 HeapRegionNode hrnReferencee = edge.getDst();
1594 ReferenceEdge edgeSummary = hrnSummary.getReferenceTo(hrnReferencee,
1598 if( edgeSummary == null ) {
1599 // the merge is trivial, nothing to be done
1601 // otherwise an edge from the referencer to hrnSummary exists already
1602 // and the edge referencer->hrn should be merged with it
1603 edgeMerged.setBeta(edgeMerged.getBeta().union(edgeSummary.getBeta() ) );
1606 addReferenceEdge(hrnSummary, hrnReferencee, edgeMerged);
1609 // next transfer references _to_ hrn over to hrnSummary
1610 Iterator<ReferenceEdge> itrReferencer = hrn.iteratorToReferencers();
1611 while( itrReferencer.hasNext() ) {
1612 ReferenceEdge edge = itrReferencer.next();
1613 ReferenceEdge edgeMerged = edge.copy();
1614 edgeMerged.setDst(hrnSummary);
1616 OwnershipNode onReferencer = edge.getSrc();
1617 ReferenceEdge edgeSummary = onReferencer.getReferenceTo(hrnSummary,
1621 if( edgeSummary == null ) {
1622 // the merge is trivial, nothing to be done
1624 // otherwise an edge from the referencer to alpha_S exists already
1625 // and the edge referencer->alpha_K should be merged with it
1626 edgeMerged.setBeta(edgeMerged.getBeta().union(edgeSummary.getBeta() ) );
1629 addReferenceEdge(onReferencer, hrnSummary, edgeMerged);
1632 // then merge hrn reachability into hrnSummary
1633 hrnSummary.setAlpha(hrnSummary.getAlpha().union(hrn.getAlpha() ) );
1637 protected void transferOnto(HeapRegionNode hrnA, HeapRegionNode hrnB) {
1639 // clear references in and out of node b
1640 clearReferenceEdgesFrom(hrnB, null, null, true);
1641 clearReferenceEdgesTo(hrnB, null, null, true);
1643 // copy each edge in and out of A to B
1644 Iterator<ReferenceEdge> itrReferencee = hrnA.iteratorToReferencees();
1645 while( itrReferencee.hasNext() ) {
1646 ReferenceEdge edge = itrReferencee.next();
1647 HeapRegionNode hrnReferencee = edge.getDst();
1648 ReferenceEdge edgeNew = edge.copy();
1649 edgeNew.setSrc(hrnB);
1651 addReferenceEdge(hrnB, hrnReferencee, edgeNew);
1654 Iterator<ReferenceEdge> itrReferencer = hrnA.iteratorToReferencers();
1655 while( itrReferencer.hasNext() ) {
1656 ReferenceEdge edge = itrReferencer.next();
1657 OwnershipNode onReferencer = edge.getSrc();
1658 ReferenceEdge edgeNew = edge.copy();
1659 edgeNew.setDst(hrnB);
1661 addReferenceEdge(onReferencer, hrnB, edgeNew);
1664 // replace hrnB reachability with hrnA's
1665 hrnB.setAlpha(hrnA.getAlpha() );
1669 protected void ageTokens(AllocationSite as, ReferenceEdge edge) {
1670 edge.setBeta(edge.getBeta().ageTokens(as) );
1673 protected void ageTokens(AllocationSite as, HeapRegionNode hrn) {
1674 hrn.setAlpha(hrn.getAlpha().ageTokens(as) );
1679 protected void propagateTokensOverNodes(HeapRegionNode nPrime,
1681 HashSet<HeapRegionNode> nodesWithNewAlpha,
1682 HashSet<ReferenceEdge> edgesWithNewBeta) {
1684 HashSet<HeapRegionNode> todoNodes
1685 = new HashSet<HeapRegionNode>();
1686 todoNodes.add(nPrime);
1688 HashSet<ReferenceEdge> todoEdges
1689 = new HashSet<ReferenceEdge>();
1691 Hashtable<HeapRegionNode, ChangeTupleSet> nodePlannedChanges
1692 = new Hashtable<HeapRegionNode, ChangeTupleSet>();
1693 nodePlannedChanges.put(nPrime, c0);
1695 Hashtable<ReferenceEdge, ChangeTupleSet> edgePlannedChanges
1696 = new Hashtable<ReferenceEdge, ChangeTupleSet>();
1698 // first propagate change sets everywhere they can go
1699 while( !todoNodes.isEmpty() ) {
1700 HeapRegionNode n = todoNodes.iterator().next();
1701 ChangeTupleSet C = nodePlannedChanges.get(n);
1703 Iterator<ReferenceEdge> referItr = n.iteratorToReferencers();
1704 while( referItr.hasNext() ) {
1705 ReferenceEdge edge = referItr.next();
1706 todoEdges.add(edge);
1708 if( !edgePlannedChanges.containsKey(edge) ) {
1709 edgePlannedChanges.put(edge, new ChangeTupleSet().makeCanonical() );
1712 edgePlannedChanges.put(edge, edgePlannedChanges.get(edge).union(C) );
1715 Iterator<ReferenceEdge> refeeItr = n.iteratorToReferencees();
1716 while( refeeItr.hasNext() ) {
1717 ReferenceEdge edgeF = refeeItr.next();
1718 HeapRegionNode m = edgeF.getDst();
1720 ChangeTupleSet changesToPass = new ChangeTupleSet().makeCanonical();
1722 Iterator<ChangeTuple> itrCprime = C.iterator();
1723 while( itrCprime.hasNext() ) {
1724 ChangeTuple c = itrCprime.next();
1725 if( edgeF.getBeta().contains( c.getSetToMatch() ) ) {
1726 changesToPass = changesToPass.union(c);
1730 if( !changesToPass.isEmpty() ) {
1731 if( !nodePlannedChanges.containsKey(m) ) {
1732 nodePlannedChanges.put(m, new ChangeTupleSet().makeCanonical() );
1735 ChangeTupleSet currentChanges = nodePlannedChanges.get(m);
1737 if( !changesToPass.isSubset(currentChanges) ) {
1739 nodePlannedChanges.put(m, currentChanges.union(changesToPass) );
1745 todoNodes.remove(n);
1748 // then apply all of the changes for each node at once
1749 Iterator itrMap = nodePlannedChanges.entrySet().iterator();
1750 while( itrMap.hasNext() ) {
1751 Map.Entry me = (Map.Entry) itrMap.next();
1752 HeapRegionNode n = (HeapRegionNode) me.getKey();
1753 ChangeTupleSet C = (ChangeTupleSet) me.getValue();
1755 // this propagation step is with respect to one change,
1756 // so we capture the full change from the old alpha:
1757 ReachabilitySet localDelta = n.getAlpha().applyChangeSet( C, true );
1759 // but this propagation may be only one of many concurrent
1760 // possible changes, so keep a running union with the node's
1761 // partially updated new alpha set
1762 n.setAlphaNew( n.getAlphaNew().union( localDelta ) );
1764 nodesWithNewAlpha.add( n );
1767 propagateTokensOverEdges(todoEdges, edgePlannedChanges, edgesWithNewBeta);
1771 protected void propagateTokensOverEdges(
1772 HashSet<ReferenceEdge> todoEdges,
1773 Hashtable<ReferenceEdge, ChangeTupleSet> edgePlannedChanges,
1774 HashSet<ReferenceEdge> edgesWithNewBeta) {
1776 // first propagate all change tuples everywhere they can go
1777 while( !todoEdges.isEmpty() ) {
1778 ReferenceEdge edgeE = todoEdges.iterator().next();
1779 todoEdges.remove(edgeE);
1781 if( !edgePlannedChanges.containsKey(edgeE) ) {
1782 edgePlannedChanges.put(edgeE, new ChangeTupleSet().makeCanonical() );
1785 ChangeTupleSet C = edgePlannedChanges.get(edgeE);
1787 ChangeTupleSet changesToPass = new ChangeTupleSet().makeCanonical();
1789 Iterator<ChangeTuple> itrC = C.iterator();
1790 while( itrC.hasNext() ) {
1791 ChangeTuple c = itrC.next();
1792 if( edgeE.getBeta().contains( c.getSetToMatch() ) ) {
1793 changesToPass = changesToPass.union(c);
1797 OwnershipNode onSrc = edgeE.getSrc();
1799 if( !changesToPass.isEmpty() && onSrc instanceof HeapRegionNode ) {
1800 HeapRegionNode n = (HeapRegionNode) onSrc;
1802 Iterator<ReferenceEdge> referItr = n.iteratorToReferencers();
1803 while( referItr.hasNext() ) {
1804 ReferenceEdge edgeF = referItr.next();
1806 if( !edgePlannedChanges.containsKey(edgeF) ) {
1807 edgePlannedChanges.put(edgeF, new ChangeTupleSet().makeCanonical() );
1810 ChangeTupleSet currentChanges = edgePlannedChanges.get(edgeF);
1812 if( !changesToPass.isSubset(currentChanges) ) {
1813 todoEdges.add(edgeF);
1814 edgePlannedChanges.put(edgeF, currentChanges.union(changesToPass) );
1820 // then apply all of the changes for each edge at once
1821 Iterator itrMap = edgePlannedChanges.entrySet().iterator();
1822 while( itrMap.hasNext() ) {
1823 Map.Entry me = (Map.Entry) itrMap.next();
1824 ReferenceEdge e = (ReferenceEdge) me.getKey();
1825 ChangeTupleSet C = (ChangeTupleSet) me.getValue();
1827 // this propagation step is with respect to one change,
1828 // so we capture the full change from the old beta:
1829 ReachabilitySet localDelta = e.getBeta().applyChangeSet( C, true );
1831 // but this propagation may be only one of many concurrent
1832 // possible changes, so keep a running union with the edge's
1833 // partially updated new beta set
1834 e.setBetaNew( e.getBetaNew().union( localDelta ) );
1836 edgesWithNewBeta.add( e );
1841 public Set<Integer> calculateAliasedParamSet( FlatCall fc,
1845 Hashtable<Integer, LabelNode> paramIndex2ln =
1846 new Hashtable<Integer, LabelNode>();
1848 Hashtable<Integer, HashSet<HeapRegionNode> > paramIndex2reachableCallerNodes =
1849 new Hashtable<Integer, HashSet<HeapRegionNode> >();
1851 for( int i = 0; i < fm.numParameters(); ++i ) {
1852 Integer paramIndex = new Integer( i );
1853 TempDescriptor tdParam = fm.getParameter( i );
1854 TypeDescriptor typeParam = tdParam.getType();
1856 if( typeParam.isImmutable() && !typeParam.isArray() ) {
1857 // don't bother with this primitive parameter, it
1858 // cannot affect reachability
1862 // now depending on whether the callee is static or not
1863 // we need to account for a "this" argument in order to
1864 // find the matching argument in the caller context
1865 TempDescriptor argTemp_i = fc.getArgMatchingParamIndex( fm, paramIndex );
1867 LabelNode argLabel_i = getLabelNodeFromTemp(argTemp_i);
1868 paramIndex2ln.put(paramIndex, argLabel_i);
1871 Iterator lnArgItr = paramIndex2ln.entrySet().iterator();
1872 while( lnArgItr.hasNext() ) {
1873 Map.Entry me = (Map.Entry)lnArgItr.next();
1874 Integer index = (Integer) me.getKey();
1875 LabelNode lnArg_i = (LabelNode) me.getValue();
1877 HashSet<HeapRegionNode> reachableNodes = new HashSet<HeapRegionNode>();
1878 HashSet<HeapRegionNode> todoNodes = new HashSet<HeapRegionNode>();
1880 // to find all reachable nodes, start with label referencees
1881 Iterator<ReferenceEdge> edgeArgItr = lnArg_i.iteratorToReferencees();
1882 while( edgeArgItr.hasNext() ) {
1883 ReferenceEdge edge = edgeArgItr.next();
1884 todoNodes.add( edge.getDst() );
1887 // then follow links until all reachable nodes have been found
1888 while( !todoNodes.isEmpty() ) {
1889 HeapRegionNode hrn = todoNodes.iterator().next();
1890 todoNodes.remove(hrn);
1891 reachableNodes.add(hrn);
1893 Iterator<ReferenceEdge> edgeItr = hrn.iteratorToReferencees();
1894 while( edgeItr.hasNext() ) {
1895 ReferenceEdge edge = edgeItr.next();
1897 if( !reachableNodes.contains(edge.getDst() ) ) {
1898 todoNodes.add(edge.getDst() );
1904 paramIndex2reachableCallerNodes.put(index, reachableNodes);
1907 Set<Integer> aliasedIndices = new HashSet<Integer>();
1909 // check for arguments that are aliased
1910 for( int i = 0; i < fm.numParameters(); ++i ) {
1911 for( int j = 0; j < i; ++j ) {
1912 HashSet<HeapRegionNode> s1 = paramIndex2reachableCallerNodes.get( i );
1913 HashSet<HeapRegionNode> s2 = paramIndex2reachableCallerNodes.get( j );
1915 // some parameters are immutable or primitive, so skip em
1916 if( s1 == null || s2 == null ) {
1920 Set<HeapRegionNode> intersection = new HashSet<HeapRegionNode>(s1);
1921 intersection.retainAll(s2);
1923 if( !intersection.isEmpty() ) {
1924 aliasedIndices.add( new Integer( i ) );
1925 aliasedIndices.add( new Integer( j ) );
1930 return aliasedIndices;
1934 private String makeMapKey( Integer i, Integer j, String field ) {
1935 return i+","+j+","+field;
1938 private String makeMapKey( Integer i, String field ) {
1942 // these hashtables are used during the mapping procedure to say that
1943 // with respect to some argument i there is an edge placed into some
1944 // category for mapping with respect to another argument index j
1945 // so the key into the hashtable is i, the value is a two-element vector
1946 // that contains in 0 the edge and in 1 the Integer index j
1947 private void ensureEmptyEdgeIndexPair( Hashtable< Integer, Set<Vector> > edge_index_pairs,
1950 Set<Vector> ei = edge_index_pairs.get( indexI );
1952 ei = new HashSet<Vector>();
1954 edge_index_pairs.put( indexI, ei );
1957 private void addEdgeIndexPair( Hashtable< Integer, Set<Vector> > edge_index_pairs,
1962 Vector v = new Vector(); v.setSize( 2 );
1964 v.set( 1 , indexJ );
1965 Set<Vector> ei = edge_index_pairs.get( indexI );
1967 ei = new HashSet<Vector>();
1970 edge_index_pairs.put( indexI, ei );
1973 private ReachabilitySet funcScriptR( ReachabilitySet rsIn,
1974 OwnershipGraph ogCallee,
1975 MethodContext mc ) {
1977 ReachabilitySet rsOut = new ReachabilitySet( rsIn );
1979 Iterator itr = ogCallee.paramIndex2paramTokenPrimary.entrySet().iterator();
1980 while( itr.hasNext() ) {
1981 Map.Entry me = (Map.Entry) itr.next();
1982 Integer i = (Integer) me.getKey();
1983 TokenTuple p_i = (TokenTuple) me.getValue();
1984 TokenTuple s_i = ogCallee.paramIndex2paramTokenSecondary.get( i );
1986 // skip this if there is no secondary token or the parameter
1987 // is part of the aliasing context
1988 if( s_i == null || mc.getAliasedParamIndices().contains( i ) ) {
1992 rsOut = rsOut.removeTokenAIfTokenB( p_i, s_i );
1998 // detects strong updates to the primary parameter object and
1999 // effects the removal of old edges in the calling graph
2000 private void effectCalleeStrongUpdates( Integer paramIndex,
2001 OwnershipGraph ogCallee,
2002 HeapRegionNode hrnCaller
2004 Integer idPrimary = ogCallee.paramIndex2idPrimary.get( paramIndex );
2005 assert idPrimary != null;
2007 HeapRegionNode hrnPrimary = ogCallee.id2hrn.get( idPrimary );
2008 assert hrnPrimary != null;
2010 TypeDescriptor typeParam = hrnPrimary.getType();
2011 assert typeParam.isClass();
2013 Set<String> fieldNamesToRemove = new HashSet<String>();
2015 ClassDescriptor cd = typeParam.getClassDesc();
2016 while( cd != null ) {
2018 Iterator fieldItr = cd.getFields();
2019 while( fieldItr.hasNext() ) {
2021 FieldDescriptor fd = (FieldDescriptor) fieldItr.next();
2022 TypeDescriptor typeField = fd.getType();
2023 assert typeField != null;
2025 if( ogCallee.hasFieldBeenUpdated( hrnPrimary, fd.getSymbol() ) ) {
2026 clearReferenceEdgesFrom( hrnCaller, fd.getType(), fd.getSymbol(), false );
2030 cd = cd.getSuperDesc();
2034 private boolean hasFieldBeenUpdated( HeapRegionNode hrnPrimary, String field ) {
2036 Iterator<ReferenceEdge> itr = hrnPrimary.iteratorToReferencees();
2037 while( itr.hasNext() ) {
2038 ReferenceEdge e = itr.next();
2039 if( e.fieldEquals( field ) && e.isInitialParam() ) {
2047 // resolveMethodCall() is used to incorporate a callee graph's effects into
2048 // *this* graph, which is the caller. This method can also be used, after
2049 // the entire analysis is complete, to perform parameter decomposition for
2050 // a given call chain.
2051 public void resolveMethodCall(FlatCall fc, // call site in caller method
2052 boolean isStatic, // whether it is a static method
2053 FlatMethod fm, // the callee method (when virtual, can be many)
2054 OwnershipGraph ogCallee, // the callee's current ownership graph
2055 MethodContext mc, // the aliasing context for this call
2056 ParameterDecomposition pd // if this is not null, we're calling after analysis
2060 mc.getDescriptor().getSymbol().equals( debugCaller ) &&
2061 fm.getMethod().getSymbol().equals( debugCallee )
2065 writeGraph("debug1BeforeCall",
2066 true, // write labels (variables)
2067 true, // selectively hide intermediate temp vars
2068 true, // prune unreachable heap regions
2069 false, // show back edges to confirm graph validity
2070 false, // show parameter indices (unmaintained!)
2071 true, // hide subset reachability states
2072 true); // hide edge taints
2074 ogCallee.writeGraph("debug0Callee",
2075 true, // write labels (variables)
2076 true, // selectively hide intermediate temp vars
2077 true, // prune unreachable heap regions
2078 false, // show back edges to confirm graph validity
2079 false, // show parameter indices (unmaintained!)
2080 true, // hide subset reachability states
2081 true); // hide edge taints
2082 } catch( IOException e ) {}
2084 System.out.println( " "+mc+" is calling "+fm );
2089 // define rewrite rules and other structures to organize data by parameter/argument index
2090 Hashtable<Integer, ReachabilitySet> paramIndex2rewriteH_p = new Hashtable<Integer, ReachabilitySet>();
2091 Hashtable<Integer, ReachabilitySet> paramIndex2rewriteH_s = new Hashtable<Integer, ReachabilitySet>();
2093 Hashtable<String, ReachabilitySet> paramIndex2rewriteJ_p2p = new Hashtable<String, ReachabilitySet>(); // select( i, j, f )
2094 Hashtable<String, ReachabilitySet> paramIndex2rewriteJ_p2s = new Hashtable<String, ReachabilitySet>(); // select( i, f )
2095 Hashtable<Integer, ReachabilitySet> paramIndex2rewriteJ_s2p = new Hashtable<Integer, ReachabilitySet>();
2096 Hashtable<Integer, ReachabilitySet> paramIndex2rewriteJ_s2s = new Hashtable<Integer, ReachabilitySet>();
2098 Hashtable<Integer, ReachabilitySet> paramIndex2rewriteK_p = new Hashtable<Integer, ReachabilitySet>();
2099 Hashtable<Integer, ReachabilitySet> paramIndex2rewriteK_p2 = new Hashtable<Integer, ReachabilitySet>();
2100 Hashtable<Integer, ReachabilitySet> paramIndex2rewriteK_s = new Hashtable<Integer, ReachabilitySet>();
2102 Hashtable<Integer, ReachabilitySet> paramIndex2rewrite_d_p = new Hashtable<Integer, ReachabilitySet>();
2103 Hashtable<Integer, ReachabilitySet> paramIndex2rewrite_d_s = new Hashtable<Integer, ReachabilitySet>();
2105 Hashtable<Integer, ReachabilitySet> paramIndex2rewriteD = new Hashtable<Integer, ReachabilitySet>();
2108 Hashtable<Integer, LabelNode> paramIndex2ln = new Hashtable<Integer, LabelNode>();
2111 paramIndex2rewriteH_p.put( bogusIndex, rsIdentity );
2112 paramIndex2rewriteH_s.put( bogusIndex, rsIdentity );
2114 paramIndex2rewriteJ_p2p.put( bogusIndex.toString(), rsIdentity );
2115 paramIndex2rewriteJ_p2s.put( bogusIndex.toString(), rsIdentity );
2116 paramIndex2rewriteJ_s2p.put( bogusIndex, rsIdentity );
2117 paramIndex2rewriteJ_s2s.put( bogusIndex, rsIdentity );
2120 for( int i = 0; i < fm.numParameters(); ++i ) {
2121 Integer paramIndex = new Integer(i);
2123 if( !ogCallee.paramIndex2idPrimary.containsKey( paramIndex ) ) {
2124 // skip this immutable parameter
2128 // setup H (primary)
2129 Integer idPrimary = ogCallee.paramIndex2idPrimary.get( paramIndex );
2130 assert ogCallee.id2hrn.containsKey( idPrimary );
2131 HeapRegionNode hrnPrimary = ogCallee.id2hrn.get( idPrimary );
2132 assert hrnPrimary != null;
2133 paramIndex2rewriteH_p.put( paramIndex, toShadowTokens( ogCallee, hrnPrimary.getAlpha() ) );
2135 // setup J (primary->X)
2136 Iterator<ReferenceEdge> p2xItr = hrnPrimary.iteratorToReferencees();
2137 while( p2xItr.hasNext() ) {
2138 ReferenceEdge p2xEdge = p2xItr.next();
2140 // we only care about initial parameter edges here
2141 if( !p2xEdge.isInitialParam() ) { continue; }
2143 HeapRegionNode hrnDst = p2xEdge.getDst();
2145 if( ogCallee.idPrimary2paramIndexSet.containsKey( hrnDst.getID() ) ) {
2146 Iterator<Integer> jItr = ogCallee.idPrimary2paramIndexSet.get( hrnDst.getID() ).iterator();
2147 while( jItr.hasNext() ) {
2148 Integer j = jItr.next();
2149 paramIndex2rewriteJ_p2p.put( makeMapKey( i, j, p2xEdge.getField() ),
2150 toShadowTokens( ogCallee, p2xEdge.getBeta() ) );
2154 assert ogCallee.idSecondary2paramIndexSet.containsKey( hrnDst.getID() );
2155 paramIndex2rewriteJ_p2s.put( makeMapKey( i, p2xEdge.getField() ),
2156 toShadowTokens( ogCallee, p2xEdge.getBeta() ) );
2160 // setup K (primary)
2161 TempDescriptor tdParamQ = ogCallee.paramIndex2tdQ.get( paramIndex );
2162 assert tdParamQ != null;
2163 LabelNode lnParamQ = ogCallee.td2ln.get( tdParamQ );
2164 assert lnParamQ != null;
2165 ReferenceEdge edgeSpecialQ_i = lnParamQ.getReferenceTo( hrnPrimary, null, null );
2166 assert edgeSpecialQ_i != null;
2167 ReachabilitySet qBeta = toShadowTokens( ogCallee, edgeSpecialQ_i.getBeta() );
2169 TokenTuple p_i = ogCallee.paramIndex2paramTokenPrimary .get( paramIndex );
2170 TokenTuple s_i = ogCallee.paramIndex2paramTokenSecondary.get( paramIndex );
2172 ReachabilitySet K_p = new ReachabilitySet().makeCanonical();
2173 ReachabilitySet K_p2 = new ReachabilitySet().makeCanonical();
2177 // sort qBeta into K_p1 and K_p2
2178 Iterator<TokenTupleSet> ttsItr = qBeta.iterator();
2179 while( ttsItr.hasNext() ) {
2180 TokenTupleSet tts = ttsItr.next();
2181 if( s_i != null && tts.containsBoth( p_i, s_i ) ) {
2182 K_p2 = K_p2.union( tts );
2184 K_p = K_p.union( tts );
2188 paramIndex2rewriteK_p .put( paramIndex, K_p );
2189 paramIndex2rewriteK_p2.put( paramIndex, K_p2 );
2192 // if there is a secondary node, compute the rest of the rewrite rules
2193 if( ogCallee.paramIndex2idSecondary.containsKey( paramIndex ) ) {
2195 // setup H (secondary)
2196 Integer idSecondary = ogCallee.paramIndex2idSecondary.get( paramIndex );
2197 assert ogCallee.id2hrn.containsKey( idSecondary );
2198 HeapRegionNode hrnSecondary = ogCallee.id2hrn.get( idSecondary );
2199 assert hrnSecondary != null;
2200 paramIndex2rewriteH_s.put( paramIndex, toShadowTokens( ogCallee, hrnSecondary.getAlpha() ) );
2202 // setup J (secondary->X)
2203 Iterator<ReferenceEdge> s2xItr = hrnSecondary.iteratorToReferencees();
2204 while( s2xItr.hasNext() ) {
2205 ReferenceEdge s2xEdge = s2xItr.next();
2207 if( !s2xEdge.isInitialParam() ) { continue; }
2209 HeapRegionNode hrnDst = s2xEdge.getDst();
2211 if( ogCallee.idPrimary2paramIndexSet.containsKey( hrnDst.getID() ) ) {
2212 Iterator<Integer> jItr = ogCallee.idPrimary2paramIndexSet.get( hrnDst.getID() ).iterator();
2213 while( jItr.hasNext() ) {
2214 Integer j = jItr.next();
2215 paramIndex2rewriteJ_s2p.put( i, toShadowTokens( ogCallee, s2xEdge.getBeta() ) );
2219 assert ogCallee.idSecondary2paramIndexSet.containsKey( hrnDst.getID() );
2220 paramIndex2rewriteJ_s2s.put( i, toShadowTokens( ogCallee, s2xEdge.getBeta() ) );
2224 // setup K (secondary)
2225 TempDescriptor tdParamR = ogCallee.paramIndex2tdR.get( paramIndex );
2226 assert tdParamR != null;
2227 LabelNode lnParamR = ogCallee.td2ln.get( tdParamR );
2228 assert lnParamR != null;
2229 ReferenceEdge edgeSpecialR_i = lnParamR.getReferenceTo( hrnSecondary, null, null );
2230 assert edgeSpecialR_i != null;
2231 paramIndex2rewriteK_s.put( paramIndex,
2232 toShadowTokens( ogCallee, edgeSpecialR_i.getBeta() ) );
2236 // now depending on whether the callee is static or not
2237 // we need to account for a "this" argument in order to
2238 // find the matching argument in the caller context
2239 TempDescriptor argTemp_i = fc.getArgMatchingParamIndex( fm, paramIndex );
2241 // remember which caller arg label maps to param index
2242 LabelNode argLabel_i = getLabelNodeFromTemp( argTemp_i );
2243 paramIndex2ln.put( paramIndex, argLabel_i );
2245 // do a callee-effect strong update pre-pass here
2246 if( argTemp_i.getType().isClass() ) {
2248 Iterator<ReferenceEdge> edgeItr = argLabel_i.iteratorToReferencees();
2249 while( edgeItr.hasNext() ) {
2250 ReferenceEdge edge = edgeItr.next();
2251 HeapRegionNode hrn = edge.getDst();
2253 if( (hrn.getNumReferencers() == 1) || // case 1
2254 (hrn.isSingleObject() && argLabel_i.getNumReferencees() == 1) // case 2
2256 if( !DISABLE_STRONG_UPDATES ) {
2257 effectCalleeStrongUpdates( paramIndex, ogCallee, hrn );
2263 // then calculate the d and D rewrite rules
2264 ReachabilitySet d_i_p = new ReachabilitySet().makeCanonical();
2265 ReachabilitySet d_i_s = new ReachabilitySet().makeCanonical();
2266 Iterator<ReferenceEdge> edgeItr = argLabel_i.iteratorToReferencees();
2267 while( edgeItr.hasNext() ) {
2268 ReferenceEdge edge = edgeItr.next();
2270 d_i_p = d_i_p.union( edge.getBeta().intersection( edge.getDst().getAlpha() ) );
2271 d_i_s = d_i_s.union( edge.getBeta() );
2273 paramIndex2rewrite_d_p.put( paramIndex, d_i_p );
2274 paramIndex2rewrite_d_s.put( paramIndex, d_i_s );
2276 // TODO: we should only do this when we need it, and then
2277 // memoize it for the rest of the mapping procedure
2278 ReachabilitySet D_i = d_i_s.exhaustiveArityCombinations();
2279 paramIndex2rewriteD.put( paramIndex, D_i );
2283 // with respect to each argument, map parameter effects into caller
2284 HashSet<HeapRegionNode> nodesWithNewAlpha = new HashSet<HeapRegionNode>();
2285 HashSet<ReferenceEdge> edgesWithNewBeta = new HashSet<ReferenceEdge>();
2287 Hashtable<Integer, Set<HeapRegionNode> > pi2dr =
2288 new Hashtable<Integer, Set<HeapRegionNode> >();
2290 Hashtable<Integer, Set<HeapRegionNode> > pi2r =
2291 new Hashtable<Integer, Set<HeapRegionNode> >();
2293 Set<HeapRegionNode> defParamObj = new HashSet<HeapRegionNode>();
2295 Iterator lnArgItr = paramIndex2ln.entrySet().iterator();
2296 while( lnArgItr.hasNext() ) {
2297 Map.Entry me = (Map.Entry) lnArgItr.next();
2298 Integer index = (Integer) me.getKey();
2299 LabelNode lnArg_i = (LabelNode) me.getValue();
2301 Set<HeapRegionNode> dr = new HashSet<HeapRegionNode>();
2302 Set<HeapRegionNode> r = new HashSet<HeapRegionNode>();
2303 Set<HeapRegionNode> todo = new HashSet<HeapRegionNode>();
2305 // find all reachable nodes starting with label referencees
2306 Iterator<ReferenceEdge> edgeArgItr = lnArg_i.iteratorToReferencees();
2307 while( edgeArgItr.hasNext() ) {
2308 ReferenceEdge edge = edgeArgItr.next();
2309 HeapRegionNode hrn = edge.getDst();
2313 if( lnArg_i.getNumReferencees() == 1 && hrn.isSingleObject() ) {
2314 defParamObj.add( hrn );
2317 Iterator<ReferenceEdge> edgeHrnItr = hrn.iteratorToReferencees();
2318 while( edgeHrnItr.hasNext() ) {
2319 ReferenceEdge edger = edgeHrnItr.next();
2320 todo.add( edger.getDst() );
2323 // then follow links until all reachable nodes have been found
2324 while( !todo.isEmpty() ) {
2325 HeapRegionNode hrnr = todo.iterator().next();
2326 todo.remove( hrnr );
2330 Iterator<ReferenceEdge> edgeItr = hrnr.iteratorToReferencees();
2331 while( edgeItr.hasNext() ) {
2332 ReferenceEdge edger = edgeItr.next();
2333 if( !r.contains( edger.getDst() ) ) {
2334 todo.add( edger.getDst() );
2339 if( hrn.isSingleObject() ) {
2344 pi2dr.put( index, dr );
2345 pi2r .put( index, r );
2348 assert defParamObj.size() <= fm.numParameters();
2350 // if we're in parameter decomposition mode, report some results here
2354 // report primary parameter object mappings
2355 mapItr = pi2dr.entrySet().iterator();
2356 while( mapItr.hasNext() ) {
2357 Map.Entry me = (Map.Entry) mapItr.next();
2358 Integer paramIndex = (Integer) me.getKey();
2359 Set<HeapRegionNode> hrnAset = (Set<HeapRegionNode>) me.getValue();
2361 Iterator<HeapRegionNode> hrnItr = hrnAset.iterator();
2362 while( hrnItr.hasNext() ) {
2363 HeapRegionNode hrnA = hrnItr.next();
2364 pd.mapRegionToParamObject( hrnA, paramIndex );
2368 // report parameter-reachable mappings
2369 mapItr = pi2r.entrySet().iterator();
2370 while( mapItr.hasNext() ) {
2371 Map.Entry me = (Map.Entry) mapItr.next();
2372 Integer paramIndex = (Integer) me.getKey();
2373 Set<HeapRegionNode> hrnRset = (Set<HeapRegionNode>) me.getValue();
2375 Iterator<HeapRegionNode> hrnItr = hrnRset.iterator();
2376 while( hrnItr.hasNext() ) {
2377 HeapRegionNode hrnR = hrnItr.next();
2378 pd.mapRegionToParamReachable( hrnR, paramIndex );
2382 // and we're done in this method for special param decomp mode
2387 // now iterate over reachable nodes to rewrite their alpha, and
2388 // classify edges found for beta rewrite
2389 Hashtable<TokenTuple, ReachabilitySet> tokens2states = new Hashtable<TokenTuple, ReachabilitySet>();
2391 Hashtable< Integer, Set<Vector> > edges_p2p = new Hashtable< Integer, Set<Vector> >();
2392 Hashtable< Integer, Set<Vector> > edges_p2s = new Hashtable< Integer, Set<Vector> >();
2393 Hashtable< Integer, Set<Vector> > edges_s2p = new Hashtable< Integer, Set<Vector> >();
2394 Hashtable< Integer, Set<Vector> > edges_s2s = new Hashtable< Integer, Set<Vector> >();
2395 Hashtable< Integer, Set<Vector> > edges_up_dr = new Hashtable< Integer, Set<Vector> >();
2396 Hashtable< Integer, Set<Vector> > edges_up_r = new Hashtable< Integer, Set<Vector> >();
2398 // so again, with respect to some arg i...
2399 lnArgItr = paramIndex2ln.entrySet().iterator();
2400 while( lnArgItr.hasNext() ) {
2401 Map.Entry me = (Map.Entry) lnArgItr.next();
2402 Integer index = (Integer) me.getKey();
2403 LabelNode lnArg_i = (LabelNode) me.getValue();
2405 TokenTuple p_i = ogCallee.paramIndex2paramTokenPrimary.get( index );
2406 TokenTuple s_i = ogCallee.paramIndex2paramTokenSecondary.get( index );
2409 ensureEmptyEdgeIndexPair( edges_p2p, index );
2410 ensureEmptyEdgeIndexPair( edges_p2s, index );
2411 ensureEmptyEdgeIndexPair( edges_s2p, index );
2412 ensureEmptyEdgeIndexPair( edges_s2s, index );
2413 ensureEmptyEdgeIndexPair( edges_up_dr, index );
2414 ensureEmptyEdgeIndexPair( edges_up_r, index );
2416 Set<HeapRegionNode> dr = pi2dr.get( index );
2417 Iterator<HeapRegionNode> hrnItr = dr.iterator();
2418 while( hrnItr.hasNext() ) {
2419 // this heap region is definitely an "a_i" or primary by virtue of being in dr
2420 HeapRegionNode hrn = hrnItr.next();
2422 tokens2states.clear();
2423 tokens2states.put( p_i, hrn.getAlpha() );
2425 rewriteCallerReachability( index,
2428 paramIndex2rewriteH_p.get( index ),
2430 paramIndex2rewrite_d_p,
2431 paramIndex2rewrite_d_s,
2432 paramIndex2rewriteD,
2437 nodesWithNewAlpha.add( hrn );
2440 Iterator<ReferenceEdge> edgeItr = hrn.iteratorToReferencers();
2441 while( edgeItr.hasNext() ) {
2442 ReferenceEdge edge = edgeItr.next();
2443 OwnershipNode on = edge.getSrc();
2445 boolean edge_classified = false;
2448 if( on instanceof HeapRegionNode ) {
2449 // hrn0 may be "a_j" and/or "r_j" or even neither
2450 HeapRegionNode hrn0 = (HeapRegionNode) on;
2452 Iterator itr = pi2dr.entrySet().iterator();
2453 while( itr.hasNext() ) {
2454 Map.Entry mo = (Map.Entry) itr.next();
2455 Integer pi = (Integer) mo.getKey();
2456 Set<HeapRegionNode> dr_i = (Set<HeapRegionNode>) mo.getValue();
2458 if( dr_i.contains( hrn0 ) ) {
2459 addEdgeIndexPair( edges_p2p, pi, edge, index );
2460 edge_classified = true;
2464 itr = pi2r.entrySet().iterator();
2465 while( itr.hasNext() ) {
2466 Map.Entry mo = (Map.Entry) itr.next();
2467 Integer pi = (Integer) mo.getKey();
2468 Set<HeapRegionNode> r_i = (Set<HeapRegionNode>) mo.getValue();
2470 if( r_i.contains( hrn0 ) ) {
2471 addEdgeIndexPair( edges_s2p, pi, edge, index );
2472 edge_classified = true;
2477 // all of these edges are upstream of directly reachable objects
2478 if( !edge_classified ) {
2479 addEdgeIndexPair( edges_up_dr, index, edge, index );
2485 Set<HeapRegionNode> r = pi2r.get( index );
2486 hrnItr = r.iterator();
2487 while( hrnItr.hasNext() ) {
2488 // this heap region is definitely an "r_i" or secondary by virtue of being in r
2489 HeapRegionNode hrn = hrnItr.next();
2491 if( paramIndex2rewriteH_s.containsKey( index ) ) {
2493 tokens2states.clear();
2494 tokens2states.put( p_i, new ReachabilitySet().makeCanonical() );
2495 tokens2states.put( s_i, hrn.getAlpha() );
2497 rewriteCallerReachability( index,
2500 paramIndex2rewriteH_s.get( index ),
2502 paramIndex2rewrite_d_p,
2503 paramIndex2rewrite_d_s,
2504 paramIndex2rewriteD,
2509 nodesWithNewAlpha.add( hrn );
2513 Iterator<ReferenceEdge> edgeItr = hrn.iteratorToReferencers();
2514 while( edgeItr.hasNext() ) {
2515 ReferenceEdge edge = edgeItr.next();
2516 OwnershipNode on = edge.getSrc();
2518 boolean edge_classified = false;
2520 if( on instanceof HeapRegionNode ) {
2521 // hrn0 may be "a_j" and/or "r_j" or even neither
2522 HeapRegionNode hrn0 = (HeapRegionNode) on;
2524 Iterator itr = pi2dr.entrySet().iterator();
2525 while( itr.hasNext() ) {
2526 Map.Entry mo = (Map.Entry) itr.next();
2527 Integer pi = (Integer) mo.getKey();
2528 Set<HeapRegionNode> dr_i = (Set<HeapRegionNode>) mo.getValue();
2530 if( dr_i.contains( hrn0 ) ) {
2531 addEdgeIndexPair( edges_p2s, pi, edge, index );
2532 edge_classified = true;
2536 itr = pi2r.entrySet().iterator();
2537 while( itr.hasNext() ) {
2538 Map.Entry mo = (Map.Entry) itr.next();
2539 Integer pi = (Integer) mo.getKey();
2540 Set<HeapRegionNode> r_i = (Set<HeapRegionNode>) mo.getValue();
2542 if( r_i.contains( hrn0 ) ) {
2543 addEdgeIndexPair( edges_s2s, pi, edge, index );
2544 edge_classified = true;
2549 // these edges are all upstream of some reachable node
2550 if( !edge_classified ) {
2551 addEdgeIndexPair( edges_up_r, index, edge, index );
2558 // and again, with respect to some arg i...
2559 lnArgItr = paramIndex2ln.entrySet().iterator();
2560 while( lnArgItr.hasNext() ) {
2561 Map.Entry me = (Map.Entry) lnArgItr.next();
2562 Integer index = (Integer) me.getKey();
2563 LabelNode lnArg_i = (LabelNode) me.getValue();
2566 // update reachable edges
2567 Iterator edgeItr = edges_p2p.get( index ).iterator();
2568 while( edgeItr.hasNext() ) {
2569 Vector mo = (Vector) edgeItr.next();
2570 ReferenceEdge edge = (ReferenceEdge) mo.get( 0 );
2571 Integer indexJ = (Integer) mo.get( 1 );
2573 if( !paramIndex2rewriteJ_p2p.containsKey( makeMapKey( index,
2575 edge.getField() ) ) ) {
2579 TokenTuple p_j = ogCallee.paramIndex2paramTokenPrimary.get( indexJ );
2582 tokens2states.clear();
2583 tokens2states.put( p_j, edge.getBeta() );
2585 rewriteCallerReachability( index,
2588 paramIndex2rewriteJ_p2p.get( makeMapKey( index,
2590 edge.getField() ) ),
2592 paramIndex2rewrite_d_p,
2593 paramIndex2rewrite_d_s,
2594 paramIndex2rewriteD,
2599 edgesWithNewBeta.add( edge );
2603 edgeItr = edges_p2s.get( index ).iterator();
2604 while( edgeItr.hasNext() ) {
2605 Vector mo = (Vector) edgeItr.next();
2606 ReferenceEdge edge = (ReferenceEdge) mo.get( 0 );
2607 Integer indexJ = (Integer) mo.get( 1 );
2609 if( !paramIndex2rewriteJ_p2s.containsKey( makeMapKey( index,
2610 edge.getField() ) ) ) {
2614 TokenTuple s_j = ogCallee.paramIndex2paramTokenSecondary.get( indexJ );
2617 tokens2states.clear();
2618 tokens2states.put( s_j, edge.getBeta() );
2620 rewriteCallerReachability( index,
2623 paramIndex2rewriteJ_p2s.get( makeMapKey( index,
2624 edge.getField() ) ),
2626 paramIndex2rewrite_d_p,
2627 paramIndex2rewrite_d_s,
2628 paramIndex2rewriteD,
2633 edgesWithNewBeta.add( edge );
2637 edgeItr = edges_s2p.get( index ).iterator();
2638 while( edgeItr.hasNext() ) {
2639 Vector mo = (Vector) edgeItr.next();
2640 ReferenceEdge edge = (ReferenceEdge) mo.get( 0 );
2641 Integer indexJ = (Integer) mo.get( 1 );
2643 if( !paramIndex2rewriteJ_s2p.containsKey( index ) ) {
2647 TokenTuple p_j = ogCallee.paramIndex2paramTokenPrimary.get( indexJ );
2650 tokens2states.clear();
2651 tokens2states.put( p_j, edge.getBeta() );
2653 rewriteCallerReachability( index,
2656 paramIndex2rewriteJ_s2p.get( index ),
2658 paramIndex2rewrite_d_p,
2659 paramIndex2rewrite_d_s,
2660 paramIndex2rewriteD,
2665 edgesWithNewBeta.add( edge );
2669 edgeItr = edges_s2s.get( index ).iterator();
2670 while( edgeItr.hasNext() ) {
2671 Vector mo = (Vector) edgeItr.next();
2672 ReferenceEdge edge = (ReferenceEdge) mo.get( 0 );
2673 Integer indexJ = (Integer) mo.get( 1 );
2675 if( !paramIndex2rewriteJ_s2s.containsKey( index ) ) {
2679 TokenTuple s_j = ogCallee.paramIndex2paramTokenSecondary.get( indexJ );
2682 tokens2states.clear();
2683 tokens2states.put( s_j, edge.getBeta() );
2685 rewriteCallerReachability( index,
2688 paramIndex2rewriteJ_s2s.get( index ),
2690 paramIndex2rewrite_d_p,
2691 paramIndex2rewrite_d_s,
2692 paramIndex2rewriteD,
2697 edgesWithNewBeta.add( edge );
2701 // update directly upstream edges
2702 Hashtable<ReferenceEdge, ChangeTupleSet> edgeUpstreamPlannedChanges =
2703 new Hashtable<ReferenceEdge, ChangeTupleSet>();
2705 HashSet<ReferenceEdge> edgesDirectlyUpstream =
2706 new HashSet<ReferenceEdge>();
2708 edgeItr = edges_up_dr.get( index ).iterator();
2709 while( edgeItr.hasNext() ) {
2710 Vector mo = (Vector) edgeItr.next();
2711 ReferenceEdge edge = (ReferenceEdge) mo.get( 0 );
2712 Integer indexJ = (Integer) mo.get( 1 );
2714 edgesDirectlyUpstream.add( edge );
2716 TokenTuple p_j = ogCallee.paramIndex2paramTokenPrimary.get( indexJ );
2719 // start with K_p2 and p_j
2720 tokens2states.clear();
2721 tokens2states.put( p_j, edge.getBeta() );
2723 rewriteCallerReachability( index,
2726 paramIndex2rewriteK_p2.get( index ),
2728 paramIndex2rewrite_d_p,
2729 paramIndex2rewrite_d_s,
2730 paramIndex2rewriteD,
2733 edgeUpstreamPlannedChanges );
2735 // and add in s_j, if required, and do K_p
2736 TokenTuple s_j = ogCallee.paramIndex2paramTokenSecondary.get( indexJ );
2738 tokens2states.put( s_j, edge.getBeta() );
2741 rewriteCallerReachability( index,
2744 paramIndex2rewriteK_p.get( index ),
2746 paramIndex2rewrite_d_p,
2747 paramIndex2rewrite_d_s,
2748 paramIndex2rewriteD,
2751 edgeUpstreamPlannedChanges );
2753 edgesWithNewBeta.add( edge );
2756 propagateTokensOverEdges( edgesDirectlyUpstream,
2757 edgeUpstreamPlannedChanges,
2761 // update upstream edges
2762 edgeUpstreamPlannedChanges =
2763 new Hashtable<ReferenceEdge, ChangeTupleSet>();
2765 HashSet<ReferenceEdge> edgesUpstream =
2766 new HashSet<ReferenceEdge>();
2768 edgeItr = edges_up_r.get( index ).iterator();
2769 while( edgeItr.hasNext() ) {
2770 Vector mo = (Vector) edgeItr.next();
2771 ReferenceEdge edge = (ReferenceEdge) mo.get( 0 );
2772 Integer indexJ = (Integer) mo.get( 1 );
2774 if( !paramIndex2rewriteK_s.containsKey( index ) ) {
2778 edgesUpstream.add( edge );
2780 TokenTuple p_j = ogCallee.paramIndex2paramTokenPrimary.get( indexJ );
2783 TokenTuple s_j = ogCallee.paramIndex2paramTokenSecondary.get( indexJ );
2786 tokens2states.clear();
2787 tokens2states.put( p_j, rsWttsEmpty );
2788 tokens2states.put( s_j, edge.getBeta() );
2790 rewriteCallerReachability( index,
2793 paramIndex2rewriteK_s.get( index ),
2795 paramIndex2rewrite_d_p,
2796 paramIndex2rewrite_d_s,
2797 paramIndex2rewriteD,
2800 edgeUpstreamPlannedChanges );
2802 edgesWithNewBeta.add( edge );
2805 propagateTokensOverEdges( edgesUpstream,
2806 edgeUpstreamPlannedChanges,
2809 } // end effects per argument/parameter map
2812 // commit changes to alpha and beta
2813 Iterator<HeapRegionNode> nodeItr = nodesWithNewAlpha.iterator();
2814 while( nodeItr.hasNext() ) {
2815 nodeItr.next().applyAlphaNew();
2818 Iterator<ReferenceEdge> edgeItr = edgesWithNewBeta.iterator();
2819 while( edgeItr.hasNext() ) {
2820 edgeItr.next().applyBetaNew();
2824 // verify the existence of allocation sites and their
2825 // shadows from the callee in the context of this caller graph
2826 // then map allocated nodes of callee onto the caller shadows
2828 Hashtable<TokenTuple, ReachabilitySet> tokens2statesEmpty = new Hashtable<TokenTuple, ReachabilitySet>();
2830 Iterator<AllocationSite> asItr = ogCallee.allocationSites.iterator();
2831 while( asItr.hasNext() ) {
2832 AllocationSite allocSite = asItr.next();
2834 // grab the summary in the caller just to make sure
2835 // the allocation site has nodes in the caller
2836 HeapRegionNode hrnSummary = getSummaryNode( allocSite );
2838 // assert that the shadow nodes have no reference edges
2839 // because they're brand new to the graph, or last time
2840 // they were used they should have been cleared of edges
2841 HeapRegionNode hrnShadowSummary = getShadowSummaryNode( allocSite );
2842 assert hrnShadowSummary.getNumReferencers() == 0;
2843 assert hrnShadowSummary.getNumReferencees() == 0;
2845 // then bring g_ij onto g'_ij and rewrite
2846 HeapRegionNode hrnSummaryCallee = ogCallee.getSummaryNode( allocSite );
2847 hrnShadowSummary.setAlpha( toShadowTokens( ogCallee, hrnSummaryCallee.getAlpha() ) );
2849 // shadow nodes only are touched by a rewrite one time,
2850 // so rewrite and immediately commit--and they don't belong
2851 // to a particular parameter, so use a bogus param index
2852 // that pulls a self-rewrite out of H
2853 rewriteCallerReachability( bogusIndex,
2856 funcScriptR( hrnShadowSummary.getAlpha(), ogCallee, mc ),
2858 paramIndex2rewrite_d_p,
2859 paramIndex2rewrite_d_s,
2860 paramIndex2rewriteD,
2865 hrnShadowSummary.applyAlphaNew();
2868 for( int i = 0; i < allocSite.getAllocationDepth(); ++i ) {
2869 Integer idIth = allocSite.getIthOldest(i);
2870 assert id2hrn.containsKey(idIth);
2871 HeapRegionNode hrnIth = id2hrn.get(idIth);
2873 Integer idShadowIth = -(allocSite.getIthOldest(i));
2874 assert id2hrn.containsKey(idShadowIth);
2875 HeapRegionNode hrnIthShadow = id2hrn.get(idShadowIth);
2876 assert hrnIthShadow.getNumReferencers() == 0;
2877 assert hrnIthShadow.getNumReferencees() == 0;
2879 assert ogCallee.id2hrn.containsKey(idIth);
2880 HeapRegionNode hrnIthCallee = ogCallee.id2hrn.get(idIth);
2881 hrnIthShadow.setAlpha(toShadowTokens(ogCallee, hrnIthCallee.getAlpha() ) );
2883 rewriteCallerReachability( bogusIndex,
2886 funcScriptR( hrnIthShadow.getAlpha(), ogCallee, mc ),
2888 paramIndex2rewrite_d_p,
2889 paramIndex2rewrite_d_s,
2890 paramIndex2rewriteD,
2895 hrnIthShadow.applyAlphaNew();
2900 // for every heap region->heap region edge in the
2901 // callee graph, create the matching edge or edges
2902 // in the caller graph
2903 Set sCallee = ogCallee.id2hrn.entrySet();
2904 Iterator iCallee = sCallee.iterator();
2906 while( iCallee.hasNext() ) {
2907 Map.Entry meCallee = (Map.Entry) iCallee.next();
2908 Integer idCallee = (Integer) meCallee.getKey();
2909 HeapRegionNode hrnCallee = (HeapRegionNode) meCallee.getValue();
2911 Iterator<ReferenceEdge> heapRegionsItrCallee = hrnCallee.iteratorToReferencees();
2912 while( heapRegionsItrCallee.hasNext() ) {
2913 ReferenceEdge edgeCallee = heapRegionsItrCallee.next();
2914 HeapRegionNode hrnChildCallee = edgeCallee.getDst();
2915 Integer idChildCallee = hrnChildCallee.getID();
2917 // only address this edge if it is not a special initial edge
2918 if( !edgeCallee.isInitialParam() ) {
2920 // now we know that in the callee method's ownership graph
2921 // there is a heap region->heap region reference edge given
2922 // by heap region pointers:
2923 // hrnCallee -> heapChildCallee
2925 // or by the ownership-graph independent ID's:
2926 // idCallee -> idChildCallee
2928 // make the edge with src and dst so beta info is
2929 // calculated once, then copy it for each new edge in caller
2931 ReferenceEdge edgeNewInCallerTemplate = new ReferenceEdge( null,
2933 edgeCallee.getType(),
2934 edgeCallee.getField(),
2936 funcScriptR( toShadowTokens( ogCallee,
2937 edgeCallee.getBeta()
2943 rewriteCallerReachability( bogusIndex,
2945 edgeNewInCallerTemplate,
2946 edgeNewInCallerTemplate.getBeta(),
2948 paramIndex2rewrite_d_p,
2949 paramIndex2rewrite_d_s,
2950 paramIndex2rewriteD,
2955 edgeNewInCallerTemplate.applyBetaNew();
2958 // So now make a set of possible source heaps in the caller graph
2959 // and a set of destination heaps in the caller graph, and make
2960 // a reference edge in the caller for every possible (src,dst) pair
2961 HashSet<HeapRegionNode> possibleCallerSrcs =
2962 getHRNSetThatPossiblyMapToCalleeHRN( ogCallee,
2963 (HeapRegionNode) edgeCallee.getSrc(),
2967 HashSet<HeapRegionNode> possibleCallerDsts =
2968 getHRNSetThatPossiblyMapToCalleeHRN( ogCallee,
2969 edgeCallee.getDst(),
2973 // make every possible pair of {srcSet} -> {dstSet} edges in the caller
2974 Iterator srcItr = possibleCallerSrcs.iterator();
2975 while( srcItr.hasNext() ) {
2976 HeapRegionNode src = (HeapRegionNode) srcItr.next();
2978 if( !hasMatchingField( src, edgeCallee ) ) {
2979 // prune this source node possibility
2983 Iterator dstItr = possibleCallerDsts.iterator();
2984 while( dstItr.hasNext() ) {
2985 HeapRegionNode dst = (HeapRegionNode) dstItr.next();
2987 if( !hasMatchingType( edgeCallee, dst ) ) {
2994 //// KEEP THIS HACK AROUND FOR EXPERIMENTING WITH EDGE REMOVAL
2995 TypeDescriptor tdX = src.getType();
2996 TypeDescriptor tdY = dst.getType();
2997 if( tdX != null && tdY != null ) {
2998 if( tdX.toPrettyString().equals( "Object[]" ) &&
2999 tdY.toPrettyString().equals( "D2" ) ) {
3000 System.out.println( "Skipping an edge from Object[] -> D2 during call mapping" );
3003 if( tdX.toPrettyString().equals( "Object[]" ) &&
3004 tdY.toPrettyString().equals( "MessageList" ) ) {
3005 System.out.println( "Skipping an edge from Object[] -> MessageList during call mapping" );
3012 // otherwise the caller src and dst pair can match the edge, so make it
3013 TypeDescriptor tdNewEdge =
3014 mostSpecificType( edgeCallee.getType(),
3015 hrnChildCallee.getType(),
3019 ReferenceEdge edgeNewInCaller = edgeNewInCallerTemplate.copy();
3020 edgeNewInCaller.setSrc( src );
3021 edgeNewInCaller.setDst( dst );
3022 edgeNewInCaller.setType( tdNewEdge );
3025 // handle taint info if callee created this edge
3027 Set<Integer> pParamSet=idPrimary2paramIndexSet.get(dst.getID());
3028 Set<Integer> sParamSet=idSecondary2paramIndexSet.get(dst.getID());
3029 HashSet<Integer> paramSet=new HashSet<Integer>();
3030 if(pParamSet!=null){
3031 paramSet.addAll(pParamSet);
3033 if(sParamSet!=null){
3034 paramSet.addAll(sParamSet);
3036 Iterator<Integer> paramIter=paramSet.iterator();
3037 int newTaintIdentifier=0;
3038 while(paramIter.hasNext()){
3039 Integer paramIdx=paramIter.next();
3040 edgeNewInCaller.tainedBy(paramIdx);
3043 ReferenceEdge edgeExisting = src.getReferenceTo( dst,
3044 edgeNewInCaller.getType(),
3045 edgeNewInCaller.getField() );
3046 if( edgeExisting == null ) {
3047 // if this edge doesn't exist in the caller, create it
3048 addReferenceEdge( src, dst, edgeNewInCaller );
3051 // if it already exists, merge with it
3052 edgeExisting.setBeta( edgeExisting.getBeta().union( edgeNewInCaller.getBeta() ) );
3062 // return value may need to be assigned in caller
3063 TempDescriptor returnTemp = fc.getReturnTemp();
3064 if( returnTemp != null && !returnTemp.getType().isImmutable() ) {
3066 LabelNode lnLhsCaller = getLabelNodeFromTemp( returnTemp );
3067 clearReferenceEdgesFrom( lnLhsCaller, null, null, true );
3069 LabelNode lnReturnCallee = ogCallee.getLabelNodeFromTemp( tdReturn );
3070 Iterator<ReferenceEdge> edgeCalleeItr = lnReturnCallee.iteratorToReferencees();
3071 while( edgeCalleeItr.hasNext() ) {
3072 ReferenceEdge edgeCallee = edgeCalleeItr.next();
3073 HeapRegionNode hrnChildCallee = edgeCallee.getDst();
3075 // some edge types are not possible return values when we can
3076 // see what type variable we are assigning it to
3077 if( !isSuperiorType( returnTemp.getType(), edgeCallee.getType() ) ) {
3078 System.out.println( "*** NOT EXPECTING TO SEE THIS: Throwing out "+edgeCallee+" for return temp "+returnTemp );
3083 ReferenceEdge edgeNewInCallerTemplate = new ReferenceEdge( null,
3085 edgeCallee.getType(),
3086 edgeCallee.getField(),
3088 funcScriptR( toShadowTokens(ogCallee,
3089 edgeCallee.getBeta() ),
3093 rewriteCallerReachability( bogusIndex,
3095 edgeNewInCallerTemplate,
3096 edgeNewInCallerTemplate.getBeta(),
3098 paramIndex2rewrite_d_p,
3099 paramIndex2rewrite_d_s,
3100 paramIndex2rewriteD,
3105 edgeNewInCallerTemplate.applyBetaNew();
3108 HashSet<HeapRegionNode> assignCallerRhs =
3109 getHRNSetThatPossiblyMapToCalleeHRN( ogCallee,
3110 edgeCallee.getDst(),
3114 Iterator<HeapRegionNode> itrHrn = assignCallerRhs.iterator();
3115 while( itrHrn.hasNext() ) {
3116 HeapRegionNode hrnCaller = itrHrn.next();
3118 // don't make edge in caller if it is disallowed by types
3119 if( !isSuperiorType( returnTemp.getType(), hrnCaller.getType() ) ) {
3124 if( !isSuperiorType( returnTemp.getType(), hrnChildCallee.getType() ) ) {
3129 if( !isSuperiorType( edgeCallee.getType(), hrnCaller.getType() ) ) {
3134 TypeDescriptor tdNewEdge =
3135 mostSpecificType( edgeCallee.getType(),
3136 hrnChildCallee.getType(),
3140 // otherwise caller node can match callee edge, so make it
3141 ReferenceEdge edgeNewInCaller = edgeNewInCallerTemplate.copy();
3142 edgeNewInCaller.setSrc( lnLhsCaller );
3143 edgeNewInCaller.setDst( hrnCaller );
3144 edgeNewInCaller.setType( tdNewEdge );
3146 ReferenceEdge edgeExisting = lnLhsCaller.getReferenceTo( hrnCaller,
3148 edgeNewInCaller.getField() );
3149 if( edgeExisting == null ) {
3151 // if this edge doesn't exist in the caller, create it
3152 addReferenceEdge( lnLhsCaller, hrnCaller, edgeNewInCaller );
3154 // if it already exists, merge with it
3155 edgeExisting.setBeta( edgeExisting.getBeta().union( edgeNewInCaller.getBeta() ) );
3164 mc.getDescriptor().getSymbol().equals( debugCaller ) &&
3165 fm.getMethod().getSymbol().equals( debugCallee )
3169 writeGraph("debug7JustBeforeMergeToKCapacity",
3170 true, // write labels (variables)
3171 true, // selectively hide intermediate temp vars
3172 true, // prune unreachable heap regions
3173 false, // show back edges to confirm graph validity
3174 false, // show parameter indices (unmaintained!)
3175 true, // hide subset reachability states
3176 true); // hide edge taints
3177 } catch( IOException e ) {}
3182 // merge the shadow nodes of allocation sites back down to normal capacity
3183 Iterator<AllocationSite> allocItr = ogCallee.allocationSites.iterator();
3184 while( allocItr.hasNext() ) {
3185 AllocationSite as = allocItr.next();
3187 // first age each allocation site enough times to make room for the shadow nodes
3188 for( int i = 0; i < as.getAllocationDepth(); ++i ) {
3192 // then merge the shadow summary into the normal summary
3193 HeapRegionNode hrnSummary = getSummaryNode( as );
3194 assert hrnSummary != null;
3196 HeapRegionNode hrnSummaryShadow = getShadowSummaryNode( as );
3197 assert hrnSummaryShadow != null;
3199 mergeIntoSummary( hrnSummaryShadow, hrnSummary );
3201 // then clear off after merge
3202 clearReferenceEdgesFrom( hrnSummaryShadow, null, null, true );
3203 clearReferenceEdgesTo ( hrnSummaryShadow, null, null, true );
3204 hrnSummaryShadow.setAlpha( new ReachabilitySet().makeCanonical() );
3206 // then transplant shadow nodes onto the now clean normal nodes
3207 for( int i = 0; i < as.getAllocationDepth(); ++i ) {
3209 Integer idIth = as.getIthOldest( i );
3210 HeapRegionNode hrnIth = id2hrn.get( idIth );
3211 Integer idIthShadow = as.getIthOldestShadow( i );
3212 HeapRegionNode hrnIthShadow = id2hrn.get( idIthShadow );
3214 transferOnto( hrnIthShadow, hrnIth );
3216 // clear off shadow nodes after transfer
3217 clearReferenceEdgesFrom( hrnIthShadow, null, null, true );
3218 clearReferenceEdgesTo ( hrnIthShadow, null, null, true );
3219 hrnIthShadow.setAlpha( new ReachabilitySet().makeCanonical() );
3222 // finally, globally change shadow tokens into normal tokens
3223 Iterator itrAllLabelNodes = td2ln.entrySet().iterator();
3224 while( itrAllLabelNodes.hasNext() ) {
3225 Map.Entry me = (Map.Entry) itrAllLabelNodes.next();
3226 LabelNode ln = (LabelNode) me.getValue();
3228 Iterator<ReferenceEdge> itrEdges = ln.iteratorToReferencees();
3229 while( itrEdges.hasNext() ) {
3230 unshadowTokens( as, itrEdges.next() );
3234 Iterator itrAllHRNodes = id2hrn.entrySet().iterator();
3235 while( itrAllHRNodes.hasNext() ) {
3236 Map.Entry me = (Map.Entry) itrAllHRNodes.next();
3237 HeapRegionNode hrnToAge = (HeapRegionNode) me.getValue();
3239 unshadowTokens( as, hrnToAge );
3241 Iterator<ReferenceEdge> itrEdges = hrnToAge.iteratorToReferencees();
3242 while( itrEdges.hasNext() ) {
3243 unshadowTokens( as, itrEdges.next() );
3251 mc.getDescriptor().getSymbol().equals( debugCaller ) &&
3252 fm.getMethod().getSymbol().equals( debugCallee )
3256 writeGraph( "debug8JustBeforeSweep",
3257 true, // write labels (variables)
3258 true, // selectively hide intermediate temp vars
3259 true, // prune unreachable heap regions
3260 false, // show back edges to confirm graph validity
3261 false, // show parameter indices (unmaintained!)
3262 true, // hide subset reachability states
3263 true); // hide edge taints
3264 } catch( IOException e ) {}
3269 // improve reachability as much as possible
3270 if( !DISABLE_GLOBAL_SWEEP ) {
3276 mc.getDescriptor().getSymbol().equals( debugCaller ) &&
3277 fm.getMethod().getSymbol().equals( debugCallee )
3281 writeGraph( "debug9endResolveCall",
3282 true, // write labels (variables)
3283 true, // selectively hide intermediate temp vars
3284 true, // prune unreachable heap regions
3285 false, // show back edges to confirm graph validity
3286 false, // show parameter indices (unmaintained!)
3287 true, // hide subset reachability states
3288 true); // hide edge taints
3289 } catch( IOException e ) {}
3290 System.out.println( " "+mc+" done calling "+fm );
3292 if( x == debugCallMapCount ) {
3301 protected boolean hasMatchingField(HeapRegionNode src, ReferenceEdge edge) {
3303 // if no type, then it's a match-everything region
3304 TypeDescriptor tdSrc = src.getType();
3305 if( tdSrc == null ) {
3309 if( tdSrc.isArray() ) {
3310 TypeDescriptor td = edge.getType();
3313 TypeDescriptor tdSrcDeref = tdSrc.dereference();
3314 assert tdSrcDeref != null;
3316 if( !typeUtil.isSuperorType( tdSrcDeref, td ) ) {
3320 return edge.getField().equals( OwnershipAnalysis.arrayElementFieldName );
3323 // if it's not a class, it doesn't have any fields to match
3324 if( !tdSrc.isClass() ) {
3328 ClassDescriptor cd = tdSrc.getClassDesc();
3329 while( cd != null ) {
3330 Iterator fieldItr = cd.getFields();
3332 while( fieldItr.hasNext() ) {
3333 FieldDescriptor fd = (FieldDescriptor) fieldItr.next();
3335 if( fd.getType().equals( edge.getType() ) &&
3336 fd.getSymbol().equals( edge.getField() ) ) {
3341 cd = cd.getSuperDesc();
3344 // otherwise it is a class with fields
3345 // but we didn't find a match
3350 protected boolean hasMatchingType(ReferenceEdge edge, HeapRegionNode dst) {
3352 // if the region has no type, matches everything
3353 TypeDescriptor tdDst = dst.getType();
3354 if( tdDst == null ) {
3358 // if the type is not a class or an array, don't
3359 // match because primitives are copied, no aliases
3360 ClassDescriptor cdDst = tdDst.getClassDesc();
3361 if( cdDst == null && !tdDst.isArray() ) {
3365 // if the edge type is null, it matches everything
3366 TypeDescriptor tdEdge = edge.getType();
3367 if( tdEdge == null ) {
3371 return typeUtil.isSuperorType(tdEdge, tdDst);
3375 protected void unshadowTokens(AllocationSite as, ReferenceEdge edge) {
3376 edge.setBeta(edge.getBeta().unshadowTokens(as) );
3379 protected void unshadowTokens(AllocationSite as, HeapRegionNode hrn) {
3380 hrn.setAlpha(hrn.getAlpha().unshadowTokens(as) );
3384 private ReachabilitySet toShadowTokens(OwnershipGraph ogCallee,
3385 ReachabilitySet rsIn) {
3387 ReachabilitySet rsOut = new ReachabilitySet(rsIn).makeCanonical();
3389 Iterator<AllocationSite> allocItr = ogCallee.allocationSites.iterator();
3390 while( allocItr.hasNext() ) {
3391 AllocationSite as = allocItr.next();
3393 rsOut = rsOut.toShadowTokens(as);
3396 return rsOut.makeCanonical();
3400 private void rewriteCallerReachability(Integer paramIndex,
3403 ReachabilitySet rules,
3404 Hashtable<TokenTuple, ReachabilitySet> tokens2states,
3405 Hashtable<Integer, ReachabilitySet> paramIndex2rewrite_d_p,
3406 Hashtable<Integer, ReachabilitySet> paramIndex2rewrite_d_s,
3407 Hashtable<Integer, ReachabilitySet> paramIndex2rewriteD,
3408 OwnershipGraph ogCallee,
3409 boolean makeChangeSet,
3410 Hashtable<ReferenceEdge, ChangeTupleSet> edgePlannedChanges) {
3412 assert(hrn == null && edge != null) ||
3413 (hrn != null && edge == null);
3415 assert rules != null;
3416 assert tokens2states != null;
3418 ReachabilitySet callerReachabilityNew = new ReachabilitySet().makeCanonical();
3420 // for initializing structures in this method
3421 TokenTupleSet ttsEmpty = new TokenTupleSet().makeCanonical();
3423 // use this to construct a change set if required; the idea is to
3424 // map every partially rewritten token tuple set to the set of
3425 // caller-context token tuple sets that were used to generate it
3426 Hashtable<TokenTupleSet, HashSet<TokenTupleSet> > rewritten2source =
3427 new Hashtable<TokenTupleSet, HashSet<TokenTupleSet> >();
3428 rewritten2source.put( ttsEmpty, new HashSet<TokenTupleSet>() );
3431 Iterator<TokenTupleSet> rulesItr = rules.iterator();
3432 while(rulesItr.hasNext()) {
3433 TokenTupleSet rule = rulesItr.next();
3435 ReachabilitySet rewrittenRule = new ReachabilitySet(ttsEmpty).makeCanonical();
3437 Iterator<TokenTuple> ruleItr = rule.iterator();
3438 while(ruleItr.hasNext()) {
3439 TokenTuple ttCallee = ruleItr.next();
3441 // compute the possibilities for rewriting this callee token
3442 ReachabilitySet ttCalleeRewrites = null;
3443 boolean callerSourceUsed = false;
3445 if( tokens2states.containsKey( ttCallee ) ) {
3446 callerSourceUsed = true;
3447 ttCalleeRewrites = tokens2states.get( ttCallee );
3448 assert ttCalleeRewrites != null;
3450 } else if( ogCallee.paramTokenPrimary2paramIndex.containsKey( ttCallee ) ) {
3452 Integer paramIndex_j = ogCallee.paramTokenPrimary2paramIndex.get( ttCallee );
3453 assert paramIndex_j != null;
3454 ttCalleeRewrites = paramIndex2rewrite_d_p.get( paramIndex_j );
3455 assert ttCalleeRewrites != null;
3457 } else if( ogCallee.paramTokenSecondary2paramIndex.containsKey( ttCallee ) ) {
3459 Integer paramIndex_j = ogCallee.paramTokenSecondary2paramIndex.get( ttCallee );
3460 assert paramIndex_j != null;
3461 ttCalleeRewrites = paramIndex2rewrite_d_s.get( paramIndex_j );
3462 assert ttCalleeRewrites != null;
3464 } else if( ogCallee.paramTokenSecondaryPlus2paramIndex.containsKey( ttCallee ) ) {
3466 Integer paramIndex_j = ogCallee.paramTokenSecondaryPlus2paramIndex.get( ttCallee );
3467 assert paramIndex_j != null;
3468 ttCalleeRewrites = paramIndex2rewriteD.get( paramIndex_j );
3469 assert ttCalleeRewrites != null;
3471 } else if( ogCallee.paramTokenSecondaryStar2paramIndex.containsKey( ttCallee ) ) {
3473 Integer paramIndex_j = ogCallee.paramTokenSecondaryStar2paramIndex.get( ttCallee );
3474 assert paramIndex_j != null;
3475 ttCalleeRewrites = paramIndex2rewriteD.get( paramIndex_j );
3476 assert ttCalleeRewrites != null;
3479 // otherwise there's no need for a rewrite, just pass this one on
3480 TokenTupleSet ttsCaller = new TokenTupleSet( ttCallee ).makeCanonical();
3481 ttCalleeRewrites = new ReachabilitySet( ttsCaller ).makeCanonical();
3484 // branch every version of the working rewritten rule with
3485 // the possibilities for rewriting the current callee token
3486 ReachabilitySet rewrittenRuleWithTTCallee = new ReachabilitySet().makeCanonical();
3488 Iterator<TokenTupleSet> rewrittenRuleItr = rewrittenRule.iterator();
3489 while( rewrittenRuleItr.hasNext() ) {
3490 TokenTupleSet ttsRewritten = rewrittenRuleItr.next();
3492 Iterator<TokenTupleSet> ttCalleeRewritesItr = ttCalleeRewrites.iterator();
3493 while( ttCalleeRewritesItr.hasNext() ) {
3494 TokenTupleSet ttsBranch = ttCalleeRewritesItr.next();
3496 TokenTupleSet ttsRewrittenNext = ttsRewritten.unionUpArity( ttsBranch );
3498 if( makeChangeSet ) {
3499 // in order to keep the list of source token tuple sets
3500 // start with the sets used to make the partially rewritten
3501 // rule up to this point
3502 HashSet<TokenTupleSet> sourceSets = rewritten2source.get( ttsRewritten );
3503 assert sourceSets != null;
3505 // make a shallow copy for possible modification
3506 sourceSets = (HashSet<TokenTupleSet>) sourceSets.clone();
3508 // if we used something from the caller to rewrite it, remember
3509 if( callerSourceUsed ) {
3510 sourceSets.add( ttsBranch );
3513 // set mapping for the further rewritten rule
3514 rewritten2source.put( ttsRewrittenNext, sourceSets );
3517 rewrittenRuleWithTTCallee =
3518 rewrittenRuleWithTTCallee.union( ttsRewrittenNext );
3522 // now the rewritten rule's possibilities have been extended by
3523 // rewriting the current callee token, remember result
3524 rewrittenRule = rewrittenRuleWithTTCallee;
3527 // the rule has been entirely rewritten into the caller context
3528 // now, so add it to the new reachability information
3529 callerReachabilityNew =
3530 callerReachabilityNew.union( rewrittenRule );
3533 if( makeChangeSet ) {
3534 ChangeTupleSet callerChangeSet = new ChangeTupleSet().makeCanonical();
3536 // each possibility for the final reachability should have a set of
3537 // caller sources mapped to it, use to create the change set
3538 Iterator<TokenTupleSet> callerReachabilityItr = callerReachabilityNew.iterator();
3539 while( callerReachabilityItr.hasNext() ) {
3540 TokenTupleSet ttsRewrittenFinal = callerReachabilityItr.next();
3541 HashSet<TokenTupleSet> sourceSets = rewritten2source.get( ttsRewrittenFinal );
3542 assert sourceSets != null;
3544 Iterator<TokenTupleSet> sourceSetsItr = sourceSets.iterator();
3545 while( sourceSetsItr.hasNext() ) {
3546 TokenTupleSet ttsSource = sourceSetsItr.next();
3549 callerChangeSet.union( new ChangeTuple( ttsSource, ttsRewrittenFinal ) );
3553 assert edgePlannedChanges != null;
3554 edgePlannedChanges.put( edge, callerChangeSet );
3558 edge.setBetaNew( edge.getBetaNew().union( callerReachabilityNew ) );
3560 hrn.setAlphaNew( hrn.getAlphaNew().union( callerReachabilityNew ) );
3566 private HashSet<HeapRegionNode>
3567 getHRNSetThatPossiblyMapToCalleeHRN( OwnershipGraph ogCallee,
3568 HeapRegionNode hrnCallee,
3569 Hashtable<Integer, Set<HeapRegionNode> > pi2dr,
3570 Hashtable<Integer, Set<HeapRegionNode> > pi2r
3573 HashSet<HeapRegionNode> possibleCallerHRNs = new HashSet<HeapRegionNode>();
3575 Set<Integer> paramIndicesCallee_p = ogCallee.idPrimary2paramIndexSet .get( hrnCallee.getID() );
3576 Set<Integer> paramIndicesCallee_s = ogCallee.idSecondary2paramIndexSet.get( hrnCallee.getID() );
3578 if( paramIndicesCallee_p == null &&
3579 paramIndicesCallee_s == null ) {
3580 // this is a node allocated in the callee and it has
3581 // exactly one shadow node in the caller to map to
3582 AllocationSite as = hrnCallee.getAllocationSite();
3585 int age = as.getAgeCategory( hrnCallee.getID() );
3586 assert age != AllocationSite.AGE_notInThisSite;
3589 if( age == AllocationSite.AGE_summary ) {
3590 idCaller = as.getSummaryShadow();
3592 } else if( age == AllocationSite.AGE_oldest ) {
3593 idCaller = as.getOldestShadow();
3596 assert age == AllocationSite.AGE_in_I;
3598 Integer I = as.getAge( hrnCallee.getID() );
3601 idCaller = as.getIthOldestShadow( I );
3604 assert id2hrn.containsKey( idCaller );
3605 possibleCallerHRNs.add( id2hrn.get( idCaller ) );
3607 return possibleCallerHRNs;
3610 // find out what primary objects this might be
3611 if( paramIndicesCallee_p != null ) {
3612 // this is a node that was created to represent a parameter
3613 // so it maps to some regions directly reachable from the arg labels
3614 Iterator<Integer> itrIndex = paramIndicesCallee_p.iterator();
3615 while( itrIndex.hasNext() ) {
3616 Integer paramIndexCallee = itrIndex.next();
3617 assert pi2dr.containsKey( paramIndexCallee );
3618 possibleCallerHRNs.addAll( pi2dr.get( paramIndexCallee ) );
3622 // find out what secondary objects this might be
3623 if( paramIndicesCallee_s != null ) {
3624 // this is a node that was created to represent objs reachable from
3625 // some parameter, so it maps to regions reachable from the arg labels
3626 Iterator<Integer> itrIndex = paramIndicesCallee_s.iterator();
3627 while( itrIndex.hasNext() ) {
3628 Integer paramIndexCallee = itrIndex.next();
3629 assert pi2r.containsKey( paramIndexCallee );
3630 possibleCallerHRNs.addAll( pi2r.get( paramIndexCallee ) );
3634 // TODO: is this true?
3635 // one of the two cases above should have put something in here
3636 //assert !possibleCallerHRNs.isEmpty();
3638 return possibleCallerHRNs;
3643 ////////////////////////////////////////////////////
3645 // This global sweep is an optional step to prune
3646 // reachability sets that are not internally
3647 // consistent with the global graph. It should be
3648 // invoked after strong updates or method calls.
3650 ////////////////////////////////////////////////////
3651 public void globalSweep() {
3653 // boldB is part of the phase 1 sweep
3654 Hashtable< Integer, Hashtable<ReferenceEdge, ReachabilitySet> > boldB =
3655 new Hashtable< Integer, Hashtable<ReferenceEdge, ReachabilitySet> >();
3657 // visit every heap region to initialize alphaNew and calculate boldB
3658 Set hrns = id2hrn.entrySet();
3659 Iterator itrHrns = hrns.iterator();
3660 while( itrHrns.hasNext() ) {
3661 Map.Entry me = (Map.Entry)itrHrns.next();
3662 Integer token = (Integer) me.getKey();
3663 HeapRegionNode hrn = (HeapRegionNode) me.getValue();
3665 // assert that this node and incoming edges have clean alphaNew
3666 // and betaNew sets, respectively
3667 assert rsEmpty.equals( hrn.getAlphaNew() );
3669 Iterator<ReferenceEdge> itrRers = hrn.iteratorToReferencers();
3670 while( itrRers.hasNext() ) {
3671 ReferenceEdge edge = itrRers.next();
3672 assert rsEmpty.equals( edge.getBetaNew() );
3675 // calculate boldB for this flagged node
3676 if( hrn.isFlagged() || hrn.isParameter() ) {
3678 Hashtable<ReferenceEdge, ReachabilitySet> boldB_f =
3679 new Hashtable<ReferenceEdge, ReachabilitySet>();
3681 Set<ReferenceEdge> workSetEdges = new HashSet<ReferenceEdge>();
3683 // initial boldB_f constraints
3684 Iterator<ReferenceEdge> itrRees = hrn.iteratorToReferencees();
3685 while( itrRees.hasNext() ) {
3686 ReferenceEdge edge = itrRees.next();
3688 assert !boldB.containsKey( edge );
3689 boldB_f.put( edge, edge.getBeta() );
3691 assert !workSetEdges.contains( edge );
3692 workSetEdges.add( edge );
3695 // enforce the boldB_f constraint at edges until we reach a fixed point
3696 while( !workSetEdges.isEmpty() ) {
3697 ReferenceEdge edge = workSetEdges.iterator().next();
3698 workSetEdges.remove( edge );
3700 Iterator<ReferenceEdge> itrPrime = edge.getDst().iteratorToReferencees();
3701 while( itrPrime.hasNext() ) {
3702 ReferenceEdge edgePrime = itrPrime.next();
3704 ReachabilitySet prevResult = boldB_f.get( edgePrime );
3705 ReachabilitySet intersection = boldB_f.get( edge ).intersection( edgePrime.getBeta() );
3707 if( prevResult == null ||
3708 prevResult.union( intersection ).size() > prevResult.size() ) {
3710 if( prevResult == null ) {
3711 boldB_f.put( edgePrime, edgePrime.getBeta().union( intersection ) );
3713 boldB_f.put( edgePrime, prevResult .union( intersection ) );
3715 workSetEdges.add( edgePrime );
3720 boldB.put( token, boldB_f );
3725 // use boldB to prune tokens from alpha states that are impossible
3726 // and propagate the differences backwards across edges
3727 HashSet<ReferenceEdge> edgesForPropagation = new HashSet<ReferenceEdge>();
3729 Hashtable<ReferenceEdge, ChangeTupleSet> edgePlannedChanges =
3730 new Hashtable<ReferenceEdge, ChangeTupleSet>();
3732 hrns = id2hrn.entrySet();
3733 itrHrns = hrns.iterator();
3734 while( itrHrns.hasNext() ) {
3735 Map.Entry me = (Map.Entry)itrHrns.next();
3736 Integer token = (Integer) me.getKey();
3737 HeapRegionNode hrn = (HeapRegionNode) me.getValue();
3739 // never remove the identity token from a flagged region
3740 // because it is trivially satisfied
3741 TokenTuple ttException = new TokenTuple( token,
3742 !hrn.isSingleObject(),
3743 TokenTuple.ARITY_ONE ).makeCanonical();
3745 ChangeTupleSet cts = new ChangeTupleSet().makeCanonical();
3747 // mark tokens for removal
3748 Iterator<TokenTupleSet> stateItr = hrn.getAlpha().iterator();
3749 while( stateItr.hasNext() ) {
3750 TokenTupleSet ttsOld = stateItr.next();
3752 TokenTupleSet markedTokens = new TokenTupleSet().makeCanonical();
3754 Iterator<TokenTuple> ttItr = ttsOld.iterator();
3755 while( ttItr.hasNext() ) {
3756 TokenTuple ttOld = ttItr.next();
3758 // never remove the identity token from a flagged region
3759 // because it is trivially satisfied
3760 if( hrn.isFlagged() || hrn.isParameter() ) {
3761 if( ttOld == ttException ) {
3766 // does boldB_ttOld allow this token?
3767 boolean foundState = false;
3768 Iterator<ReferenceEdge> incidentEdgeItr = hrn.iteratorToReferencers();
3769 while( incidentEdgeItr.hasNext() ) {
3770 ReferenceEdge incidentEdge = incidentEdgeItr.next();
3772 // if it isn't allowed, mark for removal
3773 Integer idOld = ttOld.getToken();
3774 assert id2hrn.containsKey( idOld );
3775 Hashtable<ReferenceEdge, ReachabilitySet> B = boldB.get( idOld );
3776 ReachabilitySet boldB_ttOld_incident = B.get( incidentEdge );// B is NULL!
3777 if( boldB_ttOld_incident != null &&
3778 boldB_ttOld_incident.contains( ttsOld ) ) {
3784 markedTokens = markedTokens.add( ttOld );
3788 // if there is nothing marked, just move on
3789 if( markedTokens.isEmpty() ) {
3790 hrn.setAlphaNew( hrn.getAlphaNew().union( ttsOld ) );
3794 // remove all marked tokens and establish a change set that should
3795 // propagate backwards over edges from this node
3796 TokenTupleSet ttsPruned = new TokenTupleSet().makeCanonical();
3797 ttItr = ttsOld.iterator();
3798 while( ttItr.hasNext() ) {
3799 TokenTuple ttOld = ttItr.next();
3801 if( !markedTokens.containsTuple( ttOld ) ) {
3802 ttsPruned = ttsPruned.union( ttOld );
3805 assert !ttsOld.equals( ttsPruned );
3807 hrn.setAlphaNew( hrn.getAlphaNew().union( ttsPruned ) );
3808 ChangeTuple ct = new ChangeTuple( ttsOld, ttsPruned ).makeCanonical();
3809 cts = cts.union( ct );
3812 // throw change tuple set on all incident edges
3813 if( !cts.isEmpty() ) {
3814 Iterator<ReferenceEdge> incidentEdgeItr = hrn.iteratorToReferencers();
3815 while( incidentEdgeItr.hasNext() ) {
3816 ReferenceEdge incidentEdge = incidentEdgeItr.next();
3818 edgesForPropagation.add( incidentEdge );
3820 if( edgePlannedChanges.get( incidentEdge ) == null ) {
3821 edgePlannedChanges.put( incidentEdge, cts );
3823 edgePlannedChanges.put(
3825 edgePlannedChanges.get( incidentEdge ).union( cts )
3832 HashSet<ReferenceEdge> edgesUpdated = new HashSet<ReferenceEdge>();
3834 propagateTokensOverEdges( edgesForPropagation,
3838 // at the end of the 1st phase reference edges have
3839 // beta, betaNew that correspond to beta and betaR
3841 // commit beta<-betaNew, so beta=betaR and betaNew
3842 // will represent the beta' calculation in 2nd phase
3844 // commit alpha<-alphaNew because it won't change
3845 HashSet<ReferenceEdge> res = new HashSet<ReferenceEdge>();
3847 Iterator<HeapRegionNode> nodeItr = id2hrn.values().iterator();
3848 while( nodeItr.hasNext() ) {
3849 HeapRegionNode hrn = nodeItr.next();
3850 hrn.applyAlphaNew();
3851 Iterator<ReferenceEdge> itrRes = hrn.iteratorToReferencers();
3852 while( itrRes.hasNext() ) {
3853 res.add( itrRes.next() );
3859 Iterator<ReferenceEdge> edgeItr = res.iterator();
3860 while( edgeItr.hasNext() ) {
3861 ReferenceEdge edge = edgeItr.next();
3862 HeapRegionNode hrn = edge.getDst();
3864 // commit results of last phase
3865 if( edgesUpdated.contains( edge ) ) {
3866 edge.applyBetaNew();
3869 // compute intial condition of 2nd phase
3870 edge.setBetaNew( edge.getBeta().intersection( hrn.getAlpha() ) );
3873 // every edge in the graph is the initial workset
3874 Set<ReferenceEdge> edgeWorkSet = (Set) res.clone();
3875 while( !edgeWorkSet.isEmpty() ) {
3876 ReferenceEdge edgePrime = edgeWorkSet.iterator().next();
3877 edgeWorkSet.remove( edgePrime );
3879 OwnershipNode on = edgePrime.getSrc();
3880 if( !(on instanceof HeapRegionNode) ) {
3883 HeapRegionNode hrn = (HeapRegionNode) on;
3885 Iterator<ReferenceEdge> itrEdge = hrn.iteratorToReferencers();
3886 while( itrEdge.hasNext() ) {
3887 ReferenceEdge edge = itrEdge.next();
3889 ReachabilitySet prevResult = edge.getBetaNew();
3890 assert prevResult != null;
3892 ReachabilitySet intersection = edge.getBeta().intersection( edgePrime.getBetaNew() );
3894 if( prevResult.union( intersection ).size() > prevResult.size() ) {
3895 edge.setBetaNew( prevResult.union( intersection ) );
3896 edgeWorkSet.add( edge );
3901 // commit beta' (beta<-betaNew)
3902 edgeItr = res.iterator();
3903 while( edgeItr.hasNext() ) {
3904 edgeItr.next().applyBetaNew();
3910 ////////////////////////////////////////////////////
3911 // in merge() and equals() methods the suffix A
3912 // represents the passed in graph and the suffix
3913 // B refers to the graph in this object
3914 // Merging means to take the incoming graph A and
3915 // merge it into B, so after the operation graph B
3916 // is the final result.
3917 ////////////////////////////////////////////////////
3918 public void merge(OwnershipGraph og) {
3924 mergeOwnershipNodes(og);
3925 mergeReferenceEdges(og);
3926 mergeParamIndexMappings(og);
3927 mergeAllocationSites(og);
3928 mergeAccessPaths(og);
3929 mergeTempAndLabelCategories(og);
3933 protected void mergeOwnershipNodes(OwnershipGraph og) {
3934 Set sA = og.id2hrn.entrySet();
3935 Iterator iA = sA.iterator();
3936 while( iA.hasNext() ) {
3937 Map.Entry meA = (Map.Entry)iA.next();
3938 Integer idA = (Integer) meA.getKey();
3939 HeapRegionNode hrnA = (HeapRegionNode) meA.getValue();
3941 // if this graph doesn't have a node the
3942 // incoming graph has, allocate it
3943 if( !id2hrn.containsKey(idA) ) {
3944 HeapRegionNode hrnB = hrnA.copy();
3945 id2hrn.put(idA, hrnB);
3946 gid2hrn.put(hrnA.getGloballyUniqueIdentifier(), hrnB);
3949 // otherwise this is a node present in both graphs
3950 // so make the new reachability set a union of the
3951 // nodes' reachability sets
3952 HeapRegionNode hrnB = id2hrn.get(idA);
3953 hrnB.setAlpha(hrnB.getAlpha().union(hrnA.getAlpha() ) );
3957 // now add any label nodes that are in graph B but
3959 sA = og.td2ln.entrySet();
3961 while( iA.hasNext() ) {
3962 Map.Entry meA = (Map.Entry)iA.next();
3963 TempDescriptor tdA = (TempDescriptor) meA.getKey();
3964 LabelNode lnA = (LabelNode) meA.getValue();
3966 // if the label doesn't exist in B, allocate and add it
3967 LabelNode lnB = getLabelNodeFromTemp(tdA);
3971 protected void mergeReferenceEdges(OwnershipGraph og) {
3974 Set sA = og.id2hrn.entrySet();
3975 Iterator iA = sA.iterator();
3976 while( iA.hasNext() ) {
3977 Map.Entry meA = (Map.Entry)iA.next();
3978 Integer idA = (Integer) meA.getKey();
3979 HeapRegionNode hrnA = (HeapRegionNode) meA.getValue();
3981 Iterator<ReferenceEdge> heapRegionsItrA = hrnA.iteratorToReferencees();
3982 while( heapRegionsItrA.hasNext() ) {
3983 ReferenceEdge edgeA = heapRegionsItrA.next();
3984 HeapRegionNode hrnChildA = edgeA.getDst();
3985 Integer idChildA = hrnChildA.getID();
3987 // at this point we know an edge in graph A exists
3988 // idA -> idChildA, does this exist in B?
3989 assert id2hrn.containsKey(idA);
3990 HeapRegionNode hrnB = id2hrn.get(idA);
3991 ReferenceEdge edgeToMerge = null;
3993 Iterator<ReferenceEdge> heapRegionsItrB = hrnB.iteratorToReferencees();
3994 while( heapRegionsItrB.hasNext() &&
3995 edgeToMerge == null ) {
3997 ReferenceEdge edgeB = heapRegionsItrB.next();
3998 HeapRegionNode hrnChildB = edgeB.getDst();
3999 Integer idChildB = hrnChildB.getID();
4001 // don't use the ReferenceEdge.equals() here because
4002 // we're talking about existence between graphs
4003 if( idChildB.equals( idChildA ) &&
4004 edgeB.typeAndFieldEquals( edgeA ) ) {
4006 edgeToMerge = edgeB;
4010 // if the edge from A was not found in B,
4012 if( edgeToMerge == null ) {
4013 assert id2hrn.containsKey(idChildA);
4014 HeapRegionNode hrnChildB = id2hrn.get(idChildA);
4015 edgeToMerge = edgeA.copy();
4016 edgeToMerge.setSrc(hrnB);
4017 edgeToMerge.setDst(hrnChildB);
4018 addReferenceEdge(hrnB, hrnChildB, edgeToMerge);
4020 // otherwise, the edge already existed in both graphs
4021 // so merge their reachability sets
4023 // just replace this beta set with the union
4024 assert edgeToMerge != null;
4025 edgeToMerge.setBeta(
4026 edgeToMerge.getBeta().union(edgeA.getBeta() )
4029 edgeToMerge.unionTaintIdentifier(edgeA.getTaintIdentifier());
4030 if( !edgeA.isInitialParam() ) {
4031 edgeToMerge.setIsInitialParam(false);
4037 // and then again with label nodes
4038 sA = og.td2ln.entrySet();
4040 while( iA.hasNext() ) {
4041 Map.Entry meA = (Map.Entry)iA.next();
4042 TempDescriptor tdA = (TempDescriptor) meA.getKey();
4043 LabelNode lnA = (LabelNode) meA.getValue();
4045 Iterator<ReferenceEdge> heapRegionsItrA = lnA.iteratorToReferencees();
4046 while( heapRegionsItrA.hasNext() ) {
4047 ReferenceEdge edgeA = heapRegionsItrA.next();
4048 HeapRegionNode hrnChildA = edgeA.getDst();
4049 Integer idChildA = hrnChildA.getID();
4051 // at this point we know an edge in graph A exists
4052 // tdA -> idChildA, does this exist in B?
4053 assert td2ln.containsKey(tdA);
4054 LabelNode lnB = td2ln.get(tdA);
4055 ReferenceEdge edgeToMerge = null;
4057 Iterator<ReferenceEdge> heapRegionsItrB = lnB.iteratorToReferencees();
4058 while( heapRegionsItrB.hasNext() &&
4059 edgeToMerge == null ) {
4061 ReferenceEdge edgeB = heapRegionsItrB.next();
4062 HeapRegionNode hrnChildB = edgeB.getDst();
4063 Integer idChildB = hrnChildB.getID();
4065 // don't use the ReferenceEdge.equals() here because
4066 // we're talking about existence between graphs
4067 if( idChildB.equals( idChildA ) &&
4068 edgeB.typeAndFieldEquals( edgeA ) ) {
4070 edgeToMerge = edgeB;
4074 // if the edge from A was not found in B,
4076 if( edgeToMerge == null ) {
4077 assert id2hrn.containsKey(idChildA);
4078 HeapRegionNode hrnChildB = id2hrn.get(idChildA);
4079 edgeToMerge = edgeA.copy();
4080 edgeToMerge.setSrc(lnB);
4081 edgeToMerge.setDst(hrnChildB);
4082 addReferenceEdge(lnB, hrnChildB, edgeToMerge);
4084 // otherwise, the edge already existed in both graphs
4085 // so merge their reachability sets
4087 // just replace this beta set with the union
4088 edgeToMerge.setBeta(
4089 edgeToMerge.getBeta().union(edgeA.getBeta() )
4091 edgeToMerge.unionTaintIdentifier(edgeA.getTaintIdentifier());
4092 if( !edgeA.isInitialParam() ) {
4093 edgeToMerge.setIsInitialParam(false);
4100 // you should only merge ownership graphs that have the
4101 // same number of parameters, or if one or both parameter
4102 // index tables are empty
4103 protected void mergeParamIndexMappings(OwnershipGraph og) {
4105 if( idPrimary2paramIndexSet.size() == 0 ) {
4107 idPrimary2paramIndexSet = og.idPrimary2paramIndexSet;
4108 paramIndex2idPrimary = og.paramIndex2idPrimary;
4110 idSecondary2paramIndexSet = og.idSecondary2paramIndexSet;
4111 paramIndex2idSecondary = og.paramIndex2idSecondary;
4113 paramIndex2tdQ = og.paramIndex2tdQ;
4114 paramIndex2tdR = og.paramIndex2tdR;
4116 paramTokenPrimary2paramIndex = og.paramTokenPrimary2paramIndex;
4117 paramIndex2paramTokenPrimary = og.paramIndex2paramTokenPrimary;
4119 paramTokenSecondary2paramIndex = og.paramTokenSecondary2paramIndex;
4120 paramIndex2paramTokenSecondary = og.paramIndex2paramTokenSecondary;
4121 paramTokenSecondaryPlus2paramIndex = og.paramTokenSecondaryPlus2paramIndex;
4122 paramIndex2paramTokenSecondaryPlus = og.paramIndex2paramTokenSecondaryPlus;
4123 paramTokenSecondaryStar2paramIndex = og.paramTokenSecondaryStar2paramIndex;
4124 paramIndex2paramTokenSecondaryStar = og.paramIndex2paramTokenSecondaryStar;
4129 if( og.idPrimary2paramIndexSet.size() == 0 ) {
4131 og.idPrimary2paramIndexSet = idPrimary2paramIndexSet;
4132 og.paramIndex2idPrimary = paramIndex2idPrimary;
4134 og.idSecondary2paramIndexSet = idSecondary2paramIndexSet;
4135 og.paramIndex2idSecondary = paramIndex2idSecondary;
4137 og.paramIndex2tdQ = paramIndex2tdQ;
4138 og.paramIndex2tdR = paramIndex2tdR;
4140 og.paramTokenPrimary2paramIndex = paramTokenPrimary2paramIndex;
4141 og.paramIndex2paramTokenPrimary = paramIndex2paramTokenPrimary;
4143 og.paramTokenSecondary2paramIndex = paramTokenSecondary2paramIndex;
4144 og.paramIndex2paramTokenSecondary = paramIndex2paramTokenSecondary;
4145 og.paramTokenSecondaryPlus2paramIndex = paramTokenSecondaryPlus2paramIndex;
4146 og.paramIndex2paramTokenSecondaryPlus = paramIndex2paramTokenSecondaryPlus;
4147 og.paramTokenSecondaryStar2paramIndex = paramTokenSecondaryStar2paramIndex;
4148 og.paramIndex2paramTokenSecondaryStar = paramIndex2paramTokenSecondaryStar;
4153 assert idPrimary2paramIndexSet.size() == og.idPrimary2paramIndexSet.size();
4154 assert idSecondary2paramIndexSet.size() == og.idSecondary2paramIndexSet.size();
4157 protected void mergeAllocationSites(OwnershipGraph og) {
4158 allocationSites.addAll(og.allocationSites);
4161 protected void mergeAccessPaths(OwnershipGraph og) {
4162 UtilAlgorithms.mergeHashtablesWithHashSetValues(temp2accessPaths,
4163 og.temp2accessPaths);
4166 protected void mergeTempAndLabelCategories(OwnershipGraph og) {
4167 outOfScopeTemps.addAll(og.outOfScopeTemps);
4168 outOfScopeLabels.addAll(og.outOfScopeLabels);
4169 parameterTemps.addAll(og.parameterTemps);
4170 parameterLabels.addAll(og.parameterLabels);
4175 // it is necessary in the equals() member functions
4176 // to "check both ways" when comparing the data
4177 // structures of two graphs. For instance, if all
4178 // edges between heap region nodes in graph A are
4179 // present and equal in graph B it is not sufficient
4180 // to say the graphs are equal. Consider that there
4181 // may be edges in graph B that are not in graph A.
4182 // the only way to know that all edges in both graphs
4183 // are equally present is to iterate over both data
4184 // structures and compare against the other graph.
4185 public boolean equals(OwnershipGraph og) {
4191 if( !areHeapRegionNodesEqual(og) ) {
4195 if( !areLabelNodesEqual(og) ) {
4199 if( !areReferenceEdgesEqual(og) ) {
4203 if( !areParamIndexMappingsEqual(og) ) {
4207 if( !areAccessPathsEqual(og) ) {
4211 // if everything is equal up to this point,
4212 // assert that allocationSites is also equal--
4213 // this data is redundant and kept for efficiency
4214 assert allocationSites .equals(og.allocationSites );
4215 assert outOfScopeTemps .equals(og.outOfScopeTemps );
4216 assert outOfScopeLabels.equals(og.outOfScopeLabels);
4217 assert parameterTemps .equals(og.parameterTemps );
4218 assert parameterLabels .equals(og.parameterLabels );
4223 protected boolean areHeapRegionNodesEqual(OwnershipGraph og) {
4225 if( !areallHRNinAalsoinBandequal(this, og) ) {
4229 if( !areallHRNinAalsoinBandequal(og, this) ) {
4236 static protected boolean areallHRNinAalsoinBandequal(OwnershipGraph ogA,
4237 OwnershipGraph ogB) {
4238 Set sA = ogA.id2hrn.entrySet();
4239 Iterator iA = sA.iterator();
4240 while( iA.hasNext() ) {
4241 Map.Entry meA = (Map.Entry)iA.next();
4242 Integer idA = (Integer) meA.getKey();
4243 HeapRegionNode hrnA = (HeapRegionNode) meA.getValue();
4245 if( !ogB.id2hrn.containsKey(idA) ) {
4249 HeapRegionNode hrnB = ogB.id2hrn.get(idA);
4250 if( !hrnA.equalsIncludingAlpha(hrnB) ) {
4259 protected boolean areLabelNodesEqual(OwnershipGraph og) {
4261 if( !areallLNinAalsoinBandequal(this, og) ) {
4265 if( !areallLNinAalsoinBandequal(og, this) ) {
4272 static protected boolean areallLNinAalsoinBandequal(OwnershipGraph ogA,
4273 OwnershipGraph ogB) {
4274 Set sA = ogA.td2ln.entrySet();
4275 Iterator iA = sA.iterator();
4276 while( iA.hasNext() ) {
4277 Map.Entry meA = (Map.Entry)iA.next();
4278 TempDescriptor tdA = (TempDescriptor) meA.getKey();
4280 if( !ogB.td2ln.containsKey(tdA) ) {
4289 protected boolean areReferenceEdgesEqual(OwnershipGraph og) {
4290 if( !areallREinAandBequal(this, og) ) {
4297 static protected boolean areallREinAandBequal(OwnershipGraph ogA,
4298 OwnershipGraph ogB) {
4300 // check all the heap region->heap region edges
4301 Set sA = ogA.id2hrn.entrySet();
4302 Iterator iA = sA.iterator();
4303 while( iA.hasNext() ) {
4304 Map.Entry meA = (Map.Entry)iA.next();
4305 Integer idA = (Integer) meA.getKey();
4306 HeapRegionNode hrnA = (HeapRegionNode) meA.getValue();
4308 // we should have already checked that the same
4309 // heap regions exist in both graphs
4310 assert ogB.id2hrn.containsKey(idA);
4312 if( !areallREfromAequaltoB(ogA, hrnA, ogB) ) {
4316 // then check every edge in B for presence in A, starting
4317 // from the same parent HeapRegionNode
4318 HeapRegionNode hrnB = ogB.id2hrn.get(idA);
4320 if( !areallREfromAequaltoB(ogB, hrnB, ogA) ) {
4325 // then check all the label->heap region edges
4326 sA = ogA.td2ln.entrySet();
4328 while( iA.hasNext() ) {
4329 Map.Entry meA = (Map.Entry)iA.next();
4330 TempDescriptor tdA = (TempDescriptor) meA.getKey();
4331 LabelNode lnA = (LabelNode) meA.getValue();
4333 // we should have already checked that the same
4334 // label nodes exist in both graphs
4335 assert ogB.td2ln.containsKey(tdA);
4337 if( !areallREfromAequaltoB(ogA, lnA, ogB) ) {
4341 // then check every edge in B for presence in A, starting
4342 // from the same parent LabelNode
4343 LabelNode lnB = ogB.td2ln.get(tdA);
4345 if( !areallREfromAequaltoB(ogB, lnB, ogA) ) {
4354 static protected boolean areallREfromAequaltoB(OwnershipGraph ogA,
4356 OwnershipGraph ogB) {
4358 Iterator<ReferenceEdge> itrA = onA.iteratorToReferencees();
4359 while( itrA.hasNext() ) {
4360 ReferenceEdge edgeA = itrA.next();
4361 HeapRegionNode hrnChildA = edgeA.getDst();
4362 Integer idChildA = hrnChildA.getID();
4364 assert ogB.id2hrn.containsKey(idChildA);
4366 // at this point we know an edge in graph A exists
4367 // onA -> idChildA, does this exact edge exist in B?
4368 boolean edgeFound = false;
4370 OwnershipNode onB = null;
4371 if( onA instanceof HeapRegionNode ) {
4372 HeapRegionNode hrnA = (HeapRegionNode) onA;
4373 onB = ogB.id2hrn.get(hrnA.getID() );
4375 LabelNode lnA = (LabelNode) onA;
4376 onB = ogB.td2ln.get(lnA.getTempDescriptor() );
4379 Iterator<ReferenceEdge> itrB = onB.iteratorToReferencees();
4380 while( itrB.hasNext() ) {
4381 ReferenceEdge edgeB = itrB.next();
4382 HeapRegionNode hrnChildB = edgeB.getDst();
4383 Integer idChildB = hrnChildB.getID();
4385 if( idChildA.equals( idChildB ) &&
4386 edgeA.typeAndFieldEquals( edgeB ) ) {
4388 // there is an edge in the right place with the right field,
4389 // but do they have the same attributes?
4390 if( edgeA.getBeta().equals(edgeB.getBeta() ) ) {
4405 protected boolean areParamIndexMappingsEqual(OwnershipGraph og) {
4407 if( idPrimary2paramIndexSet.size() != og.idPrimary2paramIndexSet.size() ) {
4411 if( idSecondary2paramIndexSet.size() != og.idSecondary2paramIndexSet.size() ) {
4419 protected boolean areAccessPathsEqual(OwnershipGraph og) {
4420 return temp2accessPaths.equals( og.temp2accessPaths );
4425 public Set<HeapRegionNode> hasPotentialAlias( HeapRegionNode hrn1, HeapRegionNode hrn2 ) {
4426 assert hrn1 != null;
4427 assert hrn2 != null;
4429 // then get the various tokens for these heap regions
4430 TokenTuple h1 = new TokenTuple(hrn1.getID(),
4431 !hrn1.isSingleObject(),
4432 TokenTuple.ARITY_ONE).makeCanonical();
4434 TokenTuple h1plus = new TokenTuple(hrn1.getID(),
4435 !hrn1.isSingleObject(),
4436 TokenTuple.ARITY_ONEORMORE).makeCanonical();
4438 TokenTuple h1star = new TokenTuple(hrn1.getID(),
4439 !hrn1.isSingleObject(),
4440 TokenTuple.ARITY_ZEROORMORE).makeCanonical();
4442 TokenTuple h2 = new TokenTuple(hrn2.getID(),
4443 !hrn2.isSingleObject(),
4444 TokenTuple.ARITY_ONE).makeCanonical();
4446 TokenTuple h2plus = new TokenTuple(hrn2.getID(),
4447 !hrn2.isSingleObject(),
4448 TokenTuple.ARITY_ONEORMORE).makeCanonical();
4450 TokenTuple h2star = new TokenTuple(hrn2.getID(),
4451 !hrn2.isSingleObject(),
4452 TokenTuple.ARITY_ZEROORMORE).makeCanonical();
4454 // then get the merged beta of all out-going edges from these heap regions
4455 ReachabilitySet beta1 = new ReachabilitySet().makeCanonical();
4456 Iterator<ReferenceEdge> itrEdge = hrn1.iteratorToReferencees();
4457 while( itrEdge.hasNext() ) {
4458 ReferenceEdge edge = itrEdge.next();
4459 beta1 = beta1.union( edge.getBeta() );
4462 ReachabilitySet beta2 = new ReachabilitySet().makeCanonical();
4463 itrEdge = hrn2.iteratorToReferencees();
4464 while( itrEdge.hasNext() ) {
4465 ReferenceEdge edge = itrEdge.next();
4466 beta2 = beta2.union( edge.getBeta() );
4469 boolean aliasDetected = false;
4471 // only do this one if they are different tokens
4473 beta1.containsTupleSetWithBoth(h1, h2) ) {
4474 aliasDetected = true;
4476 if( beta1.containsTupleSetWithBoth(h1plus, h2) ) {
4477 aliasDetected = true;
4479 if( beta1.containsTupleSetWithBoth(h1star, h2) ) {
4480 aliasDetected = true;
4482 if( beta1.containsTupleSetWithBoth(h1, h2plus) ) {
4483 aliasDetected = true;
4485 if( beta1.containsTupleSetWithBoth(h1plus, h2plus) ) {
4486 aliasDetected = true;
4488 if( beta1.containsTupleSetWithBoth(h1star, h2plus) ) {
4489 aliasDetected = true;
4491 if( beta1.containsTupleSetWithBoth(h1, h2star) ) {
4492 aliasDetected = true;
4494 if( beta1.containsTupleSetWithBoth(h1plus, h2star) ) {
4495 aliasDetected = true;
4497 if( beta1.containsTupleSetWithBoth(h1star, h2star) ) {
4498 aliasDetected = true;
4502 beta2.containsTupleSetWithBoth(h1, h2) ) {
4503 aliasDetected = true;
4505 if( beta2.containsTupleSetWithBoth(h1plus, h2) ) {
4506 aliasDetected = true;
4508 if( beta2.containsTupleSetWithBoth(h1star, h2) ) {
4509 aliasDetected = true;
4511 if( beta2.containsTupleSetWithBoth(h1, h2plus) ) {
4512 aliasDetected = true;
4514 if( beta2.containsTupleSetWithBoth(h1plus, h2plus) ) {
4515 aliasDetected = true;
4517 if( beta2.containsTupleSetWithBoth(h1star, h2plus) ) {
4518 aliasDetected = true;
4520 if( beta2.containsTupleSetWithBoth(h1, h2star) ) {
4521 aliasDetected = true;
4523 if( beta2.containsTupleSetWithBoth(h1plus, h2star) ) {
4524 aliasDetected = true;
4526 if( beta2.containsTupleSetWithBoth(h1star, h2star) ) {
4527 aliasDetected = true;
4530 Set<HeapRegionNode> common = new HashSet<HeapRegionNode>();
4531 if( aliasDetected ) {
4532 common = findCommonReachableNodes( hrn1, hrn2 );
4533 if( !(DISABLE_STRONG_UPDATES || DISABLE_GLOBAL_SWEEP) ) {
4534 assert !common.isEmpty();
4542 public Set<HeapRegionNode> hasPotentialAlias(Integer paramIndex1, Integer paramIndex2) {
4544 // get parameter 1's heap regions
4545 assert paramIndex2idPrimary.containsKey(paramIndex1);
4546 Integer idParamPri1 = paramIndex2idPrimary.get(paramIndex1);
4548 assert id2hrn.containsKey(idParamPri1);
4549 HeapRegionNode hrnParamPri1 = id2hrn.get(idParamPri1);
4550 assert hrnParamPri1 != null;
4552 HeapRegionNode hrnParamSec1 = null;
4553 if( paramIndex2idSecondary.containsKey(paramIndex1) ) {
4554 Integer idParamSec1 = paramIndex2idSecondary.get(paramIndex1);
4556 assert id2hrn.containsKey(idParamSec1);
4557 hrnParamSec1 = id2hrn.get(idParamSec1);
4558 assert hrnParamSec1 != null;
4562 // get the other parameter
4563 assert paramIndex2idPrimary.containsKey(paramIndex2);
4564 Integer idParamPri2 = paramIndex2idPrimary.get(paramIndex2);
4566 assert id2hrn.containsKey(idParamPri2);
4567 HeapRegionNode hrnParamPri2 = id2hrn.get(idParamPri2);
4568 assert hrnParamPri2 != null;
4570 HeapRegionNode hrnParamSec2 = null;
4571 if( paramIndex2idSecondary.containsKey(paramIndex2) ) {
4572 Integer idParamSec2 = paramIndex2idSecondary.get(paramIndex2);
4574 assert id2hrn.containsKey(idParamSec2);
4575 hrnParamSec2 = id2hrn.get(idParamSec2);
4576 assert hrnParamSec2 != null;
4579 Set<HeapRegionNode> common = new HashSet<HeapRegionNode>();
4580 common.addAll( hasPotentialAlias( hrnParamPri1, hrnParamPri2 ) );
4582 if( hrnParamSec1 != null ) {
4583 common.addAll( hasPotentialAlias( hrnParamSec1, hrnParamPri2 ) );
4586 if( hrnParamSec2 != null ) {
4587 common.addAll( hasPotentialAlias( hrnParamSec2, hrnParamPri1 ) );
4590 if( hrnParamSec1 != null && hrnParamSec2 != null ) {
4591 common.addAll( hasPotentialAlias( hrnParamSec1, hrnParamSec2 ) );
4598 public Set<HeapRegionNode> hasPotentialAlias(Integer paramIndex, AllocationSite as) {
4600 // get parameter's heap regions
4601 assert paramIndex2idPrimary.containsKey(paramIndex);
4602 Integer idParamPri = paramIndex2idPrimary.get(paramIndex);
4604 assert id2hrn.containsKey(idParamPri);
4605 HeapRegionNode hrnParamPri = id2hrn.get(idParamPri);
4606 assert hrnParamPri != null;
4608 HeapRegionNode hrnParamSec = null;
4609 if( paramIndex2idSecondary.containsKey(paramIndex) ) {
4610 Integer idParamSec = paramIndex2idSecondary.get(paramIndex);
4612 assert id2hrn.containsKey(idParamSec);
4613 hrnParamSec = id2hrn.get(idParamSec);
4614 assert hrnParamSec != null;
4618 assert id2hrn.containsKey( as.getSummary() );
4619 HeapRegionNode hrnSummary = id2hrn.get( as.getSummary() );
4620 assert hrnSummary != null;
4622 Set<HeapRegionNode> common = hasPotentialAlias( hrnParamPri, hrnSummary );
4624 if( hrnParamSec != null ) {
4625 common.addAll( hasPotentialAlias( hrnParamSec, hrnSummary ) );
4628 // check for other nodes
4629 for( int i = 0; i < as.getAllocationDepth(); ++i ) {
4631 assert id2hrn.containsKey( as.getIthOldest( i ) );
4632 HeapRegionNode hrnIthOldest = id2hrn.get( as.getIthOldest( i ) );
4633 assert hrnIthOldest != null;
4635 common = hasPotentialAlias( hrnParamPri, hrnIthOldest );
4637 if( hrnParamSec != null ) {
4638 common.addAll( hasPotentialAlias( hrnParamSec, hrnIthOldest ) );
4646 public Set<HeapRegionNode> hasPotentialAlias(AllocationSite as1, AllocationSite as2) {
4648 // get summary node 1's alpha
4649 Integer idSum1 = as1.getSummary();
4650 assert id2hrn.containsKey(idSum1);
4651 HeapRegionNode hrnSum1 = id2hrn.get(idSum1);
4652 assert hrnSum1 != null;
4654 // get summary node 2's alpha
4655 Integer idSum2 = as2.getSummary();
4656 assert id2hrn.containsKey(idSum2);
4657 HeapRegionNode hrnSum2 = id2hrn.get(idSum2);
4658 assert hrnSum2 != null;
4660 Set<HeapRegionNode> common = hasPotentialAlias( hrnSum1, hrnSum2 );
4662 // check sum2 against alloc1 nodes
4663 for( int i = 0; i < as1.getAllocationDepth(); ++i ) {
4664 Integer idI1 = as1.getIthOldest(i);
4665 assert id2hrn.containsKey(idI1);
4666 HeapRegionNode hrnI1 = id2hrn.get(idI1);
4667 assert hrnI1 != null;
4669 common.addAll( hasPotentialAlias( hrnI1, hrnSum2 ) );
4672 // check sum1 against alloc2 nodes
4673 for( int i = 0; i < as2.getAllocationDepth(); ++i ) {
4674 Integer idI2 = as2.getIthOldest(i);
4675 assert id2hrn.containsKey(idI2);
4676 HeapRegionNode hrnI2 = id2hrn.get(idI2);
4677 assert hrnI2 != null;
4679 common.addAll( hasPotentialAlias( hrnSum1, hrnI2 ) );
4681 // while we're at it, do an inner loop for alloc2 vs alloc1 nodes
4682 for( int j = 0; j < as1.getAllocationDepth(); ++j ) {
4683 Integer idI1 = as1.getIthOldest(j);
4685 // if these are the same site, don't look for the same token, no alias.
4686 // different tokens of the same site could alias together though
4687 if( idI1.equals( idI2 ) ) {
4691 HeapRegionNode hrnI1 = id2hrn.get(idI1);
4693 common.addAll( hasPotentialAlias( hrnI1, hrnI2 ) );
4701 public Set<HeapRegionNode> findCommonReachableNodes( HeapRegionNode hrn1,
4702 HeapRegionNode hrn2 ) {
4704 Set<HeapRegionNode> reachableNodes1 = new HashSet<HeapRegionNode>();
4705 Set<HeapRegionNode> reachableNodes2 = new HashSet<HeapRegionNode>();
4707 Set<HeapRegionNode> todoNodes1 = new HashSet<HeapRegionNode>();
4708 todoNodes1.add( hrn1 );
4710 Set<HeapRegionNode> todoNodes2 = new HashSet<HeapRegionNode>();
4711 todoNodes2.add( hrn2 );
4713 // follow links until all reachable nodes have been found
4714 while( !todoNodes1.isEmpty() ) {
4715 HeapRegionNode hrn = todoNodes1.iterator().next();
4716 todoNodes1.remove( hrn );
4717 reachableNodes1.add(hrn);
4719 Iterator<ReferenceEdge> edgeItr = hrn.iteratorToReferencees();
4720 while( edgeItr.hasNext() ) {
4721 ReferenceEdge edge = edgeItr.next();
4723 if( !reachableNodes1.contains( edge.getDst() ) ) {
4724 todoNodes1.add( edge.getDst() );
4729 while( !todoNodes2.isEmpty() ) {
4730 HeapRegionNode hrn = todoNodes2.iterator().next();
4731 todoNodes2.remove( hrn );
4732 reachableNodes2.add(hrn);
4734 Iterator<ReferenceEdge> edgeItr = hrn.iteratorToReferencees();
4735 while( edgeItr.hasNext() ) {
4736 ReferenceEdge edge = edgeItr.next();
4738 if( !reachableNodes2.contains( edge.getDst() ) ) {
4739 todoNodes2.add( edge.getDst() );
4744 Set<HeapRegionNode> intersection =
4745 new HashSet<HeapRegionNode>( reachableNodes1 );
4747 intersection.retainAll( reachableNodes2 );
4749 return intersection;
4753 public void writeGraph(String graphName,
4754 boolean writeLabels,
4755 boolean labelSelect,
4756 boolean pruneGarbage,
4757 boolean writeReferencers,
4758 boolean writeParamMappings,
4759 boolean hideSubsetReachability,
4760 boolean hideEdgeTaints
4761 ) throws java.io.IOException {
4763 // remove all non-word characters from the graph name so
4764 // the filename and identifier in dot don't cause errors
4765 graphName = graphName.replaceAll("[\\W]", "");
4767 BufferedWriter bw = new BufferedWriter(new FileWriter(graphName+".dot") );
4768 bw.write("digraph "+graphName+" {\n");
4770 HashSet<HeapRegionNode> visited = new HashSet<HeapRegionNode>();
4772 // then visit every heap region node
4773 Set s = id2hrn.entrySet();
4774 Iterator i = s.iterator();
4775 while( i.hasNext() ) {
4776 Map.Entry me = (Map.Entry)i.next();
4777 HeapRegionNode hrn = (HeapRegionNode) me.getValue();
4779 if( !pruneGarbage ||
4780 (hrn.isFlagged() && hrn.getID() > 0) ||
4781 hrn.getDescription().startsWith("param")
4784 if( !visited.contains(hrn) ) {
4785 traverseHeapRegionNodes(VISIT_HRN_WRITE_FULL,
4791 hideSubsetReachability,
4797 bw.write(" graphTitle[label=\""+graphName+"\",shape=box];\n");
4799 if( writeParamMappings ) {
4801 Set df = paramIndex2id.entrySet();
4802 Iterator ih = df.iterator();
4803 while( ih.hasNext() ) {
4804 Map.Entry meh = (Map.Entry)ih.next();
4805 Integer pi = (Integer) meh.getKey();
4806 Integer id = (Integer) meh.getValue();
4807 bw.write(" pindex"+pi+"[label=\""+pi+" to "+id+"\",shape=box];\n");
4812 // then visit every label node, useful for debugging
4814 s = td2ln.entrySet();
4816 while( i.hasNext() ) {
4817 Map.Entry me = (Map.Entry)i.next();
4818 LabelNode ln = (LabelNode) me.getValue();
4821 String labelStr = ln.getTempDescriptorString();
4822 if( labelStr.startsWith("___temp") ||
4823 labelStr.startsWith("___dst") ||
4824 labelStr.startsWith("___srctmp") ||
4825 labelStr.startsWith("___neverused") ||
4826 labelStr.contains(qString) ||
4827 labelStr.contains(rString) ||
4828 labelStr.contains(blobString)
4834 //bw.write(" "+ln.toString() + ";\n");
4836 Iterator<ReferenceEdge> heapRegionsItr = ln.iteratorToReferencees();
4837 while( heapRegionsItr.hasNext() ) {
4838 ReferenceEdge edge = heapRegionsItr.next();
4839 HeapRegionNode hrn = edge.getDst();
4841 if( pruneGarbage && !visited.contains(hrn) ) {
4842 traverseHeapRegionNodes(VISIT_HRN_WRITE_FULL,
4848 hideSubsetReachability,
4852 bw.write(" " + ln.toString() +
4853 " -> " + hrn.toString() +
4854 "[label=\"" + edge.toGraphEdgeString(hideSubsetReachability,
4866 protected void traverseHeapRegionNodes(int mode,
4870 HashSet<HeapRegionNode> visited,
4871 boolean writeReferencers,
4872 boolean hideSubsetReachability,
4873 boolean hideEdgeTaints
4874 ) throws java.io.IOException {
4876 if( visited.contains(hrn) ) {
4882 case VISIT_HRN_WRITE_FULL:
4884 String attributes = "[";
4886 if( hrn.isSingleObject() ) {
4887 attributes += "shape=box";
4889 attributes += "shape=Msquare";
4892 if( hrn.isFlagged() ) {
4893 attributes += ",style=filled,fillcolor=lightgrey";
4896 attributes += ",label=\"ID" +
4900 if( hrn.getType() != null ) {
4901 attributes += hrn.getType().toPrettyString() + "\\n";
4904 attributes += hrn.getDescription() +
4906 hrn.getAlphaString(hideSubsetReachability) +
4909 bw.write(" " + hrn.toString() + attributes + ";\n");
4914 // useful for debugging
4917 if( writeReferencers ) {
4918 OwnershipNode onRef = null;
4919 Iterator refItr = hrn.iteratorToReferencers();
4920 while( refItr.hasNext() ) {
4921 onRef = (OwnershipNode) refItr.next();
4924 case VISIT_HRN_WRITE_FULL:
4925 bw.write(" " + hrn.toString() +
4926 " -> " + onRef.toString() +
4927 "[color=lightgray];\n");
4934 Iterator<ReferenceEdge> childRegionsItr = hrn.iteratorToReferencees();
4935 while( childRegionsItr.hasNext() ) {
4936 ReferenceEdge edge = childRegionsItr.next();
4937 HeapRegionNode hrnChild = edge.getDst();
4940 case VISIT_HRN_WRITE_FULL:
4941 bw.write(" " + hrn.toString() +
4942 " -> " + hrnChild.toString() +
4943 "[label=\"" + edge.toGraphEdgeString(hideSubsetReachability,
4949 traverseHeapRegionNodes(mode,
4955 hideSubsetReachability,
4960 public int getTaintIdentifierFromHRN(HeapRegionNode hrn){
4961 HashSet<ReferenceEdge> referenceEdges=hrn.referencers;
4962 Iterator<ReferenceEdge> iter=referenceEdges.iterator();
4964 int taintIdentifier=0;
4965 while(iter.hasNext()){
4966 ReferenceEdge edge=iter.next();
4967 taintIdentifier=taintIdentifier | edge.getTaintIdentifier();
4970 return taintIdentifier;
4974 public void propagateTaintIdentifier(HeapRegionNode hrn, int newTaintIdentifier, HashSet<HeapRegionNode> visitedSet){
4976 HashSet<ReferenceEdge> setEdge=hrn.referencers;
4977 Iterator<ReferenceEdge> iter=setEdge.iterator();
4978 while(iter.hasNext()){
4979 ReferenceEdge edge= iter.next();
4980 edge.unionTaintIdentifier(newTaintIdentifier);
4981 if(edge.getSrc() instanceof HeapRegionNode){
4983 HeapRegionNode refHRN=(HeapRegionNode)edge.getSrc();
4984 //check whether it is reflexive edge
4985 if(!refHRN.equals(hrn) && !visitedSet.contains(refHRN)){
4986 visitedSet.add(refHRN);
4987 propagateTaintIdentifier((HeapRegionNode)edge.getSrc(),newTaintIdentifier,visitedSet);
4995 public void depropagateTaintIdentifier(HeapRegionNode hrn, int newTaintIdentifier, HashSet<HeapRegionNode> visitedSet){
4997 HashSet<ReferenceEdge> setEdge=hrn.referencers;
4998 Iterator<ReferenceEdge> iter=setEdge.iterator();
4999 while(iter.hasNext()){
5000 ReferenceEdge edge= iter.next();
5001 edge.minusTaintIdentifier(newTaintIdentifier);
5002 if(edge.getSrc() instanceof HeapRegionNode){
5004 HeapRegionNode refHRN=(HeapRegionNode)edge.getSrc();
5005 //check whether it is reflexive edge
5006 if(!refHRN.equals(hrn) && !visitedSet.contains(refHRN)){
5007 visitedSet.add(refHRN);
5008 depropagateTaintIdentifier((HeapRegionNode)edge.getSrc(),newTaintIdentifier,visitedSet);
5017 // in this analysis specifically:
5018 // we have a notion that a null type is the "match any" type,
5019 // so wrap calls to the utility methods that deal with null
5020 public TypeDescriptor mostSpecificType( TypeDescriptor td1,
5021 TypeDescriptor td2 ) {
5028 if( td1.isNull() ) {
5031 if( td2.isNull() ) {
5034 return typeUtil.mostSpecific( td1, td2 );
5037 public TypeDescriptor mostSpecificType( TypeDescriptor td1,
5039 TypeDescriptor td3 ) {
5041 return mostSpecificType( td1,
5042 mostSpecificType( td2, td3 )
5046 public TypeDescriptor mostSpecificType( TypeDescriptor td1,
5049 TypeDescriptor td4 ) {
5051 return mostSpecificType( mostSpecificType( td1, td2 ),
5052 mostSpecificType( td3, td4 )
5056 // remember, in this analysis a null type means "any type"
5057 public boolean isSuperiorType( TypeDescriptor possibleSuper,
5058 TypeDescriptor possibleChild ) {
5059 if( possibleSuper == null ||
5060 possibleChild == null ) {
5064 if( possibleSuper.isNull() ||
5065 possibleChild.isNull() ) {
5069 return typeUtil.isSuperorType( possibleSuper, possibleChild );
5072 public String generateUniqueIdentifier(FlatMethod fm, int paramIdx, String type){
5074 //type: A->aliapsed parameter heap region
5075 // P -> primary paramter heap region
5076 // S -> secondary paramter heap region
5079 if(type.equals("A")){
5081 identifier="FM"+fm.hashCode()+".A";
5083 identifier="FM"+fm.hashCode()+"."+paramIdx+"."+type;
5089 public String generateUniqueIdentifier(AllocationSite as, int age, boolean isSummary){
5093 FlatNew fn=as.getFlatNew();
5096 identifier="FN"+fn.hashCode()+".S";
5098 identifier="FN"+fn.hashCode()+"."+age;
5105 public HeapRegionNode getHRNbyUniqueID(String id) {
5107 Enumeration<HeapRegionNode> elements = id2hrn.elements();
5108 while (elements.hasMoreElements()) {
5109 HeapRegionNode hrn = elements.nextElement();
5110 if (hrn.getGloballyUniqueIdentifier().equals(id)) {