1 package Analysis.OwnershipAnalysis;
8 public class OwnershipGraph {
10 private int allocationDepth;
11 private TypeUtil typeUtil;
13 // there was already one other very similar reason
14 // for traversing heap nodes that is no longer needed
15 // instead of writing a new heap region visitor, use
16 // the existing method with a new mode to describe what
17 // actions to take during the traversal
18 protected static final int VISIT_HRN_WRITE_FULL = 0;
20 protected static final String qString = new String( "Q_spec_" );
21 protected static final String rString = new String( "R_spec_" );
22 protected static final String blobString = new String( "_AliasBlob___" );
24 protected static final TempDescriptor tdReturn = new TempDescriptor( "_Return___" );
25 protected static final TempDescriptor tdAliasBlob = new TempDescriptor( blobString );
27 protected static final TokenTupleSet ttsEmpty = new TokenTupleSet().makeCanonical();
28 protected static final ReachabilitySet rsEmpty = new ReachabilitySet().makeCanonical();
29 protected static final ReachabilitySet rsWttsEmpty = new ReachabilitySet( ttsEmpty ).makeCanonical();
31 // add a bogus entry with the identity rule for easy rewrite
32 // of new callee nodes and edges, doesn't belong to any parameter
33 protected static final int bogusParamIndexInt = -2;
34 protected static final Integer bogusID = new Integer( bogusParamIndexInt );
35 protected static final Integer bogusIndex = new Integer( bogusParamIndexInt );
36 protected static final TokenTuple bogusToken = new TokenTuple( bogusID, true, TokenTuple.ARITY_ONE ).makeCanonical();
37 protected static final TokenTuple bogusTokenPlus = new TokenTuple( bogusID, true, TokenTuple.ARITY_ONEORMORE ).makeCanonical();
38 protected static final TokenTuple bogusTokenStar = new TokenTuple( bogusID, true, TokenTuple.ARITY_ZEROORMORE ).makeCanonical();
39 protected static final ReachabilitySet rsIdentity =
40 new ReachabilitySet( new TokenTupleSet( bogusToken ).makeCanonical() ).makeCanonical();
43 public Hashtable<Integer, HeapRegionNode> id2hrn;
44 public Hashtable<TempDescriptor, LabelNode > td2ln;
46 public Hashtable<Integer, Set<Integer> > idPrimary2paramIndexSet;
47 public Hashtable<Integer, Integer > paramIndex2idPrimary;
49 public Hashtable<Integer, Set<Integer> > idSecondary2paramIndexSet;
50 public Hashtable<Integer, Integer > paramIndex2idSecondary;
52 public Hashtable<Integer, TempDescriptor> paramIndex2tdQ;
53 public Hashtable<Integer, TempDescriptor> paramIndex2tdR;
56 public HashSet<AllocationSite> allocationSites;
59 public Hashtable<TokenTuple, Integer> paramTokenPrimary2paramIndex;
60 public Hashtable<Integer, TokenTuple> paramIndex2paramTokenPrimary;
62 public Hashtable<TokenTuple, Integer> paramTokenSecondary2paramIndex;
63 public Hashtable<Integer, TokenTuple> paramIndex2paramTokenSecondary;
64 public Hashtable<TokenTuple, Integer> paramTokenSecondaryPlus2paramIndex;
65 public Hashtable<Integer, TokenTuple> paramIndex2paramTokenSecondaryPlus;
66 public Hashtable<TokenTuple, Integer> paramTokenSecondaryStar2paramIndex;
67 public Hashtable<Integer, TokenTuple> paramIndex2paramTokenSecondaryStar;
70 public OwnershipGraph(int allocationDepth, TypeUtil typeUtil) {
71 this.allocationDepth = allocationDepth;
72 this.typeUtil = typeUtil;
74 id2hrn = new Hashtable<Integer, HeapRegionNode>();
75 td2ln = new Hashtable<TempDescriptor, LabelNode >();
76 idPrimary2paramIndexSet = new Hashtable<Integer, Set<Integer> >();
77 paramIndex2idPrimary = new Hashtable<Integer, Integer >();
78 idSecondary2paramIndexSet = new Hashtable<Integer, Set<Integer> >();
79 paramIndex2idSecondary = new Hashtable<Integer, Integer >();
80 paramIndex2tdQ = new Hashtable<Integer, TempDescriptor>();
81 paramIndex2tdR = new Hashtable<Integer, TempDescriptor>();
83 paramTokenPrimary2paramIndex = new Hashtable<TokenTuple, Integer >();
84 paramIndex2paramTokenPrimary = new Hashtable<Integer, TokenTuple >();
86 paramTokenSecondary2paramIndex = new Hashtable<TokenTuple, Integer >();
87 paramIndex2paramTokenSecondary = new Hashtable<Integer, TokenTuple >();
88 paramTokenSecondaryPlus2paramIndex = new Hashtable<TokenTuple, Integer >();
89 paramIndex2paramTokenSecondaryPlus = new Hashtable<Integer, TokenTuple >();
90 paramTokenSecondaryStar2paramIndex = new Hashtable<TokenTuple, Integer >();
91 paramIndex2paramTokenSecondaryStar = new Hashtable<Integer, TokenTuple >();
93 allocationSites = new HashSet <AllocationSite>();
97 // label nodes are much easier to deal with than
98 // heap region nodes. Whenever there is a request
99 // for the label node that is associated with a
100 // temp descriptor we can either find it or make a
101 // new one and return it. This is because temp
102 // descriptors are globally unique and every label
103 // node is mapped to exactly one temp descriptor.
104 protected LabelNode getLabelNodeFromTemp(TempDescriptor td) {
107 if( !td2ln.containsKey(td) ) {
108 td2ln.put(td, new LabelNode(td) );
111 return td2ln.get(td);
115 // the reason for this method is to have the option
116 // creating new heap regions with specific IDs, or
117 // duplicating heap regions with specific IDs (especially
118 // in the merge() operation) or to create new heap
119 // regions with a new unique ID.
120 protected HeapRegionNode
121 createNewHeapRegionNode(Integer id,
122 boolean isSingleObject,
123 boolean isNewSummary,
127 AllocationSite allocSite,
128 ReachabilitySet alpha,
129 String description) {
131 boolean markForAnalysis = isFlagged || isParameter;
133 TypeDescriptor typeToUse = null;
134 if( allocSite != null ) {
135 typeToUse = allocSite.getType();
140 if( allocSite != null && allocSite.getDisjointId() != null ) {
141 markForAnalysis = true;
145 id = OwnershipAnalysis.generateUniqueHeapRegionNodeID();
148 if( alpha == null ) {
149 if( markForAnalysis ) {
150 alpha = new ReachabilitySet(
157 alpha = new ReachabilitySet(
158 new TokenTupleSet().makeCanonical()
163 HeapRegionNode hrn = new HeapRegionNode(id,
178 ////////////////////////////////////////////////
180 // Low-level referencee and referencer methods
182 // These methods provide the lowest level for
183 // creating references between ownership nodes
184 // and handling the details of maintaining both
185 // list of referencers and referencees.
187 ////////////////////////////////////////////////
188 protected void addReferenceEdge(OwnershipNode referencer,
189 HeapRegionNode referencee,
190 ReferenceEdge edge) {
191 assert referencer != null;
192 assert referencee != null;
194 assert edge.getSrc() == referencer;
195 assert edge.getDst() == referencee;
197 referencer.addReferencee(edge);
198 referencee.addReferencer(edge);
201 protected void removeReferenceEdge(OwnershipNode referencer,
202 HeapRegionNode referencee,
205 assert referencer != null;
206 assert referencee != null;
208 ReferenceEdge edge = referencer.getReferenceTo(referencee,
212 assert edge == referencee.getReferenceFrom(referencer,
216 // int oldTaint=edge.getTaintIdentifier();
217 // if(referencer instanceof HeapRegionNode){
218 // depropagateTaintIdentifier((HeapRegionNode)referencer,oldTaint,new HashSet<HeapRegionNode>());
221 referencer.removeReferencee(edge);
222 referencee.removeReferencer(edge);
225 protected void clearReferenceEdgesFrom(OwnershipNode referencer,
229 assert referencer != null;
231 // get a copy of the set to iterate over, otherwise
232 // we will be trying to take apart the set as we
233 // are iterating over it, which won't work
234 Iterator<ReferenceEdge> i = referencer.iteratorToReferenceesClone();
235 while( i.hasNext() ) {
236 ReferenceEdge edge = i.next();
239 (edge.typeEquals( type ) && edge.fieldEquals( field ))
242 HeapRegionNode referencee = edge.getDst();
244 removeReferenceEdge(referencer,
252 protected void clearReferenceEdgesTo(HeapRegionNode referencee,
256 assert referencee != null;
258 // get a copy of the set to iterate over, otherwise
259 // we will be trying to take apart the set as we
260 // are iterating over it, which won't work
261 Iterator<ReferenceEdge> i = referencee.iteratorToReferencersClone();
262 while( i.hasNext() ) {
263 ReferenceEdge edge = i.next();
266 (edge.typeEquals( type ) && edge.fieldEquals( field ))
269 OwnershipNode referencer = edge.getSrc();
271 removeReferenceEdge(referencer,
280 ////////////////////////////////////////////////////
282 // Assignment Operation Methods
284 // These methods are high-level operations for
285 // modeling program assignment statements using
286 // the low-level reference create/remove methods
289 // The destination in an assignment statement is
290 // going to have new references. The method of
291 // determining the references depends on the type
292 // of the FlatNode assignment and the predicates
293 // of the nodes and edges involved.
295 ////////////////////////////////////////////////////
296 public void assignTempXEqualToTempY(TempDescriptor x,
299 LabelNode lnX = getLabelNodeFromTemp(x);
300 LabelNode lnY = getLabelNodeFromTemp(y);
302 clearReferenceEdgesFrom(lnX, null, null, true);
304 Iterator<ReferenceEdge> itrYhrn = lnY.iteratorToReferencees();
305 while( itrYhrn.hasNext() ) {
306 ReferenceEdge edgeY = itrYhrn.next();
307 HeapRegionNode referencee = edgeY.getDst();
308 ReferenceEdge edgeNew = edgeY.copy();
311 addReferenceEdge(lnX, referencee, edgeNew);
316 public void assignTypedTempXEqualToTempY(TempDescriptor x,
318 TypeDescriptor type) {
320 LabelNode lnX = getLabelNodeFromTemp(x);
321 LabelNode lnY = getLabelNodeFromTemp(y);
323 clearReferenceEdgesFrom(lnX, null, null, true);
325 Iterator<ReferenceEdge> itrYhrn = lnY.iteratorToReferencees();
326 while( itrYhrn.hasNext() ) {
327 ReferenceEdge edgeY = itrYhrn.next();
328 HeapRegionNode referencee = edgeY.getDst();
329 ReferenceEdge edgeNew = edgeY.copy();
330 edgeNew.setSrc( lnX );
331 edgeNew.setType( type );
332 edgeNew.setField( null );
334 addReferenceEdge(lnX, referencee, edgeNew);
339 public void assignTempXEqualToTempYFieldF(TempDescriptor x,
342 LabelNode lnX = getLabelNodeFromTemp(x);
343 LabelNode lnY = getLabelNodeFromTemp(y);
345 clearReferenceEdgesFrom(lnX, null, null, true);
347 Iterator<ReferenceEdge> itrYhrn = lnY.iteratorToReferencees();
348 while( itrYhrn.hasNext() ) {
349 ReferenceEdge edgeY = itrYhrn.next();
350 HeapRegionNode hrnY = edgeY.getDst();
351 ReachabilitySet betaY = edgeY.getBeta();
353 Iterator<ReferenceEdge> itrHrnFhrn = hrnY.iteratorToReferencees();
354 while( itrHrnFhrn.hasNext() ) {
355 ReferenceEdge edgeHrn = itrHrnFhrn.next();
356 HeapRegionNode hrnHrn = edgeHrn.getDst();
357 ReachabilitySet betaHrn = edgeHrn.getBeta();
359 if( edgeHrn.getType() == null ||
360 (edgeHrn.getType() .equals( f.getType() ) &&
361 edgeHrn.getField().equals( f.getSymbol() ) )
364 ReferenceEdge edgeNew = new ReferenceEdge(lnX,
369 betaY.intersection(betaHrn) );
371 int newTaintIdentifier=getTaintIdentifierFromHRN(hrnHrn);
372 edgeNew.setTaintIdentifier(newTaintIdentifier);
374 addReferenceEdge(lnX, hrnHrn, edgeNew);
381 public void assignTempXFieldFEqualToTempY(TempDescriptor x,
384 LabelNode lnX = getLabelNodeFromTemp(x);
385 LabelNode lnY = getLabelNodeFromTemp(y);
387 HashSet<HeapRegionNode> nodesWithNewAlpha = new HashSet<HeapRegionNode>();
388 HashSet<ReferenceEdge> edgesWithNewBeta = new HashSet<ReferenceEdge>();
390 // first look for possible strong updates and remove those edges
391 boolean strongUpdate = false;
393 Iterator<ReferenceEdge> itrXhrn = lnX.iteratorToReferencees();
394 while( itrXhrn.hasNext() ) {
395 ReferenceEdge edgeX = itrXhrn.next();
396 HeapRegionNode hrnX = edgeX.getDst();
398 // we can do a strong update here if one of two cases holds
400 f != OwnershipAnalysis.getArrayField( f.getType() ) &&
401 ( (hrnX.getNumReferencers() == 1) || // case 1
402 (hrnX.isSingleObject() && lnX.getNumReferencees() == 1) // case 2
406 clearReferenceEdgesFrom( hrnX, f.getType(), f.getSymbol(), false );
410 // then do all token propagation
411 itrXhrn = lnX.iteratorToReferencees();
412 while( itrXhrn.hasNext() ) {
413 ReferenceEdge edgeX = itrXhrn.next();
414 HeapRegionNode hrnX = edgeX.getDst();
415 ReachabilitySet betaX = edgeX.getBeta();
417 ReachabilitySet R = hrnX.getAlpha().intersection(edgeX.getBeta() );
419 Iterator<ReferenceEdge> itrYhrn = lnY.iteratorToReferencees();
420 while( itrYhrn.hasNext() ) {
421 ReferenceEdge edgeY = itrYhrn.next();
422 HeapRegionNode hrnY = edgeY.getDst();
423 ReachabilitySet O = edgeY.getBeta();
426 // propagate tokens over nodes starting from hrnSrc, and it will
427 // take care of propagating back up edges from any touched nodes
428 ChangeTupleSet Cy = O.unionUpArityToChangeSet(R);
429 propagateTokensOverNodes(hrnY, Cy, nodesWithNewAlpha, edgesWithNewBeta);
432 // then propagate back just up the edges from hrn
433 ChangeTupleSet Cx = R.unionUpArityToChangeSet(O);
434 HashSet<ReferenceEdge> todoEdges = new HashSet<ReferenceEdge>();
436 Hashtable<ReferenceEdge, ChangeTupleSet> edgePlannedChanges =
437 new Hashtable<ReferenceEdge, ChangeTupleSet>();
439 Iterator<ReferenceEdge> referItr = hrnX.iteratorToReferencers();
440 while( referItr.hasNext() ) {
441 ReferenceEdge edgeUpstream = referItr.next();
442 todoEdges.add(edgeUpstream);
443 edgePlannedChanges.put(edgeUpstream, Cx);
446 propagateTokensOverEdges(todoEdges,
453 // apply the updates to reachability
454 Iterator<HeapRegionNode> nodeItr = nodesWithNewAlpha.iterator();
455 while( nodeItr.hasNext() ) {
456 nodeItr.next().applyAlphaNew();
459 Iterator<ReferenceEdge> edgeItr = edgesWithNewBeta.iterator();
460 while( edgeItr.hasNext() ) {
461 edgeItr.next().applyBetaNew();
465 // then go back through and add the new edges
466 itrXhrn = lnX.iteratorToReferencees();
467 while( itrXhrn.hasNext() ) {
468 ReferenceEdge edgeX = itrXhrn.next();
469 HeapRegionNode hrnX = edgeX.getDst();
471 Iterator<ReferenceEdge> itrYhrn = lnY.iteratorToReferencees();
472 while( itrYhrn.hasNext() ) {
473 ReferenceEdge edgeY = itrYhrn.next();
474 HeapRegionNode hrnY = edgeY.getDst();
476 // prepare the new reference edge hrnX.f -> hrnY
477 ReferenceEdge edgeNew = new ReferenceEdge(hrnX,
482 edgeY.getBeta().pruneBy( hrnX.getAlpha() )
485 // look to see if an edge with same field exists
486 // and merge with it, otherwise just add the edge
487 ReferenceEdge edgeExisting = hrnX.getReferenceTo( hrnY,
491 if( edgeExisting != null ) {
492 edgeExisting.setBeta(
493 edgeExisting.getBeta().union( edgeNew.getBeta() )
495 int newTaintIdentifier=getTaintIdentifierFromHRN(hrnY);
496 edgeExisting.unionTaintIdentifier(newTaintIdentifier);
497 // a new edge here cannot be reflexive, so existing will
498 // always be also not reflexive anymore
499 edgeExisting.setIsInitialParam( false );
501 int newTaintIdentifier=getTaintIdentifierFromHRN(hrnY);
502 edgeNew.setTaintIdentifier(newTaintIdentifier);
503 propagateTaintIdentifier(hrnX,newTaintIdentifier,new HashSet<HeapRegionNode>());
504 addReferenceEdge( hrnX, hrnY, edgeNew );
509 // if there was a strong update, make sure to improve
510 // reachability with a global sweep
519 // the parameter model is to use a single-object heap region
520 // for the primary parameter, and a multiple-object heap
521 // region for the secondary objects reachable through the
522 // primary object, if necessary
523 public void assignTempEqualToParamAlloc( TempDescriptor td,
525 Integer paramIndex ) {
528 TypeDescriptor typeParam = td.getType();
529 assert typeParam != null;
531 // either the parameter is an array or a class to be in this method
532 assert typeParam.isArray() || typeParam.isClass();
534 // discover some info from the param type and use it below
535 // to get parameter model as precise as we can
536 boolean createSecondaryRegion = false;
537 Set<FieldDescriptor> primary2primaryFields = new HashSet<FieldDescriptor>();
538 Set<FieldDescriptor> primary2secondaryFields = new HashSet<FieldDescriptor>();
540 // there might be an element reference for array types
541 if( typeParam.isArray() ) {
542 // only bother with this if the dereferenced type can
543 // affect reachability
544 TypeDescriptor typeDeref = typeParam.dereference();
545 if( !typeDeref.isImmutable() || typeDeref.isArray() ) {
546 primary2secondaryFields.add(
547 OwnershipAnalysis.getArrayField( typeDeref )
549 createSecondaryRegion = true;
551 // also handle a special case where an array of objects
552 // can point back to the array, which is an object!
553 if( typeParam.toPrettyString().equals( "Object[]" ) &&
554 typeDeref.toPrettyString().equals( "Object" ) ) {
556 primary2primaryFields.add(
557 OwnershipAnalysis.getArrayField( typeDeref )
563 // there might be member references for class types
564 if( typeParam.isClass() ) {
565 ClassDescriptor cd = typeParam.getClassDesc();
566 while( cd != null ) {
568 Iterator fieldItr = cd.getFields();
569 while( fieldItr.hasNext() ) {
571 FieldDescriptor fd = (FieldDescriptor) fieldItr.next();
572 TypeDescriptor typeField = fd.getType();
573 assert typeField != null;
575 if( !typeField.isImmutable() || typeField.isArray() ) {
576 primary2secondaryFields.add( fd );
577 createSecondaryRegion = true;
580 if( typeUtil.isSuperorType( typeField, typeParam ) ) {
581 primary2primaryFields.add( fd );
585 cd = cd.getSuperDesc();
590 // now build everything we need
591 LabelNode lnParam = getLabelNodeFromTemp( td );
592 HeapRegionNode hrnPrimary = createNewHeapRegionNode( null, // id or null to generate a new one
593 true, // single object?
596 true, // is a parameter?
598 null, // allocation site
599 null, // reachability set
600 "param"+paramIndex+" obj" );
602 // this is a non-program-accessible label that picks up beta
603 // info to be used for fixing a caller of this method
604 TempDescriptor tdParamQ = new TempDescriptor( td+qString );
605 paramIndex2tdQ.put( paramIndex, tdParamQ );
606 LabelNode lnParamQ = getLabelNodeFromTemp( tdParamQ );
608 // keep track of heap regions that were created for
609 // parameter labels, the index of the parameter they
610 // are for is important when resolving method calls
611 Integer newPrimaryID = hrnPrimary.getID();
612 assert !idPrimary2paramIndexSet.containsKey( newPrimaryID );
613 Set<Integer> s = new HashSet<Integer>();
615 idPrimary2paramIndexSet.put( newPrimaryID, s );
616 paramIndex2idPrimary.put( paramIndex, newPrimaryID );
619 TokenTuple ttPrimary = new TokenTuple( newPrimaryID,
620 false, // multi-object
621 TokenTuple.ARITY_ONE ).makeCanonical();
623 HeapRegionNode hrnSecondary = null;
624 Integer newSecondaryID = null;
625 TokenTuple ttSecondary = null;
626 TempDescriptor tdParamR = null;
627 LabelNode lnParamR = null;
629 if( createSecondaryRegion ) {
630 tdParamR = new TempDescriptor( td+rString );
631 paramIndex2tdR.put( paramIndex, tdParamR );
632 lnParamR = getLabelNodeFromTemp( tdParamR );
634 hrnSecondary = createNewHeapRegionNode( null, // id or null to generate a new one
635 false, // single object?
638 true, // is a parameter?
640 null, // allocation site
641 null, // reachability set
642 "param"+paramIndex+" reachable" );
644 newSecondaryID = hrnSecondary.getID();
645 assert !idSecondary2paramIndexSet.containsKey( newSecondaryID );
646 Set<Integer> s2 = new HashSet<Integer>();
647 s2.add( paramIndex );
648 idSecondary2paramIndexSet.put( newSecondaryID, s2 );
649 paramIndex2idSecondary.put( paramIndex, newSecondaryID );
652 ttSecondary = new TokenTuple( newSecondaryID,
653 true, // multi-object
654 TokenTuple.ARITY_ONE ).makeCanonical();
657 // use a beta that has everything and put it all over the
658 // parameter model, then use a global sweep later to fix
659 // it up, since parameters can have different shapes
660 TokenTupleSet tts0 = new TokenTupleSet( ttPrimary ).makeCanonical();
661 ReachabilitySet betaSoup;
662 if( createSecondaryRegion ) {
663 TokenTupleSet tts1 = new TokenTupleSet( ttSecondary ).makeCanonical();
664 TokenTupleSet tts2 = new TokenTupleSet( ttPrimary ).makeCanonical().union( ttSecondary );
665 betaSoup = ReachabilitySet.factory( tts0 ).union( tts1 ).union( tts2 );
667 betaSoup = ReachabilitySet.factory( tts0 );
670 ReferenceEdge edgeFromLabel =
671 new ReferenceEdge( lnParam, // src
675 false, // special param initial (not needed on label->node)
676 betaSoup ); // reachability
677 edgeFromLabel.tainedBy(paramIndex);
678 addReferenceEdge( lnParam, hrnPrimary, edgeFromLabel );
680 ReferenceEdge edgeFromLabelQ =
681 new ReferenceEdge( lnParamQ, // src
685 false, // special param initial (not needed on label->node)
686 betaSoup ); // reachability
687 edgeFromLabelQ.tainedBy(paramIndex);
688 addReferenceEdge( lnParamQ, hrnPrimary, edgeFromLabelQ );
690 ReferenceEdge edgeSecondaryReflexive;
691 if( createSecondaryRegion ) {
692 edgeSecondaryReflexive =
693 new ReferenceEdge( hrnSecondary, // src
695 null, // match all types
696 null, // match all fields
697 true, // special param initial
698 betaSoup ); // reachability
699 edgeSecondaryReflexive.tainedBy(paramIndex);
700 addReferenceEdge( hrnSecondary, hrnSecondary, edgeSecondaryReflexive );
702 ReferenceEdge edgeSecondary2Primary =
703 new ReferenceEdge( hrnSecondary, // src
705 null, // match all types
706 null, // match all fields
707 true, // special param initial
708 betaSoup ); // reachability
709 edgeSecondary2Primary.tainedBy(paramIndex);
710 addReferenceEdge( hrnSecondary, hrnPrimary, edgeSecondary2Primary );
712 ReferenceEdge edgeFromLabelR =
713 new ReferenceEdge( lnParamR, // src
717 false, // special param initial (not needed on label->node)
718 betaSoup ); // reachability
719 edgeFromLabelR.tainedBy(paramIndex);
720 addReferenceEdge( lnParamR, hrnSecondary, edgeFromLabelR );
723 Iterator<FieldDescriptor> fieldItr = primary2primaryFields.iterator();
724 while( fieldItr.hasNext() ) {
725 FieldDescriptor fd = fieldItr.next();
727 ReferenceEdge edgePrimaryReflexive =
728 new ReferenceEdge( hrnPrimary, // src
730 fd.getType(), // type
731 fd.getSymbol(), // field
732 true, // special param initial
733 betaSoup ); // reachability
734 edgePrimaryReflexive.tainedBy(paramIndex);
735 addReferenceEdge( hrnPrimary, hrnPrimary, edgePrimaryReflexive );
738 fieldItr = primary2secondaryFields.iterator();
739 while( fieldItr.hasNext() ) {
740 FieldDescriptor fd = fieldItr.next();
742 ReferenceEdge edgePrimary2Secondary =
743 new ReferenceEdge( hrnPrimary, // src
745 fd.getType(), // type
746 fd.getSymbol(), // field
747 true, // special param initial
748 betaSoup ); // reachability
749 edgePrimary2Secondary.tainedBy(paramIndex);
750 addReferenceEdge( hrnPrimary, hrnSecondary, edgePrimary2Secondary );
755 public void makeAliasedParamHeapRegionNode() {
757 LabelNode lnBlob = getLabelNodeFromTemp( tdAliasBlob );
758 HeapRegionNode hrn = createNewHeapRegionNode( null, // id or null to generate a new one
759 false, // single object?
762 true, // is a parameter?
764 null, // allocation site
765 null, // reachability set
769 ReachabilitySet beta = new ReachabilitySet( new TokenTuple( hrn.getID(),
771 TokenTuple.ARITY_ONE).makeCanonical()
774 ReferenceEdge edgeFromLabel =
775 new ReferenceEdge( lnBlob, hrn, null, null, false, beta );
777 ReferenceEdge edgeReflexive =
778 new ReferenceEdge( hrn, hrn, null, null, true, beta );
780 addReferenceEdge( lnBlob, hrn, edgeFromLabel );
781 addReferenceEdge( hrn, hrn, edgeReflexive );
785 public void assignTempEqualToAliasedParam( TempDescriptor tdParam,
786 Integer paramIndex ) {
787 assert tdParam != null;
789 TypeDescriptor typeParam = tdParam.getType();
790 assert typeParam != null;
792 LabelNode lnParam = getLabelNodeFromTemp( tdParam );
793 LabelNode lnAliased = getLabelNodeFromTemp( tdAliasBlob );
795 // this is a non-program-accessible label that picks up beta
796 // info to be used for fixing a caller of this method
797 TempDescriptor tdParamQ = new TempDescriptor( tdParam+qString );
798 TempDescriptor tdParamR = new TempDescriptor( tdParam+rString );
800 paramIndex2tdQ.put( paramIndex, tdParamQ );
801 paramIndex2tdR.put( paramIndex, tdParamR );
803 LabelNode lnParamQ = getLabelNodeFromTemp( tdParamQ );
804 LabelNode lnParamR = getLabelNodeFromTemp( tdParamR );
806 // the lnAliased should always only reference one node, and that
807 // heap region node is the aliased param blob
808 assert lnAliased.getNumReferencees() == 1;
809 HeapRegionNode hrnAliasBlob = lnAliased.iteratorToReferencees().next().getDst();
810 Integer idAliased = hrnAliasBlob.getID();
813 TokenTuple ttAliased = new TokenTuple( idAliased,
814 true, // multi-object
815 TokenTuple.ARITY_ONE ).makeCanonical();
818 HeapRegionNode hrnPrimary = createNewHeapRegionNode( null, // id or null to generate a new one
819 true, // single object?
822 true, // is a parameter?
824 null, // allocation site
825 null, // reachability set
826 "param"+paramIndex+" obj" );
828 Integer newPrimaryID = hrnPrimary.getID();
829 assert !idPrimary2paramIndexSet.containsKey( newPrimaryID );
830 Set<Integer> s1 = new HashSet<Integer>();
831 s1.add( paramIndex );
832 idPrimary2paramIndexSet.put( newPrimaryID, s1 );
833 paramIndex2idPrimary.put( paramIndex, newPrimaryID );
835 Set<Integer> s2 = idSecondary2paramIndexSet.get( idAliased );
837 s2 = new HashSet<Integer>();
839 s2.add( paramIndex );
840 idSecondary2paramIndexSet.put( idAliased, s2 );
841 paramIndex2idSecondary.put( paramIndex, idAliased );
845 TokenTuple ttPrimary = new TokenTuple( newPrimaryID,
846 false, // multi-object
847 TokenTuple.ARITY_ONE ).makeCanonical();
850 TokenTupleSet tts0 = new TokenTupleSet( ttPrimary ).makeCanonical();
851 TokenTupleSet tts1 = new TokenTupleSet( ttAliased ).makeCanonical();
852 TokenTupleSet tts2 = new TokenTupleSet( ttPrimary ).makeCanonical().union( ttAliased );
853 ReachabilitySet betaSoup = ReachabilitySet.factory( tts0 ).union( tts1 ).union( tts2 );
856 ReferenceEdge edgeFromLabel =
857 new ReferenceEdge( lnParam, // src
861 false, // special param initial (not needed on label->node)
862 betaSoup ); // reachability
863 edgeFromLabel.tainedBy(paramIndex);
864 addReferenceEdge( lnParam, hrnPrimary, edgeFromLabel );
866 ReferenceEdge edgeFromLabelQ =
867 new ReferenceEdge( lnParamQ, // src
871 false, // special param initial (not needed on label->node)
872 betaSoup ); // reachability
873 edgeFromLabelQ.tainedBy(paramIndex);
874 addReferenceEdge( lnParamQ, hrnPrimary, edgeFromLabelQ );
876 ReferenceEdge edgeAliased2Primary =
877 new ReferenceEdge( hrnAliasBlob, // src
879 null, // match all types
880 null, // match all fields
881 true, // special param initial
882 betaSoup ); // reachability
883 edgeAliased2Primary.tainedBy(paramIndex);
884 addReferenceEdge( hrnAliasBlob, hrnPrimary, edgeAliased2Primary );
886 ReferenceEdge edgeFromLabelR =
887 new ReferenceEdge( lnParamR, // src
891 false, // special param initial (not needed on label->node)
892 betaSoup ); // reachability
893 edgeFromLabelR.tainedBy(paramIndex);
894 addReferenceEdge( lnParamR, hrnAliasBlob, edgeFromLabelR );
898 public void addParam2ParamAliasEdges( FlatMethod fm,
899 Set<Integer> aliasedParamIndices ) {
901 LabelNode lnAliased = getLabelNodeFromTemp( tdAliasBlob );
903 // the lnAliased should always only reference one node, and that
904 // heap region node is the aliased param blob
905 assert lnAliased.getNumReferencees() == 1;
906 HeapRegionNode hrnAliasBlob = lnAliased.iteratorToReferencees().next().getDst();
907 Integer idAliased = hrnAliasBlob.getID();
910 TokenTuple ttAliased = new TokenTuple( idAliased,
911 true, // multi-object
912 TokenTuple.ARITY_ONE ).makeCanonical();
915 Iterator<Integer> apItrI = aliasedParamIndices.iterator();
916 while( apItrI.hasNext() ) {
917 Integer i = apItrI.next();
918 TempDescriptor tdParamI = fm.getParameter( i );
919 TypeDescriptor typeI = tdParamI.getType();
920 LabelNode lnParamI = getLabelNodeFromTemp( tdParamI );
922 Integer idPrimaryI = paramIndex2idPrimary.get( i );
923 assert idPrimaryI != null;
924 HeapRegionNode primaryI = id2hrn.get( idPrimaryI );
925 assert primaryI != null;
927 TokenTuple ttPrimaryI = new TokenTuple( idPrimaryI,
928 false, // multi-object
929 TokenTuple.ARITY_ONE ).makeCanonical();
931 TokenTupleSet ttsI = new TokenTupleSet( ttPrimaryI ).makeCanonical();
932 TokenTupleSet ttsA = new TokenTupleSet( ttAliased ).makeCanonical();
933 TokenTupleSet ttsIA = new TokenTupleSet( ttPrimaryI ).makeCanonical().union( ttAliased );
934 ReachabilitySet betaSoup = ReachabilitySet.factory( ttsI ).union( ttsA ).union( ttsIA );
937 // calculate whether fields of this aliased parameter are able to
938 // reference its own primary object, the blob, or other parameter's
940 Set<FieldDescriptor> primary2primaryFields = new HashSet<FieldDescriptor>();
941 Set<FieldDescriptor> primary2secondaryFields = new HashSet<FieldDescriptor>();
943 // there might be an element reference for array types
944 if( typeI.isArray() ) {
945 // only bother with this if the dereferenced type can
946 // affect reachability
947 TypeDescriptor typeDeref = typeI.dereference();
949 // for this parameter to be aliased the following must be true
950 assert !typeDeref.isImmutable() || typeDeref.isArray();
952 primary2secondaryFields.add(
953 OwnershipAnalysis.getArrayField( typeDeref )
956 // also handle a special case where an array of objects
957 // can point back to the array, which is an object!
958 if( typeI .toPrettyString().equals( "Object[]" ) &&
959 typeDeref.toPrettyString().equals( "Object" ) ) {
960 primary2primaryFields.add(
961 OwnershipAnalysis.getArrayField( typeDeref )
966 // there might be member references for class types
967 if( typeI.isClass() ) {
968 ClassDescriptor cd = typeI.getClassDesc();
969 while( cd != null ) {
971 Iterator fieldItr = cd.getFields();
972 while( fieldItr.hasNext() ) {
974 FieldDescriptor fd = (FieldDescriptor) fieldItr.next();
975 TypeDescriptor typeField = fd.getType();
976 assert typeField != null;
978 if( !typeField.isImmutable() || typeField.isArray() ) {
979 primary2secondaryFields.add( fd );
982 if( typeUtil.isSuperorType( typeField, typeI ) ) {
983 primary2primaryFields.add( fd );
987 cd = cd.getSuperDesc();
991 Iterator<FieldDescriptor> fieldItr = primary2primaryFields.iterator();
992 while( fieldItr.hasNext() ) {
993 FieldDescriptor fd = fieldItr.next();
995 ReferenceEdge edgePrimaryReflexive =
996 new ReferenceEdge( primaryI, // src
998 fd.getType(), // type
999 fd.getSymbol(), // field
1000 true, // special param initial
1001 betaSoup ); // reachability
1002 edgePrimaryReflexive.tainedBy(new Integer(i));
1003 addReferenceEdge( primaryI, primaryI, edgePrimaryReflexive );
1006 fieldItr = primary2secondaryFields.iterator();
1007 while( fieldItr.hasNext() ) {
1008 FieldDescriptor fd = fieldItr.next();
1009 TypeDescriptor typeField = fd.getType();
1010 assert typeField != null;
1012 ReferenceEdge edgePrimary2Secondary =
1013 new ReferenceEdge( primaryI, // src
1014 hrnAliasBlob, // dst
1015 fd.getType(), // type
1016 fd.getSymbol(), // field
1017 true, // special param initial
1018 betaSoup ); // reachability
1019 edgePrimary2Secondary.tainedBy(new Integer(i));
1020 addReferenceEdge( primaryI, hrnAliasBlob, edgePrimary2Secondary );
1022 // ask whether these fields might match any of the other aliased
1023 // parameters and make those edges too
1024 Iterator<Integer> apItrJ = aliasedParamIndices.iterator();
1025 while( apItrJ.hasNext() ) {
1026 Integer j = apItrJ.next();
1027 TempDescriptor tdParamJ = fm.getParameter( j );
1028 TypeDescriptor typeJ = tdParamJ.getType();
1030 if( !i.equals( j ) && typeUtil.isSuperorType( typeField, typeJ ) ) {
1032 Integer idPrimaryJ = paramIndex2idPrimary.get( j );
1033 assert idPrimaryJ != null;
1034 HeapRegionNode primaryJ = id2hrn.get( idPrimaryJ );
1035 assert primaryJ != null;
1037 TokenTuple ttPrimaryJ = new TokenTuple( idPrimaryJ,
1038 false, // multi-object
1039 TokenTuple.ARITY_ONE ).makeCanonical();
1041 TokenTupleSet ttsJ = new TokenTupleSet( ttPrimaryJ ).makeCanonical();
1042 TokenTupleSet ttsIJ = ttsI.union( ttsJ );
1043 TokenTupleSet ttsAJ = ttsA.union( ttsJ );
1044 TokenTupleSet ttsIAJ = ttsIA.union( ttsJ );
1045 ReachabilitySet betaSoupWJ = ReachabilitySet.factory( ttsJ ).union( ttsIJ ).union( ttsAJ ).union( ttsIAJ );
1047 ReferenceEdge edgePrimaryI2PrimaryJ =
1048 new ReferenceEdge( primaryI, // src
1050 fd.getType(), // type
1051 fd.getSymbol(), // field
1052 true, // special param initial
1053 betaSoupWJ ); // reachability
1054 edgePrimaryI2PrimaryJ.tainedBy(new Integer(i));
1055 addReferenceEdge( primaryI, primaryJ, edgePrimaryI2PrimaryJ );
1061 // look at whether aliased parameters i and j can
1062 // possibly be the same primary object, add edges
1063 Iterator<Integer> apItrJ = aliasedParamIndices.iterator();
1064 while( apItrJ.hasNext() ) {
1065 Integer j = apItrJ.next();
1066 TempDescriptor tdParamJ = fm.getParameter( j );
1067 TypeDescriptor typeJ = tdParamJ.getType();
1068 LabelNode lnParamJ = getLabelNodeFromTemp( tdParamJ );
1070 if( !i.equals( j ) && typeUtil.isSuperorType( typeI, typeJ ) ) {
1072 Integer idPrimaryJ = paramIndex2idPrimary.get( j );
1073 assert idPrimaryJ != null;
1074 HeapRegionNode primaryJ = id2hrn.get( idPrimaryJ );
1075 assert primaryJ != null;
1077 ReferenceEdge lnJ2PrimaryJ = lnParamJ.getReferenceTo( primaryJ,
1080 assert lnJ2PrimaryJ != null;
1082 ReferenceEdge lnI2PrimaryJ = lnJ2PrimaryJ.copy();
1083 lnI2PrimaryJ.setSrc( lnParamI );
1084 lnI2PrimaryJ.setType( tdParamI.getType() );
1085 lnI2PrimaryJ.tainedBy(new Integer(j));
1086 addReferenceEdge( lnParamI, primaryJ, lnI2PrimaryJ );
1092 public void prepareParamTokenMaps( FlatMethod fm ) {
1094 // always add the bogus mappings that are used to
1095 // rewrite "with respect to no parameter"
1096 paramTokenPrimary2paramIndex.put( bogusToken, bogusIndex );
1097 paramIndex2paramTokenPrimary.put( bogusIndex, bogusToken );
1099 paramTokenSecondary2paramIndex.put( bogusToken, bogusIndex );
1100 paramIndex2paramTokenSecondary.put( bogusIndex, bogusToken );
1101 paramTokenSecondaryPlus2paramIndex.put( bogusTokenPlus, bogusIndex );
1102 paramIndex2paramTokenSecondaryPlus.put( bogusIndex, bogusTokenPlus );
1103 paramTokenSecondaryStar2paramIndex.put( bogusTokenStar, bogusIndex );
1104 paramIndex2paramTokenSecondaryStar.put( bogusIndex, bogusTokenStar );
1106 for( int i = 0; i < fm.numParameters(); ++i ) {
1107 Integer paramIndex = new Integer( i );
1109 // immutable objects have no primary regions
1110 if( paramIndex2idPrimary.containsKey( paramIndex ) ) {
1111 Integer idPrimary = paramIndex2idPrimary.get( paramIndex );
1113 assert id2hrn.containsKey( idPrimary );
1114 HeapRegionNode hrnPrimary = id2hrn.get( idPrimary );
1116 TokenTuple p_i = new TokenTuple( hrnPrimary.getID(),
1117 false, // multiple-object?
1118 TokenTuple.ARITY_ONE ).makeCanonical();
1119 paramTokenPrimary2paramIndex.put( p_i, paramIndex );
1120 paramIndex2paramTokenPrimary.put( paramIndex, p_i );
1123 // any parameter object, by type, may have no secondary region
1124 if( paramIndex2idSecondary.containsKey( paramIndex ) ) {
1125 Integer idSecondary = paramIndex2idSecondary.get( paramIndex );
1127 assert id2hrn.containsKey( idSecondary );
1128 HeapRegionNode hrnSecondary = id2hrn.get( idSecondary );
1130 TokenTuple s_i = new TokenTuple( hrnSecondary.getID(),
1131 true, // multiple-object?
1132 TokenTuple.ARITY_ONE ).makeCanonical();
1133 paramTokenSecondary2paramIndex.put( s_i, paramIndex );
1134 paramIndex2paramTokenSecondary.put( paramIndex, s_i );
1136 TokenTuple s_i_plus = new TokenTuple( hrnSecondary.getID(),
1137 true, // multiple-object?
1138 TokenTuple.ARITY_ONEORMORE ).makeCanonical();
1139 paramTokenSecondaryPlus2paramIndex.put( s_i_plus, paramIndex );
1140 paramIndex2paramTokenSecondaryPlus.put( paramIndex, s_i_plus );
1142 TokenTuple s_i_star = new TokenTuple( hrnSecondary.getID(),
1143 true, // multiple-object?
1144 TokenTuple.ARITY_ZEROORMORE ).makeCanonical();
1145 paramTokenSecondaryStar2paramIndex.put( s_i_star, paramIndex );
1146 paramIndex2paramTokenSecondaryStar.put( paramIndex, s_i_star );
1153 public void assignReturnEqualToTemp(TempDescriptor x) {
1155 LabelNode lnR = getLabelNodeFromTemp(tdReturn);
1156 LabelNode lnX = getLabelNodeFromTemp(x);
1158 clearReferenceEdgesFrom(lnR, null, null, true);
1160 Iterator<ReferenceEdge> itrXhrn = lnX.iteratorToReferencees();
1161 while( itrXhrn.hasNext() ) {
1162 ReferenceEdge edgeX = itrXhrn.next();
1163 HeapRegionNode referencee = edgeX.getDst();
1164 ReferenceEdge edgeNew = edgeX.copy();
1165 edgeNew.setSrc(lnR);
1167 addReferenceEdge(lnR, referencee, edgeNew);
1172 public void assignTempEqualToNewAlloc(TempDescriptor x,
1173 AllocationSite as) {
1179 // after the age operation the newest (or zero-ith oldest)
1180 // node associated with the allocation site should have
1181 // no references to it as if it were a newly allocated
1183 Integer idNewest = as.getIthOldest( 0 );
1184 HeapRegionNode hrnNewest = id2hrn.get( idNewest );
1185 assert hrnNewest != null;
1187 LabelNode lnX = getLabelNodeFromTemp( x );
1188 clearReferenceEdgesFrom( lnX, null, null, true );
1190 // make a new reference to allocated node
1191 TypeDescriptor type = as.getType();
1192 ReferenceEdge edgeNew =
1193 new ReferenceEdge( lnX, // source
1197 false, // is initial param
1198 hrnNewest.getAlpha() // beta
1201 addReferenceEdge( lnX, hrnNewest, edgeNew );
1205 // use the allocation site (unique to entire analysis) to
1206 // locate the heap region nodes in this ownership graph
1207 // that should be aged. The process models the allocation
1208 // of new objects and collects all the oldest allocations
1209 // in a summary node to allow for a finite analysis
1211 // There is an additional property of this method. After
1212 // running it on a particular ownership graph (many graphs
1213 // may have heap regions related to the same allocation site)
1214 // the heap region node objects in this ownership graph will be
1215 // allocated. Therefore, after aging a graph for an allocation
1216 // site, attempts to retrieve the heap region nodes using the
1217 // integer id's contained in the allocation site should always
1218 // return non-null heap regions.
1219 public void age(AllocationSite as) {
1221 // aging adds this allocation site to the graph's
1222 // list of sites that exist in the graph, or does
1223 // nothing if the site is already in the list
1224 allocationSites.add(as);
1226 // get the summary node for the allocation site in the context
1227 // of this particular ownership graph
1228 HeapRegionNode hrnSummary = getSummaryNode(as);
1230 // merge oldest node into summary
1231 Integer idK = as.getOldest();
1232 HeapRegionNode hrnK = id2hrn.get(idK);
1233 mergeIntoSummary(hrnK, hrnSummary);
1235 // move down the line of heap region nodes
1236 // clobbering the ith and transferring all references
1237 // to and from i-1 to node i. Note that this clobbers
1238 // the oldest node (hrnK) that was just merged into
1240 for( int i = allocationDepth - 1; i > 0; --i ) {
1242 // move references from the i-1 oldest to the ith oldest
1243 Integer idIth = as.getIthOldest(i);
1244 HeapRegionNode hrnI = id2hrn.get(idIth);
1245 Integer idImin1th = as.getIthOldest(i - 1);
1246 HeapRegionNode hrnImin1 = id2hrn.get(idImin1th);
1248 transferOnto(hrnImin1, hrnI);
1251 // as stated above, the newest node should have had its
1252 // references moved over to the second oldest, so we wipe newest
1253 // in preparation for being the new object to assign something to
1254 Integer id0th = as.getIthOldest(0);
1255 HeapRegionNode hrn0 = id2hrn.get(id0th);
1256 assert hrn0 != null;
1258 // clear all references in and out of newest node
1259 clearReferenceEdgesFrom(hrn0, null, null, true);
1260 clearReferenceEdgesTo(hrn0, null, null, true);
1263 // now tokens in reachability sets need to "age" also
1264 Iterator itrAllLabelNodes = td2ln.entrySet().iterator();
1265 while( itrAllLabelNodes.hasNext() ) {
1266 Map.Entry me = (Map.Entry)itrAllLabelNodes.next();
1267 LabelNode ln = (LabelNode) me.getValue();
1269 Iterator<ReferenceEdge> itrEdges = ln.iteratorToReferencees();
1270 while( itrEdges.hasNext() ) {
1271 ageTokens(as, itrEdges.next() );
1275 Iterator itrAllHRNodes = id2hrn.entrySet().iterator();
1276 while( itrAllHRNodes.hasNext() ) {
1277 Map.Entry me = (Map.Entry)itrAllHRNodes.next();
1278 HeapRegionNode hrnToAge = (HeapRegionNode) me.getValue();
1280 ageTokens(as, hrnToAge);
1282 Iterator<ReferenceEdge> itrEdges = hrnToAge.iteratorToReferencees();
1283 while( itrEdges.hasNext() ) {
1284 ageTokens(as, itrEdges.next() );
1289 // after tokens have been aged, reset newest node's reachability
1290 if( hrn0.isFlagged() ) {
1291 hrn0.setAlpha(new ReachabilitySet(
1293 new TokenTuple(hrn0).makeCanonical()
1298 hrn0.setAlpha(new ReachabilitySet(
1299 new TokenTupleSet().makeCanonical()
1306 protected HeapRegionNode getSummaryNode(AllocationSite as) {
1308 Integer idSummary = as.getSummary();
1309 HeapRegionNode hrnSummary = id2hrn.get(idSummary);
1311 // If this is null then we haven't touched this allocation site
1312 // in the context of the current ownership graph, so allocate
1313 // heap region nodes appropriate for the entire allocation site.
1314 // This should only happen once per ownership graph per allocation site,
1315 // and a particular integer id can be used to locate the heap region
1316 // in different ownership graphs that represents the same part of an
1318 if( hrnSummary == null ) {
1320 boolean hasFlags = false;
1321 if( as.getType().isClass() ) {
1322 hasFlags = as.getType().getClassDesc().hasFlags();
1325 hrnSummary = createNewHeapRegionNode(idSummary, // id or null to generate a new one
1326 false, // single object?
1328 hasFlags, // flagged?
1329 false, // is a parameter?
1330 as.getType(), // type
1331 as, // allocation site
1332 null, // reachability set
1333 as.toStringForDOT() + "\\nsummary");
1335 for( int i = 0; i < as.getAllocationDepth(); ++i ) {
1336 Integer idIth = as.getIthOldest(i);
1337 assert !id2hrn.containsKey(idIth);
1338 createNewHeapRegionNode(idIth, // id or null to generate a new one
1339 true, // single object?
1341 hasFlags, // flagged?
1342 false, // is a parameter?
1343 as.getType(), // type
1344 as, // allocation site
1345 null, // reachability set
1346 as.toStringForDOT() + "\\n" + i + " oldest");
1354 protected HeapRegionNode getShadowSummaryNode(AllocationSite as) {
1356 Integer idShadowSummary = as.getSummaryShadow();
1357 HeapRegionNode hrnShadowSummary = id2hrn.get(idShadowSummary);
1359 if( hrnShadowSummary == null ) {
1361 boolean hasFlags = false;
1362 if( as.getType().isClass() ) {
1363 hasFlags = as.getType().getClassDesc().hasFlags();
1366 hrnShadowSummary = createNewHeapRegionNode(idShadowSummary, // id or null to generate a new one
1367 false, // single object?
1369 hasFlags, // flagged?
1370 false, // is a parameter?
1371 as.getType(), // type
1372 as, // allocation site
1373 null, // reachability set
1374 as + "\\n" + as.getType() + "\\nshadowSum");
1376 for( int i = 0; i < as.getAllocationDepth(); ++i ) {
1377 Integer idShadowIth = as.getIthOldestShadow(i);
1378 assert !id2hrn.containsKey(idShadowIth);
1379 createNewHeapRegionNode(idShadowIth, // id or null to generate a new one
1380 true, // single object?
1382 hasFlags, // flagged?
1383 false, // is a parameter?
1384 as.getType(), // type
1385 as, // allocation site
1386 null, // reachability set
1387 as + "\\n" + as.getType() + "\\n" + i + " shadow");
1391 return hrnShadowSummary;
1395 protected void mergeIntoSummary(HeapRegionNode hrn, HeapRegionNode hrnSummary) {
1396 assert hrnSummary.isNewSummary();
1398 // transfer references _from_ hrn over to hrnSummary
1399 Iterator<ReferenceEdge> itrReferencee = hrn.iteratorToReferencees();
1400 while( itrReferencee.hasNext() ) {
1401 ReferenceEdge edge = itrReferencee.next();
1402 ReferenceEdge edgeMerged = edge.copy();
1403 edgeMerged.setSrc(hrnSummary);
1405 HeapRegionNode hrnReferencee = edge.getDst();
1406 ReferenceEdge edgeSummary = hrnSummary.getReferenceTo(hrnReferencee,
1410 if( edgeSummary == null ) {
1411 // the merge is trivial, nothing to be done
1413 // otherwise an edge from the referencer to hrnSummary exists already
1414 // and the edge referencer->hrn should be merged with it
1415 edgeMerged.setBeta(edgeMerged.getBeta().union(edgeSummary.getBeta() ) );
1418 addReferenceEdge(hrnSummary, hrnReferencee, edgeMerged);
1421 // next transfer references _to_ hrn over to hrnSummary
1422 Iterator<ReferenceEdge> itrReferencer = hrn.iteratorToReferencers();
1423 while( itrReferencer.hasNext() ) {
1424 ReferenceEdge edge = itrReferencer.next();
1425 ReferenceEdge edgeMerged = edge.copy();
1426 edgeMerged.setDst(hrnSummary);
1428 OwnershipNode onReferencer = edge.getSrc();
1429 ReferenceEdge edgeSummary = onReferencer.getReferenceTo(hrnSummary,
1433 if( edgeSummary == null ) {
1434 // the merge is trivial, nothing to be done
1436 // otherwise an edge from the referencer to alpha_S exists already
1437 // and the edge referencer->alpha_K should be merged with it
1438 edgeMerged.setBeta(edgeMerged.getBeta().union(edgeSummary.getBeta() ) );
1441 addReferenceEdge(onReferencer, hrnSummary, edgeMerged);
1444 // then merge hrn reachability into hrnSummary
1445 hrnSummary.setAlpha(hrnSummary.getAlpha().union(hrn.getAlpha() ) );
1449 protected void transferOnto(HeapRegionNode hrnA, HeapRegionNode hrnB) {
1451 // clear references in and out of node b
1452 clearReferenceEdgesFrom(hrnB, null, null, true);
1453 clearReferenceEdgesTo(hrnB, null, null, true);
1455 // copy each edge in and out of A to B
1456 Iterator<ReferenceEdge> itrReferencee = hrnA.iteratorToReferencees();
1457 while( itrReferencee.hasNext() ) {
1458 ReferenceEdge edge = itrReferencee.next();
1459 HeapRegionNode hrnReferencee = edge.getDst();
1460 ReferenceEdge edgeNew = edge.copy();
1461 edgeNew.setSrc(hrnB);
1463 addReferenceEdge(hrnB, hrnReferencee, edgeNew);
1466 Iterator<ReferenceEdge> itrReferencer = hrnA.iteratorToReferencers();
1467 while( itrReferencer.hasNext() ) {
1468 ReferenceEdge edge = itrReferencer.next();
1469 OwnershipNode onReferencer = edge.getSrc();
1470 ReferenceEdge edgeNew = edge.copy();
1471 edgeNew.setDst(hrnB);
1473 addReferenceEdge(onReferencer, hrnB, edgeNew);
1476 // replace hrnB reachability with hrnA's
1477 hrnB.setAlpha(hrnA.getAlpha() );
1481 protected void ageTokens(AllocationSite as, ReferenceEdge edge) {
1482 edge.setBeta(edge.getBeta().ageTokens(as) );
1485 protected void ageTokens(AllocationSite as, HeapRegionNode hrn) {
1486 hrn.setAlpha(hrn.getAlpha().ageTokens(as) );
1491 protected void propagateTokensOverNodes(HeapRegionNode nPrime,
1493 HashSet<HeapRegionNode> nodesWithNewAlpha,
1494 HashSet<ReferenceEdge> edgesWithNewBeta) {
1496 HashSet<HeapRegionNode> todoNodes
1497 = new HashSet<HeapRegionNode>();
1498 todoNodes.add(nPrime);
1500 HashSet<ReferenceEdge> todoEdges
1501 = new HashSet<ReferenceEdge>();
1503 Hashtable<HeapRegionNode, ChangeTupleSet> nodePlannedChanges
1504 = new Hashtable<HeapRegionNode, ChangeTupleSet>();
1505 nodePlannedChanges.put(nPrime, c0);
1507 Hashtable<ReferenceEdge, ChangeTupleSet> edgePlannedChanges
1508 = new Hashtable<ReferenceEdge, ChangeTupleSet>();
1510 // first propagate change sets everywhere they can go
1511 while( !todoNodes.isEmpty() ) {
1512 HeapRegionNode n = todoNodes.iterator().next();
1513 ChangeTupleSet C = nodePlannedChanges.get(n);
1515 Iterator<ReferenceEdge> referItr = n.iteratorToReferencers();
1516 while( referItr.hasNext() ) {
1517 ReferenceEdge edge = referItr.next();
1518 todoEdges.add(edge);
1520 if( !edgePlannedChanges.containsKey(edge) ) {
1521 edgePlannedChanges.put(edge, new ChangeTupleSet().makeCanonical() );
1524 edgePlannedChanges.put(edge, edgePlannedChanges.get(edge).union(C) );
1527 Iterator<ReferenceEdge> refeeItr = n.iteratorToReferencees();
1528 while( refeeItr.hasNext() ) {
1529 ReferenceEdge edgeF = refeeItr.next();
1530 HeapRegionNode m = edgeF.getDst();
1532 ChangeTupleSet changesToPass = new ChangeTupleSet().makeCanonical();
1534 Iterator<ChangeTuple> itrCprime = C.iterator();
1535 while( itrCprime.hasNext() ) {
1536 ChangeTuple c = itrCprime.next();
1537 if( edgeF.getBeta().contains( c.getSetToMatch() ) ) {
1538 changesToPass = changesToPass.union(c);
1542 if( !changesToPass.isEmpty() ) {
1543 if( !nodePlannedChanges.containsKey(m) ) {
1544 nodePlannedChanges.put(m, new ChangeTupleSet().makeCanonical() );
1547 ChangeTupleSet currentChanges = nodePlannedChanges.get(m);
1549 if( !changesToPass.isSubset(currentChanges) ) {
1551 nodePlannedChanges.put(m, currentChanges.union(changesToPass) );
1557 todoNodes.remove(n);
1560 // then apply all of the changes for each node at once
1561 Iterator itrMap = nodePlannedChanges.entrySet().iterator();
1562 while( itrMap.hasNext() ) {
1563 Map.Entry me = (Map.Entry) itrMap.next();
1564 HeapRegionNode n = (HeapRegionNode) me.getKey();
1565 ChangeTupleSet C = (ChangeTupleSet) me.getValue();
1567 n.setAlphaNew( n.getAlpha().applyChangeSet( C, true ) );
1568 nodesWithNewAlpha.add( n );
1571 propagateTokensOverEdges(todoEdges, edgePlannedChanges, edgesWithNewBeta);
1575 protected void propagateTokensOverEdges(
1576 HashSet<ReferenceEdge> todoEdges,
1577 Hashtable<ReferenceEdge, ChangeTupleSet> edgePlannedChanges,
1578 HashSet<ReferenceEdge> edgesWithNewBeta) {
1580 // first propagate all change tuples everywhere they can go
1581 while( !todoEdges.isEmpty() ) {
1582 ReferenceEdge edgeE = todoEdges.iterator().next();
1583 todoEdges.remove(edgeE);
1585 if( !edgePlannedChanges.containsKey(edgeE) ) {
1586 edgePlannedChanges.put(edgeE, new ChangeTupleSet().makeCanonical() );
1589 ChangeTupleSet C = edgePlannedChanges.get(edgeE);
1591 ChangeTupleSet changesToPass = new ChangeTupleSet().makeCanonical();
1593 Iterator<ChangeTuple> itrC = C.iterator();
1594 while( itrC.hasNext() ) {
1595 ChangeTuple c = itrC.next();
1596 if( edgeE.getBeta().contains( c.getSetToMatch() ) ) {
1597 changesToPass = changesToPass.union(c);
1601 OwnershipNode onSrc = edgeE.getSrc();
1603 if( !changesToPass.isEmpty() && onSrc instanceof HeapRegionNode ) {
1604 HeapRegionNode n = (HeapRegionNode) onSrc;
1606 Iterator<ReferenceEdge> referItr = n.iteratorToReferencers();
1607 while( referItr.hasNext() ) {
1608 ReferenceEdge edgeF = referItr.next();
1610 if( !edgePlannedChanges.containsKey(edgeF) ) {
1611 edgePlannedChanges.put(edgeF, new ChangeTupleSet().makeCanonical() );
1614 ChangeTupleSet currentChanges = edgePlannedChanges.get(edgeF);
1616 if( !changesToPass.isSubset(currentChanges) ) {
1617 todoEdges.add(edgeF);
1618 edgePlannedChanges.put(edgeF, currentChanges.union(changesToPass) );
1624 // then apply all of the changes for each edge at once
1625 Iterator itrMap = edgePlannedChanges.entrySet().iterator();
1626 while( itrMap.hasNext() ) {
1627 Map.Entry me = (Map.Entry) itrMap.next();
1628 ReferenceEdge e = (ReferenceEdge) me.getKey();
1629 ChangeTupleSet C = (ChangeTupleSet) me.getValue();
1631 e.setBetaNew( e.getBetaNew().union( e.getBeta().applyChangeSet( C, true ) ) );
1632 edgesWithNewBeta.add( e );
1637 public Set<Integer> calculateAliasedParamSet( FlatCall fc,
1641 Hashtable<Integer, LabelNode> paramIndex2ln =
1642 new Hashtable<Integer, LabelNode>();
1644 Hashtable<Integer, HashSet<HeapRegionNode> > paramIndex2reachableCallerNodes =
1645 new Hashtable<Integer, HashSet<HeapRegionNode> >();
1647 for( int i = 0; i < fm.numParameters(); ++i ) {
1648 Integer paramIndex = new Integer( i );
1649 TempDescriptor tdParam = fm.getParameter( i );
1650 TypeDescriptor typeParam = tdParam.getType();
1652 if( typeParam.isImmutable() && !typeParam.isArray() ) {
1653 // don't bother with this primitive parameter, it
1654 // cannot affect reachability
1658 // now depending on whether the callee is static or not
1659 // we need to account for a "this" argument in order to
1660 // find the matching argument in the caller context
1661 TempDescriptor argTemp_i;
1663 argTemp_i = fc.getArg(paramIndex);
1665 if( paramIndex.equals(0) ) {
1666 argTemp_i = fc.getThis();
1668 argTemp_i = fc.getArg(paramIndex - 1);
1672 // in non-static methods there is a "this" pointer
1673 // that should be taken into account
1675 assert fc.numArgs() == fm.numParameters();
1677 assert fc.numArgs() + 1 == fm.numParameters();
1680 LabelNode argLabel_i = getLabelNodeFromTemp(argTemp_i);
1681 paramIndex2ln.put(paramIndex, argLabel_i);
1684 Iterator lnArgItr = paramIndex2ln.entrySet().iterator();
1685 while( lnArgItr.hasNext() ) {
1686 Map.Entry me = (Map.Entry)lnArgItr.next();
1687 Integer index = (Integer) me.getKey();
1688 LabelNode lnArg_i = (LabelNode) me.getValue();
1690 HashSet<HeapRegionNode> reachableNodes = new HashSet<HeapRegionNode>();
1691 HashSet<HeapRegionNode> todoNodes = new HashSet<HeapRegionNode>();
1693 // to find all reachable nodes, start with label referencees
1694 Iterator<ReferenceEdge> edgeArgItr = lnArg_i.iteratorToReferencees();
1695 while( edgeArgItr.hasNext() ) {
1696 ReferenceEdge edge = edgeArgItr.next();
1697 todoNodes.add( edge.getDst() );
1700 // then follow links until all reachable nodes have been found
1701 while( !todoNodes.isEmpty() ) {
1702 HeapRegionNode hrn = todoNodes.iterator().next();
1703 todoNodes.remove(hrn);
1704 reachableNodes.add(hrn);
1706 Iterator<ReferenceEdge> edgeItr = hrn.iteratorToReferencees();
1707 while( edgeItr.hasNext() ) {
1708 ReferenceEdge edge = edgeItr.next();
1710 if( !reachableNodes.contains(edge.getDst() ) ) {
1711 todoNodes.add(edge.getDst() );
1717 paramIndex2reachableCallerNodes.put(index, reachableNodes);
1720 Set<Integer> aliasedIndices = new HashSet<Integer>();
1722 // check for arguments that are aliased
1723 for( int i = 0; i < fm.numParameters(); ++i ) {
1724 for( int j = 0; j < i; ++j ) {
1725 HashSet<HeapRegionNode> s1 = paramIndex2reachableCallerNodes.get( i );
1726 HashSet<HeapRegionNode> s2 = paramIndex2reachableCallerNodes.get( j );
1728 // some parameters are immutable or primitive, so skip em
1729 if( s1 == null || s2 == null ) {
1733 Set<HeapRegionNode> intersection = new HashSet<HeapRegionNode>(s1);
1734 intersection.retainAll(s2);
1736 if( !intersection.isEmpty() ) {
1737 aliasedIndices.add( new Integer( i ) );
1738 aliasedIndices.add( new Integer( j ) );
1743 return aliasedIndices;
1747 private String makeMapKey( Integer i, Integer j, String field ) {
1748 return i+","+j+","+field;
1751 private String makeMapKey( Integer i, String field ) {
1755 // these hashtables are used during the mapping procedure to say that
1756 // with respect to some argument i there is an edge placed into some
1757 // category for mapping with respect to another argument index j
1758 // so the key into the hashtable is i, the value is a two-element vector
1759 // that contains in 0 the edge and in 1 the Integer index j
1760 private void ensureEmptyEdgeIndexPair( Hashtable< Integer, Set<Vector> > edge_index_pairs,
1763 Set<Vector> ei = edge_index_pairs.get( indexI );
1765 ei = new HashSet<Vector>();
1767 edge_index_pairs.put( indexI, ei );
1770 private void addEdgeIndexPair( Hashtable< Integer, Set<Vector> > edge_index_pairs,
1775 Vector v = new Vector(); v.setSize( 2 );
1777 v.set( 1 , indexJ );
1778 Set<Vector> ei = edge_index_pairs.get( indexI );
1780 ei = new HashSet<Vector>();
1783 edge_index_pairs.put( indexI, ei );
1786 private ReachabilitySet funcScriptR( ReachabilitySet rsIn,
1787 OwnershipGraph ogCallee,
1788 MethodContext mc ) {
1790 ReachabilitySet rsOut = new ReachabilitySet( rsIn );
1792 Iterator itr = ogCallee.paramIndex2paramTokenPrimary.entrySet().iterator();
1793 while( itr.hasNext() ) {
1794 Map.Entry me = (Map.Entry) itr.next();
1795 Integer i = (Integer) me.getKey();
1796 TokenTuple p_i = (TokenTuple) me.getValue();
1797 TokenTuple s_i = ogCallee.paramIndex2paramTokenSecondary.get( i );
1799 // skip this if there is no secondary token or the parameter
1800 // is part of the aliasing context
1801 if( s_i == null || mc.getAliasedParamIndices().contains( i ) ) {
1805 rsOut = rsOut.removeTokenAIfTokenB( p_i, s_i );
1811 // detects strong updates to the primary parameter object and
1812 // effects the removal of old edges in the calling graph
1813 private void effectCalleeStrongUpdates( Integer paramIndex,
1814 OwnershipGraph ogCallee,
1815 HeapRegionNode hrnCaller
1817 Integer idPrimary = ogCallee.paramIndex2idPrimary.get( paramIndex );
1818 assert idPrimary != null;
1820 HeapRegionNode hrnPrimary = ogCallee.id2hrn.get( idPrimary );
1821 assert hrnPrimary != null;
1823 TypeDescriptor typeParam = hrnPrimary.getType();
1824 assert typeParam.isClass();
1826 Set<String> fieldNamesToRemove = new HashSet<String>();
1828 ClassDescriptor cd = typeParam.getClassDesc();
1829 while( cd != null ) {
1831 Iterator fieldItr = cd.getFields();
1832 while( fieldItr.hasNext() ) {
1834 FieldDescriptor fd = (FieldDescriptor) fieldItr.next();
1835 TypeDescriptor typeField = fd.getType();
1836 assert typeField != null;
1838 if( ogCallee.hasFieldBeenUpdated( hrnPrimary, fd.getSymbol() ) ) {
1839 clearReferenceEdgesFrom( hrnCaller, fd.getType(), fd.getSymbol(), false );
1843 cd = cd.getSuperDesc();
1847 private boolean hasFieldBeenUpdated( HeapRegionNode hrnPrimary, String field ) {
1849 Iterator<ReferenceEdge> itr = hrnPrimary.iteratorToReferencees();
1850 while( itr.hasNext() ) {
1851 ReferenceEdge e = itr.next();
1852 if( e.fieldEquals( field ) && e.isInitialParam() ) {
1860 // resolveMethodCall() is used to incorporate a callee graph's effects into
1861 // *this* graph, which is the caller. This method can also be used, after
1862 // the entire analysis is complete, to perform parameter decomposition for
1863 // a given call chain.
1864 public void resolveMethodCall(FlatCall fc, // call site in caller method
1865 boolean isStatic, // whether it is a static method
1866 FlatMethod fm, // the callee method (when virtual, can be many)
1867 OwnershipGraph ogCallee, // the callee's current ownership graph
1868 MethodContext mc, // the aliasing context for this call
1869 ParameterDecomposition pd // if this is not null, we're calling after analysis
1873 // this debug snippet is harmless for regular use and INVALUABLE at debug time
1874 // to see what potentially goes wrong when a specific method calls another
1875 String debugCaller = "foo";
1876 String debugCallee = "bar";
1877 //String debugCaller = "StandardEngine";
1878 //String debugCaller = "register_by_type";
1879 //String debugCaller = "register_by_type_front";
1880 //String debugCaller = "addFirst";
1881 //String debugCallee = "LinkedListElement";
1883 if( mc.getDescriptor().getSymbol().equals( debugCaller ) &&
1884 fm.getMethod().getSymbol().equals( debugCallee ) ) {
1887 writeGraph( "debug1BeforeCall", true, true, true, false, false );
1888 ogCallee.writeGraph( "debug0Callee", true, true, true, false, false );
1889 } catch( IOException e ) {}
1891 System.out.println( " "+mc+" is calling "+fm );
1896 // define rewrite rules and other structures to organize data by parameter/argument index
1897 Hashtable<Integer, ReachabilitySet> paramIndex2rewriteH_p = new Hashtable<Integer, ReachabilitySet>();
1898 Hashtable<Integer, ReachabilitySet> paramIndex2rewriteH_s = new Hashtable<Integer, ReachabilitySet>();
1900 Hashtable<String, ReachabilitySet> paramIndex2rewriteJ_p2p = new Hashtable<String, ReachabilitySet>(); // select( i, j, f )
1901 Hashtable<String, ReachabilitySet> paramIndex2rewriteJ_p2s = new Hashtable<String, ReachabilitySet>(); // select( i, f )
1902 Hashtable<Integer, ReachabilitySet> paramIndex2rewriteJ_s2p = new Hashtable<Integer, ReachabilitySet>();
1903 Hashtable<Integer, ReachabilitySet> paramIndex2rewriteJ_s2s = new Hashtable<Integer, ReachabilitySet>();
1905 Hashtable<Integer, ReachabilitySet> paramIndex2rewriteK_p = new Hashtable<Integer, ReachabilitySet>();
1906 Hashtable<Integer, ReachabilitySet> paramIndex2rewriteK_p2 = new Hashtable<Integer, ReachabilitySet>();
1907 Hashtable<Integer, ReachabilitySet> paramIndex2rewriteK_s = new Hashtable<Integer, ReachabilitySet>();
1909 Hashtable<Integer, ReachabilitySet> paramIndex2rewrite_d_p = new Hashtable<Integer, ReachabilitySet>();
1910 Hashtable<Integer, ReachabilitySet> paramIndex2rewrite_d_s = new Hashtable<Integer, ReachabilitySet>();
1912 Hashtable<Integer, ReachabilitySet> paramIndex2rewriteD = new Hashtable<Integer, ReachabilitySet>();
1915 Hashtable<Integer, LabelNode> paramIndex2ln = new Hashtable<Integer, LabelNode>();
1918 paramIndex2rewriteH_p.put( bogusIndex, rsIdentity );
1919 paramIndex2rewriteH_s.put( bogusIndex, rsIdentity );
1921 paramIndex2rewriteJ_p2p.put( bogusIndex.toString(), rsIdentity );
1922 paramIndex2rewriteJ_p2s.put( bogusIndex.toString(), rsIdentity );
1923 paramIndex2rewriteJ_s2p.put( bogusIndex, rsIdentity );
1924 paramIndex2rewriteJ_s2s.put( bogusIndex, rsIdentity );
1927 for( int i = 0; i < fm.numParameters(); ++i ) {
1928 Integer paramIndex = new Integer(i);
1930 if( !ogCallee.paramIndex2idPrimary.containsKey( paramIndex ) ) {
1931 // skip this immutable parameter
1935 // setup H (primary)
1936 Integer idPrimary = ogCallee.paramIndex2idPrimary.get( paramIndex );
1937 assert ogCallee.id2hrn.containsKey( idPrimary );
1938 HeapRegionNode hrnPrimary = ogCallee.id2hrn.get( idPrimary );
1939 assert hrnPrimary != null;
1940 paramIndex2rewriteH_p.put( paramIndex, toShadowTokens( ogCallee, hrnPrimary.getAlpha() ) );
1942 // setup J (primary->X)
1943 Iterator<ReferenceEdge> p2xItr = hrnPrimary.iteratorToReferencees();
1944 while( p2xItr.hasNext() ) {
1945 ReferenceEdge p2xEdge = p2xItr.next();
1947 // we only care about initial parameter edges here
1948 if( !p2xEdge.isInitialParam() ) { continue; }
1950 HeapRegionNode hrnDst = p2xEdge.getDst();
1952 if( ogCallee.idPrimary2paramIndexSet.containsKey( hrnDst.getID() ) ) {
1953 Iterator<Integer> jItr = ogCallee.idPrimary2paramIndexSet.get( hrnDst.getID() ).iterator();
1954 while( jItr.hasNext() ) {
1955 Integer j = jItr.next();
1956 paramIndex2rewriteJ_p2p.put( makeMapKey( i, j, p2xEdge.getField() ),
1957 toShadowTokens( ogCallee, p2xEdge.getBeta() ) );
1961 assert ogCallee.idSecondary2paramIndexSet.containsKey( hrnDst.getID() );
1962 paramIndex2rewriteJ_p2s.put( makeMapKey( i, p2xEdge.getField() ),
1963 toShadowTokens( ogCallee, p2xEdge.getBeta() ) );
1967 // setup K (primary)
1968 TempDescriptor tdParamQ = ogCallee.paramIndex2tdQ.get( paramIndex );
1969 assert tdParamQ != null;
1970 LabelNode lnParamQ = ogCallee.td2ln.get( tdParamQ );
1971 assert lnParamQ != null;
1972 ReferenceEdge edgeSpecialQ_i = lnParamQ.getReferenceTo( hrnPrimary, null, null );
1973 assert edgeSpecialQ_i != null;
1974 ReachabilitySet qBeta = toShadowTokens( ogCallee, edgeSpecialQ_i.getBeta() );
1976 TokenTuple p_i = ogCallee.paramIndex2paramTokenPrimary .get( paramIndex );
1977 TokenTuple s_i = ogCallee.paramIndex2paramTokenSecondary.get( paramIndex );
1979 ReachabilitySet K_p = new ReachabilitySet().makeCanonical();
1980 ReachabilitySet K_p2 = new ReachabilitySet().makeCanonical();
1984 // sort qBeta into K_p1 and K_p2
1985 Iterator<TokenTupleSet> ttsItr = qBeta.iterator();
1986 while( ttsItr.hasNext() ) {
1987 TokenTupleSet tts = ttsItr.next();
1988 if( s_i != null && tts.containsBoth( p_i, s_i ) ) {
1989 K_p2 = K_p2.union( tts );
1991 K_p = K_p.union( tts );
1995 paramIndex2rewriteK_p .put( paramIndex, K_p );
1996 paramIndex2rewriteK_p2.put( paramIndex, K_p2 );
1999 // if there is a secondary node, compute the rest of the rewrite rules
2000 if( ogCallee.paramIndex2idSecondary.containsKey( paramIndex ) ) {
2002 // setup H (secondary)
2003 Integer idSecondary = ogCallee.paramIndex2idSecondary.get( paramIndex );
2004 assert ogCallee.id2hrn.containsKey( idSecondary );
2005 HeapRegionNode hrnSecondary = ogCallee.id2hrn.get( idSecondary );
2006 assert hrnSecondary != null;
2007 paramIndex2rewriteH_s.put( paramIndex, toShadowTokens( ogCallee, hrnSecondary.getAlpha() ) );
2010 // setup J (secondary->X)
2011 Iterator<ReferenceEdge> s2xItr = hrnSecondary.iteratorToReferencees();
2012 while( s2xItr.hasNext() ) {
2013 ReferenceEdge s2xEdge = s2xItr.next();
2015 if( !s2xEdge.isInitialParam() ) { continue; }
2017 HeapRegionNode hrnDst = s2xEdge.getDst();
2019 if( ogCallee.idPrimary2paramIndexSet.containsKey( hrnDst.getID() ) ) {
2020 Iterator<Integer> jItr = ogCallee.idPrimary2paramIndexSet.get( hrnDst.getID() ).iterator();
2021 while( jItr.hasNext() ) {
2022 Integer j = jItr.next();
2023 paramIndex2rewriteJ_s2p.put( i, toShadowTokens( ogCallee, s2xEdge.getBeta() ) );
2027 assert ogCallee.idSecondary2paramIndexSet.containsKey( hrnDst.getID() );
2028 paramIndex2rewriteJ_s2s.put( i, toShadowTokens( ogCallee, s2xEdge.getBeta() ) );
2032 // setup K (secondary)
2033 TempDescriptor tdParamR = ogCallee.paramIndex2tdR.get( paramIndex );
2034 assert tdParamR != null;
2035 LabelNode lnParamR = ogCallee.td2ln.get( tdParamR );
2036 assert lnParamR != null;
2037 ReferenceEdge edgeSpecialR_i = lnParamR.getReferenceTo( hrnSecondary, null, null );
2038 assert edgeSpecialR_i != null;
2039 paramIndex2rewriteK_s.put( paramIndex,
2040 toShadowTokens( ogCallee, edgeSpecialR_i.getBeta() ) );
2044 // now depending on whether the callee is static or not
2045 // we need to account for a "this" argument in order to
2046 // find the matching argument in the caller context
2047 TempDescriptor argTemp_i;
2049 argTemp_i = fc.getArg( paramIndex );
2051 if( paramIndex.equals( 0 ) ) {
2052 argTemp_i = fc.getThis();
2054 argTemp_i = fc.getArg( paramIndex - 1 );
2058 // in non-static methods there is a "this" pointer
2059 // that should be taken into account
2061 assert fc.numArgs() == fm.numParameters();
2063 assert fc.numArgs() + 1 == fm.numParameters();
2066 // remember which caller arg label maps to param index
2067 LabelNode argLabel_i = getLabelNodeFromTemp( argTemp_i );
2068 paramIndex2ln.put( paramIndex, argLabel_i );
2070 // do a callee-effect strong update pre-pass here
2071 if( argTemp_i.getType().isClass() ) {
2073 Iterator<ReferenceEdge> edgeItr = argLabel_i.iteratorToReferencees();
2074 while( edgeItr.hasNext() ) {
2075 ReferenceEdge edge = edgeItr.next();
2076 HeapRegionNode hrn = edge.getDst();
2078 if( (hrn.getNumReferencers() == 1) || // case 1
2079 (hrn.isSingleObject() && argLabel_i.getNumReferencees() == 1) // case 2
2082 effectCalleeStrongUpdates( paramIndex, ogCallee, hrn );
2087 // then calculate the d and D rewrite rules
2088 ReachabilitySet d_i_p = new ReachabilitySet().makeCanonical();
2089 ReachabilitySet d_i_s = new ReachabilitySet().makeCanonical();
2090 Iterator<ReferenceEdge> edgeItr = argLabel_i.iteratorToReferencees();
2091 while( edgeItr.hasNext() ) {
2092 ReferenceEdge edge = edgeItr.next();
2094 d_i_p = d_i_p.union( edge.getBeta().intersection( edge.getDst().getAlpha() ) );
2095 d_i_s = d_i_s.union( edge.getBeta() );
2097 paramIndex2rewrite_d_p.put( paramIndex, d_i_p );
2098 paramIndex2rewrite_d_s.put( paramIndex, d_i_s );
2100 // TODO: we should only do this when we need it, and then
2101 // memoize it for the rest of the mapping procedure
2102 ReachabilitySet D_i = d_i_s.exhaustiveArityCombinations();
2103 paramIndex2rewriteD.put( paramIndex, D_i );
2107 // with respect to each argument, map parameter effects into caller
2108 HashSet<HeapRegionNode> nodesWithNewAlpha = new HashSet<HeapRegionNode>();
2109 HashSet<ReferenceEdge> edgesWithNewBeta = new HashSet<ReferenceEdge>();
2111 Hashtable<Integer, Set<HeapRegionNode> > pi2dr =
2112 new Hashtable<Integer, Set<HeapRegionNode> >();
2114 Hashtable<Integer, Set<HeapRegionNode> > pi2r =
2115 new Hashtable<Integer, Set<HeapRegionNode> >();
2117 Set<HeapRegionNode> defParamObj = new HashSet<HeapRegionNode>();
2119 Iterator lnArgItr = paramIndex2ln.entrySet().iterator();
2120 while( lnArgItr.hasNext() ) {
2121 Map.Entry me = (Map.Entry) lnArgItr.next();
2122 Integer index = (Integer) me.getKey();
2123 LabelNode lnArg_i = (LabelNode) me.getValue();
2125 Set<HeapRegionNode> dr = new HashSet<HeapRegionNode>();
2126 Set<HeapRegionNode> r = new HashSet<HeapRegionNode>();
2127 Set<HeapRegionNode> todo = new HashSet<HeapRegionNode>();
2129 // find all reachable nodes starting with label referencees
2130 Iterator<ReferenceEdge> edgeArgItr = lnArg_i.iteratorToReferencees();
2131 while( edgeArgItr.hasNext() ) {
2132 ReferenceEdge edge = edgeArgItr.next();
2133 HeapRegionNode hrn = edge.getDst();
2137 if( lnArg_i.getNumReferencees() == 1 && hrn.isSingleObject() ) {
2138 defParamObj.add( hrn );
2141 Iterator<ReferenceEdge> edgeHrnItr = hrn.iteratorToReferencees();
2142 while( edgeHrnItr.hasNext() ) {
2143 ReferenceEdge edger = edgeHrnItr.next();
2144 todo.add( edger.getDst() );
2147 // then follow links until all reachable nodes have been found
2148 while( !todo.isEmpty() ) {
2149 HeapRegionNode hrnr = todo.iterator().next();
2150 todo.remove( hrnr );
2154 Iterator<ReferenceEdge> edgeItr = hrnr.iteratorToReferencees();
2155 while( edgeItr.hasNext() ) {
2156 ReferenceEdge edger = edgeItr.next();
2157 if( !r.contains( edger.getDst() ) ) {
2158 todo.add( edger.getDst() );
2163 if( hrn.isSingleObject() ) {
2168 pi2dr.put( index, dr );
2169 pi2r .put( index, r );
2172 assert defParamObj.size() <= fm.numParameters();
2174 // if we're in parameter decomposition mode, report some results here
2178 // report primary parameter object mappings
2179 mapItr = pi2dr.entrySet().iterator();
2180 while( mapItr.hasNext() ) {
2181 Map.Entry me = (Map.Entry) mapItr.next();
2182 Integer paramIndex = (Integer) me.getKey();
2183 Set<HeapRegionNode> hrnAset = (Set<HeapRegionNode>) me.getValue();
2185 Iterator<HeapRegionNode> hrnItr = hrnAset.iterator();
2186 while( hrnItr.hasNext() ) {
2187 HeapRegionNode hrnA = hrnItr.next();
2188 pd.mapRegionToParamObject( hrnA, paramIndex );
2192 // report parameter-reachable mappings
2193 mapItr = pi2r.entrySet().iterator();
2194 while( mapItr.hasNext() ) {
2195 Map.Entry me = (Map.Entry) mapItr.next();
2196 Integer paramIndex = (Integer) me.getKey();
2197 Set<HeapRegionNode> hrnRset = (Set<HeapRegionNode>) me.getValue();
2199 Iterator<HeapRegionNode> hrnItr = hrnRset.iterator();
2200 while( hrnItr.hasNext() ) {
2201 HeapRegionNode hrnR = hrnItr.next();
2202 pd.mapRegionToParamReachable( hrnR, paramIndex );
2206 // and we're done in this method for special param decomp mode
2211 // now iterate over reachable nodes to rewrite their alpha, and
2212 // classify edges found for beta rewrite
2213 Hashtable<TokenTuple, ReachabilitySet> tokens2states = new Hashtable<TokenTuple, ReachabilitySet>();
2215 Hashtable< Integer, Set<Vector> > edges_p2p = new Hashtable< Integer, Set<Vector> >();
2216 Hashtable< Integer, Set<Vector> > edges_p2s = new Hashtable< Integer, Set<Vector> >();
2217 Hashtable< Integer, Set<Vector> > edges_s2p = new Hashtable< Integer, Set<Vector> >();
2218 Hashtable< Integer, Set<Vector> > edges_s2s = new Hashtable< Integer, Set<Vector> >();
2219 Hashtable< Integer, Set<Vector> > edges_up_dr = new Hashtable< Integer, Set<Vector> >();
2220 Hashtable< Integer, Set<Vector> > edges_up_r = new Hashtable< Integer, Set<Vector> >();
2223 // so again, with respect to some arg i...
2224 lnArgItr = paramIndex2ln.entrySet().iterator();
2225 while( lnArgItr.hasNext() ) {
2226 Map.Entry me = (Map.Entry) lnArgItr.next();
2227 Integer index = (Integer) me.getKey();
2228 LabelNode lnArg_i = (LabelNode) me.getValue();
2230 TokenTuple p_i = ogCallee.paramIndex2paramTokenPrimary.get( index );
2231 TokenTuple s_i = ogCallee.paramIndex2paramTokenSecondary.get( index );
2234 ensureEmptyEdgeIndexPair( edges_p2p, index );
2235 ensureEmptyEdgeIndexPair( edges_p2s, index );
2236 ensureEmptyEdgeIndexPair( edges_s2p, index );
2237 ensureEmptyEdgeIndexPair( edges_s2s, index );
2238 ensureEmptyEdgeIndexPair( edges_up_dr, index );
2239 ensureEmptyEdgeIndexPair( edges_up_r, index );
2241 Set<HeapRegionNode> dr = pi2dr.get( index );
2242 Iterator<HeapRegionNode> hrnItr = dr.iterator();
2243 while( hrnItr.hasNext() ) {
2244 // this heap region is definitely an "a_i" or primary by virtue of being in dr
2245 HeapRegionNode hrn = hrnItr.next();
2247 tokens2states.clear();
2248 tokens2states.put( p_i, hrn.getAlpha() );
2250 rewriteCallerReachability( index,
2253 paramIndex2rewriteH_p.get( index ),
2255 paramIndex2rewrite_d_p,
2256 paramIndex2rewrite_d_s,
2257 paramIndex2rewriteD,
2262 nodesWithNewAlpha.add( hrn );
2265 Iterator<ReferenceEdge> edgeItr = hrn.iteratorToReferencers();
2266 while( edgeItr.hasNext() ) {
2267 ReferenceEdge edge = edgeItr.next();
2268 OwnershipNode on = edge.getSrc();
2270 boolean edge_classified = false;
2273 if( on instanceof HeapRegionNode ) {
2274 // hrn0 may be "a_j" and/or "r_j" or even neither
2275 HeapRegionNode hrn0 = (HeapRegionNode) on;
2277 Iterator itr = pi2dr.entrySet().iterator();
2278 while( itr.hasNext() ) {
2279 Map.Entry mo = (Map.Entry) itr.next();
2280 Integer pi = (Integer) mo.getKey();
2281 Set<HeapRegionNode> dr_i = (Set<HeapRegionNode>) mo.getValue();
2283 if( dr_i.contains( hrn0 ) ) {
2284 addEdgeIndexPair( edges_p2p, pi, edge, index );
2285 edge_classified = true;
2289 itr = pi2r.entrySet().iterator();
2290 while( itr.hasNext() ) {
2291 Map.Entry mo = (Map.Entry) itr.next();
2292 Integer pi = (Integer) mo.getKey();
2293 Set<HeapRegionNode> r_i = (Set<HeapRegionNode>) mo.getValue();
2295 if( r_i.contains( hrn0 ) ) {
2296 addEdgeIndexPair( edges_s2p, pi, edge, index );
2297 edge_classified = true;
2302 // all of these edges are upstream of directly reachable objects
2303 if( !edge_classified ) {
2304 addEdgeIndexPair( edges_up_dr, index, edge, index );
2310 Set<HeapRegionNode> r = pi2r.get( index );
2311 hrnItr = r.iterator();
2312 while( hrnItr.hasNext() ) {
2313 // this heap region is definitely an "r_i" or secondary by virtue of being in r
2314 HeapRegionNode hrn = hrnItr.next();
2316 if( paramIndex2rewriteH_s.containsKey( index ) ) {
2318 tokens2states.clear();
2319 tokens2states.put( p_i, new ReachabilitySet().makeCanonical() );
2320 tokens2states.put( s_i, hrn.getAlpha() );
2322 rewriteCallerReachability( index,
2325 paramIndex2rewriteH_s.get( index ),
2327 paramIndex2rewrite_d_p,
2328 paramIndex2rewrite_d_s,
2329 paramIndex2rewriteD,
2334 nodesWithNewAlpha.add( hrn );
2338 Iterator<ReferenceEdge> edgeItr = hrn.iteratorToReferencers();
2339 while( edgeItr.hasNext() ) {
2340 ReferenceEdge edge = edgeItr.next();
2341 OwnershipNode on = edge.getSrc();
2343 boolean edge_classified = false;
2345 if( on instanceof HeapRegionNode ) {
2346 // hrn0 may be "a_j" and/or "r_j" or even neither
2347 HeapRegionNode hrn0 = (HeapRegionNode) on;
2349 Iterator itr = pi2dr.entrySet().iterator();
2350 while( itr.hasNext() ) {
2351 Map.Entry mo = (Map.Entry) itr.next();
2352 Integer pi = (Integer) mo.getKey();
2353 Set<HeapRegionNode> dr_i = (Set<HeapRegionNode>) mo.getValue();
2355 if( dr_i.contains( hrn0 ) ) {
2356 addEdgeIndexPair( edges_p2s, pi, edge, index );
2357 edge_classified = true;
2361 itr = pi2r.entrySet().iterator();
2362 while( itr.hasNext() ) {
2363 Map.Entry mo = (Map.Entry) itr.next();
2364 Integer pi = (Integer) mo.getKey();
2365 Set<HeapRegionNode> r_i = (Set<HeapRegionNode>) mo.getValue();
2367 if( r_i.contains( hrn0 ) ) {
2368 addEdgeIndexPair( edges_s2s, pi, edge, index );
2369 edge_classified = true;
2374 // these edges are all upstream of some reachable node
2375 if( !edge_classified ) {
2376 addEdgeIndexPair( edges_up_r, index, edge, index );
2383 // and again, with respect to some arg i...
2384 lnArgItr = paramIndex2ln.entrySet().iterator();
2385 while( lnArgItr.hasNext() ) {
2386 Map.Entry me = (Map.Entry) lnArgItr.next();
2387 Integer index = (Integer) me.getKey();
2388 LabelNode lnArg_i = (LabelNode) me.getValue();
2391 // update reachable edges
2392 Iterator edgeItr = edges_p2p.get( index ).iterator();
2393 while( edgeItr.hasNext() ) {
2394 Vector mo = (Vector) edgeItr.next();
2395 ReferenceEdge edge = (ReferenceEdge) mo.get( 0 );
2396 Integer indexJ = (Integer) mo.get( 1 );
2398 if( !paramIndex2rewriteJ_p2p.containsKey( makeMapKey( index,
2400 edge.getField() ) ) ) {
2404 TokenTuple p_j = ogCallee.paramIndex2paramTokenPrimary.get( indexJ );
2407 tokens2states.clear();
2408 tokens2states.put( p_j, edge.getBeta() );
2410 rewriteCallerReachability( index,
2413 paramIndex2rewriteJ_p2p.get( makeMapKey( index,
2415 edge.getField() ) ),
2417 paramIndex2rewrite_d_p,
2418 paramIndex2rewrite_d_s,
2419 paramIndex2rewriteD,
2424 edgesWithNewBeta.add( edge );
2428 edgeItr = edges_p2s.get( index ).iterator();
2429 while( edgeItr.hasNext() ) {
2430 Vector mo = (Vector) edgeItr.next();
2431 ReferenceEdge edge = (ReferenceEdge) mo.get( 0 );
2432 Integer indexJ = (Integer) mo.get( 1 );
2434 if( !paramIndex2rewriteJ_p2s.containsKey( makeMapKey( index,
2435 edge.getField() ) ) ) {
2439 TokenTuple s_j = ogCallee.paramIndex2paramTokenSecondary.get( indexJ );
2442 tokens2states.clear();
2443 tokens2states.put( s_j, edge.getBeta() );
2445 rewriteCallerReachability( index,
2448 paramIndex2rewriteJ_p2s.get( makeMapKey( index,
2449 edge.getField() ) ),
2451 paramIndex2rewrite_d_p,
2452 paramIndex2rewrite_d_s,
2453 paramIndex2rewriteD,
2458 edgesWithNewBeta.add( edge );
2462 edgeItr = edges_s2p.get( index ).iterator();
2463 while( edgeItr.hasNext() ) {
2464 Vector mo = (Vector) edgeItr.next();
2465 ReferenceEdge edge = (ReferenceEdge) mo.get( 0 );
2466 Integer indexJ = (Integer) mo.get( 1 );
2468 if( !paramIndex2rewriteJ_s2p.containsKey( index ) ) {
2472 TokenTuple p_j = ogCallee.paramIndex2paramTokenPrimary.get( indexJ );
2475 tokens2states.clear();
2476 tokens2states.put( p_j, edge.getBeta() );
2478 rewriteCallerReachability( index,
2481 paramIndex2rewriteJ_s2p.get( index ),
2483 paramIndex2rewrite_d_p,
2484 paramIndex2rewrite_d_s,
2485 paramIndex2rewriteD,
2490 edgesWithNewBeta.add( edge );
2494 edgeItr = edges_s2s.get( index ).iterator();
2495 while( edgeItr.hasNext() ) {
2496 Vector mo = (Vector) edgeItr.next();
2497 ReferenceEdge edge = (ReferenceEdge) mo.get( 0 );
2498 Integer indexJ = (Integer) mo.get( 1 );
2500 if( !paramIndex2rewriteJ_s2s.containsKey( index ) ) {
2504 TokenTuple s_j = ogCallee.paramIndex2paramTokenSecondary.get( indexJ );
2507 tokens2states.clear();
2508 tokens2states.put( s_j, edge.getBeta() );
2510 rewriteCallerReachability( index,
2513 paramIndex2rewriteJ_s2s.get( index ),
2515 paramIndex2rewrite_d_p,
2516 paramIndex2rewrite_d_s,
2517 paramIndex2rewriteD,
2522 edgesWithNewBeta.add( edge );
2526 // update directly upstream edges
2527 Hashtable<ReferenceEdge, ChangeTupleSet> edgeUpstreamPlannedChanges =
2528 new Hashtable<ReferenceEdge, ChangeTupleSet>();
2530 HashSet<ReferenceEdge> edgesDirectlyUpstream =
2531 new HashSet<ReferenceEdge>();
2533 edgeItr = edges_up_dr.get( index ).iterator();
2534 while( edgeItr.hasNext() ) {
2535 Vector mo = (Vector) edgeItr.next();
2536 ReferenceEdge edge = (ReferenceEdge) mo.get( 0 );
2537 Integer indexJ = (Integer) mo.get( 1 );
2539 edgesDirectlyUpstream.add( edge );
2541 TokenTuple p_j = ogCallee.paramIndex2paramTokenPrimary.get( indexJ );
2544 // start with K_p2 and p_j
2545 tokens2states.clear();
2546 tokens2states.put( p_j, edge.getBeta() );
2548 rewriteCallerReachability( index,
2551 paramIndex2rewriteK_p2.get( index ),
2553 paramIndex2rewrite_d_p,
2554 paramIndex2rewrite_d_s,
2555 paramIndex2rewriteD,
2558 edgeUpstreamPlannedChanges );
2560 // and add in s_j, if required, and do K_p
2561 TokenTuple s_j = ogCallee.paramIndex2paramTokenSecondary.get( indexJ );
2563 tokens2states.put( s_j, edge.getBeta() );
2566 rewriteCallerReachability( index,
2569 paramIndex2rewriteK_p.get( index ),
2571 paramIndex2rewrite_d_p,
2572 paramIndex2rewrite_d_s,
2573 paramIndex2rewriteD,
2576 edgeUpstreamPlannedChanges );
2578 edgesWithNewBeta.add( edge );
2581 propagateTokensOverEdges( edgesDirectlyUpstream,
2582 edgeUpstreamPlannedChanges,
2586 // update upstream edges
2587 edgeUpstreamPlannedChanges =
2588 new Hashtable<ReferenceEdge, ChangeTupleSet>();
2590 HashSet<ReferenceEdge> edgesUpstream =
2591 new HashSet<ReferenceEdge>();
2593 edgeItr = edges_up_r.get( index ).iterator();
2594 while( edgeItr.hasNext() ) {
2595 Vector mo = (Vector) edgeItr.next();
2596 ReferenceEdge edge = (ReferenceEdge) mo.get( 0 );
2597 Integer indexJ = (Integer) mo.get( 1 );
2599 if( !paramIndex2rewriteK_s.containsKey( index ) ) {
2603 edgesUpstream.add( edge );
2605 TokenTuple p_j = ogCallee.paramIndex2paramTokenPrimary.get( indexJ );
2608 TokenTuple s_j = ogCallee.paramIndex2paramTokenSecondary.get( indexJ );
2611 tokens2states.clear();
2612 tokens2states.put( p_j, rsWttsEmpty );
2613 tokens2states.put( s_j, edge.getBeta() );
2615 rewriteCallerReachability( index,
2618 paramIndex2rewriteK_s.get( index ),
2620 paramIndex2rewrite_d_p,
2621 paramIndex2rewrite_d_s,
2622 paramIndex2rewriteD,
2625 edgeUpstreamPlannedChanges );
2627 edgesWithNewBeta.add( edge );
2630 propagateTokensOverEdges( edgesUpstream,
2631 edgeUpstreamPlannedChanges,
2634 } // end effects per argument/parameter map
2637 // commit changes to alpha and beta
2638 Iterator<HeapRegionNode> nodeItr = nodesWithNewAlpha.iterator();
2639 while( nodeItr.hasNext() ) {
2640 nodeItr.next().applyAlphaNew();
2643 Iterator<ReferenceEdge> edgeItr = edgesWithNewBeta.iterator();
2644 while( edgeItr.hasNext() ) {
2645 edgeItr.next().applyBetaNew();
2649 // verify the existence of allocation sites and their
2650 // shadows from the callee in the context of this caller graph
2651 // then map allocated nodes of callee onto the caller shadows
2653 Hashtable<TokenTuple, ReachabilitySet> tokens2statesEmpty = new Hashtable<TokenTuple, ReachabilitySet>();
2655 Iterator<AllocationSite> asItr = ogCallee.allocationSites.iterator();
2656 while( asItr.hasNext() ) {
2657 AllocationSite allocSite = asItr.next();
2659 // grab the summary in the caller just to make sure
2660 // the allocation site has nodes in the caller
2661 HeapRegionNode hrnSummary = getSummaryNode( allocSite );
2663 // assert that the shadow nodes have no reference edges
2664 // because they're brand new to the graph, or last time
2665 // they were used they should have been cleared of edges
2666 HeapRegionNode hrnShadowSummary = getShadowSummaryNode( allocSite );
2667 assert hrnShadowSummary.getNumReferencers() == 0;
2668 assert hrnShadowSummary.getNumReferencees() == 0;
2670 // then bring g_ij onto g'_ij and rewrite
2671 HeapRegionNode hrnSummaryCallee = ogCallee.getSummaryNode( allocSite );
2672 hrnShadowSummary.setAlpha( toShadowTokens( ogCallee, hrnSummaryCallee.getAlpha() ) );
2674 // shadow nodes only are touched by a rewrite one time,
2675 // so rewrite and immediately commit--and they don't belong
2676 // to a particular parameter, so use a bogus param index
2677 // that pulls a self-rewrite out of H
2678 rewriteCallerReachability( bogusIndex,
2681 funcScriptR( hrnShadowSummary.getAlpha(), ogCallee, mc ),
2683 paramIndex2rewrite_d_p,
2684 paramIndex2rewrite_d_s,
2685 paramIndex2rewriteD,
2690 hrnShadowSummary.applyAlphaNew();
2693 for( int i = 0; i < allocSite.getAllocationDepth(); ++i ) {
2694 Integer idIth = allocSite.getIthOldest(i);
2695 assert id2hrn.containsKey(idIth);
2696 HeapRegionNode hrnIth = id2hrn.get(idIth);
2698 Integer idShadowIth = -(allocSite.getIthOldest(i));
2699 assert id2hrn.containsKey(idShadowIth);
2700 HeapRegionNode hrnIthShadow = id2hrn.get(idShadowIth);
2701 assert hrnIthShadow.getNumReferencers() == 0;
2702 assert hrnIthShadow.getNumReferencees() == 0;
2704 assert ogCallee.id2hrn.containsKey(idIth);
2705 HeapRegionNode hrnIthCallee = ogCallee.id2hrn.get(idIth);
2706 hrnIthShadow.setAlpha(toShadowTokens(ogCallee, hrnIthCallee.getAlpha() ) );
2708 rewriteCallerReachability( bogusIndex,
2711 funcScriptR( hrnIthShadow.getAlpha(), ogCallee, mc ),
2713 paramIndex2rewrite_d_p,
2714 paramIndex2rewrite_d_s,
2715 paramIndex2rewriteD,
2720 hrnIthShadow.applyAlphaNew();
2725 // for every heap region->heap region edge in the
2726 // callee graph, create the matching edge or edges
2727 // in the caller graph
2728 Set sCallee = ogCallee.id2hrn.entrySet();
2729 Iterator iCallee = sCallee.iterator();
2730 while( iCallee.hasNext() ) {
2731 Map.Entry meCallee = (Map.Entry) iCallee.next();
2732 Integer idCallee = (Integer) meCallee.getKey();
2733 HeapRegionNode hrnCallee = (HeapRegionNode) meCallee.getValue();
2735 Iterator<ReferenceEdge> heapRegionsItrCallee = hrnCallee.iteratorToReferencees();
2736 while( heapRegionsItrCallee.hasNext() ) {
2737 ReferenceEdge edgeCallee = heapRegionsItrCallee.next();
2738 HeapRegionNode hrnChildCallee = edgeCallee.getDst();
2739 Integer idChildCallee = hrnChildCallee.getID();
2741 // only address this edge if it is not a special initial edge
2742 if( !edgeCallee.isInitialParam() ) {
2744 // now we know that in the callee method's ownership graph
2745 // there is a heap region->heap region reference edge given
2746 // by heap region pointers:
2747 // hrnCallee -> heapChildCallee
2749 // or by the ownership-graph independent ID's:
2750 // idCallee -> idChildCallee
2752 // make the edge with src and dst so beta info is
2753 // calculated once, then copy it for each new edge in caller
2755 ReferenceEdge edgeNewInCallerTemplate = new ReferenceEdge( null,
2757 edgeCallee.getType(),
2758 edgeCallee.getField(),
2760 funcScriptR( toShadowTokens( ogCallee,
2761 edgeCallee.getBeta()
2767 rewriteCallerReachability( bogusIndex,
2769 edgeNewInCallerTemplate,
2770 edgeNewInCallerTemplate.getBeta(),
2772 paramIndex2rewrite_d_p,
2773 paramIndex2rewrite_d_s,
2774 paramIndex2rewriteD,
2779 edgeNewInCallerTemplate.applyBetaNew();
2782 // So now make a set of possible source heaps in the caller graph
2783 // and a set of destination heaps in the caller graph, and make
2784 // a reference edge in the caller for every possible (src,dst) pair
2785 HashSet<HeapRegionNode> possibleCallerSrcs =
2786 getHRNSetThatPossiblyMapToCalleeHRN( ogCallee,
2787 (HeapRegionNode) edgeCallee.getSrc(),
2791 HashSet<HeapRegionNode> possibleCallerDsts =
2792 getHRNSetThatPossiblyMapToCalleeHRN( ogCallee,
2793 edgeCallee.getDst(),
2797 // make every possible pair of {srcSet} -> {dstSet} edges in the caller
2798 Iterator srcItr = possibleCallerSrcs.iterator();
2799 while( srcItr.hasNext() ) {
2800 HeapRegionNode src = (HeapRegionNode) srcItr.next();
2802 if( !hasMatchingField( src, edgeCallee ) ) {
2803 // prune this source node possibility
2807 Iterator dstItr = possibleCallerDsts.iterator();
2808 while( dstItr.hasNext() ) {
2809 HeapRegionNode dst = (HeapRegionNode) dstItr.next();
2811 if( !hasMatchingType( edgeCallee, dst ) ) {
2816 // otherwise the caller src and dst pair can match the edge, so make it
2817 ReferenceEdge edgeNewInCaller = edgeNewInCallerTemplate.copy();
2818 edgeNewInCaller.setSrc( src );
2819 edgeNewInCaller.setDst( dst );
2821 ReferenceEdge edgeExisting = src.getReferenceTo( dst,
2822 edgeNewInCaller.getType(),
2823 edgeNewInCaller.getField() );
2824 if( edgeExisting == null ) {
2825 // if this edge doesn't exist in the caller, create it
2826 addReferenceEdge( src, dst, edgeNewInCaller );
2829 // if it already exists, merge with it
2830 edgeExisting.setBeta( edgeExisting.getBeta().union( edgeNewInCaller.getBeta() ) );
2839 // return value may need to be assigned in caller
2840 TempDescriptor returnTemp = fc.getReturnTemp();
2841 if( returnTemp != null && !returnTemp.getType().isImmutable() ) {
2843 LabelNode lnLhsCaller = getLabelNodeFromTemp( returnTemp );
2844 clearReferenceEdgesFrom( lnLhsCaller, null, null, true );
2846 LabelNode lnReturnCallee = ogCallee.getLabelNodeFromTemp( tdReturn );
2847 Iterator<ReferenceEdge> edgeCalleeItr = lnReturnCallee.iteratorToReferencees();
2848 while( edgeCalleeItr.hasNext() ) {
2849 ReferenceEdge edgeCallee = edgeCalleeItr.next();
2851 ReferenceEdge edgeNewInCallerTemplate = new ReferenceEdge( null,
2853 edgeCallee.getType(),
2854 edgeCallee.getField(),
2856 funcScriptR( toShadowTokens(ogCallee,
2857 edgeCallee.getBeta() ),
2861 rewriteCallerReachability( bogusIndex,
2863 edgeNewInCallerTemplate,
2864 edgeNewInCallerTemplate.getBeta(),
2866 paramIndex2rewrite_d_p,
2867 paramIndex2rewrite_d_s,
2868 paramIndex2rewriteD,
2873 edgeNewInCallerTemplate.applyBetaNew();
2876 HashSet<HeapRegionNode> assignCallerRhs =
2877 getHRNSetThatPossiblyMapToCalleeHRN( ogCallee,
2878 edgeCallee.getDst(),
2882 Iterator<HeapRegionNode> itrHrn = assignCallerRhs.iterator();
2883 while( itrHrn.hasNext() ) {
2884 HeapRegionNode hrnCaller = itrHrn.next();
2886 if( !hasMatchingType( edgeCallee, hrnCaller ) ) {
2891 // otherwise caller node can match callee edge, so make it
2892 ReferenceEdge edgeNewInCaller = edgeNewInCallerTemplate.copy();
2893 edgeNewInCaller.setSrc( lnLhsCaller );
2894 edgeNewInCaller.setDst( hrnCaller );
2896 ReferenceEdge edgeExisting = lnLhsCaller.getReferenceTo( hrnCaller,
2897 edgeNewInCaller.getType(),
2898 edgeNewInCaller.getField() );
2899 if( edgeExisting == null ) {
2901 // if this edge doesn't exist in the caller, create it
2902 addReferenceEdge( lnLhsCaller, hrnCaller, edgeNewInCaller );
2904 // if it already exists, merge with it
2905 edgeExisting.setBeta( edgeExisting.getBeta().union( edgeNewInCaller.getBeta() ) );
2912 if( mc.getDescriptor().getSymbol().equals( debugCaller ) &&
2913 fm.getMethod().getSymbol().equals( debugCallee ) ) {
2915 writeGraph( "debug7JustBeforeMergeToKCapacity", true, true, true, false, false );
2916 } catch( IOException e ) {}
2921 // merge the shadow nodes of allocation sites back down to normal capacity
2922 Iterator<AllocationSite> allocItr = ogCallee.allocationSites.iterator();
2923 while( allocItr.hasNext() ) {
2924 AllocationSite as = allocItr.next();
2926 // first age each allocation site enough times to make room for the shadow nodes
2927 for( int i = 0; i < as.getAllocationDepth(); ++i ) {
2931 // then merge the shadow summary into the normal summary
2932 HeapRegionNode hrnSummary = getSummaryNode( as );
2933 assert hrnSummary != null;
2935 HeapRegionNode hrnSummaryShadow = getShadowSummaryNode( as );
2936 assert hrnSummaryShadow != null;
2938 mergeIntoSummary( hrnSummaryShadow, hrnSummary );
2940 // then clear off after merge
2941 clearReferenceEdgesFrom( hrnSummaryShadow, null, null, true );
2942 clearReferenceEdgesTo ( hrnSummaryShadow, null, null, true );
2943 hrnSummaryShadow.setAlpha( new ReachabilitySet().makeCanonical() );
2945 // then transplant shadow nodes onto the now clean normal nodes
2946 for( int i = 0; i < as.getAllocationDepth(); ++i ) {
2948 Integer idIth = as.getIthOldest( i );
2949 HeapRegionNode hrnIth = id2hrn.get( idIth );
2950 Integer idIthShadow = as.getIthOldestShadow( i );
2951 HeapRegionNode hrnIthShadow = id2hrn.get( idIthShadow );
2953 transferOnto( hrnIthShadow, hrnIth );
2955 // clear off shadow nodes after transfer
2956 clearReferenceEdgesFrom( hrnIthShadow, null, null, true );
2957 clearReferenceEdgesTo ( hrnIthShadow, null, null, true );
2958 hrnIthShadow.setAlpha( new ReachabilitySet().makeCanonical() );
2961 // finally, globally change shadow tokens into normal tokens
2962 Iterator itrAllLabelNodes = td2ln.entrySet().iterator();
2963 while( itrAllLabelNodes.hasNext() ) {
2964 Map.Entry me = (Map.Entry) itrAllLabelNodes.next();
2965 LabelNode ln = (LabelNode) me.getValue();
2967 Iterator<ReferenceEdge> itrEdges = ln.iteratorToReferencees();
2968 while( itrEdges.hasNext() ) {
2969 unshadowTokens( as, itrEdges.next() );
2973 Iterator itrAllHRNodes = id2hrn.entrySet().iterator();
2974 while( itrAllHRNodes.hasNext() ) {
2975 Map.Entry me = (Map.Entry) itrAllHRNodes.next();
2976 HeapRegionNode hrnToAge = (HeapRegionNode) me.getValue();
2978 unshadowTokens( as, hrnToAge );
2980 Iterator<ReferenceEdge> itrEdges = hrnToAge.iteratorToReferencees();
2981 while( itrEdges.hasNext() ) {
2982 unshadowTokens( as, itrEdges.next() );
2988 if( mc.getDescriptor().getSymbol().equals( debugCaller ) &&
2989 fm.getMethod().getSymbol().equals( debugCallee ) ) {
2991 writeGraph( "debug8JustBeforeSweep", true, true, true, false, false );
2992 } catch( IOException e ) {}
2996 // improve reachability as much as possible
3001 if( mc.getDescriptor().getSymbol().equals( debugCaller ) &&
3002 fm.getMethod().getSymbol().equals( debugCallee ) ) {
3004 writeGraph( "debug9endResolveCall", true, true, true, false, false );
3005 } catch( IOException e ) {}
3006 System.out.println( " "+mc+" done calling "+fm );
3017 protected boolean hasMatchingField(HeapRegionNode src, ReferenceEdge edge) {
3019 // if no type, then it's a match-everything region
3020 TypeDescriptor tdSrc = src.getType();
3021 if( tdSrc == null ) {
3025 if( tdSrc.isArray() ) {
3026 TypeDescriptor td = edge.getType();
3029 TypeDescriptor tdSrcDeref = tdSrc.dereference();
3030 assert tdSrcDeref != null;
3032 if( !typeUtil.isSuperorType( tdSrcDeref, td ) ) {
3036 return edge.getField().equals( OwnershipAnalysis.arrayElementFieldName );
3039 // if it's not a class, it doesn't have any fields to match
3040 if( !tdSrc.isClass() ) {
3044 ClassDescriptor cd = tdSrc.getClassDesc();
3045 while( cd != null ) {
3046 Iterator fieldItr = cd.getFields();
3048 while( fieldItr.hasNext() ) {
3049 FieldDescriptor fd = (FieldDescriptor) fieldItr.next();
3051 if( fd.getType().equals( edge.getType() ) &&
3052 fd.getSymbol().equals( edge.getField() ) ) {
3057 cd = cd.getSuperDesc();
3060 // otherwise it is a class with fields
3061 // but we didn't find a match
3066 protected boolean hasMatchingType(ReferenceEdge edge, HeapRegionNode dst) {
3068 // if the region has no type, matches everything
3069 TypeDescriptor tdDst = dst.getType();
3070 if( tdDst == null ) {
3074 // if the type is not a class or an array, don't
3075 // match because primitives are copied, no aliases
3076 ClassDescriptor cdDst = tdDst.getClassDesc();
3077 if( cdDst == null && !tdDst.isArray() ) {
3081 // if the edge type is null, it matches everything
3082 TypeDescriptor tdEdge = edge.getType();
3083 if( tdEdge == null ) {
3087 return typeUtil.isSuperorType(tdEdge, tdDst);
3092 protected void unshadowTokens(AllocationSite as, ReferenceEdge edge) {
3093 edge.setBeta(edge.getBeta().unshadowTokens(as) );
3096 protected void unshadowTokens(AllocationSite as, HeapRegionNode hrn) {
3097 hrn.setAlpha(hrn.getAlpha().unshadowTokens(as) );
3101 private ReachabilitySet toShadowTokens(OwnershipGraph ogCallee,
3102 ReachabilitySet rsIn) {
3104 ReachabilitySet rsOut = new ReachabilitySet(rsIn).makeCanonical();
3106 Iterator<AllocationSite> allocItr = ogCallee.allocationSites.iterator();
3107 while( allocItr.hasNext() ) {
3108 AllocationSite as = allocItr.next();
3110 rsOut = rsOut.toShadowTokens(as);
3113 return rsOut.makeCanonical();
3117 private void rewriteCallerReachability(Integer paramIndex,
3120 ReachabilitySet rules,
3121 Hashtable<TokenTuple, ReachabilitySet> tokens2states,
3122 Hashtable<Integer, ReachabilitySet> paramIndex2rewrite_d_p,
3123 Hashtable<Integer, ReachabilitySet> paramIndex2rewrite_d_s,
3124 Hashtable<Integer, ReachabilitySet> paramIndex2rewriteD,
3125 OwnershipGraph ogCallee,
3126 boolean makeChangeSet,
3127 Hashtable<ReferenceEdge, ChangeTupleSet> edgePlannedChanges) {
3129 assert(hrn == null && edge != null) ||
3130 (hrn != null && edge == null);
3132 assert rules != null;
3133 assert tokens2states != null;
3135 ReachabilitySet callerReachabilityNew = new ReachabilitySet().makeCanonical();
3137 // for initializing structures in this method
3138 TokenTupleSet ttsEmpty = new TokenTupleSet().makeCanonical();
3140 // use this to construct a change set if required; the idea is to
3141 // map every partially rewritten token tuple set to the set of
3142 // caller-context token tuple sets that were used to generate it
3143 Hashtable<TokenTupleSet, HashSet<TokenTupleSet> > rewritten2source =
3144 new Hashtable<TokenTupleSet, HashSet<TokenTupleSet> >();
3145 rewritten2source.put( ttsEmpty, new HashSet<TokenTupleSet>() );
3148 Iterator<TokenTupleSet> rulesItr = rules.iterator();
3149 while(rulesItr.hasNext()) {
3150 TokenTupleSet rule = rulesItr.next();
3152 ReachabilitySet rewrittenRule = new ReachabilitySet(ttsEmpty).makeCanonical();
3154 Iterator<TokenTuple> ruleItr = rule.iterator();
3155 while(ruleItr.hasNext()) {
3156 TokenTuple ttCallee = ruleItr.next();
3158 // compute the possibilities for rewriting this callee token
3159 ReachabilitySet ttCalleeRewrites = null;
3160 boolean callerSourceUsed = false;
3162 if( tokens2states.containsKey( ttCallee ) ) {
3163 callerSourceUsed = true;
3164 ttCalleeRewrites = tokens2states.get( ttCallee );
3165 assert ttCalleeRewrites != null;
3167 } else if( ogCallee.paramTokenPrimary2paramIndex.containsKey( ttCallee ) ) {
3169 Integer paramIndex_j = ogCallee.paramTokenPrimary2paramIndex.get( ttCallee );
3170 assert paramIndex_j != null;
3171 ttCalleeRewrites = paramIndex2rewrite_d_p.get( paramIndex_j );
3172 assert ttCalleeRewrites != null;
3174 } else if( ogCallee.paramTokenSecondary2paramIndex.containsKey( ttCallee ) ) {
3176 Integer paramIndex_j = ogCallee.paramTokenSecondary2paramIndex.get( ttCallee );
3177 assert paramIndex_j != null;
3178 ttCalleeRewrites = paramIndex2rewrite_d_s.get( paramIndex_j );
3179 assert ttCalleeRewrites != null;
3181 } else if( ogCallee.paramTokenSecondaryPlus2paramIndex.containsKey( ttCallee ) ) {
3183 Integer paramIndex_j = ogCallee.paramTokenSecondaryPlus2paramIndex.get( ttCallee );
3184 assert paramIndex_j != null;
3185 ttCalleeRewrites = paramIndex2rewriteD.get( paramIndex_j );
3186 assert ttCalleeRewrites != null;
3188 } else if( ogCallee.paramTokenSecondaryStar2paramIndex.containsKey( ttCallee ) ) {
3190 Integer paramIndex_j = ogCallee.paramTokenSecondaryStar2paramIndex.get( ttCallee );
3191 assert paramIndex_j != null;
3192 ttCalleeRewrites = paramIndex2rewriteD.get( paramIndex_j );
3193 assert ttCalleeRewrites != null;
3196 // otherwise there's no need for a rewrite, just pass this one on
3197 TokenTupleSet ttsCaller = new TokenTupleSet( ttCallee ).makeCanonical();
3198 ttCalleeRewrites = new ReachabilitySet( ttsCaller ).makeCanonical();
3201 // branch every version of the working rewritten rule with
3202 // the possibilities for rewriting the current callee token
3203 ReachabilitySet rewrittenRuleWithTTCallee = new ReachabilitySet().makeCanonical();
3205 Iterator<TokenTupleSet> rewrittenRuleItr = rewrittenRule.iterator();
3206 while( rewrittenRuleItr.hasNext() ) {
3207 TokenTupleSet ttsRewritten = rewrittenRuleItr.next();
3209 Iterator<TokenTupleSet> ttCalleeRewritesItr = ttCalleeRewrites.iterator();
3210 while( ttCalleeRewritesItr.hasNext() ) {
3211 TokenTupleSet ttsBranch = ttCalleeRewritesItr.next();
3213 TokenTupleSet ttsRewrittenNext = ttsRewritten.unionUpArity( ttsBranch );
3215 if( makeChangeSet ) {
3216 // in order to keep the list of source token tuple sets
3217 // start with the sets used to make the partially rewritten
3218 // rule up to this point
3219 HashSet<TokenTupleSet> sourceSets = rewritten2source.get( ttsRewritten );
3220 assert sourceSets != null;
3222 // make a shallow copy for possible modification
3223 sourceSets = (HashSet<TokenTupleSet>) sourceSets.clone();
3225 // if we used something from the caller to rewrite it, remember
3226 if( callerSourceUsed ) {
3227 sourceSets.add( ttsBranch );
3230 // set mapping for the further rewritten rule
3231 rewritten2source.put( ttsRewrittenNext, sourceSets );
3234 rewrittenRuleWithTTCallee =
3235 rewrittenRuleWithTTCallee.union( ttsRewrittenNext );
3239 // now the rewritten rule's possibilities have been extended by
3240 // rewriting the current callee token, remember result
3241 rewrittenRule = rewrittenRuleWithTTCallee;
3244 // the rule has been entirely rewritten into the caller context
3245 // now, so add it to the new reachability information
3246 callerReachabilityNew =
3247 callerReachabilityNew.union( rewrittenRule );
3250 if( makeChangeSet ) {
3251 ChangeTupleSet callerChangeSet = new ChangeTupleSet().makeCanonical();
3253 // each possibility for the final reachability should have a set of
3254 // caller sources mapped to it, use to create the change set
3255 Iterator<TokenTupleSet> callerReachabilityItr = callerReachabilityNew.iterator();
3256 while( callerReachabilityItr.hasNext() ) {
3257 TokenTupleSet ttsRewrittenFinal = callerReachabilityItr.next();
3258 HashSet<TokenTupleSet> sourceSets = rewritten2source.get( ttsRewrittenFinal );
3259 assert sourceSets != null;
3261 Iterator<TokenTupleSet> sourceSetsItr = sourceSets.iterator();
3262 while( sourceSetsItr.hasNext() ) {
3263 TokenTupleSet ttsSource = sourceSetsItr.next();
3266 callerChangeSet.union( new ChangeTuple( ttsSource, ttsRewrittenFinal ) );
3270 assert edgePlannedChanges != null;
3271 edgePlannedChanges.put( edge, callerChangeSet );
3275 edge.setBetaNew( edge.getBetaNew().union( callerReachabilityNew ) );
3277 hrn.setAlphaNew( hrn.getAlphaNew().union( callerReachabilityNew ) );
3283 private HashSet<HeapRegionNode>
3284 getHRNSetThatPossiblyMapToCalleeHRN( OwnershipGraph ogCallee,
3285 HeapRegionNode hrnCallee,
3286 Hashtable<Integer, Set<HeapRegionNode> > pi2dr,
3287 Hashtable<Integer, Set<HeapRegionNode> > pi2r
3290 HashSet<HeapRegionNode> possibleCallerHRNs = new HashSet<HeapRegionNode>();
3292 Set<Integer> paramIndicesCallee_p = ogCallee.idPrimary2paramIndexSet .get( hrnCallee.getID() );
3293 Set<Integer> paramIndicesCallee_s = ogCallee.idSecondary2paramIndexSet.get( hrnCallee.getID() );
3295 if( paramIndicesCallee_p == null &&
3296 paramIndicesCallee_s == null ) {
3297 // this is a node allocated in the callee and it has
3298 // exactly one shadow node in the caller to map to
3299 AllocationSite as = hrnCallee.getAllocationSite();
3302 int age = as.getAgeCategory( hrnCallee.getID() );
3303 assert age != AllocationSite.AGE_notInThisSite;
3306 if( age == AllocationSite.AGE_summary ) {
3307 idCaller = as.getSummaryShadow();
3309 } else if( age == AllocationSite.AGE_oldest ) {
3310 idCaller = as.getOldestShadow();
3313 assert age == AllocationSite.AGE_in_I;
3315 Integer I = as.getAge( hrnCallee.getID() );
3318 idCaller = as.getIthOldestShadow( I );
3321 assert id2hrn.containsKey( idCaller );
3322 possibleCallerHRNs.add( id2hrn.get( idCaller ) );
3324 return possibleCallerHRNs;
3327 // find out what primary objects this might be
3328 if( paramIndicesCallee_p != null ) {
3329 // this is a node that was created to represent a parameter
3330 // so it maps to some regions directly reachable from the arg labels
3331 Iterator<Integer> itrIndex = paramIndicesCallee_p.iterator();
3332 while( itrIndex.hasNext() ) {
3333 Integer paramIndexCallee = itrIndex.next();
3334 assert pi2dr.containsKey( paramIndexCallee );
3335 possibleCallerHRNs.addAll( pi2dr.get( paramIndexCallee ) );
3339 // find out what secondary objects this might be
3340 if( paramIndicesCallee_s != null ) {
3341 // this is a node that was created to represent objs reachable from
3342 // some parameter, so it maps to regions reachable from the arg labels
3343 Iterator<Integer> itrIndex = paramIndicesCallee_s.iterator();
3344 while( itrIndex.hasNext() ) {
3345 Integer paramIndexCallee = itrIndex.next();
3346 assert pi2r.containsKey( paramIndexCallee );
3347 possibleCallerHRNs.addAll( pi2r.get( paramIndexCallee ) );
3351 // TODO: is this true?
3352 // one of the two cases above should have put something in here
3353 //assert !possibleCallerHRNs.isEmpty();
3355 return possibleCallerHRNs;
3360 ////////////////////////////////////////////////////
3362 // This global sweep is an optional step to prune
3363 // reachability sets that are not internally
3364 // consistent with the global graph. It should be
3365 // invoked after strong updates or method calls.
3367 ////////////////////////////////////////////////////
3368 public void globalSweep() {
3370 // boldB is part of the phase 1 sweep
3371 Hashtable< Integer, Hashtable<ReferenceEdge, ReachabilitySet> > boldB =
3372 new Hashtable< Integer, Hashtable<ReferenceEdge, ReachabilitySet> >();
3374 // visit every heap region to initialize alphaNew and calculate boldB
3375 Set hrns = id2hrn.entrySet();
3376 Iterator itrHrns = hrns.iterator();
3377 while( itrHrns.hasNext() ) {
3378 Map.Entry me = (Map.Entry)itrHrns.next();
3379 Integer token = (Integer) me.getKey();
3380 HeapRegionNode hrn = (HeapRegionNode) me.getValue();
3382 // assert that this node and incoming edges have clean alphaNew
3383 // and betaNew sets, respectively
3384 assert rsEmpty.equals( hrn.getAlphaNew() );
3386 Iterator<ReferenceEdge> itrRers = hrn.iteratorToReferencers();
3387 while( itrRers.hasNext() ) {
3388 ReferenceEdge edge = itrRers.next();
3389 assert rsEmpty.equals( edge.getBetaNew() );
3392 // calculate boldB for this flagged node
3393 if( hrn.isFlagged() || hrn.isParameter() ) {
3395 Hashtable<ReferenceEdge, ReachabilitySet> boldB_f =
3396 new Hashtable<ReferenceEdge, ReachabilitySet>();
3398 Set<ReferenceEdge> workSetEdges = new HashSet<ReferenceEdge>();
3400 // initial boldB_f constraints
3401 Iterator<ReferenceEdge> itrRees = hrn.iteratorToReferencees();
3402 while( itrRees.hasNext() ) {
3403 ReferenceEdge edge = itrRees.next();
3405 assert !boldB.containsKey( edge );
3406 boldB_f.put( edge, edge.getBeta() );
3408 assert !workSetEdges.contains( edge );
3409 workSetEdges.add( edge );
3412 // enforce the boldB_f constraint at edges until we reach a fixed point
3413 while( !workSetEdges.isEmpty() ) {
3414 ReferenceEdge edge = workSetEdges.iterator().next();
3415 workSetEdges.remove( edge );
3417 Iterator<ReferenceEdge> itrPrime = edge.getDst().iteratorToReferencees();
3418 while( itrPrime.hasNext() ) {
3419 ReferenceEdge edgePrime = itrPrime.next();
3421 ReachabilitySet prevResult = boldB_f.get( edgePrime );
3422 ReachabilitySet intersection = boldB_f.get( edge ).intersection( edgePrime.getBeta() );
3424 if( prevResult == null ||
3425 prevResult.union( intersection ).size() > prevResult.size() ) {
3427 if( prevResult == null ) {
3428 boldB_f.put( edgePrime, edgePrime.getBeta().union( intersection ) );
3430 boldB_f.put( edgePrime, prevResult .union( intersection ) );
3432 workSetEdges.add( edgePrime );
3437 boldB.put( token, boldB_f );
3442 // use boldB to prune tokens from alpha states that are impossible
3443 // and propagate the differences backwards across edges
3444 HashSet<ReferenceEdge> edgesForPropagation = new HashSet<ReferenceEdge>();
3446 Hashtable<ReferenceEdge, ChangeTupleSet> edgePlannedChanges =
3447 new Hashtable<ReferenceEdge, ChangeTupleSet>();
3449 hrns = id2hrn.entrySet();
3450 itrHrns = hrns.iterator();
3451 while( itrHrns.hasNext() ) {
3452 Map.Entry me = (Map.Entry)itrHrns.next();
3453 Integer token = (Integer) me.getKey();
3454 HeapRegionNode hrn = (HeapRegionNode) me.getValue();
3456 // never remove the identity token from a flagged region
3457 // because it is trivially satisfied
3458 TokenTuple ttException = new TokenTuple( token,
3459 !hrn.isSingleObject(),
3460 TokenTuple.ARITY_ONE ).makeCanonical();
3462 ChangeTupleSet cts = new ChangeTupleSet().makeCanonical();
3464 // mark tokens for removal
3465 Iterator<TokenTupleSet> stateItr = hrn.getAlpha().iterator();
3466 while( stateItr.hasNext() ) {
3467 TokenTupleSet ttsOld = stateItr.next();
3469 TokenTupleSet markedTokens = new TokenTupleSet().makeCanonical();
3471 Iterator<TokenTuple> ttItr = ttsOld.iterator();
3472 while( ttItr.hasNext() ) {
3473 TokenTuple ttOld = ttItr.next();
3475 // never remove the identity token from a flagged region
3476 // because it is trivially satisfied
3477 if( hrn.isFlagged() || hrn.isParameter() ) {
3478 if( ttOld == ttException ) {
3483 // does boldB_ttOld allow this token?
3484 boolean foundState = false;
3485 Iterator<ReferenceEdge> incidentEdgeItr = hrn.iteratorToReferencers();
3486 while( incidentEdgeItr.hasNext() ) {
3487 ReferenceEdge incidentEdge = incidentEdgeItr.next();
3489 // if it isn't allowed, mark for removal
3490 Integer idOld = ttOld.getToken();
3491 assert id2hrn.containsKey( idOld );
3492 Hashtable<ReferenceEdge, ReachabilitySet> B = boldB.get( idOld );
3493 ReachabilitySet boldB_ttOld_incident = B.get( incidentEdge );// B is NULL!
3494 if( boldB_ttOld_incident != null &&
3495 boldB_ttOld_incident.contains( ttsOld ) ) {
3501 markedTokens = markedTokens.add( ttOld );
3505 // if there is nothing marked, just move on
3506 if( markedTokens.isEmpty() ) {
3507 hrn.setAlphaNew( hrn.getAlphaNew().union( ttsOld ) );
3511 // remove all marked tokens and establish a change set that should
3512 // propagate backwards over edges from this node
3513 TokenTupleSet ttsPruned = new TokenTupleSet().makeCanonical();
3514 ttItr = ttsOld.iterator();
3515 while( ttItr.hasNext() ) {
3516 TokenTuple ttOld = ttItr.next();
3518 if( !markedTokens.containsTuple( ttOld ) ) {
3519 ttsPruned = ttsPruned.union( ttOld );
3522 assert !ttsOld.equals( ttsPruned );
3524 hrn.setAlphaNew( hrn.getAlphaNew().union( ttsPruned ) );
3525 ChangeTuple ct = new ChangeTuple( ttsOld, ttsPruned ).makeCanonical();
3526 cts = cts.union( ct );
3529 // throw change tuple set on all incident edges
3530 if( !cts.isEmpty() ) {
3531 Iterator<ReferenceEdge> incidentEdgeItr = hrn.iteratorToReferencers();
3532 while( incidentEdgeItr.hasNext() ) {
3533 ReferenceEdge incidentEdge = incidentEdgeItr.next();
3535 edgesForPropagation.add( incidentEdge );
3537 if( edgePlannedChanges.get( incidentEdge ) == null ) {
3538 edgePlannedChanges.put( incidentEdge, cts );
3540 edgePlannedChanges.put(
3542 edgePlannedChanges.get( incidentEdge ).union( cts )
3549 HashSet<ReferenceEdge> edgesUpdated = new HashSet<ReferenceEdge>();
3551 propagateTokensOverEdges( edgesForPropagation,
3555 // at the end of the 1st phase reference edges have
3556 // beta, betaNew that correspond to beta and betaR
3558 // commit beta<-betaNew, so beta=betaR and betaNew
3559 // will represent the beta' calculation in 2nd phase
3561 // commit alpha<-alphaNew because it won't change
3562 HashSet<ReferenceEdge> res = new HashSet<ReferenceEdge>();
3564 Iterator<HeapRegionNode> nodeItr = id2hrn.values().iterator();
3565 while( nodeItr.hasNext() ) {
3566 HeapRegionNode hrn = nodeItr.next();
3567 hrn.applyAlphaNew();
3568 Iterator<ReferenceEdge> itrRes = hrn.iteratorToReferencers();
3569 while( itrRes.hasNext() ) {
3570 res.add( itrRes.next() );
3576 Iterator<ReferenceEdge> edgeItr = res.iterator();
3577 while( edgeItr.hasNext() ) {
3578 ReferenceEdge edge = edgeItr.next();
3579 HeapRegionNode hrn = edge.getDst();
3581 // commit results of last phase
3582 if( edgesUpdated.contains( edge ) ) {
3583 edge.applyBetaNew();
3586 // compute intial condition of 2nd phase
3587 edge.setBetaNew( edge.getBeta().intersection( hrn.getAlpha() ) );
3590 // every edge in the graph is the initial workset
3591 Set<ReferenceEdge> edgeWorkSet = (Set) res.clone();
3592 while( !edgeWorkSet.isEmpty() ) {
3593 ReferenceEdge edgePrime = edgeWorkSet.iterator().next();
3594 edgeWorkSet.remove( edgePrime );
3596 OwnershipNode on = edgePrime.getSrc();
3597 if( !(on instanceof HeapRegionNode) ) {
3600 HeapRegionNode hrn = (HeapRegionNode) on;
3602 Iterator<ReferenceEdge> itrEdge = hrn.iteratorToReferencers();
3603 while( itrEdge.hasNext() ) {
3604 ReferenceEdge edge = itrEdge.next();
3606 ReachabilitySet prevResult = edge.getBetaNew();
3607 assert prevResult != null;
3609 ReachabilitySet intersection = edge.getBeta().intersection( edgePrime.getBetaNew() );
3611 if( prevResult.union( intersection ).size() > prevResult.size() ) {
3612 edge.setBetaNew( prevResult.union( intersection ) );
3613 edgeWorkSet.add( edge );
3618 // commit beta' (beta<-betaNew)
3619 edgeItr = res.iterator();
3620 while( edgeItr.hasNext() ) {
3621 edgeItr.next().applyBetaNew();
3627 ////////////////////////////////////////////////////
3628 // in merge() and equals() methods the suffix A
3629 // represents the passed in graph and the suffix
3630 // B refers to the graph in this object
3631 // Merging means to take the incoming graph A and
3632 // merge it into B, so after the operation graph B
3633 // is the final result.
3634 ////////////////////////////////////////////////////
3635 public void merge(OwnershipGraph og) {
3641 mergeOwnershipNodes(og);
3642 mergeReferenceEdges(og);
3643 mergeParamIndexMappings(og);
3644 mergeAllocationSites(og);
3648 protected void mergeOwnershipNodes(OwnershipGraph og) {
3649 Set sA = og.id2hrn.entrySet();
3650 Iterator iA = sA.iterator();
3651 while( iA.hasNext() ) {
3652 Map.Entry meA = (Map.Entry)iA.next();
3653 Integer idA = (Integer) meA.getKey();
3654 HeapRegionNode hrnA = (HeapRegionNode) meA.getValue();
3656 // if this graph doesn't have a node the
3657 // incoming graph has, allocate it
3658 if( !id2hrn.containsKey(idA) ) {
3659 HeapRegionNode hrnB = hrnA.copy();
3660 id2hrn.put(idA, hrnB);
3663 // otherwise this is a node present in both graphs
3664 // so make the new reachability set a union of the
3665 // nodes' reachability sets
3666 HeapRegionNode hrnB = id2hrn.get(idA);
3667 hrnB.setAlpha(hrnB.getAlpha().union(hrnA.getAlpha() ) );
3671 // now add any label nodes that are in graph B but
3673 sA = og.td2ln.entrySet();
3675 while( iA.hasNext() ) {
3676 Map.Entry meA = (Map.Entry)iA.next();
3677 TempDescriptor tdA = (TempDescriptor) meA.getKey();
3678 LabelNode lnA = (LabelNode) meA.getValue();
3680 // if the label doesn't exist in B, allocate and add it
3681 LabelNode lnB = getLabelNodeFromTemp(tdA);
3685 protected void mergeReferenceEdges(OwnershipGraph og) {
3688 Set sA = og.id2hrn.entrySet();
3689 Iterator iA = sA.iterator();
3690 while( iA.hasNext() ) {
3691 Map.Entry meA = (Map.Entry)iA.next();
3692 Integer idA = (Integer) meA.getKey();
3693 HeapRegionNode hrnA = (HeapRegionNode) meA.getValue();
3695 Iterator<ReferenceEdge> heapRegionsItrA = hrnA.iteratorToReferencees();
3696 while( heapRegionsItrA.hasNext() ) {
3697 ReferenceEdge edgeA = heapRegionsItrA.next();
3698 HeapRegionNode hrnChildA = edgeA.getDst();
3699 Integer idChildA = hrnChildA.getID();
3701 // at this point we know an edge in graph A exists
3702 // idA -> idChildA, does this exist in B?
3703 assert id2hrn.containsKey(idA);
3704 HeapRegionNode hrnB = id2hrn.get(idA);
3705 ReferenceEdge edgeToMerge = null;
3707 Iterator<ReferenceEdge> heapRegionsItrB = hrnB.iteratorToReferencees();
3708 while( heapRegionsItrB.hasNext() &&
3709 edgeToMerge == null ) {
3711 ReferenceEdge edgeB = heapRegionsItrB.next();
3712 HeapRegionNode hrnChildB = edgeB.getDst();
3713 Integer idChildB = hrnChildB.getID();
3715 // don't use the ReferenceEdge.equals() here because
3716 // we're talking about existence between graphs
3717 if( idChildB.equals( idChildA ) &&
3718 edgeB.typeAndFieldEquals( edgeA ) ) {
3720 edgeToMerge = edgeB;
3724 // if the edge from A was not found in B,
3726 if( edgeToMerge == null ) {
3727 assert id2hrn.containsKey(idChildA);
3728 HeapRegionNode hrnChildB = id2hrn.get(idChildA);
3729 edgeToMerge = edgeA.copy();
3730 edgeToMerge.setSrc(hrnB);
3731 edgeToMerge.setDst(hrnChildB);
3732 addReferenceEdge(hrnB, hrnChildB, edgeToMerge);
3734 // otherwise, the edge already existed in both graphs
3735 // so merge their reachability sets
3737 // just replace this beta set with the union
3738 assert edgeToMerge != null;
3739 edgeToMerge.setBeta(
3740 edgeToMerge.getBeta().union(edgeA.getBeta() )
3743 edgeToMerge.unionTaintIdentifier(edgeA.getTaintIdentifier());
3744 if( !edgeA.isInitialParam() ) {
3745 edgeToMerge.setIsInitialParam(false);
3751 // and then again with label nodes
3752 sA = og.td2ln.entrySet();
3754 while( iA.hasNext() ) {
3755 Map.Entry meA = (Map.Entry)iA.next();
3756 TempDescriptor tdA = (TempDescriptor) meA.getKey();
3757 LabelNode lnA = (LabelNode) meA.getValue();
3759 Iterator<ReferenceEdge> heapRegionsItrA = lnA.iteratorToReferencees();
3760 while( heapRegionsItrA.hasNext() ) {
3761 ReferenceEdge edgeA = heapRegionsItrA.next();
3762 HeapRegionNode hrnChildA = edgeA.getDst();
3763 Integer idChildA = hrnChildA.getID();
3765 // at this point we know an edge in graph A exists
3766 // tdA -> idChildA, does this exist in B?
3767 assert td2ln.containsKey(tdA);
3768 LabelNode lnB = td2ln.get(tdA);
3769 ReferenceEdge edgeToMerge = null;
3771 Iterator<ReferenceEdge> heapRegionsItrB = lnB.iteratorToReferencees();
3772 while( heapRegionsItrB.hasNext() &&
3773 edgeToMerge == null ) {
3775 ReferenceEdge edgeB = heapRegionsItrB.next();
3776 HeapRegionNode hrnChildB = edgeB.getDst();
3777 Integer idChildB = hrnChildB.getID();
3779 // don't use the ReferenceEdge.equals() here because
3780 // we're talking about existence between graphs
3781 if( idChildB.equals( idChildA ) &&
3782 edgeB.typeAndFieldEquals( edgeA ) ) {
3784 edgeToMerge = edgeB;
3788 // if the edge from A was not found in B,
3790 if( edgeToMerge == null ) {
3791 assert id2hrn.containsKey(idChildA);
3792 HeapRegionNode hrnChildB = id2hrn.get(idChildA);
3793 edgeToMerge = edgeA.copy();
3794 edgeToMerge.setSrc(lnB);
3795 edgeToMerge.setDst(hrnChildB);
3796 addReferenceEdge(lnB, hrnChildB, edgeToMerge);
3798 // otherwise, the edge already existed in both graphs
3799 // so merge their reachability sets
3801 // just replace this beta set with the union
3802 edgeToMerge.setBeta(
3803 edgeToMerge.getBeta().union(edgeA.getBeta() )
3806 edgeToMerge.unionTaintIdentifier(edgeA.getTaintIdentifier());
3807 if( !edgeA.isInitialParam() ) {
3808 edgeToMerge.setIsInitialParam(false);
3815 // you should only merge ownership graphs that have the
3816 // same number of parameters, or if one or both parameter
3817 // index tables are empty
3818 protected void mergeParamIndexMappings(OwnershipGraph og) {
3820 if( idPrimary2paramIndexSet.size() == 0 ) {
3822 idPrimary2paramIndexSet = og.idPrimary2paramIndexSet;
3823 paramIndex2idPrimary = og.paramIndex2idPrimary;
3825 idSecondary2paramIndexSet = og.idSecondary2paramIndexSet;
3826 paramIndex2idSecondary = og.paramIndex2idSecondary;
3828 paramIndex2tdQ = og.paramIndex2tdQ;
3829 paramIndex2tdR = og.paramIndex2tdR;
3831 paramTokenPrimary2paramIndex = og.paramTokenPrimary2paramIndex;
3832 paramIndex2paramTokenPrimary = og.paramIndex2paramTokenPrimary;
3834 paramTokenSecondary2paramIndex = og.paramTokenSecondary2paramIndex;
3835 paramIndex2paramTokenSecondary = og.paramIndex2paramTokenSecondary;
3836 paramTokenSecondaryPlus2paramIndex = og.paramTokenSecondaryPlus2paramIndex;
3837 paramIndex2paramTokenSecondaryPlus = og.paramIndex2paramTokenSecondaryPlus;
3838 paramTokenSecondaryStar2paramIndex = og.paramTokenSecondaryStar2paramIndex;
3839 paramIndex2paramTokenSecondaryStar = og.paramIndex2paramTokenSecondaryStar;
3844 if( og.idPrimary2paramIndexSet.size() == 0 ) {
3846 og.idPrimary2paramIndexSet = idPrimary2paramIndexSet;
3847 og.paramIndex2idPrimary = paramIndex2idPrimary;
3849 og.idSecondary2paramIndexSet = idSecondary2paramIndexSet;
3850 og.paramIndex2idSecondary = paramIndex2idSecondary;
3852 og.paramIndex2tdQ = paramIndex2tdQ;
3853 og.paramIndex2tdR = paramIndex2tdR;
3855 og.paramTokenPrimary2paramIndex = paramTokenPrimary2paramIndex;
3856 og.paramIndex2paramTokenPrimary = paramIndex2paramTokenPrimary;
3858 og.paramTokenSecondary2paramIndex = paramTokenSecondary2paramIndex;
3859 og.paramIndex2paramTokenSecondary = paramIndex2paramTokenSecondary;
3860 og.paramTokenSecondaryPlus2paramIndex = paramTokenSecondaryPlus2paramIndex;
3861 og.paramIndex2paramTokenSecondaryPlus = paramIndex2paramTokenSecondaryPlus;
3862 og.paramTokenSecondaryStar2paramIndex = paramTokenSecondaryStar2paramIndex;
3863 og.paramIndex2paramTokenSecondaryStar = paramIndex2paramTokenSecondaryStar;
3868 assert idPrimary2paramIndexSet.size() == og.idPrimary2paramIndexSet.size();
3869 assert idSecondary2paramIndexSet.size() == og.idSecondary2paramIndexSet.size();
3872 protected void mergeAllocationSites(OwnershipGraph og) {
3873 allocationSites.addAll(og.allocationSites);
3878 // it is necessary in the equals() member functions
3879 // to "check both ways" when comparing the data
3880 // structures of two graphs. For instance, if all
3881 // edges between heap region nodes in graph A are
3882 // present and equal in graph B it is not sufficient
3883 // to say the graphs are equal. Consider that there
3884 // may be edges in graph B that are not in graph A.
3885 // the only way to know that all edges in both graphs
3886 // are equally present is to iterate over both data
3887 // structures and compare against the other graph.
3888 public boolean equals(OwnershipGraph og) {
3894 if( !areHeapRegionNodesEqual(og) ) {
3898 if( !areLabelNodesEqual(og) ) {
3902 if( !areReferenceEdgesEqual(og) ) {
3906 if( !areParamIndexMappingsEqual(og) ) {
3910 // if everything is equal up to this point,
3911 // assert that allocationSites is also equal--
3912 // this data is redundant and kept for efficiency
3913 assert allocationSites.equals(og.allocationSites);
3918 protected boolean areHeapRegionNodesEqual(OwnershipGraph og) {
3920 if( !areallHRNinAalsoinBandequal(this, og) ) {
3924 if( !areallHRNinAalsoinBandequal(og, this) ) {
3931 static protected boolean areallHRNinAalsoinBandequal(OwnershipGraph ogA,
3932 OwnershipGraph ogB) {
3933 Set sA = ogA.id2hrn.entrySet();
3934 Iterator iA = sA.iterator();
3935 while( iA.hasNext() ) {
3936 Map.Entry meA = (Map.Entry)iA.next();
3937 Integer idA = (Integer) meA.getKey();
3938 HeapRegionNode hrnA = (HeapRegionNode) meA.getValue();
3940 if( !ogB.id2hrn.containsKey(idA) ) {
3944 HeapRegionNode hrnB = ogB.id2hrn.get(idA);
3945 if( !hrnA.equalsIncludingAlpha(hrnB) ) {
3954 protected boolean areLabelNodesEqual(OwnershipGraph og) {
3956 if( !areallLNinAalsoinBandequal(this, og) ) {
3960 if( !areallLNinAalsoinBandequal(og, this) ) {
3967 static protected boolean areallLNinAalsoinBandequal(OwnershipGraph ogA,
3968 OwnershipGraph ogB) {
3969 Set sA = ogA.td2ln.entrySet();
3970 Iterator iA = sA.iterator();
3971 while( iA.hasNext() ) {
3972 Map.Entry meA = (Map.Entry)iA.next();
3973 TempDescriptor tdA = (TempDescriptor) meA.getKey();
3975 if( !ogB.td2ln.containsKey(tdA) ) {
3984 protected boolean areReferenceEdgesEqual(OwnershipGraph og) {
3985 if( !areallREinAandBequal(this, og) ) {
3992 static protected boolean areallREinAandBequal(OwnershipGraph ogA,
3993 OwnershipGraph ogB) {
3995 // check all the heap region->heap region edges
3996 Set sA = ogA.id2hrn.entrySet();
3997 Iterator iA = sA.iterator();
3998 while( iA.hasNext() ) {
3999 Map.Entry meA = (Map.Entry)iA.next();
4000 Integer idA = (Integer) meA.getKey();
4001 HeapRegionNode hrnA = (HeapRegionNode) meA.getValue();
4003 // we should have already checked that the same
4004 // heap regions exist in both graphs
4005 assert ogB.id2hrn.containsKey(idA);
4007 if( !areallREfromAequaltoB(ogA, hrnA, ogB) ) {
4011 // then check every edge in B for presence in A, starting
4012 // from the same parent HeapRegionNode
4013 HeapRegionNode hrnB = ogB.id2hrn.get(idA);
4015 if( !areallREfromAequaltoB(ogB, hrnB, ogA) ) {
4020 // then check all the label->heap region edges
4021 sA = ogA.td2ln.entrySet();
4023 while( iA.hasNext() ) {
4024 Map.Entry meA = (Map.Entry)iA.next();
4025 TempDescriptor tdA = (TempDescriptor) meA.getKey();
4026 LabelNode lnA = (LabelNode) meA.getValue();
4028 // we should have already checked that the same
4029 // label nodes exist in both graphs
4030 assert ogB.td2ln.containsKey(tdA);
4032 if( !areallREfromAequaltoB(ogA, lnA, ogB) ) {
4036 // then check every edge in B for presence in A, starting
4037 // from the same parent LabelNode
4038 LabelNode lnB = ogB.td2ln.get(tdA);
4040 if( !areallREfromAequaltoB(ogB, lnB, ogA) ) {
4049 static protected boolean areallREfromAequaltoB(OwnershipGraph ogA,
4051 OwnershipGraph ogB) {
4053 Iterator<ReferenceEdge> itrA = onA.iteratorToReferencees();
4054 while( itrA.hasNext() ) {
4055 ReferenceEdge edgeA = itrA.next();
4056 HeapRegionNode hrnChildA = edgeA.getDst();
4057 Integer idChildA = hrnChildA.getID();
4059 assert ogB.id2hrn.containsKey(idChildA);
4061 // at this point we know an edge in graph A exists
4062 // onA -> idChildA, does this exact edge exist in B?
4063 boolean edgeFound = false;
4065 OwnershipNode onB = null;
4066 if( onA instanceof HeapRegionNode ) {
4067 HeapRegionNode hrnA = (HeapRegionNode) onA;
4068 onB = ogB.id2hrn.get(hrnA.getID() );
4070 LabelNode lnA = (LabelNode) onA;
4071 onB = ogB.td2ln.get(lnA.getTempDescriptor() );
4074 Iterator<ReferenceEdge> itrB = onB.iteratorToReferencees();
4075 while( itrB.hasNext() ) {
4076 ReferenceEdge edgeB = itrB.next();
4077 HeapRegionNode hrnChildB = edgeB.getDst();
4078 Integer idChildB = hrnChildB.getID();
4080 if( idChildA.equals( idChildB ) &&
4081 edgeA.typeAndFieldEquals( edgeB ) ) {
4083 // there is an edge in the right place with the right field,
4084 // but do they have the same attributes?
4085 if( edgeA.getBeta().equals(edgeB.getBeta() ) ) {
4100 protected boolean areParamIndexMappingsEqual(OwnershipGraph og) {
4102 if( idPrimary2paramIndexSet.size() != og.idPrimary2paramIndexSet.size() ) {
4106 if( idSecondary2paramIndexSet.size() != og.idSecondary2paramIndexSet.size() ) {
4114 public Set<HeapRegionNode> hasPotentialAlias( HeapRegionNode hrn1, HeapRegionNode hrn2 ) {
4115 assert hrn1 != null;
4116 assert hrn2 != null;
4118 // then get the various tokens for these heap regions
4119 TokenTuple h1 = new TokenTuple(hrn1.getID(),
4120 !hrn1.isSingleObject(),
4121 TokenTuple.ARITY_ONE).makeCanonical();
4123 TokenTuple h1plus = new TokenTuple(hrn1.getID(),
4124 !hrn1.isSingleObject(),
4125 TokenTuple.ARITY_ONEORMORE).makeCanonical();
4127 TokenTuple h1star = new TokenTuple(hrn1.getID(),
4128 !hrn1.isSingleObject(),
4129 TokenTuple.ARITY_ZEROORMORE).makeCanonical();
4131 TokenTuple h2 = new TokenTuple(hrn2.getID(),
4132 !hrn2.isSingleObject(),
4133 TokenTuple.ARITY_ONE).makeCanonical();
4135 TokenTuple h2plus = new TokenTuple(hrn2.getID(),
4136 !hrn2.isSingleObject(),
4137 TokenTuple.ARITY_ONEORMORE).makeCanonical();
4139 TokenTuple h2star = new TokenTuple(hrn2.getID(),
4140 !hrn2.isSingleObject(),
4141 TokenTuple.ARITY_ZEROORMORE).makeCanonical();
4143 // then get the merged beta of all out-going edges from these heap regions
4144 ReachabilitySet beta1 = new ReachabilitySet().makeCanonical();
4145 Iterator<ReferenceEdge> itrEdge = hrn1.iteratorToReferencees();
4146 while( itrEdge.hasNext() ) {
4147 ReferenceEdge edge = itrEdge.next();
4148 beta1 = beta1.union( edge.getBeta() );
4151 ReachabilitySet beta2 = new ReachabilitySet().makeCanonical();
4152 itrEdge = hrn2.iteratorToReferencees();
4153 while( itrEdge.hasNext() ) {
4154 ReferenceEdge edge = itrEdge.next();
4155 beta2 = beta2.union( edge.getBeta() );
4158 boolean aliasDetected = false;
4160 // only do this one if they are different tokens
4162 beta1.containsTupleSetWithBoth(h1, h2) ) {
4163 aliasDetected = true;
4165 if( beta1.containsTupleSetWithBoth(h1plus, h2) ) {
4166 aliasDetected = true;
4168 if( beta1.containsTupleSetWithBoth(h1star, h2) ) {
4169 aliasDetected = true;
4171 if( beta1.containsTupleSetWithBoth(h1, h2plus) ) {
4172 aliasDetected = true;
4174 if( beta1.containsTupleSetWithBoth(h1plus, h2plus) ) {
4175 aliasDetected = true;
4177 if( beta1.containsTupleSetWithBoth(h1star, h2plus) ) {
4178 aliasDetected = true;
4180 if( beta1.containsTupleSetWithBoth(h1, h2star) ) {
4181 aliasDetected = true;
4183 if( beta1.containsTupleSetWithBoth(h1plus, h2star) ) {
4184 aliasDetected = true;
4186 if( beta1.containsTupleSetWithBoth(h1star, h2star) ) {
4187 aliasDetected = true;
4191 beta2.containsTupleSetWithBoth(h1, h2) ) {
4192 aliasDetected = true;
4194 if( beta2.containsTupleSetWithBoth(h1plus, h2) ) {
4195 aliasDetected = true;
4197 if( beta2.containsTupleSetWithBoth(h1star, h2) ) {
4198 aliasDetected = true;
4200 if( beta2.containsTupleSetWithBoth(h1, h2plus) ) {
4201 aliasDetected = true;
4203 if( beta2.containsTupleSetWithBoth(h1plus, h2plus) ) {
4204 aliasDetected = true;
4206 if( beta2.containsTupleSetWithBoth(h1star, h2plus) ) {
4207 aliasDetected = true;
4209 if( beta2.containsTupleSetWithBoth(h1, h2star) ) {
4210 aliasDetected = true;
4212 if( beta2.containsTupleSetWithBoth(h1plus, h2star) ) {
4213 aliasDetected = true;
4215 if( beta2.containsTupleSetWithBoth(h1star, h2star) ) {
4216 aliasDetected = true;
4219 Set<HeapRegionNode> common = new HashSet<HeapRegionNode>();
4220 if( aliasDetected ) {
4221 common = findCommonReachableNodes( hrn1, hrn2 );
4222 assert !common.isEmpty();
4229 public Set<HeapRegionNode> hasPotentialAlias(Integer paramIndex1, Integer paramIndex2) {
4231 // get parameter 1's heap regions
4232 assert paramIndex2idPrimary.containsKey(paramIndex1);
4233 Integer idParamPri1 = paramIndex2idPrimary.get(paramIndex1);
4235 assert id2hrn.containsKey(idParamPri1);
4236 HeapRegionNode hrnParamPri1 = id2hrn.get(idParamPri1);
4237 assert hrnParamPri1 != null;
4239 HeapRegionNode hrnParamSec1 = null;
4240 if( paramIndex2idSecondary.containsKey(paramIndex1) ) {
4241 Integer idParamSec1 = paramIndex2idSecondary.get(paramIndex1);
4243 assert id2hrn.containsKey(idParamSec1);
4244 hrnParamSec1 = id2hrn.get(idParamSec1);
4245 assert hrnParamSec1 != null;
4249 // get the other parameter
4250 assert paramIndex2idPrimary.containsKey(paramIndex2);
4251 Integer idParamPri2 = paramIndex2idPrimary.get(paramIndex2);
4253 assert id2hrn.containsKey(idParamPri2);
4254 HeapRegionNode hrnParamPri2 = id2hrn.get(idParamPri2);
4255 assert hrnParamPri2 != null;
4257 HeapRegionNode hrnParamSec2 = null;
4258 if( paramIndex2idSecondary.containsKey(paramIndex2) ) {
4259 Integer idParamSec2 = paramIndex2idSecondary.get(paramIndex2);
4261 assert id2hrn.containsKey(idParamSec2);
4262 hrnParamSec2 = id2hrn.get(idParamSec2);
4263 assert hrnParamSec2 != null;
4266 Set<HeapRegionNode> common = new HashSet<HeapRegionNode>();
4267 common.addAll( hasPotentialAlias( hrnParamPri1, hrnParamPri2 ) );
4269 if( hrnParamSec1 != null ) {
4270 common.addAll( hasPotentialAlias( hrnParamSec1, hrnParamPri2 ) );
4273 if( hrnParamSec2 != null ) {
4274 common.addAll( hasPotentialAlias( hrnParamSec2, hrnParamPri1 ) );
4277 if( hrnParamSec1 != null && hrnParamSec2 != null ) {
4278 common.addAll( hasPotentialAlias( hrnParamSec1, hrnParamSec2 ) );
4285 public Set<HeapRegionNode> hasPotentialAlias(Integer paramIndex, AllocationSite as) {
4287 // get parameter's heap regions
4288 assert paramIndex2idPrimary.containsKey(paramIndex);
4289 Integer idParamPri = paramIndex2idPrimary.get(paramIndex);
4291 assert id2hrn.containsKey(idParamPri);
4292 HeapRegionNode hrnParamPri = id2hrn.get(idParamPri);
4293 assert hrnParamPri != null;
4295 HeapRegionNode hrnParamSec = null;
4296 if( paramIndex2idSecondary.containsKey(paramIndex) ) {
4297 Integer idParamSec = paramIndex2idSecondary.get(paramIndex);
4299 assert id2hrn.containsKey(idParamSec);
4300 hrnParamSec = id2hrn.get(idParamSec);
4301 assert hrnParamSec != null;
4305 assert id2hrn.containsKey( as.getSummary() );
4306 HeapRegionNode hrnSummary = id2hrn.get( as.getSummary() );
4307 assert hrnSummary != null;
4309 Set<HeapRegionNode> common = hasPotentialAlias( hrnParamPri, hrnSummary );
4311 if( hrnParamSec != null ) {
4312 common.addAll( hasPotentialAlias( hrnParamSec, hrnSummary ) );
4315 // check for other nodes
4316 for( int i = 0; i < as.getAllocationDepth(); ++i ) {
4318 assert id2hrn.containsKey( as.getIthOldest( i ) );
4319 HeapRegionNode hrnIthOldest = id2hrn.get( as.getIthOldest( i ) );
4320 assert hrnIthOldest != null;
4322 common = hasPotentialAlias( hrnParamPri, hrnIthOldest );
4324 if( hrnParamSec != null ) {
4325 common.addAll( hasPotentialAlias( hrnParamSec, hrnIthOldest ) );
4333 public Set<HeapRegionNode> hasPotentialAlias(AllocationSite as1, AllocationSite as2) {
4335 // get summary node 1's alpha
4336 Integer idSum1 = as1.getSummary();
4337 assert id2hrn.containsKey(idSum1);
4338 HeapRegionNode hrnSum1 = id2hrn.get(idSum1);
4339 assert hrnSum1 != null;
4341 // get summary node 2's alpha
4342 Integer idSum2 = as2.getSummary();
4343 assert id2hrn.containsKey(idSum2);
4344 HeapRegionNode hrnSum2 = id2hrn.get(idSum2);
4345 assert hrnSum2 != null;
4347 Set<HeapRegionNode> common = hasPotentialAlias( hrnSum1, hrnSum2 );
4349 // check sum2 against alloc1 nodes
4350 for( int i = 0; i < as1.getAllocationDepth(); ++i ) {
4351 Integer idI1 = as1.getIthOldest(i);
4352 assert id2hrn.containsKey(idI1);
4353 HeapRegionNode hrnI1 = id2hrn.get(idI1);
4354 assert hrnI1 != null;
4356 common.addAll( hasPotentialAlias( hrnI1, hrnSum2 ) );
4359 // check sum1 against alloc2 nodes
4360 for( int i = 0; i < as2.getAllocationDepth(); ++i ) {
4361 Integer idI2 = as2.getIthOldest(i);
4362 assert id2hrn.containsKey(idI2);
4363 HeapRegionNode hrnI2 = id2hrn.get(idI2);
4364 assert hrnI2 != null;
4366 common.addAll( hasPotentialAlias( hrnSum1, hrnI2 ) );
4368 // while we're at it, do an inner loop for alloc2 vs alloc1 nodes
4369 for( int j = 0; j < as1.getAllocationDepth(); ++j ) {
4370 Integer idI1 = as1.getIthOldest(j);
4372 // if these are the same site, don't look for the same token, no alias.
4373 // different tokens of the same site could alias together though
4374 if( idI1.equals( idI2 ) ) {
4378 HeapRegionNode hrnI1 = id2hrn.get(idI1);
4380 common.addAll( hasPotentialAlias( hrnI1, hrnI2 ) );
4388 public Set<HeapRegionNode> findCommonReachableNodes( HeapRegionNode hrn1,
4389 HeapRegionNode hrn2 ) {
4391 Set<HeapRegionNode> reachableNodes1 = new HashSet<HeapRegionNode>();
4392 Set<HeapRegionNode> reachableNodes2 = new HashSet<HeapRegionNode>();
4394 Set<HeapRegionNode> todoNodes1 = new HashSet<HeapRegionNode>();
4395 todoNodes1.add( hrn1 );
4397 Set<HeapRegionNode> todoNodes2 = new HashSet<HeapRegionNode>();
4398 todoNodes2.add( hrn2 );
4400 // follow links until all reachable nodes have been found
4401 while( !todoNodes1.isEmpty() ) {
4402 HeapRegionNode hrn = todoNodes1.iterator().next();
4403 todoNodes1.remove( hrn );
4404 reachableNodes1.add(hrn);
4406 Iterator<ReferenceEdge> edgeItr = hrn.iteratorToReferencees();
4407 while( edgeItr.hasNext() ) {
4408 ReferenceEdge edge = edgeItr.next();
4410 if( !reachableNodes1.contains( edge.getDst() ) ) {
4411 todoNodes1.add( edge.getDst() );
4416 while( !todoNodes2.isEmpty() ) {
4417 HeapRegionNode hrn = todoNodes2.iterator().next();
4418 todoNodes2.remove( hrn );
4419 reachableNodes2.add(hrn);
4421 Iterator<ReferenceEdge> edgeItr = hrn.iteratorToReferencees();
4422 while( edgeItr.hasNext() ) {
4423 ReferenceEdge edge = edgeItr.next();
4425 if( !reachableNodes2.contains( edge.getDst() ) ) {
4426 todoNodes2.add( edge.getDst() );
4431 Set<HeapRegionNode> intersection =
4432 new HashSet<HeapRegionNode>( reachableNodes1 );
4434 intersection.retainAll( reachableNodes2 );
4436 return intersection;
4440 // for writing ownership graphs to dot files
4441 public void writeGraph(MethodContext mc,
4443 boolean writeLabels,
4444 boolean labelSelect,
4445 boolean pruneGarbage,
4446 boolean writeReferencers,
4447 boolean writeParamMappings
4448 ) throws java.io.IOException {
4460 public void writeGraph(MethodContext mc,
4461 boolean writeLabels,
4462 boolean labelSelect,
4463 boolean pruneGarbage,
4464 boolean writeReferencers,
4465 boolean writeParamMappings
4466 ) throws java.io.IOException {
4468 writeGraph(mc+"COMPLETE",
4477 public void writeGraph(MethodContext mc,
4479 boolean writeLabels,
4480 boolean labelSelect,
4481 boolean pruneGarbage,
4482 boolean writeReferencers,
4483 boolean writeParamMappings
4484 ) throws java.io.IOException {
4488 writeGraph(mc+"COMPLETE"+String.format("%05d", numUpdate),
4497 public void writeGraph(String graphName,
4498 boolean writeLabels,
4499 boolean labelSelect,
4500 boolean pruneGarbage,
4501 boolean writeReferencers,
4502 boolean writeParamMappings
4503 ) throws java.io.IOException {
4505 // remove all non-word characters from the graph name so
4506 // the filename and identifier in dot don't cause errors
4507 graphName = graphName.replaceAll("[\\W]", "");
4509 BufferedWriter bw = new BufferedWriter(new FileWriter(graphName+".dot") );
4510 bw.write("digraph "+graphName+" {\n");
4512 HashSet<HeapRegionNode> visited = new HashSet<HeapRegionNode>();
4514 // then visit every heap region node
4515 Set s = id2hrn.entrySet();
4516 Iterator i = s.iterator();
4517 while( i.hasNext() ) {
4518 Map.Entry me = (Map.Entry)i.next();
4519 HeapRegionNode hrn = (HeapRegionNode) me.getValue();
4521 if( !pruneGarbage ||
4522 (hrn.isFlagged() && hrn.getID() > 0) ||
4523 hrn.getDescription().startsWith("param")
4526 if( !visited.contains(hrn) ) {
4527 traverseHeapRegionNodes(VISIT_HRN_WRITE_FULL,
4537 bw.write(" graphTitle[label=\""+graphName+"\",shape=box];\n");
4539 if( writeParamMappings ) {
4541 Set df = paramIndex2id.entrySet();
4542 Iterator ih = df.iterator();
4543 while( ih.hasNext() ) {
4544 Map.Entry meh = (Map.Entry)ih.next();
4545 Integer pi = (Integer) meh.getKey();
4546 Integer id = (Integer) meh.getValue();
4547 bw.write(" pindex"+pi+"[label=\""+pi+" to "+id+"\",shape=box];\n");
4552 // then visit every label node, useful for debugging
4554 s = td2ln.entrySet();
4556 while( i.hasNext() ) {
4557 Map.Entry me = (Map.Entry)i.next();
4558 LabelNode ln = (LabelNode) me.getValue();
4561 String labelStr = ln.getTempDescriptorString();
4562 if( labelStr.startsWith("___temp") ||
4563 labelStr.startsWith("___dst") ||
4564 labelStr.startsWith("___srctmp") ||
4565 labelStr.startsWith("___neverused") ||
4566 labelStr.contains(qString) ||
4567 labelStr.contains(rString) ||
4568 labelStr.contains(blobString)
4574 //bw.write(" "+ln.toString() + ";\n");
4576 Iterator<ReferenceEdge> heapRegionsItr = ln.iteratorToReferencees();
4577 while( heapRegionsItr.hasNext() ) {
4578 ReferenceEdge edge = heapRegionsItr.next();
4579 HeapRegionNode hrn = edge.getDst();
4581 if( pruneGarbage && !visited.contains(hrn) ) {
4582 traverseHeapRegionNodes(VISIT_HRN_WRITE_FULL,
4590 bw.write(" " + ln.toString() +
4591 " -> " + hrn.toString() +
4592 "[label=\"" + edge.toGraphEdgeString() +
4603 protected void traverseHeapRegionNodes(int mode,
4607 HashSet<HeapRegionNode> visited,
4608 boolean writeReferencers
4609 ) throws java.io.IOException {
4611 if( visited.contains(hrn) ) {
4617 case VISIT_HRN_WRITE_FULL:
4619 String attributes = "[";
4621 if( hrn.isSingleObject() ) {
4622 attributes += "shape=box";
4624 attributes += "shape=Msquare";
4627 if( hrn.isFlagged() ) {
4628 attributes += ",style=filled,fillcolor=lightgrey";
4631 attributes += ",label=\"ID" +
4635 if( hrn.getType() != null ) {
4636 attributes += hrn.getType().toPrettyString() + "\\n";
4639 attributes += hrn.getDescription() +
4641 hrn.getAlphaString() +
4644 bw.write(" " + hrn.toString() + attributes + ";\n");
4649 // useful for debugging
4652 if( writeReferencers ) {
4653 OwnershipNode onRef = null;
4654 Iterator refItr = hrn.iteratorToReferencers();
4655 while( refItr.hasNext() ) {
4656 onRef = (OwnershipNode) refItr.next();
4659 case VISIT_HRN_WRITE_FULL:
4660 bw.write(" " + hrn.toString() +
4661 " -> " + onRef.toString() +
4662 "[color=lightgray];\n");
4669 Iterator<ReferenceEdge> childRegionsItr = hrn.iteratorToReferencees();
4670 while( childRegionsItr.hasNext() ) {
4671 ReferenceEdge edge = childRegionsItr.next();
4672 HeapRegionNode hrnChild = edge.getDst();
4675 case VISIT_HRN_WRITE_FULL:
4676 bw.write(" " + hrn.toString() +
4677 " -> " + hrnChild.toString() +
4678 "[label=\"" + edge.toGraphEdgeString() +
4683 traverseHeapRegionNodes(mode,
4692 public int getTaintIdentifierFromHRN(HeapRegionNode hrn){
4693 HashSet<ReferenceEdge> referenceEdges=hrn.referencers;
4694 Iterator<ReferenceEdge> iter=referenceEdges.iterator();
4696 int taintIdentifier=0;
4697 while(iter.hasNext()){
4698 ReferenceEdge edge=iter.next();
4699 taintIdentifier=taintIdentifier | edge.getTaintIdentifier();
4702 return taintIdentifier;
4706 public void propagateTaintIdentifier(HeapRegionNode hrn, int newTaintIdentifier, HashSet<HeapRegionNode> visitedSet){
4708 HashSet<ReferenceEdge> setEdge=hrn.referencers;
4709 Iterator<ReferenceEdge> iter=setEdge.iterator();
4710 while(iter.hasNext()){
4711 ReferenceEdge edge= iter.next();
4712 edge.unionTaintIdentifier(newTaintIdentifier);
4713 if(edge.getSrc() instanceof HeapRegionNode){
4715 HeapRegionNode refHRN=(HeapRegionNode)edge.getSrc();
4716 //check whether it is reflexive edge
4717 if(!refHRN.equals(hrn) && !visitedSet.contains(refHRN)){
4718 visitedSet.add(refHRN);
4719 propagateTaintIdentifier((HeapRegionNode)edge.getSrc(),newTaintIdentifier,visitedSet);
4727 public void depropagateTaintIdentifier(HeapRegionNode hrn, int newTaintIdentifier, HashSet<HeapRegionNode> visitedSet){
4729 HashSet<ReferenceEdge> setEdge=hrn.referencers;
4730 Iterator<ReferenceEdge> iter=setEdge.iterator();
4731 while(iter.hasNext()){
4732 ReferenceEdge edge= iter.next();
4733 edge.minusTaintIdentifier(newTaintIdentifier);
4734 if(edge.getSrc() instanceof HeapRegionNode){
4736 HeapRegionNode refHRN=(HeapRegionNode)edge.getSrc();
4737 //check whether it is reflexive edge
4738 if(!refHRN.equals(hrn) && !visitedSet.contains(refHRN)){
4739 visitedSet.add(refHRN);
4740 depropagateTaintIdentifier((HeapRegionNode)edge.getSrc(),newTaintIdentifier,visitedSet);