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 referencer.removeReferencee(edge);
217 referencee.removeReferencer(edge);
220 protected void clearReferenceEdgesFrom(OwnershipNode referencer,
224 assert referencer != null;
226 // get a copy of the set to iterate over, otherwise
227 // we will be trying to take apart the set as we
228 // are iterating over it, which won't work
229 Iterator<ReferenceEdge> i = referencer.iteratorToReferenceesClone();
230 while( i.hasNext() ) {
231 ReferenceEdge edge = i.next();
234 (edge.typeEquals( type ) && edge.fieldEquals( field ))
237 HeapRegionNode referencee = edge.getDst();
239 removeReferenceEdge(referencer,
247 protected void clearReferenceEdgesTo(HeapRegionNode referencee,
251 assert referencee != null;
253 // get a copy of the set to iterate over, otherwise
254 // we will be trying to take apart the set as we
255 // are iterating over it, which won't work
256 Iterator<ReferenceEdge> i = referencee.iteratorToReferencersClone();
257 while( i.hasNext() ) {
258 ReferenceEdge edge = i.next();
261 (edge.typeEquals( type ) && edge.fieldEquals( field ))
264 OwnershipNode referencer = edge.getSrc();
266 removeReferenceEdge(referencer,
275 ////////////////////////////////////////////////////
277 // Assignment Operation Methods
279 // These methods are high-level operations for
280 // modeling program assignment statements using
281 // the low-level reference create/remove methods
284 // The destination in an assignment statement is
285 // going to have new references. The method of
286 // determining the references depends on the type
287 // of the FlatNode assignment and the predicates
288 // of the nodes and edges involved.
290 ////////////////////////////////////////////////////
291 public void assignTempXEqualToTempY(TempDescriptor x,
294 LabelNode lnX = getLabelNodeFromTemp(x);
295 LabelNode lnY = getLabelNodeFromTemp(y);
297 clearReferenceEdgesFrom(lnX, null, null, true);
299 Iterator<ReferenceEdge> itrYhrn = lnY.iteratorToReferencees();
300 while( itrYhrn.hasNext() ) {
301 ReferenceEdge edgeY = itrYhrn.next();
302 HeapRegionNode referencee = edgeY.getDst();
303 ReferenceEdge edgeNew = edgeY.copy();
306 addReferenceEdge(lnX, referencee, edgeNew);
311 public void assignTypedTempXEqualToTempY(TempDescriptor x,
313 TypeDescriptor type) {
315 LabelNode lnX = getLabelNodeFromTemp(x);
316 LabelNode lnY = getLabelNodeFromTemp(y);
318 clearReferenceEdgesFrom(lnX, null, null, true);
320 Iterator<ReferenceEdge> itrYhrn = lnY.iteratorToReferencees();
321 while( itrYhrn.hasNext() ) {
322 ReferenceEdge edgeY = itrYhrn.next();
323 HeapRegionNode referencee = edgeY.getDst();
324 ReferenceEdge edgeNew = edgeY.copy();
325 edgeNew.setSrc( lnX );
326 edgeNew.setType( type );
327 edgeNew.setField( null );
329 addReferenceEdge(lnX, referencee, edgeNew);
334 public void assignTempXEqualToTempYFieldF(TempDescriptor x,
337 LabelNode lnX = getLabelNodeFromTemp(x);
338 LabelNode lnY = getLabelNodeFromTemp(y);
340 clearReferenceEdgesFrom(lnX, null, null, true);
342 Iterator<ReferenceEdge> itrYhrn = lnY.iteratorToReferencees();
343 while( itrYhrn.hasNext() ) {
344 ReferenceEdge edgeY = itrYhrn.next();
345 HeapRegionNode hrnY = edgeY.getDst();
346 ReachabilitySet betaY = edgeY.getBeta();
348 Iterator<ReferenceEdge> itrHrnFhrn = hrnY.iteratorToReferencees();
349 while( itrHrnFhrn.hasNext() ) {
350 ReferenceEdge edgeHrn = itrHrnFhrn.next();
351 HeapRegionNode hrnHrn = edgeHrn.getDst();
352 ReachabilitySet betaHrn = edgeHrn.getBeta();
354 if( edgeHrn.getType() == null ||
355 (edgeHrn.getType() .equals( f.getType() ) &&
356 edgeHrn.getField().equals( f.getSymbol() ) )
359 ReferenceEdge edgeNew = new ReferenceEdge(lnX,
364 betaY.intersection(betaHrn) );
366 addReferenceEdge(lnX, hrnHrn, edgeNew);
373 public void assignTempXFieldFEqualToTempY(TempDescriptor x,
376 LabelNode lnX = getLabelNodeFromTemp(x);
377 LabelNode lnY = getLabelNodeFromTemp(y);
379 HashSet<HeapRegionNode> nodesWithNewAlpha = new HashSet<HeapRegionNode>();
380 HashSet<ReferenceEdge> edgesWithNewBeta = new HashSet<ReferenceEdge>();
382 // first look for possible strong updates and remove those edges
383 boolean strongUpdate = false;
385 Iterator<ReferenceEdge> itrXhrn = lnX.iteratorToReferencees();
386 while( itrXhrn.hasNext() ) {
387 ReferenceEdge edgeX = itrXhrn.next();
388 HeapRegionNode hrnX = edgeX.getDst();
390 // we can do a strong update here if one of two cases holds
392 f != OwnershipAnalysis.getArrayField( f.getType() ) &&
393 ( (hrnX.getNumReferencers() == 1) || // case 1
394 (hrnX.isSingleObject() && lnX.getNumReferencees() == 1) // case 2
398 clearReferenceEdgesFrom( hrnX, f.getType(), f.getSymbol(), false );
402 // then do all token propagation
403 itrXhrn = lnX.iteratorToReferencees();
404 while( itrXhrn.hasNext() ) {
405 ReferenceEdge edgeX = itrXhrn.next();
406 HeapRegionNode hrnX = edgeX.getDst();
407 ReachabilitySet betaX = edgeX.getBeta();
409 ReachabilitySet R = hrnX.getAlpha().intersection(edgeX.getBeta() );
411 Iterator<ReferenceEdge> itrYhrn = lnY.iteratorToReferencees();
412 while( itrYhrn.hasNext() ) {
413 ReferenceEdge edgeY = itrYhrn.next();
414 HeapRegionNode hrnY = edgeY.getDst();
415 ReachabilitySet O = edgeY.getBeta();
418 // propagate tokens over nodes starting from hrnSrc, and it will
419 // take care of propagating back up edges from any touched nodes
420 ChangeTupleSet Cy = O.unionUpArityToChangeSet(R);
421 propagateTokensOverNodes(hrnY, Cy, nodesWithNewAlpha, edgesWithNewBeta);
424 // then propagate back just up the edges from hrn
425 ChangeTupleSet Cx = R.unionUpArityToChangeSet(O);
426 HashSet<ReferenceEdge> todoEdges = new HashSet<ReferenceEdge>();
428 Hashtable<ReferenceEdge, ChangeTupleSet> edgePlannedChanges =
429 new Hashtable<ReferenceEdge, ChangeTupleSet>();
431 Iterator<ReferenceEdge> referItr = hrnX.iteratorToReferencers();
432 while( referItr.hasNext() ) {
433 ReferenceEdge edgeUpstream = referItr.next();
434 todoEdges.add(edgeUpstream);
435 edgePlannedChanges.put(edgeUpstream, Cx);
438 propagateTokensOverEdges(todoEdges,
445 // apply the updates to reachability
446 Iterator<HeapRegionNode> nodeItr = nodesWithNewAlpha.iterator();
447 while( nodeItr.hasNext() ) {
448 nodeItr.next().applyAlphaNew();
451 Iterator<ReferenceEdge> edgeItr = edgesWithNewBeta.iterator();
452 while( edgeItr.hasNext() ) {
453 edgeItr.next().applyBetaNew();
457 // then go back through and add the new edges
458 itrXhrn = lnX.iteratorToReferencees();
459 while( itrXhrn.hasNext() ) {
460 ReferenceEdge edgeX = itrXhrn.next();
461 HeapRegionNode hrnX = edgeX.getDst();
463 Iterator<ReferenceEdge> itrYhrn = lnY.iteratorToReferencees();
464 while( itrYhrn.hasNext() ) {
465 ReferenceEdge edgeY = itrYhrn.next();
466 HeapRegionNode hrnY = edgeY.getDst();
468 // prepare the new reference edge hrnX.f -> hrnY
469 ReferenceEdge edgeNew = new ReferenceEdge(hrnX,
474 edgeY.getBeta().pruneBy( hrnX.getAlpha() )
477 // look to see if an edge with same field exists
478 // and merge with it, otherwise just add the edge
479 ReferenceEdge edgeExisting = hrnX.getReferenceTo( hrnY,
483 if( edgeExisting != null ) {
484 edgeExisting.setBeta(
485 edgeExisting.getBeta().union( edgeNew.getBeta() )
487 // a new edge here cannot be reflexive, so existing will
488 // always be also not reflexive anymore
489 edgeExisting.setIsInitialParam( false );
491 addReferenceEdge( hrnX, hrnY, edgeNew );
496 // if there was a strong update, make sure to improve
497 // reachability with a global sweep
506 // the parameter model is to use a single-object heap region
507 // for the primary parameter, and a multiple-object heap
508 // region for the secondary objects reachable through the
509 // primary object, if necessary
510 public void assignTempEqualToParamAlloc( TempDescriptor td,
512 Integer paramIndex ) {
515 TypeDescriptor typeParam = td.getType();
516 assert typeParam != null;
518 // either the parameter is an array or a class to be in this method
519 assert typeParam.isArray() || typeParam.isClass();
521 // discover some info from the param type and use it below
522 // to get parameter model as precise as we can
523 boolean createSecondaryRegion = false;
524 Set<FieldDescriptor> primary2primaryFields = new HashSet<FieldDescriptor>();
525 Set<FieldDescriptor> primary2secondaryFields = new HashSet<FieldDescriptor>();
527 // there might be an element reference for array types
528 if( typeParam.isArray() ) {
529 // only bother with this if the dereferenced type can
530 // affect reachability
531 TypeDescriptor typeDeref = typeParam.dereference();
532 if( !typeDeref.isImmutable() || typeDeref.isArray() ) {
533 primary2secondaryFields.add(
534 OwnershipAnalysis.getArrayField( typeDeref )
536 createSecondaryRegion = true;
538 // also handle a special case where an array of objects
539 // can point back to the array, which is an object!
540 if( typeParam.toPrettyString().equals( "Object[]" ) &&
541 typeDeref.toPrettyString().equals( "Object" ) ) {
543 primary2primaryFields.add(
544 OwnershipAnalysis.getArrayField( typeDeref )
550 // there might be member references for class types
551 if( typeParam.isClass() ) {
552 ClassDescriptor cd = typeParam.getClassDesc();
553 while( cd != null ) {
555 Iterator fieldItr = cd.getFields();
556 while( fieldItr.hasNext() ) {
558 FieldDescriptor fd = (FieldDescriptor) fieldItr.next();
559 TypeDescriptor typeField = fd.getType();
560 assert typeField != null;
562 if( !typeField.isImmutable() || typeField.isArray() ) {
563 primary2secondaryFields.add( fd );
564 createSecondaryRegion = true;
567 if( typeUtil.isSuperorType( typeField, typeParam ) ) {
568 primary2primaryFields.add( fd );
572 cd = cd.getSuperDesc();
577 // now build everything we need
578 LabelNode lnParam = getLabelNodeFromTemp( td );
579 HeapRegionNode hrnPrimary = createNewHeapRegionNode( null, // id or null to generate a new one
580 true, // single object?
583 true, // is a parameter?
585 null, // allocation site
586 null, // reachability set
587 "param"+paramIndex+" obj" );
589 // this is a non-program-accessible label that picks up beta
590 // info to be used for fixing a caller of this method
591 TempDescriptor tdParamQ = new TempDescriptor( td+qString );
592 paramIndex2tdQ.put( paramIndex, tdParamQ );
593 LabelNode lnParamQ = getLabelNodeFromTemp( tdParamQ );
595 // keep track of heap regions that were created for
596 // parameter labels, the index of the parameter they
597 // are for is important when resolving method calls
598 Integer newPrimaryID = hrnPrimary.getID();
599 assert !idPrimary2paramIndexSet.containsKey( newPrimaryID );
600 Set<Integer> s = new HashSet<Integer>();
602 idPrimary2paramIndexSet.put( newPrimaryID, s );
603 paramIndex2idPrimary.put( paramIndex, newPrimaryID );
606 TokenTuple ttPrimary = new TokenTuple( newPrimaryID,
607 false, // multi-object
608 TokenTuple.ARITY_ONE ).makeCanonical();
610 HeapRegionNode hrnSecondary = null;
611 Integer newSecondaryID = null;
612 TokenTuple ttSecondary = null;
613 TempDescriptor tdParamR = null;
614 LabelNode lnParamR = null;
616 if( createSecondaryRegion ) {
617 tdParamR = new TempDescriptor( td+rString );
618 paramIndex2tdR.put( paramIndex, tdParamR );
619 lnParamR = getLabelNodeFromTemp( tdParamR );
621 hrnSecondary = createNewHeapRegionNode( null, // id or null to generate a new one
622 false, // single object?
625 true, // is a parameter?
627 null, // allocation site
628 null, // reachability set
629 "param"+paramIndex+" reachable" );
631 newSecondaryID = hrnSecondary.getID();
632 assert !idSecondary2paramIndexSet.containsKey( newSecondaryID );
633 Set<Integer> s2 = new HashSet<Integer>();
634 s2.add( paramIndex );
635 idSecondary2paramIndexSet.put( newSecondaryID, s2 );
636 paramIndex2idSecondary.put( paramIndex, newSecondaryID );
639 ttSecondary = new TokenTuple( newSecondaryID,
640 true, // multi-object
641 TokenTuple.ARITY_ONE ).makeCanonical();
644 // use a beta that has everything and put it all over the
645 // parameter model, then use a global sweep later to fix
646 // it up, since parameters can have different shapes
647 TokenTupleSet tts0 = new TokenTupleSet( ttPrimary ).makeCanonical();
648 ReachabilitySet betaSoup;
649 if( createSecondaryRegion ) {
650 TokenTupleSet tts1 = new TokenTupleSet( ttSecondary ).makeCanonical();
651 TokenTupleSet tts2 = new TokenTupleSet( ttPrimary ).makeCanonical().union( ttSecondary );
652 betaSoup = ReachabilitySet.factory( tts0 ).union( tts1 ).union( tts2 );
654 betaSoup = ReachabilitySet.factory( tts0 );
657 ReferenceEdge edgeFromLabel =
658 new ReferenceEdge( lnParam, // src
662 false, // special param initial (not needed on label->node)
663 betaSoup ); // reachability
664 addReferenceEdge( lnParam, hrnPrimary, edgeFromLabel );
666 ReferenceEdge edgeFromLabelQ =
667 new ReferenceEdge( lnParamQ, // src
671 false, // special param initial (not needed on label->node)
672 betaSoup ); // reachability
673 addReferenceEdge( lnParamQ, hrnPrimary, edgeFromLabelQ );
675 ReferenceEdge edgeSecondaryReflexive;
676 if( createSecondaryRegion ) {
677 edgeSecondaryReflexive =
678 new ReferenceEdge( hrnSecondary, // src
680 null, // match all types
681 null, // match all fields
682 true, // special param initial
683 betaSoup ); // reachability
684 addReferenceEdge( hrnSecondary, hrnSecondary, edgeSecondaryReflexive );
686 ReferenceEdge edgeSecondary2Primary =
687 new ReferenceEdge( hrnSecondary, // src
689 null, // match all types
690 null, // match all fields
691 true, // special param initial
692 betaSoup ); // reachability
693 addReferenceEdge( hrnSecondary, hrnPrimary, edgeSecondary2Primary );
695 ReferenceEdge edgeFromLabelR =
696 new ReferenceEdge( lnParamR, // src
700 false, // special param initial (not needed on label->node)
701 betaSoup ); // reachability
702 addReferenceEdge( lnParamR, hrnSecondary, edgeFromLabelR );
705 Iterator<FieldDescriptor> fieldItr = primary2primaryFields.iterator();
706 while( fieldItr.hasNext() ) {
707 FieldDescriptor fd = fieldItr.next();
709 ReferenceEdge edgePrimaryReflexive =
710 new ReferenceEdge( hrnPrimary, // src
712 fd.getType(), // type
713 fd.getSymbol(), // field
714 true, // special param initial
715 betaSoup ); // reachability
716 addReferenceEdge( hrnPrimary, hrnPrimary, edgePrimaryReflexive );
719 fieldItr = primary2secondaryFields.iterator();
720 while( fieldItr.hasNext() ) {
721 FieldDescriptor fd = fieldItr.next();
723 ReferenceEdge edgePrimary2Secondary =
724 new ReferenceEdge( hrnPrimary, // src
726 fd.getType(), // type
727 fd.getSymbol(), // field
728 true, // special param initial
729 betaSoup ); // reachability
730 addReferenceEdge( hrnPrimary, hrnSecondary, edgePrimary2Secondary );
735 public void makeAliasedParamHeapRegionNode() {
737 LabelNode lnBlob = getLabelNodeFromTemp( tdAliasBlob );
738 HeapRegionNode hrn = createNewHeapRegionNode( null, // id or null to generate a new one
739 false, // single object?
742 true, // is a parameter?
744 null, // allocation site
745 null, // reachability set
749 ReachabilitySet beta = new ReachabilitySet( new TokenTuple( hrn.getID(),
751 TokenTuple.ARITY_ONE).makeCanonical()
754 ReferenceEdge edgeFromLabel =
755 new ReferenceEdge( lnBlob, hrn, null, null, false, beta );
757 ReferenceEdge edgeReflexive =
758 new ReferenceEdge( hrn, hrn, null, null, true, beta );
760 addReferenceEdge( lnBlob, hrn, edgeFromLabel );
761 addReferenceEdge( hrn, hrn, edgeReflexive );
765 public void assignTempEqualToAliasedParam( TempDescriptor tdParam,
766 Integer paramIndex ) {
767 assert tdParam != null;
769 TypeDescriptor typeParam = tdParam.getType();
770 assert typeParam != null;
772 LabelNode lnParam = getLabelNodeFromTemp( tdParam );
773 LabelNode lnAliased = getLabelNodeFromTemp( tdAliasBlob );
775 // this is a non-program-accessible label that picks up beta
776 // info to be used for fixing a caller of this method
777 TempDescriptor tdParamQ = new TempDescriptor( tdParam+qString );
778 TempDescriptor tdParamR = new TempDescriptor( tdParam+rString );
780 paramIndex2tdQ.put( paramIndex, tdParamQ );
781 paramIndex2tdR.put( paramIndex, tdParamR );
783 LabelNode lnParamQ = getLabelNodeFromTemp( tdParamQ );
784 LabelNode lnParamR = getLabelNodeFromTemp( tdParamR );
786 // the lnAliased should always only reference one node, and that
787 // heap region node is the aliased param blob
788 assert lnAliased.getNumReferencees() == 1;
789 HeapRegionNode hrnAliasBlob = lnAliased.iteratorToReferencees().next().getDst();
790 Integer idAliased = hrnAliasBlob.getID();
793 TokenTuple ttAliased = new TokenTuple( idAliased,
794 true, // multi-object
795 TokenTuple.ARITY_ONE ).makeCanonical();
798 HeapRegionNode hrnPrimary = createNewHeapRegionNode( null, // id or null to generate a new one
799 true, // single object?
802 true, // is a parameter?
804 null, // allocation site
805 null, // reachability set
806 "param"+paramIndex+" obj" );
808 Integer newPrimaryID = hrnPrimary.getID();
809 assert !idPrimary2paramIndexSet.containsKey( newPrimaryID );
810 Set<Integer> s1 = new HashSet<Integer>();
811 s1.add( paramIndex );
812 idPrimary2paramIndexSet.put( newPrimaryID, s1 );
813 paramIndex2idPrimary.put( paramIndex, newPrimaryID );
815 Set<Integer> s2 = idSecondary2paramIndexSet.get( idAliased );
817 s2 = new HashSet<Integer>();
819 s2.add( paramIndex );
820 idSecondary2paramIndexSet.put( idAliased, s2 );
821 paramIndex2idSecondary.put( paramIndex, idAliased );
825 TokenTuple ttPrimary = new TokenTuple( newPrimaryID,
826 false, // multi-object
827 TokenTuple.ARITY_ONE ).makeCanonical();
830 TokenTupleSet tts0 = new TokenTupleSet( ttPrimary ).makeCanonical();
831 TokenTupleSet tts1 = new TokenTupleSet( ttAliased ).makeCanonical();
832 TokenTupleSet tts2 = new TokenTupleSet( ttPrimary ).makeCanonical().union( ttAliased );
833 ReachabilitySet betaSoup = ReachabilitySet.factory( tts0 ).union( tts1 ).union( tts2 );
836 ReferenceEdge edgeFromLabel =
837 new ReferenceEdge( lnParam, // src
841 false, // special param initial (not needed on label->node)
842 betaSoup ); // reachability
843 addReferenceEdge( lnParam, hrnPrimary, edgeFromLabel );
845 ReferenceEdge edgeFromLabelQ =
846 new ReferenceEdge( lnParamQ, // src
850 false, // special param initial (not needed on label->node)
851 betaSoup ); // reachability
852 addReferenceEdge( lnParamQ, hrnPrimary, edgeFromLabelQ );
854 ReferenceEdge edgeAliased2Primary =
855 new ReferenceEdge( hrnAliasBlob, // src
857 null, // match all types
858 null, // match all fields
859 true, // special param initial
860 betaSoup ); // reachability
861 addReferenceEdge( hrnAliasBlob, hrnPrimary, edgeAliased2Primary );
863 ReferenceEdge edgeFromLabelR =
864 new ReferenceEdge( lnParamR, // src
868 false, // special param initial (not needed on label->node)
869 betaSoup ); // reachability
870 addReferenceEdge( lnParamR, hrnAliasBlob, edgeFromLabelR );
874 public void addParam2ParamAliasEdges( FlatMethod fm,
875 Set<Integer> aliasedParamIndices ) {
877 LabelNode lnAliased = getLabelNodeFromTemp( tdAliasBlob );
879 // the lnAliased should always only reference one node, and that
880 // heap region node is the aliased param blob
881 assert lnAliased.getNumReferencees() == 1;
882 HeapRegionNode hrnAliasBlob = lnAliased.iteratorToReferencees().next().getDst();
883 Integer idAliased = hrnAliasBlob.getID();
886 TokenTuple ttAliased = new TokenTuple( idAliased,
887 true, // multi-object
888 TokenTuple.ARITY_ONE ).makeCanonical();
891 Iterator<Integer> apItrI = aliasedParamIndices.iterator();
892 while( apItrI.hasNext() ) {
893 Integer i = apItrI.next();
894 TempDescriptor tdParamI = fm.getParameter( i );
895 TypeDescriptor typeI = tdParamI.getType();
896 LabelNode lnParamI = getLabelNodeFromTemp( tdParamI );
898 Integer idPrimaryI = paramIndex2idPrimary.get( i );
899 assert idPrimaryI != null;
900 HeapRegionNode primaryI = id2hrn.get( idPrimaryI );
901 assert primaryI != null;
903 TokenTuple ttPrimaryI = new TokenTuple( idPrimaryI,
904 false, // multi-object
905 TokenTuple.ARITY_ONE ).makeCanonical();
907 TokenTupleSet ttsI = new TokenTupleSet( ttPrimaryI ).makeCanonical();
908 TokenTupleSet ttsA = new TokenTupleSet( ttAliased ).makeCanonical();
909 TokenTupleSet ttsIA = new TokenTupleSet( ttPrimaryI ).makeCanonical().union( ttAliased );
910 ReachabilitySet betaSoup = ReachabilitySet.factory( ttsI ).union( ttsA ).union( ttsIA );
913 // calculate whether fields of this aliased parameter are able to
914 // reference its own primary object, the blob, or other parameter's
916 Set<FieldDescriptor> primary2primaryFields = new HashSet<FieldDescriptor>();
917 Set<FieldDescriptor> primary2secondaryFields = new HashSet<FieldDescriptor>();
919 // there might be an element reference for array types
920 if( typeI.isArray() ) {
921 // only bother with this if the dereferenced type can
922 // affect reachability
923 TypeDescriptor typeDeref = typeI.dereference();
925 // for this parameter to be aliased the following must be true
926 assert !typeDeref.isImmutable() || typeDeref.isArray();
928 primary2secondaryFields.add(
929 OwnershipAnalysis.getArrayField( typeDeref )
932 // also handle a special case where an array of objects
933 // can point back to the array, which is an object!
934 if( typeI .toPrettyString().equals( "Object[]" ) &&
935 typeDeref.toPrettyString().equals( "Object" ) ) {
936 primary2primaryFields.add(
937 OwnershipAnalysis.getArrayField( typeDeref )
942 // there might be member references for class types
943 if( typeI.isClass() ) {
944 ClassDescriptor cd = typeI.getClassDesc();
945 while( cd != null ) {
947 Iterator fieldItr = cd.getFields();
948 while( fieldItr.hasNext() ) {
950 FieldDescriptor fd = (FieldDescriptor) fieldItr.next();
951 TypeDescriptor typeField = fd.getType();
952 assert typeField != null;
954 if( !typeField.isImmutable() || typeField.isArray() ) {
955 primary2secondaryFields.add( fd );
958 if( typeUtil.isSuperorType( typeField, typeI ) ) {
959 primary2primaryFields.add( fd );
963 cd = cd.getSuperDesc();
967 Iterator<FieldDescriptor> fieldItr = primary2primaryFields.iterator();
968 while( fieldItr.hasNext() ) {
969 FieldDescriptor fd = fieldItr.next();
971 ReferenceEdge edgePrimaryReflexive =
972 new ReferenceEdge( primaryI, // src
974 fd.getType(), // type
975 fd.getSymbol(), // field
976 true, // special param initial
977 betaSoup ); // reachability
978 addReferenceEdge( primaryI, primaryI, edgePrimaryReflexive );
981 fieldItr = primary2secondaryFields.iterator();
982 while( fieldItr.hasNext() ) {
983 FieldDescriptor fd = fieldItr.next();
984 TypeDescriptor typeField = fd.getType();
985 assert typeField != null;
987 ReferenceEdge edgePrimary2Secondary =
988 new ReferenceEdge( primaryI, // src
990 fd.getType(), // type
991 fd.getSymbol(), // field
992 true, // special param initial
993 betaSoup ); // reachability
994 addReferenceEdge( primaryI, hrnAliasBlob, edgePrimary2Secondary );
996 // ask whether these fields might match any of the other aliased
997 // parameters and make those edges too
998 Iterator<Integer> apItrJ = aliasedParamIndices.iterator();
999 while( apItrJ.hasNext() ) {
1000 Integer j = apItrJ.next();
1001 TempDescriptor tdParamJ = fm.getParameter( j );
1002 TypeDescriptor typeJ = tdParamJ.getType();
1004 if( !i.equals( j ) && typeUtil.isSuperorType( typeField, typeJ ) ) {
1006 Integer idPrimaryJ = paramIndex2idPrimary.get( j );
1007 assert idPrimaryJ != null;
1008 HeapRegionNode primaryJ = id2hrn.get( idPrimaryJ );
1009 assert primaryJ != null;
1011 TokenTuple ttPrimaryJ = new TokenTuple( idPrimaryJ,
1012 false, // multi-object
1013 TokenTuple.ARITY_ONE ).makeCanonical();
1015 TokenTupleSet ttsJ = new TokenTupleSet( ttPrimaryJ ).makeCanonical();
1016 TokenTupleSet ttsIJ = ttsI.union( ttsJ );
1017 TokenTupleSet ttsAJ = ttsA.union( ttsJ );
1018 TokenTupleSet ttsIAJ = ttsIA.union( ttsJ );
1019 ReachabilitySet betaSoupWJ = ReachabilitySet.factory( ttsJ ).union( ttsIJ ).union( ttsAJ ).union( ttsIAJ );
1021 ReferenceEdge edgePrimaryI2PrimaryJ =
1022 new ReferenceEdge( primaryI, // src
1024 fd.getType(), // type
1025 fd.getSymbol(), // field
1026 true, // special param initial
1027 betaSoupWJ ); // reachability
1028 addReferenceEdge( primaryI, primaryJ, edgePrimaryI2PrimaryJ );
1034 // look at whether aliased parameters i and j can
1035 // possibly be the same primary object, add edges
1036 Iterator<Integer> apItrJ = aliasedParamIndices.iterator();
1037 while( apItrJ.hasNext() ) {
1038 Integer j = apItrJ.next();
1039 TempDescriptor tdParamJ = fm.getParameter( j );
1040 TypeDescriptor typeJ = tdParamJ.getType();
1041 LabelNode lnParamJ = getLabelNodeFromTemp( tdParamJ );
1043 if( !i.equals( j ) && typeUtil.isSuperorType( typeI, typeJ ) ) {
1045 Integer idPrimaryJ = paramIndex2idPrimary.get( j );
1046 assert idPrimaryJ != null;
1047 HeapRegionNode primaryJ = id2hrn.get( idPrimaryJ );
1048 assert primaryJ != null;
1050 ReferenceEdge lnJ2PrimaryJ = lnParamJ.getReferenceTo( primaryJ,
1053 assert lnJ2PrimaryJ != null;
1055 ReferenceEdge lnI2PrimaryJ = lnJ2PrimaryJ.copy();
1056 lnI2PrimaryJ.setSrc( lnParamI );
1057 lnI2PrimaryJ.setType( tdParamI.getType() );
1058 addReferenceEdge( lnParamI, primaryJ, lnI2PrimaryJ );
1064 public void prepareParamTokenMaps( FlatMethod fm ) {
1066 // always add the bogus mappings that are used to
1067 // rewrite "with respect to no parameter"
1068 paramTokenPrimary2paramIndex.put( bogusToken, bogusIndex );
1069 paramIndex2paramTokenPrimary.put( bogusIndex, bogusToken );
1071 paramTokenSecondary2paramIndex.put( bogusToken, bogusIndex );
1072 paramIndex2paramTokenSecondary.put( bogusIndex, bogusToken );
1073 paramTokenSecondaryPlus2paramIndex.put( bogusTokenPlus, bogusIndex );
1074 paramIndex2paramTokenSecondaryPlus.put( bogusIndex, bogusTokenPlus );
1075 paramTokenSecondaryStar2paramIndex.put( bogusTokenStar, bogusIndex );
1076 paramIndex2paramTokenSecondaryStar.put( bogusIndex, bogusTokenStar );
1078 for( int i = 0; i < fm.numParameters(); ++i ) {
1079 Integer paramIndex = new Integer( i );
1081 // immutable objects have no primary regions
1082 if( paramIndex2idPrimary.containsKey( paramIndex ) ) {
1083 Integer idPrimary = paramIndex2idPrimary.get( paramIndex );
1085 assert id2hrn.containsKey( idPrimary );
1086 HeapRegionNode hrnPrimary = id2hrn.get( idPrimary );
1088 TokenTuple p_i = new TokenTuple( hrnPrimary.getID(),
1089 false, // multiple-object?
1090 TokenTuple.ARITY_ONE ).makeCanonical();
1091 paramTokenPrimary2paramIndex.put( p_i, paramIndex );
1092 paramIndex2paramTokenPrimary.put( paramIndex, p_i );
1095 // any parameter object, by type, may have no secondary region
1096 if( paramIndex2idSecondary.containsKey( paramIndex ) ) {
1097 Integer idSecondary = paramIndex2idSecondary.get( paramIndex );
1099 assert id2hrn.containsKey( idSecondary );
1100 HeapRegionNode hrnSecondary = id2hrn.get( idSecondary );
1102 TokenTuple s_i = new TokenTuple( hrnSecondary.getID(),
1103 true, // multiple-object?
1104 TokenTuple.ARITY_ONE ).makeCanonical();
1105 paramTokenSecondary2paramIndex.put( s_i, paramIndex );
1106 paramIndex2paramTokenSecondary.put( paramIndex, s_i );
1108 TokenTuple s_i_plus = new TokenTuple( hrnSecondary.getID(),
1109 true, // multiple-object?
1110 TokenTuple.ARITY_ONEORMORE ).makeCanonical();
1111 paramTokenSecondaryPlus2paramIndex.put( s_i_plus, paramIndex );
1112 paramIndex2paramTokenSecondaryPlus.put( paramIndex, s_i_plus );
1114 TokenTuple s_i_star = new TokenTuple( hrnSecondary.getID(),
1115 true, // multiple-object?
1116 TokenTuple.ARITY_ZEROORMORE ).makeCanonical();
1117 paramTokenSecondaryStar2paramIndex.put( s_i_star, paramIndex );
1118 paramIndex2paramTokenSecondaryStar.put( paramIndex, s_i_star );
1125 public void assignReturnEqualToTemp(TempDescriptor x) {
1127 LabelNode lnR = getLabelNodeFromTemp(tdReturn);
1128 LabelNode lnX = getLabelNodeFromTemp(x);
1130 clearReferenceEdgesFrom(lnR, null, null, true);
1132 Iterator<ReferenceEdge> itrXhrn = lnX.iteratorToReferencees();
1133 while( itrXhrn.hasNext() ) {
1134 ReferenceEdge edgeX = itrXhrn.next();
1135 HeapRegionNode referencee = edgeX.getDst();
1136 ReferenceEdge edgeNew = edgeX.copy();
1137 edgeNew.setSrc(lnR);
1139 addReferenceEdge(lnR, referencee, edgeNew);
1144 public void assignTempEqualToNewAlloc(TempDescriptor x,
1145 AllocationSite as) {
1151 // after the age operation the newest (or zero-ith oldest)
1152 // node associated with the allocation site should have
1153 // no references to it as if it were a newly allocated
1155 Integer idNewest = as.getIthOldest( 0 );
1156 HeapRegionNode hrnNewest = id2hrn.get( idNewest );
1157 assert hrnNewest != null;
1159 LabelNode lnX = getLabelNodeFromTemp( x );
1160 clearReferenceEdgesFrom( lnX, null, null, true );
1162 // make a new reference to allocated node
1163 TypeDescriptor type = as.getType();
1164 ReferenceEdge edgeNew =
1165 new ReferenceEdge( lnX, // source
1169 false, // is initial param
1170 hrnNewest.getAlpha() // beta
1173 addReferenceEdge( lnX, hrnNewest, edgeNew );
1177 // use the allocation site (unique to entire analysis) to
1178 // locate the heap region nodes in this ownership graph
1179 // that should be aged. The process models the allocation
1180 // of new objects and collects all the oldest allocations
1181 // in a summary node to allow for a finite analysis
1183 // There is an additional property of this method. After
1184 // running it on a particular ownership graph (many graphs
1185 // may have heap regions related to the same allocation site)
1186 // the heap region node objects in this ownership graph will be
1187 // allocated. Therefore, after aging a graph for an allocation
1188 // site, attempts to retrieve the heap region nodes using the
1189 // integer id's contained in the allocation site should always
1190 // return non-null heap regions.
1191 public void age(AllocationSite as) {
1193 // aging adds this allocation site to the graph's
1194 // list of sites that exist in the graph, or does
1195 // nothing if the site is already in the list
1196 allocationSites.add(as);
1198 // get the summary node for the allocation site in the context
1199 // of this particular ownership graph
1200 HeapRegionNode hrnSummary = getSummaryNode(as);
1202 // merge oldest node into summary
1203 Integer idK = as.getOldest();
1204 HeapRegionNode hrnK = id2hrn.get(idK);
1205 mergeIntoSummary(hrnK, hrnSummary);
1207 // move down the line of heap region nodes
1208 // clobbering the ith and transferring all references
1209 // to and from i-1 to node i. Note that this clobbers
1210 // the oldest node (hrnK) that was just merged into
1212 for( int i = allocationDepth - 1; i > 0; --i ) {
1214 // move references from the i-1 oldest to the ith oldest
1215 Integer idIth = as.getIthOldest(i);
1216 HeapRegionNode hrnI = id2hrn.get(idIth);
1217 Integer idImin1th = as.getIthOldest(i - 1);
1218 HeapRegionNode hrnImin1 = id2hrn.get(idImin1th);
1220 transferOnto(hrnImin1, hrnI);
1223 // as stated above, the newest node should have had its
1224 // references moved over to the second oldest, so we wipe newest
1225 // in preparation for being the new object to assign something to
1226 Integer id0th = as.getIthOldest(0);
1227 HeapRegionNode hrn0 = id2hrn.get(id0th);
1228 assert hrn0 != null;
1230 // clear all references in and out of newest node
1231 clearReferenceEdgesFrom(hrn0, null, null, true);
1232 clearReferenceEdgesTo(hrn0, null, null, true);
1235 // now tokens in reachability sets need to "age" also
1236 Iterator itrAllLabelNodes = td2ln.entrySet().iterator();
1237 while( itrAllLabelNodes.hasNext() ) {
1238 Map.Entry me = (Map.Entry)itrAllLabelNodes.next();
1239 LabelNode ln = (LabelNode) me.getValue();
1241 Iterator<ReferenceEdge> itrEdges = ln.iteratorToReferencees();
1242 while( itrEdges.hasNext() ) {
1243 ageTokens(as, itrEdges.next() );
1247 Iterator itrAllHRNodes = id2hrn.entrySet().iterator();
1248 while( itrAllHRNodes.hasNext() ) {
1249 Map.Entry me = (Map.Entry)itrAllHRNodes.next();
1250 HeapRegionNode hrnToAge = (HeapRegionNode) me.getValue();
1252 ageTokens(as, hrnToAge);
1254 Iterator<ReferenceEdge> itrEdges = hrnToAge.iteratorToReferencees();
1255 while( itrEdges.hasNext() ) {
1256 ageTokens(as, itrEdges.next() );
1261 // after tokens have been aged, reset newest node's reachability
1262 if( hrn0.isFlagged() ) {
1263 hrn0.setAlpha(new ReachabilitySet(
1265 new TokenTuple(hrn0).makeCanonical()
1270 hrn0.setAlpha(new ReachabilitySet(
1271 new TokenTupleSet().makeCanonical()
1278 protected HeapRegionNode getSummaryNode(AllocationSite as) {
1280 Integer idSummary = as.getSummary();
1281 HeapRegionNode hrnSummary = id2hrn.get(idSummary);
1283 // If this is null then we haven't touched this allocation site
1284 // in the context of the current ownership graph, so allocate
1285 // heap region nodes appropriate for the entire allocation site.
1286 // This should only happen once per ownership graph per allocation site,
1287 // and a particular integer id can be used to locate the heap region
1288 // in different ownership graphs that represents the same part of an
1290 if( hrnSummary == null ) {
1292 boolean hasFlags = false;
1293 if( as.getType().isClass() ) {
1294 hasFlags = as.getType().getClassDesc().hasFlags();
1297 hrnSummary = createNewHeapRegionNode(idSummary, // id or null to generate a new one
1298 false, // single object?
1300 hasFlags, // flagged?
1301 false, // is a parameter?
1302 as.getType(), // type
1303 as, // allocation site
1304 null, // reachability set
1305 as.toStringForDOT() + "\\nsummary");
1307 for( int i = 0; i < as.getAllocationDepth(); ++i ) {
1308 Integer idIth = as.getIthOldest(i);
1309 assert !id2hrn.containsKey(idIth);
1310 createNewHeapRegionNode(idIth, // id or null to generate a new one
1311 true, // single object?
1313 hasFlags, // flagged?
1314 false, // is a parameter?
1315 as.getType(), // type
1316 as, // allocation site
1317 null, // reachability set
1318 as.toStringForDOT() + "\\n" + i + " oldest");
1326 protected HeapRegionNode getShadowSummaryNode(AllocationSite as) {
1328 Integer idShadowSummary = as.getSummaryShadow();
1329 HeapRegionNode hrnShadowSummary = id2hrn.get(idShadowSummary);
1331 if( hrnShadowSummary == null ) {
1333 boolean hasFlags = false;
1334 if( as.getType().isClass() ) {
1335 hasFlags = as.getType().getClassDesc().hasFlags();
1338 hrnShadowSummary = createNewHeapRegionNode(idShadowSummary, // id or null to generate a new one
1339 false, // single object?
1341 hasFlags, // flagged?
1342 false, // is a parameter?
1343 as.getType(), // type
1344 as, // allocation site
1345 null, // reachability set
1346 as + "\\n" + as.getType() + "\\nshadowSum");
1348 for( int i = 0; i < as.getAllocationDepth(); ++i ) {
1349 Integer idShadowIth = as.getIthOldestShadow(i);
1350 assert !id2hrn.containsKey(idShadowIth);
1351 createNewHeapRegionNode(idShadowIth, // id or null to generate a new one
1352 true, // single object?
1354 hasFlags, // flagged?
1355 false, // is a parameter?
1356 as.getType(), // type
1357 as, // allocation site
1358 null, // reachability set
1359 as + "\\n" + as.getType() + "\\n" + i + " shadow");
1363 return hrnShadowSummary;
1367 protected void mergeIntoSummary(HeapRegionNode hrn, HeapRegionNode hrnSummary) {
1368 assert hrnSummary.isNewSummary();
1370 // transfer references _from_ hrn over to hrnSummary
1371 Iterator<ReferenceEdge> itrReferencee = hrn.iteratorToReferencees();
1372 while( itrReferencee.hasNext() ) {
1373 ReferenceEdge edge = itrReferencee.next();
1374 ReferenceEdge edgeMerged = edge.copy();
1375 edgeMerged.setSrc(hrnSummary);
1377 HeapRegionNode hrnReferencee = edge.getDst();
1378 ReferenceEdge edgeSummary = hrnSummary.getReferenceTo(hrnReferencee,
1382 if( edgeSummary == null ) {
1383 // the merge is trivial, nothing to be done
1385 // otherwise an edge from the referencer to hrnSummary exists already
1386 // and the edge referencer->hrn should be merged with it
1387 edgeMerged.setBeta(edgeMerged.getBeta().union(edgeSummary.getBeta() ) );
1390 addReferenceEdge(hrnSummary, hrnReferencee, edgeMerged);
1393 // next transfer references _to_ hrn over to hrnSummary
1394 Iterator<ReferenceEdge> itrReferencer = hrn.iteratorToReferencers();
1395 while( itrReferencer.hasNext() ) {
1396 ReferenceEdge edge = itrReferencer.next();
1397 ReferenceEdge edgeMerged = edge.copy();
1398 edgeMerged.setDst(hrnSummary);
1400 OwnershipNode onReferencer = edge.getSrc();
1401 ReferenceEdge edgeSummary = onReferencer.getReferenceTo(hrnSummary,
1405 if( edgeSummary == null ) {
1406 // the merge is trivial, nothing to be done
1408 // otherwise an edge from the referencer to alpha_S exists already
1409 // and the edge referencer->alpha_K should be merged with it
1410 edgeMerged.setBeta(edgeMerged.getBeta().union(edgeSummary.getBeta() ) );
1413 addReferenceEdge(onReferencer, hrnSummary, edgeMerged);
1416 // then merge hrn reachability into hrnSummary
1417 hrnSummary.setAlpha(hrnSummary.getAlpha().union(hrn.getAlpha() ) );
1421 protected void transferOnto(HeapRegionNode hrnA, HeapRegionNode hrnB) {
1423 // clear references in and out of node b
1424 clearReferenceEdgesFrom(hrnB, null, null, true);
1425 clearReferenceEdgesTo(hrnB, null, null, true);
1427 // copy each edge in and out of A to B
1428 Iterator<ReferenceEdge> itrReferencee = hrnA.iteratorToReferencees();
1429 while( itrReferencee.hasNext() ) {
1430 ReferenceEdge edge = itrReferencee.next();
1431 HeapRegionNode hrnReferencee = edge.getDst();
1432 ReferenceEdge edgeNew = edge.copy();
1433 edgeNew.setSrc(hrnB);
1435 addReferenceEdge(hrnB, hrnReferencee, edgeNew);
1438 Iterator<ReferenceEdge> itrReferencer = hrnA.iteratorToReferencers();
1439 while( itrReferencer.hasNext() ) {
1440 ReferenceEdge edge = itrReferencer.next();
1441 OwnershipNode onReferencer = edge.getSrc();
1442 ReferenceEdge edgeNew = edge.copy();
1443 edgeNew.setDst(hrnB);
1445 addReferenceEdge(onReferencer, hrnB, edgeNew);
1448 // replace hrnB reachability with hrnA's
1449 hrnB.setAlpha(hrnA.getAlpha() );
1453 protected void ageTokens(AllocationSite as, ReferenceEdge edge) {
1454 edge.setBeta(edge.getBeta().ageTokens(as) );
1457 protected void ageTokens(AllocationSite as, HeapRegionNode hrn) {
1458 hrn.setAlpha(hrn.getAlpha().ageTokens(as) );
1463 protected void propagateTokensOverNodes(HeapRegionNode nPrime,
1465 HashSet<HeapRegionNode> nodesWithNewAlpha,
1466 HashSet<ReferenceEdge> edgesWithNewBeta) {
1468 HashSet<HeapRegionNode> todoNodes
1469 = new HashSet<HeapRegionNode>();
1470 todoNodes.add(nPrime);
1472 HashSet<ReferenceEdge> todoEdges
1473 = new HashSet<ReferenceEdge>();
1475 Hashtable<HeapRegionNode, ChangeTupleSet> nodePlannedChanges
1476 = new Hashtable<HeapRegionNode, ChangeTupleSet>();
1477 nodePlannedChanges.put(nPrime, c0);
1479 Hashtable<ReferenceEdge, ChangeTupleSet> edgePlannedChanges
1480 = new Hashtable<ReferenceEdge, ChangeTupleSet>();
1482 // first propagate change sets everywhere they can go
1483 while( !todoNodes.isEmpty() ) {
1484 HeapRegionNode n = todoNodes.iterator().next();
1485 ChangeTupleSet C = nodePlannedChanges.get(n);
1487 Iterator<ReferenceEdge> referItr = n.iteratorToReferencers();
1488 while( referItr.hasNext() ) {
1489 ReferenceEdge edge = referItr.next();
1490 todoEdges.add(edge);
1492 if( !edgePlannedChanges.containsKey(edge) ) {
1493 edgePlannedChanges.put(edge, new ChangeTupleSet().makeCanonical() );
1496 edgePlannedChanges.put(edge, edgePlannedChanges.get(edge).union(C) );
1499 Iterator<ReferenceEdge> refeeItr = n.iteratorToReferencees();
1500 while( refeeItr.hasNext() ) {
1501 ReferenceEdge edgeF = refeeItr.next();
1502 HeapRegionNode m = edgeF.getDst();
1504 ChangeTupleSet changesToPass = new ChangeTupleSet().makeCanonical();
1506 Iterator<ChangeTuple> itrCprime = C.iterator();
1507 while( itrCprime.hasNext() ) {
1508 ChangeTuple c = itrCprime.next();
1509 if( edgeF.getBeta().contains( c.getSetToMatch() ) ) {
1510 changesToPass = changesToPass.union(c);
1514 if( !changesToPass.isEmpty() ) {
1515 if( !nodePlannedChanges.containsKey(m) ) {
1516 nodePlannedChanges.put(m, new ChangeTupleSet().makeCanonical() );
1519 ChangeTupleSet currentChanges = nodePlannedChanges.get(m);
1521 if( !changesToPass.isSubset(currentChanges) ) {
1523 nodePlannedChanges.put(m, currentChanges.union(changesToPass) );
1529 todoNodes.remove(n);
1532 // then apply all of the changes for each node at once
1533 Iterator itrMap = nodePlannedChanges.entrySet().iterator();
1534 while( itrMap.hasNext() ) {
1535 Map.Entry me = (Map.Entry) itrMap.next();
1536 HeapRegionNode n = (HeapRegionNode) me.getKey();
1537 ChangeTupleSet C = (ChangeTupleSet) me.getValue();
1539 n.setAlphaNew( n.getAlpha().applyChangeSet( C, true ) );
1540 nodesWithNewAlpha.add( n );
1543 propagateTokensOverEdges(todoEdges, edgePlannedChanges, edgesWithNewBeta);
1547 protected void propagateTokensOverEdges(
1548 HashSet<ReferenceEdge> todoEdges,
1549 Hashtable<ReferenceEdge, ChangeTupleSet> edgePlannedChanges,
1550 HashSet<ReferenceEdge> edgesWithNewBeta) {
1552 // first propagate all change tuples everywhere they can go
1553 while( !todoEdges.isEmpty() ) {
1554 ReferenceEdge edgeE = todoEdges.iterator().next();
1555 todoEdges.remove(edgeE);
1557 if( !edgePlannedChanges.containsKey(edgeE) ) {
1558 edgePlannedChanges.put(edgeE, new ChangeTupleSet().makeCanonical() );
1561 ChangeTupleSet C = edgePlannedChanges.get(edgeE);
1563 ChangeTupleSet changesToPass = new ChangeTupleSet().makeCanonical();
1565 Iterator<ChangeTuple> itrC = C.iterator();
1566 while( itrC.hasNext() ) {
1567 ChangeTuple c = itrC.next();
1568 if( edgeE.getBeta().contains( c.getSetToMatch() ) ) {
1569 changesToPass = changesToPass.union(c);
1573 OwnershipNode onSrc = edgeE.getSrc();
1575 if( !changesToPass.isEmpty() && onSrc instanceof HeapRegionNode ) {
1576 HeapRegionNode n = (HeapRegionNode) onSrc;
1578 Iterator<ReferenceEdge> referItr = n.iteratorToReferencers();
1579 while( referItr.hasNext() ) {
1580 ReferenceEdge edgeF = referItr.next();
1582 if( !edgePlannedChanges.containsKey(edgeF) ) {
1583 edgePlannedChanges.put(edgeF, new ChangeTupleSet().makeCanonical() );
1586 ChangeTupleSet currentChanges = edgePlannedChanges.get(edgeF);
1588 if( !changesToPass.isSubset(currentChanges) ) {
1589 todoEdges.add(edgeF);
1590 edgePlannedChanges.put(edgeF, currentChanges.union(changesToPass) );
1596 // then apply all of the changes for each edge at once
1597 Iterator itrMap = edgePlannedChanges.entrySet().iterator();
1598 while( itrMap.hasNext() ) {
1599 Map.Entry me = (Map.Entry) itrMap.next();
1600 ReferenceEdge e = (ReferenceEdge) me.getKey();
1601 ChangeTupleSet C = (ChangeTupleSet) me.getValue();
1603 e.setBetaNew( e.getBetaNew().union( e.getBeta().applyChangeSet( C, true ) ) );
1604 edgesWithNewBeta.add( e );
1609 public Set<Integer> calculateAliasedParamSet( FlatCall fc,
1613 Hashtable<Integer, LabelNode> paramIndex2ln =
1614 new Hashtable<Integer, LabelNode>();
1616 Hashtable<Integer, HashSet<HeapRegionNode> > paramIndex2reachableCallerNodes =
1617 new Hashtable<Integer, HashSet<HeapRegionNode> >();
1619 for( int i = 0; i < fm.numParameters(); ++i ) {
1620 Integer paramIndex = new Integer( i );
1621 TempDescriptor tdParam = fm.getParameter( i );
1622 TypeDescriptor typeParam = tdParam.getType();
1624 if( typeParam.isImmutable() && !typeParam.isArray() ) {
1625 // don't bother with this primitive parameter, it
1626 // cannot affect reachability
1630 // now depending on whether the callee is static or not
1631 // we need to account for a "this" argument in order to
1632 // find the matching argument in the caller context
1633 TempDescriptor argTemp_i;
1635 argTemp_i = fc.getArg(paramIndex);
1637 if( paramIndex.equals(0) ) {
1638 argTemp_i = fc.getThis();
1640 argTemp_i = fc.getArg(paramIndex - 1);
1644 // in non-static methods there is a "this" pointer
1645 // that should be taken into account
1647 assert fc.numArgs() == fm.numParameters();
1649 assert fc.numArgs() + 1 == fm.numParameters();
1652 LabelNode argLabel_i = getLabelNodeFromTemp(argTemp_i);
1653 paramIndex2ln.put(paramIndex, argLabel_i);
1656 Iterator lnArgItr = paramIndex2ln.entrySet().iterator();
1657 while( lnArgItr.hasNext() ) {
1658 Map.Entry me = (Map.Entry)lnArgItr.next();
1659 Integer index = (Integer) me.getKey();
1660 LabelNode lnArg_i = (LabelNode) me.getValue();
1662 HashSet<HeapRegionNode> reachableNodes = new HashSet<HeapRegionNode>();
1663 HashSet<HeapRegionNode> todoNodes = new HashSet<HeapRegionNode>();
1665 // to find all reachable nodes, start with label referencees
1666 Iterator<ReferenceEdge> edgeArgItr = lnArg_i.iteratorToReferencees();
1667 while( edgeArgItr.hasNext() ) {
1668 ReferenceEdge edge = edgeArgItr.next();
1669 todoNodes.add( edge.getDst() );
1672 // then follow links until all reachable nodes have been found
1673 while( !todoNodes.isEmpty() ) {
1674 HeapRegionNode hrn = todoNodes.iterator().next();
1675 todoNodes.remove(hrn);
1676 reachableNodes.add(hrn);
1678 Iterator<ReferenceEdge> edgeItr = hrn.iteratorToReferencees();
1679 while( edgeItr.hasNext() ) {
1680 ReferenceEdge edge = edgeItr.next();
1682 if( !reachableNodes.contains(edge.getDst() ) ) {
1683 todoNodes.add(edge.getDst() );
1689 paramIndex2reachableCallerNodes.put(index, reachableNodes);
1692 Set<Integer> aliasedIndices = new HashSet<Integer>();
1694 // check for arguments that are aliased
1695 for( int i = 0; i < fm.numParameters(); ++i ) {
1696 for( int j = 0; j < i; ++j ) {
1697 HashSet<HeapRegionNode> s1 = paramIndex2reachableCallerNodes.get( i );
1698 HashSet<HeapRegionNode> s2 = paramIndex2reachableCallerNodes.get( j );
1700 // some parameters are immutable or primitive, so skip em
1701 if( s1 == null || s2 == null ) {
1705 Set<HeapRegionNode> intersection = new HashSet<HeapRegionNode>(s1);
1706 intersection.retainAll(s2);
1708 if( !intersection.isEmpty() ) {
1709 aliasedIndices.add( new Integer( i ) );
1710 aliasedIndices.add( new Integer( j ) );
1715 return aliasedIndices;
1719 private String makeMapKey( Integer i, Integer j, String field ) {
1720 return i+","+j+","+field;
1723 private String makeMapKey( Integer i, String field ) {
1727 // these hashtables are used during the mapping procedure to say that
1728 // with respect to some argument i there is an edge placed into some
1729 // category for mapping with respect to another argument index j
1730 // so the key into the hashtable is i, the value is a two-element vector
1731 // that contains in 0 the edge and in 1 the Integer index j
1732 private void ensureEmptyEdgeIndexPair( Hashtable< Integer, Set<Vector> > edge_index_pairs,
1735 Set<Vector> ei = edge_index_pairs.get( indexI );
1737 ei = new HashSet<Vector>();
1739 edge_index_pairs.put( indexI, ei );
1742 private void addEdgeIndexPair( Hashtable< Integer, Set<Vector> > edge_index_pairs,
1747 Vector v = new Vector(); v.setSize( 2 );
1749 v.set( 1 , indexJ );
1750 Set<Vector> ei = edge_index_pairs.get( indexI );
1752 ei = new HashSet<Vector>();
1755 edge_index_pairs.put( indexI, ei );
1758 private ReachabilitySet funcScriptR( ReachabilitySet rsIn,
1759 OwnershipGraph ogCallee,
1760 MethodContext mc ) {
1762 ReachabilitySet rsOut = new ReachabilitySet( rsIn );
1764 Iterator itr = ogCallee.paramIndex2paramTokenPrimary.entrySet().iterator();
1765 while( itr.hasNext() ) {
1766 Map.Entry me = (Map.Entry) itr.next();
1767 Integer i = (Integer) me.getKey();
1768 TokenTuple p_i = (TokenTuple) me.getValue();
1769 TokenTuple s_i = ogCallee.paramIndex2paramTokenSecondary.get( i );
1771 // skip this if there is no secondary token or the parameter
1772 // is part of the aliasing context
1773 if( s_i == null || mc.getAliasedParamIndices().contains( i ) ) {
1777 rsOut = rsOut.removeTokenAIfTokenB( p_i, s_i );
1783 private void effectCalleeStrongUpdates( Integer paramIndex,
1784 OwnershipGraph ogCallee,
1785 HeapRegionNode hrnCaller
1787 Integer idPrimary = ogCallee.paramIndex2idPrimary.get( paramIndex );
1788 assert idPrimary != null;
1790 HeapRegionNode hrnPrimary = ogCallee.id2hrn.get( idPrimary );
1791 assert hrnPrimary != null;
1793 TypeDescriptor typeParam = hrnPrimary.getType();
1794 assert typeParam.isClass();
1796 Set<String> fieldNamesToRemove = new HashSet<String>();
1798 ClassDescriptor cd = typeParam.getClassDesc();
1799 while( cd != null ) {
1801 Iterator fieldItr = cd.getFields();
1802 while( fieldItr.hasNext() ) {
1804 FieldDescriptor fd = (FieldDescriptor) fieldItr.next();
1805 TypeDescriptor typeField = fd.getType();
1806 assert typeField != null;
1808 if( ogCallee.hasFieldBeenUpdated( hrnPrimary, fd.getSymbol() ) ) {
1809 clearReferenceEdgesFrom( hrnCaller, fd.getType(), fd.getSymbol(), false );
1813 cd = cd.getSuperDesc();
1817 private boolean hasFieldBeenUpdated( HeapRegionNode hrnPrimary, String field ) {
1819 Iterator<ReferenceEdge> itr = hrnPrimary.iteratorToReferencees();
1820 while( itr.hasNext() ) {
1821 ReferenceEdge e = itr.next();
1822 if( e.fieldEquals( field ) && e.isInitialParam() ) {
1830 public void resolveMethodCall(FlatCall fc,
1833 OwnershipGraph ogCallee,
1837 String debugCaller = "foo";
1838 String debugCallee = "bar";
1839 //String debugCaller = "StandardEngine";
1840 //String debugCaller = "register_by_type";
1841 //String debugCaller = "register_by_type_front";
1842 //String debugCaller = "addFirst";
1843 //String debugCallee = "LinkedListElement";
1845 if( mc.getDescriptor().getSymbol().equals( debugCaller ) &&
1846 fm.getMethod().getSymbol().equals( debugCallee ) ) {
1849 writeGraph( "debug1BeforeCall", true, true, true, false, false );
1850 ogCallee.writeGraph( "debug0Callee", true, true, true, false, false );
1851 } catch( IOException e ) {}
1853 System.out.println( " "+mc+" is calling "+fm );
1857 // define rewrite rules and other structures to organize data by parameter/argument index
1858 Hashtable<Integer, ReachabilitySet> paramIndex2rewriteH_p = new Hashtable<Integer, ReachabilitySet>();
1859 Hashtable<Integer, ReachabilitySet> paramIndex2rewriteH_s = new Hashtable<Integer, ReachabilitySet>();
1861 Hashtable<String, ReachabilitySet> paramIndex2rewriteJ_p2p = new Hashtable<String, ReachabilitySet>(); // select( i, j, f )
1862 Hashtable<String, ReachabilitySet> paramIndex2rewriteJ_p2s = new Hashtable<String, ReachabilitySet>(); // select( i, f )
1863 Hashtable<Integer, ReachabilitySet> paramIndex2rewriteJ_s2p = new Hashtable<Integer, ReachabilitySet>();
1864 Hashtable<Integer, ReachabilitySet> paramIndex2rewriteJ_s2s = new Hashtable<Integer, ReachabilitySet>();
1866 Hashtable<Integer, ReachabilitySet> paramIndex2rewriteK_p = new Hashtable<Integer, ReachabilitySet>();
1867 Hashtable<Integer, ReachabilitySet> paramIndex2rewriteK_p2 = new Hashtable<Integer, ReachabilitySet>();
1868 Hashtable<Integer, ReachabilitySet> paramIndex2rewriteK_s = new Hashtable<Integer, ReachabilitySet>();
1870 Hashtable<Integer, ReachabilitySet> paramIndex2rewrite_d_p = new Hashtable<Integer, ReachabilitySet>();
1871 Hashtable<Integer, ReachabilitySet> paramIndex2rewrite_d_s = new Hashtable<Integer, ReachabilitySet>();
1873 Hashtable<Integer, ReachabilitySet> paramIndex2rewriteD = new Hashtable<Integer, ReachabilitySet>();
1876 Hashtable<Integer, LabelNode> paramIndex2ln = new Hashtable<Integer, LabelNode>();
1879 paramIndex2rewriteH_p.put( bogusIndex, rsIdentity );
1880 paramIndex2rewriteH_s.put( bogusIndex, rsIdentity );
1882 paramIndex2rewriteJ_p2p.put( bogusIndex.toString(), rsIdentity );
1883 paramIndex2rewriteJ_p2s.put( bogusIndex.toString(), rsIdentity );
1884 paramIndex2rewriteJ_s2p.put( bogusIndex, rsIdentity );
1885 paramIndex2rewriteJ_s2s.put( bogusIndex, rsIdentity );
1888 for( int i = 0; i < fm.numParameters(); ++i ) {
1889 Integer paramIndex = new Integer(i);
1891 if( !ogCallee.paramIndex2idPrimary.containsKey( paramIndex ) ) {
1892 // skip this immutable parameter
1896 // setup H (primary)
1897 Integer idPrimary = ogCallee.paramIndex2idPrimary.get( paramIndex );
1898 assert ogCallee.id2hrn.containsKey( idPrimary );
1899 HeapRegionNode hrnPrimary = ogCallee.id2hrn.get( idPrimary );
1900 assert hrnPrimary != null;
1901 paramIndex2rewriteH_p.put( paramIndex, toShadowTokens( ogCallee, hrnPrimary.getAlpha() ) );
1903 // setup J (primary->X)
1904 Iterator<ReferenceEdge> p2xItr = hrnPrimary.iteratorToReferencees();
1905 while( p2xItr.hasNext() ) {
1906 ReferenceEdge p2xEdge = p2xItr.next();
1908 // we only care about initial parameter edges here
1909 if( !p2xEdge.isInitialParam() ) { continue; }
1911 HeapRegionNode hrnDst = p2xEdge.getDst();
1913 if( ogCallee.idPrimary2paramIndexSet.containsKey( hrnDst.getID() ) ) {
1914 Iterator<Integer> jItr = ogCallee.idPrimary2paramIndexSet.get( hrnDst.getID() ).iterator();
1915 while( jItr.hasNext() ) {
1916 Integer j = jItr.next();
1917 paramIndex2rewriteJ_p2p.put( makeMapKey( i, j, p2xEdge.getField() ),
1918 toShadowTokens( ogCallee, p2xEdge.getBeta() ) );
1922 assert ogCallee.idSecondary2paramIndexSet.containsKey( hrnDst.getID() );
1923 paramIndex2rewriteJ_p2s.put( makeMapKey( i, p2xEdge.getField() ),
1924 toShadowTokens( ogCallee, p2xEdge.getBeta() ) );
1928 // setup K (primary)
1929 TempDescriptor tdParamQ = ogCallee.paramIndex2tdQ.get( paramIndex );
1930 assert tdParamQ != null;
1931 LabelNode lnParamQ = ogCallee.td2ln.get( tdParamQ );
1932 assert lnParamQ != null;
1933 ReferenceEdge edgeSpecialQ_i = lnParamQ.getReferenceTo( hrnPrimary, null, null );
1934 assert edgeSpecialQ_i != null;
1935 ReachabilitySet qBeta = toShadowTokens( ogCallee, edgeSpecialQ_i.getBeta() );
1937 TokenTuple p_i = ogCallee.paramIndex2paramTokenPrimary .get( paramIndex );
1938 TokenTuple s_i = ogCallee.paramIndex2paramTokenSecondary.get( paramIndex );
1940 ReachabilitySet K_p = new ReachabilitySet().makeCanonical();
1941 ReachabilitySet K_p2 = new ReachabilitySet().makeCanonical();
1945 // sort qBeta into K_p1 and K_p2
1946 Iterator<TokenTupleSet> ttsItr = qBeta.iterator();
1947 while( ttsItr.hasNext() ) {
1948 TokenTupleSet tts = ttsItr.next();
1949 if( s_i != null && tts.containsBoth( p_i, s_i ) ) {
1950 K_p2 = K_p2.union( tts );
1952 K_p = K_p.union( tts );
1956 paramIndex2rewriteK_p .put( paramIndex, K_p );
1957 paramIndex2rewriteK_p2.put( paramIndex, K_p2 );
1960 // if there is a secondary node, compute the rest of the rewrite rules
1961 if( ogCallee.paramIndex2idSecondary.containsKey( paramIndex ) ) {
1963 // setup H (secondary)
1964 Integer idSecondary = ogCallee.paramIndex2idSecondary.get( paramIndex );
1965 assert ogCallee.id2hrn.containsKey( idSecondary );
1966 HeapRegionNode hrnSecondary = ogCallee.id2hrn.get( idSecondary );
1967 assert hrnSecondary != null;
1968 paramIndex2rewriteH_s.put( paramIndex, toShadowTokens( ogCallee, hrnSecondary.getAlpha() ) );
1971 // setup J (secondary->X)
1972 Iterator<ReferenceEdge> s2xItr = hrnSecondary.iteratorToReferencees();
1973 while( s2xItr.hasNext() ) {
1974 ReferenceEdge s2xEdge = s2xItr.next();
1976 if( !s2xEdge.isInitialParam() ) { continue; }
1978 HeapRegionNode hrnDst = s2xEdge.getDst();
1980 if( ogCallee.idPrimary2paramIndexSet.containsKey( hrnDst.getID() ) ) {
1981 Iterator<Integer> jItr = ogCallee.idPrimary2paramIndexSet.get( hrnDst.getID() ).iterator();
1982 while( jItr.hasNext() ) {
1983 Integer j = jItr.next();
1984 paramIndex2rewriteJ_s2p.put( i, toShadowTokens( ogCallee, s2xEdge.getBeta() ) );
1988 assert ogCallee.idSecondary2paramIndexSet.containsKey( hrnDst.getID() );
1989 paramIndex2rewriteJ_s2s.put( i, toShadowTokens( ogCallee, s2xEdge.getBeta() ) );
1993 // setup K (secondary)
1994 TempDescriptor tdParamR = ogCallee.paramIndex2tdR.get( paramIndex );
1995 assert tdParamR != null;
1996 LabelNode lnParamR = ogCallee.td2ln.get( tdParamR );
1997 assert lnParamR != null;
1998 ReferenceEdge edgeSpecialR_i = lnParamR.getReferenceTo( hrnSecondary, null, null );
1999 assert edgeSpecialR_i != null;
2000 paramIndex2rewriteK_s.put( paramIndex,
2001 toShadowTokens( ogCallee, edgeSpecialR_i.getBeta() ) );
2005 // now depending on whether the callee is static or not
2006 // we need to account for a "this" argument in order to
2007 // find the matching argument in the caller context
2008 TempDescriptor argTemp_i;
2010 argTemp_i = fc.getArg( paramIndex );
2012 if( paramIndex.equals( 0 ) ) {
2013 argTemp_i = fc.getThis();
2015 argTemp_i = fc.getArg( paramIndex - 1 );
2019 // in non-static methods there is a "this" pointer
2020 // that should be taken into account
2022 assert fc.numArgs() == fm.numParameters();
2024 assert fc.numArgs() + 1 == fm.numParameters();
2027 // remember which caller arg label maps to param index
2028 LabelNode argLabel_i = getLabelNodeFromTemp( argTemp_i );
2029 paramIndex2ln.put( paramIndex, argLabel_i );
2031 // do a callee-effect strong update pre-pass here
2032 if( argTemp_i.getType().isClass() ) {
2034 Iterator<ReferenceEdge> edgeItr = argLabel_i.iteratorToReferencees();
2035 while( edgeItr.hasNext() ) {
2036 ReferenceEdge edge = edgeItr.next();
2037 HeapRegionNode hrn = edge.getDst();
2039 if( (hrn.getNumReferencers() == 1) || // case 1
2040 (hrn.isSingleObject() && argLabel_i.getNumReferencees() == 1) // case 2
2043 effectCalleeStrongUpdates( paramIndex, ogCallee, hrn );
2048 // then calculate the d and D rewrite rules
2049 ReachabilitySet d_i_p = new ReachabilitySet().makeCanonical();
2050 ReachabilitySet d_i_s = new ReachabilitySet().makeCanonical();
2051 Iterator<ReferenceEdge> edgeItr = argLabel_i.iteratorToReferencees();
2052 while( edgeItr.hasNext() ) {
2053 ReferenceEdge edge = edgeItr.next();
2055 d_i_p = d_i_p.union( edge.getBeta().intersection( edge.getDst().getAlpha() ) );
2056 d_i_s = d_i_s.union( edge.getBeta() );
2058 paramIndex2rewrite_d_p.put( paramIndex, d_i_p );
2059 paramIndex2rewrite_d_s.put( paramIndex, d_i_s );
2061 // TODO: we should only do this when we need it, and then
2062 // memoize it for the rest of the mapping procedure
2063 ReachabilitySet D_i = d_i_s.exhaustiveArityCombinations();
2064 paramIndex2rewriteD.put( paramIndex, D_i );
2068 // with respect to each argument, map parameter effects into caller
2069 HashSet<HeapRegionNode> nodesWithNewAlpha = new HashSet<HeapRegionNode>();
2070 HashSet<ReferenceEdge> edgesWithNewBeta = new HashSet<ReferenceEdge>();
2072 Hashtable<Integer, Set<HeapRegionNode> > pi2dr =
2073 new Hashtable<Integer, Set<HeapRegionNode> >();
2075 Hashtable<Integer, Set<HeapRegionNode> > pi2r =
2076 new Hashtable<Integer, Set<HeapRegionNode> >();
2078 Set<HeapRegionNode> defParamObj = new HashSet<HeapRegionNode>();
2080 Iterator lnArgItr = paramIndex2ln.entrySet().iterator();
2081 while( lnArgItr.hasNext() ) {
2082 Map.Entry me = (Map.Entry) lnArgItr.next();
2083 Integer index = (Integer) me.getKey();
2084 LabelNode lnArg_i = (LabelNode) me.getValue();
2086 Set<HeapRegionNode> dr = new HashSet<HeapRegionNode>();
2087 Set<HeapRegionNode> r = new HashSet<HeapRegionNode>();
2088 Set<HeapRegionNode> todo = new HashSet<HeapRegionNode>();
2090 // find all reachable nodes starting with label referencees
2091 Iterator<ReferenceEdge> edgeArgItr = lnArg_i.iteratorToReferencees();
2092 while( edgeArgItr.hasNext() ) {
2093 ReferenceEdge edge = edgeArgItr.next();
2094 HeapRegionNode hrn = edge.getDst();
2098 if( lnArg_i.getNumReferencees() == 1 && hrn.isSingleObject() ) {
2099 defParamObj.add( hrn );
2102 Iterator<ReferenceEdge> edgeHrnItr = hrn.iteratorToReferencees();
2103 while( edgeHrnItr.hasNext() ) {
2104 ReferenceEdge edger = edgeHrnItr.next();
2105 todo.add( edger.getDst() );
2108 // then follow links until all reachable nodes have been found
2109 while( !todo.isEmpty() ) {
2110 HeapRegionNode hrnr = todo.iterator().next();
2111 todo.remove( hrnr );
2115 Iterator<ReferenceEdge> edgeItr = hrnr.iteratorToReferencees();
2116 while( edgeItr.hasNext() ) {
2117 ReferenceEdge edger = edgeItr.next();
2118 if( !r.contains( edger.getDst() ) ) {
2119 todo.add( edger.getDst() );
2124 if( hrn.isSingleObject() ) {
2129 pi2dr.put( index, dr );
2130 pi2r .put( index, r );
2133 assert defParamObj.size() <= fm.numParameters();
2136 // now iterate over reachable nodes to rewrite their alpha, and
2137 // classify edges found for beta rewrite
2138 Hashtable<TokenTuple, ReachabilitySet> tokens2states = new Hashtable<TokenTuple, ReachabilitySet>();
2140 Hashtable< Integer, Set<Vector> > edges_p2p = new Hashtable< Integer, Set<Vector> >();
2141 Hashtable< Integer, Set<Vector> > edges_p2s = new Hashtable< Integer, Set<Vector> >();
2142 Hashtable< Integer, Set<Vector> > edges_s2p = new Hashtable< Integer, Set<Vector> >();
2143 Hashtable< Integer, Set<Vector> > edges_s2s = new Hashtable< Integer, Set<Vector> >();
2144 Hashtable< Integer, Set<Vector> > edges_up_dr = new Hashtable< Integer, Set<Vector> >();
2145 Hashtable< Integer, Set<Vector> > edges_up_r = new Hashtable< Integer, Set<Vector> >();
2148 // so again, with respect to some arg i...
2149 lnArgItr = paramIndex2ln.entrySet().iterator();
2150 while( lnArgItr.hasNext() ) {
2151 Map.Entry me = (Map.Entry) lnArgItr.next();
2152 Integer index = (Integer) me.getKey();
2153 LabelNode lnArg_i = (LabelNode) me.getValue();
2155 TokenTuple p_i = ogCallee.paramIndex2paramTokenPrimary.get( index );
2156 TokenTuple s_i = ogCallee.paramIndex2paramTokenSecondary.get( index );
2159 ensureEmptyEdgeIndexPair( edges_p2p, index );
2160 ensureEmptyEdgeIndexPair( edges_p2s, index );
2161 ensureEmptyEdgeIndexPair( edges_s2p, index );
2162 ensureEmptyEdgeIndexPair( edges_s2s, index );
2163 ensureEmptyEdgeIndexPair( edges_up_dr, index );
2164 ensureEmptyEdgeIndexPair( edges_up_r, index );
2166 Set<HeapRegionNode> dr = pi2dr.get( index );
2167 Iterator<HeapRegionNode> hrnItr = dr.iterator();
2168 while( hrnItr.hasNext() ) {
2169 // this heap region is definitely an "a_i" or primary by virtue of being in dr
2170 HeapRegionNode hrn = hrnItr.next();
2172 tokens2states.clear();
2173 tokens2states.put( p_i, hrn.getAlpha() );
2175 rewriteCallerReachability( index,
2178 paramIndex2rewriteH_p.get( index ),
2180 paramIndex2rewrite_d_p,
2181 paramIndex2rewrite_d_s,
2182 paramIndex2rewriteD,
2187 nodesWithNewAlpha.add( hrn );
2190 Iterator<ReferenceEdge> edgeItr = hrn.iteratorToReferencers();
2191 while( edgeItr.hasNext() ) {
2192 ReferenceEdge edge = edgeItr.next();
2193 OwnershipNode on = edge.getSrc();
2195 boolean edge_classified = false;
2198 if( on instanceof HeapRegionNode ) {
2199 // hrn0 may be "a_j" and/or "r_j" or even neither
2200 HeapRegionNode hrn0 = (HeapRegionNode) on;
2202 Iterator itr = pi2dr.entrySet().iterator();
2203 while( itr.hasNext() ) {
2204 Map.Entry mo = (Map.Entry) itr.next();
2205 Integer pi = (Integer) mo.getKey();
2206 Set<HeapRegionNode> dr_i = (Set<HeapRegionNode>) mo.getValue();
2208 if( dr_i.contains( hrn0 ) ) {
2209 addEdgeIndexPair( edges_p2p, pi, edge, index );
2210 edge_classified = true;
2214 itr = pi2r.entrySet().iterator();
2215 while( itr.hasNext() ) {
2216 Map.Entry mo = (Map.Entry) itr.next();
2217 Integer pi = (Integer) mo.getKey();
2218 Set<HeapRegionNode> r_i = (Set<HeapRegionNode>) mo.getValue();
2220 if( r_i.contains( hrn0 ) ) {
2221 addEdgeIndexPair( edges_s2p, pi, edge, index );
2222 edge_classified = true;
2227 // all of these edges are upstream of directly reachable objects
2228 if( !edge_classified ) {
2229 addEdgeIndexPair( edges_up_dr, index, edge, index );
2235 Set<HeapRegionNode> r = pi2r.get( index );
2236 hrnItr = r.iterator();
2237 while( hrnItr.hasNext() ) {
2238 // this heap region is definitely an "r_i" or secondary by virtue of being in r
2239 HeapRegionNode hrn = hrnItr.next();
2241 if( paramIndex2rewriteH_s.containsKey( index ) ) {
2243 tokens2states.clear();
2244 tokens2states.put( p_i, new ReachabilitySet().makeCanonical() );
2245 tokens2states.put( s_i, hrn.getAlpha() );
2247 rewriteCallerReachability( index,
2250 paramIndex2rewriteH_s.get( index ),
2252 paramIndex2rewrite_d_p,
2253 paramIndex2rewrite_d_s,
2254 paramIndex2rewriteD,
2259 nodesWithNewAlpha.add( hrn );
2263 Iterator<ReferenceEdge> edgeItr = hrn.iteratorToReferencers();
2264 while( edgeItr.hasNext() ) {
2265 ReferenceEdge edge = edgeItr.next();
2266 OwnershipNode on = edge.getSrc();
2268 boolean edge_classified = false;
2270 if( on instanceof HeapRegionNode ) {
2271 // hrn0 may be "a_j" and/or "r_j" or even neither
2272 HeapRegionNode hrn0 = (HeapRegionNode) on;
2274 Iterator itr = pi2dr.entrySet().iterator();
2275 while( itr.hasNext() ) {
2276 Map.Entry mo = (Map.Entry) itr.next();
2277 Integer pi = (Integer) mo.getKey();
2278 Set<HeapRegionNode> dr_i = (Set<HeapRegionNode>) mo.getValue();
2280 if( dr_i.contains( hrn0 ) ) {
2281 addEdgeIndexPair( edges_p2s, pi, edge, index );
2282 edge_classified = true;
2286 itr = pi2r.entrySet().iterator();
2287 while( itr.hasNext() ) {
2288 Map.Entry mo = (Map.Entry) itr.next();
2289 Integer pi = (Integer) mo.getKey();
2290 Set<HeapRegionNode> r_i = (Set<HeapRegionNode>) mo.getValue();
2292 if( r_i.contains( hrn0 ) ) {
2293 addEdgeIndexPair( edges_s2s, pi, edge, index );
2294 edge_classified = true;
2299 // these edges are all upstream of some reachable node
2300 if( !edge_classified ) {
2301 addEdgeIndexPair( edges_up_r, index, edge, index );
2308 // and again, with respect to some arg i...
2309 lnArgItr = paramIndex2ln.entrySet().iterator();
2310 while( lnArgItr.hasNext() ) {
2311 Map.Entry me = (Map.Entry) lnArgItr.next();
2312 Integer index = (Integer) me.getKey();
2313 LabelNode lnArg_i = (LabelNode) me.getValue();
2316 // update reachable edges
2317 Iterator edgeItr = edges_p2p.get( index ).iterator();
2318 while( edgeItr.hasNext() ) {
2319 Vector mo = (Vector) edgeItr.next();
2320 ReferenceEdge edge = (ReferenceEdge) mo.get( 0 );
2321 Integer indexJ = (Integer) mo.get( 1 );
2323 if( !paramIndex2rewriteJ_p2p.containsKey( makeMapKey( index,
2325 edge.getField() ) ) ) {
2329 TokenTuple p_j = ogCallee.paramIndex2paramTokenPrimary.get( indexJ );
2332 tokens2states.clear();
2333 tokens2states.put( p_j, edge.getBeta() );
2335 rewriteCallerReachability( index,
2338 paramIndex2rewriteJ_p2p.get( makeMapKey( index,
2340 edge.getField() ) ),
2342 paramIndex2rewrite_d_p,
2343 paramIndex2rewrite_d_s,
2344 paramIndex2rewriteD,
2349 edgesWithNewBeta.add( edge );
2353 edgeItr = edges_p2s.get( index ).iterator();
2354 while( edgeItr.hasNext() ) {
2355 Vector mo = (Vector) edgeItr.next();
2356 ReferenceEdge edge = (ReferenceEdge) mo.get( 0 );
2357 Integer indexJ = (Integer) mo.get( 1 );
2359 if( !paramIndex2rewriteJ_p2s.containsKey( makeMapKey( index,
2360 edge.getField() ) ) ) {
2364 TokenTuple s_j = ogCallee.paramIndex2paramTokenSecondary.get( indexJ );
2367 tokens2states.clear();
2368 tokens2states.put( s_j, edge.getBeta() );
2370 rewriteCallerReachability( index,
2373 paramIndex2rewriteJ_p2s.get( makeMapKey( index,
2374 edge.getField() ) ),
2376 paramIndex2rewrite_d_p,
2377 paramIndex2rewrite_d_s,
2378 paramIndex2rewriteD,
2383 edgesWithNewBeta.add( edge );
2387 edgeItr = edges_s2p.get( index ).iterator();
2388 while( edgeItr.hasNext() ) {
2389 Vector mo = (Vector) edgeItr.next();
2390 ReferenceEdge edge = (ReferenceEdge) mo.get( 0 );
2391 Integer indexJ = (Integer) mo.get( 1 );
2393 if( !paramIndex2rewriteJ_s2p.containsKey( index ) ) {
2397 TokenTuple p_j = ogCallee.paramIndex2paramTokenPrimary.get( indexJ );
2400 tokens2states.clear();
2401 tokens2states.put( p_j, edge.getBeta() );
2403 rewriteCallerReachability( index,
2406 paramIndex2rewriteJ_s2p.get( index ),
2408 paramIndex2rewrite_d_p,
2409 paramIndex2rewrite_d_s,
2410 paramIndex2rewriteD,
2415 edgesWithNewBeta.add( edge );
2419 edgeItr = edges_s2s.get( index ).iterator();
2420 while( edgeItr.hasNext() ) {
2421 Vector mo = (Vector) edgeItr.next();
2422 ReferenceEdge edge = (ReferenceEdge) mo.get( 0 );
2423 Integer indexJ = (Integer) mo.get( 1 );
2425 if( !paramIndex2rewriteJ_s2s.containsKey( index ) ) {
2429 TokenTuple s_j = ogCallee.paramIndex2paramTokenSecondary.get( indexJ );
2432 tokens2states.clear();
2433 tokens2states.put( s_j, edge.getBeta() );
2435 rewriteCallerReachability( index,
2438 paramIndex2rewriteJ_s2s.get( index ),
2440 paramIndex2rewrite_d_p,
2441 paramIndex2rewrite_d_s,
2442 paramIndex2rewriteD,
2447 edgesWithNewBeta.add( edge );
2451 // update directly upstream edges
2452 Hashtable<ReferenceEdge, ChangeTupleSet> edgeUpstreamPlannedChanges =
2453 new Hashtable<ReferenceEdge, ChangeTupleSet>();
2455 HashSet<ReferenceEdge> edgesDirectlyUpstream =
2456 new HashSet<ReferenceEdge>();
2458 edgeItr = edges_up_dr.get( index ).iterator();
2459 while( edgeItr.hasNext() ) {
2460 Vector mo = (Vector) edgeItr.next();
2461 ReferenceEdge edge = (ReferenceEdge) mo.get( 0 );
2462 Integer indexJ = (Integer) mo.get( 1 );
2464 edgesDirectlyUpstream.add( edge );
2466 TokenTuple p_j = ogCallee.paramIndex2paramTokenPrimary.get( indexJ );
2469 // start with K_p2 and p_j
2470 tokens2states.clear();
2471 tokens2states.put( p_j, edge.getBeta() );
2473 rewriteCallerReachability( index,
2476 paramIndex2rewriteK_p2.get( index ),
2478 paramIndex2rewrite_d_p,
2479 paramIndex2rewrite_d_s,
2480 paramIndex2rewriteD,
2483 edgeUpstreamPlannedChanges );
2485 // and add in s_j, if required, and do K_p
2486 TokenTuple s_j = ogCallee.paramIndex2paramTokenSecondary.get( indexJ );
2488 tokens2states.put( s_j, edge.getBeta() );
2491 rewriteCallerReachability( index,
2494 paramIndex2rewriteK_p.get( index ),
2496 paramIndex2rewrite_d_p,
2497 paramIndex2rewrite_d_s,
2498 paramIndex2rewriteD,
2501 edgeUpstreamPlannedChanges );
2503 edgesWithNewBeta.add( edge );
2506 propagateTokensOverEdges( edgesDirectlyUpstream,
2507 edgeUpstreamPlannedChanges,
2511 // update upstream edges
2512 edgeUpstreamPlannedChanges =
2513 new Hashtable<ReferenceEdge, ChangeTupleSet>();
2515 HashSet<ReferenceEdge> edgesUpstream =
2516 new HashSet<ReferenceEdge>();
2518 edgeItr = edges_up_r.get( index ).iterator();
2519 while( edgeItr.hasNext() ) {
2520 Vector mo = (Vector) edgeItr.next();
2521 ReferenceEdge edge = (ReferenceEdge) mo.get( 0 );
2522 Integer indexJ = (Integer) mo.get( 1 );
2524 if( !paramIndex2rewriteK_s.containsKey( index ) ) {
2528 edgesUpstream.add( edge );
2530 TokenTuple p_j = ogCallee.paramIndex2paramTokenPrimary.get( indexJ );
2533 TokenTuple s_j = ogCallee.paramIndex2paramTokenSecondary.get( indexJ );
2536 tokens2states.clear();
2537 tokens2states.put( p_j, rsWttsEmpty );
2538 tokens2states.put( s_j, edge.getBeta() );
2540 rewriteCallerReachability( index,
2543 paramIndex2rewriteK_s.get( index ),
2545 paramIndex2rewrite_d_p,
2546 paramIndex2rewrite_d_s,
2547 paramIndex2rewriteD,
2550 edgeUpstreamPlannedChanges );
2552 edgesWithNewBeta.add( edge );
2555 propagateTokensOverEdges( edgesUpstream,
2556 edgeUpstreamPlannedChanges,
2559 } // end effects per argument/parameter map
2562 // commit changes to alpha and beta
2563 Iterator<HeapRegionNode> nodeItr = nodesWithNewAlpha.iterator();
2564 while( nodeItr.hasNext() ) {
2565 nodeItr.next().applyAlphaNew();
2568 Iterator<ReferenceEdge> edgeItr = edgesWithNewBeta.iterator();
2569 while( edgeItr.hasNext() ) {
2570 edgeItr.next().applyBetaNew();
2574 // verify the existence of allocation sites and their
2575 // shadows from the callee in the context of this caller graph
2576 // then map allocated nodes of callee onto the caller shadows
2578 Hashtable<TokenTuple, ReachabilitySet> tokens2statesEmpty = new Hashtable<TokenTuple, ReachabilitySet>();
2580 Iterator<AllocationSite> asItr = ogCallee.allocationSites.iterator();
2581 while( asItr.hasNext() ) {
2582 AllocationSite allocSite = asItr.next();
2584 // grab the summary in the caller just to make sure
2585 // the allocation site has nodes in the caller
2586 HeapRegionNode hrnSummary = getSummaryNode( allocSite );
2588 // assert that the shadow nodes have no reference edges
2589 // because they're brand new to the graph, or last time
2590 // they were used they should have been cleared of edges
2591 HeapRegionNode hrnShadowSummary = getShadowSummaryNode( allocSite );
2592 assert hrnShadowSummary.getNumReferencers() == 0;
2593 assert hrnShadowSummary.getNumReferencees() == 0;
2595 // then bring g_ij onto g'_ij and rewrite
2596 HeapRegionNode hrnSummaryCallee = ogCallee.getSummaryNode( allocSite );
2597 hrnShadowSummary.setAlpha( toShadowTokens( ogCallee, hrnSummaryCallee.getAlpha() ) );
2599 // shadow nodes only are touched by a rewrite one time,
2600 // so rewrite and immediately commit--and they don't belong
2601 // to a particular parameter, so use a bogus param index
2602 // that pulls a self-rewrite out of H
2603 rewriteCallerReachability( bogusIndex,
2606 funcScriptR( hrnShadowSummary.getAlpha(), ogCallee, mc ),
2608 paramIndex2rewrite_d_p,
2609 paramIndex2rewrite_d_s,
2610 paramIndex2rewriteD,
2615 hrnShadowSummary.applyAlphaNew();
2618 for( int i = 0; i < allocSite.getAllocationDepth(); ++i ) {
2619 Integer idIth = allocSite.getIthOldest(i);
2620 assert id2hrn.containsKey(idIth);
2621 HeapRegionNode hrnIth = id2hrn.get(idIth);
2623 Integer idShadowIth = -(allocSite.getIthOldest(i));
2624 assert id2hrn.containsKey(idShadowIth);
2625 HeapRegionNode hrnIthShadow = id2hrn.get(idShadowIth);
2626 assert hrnIthShadow.getNumReferencers() == 0;
2627 assert hrnIthShadow.getNumReferencees() == 0;
2629 assert ogCallee.id2hrn.containsKey(idIth);
2630 HeapRegionNode hrnIthCallee = ogCallee.id2hrn.get(idIth);
2631 hrnIthShadow.setAlpha(toShadowTokens(ogCallee, hrnIthCallee.getAlpha() ) );
2633 rewriteCallerReachability( bogusIndex,
2636 funcScriptR( hrnIthShadow.getAlpha(), ogCallee, mc ),
2638 paramIndex2rewrite_d_p,
2639 paramIndex2rewrite_d_s,
2640 paramIndex2rewriteD,
2645 hrnIthShadow.applyAlphaNew();
2650 // for every heap region->heap region edge in the
2651 // callee graph, create the matching edge or edges
2652 // in the caller graph
2653 Set sCallee = ogCallee.id2hrn.entrySet();
2654 Iterator iCallee = sCallee.iterator();
2655 while( iCallee.hasNext() ) {
2656 Map.Entry meCallee = (Map.Entry) iCallee.next();
2657 Integer idCallee = (Integer) meCallee.getKey();
2658 HeapRegionNode hrnCallee = (HeapRegionNode) meCallee.getValue();
2660 Iterator<ReferenceEdge> heapRegionsItrCallee = hrnCallee.iteratorToReferencees();
2661 while( heapRegionsItrCallee.hasNext() ) {
2662 ReferenceEdge edgeCallee = heapRegionsItrCallee.next();
2663 HeapRegionNode hrnChildCallee = edgeCallee.getDst();
2664 Integer idChildCallee = hrnChildCallee.getID();
2666 // only address this edge if it is not a special initial edge
2667 if( !edgeCallee.isInitialParam() ) {
2669 // now we know that in the callee method's ownership graph
2670 // there is a heap region->heap region reference edge given
2671 // by heap region pointers:
2672 // hrnCallee -> heapChildCallee
2674 // or by the ownership-graph independent ID's:
2675 // idCallee -> idChildCallee
2677 // make the edge with src and dst so beta info is
2678 // calculated once, then copy it for each new edge in caller
2680 ReferenceEdge edgeNewInCallerTemplate = new ReferenceEdge( null,
2682 edgeCallee.getType(),
2683 edgeCallee.getField(),
2685 funcScriptR( toShadowTokens( ogCallee,
2686 edgeCallee.getBeta()
2692 rewriteCallerReachability( bogusIndex,
2694 edgeNewInCallerTemplate,
2695 edgeNewInCallerTemplate.getBeta(),
2697 paramIndex2rewrite_d_p,
2698 paramIndex2rewrite_d_s,
2699 paramIndex2rewriteD,
2704 edgeNewInCallerTemplate.applyBetaNew();
2707 // So now make a set of possible source heaps in the caller graph
2708 // and a set of destination heaps in the caller graph, and make
2709 // a reference edge in the caller for every possible (src,dst) pair
2710 HashSet<HeapRegionNode> possibleCallerSrcs =
2711 getHRNSetThatPossiblyMapToCalleeHRN( ogCallee,
2712 (HeapRegionNode) edgeCallee.getSrc(),
2716 HashSet<HeapRegionNode> possibleCallerDsts =
2717 getHRNSetThatPossiblyMapToCalleeHRN( ogCallee,
2718 edgeCallee.getDst(),
2722 // make every possible pair of {srcSet} -> {dstSet} edges in the caller
2723 Iterator srcItr = possibleCallerSrcs.iterator();
2724 while( srcItr.hasNext() ) {
2725 HeapRegionNode src = (HeapRegionNode) srcItr.next();
2727 if( !hasMatchingField( src, edgeCallee ) ) {
2728 // prune this source node possibility
2732 Iterator dstItr = possibleCallerDsts.iterator();
2733 while( dstItr.hasNext() ) {
2734 HeapRegionNode dst = (HeapRegionNode) dstItr.next();
2736 if( !hasMatchingType( edgeCallee, dst ) ) {
2741 // otherwise the caller src and dst pair can match the edge, so make it
2742 ReferenceEdge edgeNewInCaller = edgeNewInCallerTemplate.copy();
2743 edgeNewInCaller.setSrc( src );
2744 edgeNewInCaller.setDst( dst );
2746 ReferenceEdge edgeExisting = src.getReferenceTo( dst,
2747 edgeNewInCaller.getType(),
2748 edgeNewInCaller.getField() );
2749 if( edgeExisting == null ) {
2750 // if this edge doesn't exist in the caller, create it
2751 addReferenceEdge( src, dst, edgeNewInCaller );
2754 // if it already exists, merge with it
2755 edgeExisting.setBeta( edgeExisting.getBeta().union( edgeNewInCaller.getBeta() ) );
2764 // return value may need to be assigned in caller
2765 TempDescriptor returnTemp = fc.getReturnTemp();
2766 if( returnTemp != null && !returnTemp.getType().isImmutable() ) {
2768 LabelNode lnLhsCaller = getLabelNodeFromTemp( returnTemp );
2769 clearReferenceEdgesFrom( lnLhsCaller, null, null, true );
2771 LabelNode lnReturnCallee = ogCallee.getLabelNodeFromTemp( tdReturn );
2772 Iterator<ReferenceEdge> edgeCalleeItr = lnReturnCallee.iteratorToReferencees();
2773 while( edgeCalleeItr.hasNext() ) {
2774 ReferenceEdge edgeCallee = edgeCalleeItr.next();
2776 ReferenceEdge edgeNewInCallerTemplate = new ReferenceEdge( null,
2778 edgeCallee.getType(),
2779 edgeCallee.getField(),
2781 funcScriptR( toShadowTokens(ogCallee,
2782 edgeCallee.getBeta() ),
2786 rewriteCallerReachability( bogusIndex,
2788 edgeNewInCallerTemplate,
2789 edgeNewInCallerTemplate.getBeta(),
2791 paramIndex2rewrite_d_p,
2792 paramIndex2rewrite_d_s,
2793 paramIndex2rewriteD,
2798 edgeNewInCallerTemplate.applyBetaNew();
2801 HashSet<HeapRegionNode> assignCallerRhs =
2802 getHRNSetThatPossiblyMapToCalleeHRN( ogCallee,
2803 edgeCallee.getDst(),
2807 Iterator<HeapRegionNode> itrHrn = assignCallerRhs.iterator();
2808 while( itrHrn.hasNext() ) {
2809 HeapRegionNode hrnCaller = itrHrn.next();
2811 if( !hasMatchingType( edgeCallee, hrnCaller ) ) {
2816 // otherwise caller node can match callee edge, so make it
2817 ReferenceEdge edgeNewInCaller = edgeNewInCallerTemplate.copy();
2818 edgeNewInCaller.setSrc( lnLhsCaller );
2819 edgeNewInCaller.setDst( hrnCaller );
2821 ReferenceEdge edgeExisting = lnLhsCaller.getReferenceTo( hrnCaller,
2822 edgeNewInCaller.getType(),
2823 edgeNewInCaller.getField() );
2824 if( edgeExisting == null ) {
2826 // if this edge doesn't exist in the caller, create it
2827 addReferenceEdge( lnLhsCaller, hrnCaller, edgeNewInCaller );
2829 // if it already exists, merge with it
2830 edgeExisting.setBeta( edgeExisting.getBeta().union( edgeNewInCaller.getBeta() ) );
2837 if( mc.getDescriptor().getSymbol().equals( debugCaller ) &&
2838 fm.getMethod().getSymbol().equals( debugCallee ) ) {
2840 writeGraph( "debug7JustBeforeMergeToKCapacity", true, true, true, false, false );
2841 } catch( IOException e ) {}
2846 // merge the shadow nodes of allocation sites back down to normal capacity
2847 Iterator<AllocationSite> allocItr = ogCallee.allocationSites.iterator();
2848 while( allocItr.hasNext() ) {
2849 AllocationSite as = allocItr.next();
2851 // first age each allocation site enough times to make room for the shadow nodes
2852 for( int i = 0; i < as.getAllocationDepth(); ++i ) {
2856 // then merge the shadow summary into the normal summary
2857 HeapRegionNode hrnSummary = getSummaryNode( as );
2858 assert hrnSummary != null;
2860 HeapRegionNode hrnSummaryShadow = getShadowSummaryNode( as );
2861 assert hrnSummaryShadow != null;
2863 mergeIntoSummary( hrnSummaryShadow, hrnSummary );
2865 // then clear off after merge
2866 clearReferenceEdgesFrom( hrnSummaryShadow, null, null, true );
2867 clearReferenceEdgesTo ( hrnSummaryShadow, null, null, true );
2868 hrnSummaryShadow.setAlpha( new ReachabilitySet().makeCanonical() );
2870 // then transplant shadow nodes onto the now clean normal nodes
2871 for( int i = 0; i < as.getAllocationDepth(); ++i ) {
2873 Integer idIth = as.getIthOldest( i );
2874 HeapRegionNode hrnIth = id2hrn.get( idIth );
2875 Integer idIthShadow = as.getIthOldestShadow( i );
2876 HeapRegionNode hrnIthShadow = id2hrn.get( idIthShadow );
2878 transferOnto( hrnIthShadow, hrnIth );
2880 // clear off shadow nodes after transfer
2881 clearReferenceEdgesFrom( hrnIthShadow, null, null, true );
2882 clearReferenceEdgesTo ( hrnIthShadow, null, null, true );
2883 hrnIthShadow.setAlpha( new ReachabilitySet().makeCanonical() );
2886 // finally, globally change shadow tokens into normal tokens
2887 Iterator itrAllLabelNodes = td2ln.entrySet().iterator();
2888 while( itrAllLabelNodes.hasNext() ) {
2889 Map.Entry me = (Map.Entry) itrAllLabelNodes.next();
2890 LabelNode ln = (LabelNode) me.getValue();
2892 Iterator<ReferenceEdge> itrEdges = ln.iteratorToReferencees();
2893 while( itrEdges.hasNext() ) {
2894 unshadowTokens( as, itrEdges.next() );
2898 Iterator itrAllHRNodes = id2hrn.entrySet().iterator();
2899 while( itrAllHRNodes.hasNext() ) {
2900 Map.Entry me = (Map.Entry) itrAllHRNodes.next();
2901 HeapRegionNode hrnToAge = (HeapRegionNode) me.getValue();
2903 unshadowTokens( as, hrnToAge );
2905 Iterator<ReferenceEdge> itrEdges = hrnToAge.iteratorToReferencees();
2906 while( itrEdges.hasNext() ) {
2907 unshadowTokens( as, itrEdges.next() );
2913 if( mc.getDescriptor().getSymbol().equals( debugCaller ) &&
2914 fm.getMethod().getSymbol().equals( debugCallee ) ) {
2916 writeGraph( "debug8JustBeforeSweep", true, true, true, false, false );
2917 } catch( IOException e ) {}
2921 // improve reachability as much as possible
2926 if( mc.getDescriptor().getSymbol().equals( debugCaller ) &&
2927 fm.getMethod().getSymbol().equals( debugCallee ) ) {
2929 writeGraph( "debug9endResolveCall", true, true, true, false, false );
2930 } catch( IOException e ) {}
2931 System.out.println( " "+mc+" done calling "+fm );
2942 protected boolean hasMatchingField(HeapRegionNode src, ReferenceEdge edge) {
2944 // if no type, then it's a match-everything region
2945 TypeDescriptor tdSrc = src.getType();
2946 if( tdSrc == null ) {
2950 if( tdSrc.isArray() ) {
2951 TypeDescriptor td = edge.getType();
2954 TypeDescriptor tdSrcDeref = tdSrc.dereference();
2955 assert tdSrcDeref != null;
2957 if( !typeUtil.isSuperorType( tdSrcDeref, td ) ) {
2961 return edge.getField().equals( OwnershipAnalysis.arrayElementFieldName );
2964 // if it's not a class, it doesn't have any fields to match
2965 if( !tdSrc.isClass() ) {
2969 ClassDescriptor cd = tdSrc.getClassDesc();
2970 while( cd != null ) {
2971 Iterator fieldItr = cd.getFields();
2973 while( fieldItr.hasNext() ) {
2974 FieldDescriptor fd = (FieldDescriptor) fieldItr.next();
2976 if( fd.getType().equals( edge.getType() ) &&
2977 fd.getSymbol().equals( edge.getField() ) ) {
2982 cd = cd.getSuperDesc();
2985 // otherwise it is a class with fields
2986 // but we didn't find a match
2991 protected boolean hasMatchingType(ReferenceEdge edge, HeapRegionNode dst) {
2993 // if the region has no type, matches everything
2994 TypeDescriptor tdDst = dst.getType();
2995 if( tdDst == null ) {
2999 // if the type is not a class or an array, don't
3000 // match because primitives are copied, no aliases
3001 ClassDescriptor cdDst = tdDst.getClassDesc();
3002 if( cdDst == null && !tdDst.isArray() ) {
3006 // if the edge type is null, it matches everything
3007 TypeDescriptor tdEdge = edge.getType();
3008 if( tdEdge == null ) {
3012 return typeUtil.isSuperorType(tdEdge, tdDst);
3017 protected void unshadowTokens(AllocationSite as, ReferenceEdge edge) {
3018 edge.setBeta(edge.getBeta().unshadowTokens(as) );
3021 protected void unshadowTokens(AllocationSite as, HeapRegionNode hrn) {
3022 hrn.setAlpha(hrn.getAlpha().unshadowTokens(as) );
3026 private ReachabilitySet toShadowTokens(OwnershipGraph ogCallee,
3027 ReachabilitySet rsIn) {
3029 ReachabilitySet rsOut = new ReachabilitySet(rsIn).makeCanonical();
3031 Iterator<AllocationSite> allocItr = ogCallee.allocationSites.iterator();
3032 while( allocItr.hasNext() ) {
3033 AllocationSite as = allocItr.next();
3035 rsOut = rsOut.toShadowTokens(as);
3038 return rsOut.makeCanonical();
3042 private void rewriteCallerReachability(Integer paramIndex,
3045 ReachabilitySet rules,
3046 Hashtable<TokenTuple, ReachabilitySet> tokens2states,
3047 Hashtable<Integer, ReachabilitySet> paramIndex2rewrite_d_p,
3048 Hashtable<Integer, ReachabilitySet> paramIndex2rewrite_d_s,
3049 Hashtable<Integer, ReachabilitySet> paramIndex2rewriteD,
3050 OwnershipGraph ogCallee,
3051 boolean makeChangeSet,
3052 Hashtable<ReferenceEdge, ChangeTupleSet> edgePlannedChanges) {
3054 assert(hrn == null && edge != null) ||
3055 (hrn != null && edge == null);
3057 assert rules != null;
3058 assert tokens2states != null;
3060 ReachabilitySet callerReachabilityNew = new ReachabilitySet().makeCanonical();
3062 // for initializing structures in this method
3063 TokenTupleSet ttsEmpty = new TokenTupleSet().makeCanonical();
3065 // use this to construct a change set if required; the idea is to
3066 // map every partially rewritten token tuple set to the set of
3067 // caller-context token tuple sets that were used to generate it
3068 Hashtable<TokenTupleSet, HashSet<TokenTupleSet> > rewritten2source =
3069 new Hashtable<TokenTupleSet, HashSet<TokenTupleSet> >();
3070 rewritten2source.put( ttsEmpty, new HashSet<TokenTupleSet>() );
3073 Iterator<TokenTupleSet> rulesItr = rules.iterator();
3074 while(rulesItr.hasNext()) {
3075 TokenTupleSet rule = rulesItr.next();
3077 ReachabilitySet rewrittenRule = new ReachabilitySet(ttsEmpty).makeCanonical();
3079 Iterator<TokenTuple> ruleItr = rule.iterator();
3080 while(ruleItr.hasNext()) {
3081 TokenTuple ttCallee = ruleItr.next();
3083 // compute the possibilities for rewriting this callee token
3084 ReachabilitySet ttCalleeRewrites = null;
3085 boolean callerSourceUsed = false;
3087 if( tokens2states.containsKey( ttCallee ) ) {
3088 callerSourceUsed = true;
3089 ttCalleeRewrites = tokens2states.get( ttCallee );
3090 assert ttCalleeRewrites != null;
3092 } else if( ogCallee.paramTokenPrimary2paramIndex.containsKey( ttCallee ) ) {
3094 Integer paramIndex_j = ogCallee.paramTokenPrimary2paramIndex.get( ttCallee );
3095 assert paramIndex_j != null;
3096 ttCalleeRewrites = paramIndex2rewrite_d_p.get( paramIndex_j );
3097 assert ttCalleeRewrites != null;
3099 } else if( ogCallee.paramTokenSecondary2paramIndex.containsKey( ttCallee ) ) {
3101 Integer paramIndex_j = ogCallee.paramTokenSecondary2paramIndex.get( ttCallee );
3102 assert paramIndex_j != null;
3103 ttCalleeRewrites = paramIndex2rewrite_d_s.get( paramIndex_j );
3104 assert ttCalleeRewrites != null;
3106 } else if( ogCallee.paramTokenSecondaryPlus2paramIndex.containsKey( ttCallee ) ) {
3108 Integer paramIndex_j = ogCallee.paramTokenSecondaryPlus2paramIndex.get( ttCallee );
3109 assert paramIndex_j != null;
3110 ttCalleeRewrites = paramIndex2rewriteD.get( paramIndex_j );
3111 assert ttCalleeRewrites != null;
3113 } else if( ogCallee.paramTokenSecondaryStar2paramIndex.containsKey( ttCallee ) ) {
3115 Integer paramIndex_j = ogCallee.paramTokenSecondaryStar2paramIndex.get( ttCallee );
3116 assert paramIndex_j != null;
3117 ttCalleeRewrites = paramIndex2rewriteD.get( paramIndex_j );
3118 assert ttCalleeRewrites != null;
3121 // otherwise there's no need for a rewrite, just pass this one on
3122 TokenTupleSet ttsCaller = new TokenTupleSet( ttCallee ).makeCanonical();
3123 ttCalleeRewrites = new ReachabilitySet( ttsCaller ).makeCanonical();
3126 // branch every version of the working rewritten rule with
3127 // the possibilities for rewriting the current callee token
3128 ReachabilitySet rewrittenRuleWithTTCallee = new ReachabilitySet().makeCanonical();
3130 Iterator<TokenTupleSet> rewrittenRuleItr = rewrittenRule.iterator();
3131 while( rewrittenRuleItr.hasNext() ) {
3132 TokenTupleSet ttsRewritten = rewrittenRuleItr.next();
3134 Iterator<TokenTupleSet> ttCalleeRewritesItr = ttCalleeRewrites.iterator();
3135 while( ttCalleeRewritesItr.hasNext() ) {
3136 TokenTupleSet ttsBranch = ttCalleeRewritesItr.next();
3138 TokenTupleSet ttsRewrittenNext = ttsRewritten.unionUpArity( ttsBranch );
3140 if( makeChangeSet ) {
3141 // in order to keep the list of source token tuple sets
3142 // start with the sets used to make the partially rewritten
3143 // rule up to this point
3144 HashSet<TokenTupleSet> sourceSets = rewritten2source.get( ttsRewritten );
3145 assert sourceSets != null;
3147 // make a shallow copy for possible modification
3148 sourceSets = (HashSet<TokenTupleSet>) sourceSets.clone();
3150 // if we used something from the caller to rewrite it, remember
3151 if( callerSourceUsed ) {
3152 sourceSets.add( ttsBranch );
3155 // set mapping for the further rewritten rule
3156 rewritten2source.put( ttsRewrittenNext, sourceSets );
3159 rewrittenRuleWithTTCallee =
3160 rewrittenRuleWithTTCallee.union( ttsRewrittenNext );
3164 // now the rewritten rule's possibilities have been extended by
3165 // rewriting the current callee token, remember result
3166 rewrittenRule = rewrittenRuleWithTTCallee;
3169 // the rule has been entirely rewritten into the caller context
3170 // now, so add it to the new reachability information
3171 callerReachabilityNew =
3172 callerReachabilityNew.union( rewrittenRule );
3175 if( makeChangeSet ) {
3176 ChangeTupleSet callerChangeSet = new ChangeTupleSet().makeCanonical();
3178 // each possibility for the final reachability should have a set of
3179 // caller sources mapped to it, use to create the change set
3180 Iterator<TokenTupleSet> callerReachabilityItr = callerReachabilityNew.iterator();
3181 while( callerReachabilityItr.hasNext() ) {
3182 TokenTupleSet ttsRewrittenFinal = callerReachabilityItr.next();
3183 HashSet<TokenTupleSet> sourceSets = rewritten2source.get( ttsRewrittenFinal );
3184 assert sourceSets != null;
3186 Iterator<TokenTupleSet> sourceSetsItr = sourceSets.iterator();
3187 while( sourceSetsItr.hasNext() ) {
3188 TokenTupleSet ttsSource = sourceSetsItr.next();
3191 callerChangeSet.union( new ChangeTuple( ttsSource, ttsRewrittenFinal ) );
3195 assert edgePlannedChanges != null;
3196 edgePlannedChanges.put( edge, callerChangeSet );
3200 edge.setBetaNew( edge.getBetaNew().union( callerReachabilityNew ) );
3202 hrn.setAlphaNew( hrn.getAlphaNew().union( callerReachabilityNew ) );
3208 private HashSet<HeapRegionNode>
3209 getHRNSetThatPossiblyMapToCalleeHRN( OwnershipGraph ogCallee,
3210 HeapRegionNode hrnCallee,
3211 Hashtable<Integer, Set<HeapRegionNode> > pi2dr,
3212 Hashtable<Integer, Set<HeapRegionNode> > pi2r
3215 HashSet<HeapRegionNode> possibleCallerHRNs = new HashSet<HeapRegionNode>();
3217 Set<Integer> paramIndicesCallee_p = ogCallee.idPrimary2paramIndexSet .get( hrnCallee.getID() );
3218 Set<Integer> paramIndicesCallee_s = ogCallee.idSecondary2paramIndexSet.get( hrnCallee.getID() );
3220 if( paramIndicesCallee_p == null &&
3221 paramIndicesCallee_s == null ) {
3222 // this is a node allocated in the callee and it has
3223 // exactly one shadow node in the caller to map to
3224 AllocationSite as = hrnCallee.getAllocationSite();
3227 int age = as.getAgeCategory( hrnCallee.getID() );
3228 assert age != AllocationSite.AGE_notInThisSite;
3231 if( age == AllocationSite.AGE_summary ) {
3232 idCaller = as.getSummaryShadow();
3234 } else if( age == AllocationSite.AGE_oldest ) {
3235 idCaller = as.getOldestShadow();
3238 assert age == AllocationSite.AGE_in_I;
3240 Integer I = as.getAge( hrnCallee.getID() );
3243 idCaller = as.getIthOldestShadow( I );
3246 assert id2hrn.containsKey( idCaller );
3247 possibleCallerHRNs.add( id2hrn.get( idCaller ) );
3249 return possibleCallerHRNs;
3252 // find out what primary objects this might be
3253 if( paramIndicesCallee_p != null ) {
3254 // this is a node that was created to represent a parameter
3255 // so it maps to some regions directly reachable from the arg labels
3256 Iterator<Integer> itrIndex = paramIndicesCallee_p.iterator();
3257 while( itrIndex.hasNext() ) {
3258 Integer paramIndexCallee = itrIndex.next();
3259 assert pi2dr.containsKey( paramIndexCallee );
3260 possibleCallerHRNs.addAll( pi2dr.get( paramIndexCallee ) );
3264 // find out what secondary objects this might be
3265 if( paramIndicesCallee_s != null ) {
3266 // this is a node that was created to represent objs reachable from
3267 // some parameter, so it maps to regions reachable from the arg labels
3268 Iterator<Integer> itrIndex = paramIndicesCallee_s.iterator();
3269 while( itrIndex.hasNext() ) {
3270 Integer paramIndexCallee = itrIndex.next();
3271 assert pi2r.containsKey( paramIndexCallee );
3272 possibleCallerHRNs.addAll( pi2r.get( paramIndexCallee ) );
3276 // TODO: is this true?
3277 // one of the two cases above should have put something in here
3278 //assert !possibleCallerHRNs.isEmpty();
3280 return possibleCallerHRNs;
3285 ////////////////////////////////////////////////////
3287 // This global sweep is an optional step to prune
3288 // reachability sets that are not internally
3289 // consistent with the global graph. It should be
3290 // invoked after strong updates or method calls.
3292 ////////////////////////////////////////////////////
3293 public void globalSweep() {
3295 // boldB is part of the phase 1 sweep
3296 Hashtable< Integer, Hashtable<ReferenceEdge, ReachabilitySet> > boldB =
3297 new Hashtable< Integer, Hashtable<ReferenceEdge, ReachabilitySet> >();
3299 // visit every heap region to initialize alphaNew and calculate boldB
3300 Set hrns = id2hrn.entrySet();
3301 Iterator itrHrns = hrns.iterator();
3302 while( itrHrns.hasNext() ) {
3303 Map.Entry me = (Map.Entry)itrHrns.next();
3304 Integer token = (Integer) me.getKey();
3305 HeapRegionNode hrn = (HeapRegionNode) me.getValue();
3307 // assert that this node and incoming edges have clean alphaNew
3308 // and betaNew sets, respectively
3309 assert rsEmpty.equals( hrn.getAlphaNew() );
3311 Iterator<ReferenceEdge> itrRers = hrn.iteratorToReferencers();
3312 while( itrRers.hasNext() ) {
3313 ReferenceEdge edge = itrRers.next();
3314 assert rsEmpty.equals( edge.getBetaNew() );
3317 // calculate boldB for this flagged node
3318 if( hrn.isFlagged() || hrn.isParameter() ) {
3320 Hashtable<ReferenceEdge, ReachabilitySet> boldB_f =
3321 new Hashtable<ReferenceEdge, ReachabilitySet>();
3323 Set<ReferenceEdge> workSetEdges = new HashSet<ReferenceEdge>();
3325 // initial boldB_f constraints
3326 Iterator<ReferenceEdge> itrRees = hrn.iteratorToReferencees();
3327 while( itrRees.hasNext() ) {
3328 ReferenceEdge edge = itrRees.next();
3330 assert !boldB.containsKey( edge );
3331 boldB_f.put( edge, edge.getBeta() );
3333 assert !workSetEdges.contains( edge );
3334 workSetEdges.add( edge );
3337 // enforce the boldB_f constraint at edges until we reach a fixed point
3338 while( !workSetEdges.isEmpty() ) {
3339 ReferenceEdge edge = workSetEdges.iterator().next();
3340 workSetEdges.remove( edge );
3342 Iterator<ReferenceEdge> itrPrime = edge.getDst().iteratorToReferencees();
3343 while( itrPrime.hasNext() ) {
3344 ReferenceEdge edgePrime = itrPrime.next();
3346 ReachabilitySet prevResult = boldB_f.get( edgePrime );
3347 ReachabilitySet intersection = boldB_f.get( edge ).intersection( edgePrime.getBeta() );
3349 if( prevResult == null ||
3350 prevResult.union( intersection ).size() > prevResult.size() ) {
3352 if( prevResult == null ) {
3353 boldB_f.put( edgePrime, edgePrime.getBeta().union( intersection ) );
3355 boldB_f.put( edgePrime, prevResult .union( intersection ) );
3357 workSetEdges.add( edgePrime );
3362 boldB.put( token, boldB_f );
3367 // use boldB to prune tokens from alpha states that are impossible
3368 // and propagate the differences backwards across edges
3369 HashSet<ReferenceEdge> edgesForPropagation = new HashSet<ReferenceEdge>();
3371 Hashtable<ReferenceEdge, ChangeTupleSet> edgePlannedChanges =
3372 new Hashtable<ReferenceEdge, ChangeTupleSet>();
3374 hrns = id2hrn.entrySet();
3375 itrHrns = hrns.iterator();
3376 while( itrHrns.hasNext() ) {
3377 Map.Entry me = (Map.Entry)itrHrns.next();
3378 Integer token = (Integer) me.getKey();
3379 HeapRegionNode hrn = (HeapRegionNode) me.getValue();
3381 // never remove the identity token from a flagged region
3382 // because it is trivially satisfied
3383 TokenTuple ttException = new TokenTuple( token,
3384 !hrn.isSingleObject(),
3385 TokenTuple.ARITY_ONE ).makeCanonical();
3387 ChangeTupleSet cts = new ChangeTupleSet().makeCanonical();
3389 // mark tokens for removal
3390 Iterator<TokenTupleSet> stateItr = hrn.getAlpha().iterator();
3391 while( stateItr.hasNext() ) {
3392 TokenTupleSet ttsOld = stateItr.next();
3394 TokenTupleSet markedTokens = new TokenTupleSet().makeCanonical();
3396 Iterator<TokenTuple> ttItr = ttsOld.iterator();
3397 while( ttItr.hasNext() ) {
3398 TokenTuple ttOld = ttItr.next();
3400 // never remove the identity token from a flagged region
3401 // because it is trivially satisfied
3402 if( hrn.isFlagged() || hrn.isParameter() ) {
3403 if( ttOld == ttException ) {
3408 // does boldB_ttOld allow this token?
3409 boolean foundState = false;
3410 Iterator<ReferenceEdge> incidentEdgeItr = hrn.iteratorToReferencers();
3411 while( incidentEdgeItr.hasNext() ) {
3412 ReferenceEdge incidentEdge = incidentEdgeItr.next();
3414 // if it isn't allowed, mark for removal
3415 Integer idOld = ttOld.getToken();
3416 assert id2hrn.containsKey( idOld );
3417 Hashtable<ReferenceEdge, ReachabilitySet> B = boldB.get( idOld );
3418 ReachabilitySet boldB_ttOld_incident = B.get( incidentEdge );// B is NULL!
3419 if( boldB_ttOld_incident != null &&
3420 boldB_ttOld_incident.contains( ttsOld ) ) {
3426 markedTokens = markedTokens.add( ttOld );
3430 // if there is nothing marked, just move on
3431 if( markedTokens.isEmpty() ) {
3432 hrn.setAlphaNew( hrn.getAlphaNew().union( ttsOld ) );
3436 // remove all marked tokens and establish a change set that should
3437 // propagate backwards over edges from this node
3438 TokenTupleSet ttsPruned = new TokenTupleSet().makeCanonical();
3439 ttItr = ttsOld.iterator();
3440 while( ttItr.hasNext() ) {
3441 TokenTuple ttOld = ttItr.next();
3443 if( !markedTokens.containsTuple( ttOld ) ) {
3444 ttsPruned = ttsPruned.union( ttOld );
3447 assert !ttsOld.equals( ttsPruned );
3449 hrn.setAlphaNew( hrn.getAlphaNew().union( ttsPruned ) );
3450 ChangeTuple ct = new ChangeTuple( ttsOld, ttsPruned ).makeCanonical();
3451 cts = cts.union( ct );
3454 // throw change tuple set on all incident edges
3455 if( !cts.isEmpty() ) {
3456 Iterator<ReferenceEdge> incidentEdgeItr = hrn.iteratorToReferencers();
3457 while( incidentEdgeItr.hasNext() ) {
3458 ReferenceEdge incidentEdge = incidentEdgeItr.next();
3460 edgesForPropagation.add( incidentEdge );
3462 if( edgePlannedChanges.get( incidentEdge ) == null ) {
3463 edgePlannedChanges.put( incidentEdge, cts );
3465 edgePlannedChanges.put(
3467 edgePlannedChanges.get( incidentEdge ).union( cts )
3474 HashSet<ReferenceEdge> edgesUpdated = new HashSet<ReferenceEdge>();
3476 propagateTokensOverEdges( edgesForPropagation,
3480 // at the end of the 1st phase reference edges have
3481 // beta, betaNew that correspond to beta and betaR
3483 // commit beta<-betaNew, so beta=betaR and betaNew
3484 // will represent the beta' calculation in 2nd phase
3486 // commit alpha<-alphaNew because it won't change
3487 HashSet<ReferenceEdge> res = new HashSet<ReferenceEdge>();
3489 Iterator<HeapRegionNode> nodeItr = id2hrn.values().iterator();
3490 while( nodeItr.hasNext() ) {
3491 HeapRegionNode hrn = nodeItr.next();
3492 hrn.applyAlphaNew();
3493 Iterator<ReferenceEdge> itrRes = hrn.iteratorToReferencers();
3494 while( itrRes.hasNext() ) {
3495 res.add( itrRes.next() );
3501 Iterator<ReferenceEdge> edgeItr = res.iterator();
3502 while( edgeItr.hasNext() ) {
3503 ReferenceEdge edge = edgeItr.next();
3504 HeapRegionNode hrn = edge.getDst();
3506 // commit results of last phase
3507 if( edgesUpdated.contains( edge ) ) {
3508 edge.applyBetaNew();
3511 // compute intial condition of 2nd phase
3512 edge.setBetaNew( edge.getBeta().intersection( hrn.getAlpha() ) );
3515 // every edge in the graph is the initial workset
3516 Set<ReferenceEdge> edgeWorkSet = (Set) res.clone();
3517 while( !edgeWorkSet.isEmpty() ) {
3518 ReferenceEdge edgePrime = edgeWorkSet.iterator().next();
3519 edgeWorkSet.remove( edgePrime );
3521 OwnershipNode on = edgePrime.getSrc();
3522 if( !(on instanceof HeapRegionNode) ) {
3525 HeapRegionNode hrn = (HeapRegionNode) on;
3527 Iterator<ReferenceEdge> itrEdge = hrn.iteratorToReferencers();
3528 while( itrEdge.hasNext() ) {
3529 ReferenceEdge edge = itrEdge.next();
3531 ReachabilitySet prevResult = edge.getBetaNew();
3532 assert prevResult != null;
3534 ReachabilitySet intersection = edge.getBeta().intersection( edgePrime.getBetaNew() );
3536 if( prevResult.union( intersection ).size() > prevResult.size() ) {
3537 edge.setBetaNew( prevResult.union( intersection ) );
3538 edgeWorkSet.add( edge );
3543 // commit beta' (beta<-betaNew)
3544 edgeItr = res.iterator();
3545 while( edgeItr.hasNext() ) {
3546 edgeItr.next().applyBetaNew();
3552 ////////////////////////////////////////////////////
3553 // in merge() and equals() methods the suffix A
3554 // represents the passed in graph and the suffix
3555 // B refers to the graph in this object
3556 // Merging means to take the incoming graph A and
3557 // merge it into B, so after the operation graph B
3558 // is the final result.
3559 ////////////////////////////////////////////////////
3560 public void merge(OwnershipGraph og) {
3566 mergeOwnershipNodes(og);
3567 mergeReferenceEdges(og);
3568 mergeParamIndexMappings(og);
3569 mergeAllocationSites(og);
3573 protected void mergeOwnershipNodes(OwnershipGraph og) {
3574 Set sA = og.id2hrn.entrySet();
3575 Iterator iA = sA.iterator();
3576 while( iA.hasNext() ) {
3577 Map.Entry meA = (Map.Entry)iA.next();
3578 Integer idA = (Integer) meA.getKey();
3579 HeapRegionNode hrnA = (HeapRegionNode) meA.getValue();
3581 // if this graph doesn't have a node the
3582 // incoming graph has, allocate it
3583 if( !id2hrn.containsKey(idA) ) {
3584 HeapRegionNode hrnB = hrnA.copy();
3585 id2hrn.put(idA, hrnB);
3588 // otherwise this is a node present in both graphs
3589 // so make the new reachability set a union of the
3590 // nodes' reachability sets
3591 HeapRegionNode hrnB = id2hrn.get(idA);
3592 hrnB.setAlpha(hrnB.getAlpha().union(hrnA.getAlpha() ) );
3596 // now add any label nodes that are in graph B but
3598 sA = og.td2ln.entrySet();
3600 while( iA.hasNext() ) {
3601 Map.Entry meA = (Map.Entry)iA.next();
3602 TempDescriptor tdA = (TempDescriptor) meA.getKey();
3603 LabelNode lnA = (LabelNode) meA.getValue();
3605 // if the label doesn't exist in B, allocate and add it
3606 LabelNode lnB = getLabelNodeFromTemp(tdA);
3610 protected void mergeReferenceEdges(OwnershipGraph og) {
3613 Set sA = og.id2hrn.entrySet();
3614 Iterator iA = sA.iterator();
3615 while( iA.hasNext() ) {
3616 Map.Entry meA = (Map.Entry)iA.next();
3617 Integer idA = (Integer) meA.getKey();
3618 HeapRegionNode hrnA = (HeapRegionNode) meA.getValue();
3620 Iterator<ReferenceEdge> heapRegionsItrA = hrnA.iteratorToReferencees();
3621 while( heapRegionsItrA.hasNext() ) {
3622 ReferenceEdge edgeA = heapRegionsItrA.next();
3623 HeapRegionNode hrnChildA = edgeA.getDst();
3624 Integer idChildA = hrnChildA.getID();
3626 // at this point we know an edge in graph A exists
3627 // idA -> idChildA, does this exist in B?
3628 assert id2hrn.containsKey(idA);
3629 HeapRegionNode hrnB = id2hrn.get(idA);
3630 ReferenceEdge edgeToMerge = null;
3632 Iterator<ReferenceEdge> heapRegionsItrB = hrnB.iteratorToReferencees();
3633 while( heapRegionsItrB.hasNext() &&
3634 edgeToMerge == null ) {
3636 ReferenceEdge edgeB = heapRegionsItrB.next();
3637 HeapRegionNode hrnChildB = edgeB.getDst();
3638 Integer idChildB = hrnChildB.getID();
3640 // don't use the ReferenceEdge.equals() here because
3641 // we're talking about existence between graphs
3642 if( idChildB.equals( idChildA ) &&
3643 edgeB.typeAndFieldEquals( edgeA ) ) {
3645 edgeToMerge = edgeB;
3649 // if the edge from A was not found in B,
3651 if( edgeToMerge == null ) {
3652 assert id2hrn.containsKey(idChildA);
3653 HeapRegionNode hrnChildB = id2hrn.get(idChildA);
3654 edgeToMerge = edgeA.copy();
3655 edgeToMerge.setSrc(hrnB);
3656 edgeToMerge.setDst(hrnChildB);
3657 addReferenceEdge(hrnB, hrnChildB, edgeToMerge);
3659 // otherwise, the edge already existed in both graphs
3660 // so merge their reachability sets
3662 // just replace this beta set with the union
3663 assert edgeToMerge != null;
3664 edgeToMerge.setBeta(
3665 edgeToMerge.getBeta().union(edgeA.getBeta() )
3667 if( !edgeA.isInitialParam() ) {
3668 edgeToMerge.setIsInitialParam(false);
3674 // and then again with label nodes
3675 sA = og.td2ln.entrySet();
3677 while( iA.hasNext() ) {
3678 Map.Entry meA = (Map.Entry)iA.next();
3679 TempDescriptor tdA = (TempDescriptor) meA.getKey();
3680 LabelNode lnA = (LabelNode) meA.getValue();
3682 Iterator<ReferenceEdge> heapRegionsItrA = lnA.iteratorToReferencees();
3683 while( heapRegionsItrA.hasNext() ) {
3684 ReferenceEdge edgeA = heapRegionsItrA.next();
3685 HeapRegionNode hrnChildA = edgeA.getDst();
3686 Integer idChildA = hrnChildA.getID();
3688 // at this point we know an edge in graph A exists
3689 // tdA -> idChildA, does this exist in B?
3690 assert td2ln.containsKey(tdA);
3691 LabelNode lnB = td2ln.get(tdA);
3692 ReferenceEdge edgeToMerge = null;
3694 Iterator<ReferenceEdge> heapRegionsItrB = lnB.iteratorToReferencees();
3695 while( heapRegionsItrB.hasNext() &&
3696 edgeToMerge == null ) {
3698 ReferenceEdge edgeB = heapRegionsItrB.next();
3699 HeapRegionNode hrnChildB = edgeB.getDst();
3700 Integer idChildB = hrnChildB.getID();
3702 // don't use the ReferenceEdge.equals() here because
3703 // we're talking about existence between graphs
3704 if( idChildB.equals( idChildA ) &&
3705 edgeB.typeAndFieldEquals( edgeA ) ) {
3707 edgeToMerge = edgeB;
3711 // if the edge from A was not found in B,
3713 if( edgeToMerge == null ) {
3714 assert id2hrn.containsKey(idChildA);
3715 HeapRegionNode hrnChildB = id2hrn.get(idChildA);
3716 edgeToMerge = edgeA.copy();
3717 edgeToMerge.setSrc(lnB);
3718 edgeToMerge.setDst(hrnChildB);
3719 addReferenceEdge(lnB, hrnChildB, edgeToMerge);
3721 // otherwise, the edge already existed in both graphs
3722 // so merge their reachability sets
3724 // just replace this beta set with the union
3725 edgeToMerge.setBeta(
3726 edgeToMerge.getBeta().union(edgeA.getBeta() )
3728 if( !edgeA.isInitialParam() ) {
3729 edgeToMerge.setIsInitialParam(false);
3736 // you should only merge ownership graphs that have the
3737 // same number of parameters, or if one or both parameter
3738 // index tables are empty
3739 protected void mergeParamIndexMappings(OwnershipGraph og) {
3741 if( idPrimary2paramIndexSet.size() == 0 ) {
3743 idPrimary2paramIndexSet = og.idPrimary2paramIndexSet;
3744 paramIndex2idPrimary = og.paramIndex2idPrimary;
3746 idSecondary2paramIndexSet = og.idSecondary2paramIndexSet;
3747 paramIndex2idSecondary = og.paramIndex2idSecondary;
3749 paramIndex2tdQ = og.paramIndex2tdQ;
3750 paramIndex2tdR = og.paramIndex2tdR;
3752 paramTokenPrimary2paramIndex = og.paramTokenPrimary2paramIndex;
3753 paramIndex2paramTokenPrimary = og.paramIndex2paramTokenPrimary;
3755 paramTokenSecondary2paramIndex = og.paramTokenSecondary2paramIndex;
3756 paramIndex2paramTokenSecondary = og.paramIndex2paramTokenSecondary;
3757 paramTokenSecondaryPlus2paramIndex = og.paramTokenSecondaryPlus2paramIndex;
3758 paramIndex2paramTokenSecondaryPlus = og.paramIndex2paramTokenSecondaryPlus;
3759 paramTokenSecondaryStar2paramIndex = og.paramTokenSecondaryStar2paramIndex;
3760 paramIndex2paramTokenSecondaryStar = og.paramIndex2paramTokenSecondaryStar;
3765 if( og.idPrimary2paramIndexSet.size() == 0 ) {
3767 og.idPrimary2paramIndexSet = idPrimary2paramIndexSet;
3768 og.paramIndex2idPrimary = paramIndex2idPrimary;
3770 og.idSecondary2paramIndexSet = idSecondary2paramIndexSet;
3771 og.paramIndex2idSecondary = paramIndex2idSecondary;
3773 og.paramIndex2tdQ = paramIndex2tdQ;
3774 og.paramIndex2tdR = paramIndex2tdR;
3776 og.paramTokenPrimary2paramIndex = paramTokenPrimary2paramIndex;
3777 og.paramIndex2paramTokenPrimary = paramIndex2paramTokenPrimary;
3779 og.paramTokenSecondary2paramIndex = paramTokenSecondary2paramIndex;
3780 og.paramIndex2paramTokenSecondary = paramIndex2paramTokenSecondary;
3781 og.paramTokenSecondaryPlus2paramIndex = paramTokenSecondaryPlus2paramIndex;
3782 og.paramIndex2paramTokenSecondaryPlus = paramIndex2paramTokenSecondaryPlus;
3783 og.paramTokenSecondaryStar2paramIndex = paramTokenSecondaryStar2paramIndex;
3784 og.paramIndex2paramTokenSecondaryStar = paramIndex2paramTokenSecondaryStar;
3789 assert idPrimary2paramIndexSet.size() == og.idPrimary2paramIndexSet.size();
3790 assert idSecondary2paramIndexSet.size() == og.idSecondary2paramIndexSet.size();
3793 protected void mergeAllocationSites(OwnershipGraph og) {
3794 allocationSites.addAll(og.allocationSites);
3799 // it is necessary in the equals() member functions
3800 // to "check both ways" when comparing the data
3801 // structures of two graphs. For instance, if all
3802 // edges between heap region nodes in graph A are
3803 // present and equal in graph B it is not sufficient
3804 // to say the graphs are equal. Consider that there
3805 // may be edges in graph B that are not in graph A.
3806 // the only way to know that all edges in both graphs
3807 // are equally present is to iterate over both data
3808 // structures and compare against the other graph.
3809 public boolean equals(OwnershipGraph og) {
3815 if( !areHeapRegionNodesEqual(og) ) {
3819 if( !areLabelNodesEqual(og) ) {
3823 if( !areReferenceEdgesEqual(og) ) {
3827 if( !areParamIndexMappingsEqual(og) ) {
3831 // if everything is equal up to this point,
3832 // assert that allocationSites is also equal--
3833 // this data is redundant and kept for efficiency
3834 assert allocationSites.equals(og.allocationSites);
3839 protected boolean areHeapRegionNodesEqual(OwnershipGraph og) {
3841 if( !areallHRNinAalsoinBandequal(this, og) ) {
3845 if( !areallHRNinAalsoinBandequal(og, this) ) {
3852 static protected boolean areallHRNinAalsoinBandequal(OwnershipGraph ogA,
3853 OwnershipGraph ogB) {
3854 Set sA = ogA.id2hrn.entrySet();
3855 Iterator iA = sA.iterator();
3856 while( iA.hasNext() ) {
3857 Map.Entry meA = (Map.Entry)iA.next();
3858 Integer idA = (Integer) meA.getKey();
3859 HeapRegionNode hrnA = (HeapRegionNode) meA.getValue();
3861 if( !ogB.id2hrn.containsKey(idA) ) {
3865 HeapRegionNode hrnB = ogB.id2hrn.get(idA);
3866 if( !hrnA.equalsIncludingAlpha(hrnB) ) {
3875 protected boolean areLabelNodesEqual(OwnershipGraph og) {
3877 if( !areallLNinAalsoinBandequal(this, og) ) {
3881 if( !areallLNinAalsoinBandequal(og, this) ) {
3888 static protected boolean areallLNinAalsoinBandequal(OwnershipGraph ogA,
3889 OwnershipGraph ogB) {
3890 Set sA = ogA.td2ln.entrySet();
3891 Iterator iA = sA.iterator();
3892 while( iA.hasNext() ) {
3893 Map.Entry meA = (Map.Entry)iA.next();
3894 TempDescriptor tdA = (TempDescriptor) meA.getKey();
3896 if( !ogB.td2ln.containsKey(tdA) ) {
3905 protected boolean areReferenceEdgesEqual(OwnershipGraph og) {
3906 if( !areallREinAandBequal(this, og) ) {
3913 static protected boolean areallREinAandBequal(OwnershipGraph ogA,
3914 OwnershipGraph ogB) {
3916 // check all the heap region->heap region edges
3917 Set sA = ogA.id2hrn.entrySet();
3918 Iterator iA = sA.iterator();
3919 while( iA.hasNext() ) {
3920 Map.Entry meA = (Map.Entry)iA.next();
3921 Integer idA = (Integer) meA.getKey();
3922 HeapRegionNode hrnA = (HeapRegionNode) meA.getValue();
3924 // we should have already checked that the same
3925 // heap regions exist in both graphs
3926 assert ogB.id2hrn.containsKey(idA);
3928 if( !areallREfromAequaltoB(ogA, hrnA, ogB) ) {
3932 // then check every edge in B for presence in A, starting
3933 // from the same parent HeapRegionNode
3934 HeapRegionNode hrnB = ogB.id2hrn.get(idA);
3936 if( !areallREfromAequaltoB(ogB, hrnB, ogA) ) {
3941 // then check all the label->heap region edges
3942 sA = ogA.td2ln.entrySet();
3944 while( iA.hasNext() ) {
3945 Map.Entry meA = (Map.Entry)iA.next();
3946 TempDescriptor tdA = (TempDescriptor) meA.getKey();
3947 LabelNode lnA = (LabelNode) meA.getValue();
3949 // we should have already checked that the same
3950 // label nodes exist in both graphs
3951 assert ogB.td2ln.containsKey(tdA);
3953 if( !areallREfromAequaltoB(ogA, lnA, ogB) ) {
3957 // then check every edge in B for presence in A, starting
3958 // from the same parent LabelNode
3959 LabelNode lnB = ogB.td2ln.get(tdA);
3961 if( !areallREfromAequaltoB(ogB, lnB, ogA) ) {
3970 static protected boolean areallREfromAequaltoB(OwnershipGraph ogA,
3972 OwnershipGraph ogB) {
3974 Iterator<ReferenceEdge> itrA = onA.iteratorToReferencees();
3975 while( itrA.hasNext() ) {
3976 ReferenceEdge edgeA = itrA.next();
3977 HeapRegionNode hrnChildA = edgeA.getDst();
3978 Integer idChildA = hrnChildA.getID();
3980 assert ogB.id2hrn.containsKey(idChildA);
3982 // at this point we know an edge in graph A exists
3983 // onA -> idChildA, does this exact edge exist in B?
3984 boolean edgeFound = false;
3986 OwnershipNode onB = null;
3987 if( onA instanceof HeapRegionNode ) {
3988 HeapRegionNode hrnA = (HeapRegionNode) onA;
3989 onB = ogB.id2hrn.get(hrnA.getID() );
3991 LabelNode lnA = (LabelNode) onA;
3992 onB = ogB.td2ln.get(lnA.getTempDescriptor() );
3995 Iterator<ReferenceEdge> itrB = onB.iteratorToReferencees();
3996 while( itrB.hasNext() ) {
3997 ReferenceEdge edgeB = itrB.next();
3998 HeapRegionNode hrnChildB = edgeB.getDst();
3999 Integer idChildB = hrnChildB.getID();
4001 if( idChildA.equals( idChildB ) &&
4002 edgeA.typeAndFieldEquals( edgeB ) ) {
4004 // there is an edge in the right place with the right field,
4005 // but do they have the same attributes?
4006 if( edgeA.getBeta().equals(edgeB.getBeta() ) ) {
4021 protected boolean areParamIndexMappingsEqual(OwnershipGraph og) {
4023 if( idPrimary2paramIndexSet.size() != og.idPrimary2paramIndexSet.size() ) {
4027 if( idSecondary2paramIndexSet.size() != og.idSecondary2paramIndexSet.size() ) {
4035 public Set<HeapRegionNode> hasPotentialAlias( HeapRegionNode hrn1, HeapRegionNode hrn2 ) {
4036 assert hrn1 != null;
4037 assert hrn2 != null;
4039 // then get the various tokens for these heap regions
4040 TokenTuple h1 = new TokenTuple(hrn1.getID(),
4041 !hrn1.isSingleObject(),
4042 TokenTuple.ARITY_ONE).makeCanonical();
4044 TokenTuple h1plus = new TokenTuple(hrn1.getID(),
4045 !hrn1.isSingleObject(),
4046 TokenTuple.ARITY_ONEORMORE).makeCanonical();
4048 TokenTuple h1star = new TokenTuple(hrn1.getID(),
4049 !hrn1.isSingleObject(),
4050 TokenTuple.ARITY_ZEROORMORE).makeCanonical();
4052 TokenTuple h2 = new TokenTuple(hrn2.getID(),
4053 !hrn2.isSingleObject(),
4054 TokenTuple.ARITY_ONE).makeCanonical();
4056 TokenTuple h2plus = new TokenTuple(hrn2.getID(),
4057 !hrn2.isSingleObject(),
4058 TokenTuple.ARITY_ONEORMORE).makeCanonical();
4060 TokenTuple h2star = new TokenTuple(hrn2.getID(),
4061 !hrn2.isSingleObject(),
4062 TokenTuple.ARITY_ZEROORMORE).makeCanonical();
4064 // then get the merged beta of all out-going edges from these heap regions
4065 ReachabilitySet beta1 = new ReachabilitySet().makeCanonical();
4066 Iterator<ReferenceEdge> itrEdge = hrn1.iteratorToReferencees();
4067 while( itrEdge.hasNext() ) {
4068 ReferenceEdge edge = itrEdge.next();
4069 beta1 = beta1.union( edge.getBeta() );
4072 ReachabilitySet beta2 = new ReachabilitySet().makeCanonical();
4073 itrEdge = hrn2.iteratorToReferencees();
4074 while( itrEdge.hasNext() ) {
4075 ReferenceEdge edge = itrEdge.next();
4076 beta2 = beta2.union( edge.getBeta() );
4079 boolean aliasDetected = false;
4081 // only do this one if they are different tokens
4083 beta1.containsTupleSetWithBoth(h1, h2) ) {
4084 aliasDetected = true;
4086 if( beta1.containsTupleSetWithBoth(h1plus, h2) ) {
4087 aliasDetected = true;
4089 if( beta1.containsTupleSetWithBoth(h1star, h2) ) {
4090 aliasDetected = true;
4092 if( beta1.containsTupleSetWithBoth(h1, h2plus) ) {
4093 aliasDetected = true;
4095 if( beta1.containsTupleSetWithBoth(h1plus, h2plus) ) {
4096 aliasDetected = true;
4098 if( beta1.containsTupleSetWithBoth(h1star, h2plus) ) {
4099 aliasDetected = true;
4101 if( beta1.containsTupleSetWithBoth(h1, h2star) ) {
4102 aliasDetected = true;
4104 if( beta1.containsTupleSetWithBoth(h1plus, h2star) ) {
4105 aliasDetected = true;
4107 if( beta1.containsTupleSetWithBoth(h1star, h2star) ) {
4108 aliasDetected = true;
4112 beta2.containsTupleSetWithBoth(h1, h2) ) {
4113 aliasDetected = true;
4115 if( beta2.containsTupleSetWithBoth(h1plus, h2) ) {
4116 aliasDetected = true;
4118 if( beta2.containsTupleSetWithBoth(h1star, h2) ) {
4119 aliasDetected = true;
4121 if( beta2.containsTupleSetWithBoth(h1, h2plus) ) {
4122 aliasDetected = true;
4124 if( beta2.containsTupleSetWithBoth(h1plus, h2plus) ) {
4125 aliasDetected = true;
4127 if( beta2.containsTupleSetWithBoth(h1star, h2plus) ) {
4128 aliasDetected = true;
4130 if( beta2.containsTupleSetWithBoth(h1, h2star) ) {
4131 aliasDetected = true;
4133 if( beta2.containsTupleSetWithBoth(h1plus, h2star) ) {
4134 aliasDetected = true;
4136 if( beta2.containsTupleSetWithBoth(h1star, h2star) ) {
4137 aliasDetected = true;
4140 Set<HeapRegionNode> common = new HashSet<HeapRegionNode>();
4141 if( aliasDetected ) {
4142 common = findCommonReachableNodes( hrn1, hrn2 );
4143 assert !common.isEmpty();
4150 public Set<HeapRegionNode> hasPotentialAlias(Integer paramIndex1, Integer paramIndex2) {
4152 // get parameter 1's heap regions
4153 assert paramIndex2idPrimary.containsKey(paramIndex1);
4154 Integer idParamPri1 = paramIndex2idPrimary.get(paramIndex1);
4156 assert id2hrn.containsKey(idParamPri1);
4157 HeapRegionNode hrnParamPri1 = id2hrn.get(idParamPri1);
4158 assert hrnParamPri1 != null;
4160 HeapRegionNode hrnParamSec1 = null;
4161 if( paramIndex2idSecondary.containsKey(paramIndex1) ) {
4162 Integer idParamSec1 = paramIndex2idSecondary.get(paramIndex1);
4164 assert id2hrn.containsKey(idParamSec1);
4165 hrnParamSec1 = id2hrn.get(idParamSec1);
4166 assert hrnParamSec1 != null;
4170 // get the other parameter
4171 assert paramIndex2idPrimary.containsKey(paramIndex2);
4172 Integer idParamPri2 = paramIndex2idPrimary.get(paramIndex2);
4174 assert id2hrn.containsKey(idParamPri2);
4175 HeapRegionNode hrnParamPri2 = id2hrn.get(idParamPri2);
4176 assert hrnParamPri2 != null;
4178 HeapRegionNode hrnParamSec2 = null;
4179 if( paramIndex2idSecondary.containsKey(paramIndex2) ) {
4180 Integer idParamSec2 = paramIndex2idSecondary.get(paramIndex2);
4182 assert id2hrn.containsKey(idParamSec2);
4183 hrnParamSec2 = id2hrn.get(idParamSec2);
4184 assert hrnParamSec2 != null;
4187 Set<HeapRegionNode> common = new HashSet<HeapRegionNode>();
4188 common.addAll( hasPotentialAlias( hrnParamPri1, hrnParamPri2 ) );
4190 if( hrnParamSec1 != null ) {
4191 common.addAll( hasPotentialAlias( hrnParamSec1, hrnParamPri2 ) );
4194 if( hrnParamSec2 != null ) {
4195 common.addAll( hasPotentialAlias( hrnParamSec2, hrnParamPri1 ) );
4198 if( hrnParamSec1 != null && hrnParamSec2 != null ) {
4199 common.addAll( hasPotentialAlias( hrnParamSec1, hrnParamSec2 ) );
4206 public Set<HeapRegionNode> hasPotentialAlias(Integer paramIndex, AllocationSite as) {
4208 // get parameter's heap regions
4209 assert paramIndex2idPrimary.containsKey(paramIndex);
4210 Integer idParamPri = paramIndex2idPrimary.get(paramIndex);
4212 assert id2hrn.containsKey(idParamPri);
4213 HeapRegionNode hrnParamPri = id2hrn.get(idParamPri);
4214 assert hrnParamPri != null;
4216 HeapRegionNode hrnParamSec = null;
4217 if( paramIndex2idSecondary.containsKey(paramIndex) ) {
4218 Integer idParamSec = paramIndex2idSecondary.get(paramIndex);
4220 assert id2hrn.containsKey(idParamSec);
4221 hrnParamSec = id2hrn.get(idParamSec);
4222 assert hrnParamSec != null;
4226 assert id2hrn.containsKey( as.getSummary() );
4227 HeapRegionNode hrnSummary = id2hrn.get( as.getSummary() );
4228 assert hrnSummary != null;
4230 Set<HeapRegionNode> common = hasPotentialAlias( hrnParamPri, hrnSummary );
4232 if( hrnParamSec != null ) {
4233 common.addAll( hasPotentialAlias( hrnParamSec, hrnSummary ) );
4236 // check for other nodes
4237 for( int i = 0; i < as.getAllocationDepth(); ++i ) {
4239 assert id2hrn.containsKey( as.getIthOldest( i ) );
4240 HeapRegionNode hrnIthOldest = id2hrn.get( as.getIthOldest( i ) );
4241 assert hrnIthOldest != null;
4243 common = hasPotentialAlias( hrnParamPri, hrnIthOldest );
4245 if( hrnParamSec != null ) {
4246 common.addAll( hasPotentialAlias( hrnParamSec, hrnIthOldest ) );
4254 public Set<HeapRegionNode> hasPotentialAlias(AllocationSite as1, AllocationSite as2) {
4256 // get summary node 1's alpha
4257 Integer idSum1 = as1.getSummary();
4258 assert id2hrn.containsKey(idSum1);
4259 HeapRegionNode hrnSum1 = id2hrn.get(idSum1);
4260 assert hrnSum1 != null;
4262 // get summary node 2's alpha
4263 Integer idSum2 = as2.getSummary();
4264 assert id2hrn.containsKey(idSum2);
4265 HeapRegionNode hrnSum2 = id2hrn.get(idSum2);
4266 assert hrnSum2 != null;
4268 Set<HeapRegionNode> common = hasPotentialAlias( hrnSum1, hrnSum2 );
4270 // check sum2 against alloc1 nodes
4271 for( int i = 0; i < as1.getAllocationDepth(); ++i ) {
4272 Integer idI1 = as1.getIthOldest(i);
4273 assert id2hrn.containsKey(idI1);
4274 HeapRegionNode hrnI1 = id2hrn.get(idI1);
4275 assert hrnI1 != null;
4277 common.addAll( hasPotentialAlias( hrnI1, hrnSum2 ) );
4280 // check sum1 against alloc2 nodes
4281 for( int i = 0; i < as2.getAllocationDepth(); ++i ) {
4282 Integer idI2 = as2.getIthOldest(i);
4283 assert id2hrn.containsKey(idI2);
4284 HeapRegionNode hrnI2 = id2hrn.get(idI2);
4285 assert hrnI2 != null;
4287 common.addAll( hasPotentialAlias( hrnSum1, hrnI2 ) );
4289 // while we're at it, do an inner loop for alloc2 vs alloc1 nodes
4290 for( int j = 0; j < as1.getAllocationDepth(); ++j ) {
4291 Integer idI1 = as1.getIthOldest(j);
4293 // if these are the same site, don't look for the same token, no alias.
4294 // different tokens of the same site could alias together though
4295 if( idI1.equals( idI2 ) ) {
4299 HeapRegionNode hrnI1 = id2hrn.get(idI1);
4301 common.addAll( hasPotentialAlias( hrnI1, hrnI2 ) );
4309 public Set<HeapRegionNode> findCommonReachableNodes( HeapRegionNode hrn1,
4310 HeapRegionNode hrn2 ) {
4312 Set<HeapRegionNode> reachableNodes1 = new HashSet<HeapRegionNode>();
4313 Set<HeapRegionNode> reachableNodes2 = new HashSet<HeapRegionNode>();
4315 Set<HeapRegionNode> todoNodes1 = new HashSet<HeapRegionNode>();
4316 todoNodes1.add( hrn1 );
4318 Set<HeapRegionNode> todoNodes2 = new HashSet<HeapRegionNode>();
4319 todoNodes2.add( hrn2 );
4321 // follow links until all reachable nodes have been found
4322 while( !todoNodes1.isEmpty() ) {
4323 HeapRegionNode hrn = todoNodes1.iterator().next();
4324 todoNodes1.remove( hrn );
4325 reachableNodes1.add(hrn);
4327 Iterator<ReferenceEdge> edgeItr = hrn.iteratorToReferencees();
4328 while( edgeItr.hasNext() ) {
4329 ReferenceEdge edge = edgeItr.next();
4331 if( !reachableNodes1.contains( edge.getDst() ) ) {
4332 todoNodes1.add( edge.getDst() );
4337 while( !todoNodes2.isEmpty() ) {
4338 HeapRegionNode hrn = todoNodes2.iterator().next();
4339 todoNodes2.remove( hrn );
4340 reachableNodes2.add(hrn);
4342 Iterator<ReferenceEdge> edgeItr = hrn.iteratorToReferencees();
4343 while( edgeItr.hasNext() ) {
4344 ReferenceEdge edge = edgeItr.next();
4346 if( !reachableNodes2.contains( edge.getDst() ) ) {
4347 todoNodes2.add( edge.getDst() );
4352 Set<HeapRegionNode> intersection =
4353 new HashSet<HeapRegionNode>( reachableNodes1 );
4355 intersection.retainAll( reachableNodes2 );
4357 return intersection;
4361 // for writing ownership graphs to dot files
4362 public void writeGraph(MethodContext mc,
4364 boolean writeLabels,
4365 boolean labelSelect,
4366 boolean pruneGarbage,
4367 boolean writeReferencers,
4368 boolean writeParamMappings
4369 ) throws java.io.IOException {
4381 public void writeGraph(MethodContext mc,
4382 boolean writeLabels,
4383 boolean labelSelect,
4384 boolean pruneGarbage,
4385 boolean writeReferencers,
4386 boolean writeParamMappings
4387 ) throws java.io.IOException {
4389 writeGraph(mc+"COMPLETE",
4398 public void writeGraph(MethodContext mc,
4400 boolean writeLabels,
4401 boolean labelSelect,
4402 boolean pruneGarbage,
4403 boolean writeReferencers,
4404 boolean writeParamMappings
4405 ) throws java.io.IOException {
4409 writeGraph(mc+"COMPLETE"+String.format("%05d", numUpdate),
4418 public void writeGraph(String graphName,
4419 boolean writeLabels,
4420 boolean labelSelect,
4421 boolean pruneGarbage,
4422 boolean writeReferencers,
4423 boolean writeParamMappings
4424 ) throws java.io.IOException {
4426 // remove all non-word characters from the graph name so
4427 // the filename and identifier in dot don't cause errors
4428 graphName = graphName.replaceAll("[\\W]", "");
4430 BufferedWriter bw = new BufferedWriter(new FileWriter(graphName+".dot") );
4431 bw.write("digraph "+graphName+" {\n");
4433 HashSet<HeapRegionNode> visited = new HashSet<HeapRegionNode>();
4435 // then visit every heap region node
4436 Set s = id2hrn.entrySet();
4437 Iterator i = s.iterator();
4438 while( i.hasNext() ) {
4439 Map.Entry me = (Map.Entry)i.next();
4440 HeapRegionNode hrn = (HeapRegionNode) me.getValue();
4442 if( !pruneGarbage ||
4443 (hrn.isFlagged() && hrn.getID() > 0) ||
4444 hrn.getDescription().startsWith("param")
4447 if( !visited.contains(hrn) ) {
4448 traverseHeapRegionNodes(VISIT_HRN_WRITE_FULL,
4458 bw.write(" graphTitle[label=\""+graphName+"\",shape=box];\n");
4460 if( writeParamMappings ) {
4462 Set df = paramIndex2id.entrySet();
4463 Iterator ih = df.iterator();
4464 while( ih.hasNext() ) {
4465 Map.Entry meh = (Map.Entry)ih.next();
4466 Integer pi = (Integer) meh.getKey();
4467 Integer id = (Integer) meh.getValue();
4468 bw.write(" pindex"+pi+"[label=\""+pi+" to "+id+"\",shape=box];\n");
4473 // then visit every label node, useful for debugging
4475 s = td2ln.entrySet();
4477 while( i.hasNext() ) {
4478 Map.Entry me = (Map.Entry)i.next();
4479 LabelNode ln = (LabelNode) me.getValue();
4482 String labelStr = ln.getTempDescriptorString();
4483 if( labelStr.startsWith("___temp") ||
4484 labelStr.startsWith("___dst") ||
4485 labelStr.startsWith("___srctmp") ||
4486 labelStr.startsWith("___neverused") ||
4487 labelStr.contains(qString) ||
4488 labelStr.contains(rString) ||
4489 labelStr.contains(blobString)
4495 //bw.write(" "+ln.toString() + ";\n");
4497 Iterator<ReferenceEdge> heapRegionsItr = ln.iteratorToReferencees();
4498 while( heapRegionsItr.hasNext() ) {
4499 ReferenceEdge edge = heapRegionsItr.next();
4500 HeapRegionNode hrn = edge.getDst();
4502 if( pruneGarbage && !visited.contains(hrn) ) {
4503 traverseHeapRegionNodes(VISIT_HRN_WRITE_FULL,
4511 bw.write(" " + ln.toString() +
4512 " -> " + hrn.toString() +
4513 "[label=\"" + edge.toGraphEdgeString() +
4524 protected void traverseHeapRegionNodes(int mode,
4528 HashSet<HeapRegionNode> visited,
4529 boolean writeReferencers
4530 ) throws java.io.IOException {
4532 if( visited.contains(hrn) ) {
4538 case VISIT_HRN_WRITE_FULL:
4540 String attributes = "[";
4542 if( hrn.isSingleObject() ) {
4543 attributes += "shape=box";
4545 attributes += "shape=Msquare";
4548 if( hrn.isFlagged() ) {
4549 attributes += ",style=filled,fillcolor=lightgrey";
4552 attributes += ",label=\"ID" +
4556 if( hrn.getType() != null ) {
4557 attributes += hrn.getType().toPrettyString() + "\\n";
4560 attributes += hrn.getDescription() +
4562 hrn.getAlphaString() +
4565 bw.write(" " + hrn.toString() + attributes + ";\n");
4570 // useful for debugging
4573 if( writeReferencers ) {
4574 OwnershipNode onRef = null;
4575 Iterator refItr = hrn.iteratorToReferencers();
4576 while( refItr.hasNext() ) {
4577 onRef = (OwnershipNode) refItr.next();
4580 case VISIT_HRN_WRITE_FULL:
4581 bw.write(" " + hrn.toString() +
4582 " -> " + onRef.toString() +
4583 "[color=lightgray];\n");
4590 Iterator<ReferenceEdge> childRegionsItr = hrn.iteratorToReferencees();
4591 while( childRegionsItr.hasNext() ) {
4592 ReferenceEdge edge = childRegionsItr.next();
4593 HeapRegionNode hrnChild = edge.getDst();
4596 case VISIT_HRN_WRITE_FULL:
4597 bw.write(" " + hrn.toString() +
4598 " -> " + hrnChild.toString() +
4599 "[label=\"" + edge.toGraphEdgeString() +
4604 traverseHeapRegionNodes(mode,