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 String qString = new String( "Q_spec_" );
21 protected static String rString = new String( "R_spec_" );
22 protected static String blobString = new String( "_AliasBlob___" );
24 protected static TempDescriptor tdReturn = new TempDescriptor( "_Return___" );
25 protected static TempDescriptor tdAliasBlob = new TempDescriptor( blobString );
27 // add a bogus entry with the identity rule for easy rewrite
28 // of new callee nodes and edges, doesn't belong to any parameter
29 protected static final int bogusParamIndexInt = -2;
30 protected static final Integer bogusID = new Integer( bogusParamIndexInt );
31 protected static final Integer bogusIndex = new Integer( bogusParamIndexInt );
32 protected static final TokenTuple bogusToken = new TokenTuple( bogusID, true, TokenTuple.ARITY_ONE ).makeCanonical();
33 protected static final TokenTuple bogusTokenPlus = new TokenTuple( bogusID, true, TokenTuple.ARITY_ONEORMORE ).makeCanonical();
34 protected static final TokenTuple bogusTokenStar = new TokenTuple( bogusID, true, TokenTuple.ARITY_ZEROORMORE ).makeCanonical();
35 protected static final ReachabilitySet rsIdentity =
36 new ReachabilitySet( new TokenTupleSet( bogusToken ).makeCanonical() ).makeCanonical();
39 public Hashtable<Integer, HeapRegionNode> id2hrn;
40 public Hashtable<TempDescriptor, LabelNode > td2ln;
42 public Hashtable<Integer, Set<Integer> > idPrimary2paramIndexSet;
43 public Hashtable<Integer, Integer > paramIndex2idPrimary;
45 public Hashtable<Integer, Set<Integer> > idSecondary2paramIndexSet;
46 public Hashtable<Integer, Integer > paramIndex2idSecondary;
48 public Hashtable<Integer, TempDescriptor> paramIndex2tdQ;
49 public Hashtable<Integer, TempDescriptor> paramIndex2tdR;
52 public HashSet<AllocationSite> allocationSites;
55 public Hashtable<TokenTuple, Integer> paramTokenPrimary2paramIndex;
56 public Hashtable<Integer, TokenTuple> paramIndex2paramTokenPrimary;
57 public Hashtable<TokenTuple, Integer> paramTokenPrimaryPlus2paramIndex;
58 public Hashtable<Integer, TokenTuple> paramIndex2paramTokenPrimaryPlus;
59 public Hashtable<TokenTuple, Integer> paramTokenPrimaryStar2paramIndex;
60 public Hashtable<Integer, TokenTuple> paramIndex2paramTokenPrimaryStar;
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 >();
85 paramTokenPrimaryPlus2paramIndex = new Hashtable<TokenTuple, Integer >();
86 paramIndex2paramTokenPrimaryPlus = new Hashtable<Integer, TokenTuple >();
87 paramTokenPrimaryStar2paramIndex = new Hashtable<TokenTuple, Integer >();
88 paramIndex2paramTokenPrimaryStar = new Hashtable<Integer, TokenTuple >();
90 paramTokenSecondary2paramIndex = new Hashtable<TokenTuple, Integer >();
91 paramIndex2paramTokenSecondary = new Hashtable<Integer, TokenTuple >();
92 paramTokenSecondaryPlus2paramIndex = new Hashtable<TokenTuple, Integer >();
93 paramIndex2paramTokenSecondaryPlus = new Hashtable<Integer, TokenTuple >();
94 paramTokenSecondaryStar2paramIndex = new Hashtable<TokenTuple, Integer >();
95 paramIndex2paramTokenSecondaryStar = new Hashtable<Integer, TokenTuple >();
97 allocationSites = new HashSet <AllocationSite>();
101 // label nodes are much easier to deal with than
102 // heap region nodes. Whenever there is a request
103 // for the label node that is associated with a
104 // temp descriptor we can either find it or make a
105 // new one and return it. This is because temp
106 // descriptors are globally unique and every label
107 // node is mapped to exactly one temp descriptor.
108 protected LabelNode getLabelNodeFromTemp(TempDescriptor td) {
111 if( !td2ln.containsKey(td) ) {
112 td2ln.put(td, new LabelNode(td) );
115 return td2ln.get(td);
119 // the reason for this method is to have the option
120 // creating new heap regions with specific IDs, or
121 // duplicating heap regions with specific IDs (especially
122 // in the merge() operation) or to create new heap
123 // regions with a new unique ID.
124 protected HeapRegionNode
125 createNewHeapRegionNode(Integer id,
126 boolean isSingleObject,
127 boolean isNewSummary,
131 AllocationSite allocSite,
132 ReachabilitySet alpha,
133 String description) {
135 boolean markForAnalysis = isFlagged || isParameter;
137 TypeDescriptor typeToUse = null;
138 if( allocSite != null ) {
139 typeToUse = allocSite.getType();
144 if( allocSite != null && allocSite.getDisjointId() != null ) {
145 markForAnalysis = true;
149 id = OwnershipAnalysis.generateUniqueHeapRegionNodeID();
152 if( alpha == null ) {
153 if( markForAnalysis ) {
154 alpha = new ReachabilitySet(
161 alpha = new ReachabilitySet(
162 new TokenTupleSet().makeCanonical()
167 HeapRegionNode hrn = new HeapRegionNode(id,
182 ////////////////////////////////////////////////
184 // Low-level referencee and referencer methods
186 // These methods provide the lowest level for
187 // creating references between ownership nodes
188 // and handling the details of maintaining both
189 // list of referencers and referencees.
191 ////////////////////////////////////////////////
192 protected void addReferenceEdge(OwnershipNode referencer,
193 HeapRegionNode referencee,
194 ReferenceEdge edge) {
195 assert referencer != null;
196 assert referencee != null;
198 assert edge.getSrc() == referencer;
199 assert edge.getDst() == referencee;
201 referencer.addReferencee(edge);
202 referencee.addReferencer(edge);
205 protected void removeReferenceEdge(OwnershipNode referencer,
206 HeapRegionNode referencee,
209 assert referencer != null;
210 assert referencee != null;
212 ReferenceEdge edge = referencer.getReferenceTo(referencee,
216 assert edge == referencee.getReferenceFrom(referencer,
220 referencer.removeReferencee(edge);
221 referencee.removeReferencer(edge);
224 protected void clearReferenceEdgesFrom(OwnershipNode referencer,
228 assert referencer != null;
230 // get a copy of the set to iterate over, otherwise
231 // we will be trying to take apart the set as we
232 // are iterating over it, which won't work
233 Iterator<ReferenceEdge> i = referencer.iteratorToReferenceesClone();
234 while( i.hasNext() ) {
235 ReferenceEdge edge = i.next();
238 (type != null && edge.getType() .equals( type )) ||
239 (field != null && edge.getField().equals( field ))
242 HeapRegionNode referencee = edge.getDst();
244 removeReferenceEdge(referencer,
252 protected void clearReferenceEdgesTo(HeapRegionNode referencee,
256 assert referencee != null;
258 // get a copy of the set to iterate over, otherwise
259 // we will be trying to take apart the set as we
260 // are iterating over it, which won't work
261 Iterator<ReferenceEdge> i = referencee.iteratorToReferencersClone();
262 while( i.hasNext() ) {
263 ReferenceEdge edge = i.next();
266 (type != null && edge.getType() .equals( type )) ||
267 (field != null && edge.getField().equals( field ))
270 OwnershipNode referencer = edge.getSrc();
272 removeReferenceEdge(referencer,
281 ////////////////////////////////////////////////////
283 // Assignment Operation Methods
285 // These methods are high-level operations for
286 // modeling program assignment statements using
287 // the low-level reference create/remove methods
290 // The destination in an assignment statement is
291 // going to have new references. The method of
292 // determining the references depends on the type
293 // of the FlatNode assignment and the predicates
294 // of the nodes and edges involved.
296 ////////////////////////////////////////////////////
297 public void assignTempXEqualToTempY(TempDescriptor x,
300 LabelNode lnX = getLabelNodeFromTemp(x);
301 LabelNode lnY = getLabelNodeFromTemp(y);
303 clearReferenceEdgesFrom(lnX, null, null, true);
305 Iterator<ReferenceEdge> itrYhrn = lnY.iteratorToReferencees();
306 while( itrYhrn.hasNext() ) {
307 ReferenceEdge edgeY = itrYhrn.next();
308 HeapRegionNode referencee = edgeY.getDst();
309 ReferenceEdge edgeNew = edgeY.copy();
312 addReferenceEdge(lnX, referencee, edgeNew);
317 public void assignTypedTempXEqualToTempY(TempDescriptor x,
319 TypeDescriptor type) {
321 LabelNode lnX = getLabelNodeFromTemp(x);
322 LabelNode lnY = getLabelNodeFromTemp(y);
324 clearReferenceEdgesFrom(lnX, null, null, true);
326 Iterator<ReferenceEdge> itrYhrn = lnY.iteratorToReferencees();
327 while( itrYhrn.hasNext() ) {
328 ReferenceEdge edgeY = itrYhrn.next();
329 HeapRegionNode referencee = edgeY.getDst();
330 ReferenceEdge edgeNew = edgeY.copy();
331 edgeNew.setSrc( lnX );
332 edgeNew.setType( type );
333 edgeNew.setField( null );
335 addReferenceEdge(lnX, referencee, edgeNew);
340 public void assignTempXEqualToTempYFieldF(TempDescriptor x,
343 LabelNode lnX = getLabelNodeFromTemp(x);
344 LabelNode lnY = getLabelNodeFromTemp(y);
346 clearReferenceEdgesFrom(lnX, null, null, true);
348 Iterator<ReferenceEdge> itrYhrn = lnY.iteratorToReferencees();
349 while( itrYhrn.hasNext() ) {
350 ReferenceEdge edgeY = itrYhrn.next();
351 HeapRegionNode hrnY = edgeY.getDst();
352 ReachabilitySet betaY = edgeY.getBeta();
354 Iterator<ReferenceEdge> itrHrnFhrn = hrnY.iteratorToReferencees();
355 while( itrHrnFhrn.hasNext() ) {
356 ReferenceEdge edgeHrn = itrHrnFhrn.next();
357 HeapRegionNode hrnHrn = edgeHrn.getDst();
358 ReachabilitySet betaHrn = edgeHrn.getBeta();
360 if( edgeHrn.getType() == null ||
361 edgeHrn.getType().equals( f.getType() ) ) {
363 ReferenceEdge edgeNew = new ReferenceEdge(lnX,
368 betaY.intersection(betaHrn) );
370 addReferenceEdge(lnX, hrnHrn, edgeNew);
377 public void assignTempXFieldFEqualToTempY(TempDescriptor x,
380 LabelNode lnX = getLabelNodeFromTemp(x);
381 LabelNode lnY = getLabelNodeFromTemp(y);
383 HashSet<HeapRegionNode> nodesWithNewAlpha = new HashSet<HeapRegionNode>();
384 HashSet<ReferenceEdge> edgesWithNewBeta = new HashSet<ReferenceEdge>();
387 // first look for possible strong updates and remove those edges
388 boolean strongUpdate = false;
390 Iterator<ReferenceEdge> itrXhrn = lnX.iteratorToReferencees();
391 while( itrXhrn.hasNext() ) {
392 ReferenceEdge edgeX = itrXhrn.next();
393 HeapRegionNode hrnX = edgeX.getDst();
395 Iterator<ReferenceEdge> itrYhrn = lnY.iteratorToReferencees();
396 while( itrYhrn.hasNext() ) {
397 ReferenceEdge edgeY = itrYhrn.next();
398 HeapRegionNode hrnY = edgeY.getDst();
400 // we can do a strong update here if one of two cases holds
402 hrnX.isSingleObject() &&
403 ( (hrnX.getNumReferencers() == 1) ||
404 ( lnX.getNumReferencees() == 1)
408 clearReferenceEdgesFrom( hrnX, f.getType(), f.getSymbol(), false );
413 // then do all token propagation
414 itrXhrn = lnX.iteratorToReferencees();
415 while( itrXhrn.hasNext() ) {
416 ReferenceEdge edgeX = itrXhrn.next();
417 HeapRegionNode hrnX = edgeX.getDst();
418 ReachabilitySet betaX = edgeX.getBeta();
420 ReachabilitySet R = hrnX.getAlpha().intersection(edgeX.getBeta() );
422 Iterator<ReferenceEdge> itrYhrn = lnY.iteratorToReferencees();
423 while( itrYhrn.hasNext() ) {
424 ReferenceEdge edgeY = itrYhrn.next();
425 HeapRegionNode hrnY = edgeY.getDst();
426 ReachabilitySet O = edgeY.getBeta();
429 // propagate tokens over nodes starting from hrnSrc, and it will
430 // take care of propagating back up edges from any touched nodes
431 ChangeTupleSet Cy = O.unionUpArityToChangeSet(R);
432 propagateTokensOverNodes(hrnY, Cy, nodesWithNewAlpha, edgesWithNewBeta);
435 // then propagate back just up the edges from hrn
436 ChangeTupleSet Cx = R.unionUpArityToChangeSet(O);
439 HashSet<ReferenceEdge> todoEdges = new HashSet<ReferenceEdge>();
441 Hashtable<ReferenceEdge, ChangeTupleSet> edgePlannedChanges =
442 new Hashtable<ReferenceEdge, ChangeTupleSet>();
444 Iterator<ReferenceEdge> referItr = hrnX.iteratorToReferencers();
445 while( referItr.hasNext() ) {
446 ReferenceEdge edgeUpstream = referItr.next();
447 todoEdges.add(edgeUpstream);
448 edgePlannedChanges.put(edgeUpstream, Cx);
451 propagateTokensOverEdges(todoEdges,
458 // apply the updates to reachability
459 Iterator<HeapRegionNode> nodeItr = nodesWithNewAlpha.iterator();
460 while( nodeItr.hasNext() ) {
461 nodeItr.next().applyAlphaNew();
464 Iterator<ReferenceEdge> edgeItr = edgesWithNewBeta.iterator();
465 while( edgeItr.hasNext() ) {
466 edgeItr.next().applyBetaNew();
469 // then go back through and add the new edges
470 itrXhrn = lnX.iteratorToReferencees();
471 while( itrXhrn.hasNext() ) {
472 ReferenceEdge edgeX = itrXhrn.next();
473 HeapRegionNode hrnX = edgeX.getDst();
475 Iterator<ReferenceEdge> itrYhrn = lnY.iteratorToReferencees();
476 while( itrYhrn.hasNext() ) {
477 ReferenceEdge edgeY = itrYhrn.next();
478 HeapRegionNode hrnY = edgeY.getDst();
480 // prepare the new reference edge hrnX.f -> hrnY
481 ReferenceEdge edgeNew = new ReferenceEdge(hrnX,
486 edgeY.getBeta().pruneBy( hrnX.getAlpha() )
489 // look to see if an edge with same field exists
490 // and merge with it, otherwise just add the edge
491 ReferenceEdge edgeExisting = hrnX.getReferenceTo( hrnY,
495 if( edgeExisting != null ) {
496 edgeExisting.setBeta(
497 edgeExisting.getBeta().union( edgeNew.getBeta() )
499 // a new edge here cannot be reflexive, so existing will
500 // always be also not reflexive anymore
501 edgeExisting.setIsInitialParam( false );
503 addReferenceEdge( hrnX, hrnY, edgeNew );
508 // if there was a strong update, make sure to improve
509 // reachability with a global sweep
516 // the parameter model is to use a single-object heap region
517 // for the primary parameter, and a multiple-object heap
518 // region for the secondary objects reachable through the
519 // primary object, if necessary
520 public void assignTempEqualToParamAlloc( TempDescriptor td,
522 Integer paramIndex ) {
525 TypeDescriptor typeParam = td.getType();
526 assert typeParam != null;
528 // either the parameter is an array or a class to be in this method
529 assert typeParam.isArray() || typeParam.isClass();
531 // discover some info from the param type and use it below
532 // to get parameter model as precise as we can
533 boolean createSecondaryRegion = false;
534 Set<FieldDescriptor> primary2primaryFields = new HashSet<FieldDescriptor>();
535 Set<FieldDescriptor> primary2secondaryFields = new HashSet<FieldDescriptor>();
537 // there might be an element reference for array types
538 if( typeParam.isArray() ) {
539 // only bother with this if the dereferenced type can
540 // affect reachability
541 TypeDescriptor typeDeref = typeParam.dereference();
542 if( !typeDeref.isImmutable() || typeDeref.isArray() ) {
543 primary2secondaryFields.add(
544 OwnershipAnalysis.getArrayField( typeDeref )
546 createSecondaryRegion = true;
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 );
605 TokenTuple ttPrimary = new TokenTuple( newPrimaryID,
606 false, // multi-object
607 TokenTuple.ARITY_ONE ).makeCanonical();
609 HeapRegionNode hrnSecondary = null;
610 Integer newSecondaryID = null;
611 TokenTuple ttSecondary = null;
612 TempDescriptor tdParamR = null;
613 LabelNode lnParamR = null;
615 if( createSecondaryRegion ) {
616 tdParamR = new TempDescriptor( td+rString );
617 paramIndex2tdR.put( paramIndex, tdParamR );
618 lnParamR = getLabelNodeFromTemp( tdParamR );
620 hrnSecondary = createNewHeapRegionNode( null, // id or null to generate a new one
621 false, // single object?
624 true, // is a parameter?
626 null, // allocation site
627 null, // reachability set
628 "param"+paramIndex+" reachable" );
630 newSecondaryID = hrnSecondary.getID();
631 assert !idSecondary2paramIndexSet.containsKey( newSecondaryID );
632 Set<Integer> s2 = new HashSet<Integer>();
633 s2.add( paramIndex );
634 idSecondary2paramIndexSet.put( newSecondaryID, s2 );
635 paramIndex2idSecondary.put( paramIndex, newSecondaryID );
637 ttSecondary = new TokenTuple( newSecondaryID,
638 true, // multi-object
639 TokenTuple.ARITY_ONE ).makeCanonical();
642 // use a beta that has everything and put it all over the
643 // parameter model, then use a global sweep later to fix
644 // it up, since parameters can have different shapes
645 TokenTupleSet tts0 = new TokenTupleSet( ttPrimary ).makeCanonical();
646 ReachabilitySet betaSoup;
647 if( createSecondaryRegion ) {
648 TokenTupleSet tts1 = new TokenTupleSet( ttSecondary ).makeCanonical();
649 TokenTupleSet tts2 = new TokenTupleSet( ttPrimary ).union( ttSecondary );
650 betaSoup = new ReachabilitySet().union( tts0 ).union( tts1 ).union( tts2 );
652 betaSoup = new ReachabilitySet().union( tts0 );
655 ReferenceEdge edgeFromLabel =
656 new ReferenceEdge( lnParam, // src
660 false, // special param initial (not needed on label->node)
661 betaSoup ); // reachability
662 addReferenceEdge( lnParam, hrnPrimary, edgeFromLabel );
664 ReferenceEdge edgeFromLabelQ =
665 new ReferenceEdge( lnParamQ, // src
669 false, // special param initial (not needed on label->node)
670 betaSoup ); // reachability
671 addReferenceEdge( lnParamQ, hrnPrimary, edgeFromLabelQ );
673 ReferenceEdge edgeSecondaryReflexive;
674 if( createSecondaryRegion ) {
675 edgeSecondaryReflexive =
676 new ReferenceEdge( hrnSecondary, // src
678 null, // match all types
679 null, // match all fields
680 true, // special param initial
681 betaSoup ); // reachability
682 addReferenceEdge( hrnSecondary, hrnSecondary, edgeSecondaryReflexive );
684 ReferenceEdge edgeSecondary2Primary =
685 new ReferenceEdge( hrnSecondary, // src
687 null, // match all types
688 null, // match all fields
689 true, // special param initial
690 betaSoup ); // reachability
691 addReferenceEdge( hrnSecondary, hrnPrimary, edgeSecondary2Primary );
693 ReferenceEdge edgeFromLabelR =
694 new ReferenceEdge( lnParamR, // src
698 false, // special param initial (not needed on label->node)
699 betaSoup ); // reachability
700 addReferenceEdge( lnParamR, hrnSecondary, edgeFromLabelR );
703 Iterator<FieldDescriptor> fieldItr = primary2primaryFields.iterator();
704 while( fieldItr.hasNext() ) {
705 FieldDescriptor fd = fieldItr.next();
707 ReferenceEdge edgePrimaryReflexive =
708 new ReferenceEdge( hrnPrimary, // src
710 fd.getType(), // type
711 fd.getSymbol(), // field
712 true, // special param initial
713 betaSoup ); // reachability
714 addReferenceEdge( hrnPrimary, hrnPrimary, edgePrimaryReflexive );
717 fieldItr = primary2secondaryFields.iterator();
718 while( fieldItr.hasNext() ) {
719 FieldDescriptor fd = fieldItr.next();
721 ReferenceEdge edgePrimary2Secondary =
722 new ReferenceEdge( hrnPrimary, // src
724 fd.getType(), // type
725 fd.getSymbol(), // field
726 true, // special param initial
727 betaSoup ); // reachability
728 addReferenceEdge( hrnPrimary, hrnSecondary, edgePrimary2Secondary );
733 public void makeAliasedParamHeapRegionNode() {
735 LabelNode lnBlob = getLabelNodeFromTemp( tdAliasBlob );
736 HeapRegionNode hrn = createNewHeapRegionNode( null, // id or null to generate a new one
737 false, // single object?
740 true, // is a parameter?
742 null, // allocation site
743 null, // reachability set
746 ReachabilitySet beta = new ReachabilitySet( new TokenTuple( hrn.getID(),
748 TokenTuple.ARITY_ONE).makeCanonical()
751 ReferenceEdge edgeFromLabel =
752 new ReferenceEdge( lnBlob, hrn, null, null, false, beta );
754 ReferenceEdge edgeReflexive =
755 new ReferenceEdge( hrn, hrn, null, null, true, beta );
757 addReferenceEdge( lnBlob, hrn, edgeFromLabel );
758 addReferenceEdge( hrn, hrn, edgeReflexive );
762 public void assignTempEqualToAliasedParam( TempDescriptor tdParam,
763 Integer paramIndex ) {
764 assert tdParam != null;
766 TypeDescriptor typeParam = tdParam.getType();
767 assert typeParam != null;
769 LabelNode lnParam = getLabelNodeFromTemp( tdParam );
770 LabelNode lnAliased = getLabelNodeFromTemp( tdAliasBlob );
772 // this is a non-program-accessible label that picks up beta
773 // info to be used for fixing a caller of this method
774 TempDescriptor tdParamQ = new TempDescriptor( tdParam+qString );
775 TempDescriptor tdParamR = new TempDescriptor( tdParam+rString );
777 paramIndex2tdQ.put( paramIndex, tdParamQ );
778 paramIndex2tdR.put( paramIndex, tdParamR );
780 LabelNode lnParamQ = getLabelNodeFromTemp( tdParamQ );
781 LabelNode lnParamR = getLabelNodeFromTemp( tdParamR );
783 // the lnAliased should always only reference one node, and that
784 // heap region node is the aliased param blob
785 assert lnAliased.getNumReferencees() == 1;
786 HeapRegionNode hrnAliasBlob = lnAliased.iteratorToReferencees().next().getDst();
787 Integer idAliased = hrnAliasBlob.getID();
789 TokenTuple ttAliased = new TokenTuple( idAliased,
790 true, // multi-object
791 TokenTuple.ARITY_ONE ).makeCanonical();
793 HeapRegionNode hrnPrimary = createNewHeapRegionNode( null, // id or null to generate a new one
794 true, // single object?
797 true, // is a parameter?
799 null, // allocation site
800 null, // reachability set
801 "param"+paramIndex+" obj" );
803 Integer newPrimaryID = hrnPrimary.getID();
804 assert !idPrimary2paramIndexSet.containsKey( newPrimaryID );
805 Set<Integer> s1 = new HashSet<Integer>();
806 s1.add( paramIndex );
807 idPrimary2paramIndexSet.put( newPrimaryID, s1 );
808 paramIndex2idPrimary.put( paramIndex, newPrimaryID );
810 Set<Integer> s2 = idSecondary2paramIndexSet.get( idAliased );
812 s2 = new HashSet<Integer>();
814 s2.add( paramIndex );
815 idSecondary2paramIndexSet.put( idAliased, s2 );
816 paramIndex2idSecondary.put( paramIndex, idAliased );
819 TokenTuple ttPrimary = new TokenTuple( newPrimaryID,
820 false, // multi-object
821 TokenTuple.ARITY_ONE ).makeCanonical();
823 TokenTupleSet tts0 = new TokenTupleSet( ttPrimary ).makeCanonical();
824 TokenTupleSet tts1 = new TokenTupleSet( ttAliased ).makeCanonical();
825 TokenTupleSet tts2 = new TokenTupleSet( ttPrimary ).union( ttAliased );
826 ReachabilitySet betaSoup = new ReachabilitySet().union( tts0 ).union( tts1 ).union( tts2 );
829 ReferenceEdge edgeFromLabel =
830 new ReferenceEdge( lnParam, // src
834 false, // special param initial (not needed on label->node)
835 betaSoup ); // reachability
836 addReferenceEdge( lnParam, hrnPrimary, edgeFromLabel );
838 ReferenceEdge edgeFromLabelQ =
839 new ReferenceEdge( lnParamQ, // src
843 false, // special param initial (not needed on label->node)
844 betaSoup ); // reachability
845 addReferenceEdge( lnParamQ, hrnPrimary, edgeFromLabelQ );
847 ReferenceEdge edgeAliased2Primary =
848 new ReferenceEdge( hrnAliasBlob, // src
850 null, // match all types
851 null, // match all fields
852 true, // special param initial
853 betaSoup ); // reachability
854 addReferenceEdge( hrnAliasBlob, hrnPrimary, edgeAliased2Primary );
856 ReferenceEdge edgeFromLabelR =
857 new ReferenceEdge( lnParamR, // src
861 false, // special param initial (not needed on label->node)
862 betaSoup ); // reachability
863 addReferenceEdge( lnParamR, hrnAliasBlob, edgeFromLabelR );
867 public void addParam2ParamAliasEdges( FlatMethod fm,
868 Set<Integer> aliasedParamIndices ) {
870 LabelNode lnAliased = getLabelNodeFromTemp( tdAliasBlob );
872 // the lnAliased should always only reference one node, and that
873 // heap region node is the aliased param blob
874 assert lnAliased.getNumReferencees() == 1;
875 HeapRegionNode hrnAliasBlob = lnAliased.iteratorToReferencees().next().getDst();
876 Integer idAliased = hrnAliasBlob.getID();
877 TokenTuple ttAliased = new TokenTuple( idAliased,
878 true, // multi-object
879 TokenTuple.ARITY_ONE ).makeCanonical();
882 Iterator<Integer> apItrI = aliasedParamIndices.iterator();
883 while( apItrI.hasNext() ) {
884 Integer i = apItrI.next();
885 TempDescriptor tdParamI = fm.getParameter( i );
886 TypeDescriptor typeI = tdParamI.getType();
887 LabelNode lnParamI = getLabelNodeFromTemp( tdParamI );
889 Integer idPrimaryI = paramIndex2idPrimary.get( i );
890 assert idPrimaryI != null;
891 HeapRegionNode primaryI = id2hrn.get( idPrimaryI );
892 assert primaryI != null;
894 TokenTuple ttPrimaryI = new TokenTuple( idPrimaryI,
895 false, // multi-object
896 TokenTuple.ARITY_ONE ).makeCanonical();
898 TokenTupleSet ttsI = new TokenTupleSet( ttPrimaryI ).makeCanonical();
899 TokenTupleSet ttsA = new TokenTupleSet( ttAliased ).makeCanonical();
900 TokenTupleSet ttsIA = new TokenTupleSet( ttPrimaryI ).union( ttAliased );
901 ReachabilitySet betaSoup = new ReachabilitySet().union( ttsI ).union( ttsA ).union( ttsIA );
904 // calculate whether fields of this aliased parameter are able to
905 // reference its own primary object, the blob, or other parameter's
907 Set<FieldDescriptor> primary2primaryFields = new HashSet<FieldDescriptor>();
908 Set<FieldDescriptor> primary2secondaryFields = new HashSet<FieldDescriptor>();
910 // there might be an element reference for array types
911 if( typeI.isArray() ) {
912 // only bother with this if the dereferenced type can
913 // affect reachability
914 TypeDescriptor typeDeref = typeI.dereference();
916 // for this parameter to be aliased the following must be true
917 assert !typeDeref.isImmutable() || typeDeref.isArray();
919 primary2secondaryFields.add(
920 OwnershipAnalysis.getArrayField( typeDeref )
924 // there might be member references for class types
925 if( typeI.isClass() ) {
926 ClassDescriptor cd = typeI.getClassDesc();
927 while( cd != null ) {
929 Iterator fieldItr = cd.getFields();
930 while( fieldItr.hasNext() ) {
932 FieldDescriptor fd = (FieldDescriptor) fieldItr.next();
933 TypeDescriptor typeField = fd.getType();
934 assert typeField != null;
936 if( !typeField.isImmutable() || typeField.isArray() ) {
937 primary2secondaryFields.add( fd );
940 if( typeUtil.isSuperorType( typeField, typeI ) ) {
941 primary2primaryFields.add( fd );
945 cd = cd.getSuperDesc();
949 // there must be at least one edge into the blob
950 assert primary2secondaryFields.size() > 0;
952 Iterator<FieldDescriptor> fieldItr = primary2primaryFields.iterator();
953 while( fieldItr.hasNext() ) {
954 FieldDescriptor fd = fieldItr.next();
956 ReferenceEdge edgePrimaryReflexive =
957 new ReferenceEdge( primaryI, // src
959 fd.getType(), // type
960 fd.getSymbol(), // field
961 true, // special param initial
962 betaSoup ); // reachability
963 addReferenceEdge( primaryI, primaryI, edgePrimaryReflexive );
966 fieldItr = primary2secondaryFields.iterator();
967 while( fieldItr.hasNext() ) {
968 FieldDescriptor fd = fieldItr.next();
969 TypeDescriptor typeField = fd.getType();
970 assert typeField != null;
972 ReferenceEdge edgePrimary2Secondary =
973 new ReferenceEdge( primaryI, // src
975 fd.getType(), // type
976 fd.getSymbol(), // field
977 true, // special param initial
978 betaSoup ); // reachability
979 addReferenceEdge( primaryI, hrnAliasBlob, edgePrimary2Secondary );
981 // ask whether these fields might match any of the other aliased
982 // parameters and make those edges too
983 Iterator<Integer> apItrJ = aliasedParamIndices.iterator();
984 while( apItrJ.hasNext() ) {
985 Integer j = apItrJ.next();
986 TempDescriptor tdParamJ = fm.getParameter( j );
987 TypeDescriptor typeJ = tdParamJ.getType();
989 if( !i.equals( j ) && typeUtil.isSuperorType( typeField, typeJ ) ) {
991 Integer idPrimaryJ = paramIndex2idPrimary.get( j );
992 assert idPrimaryJ != null;
993 HeapRegionNode primaryJ = id2hrn.get( idPrimaryJ );
994 assert primaryJ != null;
996 TokenTuple ttPrimaryJ = new TokenTuple( idPrimaryJ,
997 false, // multi-object
998 TokenTuple.ARITY_ONE ).makeCanonical();
1000 TokenTupleSet ttsJ = new TokenTupleSet( ttPrimaryJ ).makeCanonical();
1001 TokenTupleSet ttsIJ = ttsI.union( ttsJ );
1002 TokenTupleSet ttsAJ = ttsA.union( ttsJ );
1003 TokenTupleSet ttsIAJ = ttsIA.union( ttsJ );
1004 ReachabilitySet betaSoupWJ = new ReachabilitySet().union( ttsJ ).union( ttsIJ ).union( ttsAJ ).union( ttsIAJ );
1006 ReferenceEdge edgePrimaryI2PrimaryJ =
1007 new ReferenceEdge( primaryI, // src
1009 fd.getType(), // type
1010 fd.getSymbol(), // field
1011 true, // special param initial
1012 betaSoupWJ ); // reachability
1013 addReferenceEdge( primaryI, primaryJ, edgePrimaryI2PrimaryJ );
1019 // look at whether aliased parameters i and j can
1020 // possibly be the same primary object, add edges
1021 Iterator<Integer> apItrJ = aliasedParamIndices.iterator();
1022 while( apItrJ.hasNext() ) {
1023 Integer j = apItrJ.next();
1024 TempDescriptor tdParamJ = fm.getParameter( j );
1025 TypeDescriptor typeJ = tdParamJ.getType();
1026 LabelNode lnParamJ = getLabelNodeFromTemp( tdParamJ );
1028 if( !i.equals( j ) && typeUtil.isSuperorType( typeI, typeJ ) ) {
1030 Integer idPrimaryJ = paramIndex2idPrimary.get( j );
1031 assert idPrimaryJ != null;
1032 HeapRegionNode primaryJ = id2hrn.get( idPrimaryJ );
1033 assert primaryJ != null;
1035 ReferenceEdge lnJ2PrimaryJ = lnParamJ.getReferenceTo( primaryJ,
1038 assert lnJ2PrimaryJ != null;
1040 ReferenceEdge lnI2PrimaryJ = lnJ2PrimaryJ.copy();
1041 lnI2PrimaryJ.setSrc( lnParamI );
1042 lnI2PrimaryJ.setType( tdParamI.getType() );
1043 addReferenceEdge( lnParamI, primaryJ, lnI2PrimaryJ );
1049 public void prepareParamTokenMaps( FlatMethod fm ) {
1051 // always add the bogus mappings that are used to
1052 // rewrite "with respect to no parameter"
1053 paramTokenPrimary2paramIndex.put( bogusToken, bogusIndex );
1054 paramIndex2paramTokenPrimary.put( bogusIndex, bogusToken );
1055 paramTokenPrimaryPlus2paramIndex.put( bogusTokenPlus, bogusIndex );
1056 paramIndex2paramTokenPrimaryPlus.put( bogusIndex, bogusTokenPlus );
1057 paramTokenPrimaryStar2paramIndex.put( bogusTokenStar, bogusIndex );
1058 paramIndex2paramTokenPrimaryStar.put( bogusIndex, bogusTokenStar );
1060 paramTokenSecondary2paramIndex.put( bogusToken, bogusIndex );
1061 paramIndex2paramTokenSecondary.put( bogusIndex, bogusToken );
1062 paramTokenSecondaryPlus2paramIndex.put( bogusTokenPlus, bogusIndex );
1063 paramIndex2paramTokenSecondaryPlus.put( bogusIndex, bogusTokenPlus );
1064 paramTokenSecondaryStar2paramIndex.put( bogusTokenStar, bogusIndex );
1065 paramIndex2paramTokenSecondaryStar.put( bogusIndex, bogusTokenStar );
1067 for( int i = 0; i < fm.numParameters(); ++i ) {
1068 Integer paramIndex = new Integer( i );
1070 // immutable objects have no primary regions
1071 if( paramIndex2idPrimary.containsKey( paramIndex ) ) {
1072 Integer idPrimary = paramIndex2idPrimary.get( paramIndex );
1074 assert id2hrn.containsKey( idPrimary );
1075 HeapRegionNode hrnPrimary = id2hrn.get( idPrimary );
1077 TokenTuple p_i = new TokenTuple( hrnPrimary.getID(),
1078 false, // multiple-object?
1079 TokenTuple.ARITY_ONE ).makeCanonical();
1080 paramTokenPrimary2paramIndex.put( p_i, paramIndex );
1081 paramIndex2paramTokenPrimary.put( paramIndex, p_i );
1083 TokenTuple p_i_plus = new TokenTuple( hrnPrimary.getID(),
1084 false, // multiple-object?
1085 TokenTuple.ARITY_ONEORMORE ).makeCanonical();
1086 paramTokenPrimaryPlus2paramIndex.put( p_i_plus, paramIndex );
1087 paramIndex2paramTokenPrimaryPlus.put( paramIndex, p_i_plus );
1089 TokenTuple p_i_star = new TokenTuple( hrnPrimary.getID(),
1090 false, // multiple-object?
1091 TokenTuple.ARITY_ZEROORMORE ).makeCanonical();
1092 paramTokenPrimaryStar2paramIndex.put( p_i_star, paramIndex );
1093 paramIndex2paramTokenPrimaryStar.put( paramIndex, p_i_star );
1096 // any parameter object, by type, may have no secondary region
1097 if( paramIndex2idSecondary.containsKey( paramIndex ) ) {
1098 Integer idSecondary = paramIndex2idSecondary.get( paramIndex );
1100 assert id2hrn.containsKey( idSecondary );
1101 HeapRegionNode hrnSecondary = id2hrn.get( idSecondary );
1103 TokenTuple r_i = new TokenTuple( hrnSecondary.getID(),
1104 true, // multiple-object?
1105 TokenTuple.ARITY_ONE ).makeCanonical();
1106 paramTokenSecondary2paramIndex.put( r_i, paramIndex );
1107 paramIndex2paramTokenSecondary.put( paramIndex, r_i );
1109 TokenTuple r_i_plus = new TokenTuple( hrnSecondary.getID(),
1110 true, // multiple-object?
1111 TokenTuple.ARITY_ONEORMORE ).makeCanonical();
1112 paramTokenSecondaryPlus2paramIndex.put( r_i_plus, paramIndex );
1113 paramIndex2paramTokenSecondaryPlus.put( paramIndex, r_i_plus );
1115 TokenTuple r_i_star = new TokenTuple( hrnSecondary.getID(),
1116 true, // multiple-object?
1117 TokenTuple.ARITY_ZEROORMORE ).makeCanonical();
1118 paramTokenSecondaryStar2paramIndex.put( r_i_star, paramIndex );
1119 paramIndex2paramTokenSecondaryStar.put( paramIndex, r_i_star );
1126 public void assignReturnEqualToTemp(TempDescriptor x) {
1128 LabelNode lnR = getLabelNodeFromTemp(tdReturn);
1129 LabelNode lnX = getLabelNodeFromTemp(x);
1131 clearReferenceEdgesFrom(lnR, null, null, true);
1133 Iterator<ReferenceEdge> itrXhrn = lnX.iteratorToReferencees();
1134 while( itrXhrn.hasNext() ) {
1135 ReferenceEdge edgeX = itrXhrn.next();
1136 HeapRegionNode referencee = edgeX.getDst();
1137 ReferenceEdge edgeNew = edgeX.copy();
1138 edgeNew.setSrc(lnR);
1140 addReferenceEdge(lnR, referencee, edgeNew);
1145 public void assignTempEqualToNewAlloc(TempDescriptor x,
1146 AllocationSite as) {
1152 // after the age operation the newest (or zero-ith oldest)
1153 // node associated with the allocation site should have
1154 // no references to it as if it were a newly allocated
1155 // heap region, so make a reference to it to complete
1158 Integer idNewest = as.getIthOldest(0);
1159 HeapRegionNode hrnNewest = id2hrn.get(idNewest);
1160 assert hrnNewest != null;
1162 LabelNode lnX = getLabelNodeFromTemp(x);
1163 clearReferenceEdgesFrom(lnX, null, null, true);
1165 ReferenceEdge edgeNew =
1166 new ReferenceEdge(lnX, hrnNewest, null, null, false, hrnNewest.getAlpha() );
1168 addReferenceEdge(lnX, hrnNewest, edgeNew);
1172 // use the allocation site (unique to entire analysis) to
1173 // locate the heap region nodes in this ownership graph
1174 // that should be aged. The process models the allocation
1175 // of new objects and collects all the oldest allocations
1176 // in a summary node to allow for a finite analysis
1178 // There is an additional property of this method. After
1179 // running it on a particular ownership graph (many graphs
1180 // may have heap regions related to the same allocation site)
1181 // the heap region node objects in this ownership graph will be
1182 // allocated. Therefore, after aging a graph for an allocation
1183 // site, attempts to retrieve the heap region nodes using the
1184 // integer id's contained in the allocation site should always
1185 // return non-null heap regions.
1186 public void age(AllocationSite as) {
1188 // aging adds this allocation site to the graph's
1189 // list of sites that exist in the graph, or does
1190 // nothing if the site is already in the list
1191 allocationSites.add(as);
1193 // get the summary node for the allocation site in the context
1194 // of this particular ownership graph
1195 HeapRegionNode hrnSummary = getSummaryNode(as);
1197 // merge oldest node into summary
1198 Integer idK = as.getOldest();
1199 HeapRegionNode hrnK = id2hrn.get(idK);
1200 mergeIntoSummary(hrnK, hrnSummary);
1202 // move down the line of heap region nodes
1203 // clobbering the ith and transferring all references
1204 // to and from i-1 to node i. Note that this clobbers
1205 // the oldest node (hrnK) that was just merged into
1207 for( int i = allocationDepth - 1; i > 0; --i ) {
1209 // move references from the i-1 oldest to the ith oldest
1210 Integer idIth = as.getIthOldest(i);
1211 HeapRegionNode hrnI = id2hrn.get(idIth);
1212 Integer idImin1th = as.getIthOldest(i - 1);
1213 HeapRegionNode hrnImin1 = id2hrn.get(idImin1th);
1215 transferOnto(hrnImin1, hrnI);
1218 // as stated above, the newest node should have had its
1219 // references moved over to the second oldest, so we wipe newest
1220 // in preparation for being the new object to assign something to
1221 Integer id0th = as.getIthOldest(0);
1222 HeapRegionNode hrn0 = id2hrn.get(id0th);
1223 assert hrn0 != null;
1225 // clear all references in and out of newest node
1226 clearReferenceEdgesFrom(hrn0, null, null, true);
1227 clearReferenceEdgesTo(hrn0, null, null, true);
1230 // now tokens in reachability sets need to "age" also
1231 Iterator itrAllLabelNodes = td2ln.entrySet().iterator();
1232 while( itrAllLabelNodes.hasNext() ) {
1233 Map.Entry me = (Map.Entry)itrAllLabelNodes.next();
1234 LabelNode ln = (LabelNode) me.getValue();
1236 Iterator<ReferenceEdge> itrEdges = ln.iteratorToReferencees();
1237 while( itrEdges.hasNext() ) {
1238 ageTokens(as, itrEdges.next() );
1242 Iterator itrAllHRNodes = id2hrn.entrySet().iterator();
1243 while( itrAllHRNodes.hasNext() ) {
1244 Map.Entry me = (Map.Entry)itrAllHRNodes.next();
1245 HeapRegionNode hrnToAge = (HeapRegionNode) me.getValue();
1247 ageTokens(as, hrnToAge);
1249 Iterator<ReferenceEdge> itrEdges = hrnToAge.iteratorToReferencees();
1250 while( itrEdges.hasNext() ) {
1251 ageTokens(as, itrEdges.next() );
1256 // after tokens have been aged, reset newest node's reachability
1257 if( hrn0.isFlagged() ) {
1258 hrn0.setAlpha(new ReachabilitySet(
1260 new TokenTuple(hrn0).makeCanonical()
1265 hrn0.setAlpha(new ReachabilitySet(
1266 new TokenTupleSet().makeCanonical()
1273 protected HeapRegionNode getSummaryNode(AllocationSite as) {
1275 Integer idSummary = as.getSummary();
1276 HeapRegionNode hrnSummary = id2hrn.get(idSummary);
1278 // If this is null then we haven't touched this allocation site
1279 // in the context of the current ownership graph, so allocate
1280 // heap region nodes appropriate for the entire allocation site.
1281 // This should only happen once per ownership graph per allocation site,
1282 // and a particular integer id can be used to locate the heap region
1283 // in different ownership graphs that represents the same part of an
1285 if( hrnSummary == null ) {
1287 boolean hasFlags = false;
1288 if( as.getType().isClass() ) {
1289 hasFlags = as.getType().getClassDesc().hasFlags();
1292 hrnSummary = createNewHeapRegionNode(idSummary, // id or null to generate a new one
1293 false, // single object?
1295 hasFlags, // flagged?
1296 false, // is a parameter?
1297 as.getType(), // type
1298 as, // allocation site
1299 null, // reachability set
1300 as.toStringForDOT() + "\\nsummary");
1302 for( int i = 0; i < as.getAllocationDepth(); ++i ) {
1303 Integer idIth = as.getIthOldest(i);
1304 assert !id2hrn.containsKey(idIth);
1305 createNewHeapRegionNode(idIth, // id or null to generate a new one
1306 true, // single object?
1308 hasFlags, // flagged?
1309 false, // is a parameter?
1310 as.getType(), // type
1311 as, // allocation site
1312 null, // reachability set
1313 as.toStringForDOT() + "\\n" + i + " oldest");
1321 protected HeapRegionNode getShadowSummaryNode(AllocationSite as) {
1323 Integer idShadowSummary = as.getSummaryShadow();
1324 HeapRegionNode hrnShadowSummary = id2hrn.get(idShadowSummary);
1326 if( hrnShadowSummary == null ) {
1328 boolean hasFlags = false;
1329 if( as.getType().isClass() ) {
1330 hasFlags = as.getType().getClassDesc().hasFlags();
1333 hrnShadowSummary = createNewHeapRegionNode(idShadowSummary, // id or null to generate a new one
1334 false, // single object?
1336 hasFlags, // flagged?
1337 false, // is a parameter?
1338 as.getType(), // type
1339 as, // allocation site
1340 null, // reachability set
1341 as + "\\n" + as.getType() + "\\nshadowSum");
1343 for( int i = 0; i < as.getAllocationDepth(); ++i ) {
1344 Integer idShadowIth = as.getIthOldestShadow(i);
1345 assert !id2hrn.containsKey(idShadowIth);
1346 createNewHeapRegionNode(idShadowIth, // id or null to generate a new one
1347 true, // single object?
1349 hasFlags, // flagged?
1350 false, // is a parameter?
1351 as.getType(), // type
1352 as, // allocation site
1353 null, // reachability set
1354 as + "\\n" + as.getType() + "\\n" + i + " shadow");
1358 return hrnShadowSummary;
1362 protected void mergeIntoSummary(HeapRegionNode hrn, HeapRegionNode hrnSummary) {
1363 assert hrnSummary.isNewSummary();
1365 // transfer references _from_ hrn over to hrnSummary
1366 Iterator<ReferenceEdge> itrReferencee = hrn.iteratorToReferencees();
1367 while( itrReferencee.hasNext() ) {
1368 ReferenceEdge edge = itrReferencee.next();
1369 ReferenceEdge edgeMerged = edge.copy();
1370 edgeMerged.setSrc(hrnSummary);
1372 HeapRegionNode hrnReferencee = edge.getDst();
1373 ReferenceEdge edgeSummary = hrnSummary.getReferenceTo(hrnReferencee,
1377 if( edgeSummary == null ) {
1378 // the merge is trivial, nothing to be done
1380 // otherwise an edge from the referencer to hrnSummary exists already
1381 // and the edge referencer->hrn should be merged with it
1382 edgeMerged.setBeta(edgeMerged.getBeta().union(edgeSummary.getBeta() ) );
1385 addReferenceEdge(hrnSummary, hrnReferencee, edgeMerged);
1388 // next transfer references _to_ hrn over to hrnSummary
1389 Iterator<ReferenceEdge> itrReferencer = hrn.iteratorToReferencers();
1390 while( itrReferencer.hasNext() ) {
1391 ReferenceEdge edge = itrReferencer.next();
1392 ReferenceEdge edgeMerged = edge.copy();
1393 edgeMerged.setDst(hrnSummary);
1395 OwnershipNode onReferencer = edge.getSrc();
1396 ReferenceEdge edgeSummary = onReferencer.getReferenceTo(hrnSummary,
1400 if( edgeSummary == null ) {
1401 // the merge is trivial, nothing to be done
1403 // otherwise an edge from the referencer to alpha_S exists already
1404 // and the edge referencer->alpha_K should be merged with it
1405 edgeMerged.setBeta(edgeMerged.getBeta().union(edgeSummary.getBeta() ) );
1408 addReferenceEdge(onReferencer, hrnSummary, edgeMerged);
1411 // then merge hrn reachability into hrnSummary
1412 hrnSummary.setAlpha(hrnSummary.getAlpha().union(hrn.getAlpha() ) );
1416 protected void transferOnto(HeapRegionNode hrnA, HeapRegionNode hrnB) {
1418 // clear references in and out of node b
1419 clearReferenceEdgesFrom(hrnB, null, null, true);
1420 clearReferenceEdgesTo(hrnB, null, null, true);
1422 // copy each edge in and out of A to B
1423 Iterator<ReferenceEdge> itrReferencee = hrnA.iteratorToReferencees();
1424 while( itrReferencee.hasNext() ) {
1425 ReferenceEdge edge = itrReferencee.next();
1426 HeapRegionNode hrnReferencee = edge.getDst();
1427 ReferenceEdge edgeNew = edge.copy();
1428 edgeNew.setSrc(hrnB);
1430 addReferenceEdge(hrnB, hrnReferencee, edgeNew);
1433 Iterator<ReferenceEdge> itrReferencer = hrnA.iteratorToReferencers();
1434 while( itrReferencer.hasNext() ) {
1435 ReferenceEdge edge = itrReferencer.next();
1436 OwnershipNode onReferencer = edge.getSrc();
1437 ReferenceEdge edgeNew = edge.copy();
1438 edgeNew.setDst(hrnB);
1440 addReferenceEdge(onReferencer, hrnB, edgeNew);
1443 // replace hrnB reachability with hrnA's
1444 hrnB.setAlpha(hrnA.getAlpha() );
1448 protected void ageTokens(AllocationSite as, ReferenceEdge edge) {
1449 edge.setBeta(edge.getBeta().ageTokens(as) );
1452 protected void ageTokens(AllocationSite as, HeapRegionNode hrn) {
1453 hrn.setAlpha(hrn.getAlpha().ageTokens(as) );
1458 protected void propagateTokensOverNodes(HeapRegionNode nPrime,
1460 HashSet<HeapRegionNode> nodesWithNewAlpha,
1461 HashSet<ReferenceEdge> edgesWithNewBeta) {
1463 HashSet<HeapRegionNode> todoNodes
1464 = new HashSet<HeapRegionNode>();
1465 todoNodes.add(nPrime);
1467 HashSet<ReferenceEdge> todoEdges
1468 = new HashSet<ReferenceEdge>();
1470 Hashtable<HeapRegionNode, ChangeTupleSet> nodePlannedChanges
1471 = new Hashtable<HeapRegionNode, ChangeTupleSet>();
1472 nodePlannedChanges.put(nPrime, c0);
1474 Hashtable<ReferenceEdge, ChangeTupleSet> edgePlannedChanges
1475 = new Hashtable<ReferenceEdge, ChangeTupleSet>();
1477 // first propagate change sets everywhere they can go
1478 while( !todoNodes.isEmpty() ) {
1479 HeapRegionNode n = todoNodes.iterator().next();
1480 ChangeTupleSet C = nodePlannedChanges.get(n);
1482 Iterator<ReferenceEdge> referItr = n.iteratorToReferencers();
1483 while( referItr.hasNext() ) {
1484 ReferenceEdge edge = referItr.next();
1485 todoEdges.add(edge);
1487 if( !edgePlannedChanges.containsKey(edge) ) {
1488 edgePlannedChanges.put(edge, new ChangeTupleSet().makeCanonical() );
1491 edgePlannedChanges.put(edge, edgePlannedChanges.get(edge).union(C) );
1494 Iterator<ReferenceEdge> refeeItr = n.iteratorToReferencees();
1495 while( refeeItr.hasNext() ) {
1496 ReferenceEdge edgeF = refeeItr.next();
1497 HeapRegionNode m = edgeF.getDst();
1499 ChangeTupleSet changesToPass = new ChangeTupleSet().makeCanonical();
1501 Iterator<ChangeTuple> itrCprime = C.iterator();
1502 while( itrCprime.hasNext() ) {
1503 ChangeTuple c = itrCprime.next();
1504 if( edgeF.getBeta().contains( c.getSetToMatch() ) ) {
1505 changesToPass = changesToPass.union(c);
1509 if( !changesToPass.isEmpty() ) {
1510 if( !nodePlannedChanges.containsKey(m) ) {
1511 nodePlannedChanges.put(m, new ChangeTupleSet().makeCanonical() );
1514 ChangeTupleSet currentChanges = nodePlannedChanges.get(m);
1516 if( !changesToPass.isSubset(currentChanges) ) {
1518 nodePlannedChanges.put(m, currentChanges.union(changesToPass) );
1524 todoNodes.remove(n);
1527 // then apply all of the changes for each node at once
1528 Iterator itrMap = nodePlannedChanges.entrySet().iterator();
1529 while( itrMap.hasNext() ) {
1530 Map.Entry me = (Map.Entry) itrMap.next();
1531 HeapRegionNode n = (HeapRegionNode) me.getKey();
1532 ChangeTupleSet C = (ChangeTupleSet) me.getValue();
1534 n.setAlphaNew( n.getAlpha().applyChangeSet( C, false ) );
1535 nodesWithNewAlpha.add( n );
1538 propagateTokensOverEdges(todoEdges, edgePlannedChanges, edgesWithNewBeta);
1542 protected void propagateTokensOverEdges(
1543 HashSet<ReferenceEdge> todoEdges,
1544 Hashtable<ReferenceEdge, ChangeTupleSet> edgePlannedChanges,
1545 HashSet<ReferenceEdge> edgesWithNewBeta) {
1547 // first propagate all change tuples everywhere they can go
1548 while( !todoEdges.isEmpty() ) {
1549 ReferenceEdge edgeE = todoEdges.iterator().next();
1550 todoEdges.remove(edgeE);
1552 if( !edgePlannedChanges.containsKey(edgeE) ) {
1553 edgePlannedChanges.put(edgeE, new ChangeTupleSet().makeCanonical() );
1556 ChangeTupleSet C = edgePlannedChanges.get(edgeE);
1558 ChangeTupleSet changesToPass = new ChangeTupleSet().makeCanonical();
1561 Iterator<ChangeTuple> itrC = C.iterator();
1562 while( itrC.hasNext() ) {
1563 ChangeTuple c = itrC.next();
1564 if( edgeE.getBeta().contains( c.getSetToMatch() ) ) {
1565 changesToPass = changesToPass.union(c);
1569 OwnershipNode onSrc = edgeE.getSrc();
1571 if( !changesToPass.isEmpty() && onSrc instanceof HeapRegionNode ) {
1572 HeapRegionNode n = (HeapRegionNode) onSrc;
1574 Iterator<ReferenceEdge> referItr = n.iteratorToReferencers();
1575 while( referItr.hasNext() ) {
1576 ReferenceEdge edgeF = referItr.next();
1578 if( !edgePlannedChanges.containsKey(edgeF) ) {
1579 edgePlannedChanges.put(edgeF, new ChangeTupleSet().makeCanonical() );
1582 ChangeTupleSet currentChanges = edgePlannedChanges.get(edgeF);
1584 if( !changesToPass.isSubset(currentChanges) ) {
1585 todoEdges.add(edgeF);
1586 edgePlannedChanges.put(edgeF, currentChanges.union(changesToPass) );
1592 // then apply all of the changes for each edge at once
1593 Iterator itrMap = edgePlannedChanges.entrySet().iterator();
1594 while( itrMap.hasNext() ) {
1595 Map.Entry me = (Map.Entry) itrMap.next();
1596 ReferenceEdge e = (ReferenceEdge) me.getKey();
1597 ChangeTupleSet C = (ChangeTupleSet) me.getValue();
1599 e.setBetaNew( e.getBeta().applyChangeSet( C, true ) );
1600 edgesWithNewBeta.add( e );
1605 public Set<Integer> calculateAliasedParamSet(FlatCall fc,
1609 Hashtable<Integer, LabelNode> paramIndex2ln =
1610 new Hashtable<Integer, LabelNode>();
1612 Hashtable<Integer, HashSet<HeapRegionNode> > paramIndex2reachableCallerNodes =
1613 new Hashtable<Integer, HashSet<HeapRegionNode> >();
1615 for( int i = 0; i < fm.numParameters(); ++i ) {
1616 Integer paramIndex = new Integer(i);
1618 // now depending on whether the callee is static or not
1619 // we need to account for a "this" argument in order to
1620 // find the matching argument in the caller context
1621 TempDescriptor argTemp_i;
1623 argTemp_i = fc.getArg(paramIndex);
1625 if( paramIndex.equals(0) ) {
1626 argTemp_i = fc.getThis();
1628 argTemp_i = fc.getArg(paramIndex - 1);
1632 // in non-static methods there is a "this" pointer
1633 // that should be taken into account
1635 assert fc.numArgs() == fm.numParameters();
1637 assert fc.numArgs() + 1 == fm.numParameters();
1640 LabelNode argLabel_i = getLabelNodeFromTemp(argTemp_i);
1641 paramIndex2ln.put(paramIndex, argLabel_i);
1644 Iterator lnArgItr = paramIndex2ln.entrySet().iterator();
1645 while( lnArgItr.hasNext() ) {
1646 Map.Entry me = (Map.Entry)lnArgItr.next();
1647 Integer index = (Integer) me.getKey();
1648 LabelNode lnArg_i = (LabelNode) me.getValue();
1650 // rewrite alpha for the nodes reachable from argument label i
1651 HashSet<HeapRegionNode> reachableNodes = new HashSet<HeapRegionNode>();
1652 HashSet<HeapRegionNode> todoNodes = new HashSet<HeapRegionNode>();
1654 // to find all reachable nodes, start with label referencees
1655 Iterator<ReferenceEdge> edgeArgItr = lnArg_i.iteratorToReferencees();
1656 while( edgeArgItr.hasNext() ) {
1657 ReferenceEdge edge = edgeArgItr.next();
1658 todoNodes.add(edge.getDst() );
1661 // then follow links until all reachable nodes have been found
1662 while( !todoNodes.isEmpty() ) {
1663 HeapRegionNode hrn = todoNodes.iterator().next();
1664 todoNodes.remove(hrn);
1665 reachableNodes.add(hrn);
1667 Iterator<ReferenceEdge> edgeItr = hrn.iteratorToReferencees();
1668 while( edgeItr.hasNext() ) {
1669 ReferenceEdge edge = edgeItr.next();
1671 if( !reachableNodes.contains(edge.getDst() ) ) {
1672 todoNodes.add(edge.getDst() );
1678 paramIndex2reachableCallerNodes.put(index, reachableNodes);
1681 Set<Integer> aliasedIndices = new HashSet<Integer>();
1683 // check for arguments that are aliased
1684 for( int i = 0; i < fm.numParameters(); ++i ) {
1685 for( int j = 0; j < i; ++j ) {
1686 HashSet<HeapRegionNode> s1 = paramIndex2reachableCallerNodes.get( i );
1687 HashSet<HeapRegionNode> s2 = paramIndex2reachableCallerNodes.get( j );
1689 Set<HeapRegionNode> intersection = new HashSet<HeapRegionNode>(s1);
1690 intersection.retainAll(s2);
1692 if( !intersection.isEmpty() ) {
1693 aliasedIndices.add( new Integer( i ) );
1694 aliasedIndices.add( new Integer( j ) );
1699 return aliasedIndices;
1703 private String makeMapKey( Integer i, Integer j, String field ) {
1704 return i+","+j+","+field;
1707 private String makeMapKey( Integer i, String field ) {
1711 public void resolveMethodCall(FlatCall fc,
1714 OwnershipGraph ogCallee,
1718 String debugCaller = "foo";
1719 String debugCallee = "bar";
1721 if( mc.getDescriptor().getSymbol().equals( debugCaller ) &&
1722 fm.getMethod().getSymbol().equals( debugCallee ) ) {
1725 writeGraph( "debug1Before", true, true, true, false, false );
1726 ogCallee.writeGraph( "debug0Callee", true, true, true, false, false );
1727 } catch( IOException e ) {}
1729 System.out.println( " "+mc+" is calling "+fm );
1733 // define rewrite rules and other structures to organize data by parameter/argument index
1734 Hashtable<Integer, ReachabilitySet> paramIndex2rewriteH_p = new Hashtable<Integer, ReachabilitySet>();
1735 Hashtable<Integer, ReachabilitySet> paramIndex2rewriteH_s = new Hashtable<Integer, ReachabilitySet>();
1737 Hashtable<String, ReachabilitySet> paramIndex2rewriteJ_p2p = new Hashtable<String, ReachabilitySet>(); // select( i, j, f )
1738 Hashtable<String, ReachabilitySet> paramIndex2rewriteJ_p2s = new Hashtable<String, ReachabilitySet>(); // select( i, f )
1739 Hashtable<Integer, ReachabilitySet> paramIndex2rewriteJ_s2p = new Hashtable<Integer, ReachabilitySet>();
1740 Hashtable<Integer, ReachabilitySet> paramIndex2rewriteJ_s2s = new Hashtable<Integer, ReachabilitySet>();
1742 Hashtable<Integer, ReachabilitySet> paramIndex2rewriteK_p = new Hashtable<Integer, ReachabilitySet>();
1743 Hashtable<Integer, ReachabilitySet> paramIndex2rewriteK_s = new Hashtable<Integer, ReachabilitySet>();
1745 Hashtable<Integer, ReachabilitySet> paramIndex2rewrite_d_p = new Hashtable<Integer, ReachabilitySet>();
1746 Hashtable<Integer, ReachabilitySet> paramIndex2rewrite_d_s = new Hashtable<Integer, ReachabilitySet>();
1748 Hashtable<Integer, ReachabilitySet> paramIndex2rewriteD = new Hashtable<Integer, ReachabilitySet>();
1751 Hashtable<Integer, LabelNode> paramIndex2ln = new Hashtable<Integer, LabelNode>();
1754 paramIndex2rewriteH_p.put( bogusIndex, rsIdentity );
1755 paramIndex2rewriteH_s.put( bogusIndex, rsIdentity );
1757 paramIndex2rewriteJ_p2p.put( bogusIndex.toString(), rsIdentity );
1758 paramIndex2rewriteJ_p2s.put( bogusIndex.toString(), rsIdentity );
1759 paramIndex2rewriteJ_s2p.put( bogusIndex, rsIdentity );
1760 paramIndex2rewriteJ_s2s.put( bogusIndex, rsIdentity );
1763 for( int i = 0; i < fm.numParameters(); ++i ) {
1764 Integer paramIndex = new Integer(i);
1766 if( !ogCallee.paramIndex2idPrimary.containsKey( paramIndex ) ) {
1767 // skip this immutable parameter
1771 // setup H (primary)
1772 Integer idPrimary = ogCallee.paramIndex2idPrimary.get( paramIndex );
1773 assert ogCallee.id2hrn.containsKey( idPrimary );
1774 HeapRegionNode hrnPrimary = ogCallee.id2hrn.get( idPrimary );
1775 assert hrnPrimary != null;
1776 paramIndex2rewriteH_p.put( paramIndex, toShadowTokens( ogCallee, hrnPrimary.getAlpha() ) );
1778 // setup J (primary->X)
1779 Iterator<ReferenceEdge> p2xItr = hrnPrimary.iteratorToReferencees();
1780 while( p2xItr.hasNext() ) {
1781 ReferenceEdge p2xEdge = p2xItr.next();
1783 // we only care about initial parameter edges here
1784 if( !p2xEdge.isInitialParam() ) { continue; }
1786 HeapRegionNode hrnDst = p2xEdge.getDst();
1788 if( ogCallee.idPrimary2paramIndexSet.containsKey( hrnDst.getID() ) ) {
1789 Iterator<Integer> jItr = ogCallee.idPrimary2paramIndexSet.get( hrnDst.getID() ).iterator();
1790 while( jItr.hasNext() ) {
1791 Integer j = jItr.next();
1792 paramIndex2rewriteJ_p2p.put( makeMapKey( i, j, p2xEdge.getField() ),
1793 toShadowTokens( ogCallee, p2xEdge.getBeta() ) );
1797 assert ogCallee.idSecondary2paramIndexSet.containsKey( hrnDst.getID() );
1798 paramIndex2rewriteJ_p2s.put( makeMapKey( i, p2xEdge.getField() ),
1799 toShadowTokens( ogCallee, p2xEdge.getBeta() ) );
1803 // setup K (primary)
1804 TempDescriptor tdParamQ = ogCallee.paramIndex2tdQ.get( paramIndex );
1805 assert tdParamQ != null;
1806 LabelNode lnParamQ = ogCallee.td2ln.get( tdParamQ );
1807 assert lnParamQ != null;
1808 ReferenceEdge edgeSpecialQ_i = lnParamQ.getReferenceTo( hrnPrimary, null, null );
1809 assert edgeSpecialQ_i != null;
1810 paramIndex2rewriteK_p.put( paramIndex,
1811 toShadowTokens( ogCallee, edgeSpecialQ_i.getBeta() ) );
1814 // if there is a secondary node, compute the rest of the rewrite rules
1815 if( ogCallee.paramIndex2idSecondary.containsKey( paramIndex ) ) {
1817 // setup H (secondary)
1818 Integer idSecondary = ogCallee.paramIndex2idSecondary.get( paramIndex );
1819 assert ogCallee.id2hrn.containsKey( idSecondary );
1820 HeapRegionNode hrnSecondary = ogCallee.id2hrn.get( idSecondary );
1821 assert hrnSecondary != null;
1822 paramIndex2rewriteH_s.put( paramIndex, toShadowTokens( ogCallee, hrnSecondary.getAlpha() ) );
1824 // setup J (secondary->X)
1825 Iterator<ReferenceEdge> s2xItr = hrnSecondary.iteratorToReferencees();
1826 while( s2xItr.hasNext() ) {
1827 ReferenceEdge s2xEdge = s2xItr.next();
1829 if( !s2xEdge.isInitialParam() ) { continue; }
1831 HeapRegionNode hrnDst = s2xEdge.getDst();
1833 if( ogCallee.idPrimary2paramIndexSet.containsKey( hrnDst.getID() ) ) {
1834 Iterator<Integer> jItr = ogCallee.idPrimary2paramIndexSet.get( hrnDst.getID() ).iterator();
1835 while( jItr.hasNext() ) {
1836 Integer j = jItr.next();
1837 paramIndex2rewriteJ_s2p.put( i, toShadowTokens( ogCallee, s2xEdge.getBeta() ) );
1841 assert ogCallee.idSecondary2paramIndexSet.containsKey( hrnDst.getID() );
1842 paramIndex2rewriteJ_s2s.put( i, toShadowTokens( ogCallee, s2xEdge.getBeta() ) );
1846 // setup K (secondary)
1847 TempDescriptor tdParamR = ogCallee.paramIndex2tdR.get( paramIndex );
1848 assert tdParamR != null;
1849 LabelNode lnParamR = ogCallee.td2ln.get( tdParamR );
1850 assert lnParamR != null;
1851 ReferenceEdge edgeSpecialR_i = lnParamR.getReferenceTo( hrnSecondary, null, null );
1852 assert edgeSpecialR_i != null;
1853 paramIndex2rewriteK_s.put( paramIndex,
1854 toShadowTokens( ogCallee, edgeSpecialR_i.getBeta() ) );
1858 // now depending on whether the callee is static or not
1859 // we need to account for a "this" argument in order to
1860 // find the matching argument in the caller context
1861 TempDescriptor argTemp_i;
1863 argTemp_i = fc.getArg( paramIndex );
1865 if( paramIndex.equals( 0 ) ) {
1866 argTemp_i = fc.getThis();
1868 argTemp_i = fc.getArg( paramIndex - 1 );
1872 // in non-static methods there is a "this" pointer
1873 // that should be taken into account
1875 assert fc.numArgs() == fm.numParameters();
1877 assert fc.numArgs() + 1 == fm.numParameters();
1880 // remember which caller arg label maps to param index
1881 LabelNode argLabel_i = getLabelNodeFromTemp( argTemp_i );
1882 paramIndex2ln.put( paramIndex, argLabel_i );
1884 ReachabilitySet d_i_p = new ReachabilitySet().makeCanonical();
1885 ReachabilitySet d_i_s = new ReachabilitySet().makeCanonical();
1886 Iterator<ReferenceEdge> edgeItr = argLabel_i.iteratorToReferencees();
1887 while( edgeItr.hasNext() ) {
1888 ReferenceEdge edge = edgeItr.next();
1890 d_i_p = d_i_p.union( edge.getBeta().intersection( edge.getDst().getAlpha() ) );
1891 d_i_s = d_i_s.union( edge.getBeta() );
1893 paramIndex2rewrite_d_p.put( paramIndex, d_i_p );
1894 paramIndex2rewrite_d_s.put( paramIndex, d_i_s );
1896 // TODO: we should only do this when we need it, and then
1897 // memoize it for the rest of the mapping procedure
1898 ReachabilitySet D_i = d_i_s.exhaustiveArityCombinations();
1899 paramIndex2rewriteD.put( paramIndex, D_i );
1903 HashSet<HeapRegionNode> nodesWithNewAlpha = new HashSet<HeapRegionNode>();
1904 HashSet<ReferenceEdge> edgesWithNewBeta = new HashSet<ReferenceEdge>();
1906 Hashtable<Integer, HashSet<HeapRegionNode> > paramIndex2directlyReachableCallerNodes =
1907 new Hashtable<Integer, HashSet<HeapRegionNode> >();
1909 Hashtable<Integer, HashSet<HeapRegionNode> > paramIndex2reachableCallerNodes =
1910 new Hashtable<Integer, HashSet<HeapRegionNode> >();
1912 HashSet<HeapRegionNode> nodesDirectlyReachableAnyParam = new HashSet<HeapRegionNode>();
1913 HashSet<HeapRegionNode> nodesReachableAnyParam = new HashSet<HeapRegionNode>();
1915 Iterator lnArgItr = paramIndex2ln.entrySet().iterator();
1916 while( lnArgItr.hasNext() ) {
1917 Map.Entry me = (Map.Entry) lnArgItr.next();
1918 Integer index = (Integer) me.getKey();
1919 LabelNode lnArg_i = (LabelNode) me.getValue();
1921 HashSet<HeapRegionNode> nodesDirectlyReachable = new HashSet<HeapRegionNode>();
1922 HashSet<HeapRegionNode> nodesReachable = new HashSet<HeapRegionNode>();
1923 HashSet<HeapRegionNode> nodesTodo = new HashSet<HeapRegionNode>();
1925 // find all reachable nodes starting with label referencees
1926 Iterator<ReferenceEdge> edgeArgItr = lnArg_i.iteratorToReferencees();
1927 while( edgeArgItr.hasNext() ) {
1928 ReferenceEdge edge = edgeArgItr.next();
1929 HeapRegionNode hrn = edge.getDst();
1930 nodesTodo.add( hrn );
1931 nodesDirectlyReachable.add( hrn );
1932 nodesDirectlyReachableAnyParam.add( hrn );
1935 // then follow links until all reachable nodes have been found
1936 while( !nodesTodo.isEmpty() ) {
1937 HeapRegionNode hrn = nodesTodo.iterator().next();
1938 nodesTodo.remove( hrn );
1939 nodesReachable.add( hrn );
1940 nodesReachableAnyParam.add( hrn );
1942 Iterator<ReferenceEdge> edgeItr = hrn.iteratorToReferencees();
1943 while( edgeItr.hasNext() ) {
1944 ReferenceEdge edge = edgeItr.next();
1945 if( !nodesReachable.contains( edge.getDst() ) ) {
1946 nodesTodo.add( edge.getDst() );
1951 paramIndex2directlyReachableCallerNodes.put( index, nodesDirectlyReachable );
1952 paramIndex2reachableCallerNodes .put( index, nodesReachable );
1955 // now iterate over reachable nodes to rewrite their alpha, and
1956 // classify edges found for beta rewrite
1957 HashSet<ReferenceEdge> edges_p2p = new HashSet<ReferenceEdge>();
1958 HashSet<ReferenceEdge> edges_p2s = new HashSet<ReferenceEdge>();
1959 HashSet<ReferenceEdge> edges_s2p = new HashSet<ReferenceEdge>();
1960 HashSet<ReferenceEdge> edges_s2s = new HashSet<ReferenceEdge>();
1961 HashSet<ReferenceEdge> edgesUpstreamDirectlyReachable = new HashSet<ReferenceEdge>();
1962 HashSet<ReferenceEdge> edgesUpstreamReachable = new HashSet<ReferenceEdge>();
1965 Iterator lnArgItr = paramIndex2ln.entrySet().iterator();
1966 while( lnArgItr.hasNext() ) {
1967 Map.Entry me = (Map.Entry) lnArgItr.next();
1968 Integer index = (Integer) me.getKey();
1969 LabelNode lnArg_i = (LabelNode) me.getValue();
1971 nodesDirectlyReachable = paramIndex2directlyReachableCallerNodes.get( index );
1972 Iterator<HeapRegionNode> hrnItr = nodesDirectlyReachable.iterator();
1973 while( hrnItr.hasNext() ) {
1974 HeapRegionNode hrn = hrnItr.next();
1976 rewriteCallerReachability( index,
1979 paramIndex2rewriteH_p.get( index ),
1980 paramIndex2rewrite_d_p,
1981 paramIndex2rewrite_d,
1982 paramIndex2rewriteD,
1983 paramIndex2paramToken.get( index ),
1984 paramToken2paramIndex,
1985 paramTokenPlus2paramIndex,
1986 paramTokenStar2paramIndex,
1990 nodesWithNewAlpha.add( hrn );
1993 Iterator<ReferenceEdge> edgeItr = hrn.iteratorToReferencers();
1994 while( edgeItr.hasNext() ) {
1995 ReferenceEdge edge = edgeItr.next();
1996 OwnershipNode on = edge.getSrc();
1998 if( on instanceof LabelNode ) {
1999 LabelNode ln0 = (LabelNode) on;
2000 if( ln0.equals( lnArg_i ) ) {
2001 edgesReachable.add( edge );
2003 edgesUpstream.add( edge );
2007 HeapRegionNode hrn0 = (HeapRegionNode) on;
2008 if( nodesReachable.contains( hrn0 ) ) {
2009 edgesReachable.add( edge );
2011 edgesUpstream.add( edge );
2017 nodesReachable = paramIndex2reachableCallerNodes.get( index );
2018 hrnItr = nodesReachable.iterator();
2019 while( hrnItr.hasNext() ) {
2020 HeapRegionNode hrn = hrnItr.next();
2022 rewriteCallerReachability(index,
2025 paramIndex2rewriteH.get(index),
2026 paramIndex2rewrite_d,
2027 paramIndex2rewriteD,
2028 paramIndex2paramToken.get(index),
2029 paramToken2paramIndex,
2030 paramTokenPlus2paramIndex,
2031 paramTokenStar2paramIndex,
2035 nodesWithNewAlpha.add(hrn);
2037 // look at all incoming edges to the reachable nodes
2038 // and sort them as edges reachable from the argument
2039 // label node, or upstream edges
2040 Iterator<ReferenceEdge> edgeItr = hrn.iteratorToReferencers();
2041 while( edgeItr.hasNext() ) {
2042 ReferenceEdge edge = edgeItr.next();
2043 OwnershipNode on = edge.getSrc();
2045 if( on instanceof LabelNode ) {
2046 LabelNode ln0 = (LabelNode) on;
2047 if( ln0.equals(lnArg_i) ) {
2048 edgesReachable.add(edge);
2050 edgesUpstream.add(edge);
2054 HeapRegionNode hrn0 = (HeapRegionNode) on;
2055 if( nodesReachable.contains(hrn0) ) {
2056 edgesReachable.add(edge);
2058 edgesUpstream.add(edge);
2065 // update reachable edges
2066 Iterator<ReferenceEdge> edgeReachableItr = edgesReachable.iterator();
2067 while( edgeReachableItr.hasNext() ) {
2068 ReferenceEdge edgeReachable = edgeReachableItr.next();
2070 rewriteCallerReachability(index,
2073 paramIndex2rewriteJ.get(index),
2074 paramIndex2rewrite_d,
2075 paramIndex2rewriteD,
2076 paramIndex2paramToken.get(index),
2077 paramToken2paramIndex,
2078 paramTokenPlus2paramIndex,
2079 paramTokenStar2paramIndex,
2083 edgesWithNewBeta.add(edgeReachable);
2086 // update upstream edges
2087 Hashtable<ReferenceEdge, ChangeTupleSet> edgeUpstreamPlannedChanges =
2088 new Hashtable<ReferenceEdge, ChangeTupleSet>();
2090 Iterator<ReferenceEdge> edgeUpstreamItr = edgesUpstream.iterator();
2091 while( edgeUpstreamItr.hasNext() ) {
2092 ReferenceEdge edgeUpstream = edgeUpstreamItr.next();
2094 rewriteCallerReachability(index,
2097 paramIndex2rewriteK.get(index),
2098 paramIndex2rewrite_d,
2099 paramIndex2rewriteD,
2100 paramIndex2paramToken.get(index),
2101 paramToken2paramIndex,
2102 paramTokenPlus2paramIndex,
2103 paramTokenStar2paramIndex,
2105 edgeUpstreamPlannedChanges);
2107 edgesWithNewBeta.add(edgeUpstream);
2110 propagateTokensOverEdges(edgesUpstream,
2111 edgeUpstreamPlannedChanges,
2117 // commit changes to alpha and beta
2118 Iterator<HeapRegionNode> nodeItr = nodesWithNewAlpha.iterator();
2119 while( nodeItr.hasNext() ) {
2120 nodeItr.next().applyAlphaNew();
2123 Iterator<ReferenceEdge> edgeItr = edgesWithNewBeta.iterator();
2124 while( edgeItr.hasNext() ) {
2125 edgeItr.next().applyBetaNew();
2130 // verify the existence of allocation sites and their
2131 // shadows from the callee in the context of this caller graph
2132 // then map allocated nodes of callee onto the caller shadows
2134 Iterator<AllocationSite> asItr = ogCallee.allocationSites.iterator();
2135 while( asItr.hasNext() ) {
2136 AllocationSite allocSite = asItr.next();
2138 // grab the summary in the caller just to make sure
2139 // the allocation site has nodes in the caller
2140 HeapRegionNode hrnSummary = getSummaryNode(allocSite);
2142 // assert that the shadow nodes have no reference edges
2143 // because they're brand new to the graph, or last time
2144 // they were used they should have been cleared of edges
2145 HeapRegionNode hrnShadowSummary = getShadowSummaryNode(allocSite);
2146 assert hrnShadowSummary.getNumReferencers() == 0;
2147 assert hrnShadowSummary.getNumReferencees() == 0;
2149 // then bring g_ij onto g'_ij and rewrite
2150 HeapRegionNode hrnSummaryCallee = ogCallee.getSummaryNode(allocSite);
2151 hrnShadowSummary.setAlpha(toShadowTokens(ogCallee, hrnSummaryCallee.getAlpha() ) );
2153 // shadow nodes only are touched by a rewrite one time,
2154 // so rewrite and immediately commit--and they don't belong
2155 // to a particular parameter, so use a bogus param index
2156 // that pulls a self-rewrite out of H
2157 rewriteCallerReachability(bogusIndex,
2160 hrnShadowSummary.getAlpha(),
2161 paramIndex2rewrite_d,
2162 paramIndex2rewriteD,
2164 paramToken2paramIndex,
2165 paramTokenPlus2paramIndex,
2166 paramTokenStar2paramIndex,
2170 hrnShadowSummary.applyAlphaNew();
2173 for( int i = 0; i < allocSite.getAllocationDepth(); ++i ) {
2174 Integer idIth = allocSite.getIthOldest(i);
2175 assert id2hrn.containsKey(idIth);
2176 HeapRegionNode hrnIth = id2hrn.get(idIth);
2178 Integer idShadowIth = -(allocSite.getIthOldest(i));
2179 assert id2hrn.containsKey(idShadowIth);
2180 HeapRegionNode hrnIthShadow = id2hrn.get(idShadowIth);
2181 assert hrnIthShadow.getNumReferencers() == 0;
2182 assert hrnIthShadow.getNumReferencees() == 0;
2184 assert ogCallee.id2hrn.containsKey(idIth);
2185 HeapRegionNode hrnIthCallee = ogCallee.id2hrn.get(idIth);
2186 hrnIthShadow.setAlpha(toShadowTokens(ogCallee, hrnIthCallee.getAlpha() ) );
2188 rewriteCallerReachability(bogusIndex,
2191 hrnIthShadow.getAlpha(),
2192 paramIndex2rewrite_d,
2193 paramIndex2rewriteD,
2195 paramToken2paramIndex,
2196 paramTokenPlus2paramIndex,
2197 paramTokenStar2paramIndex,
2201 hrnIthShadow.applyAlphaNew();
2206 // for every heap region->heap region edge in the
2207 // callee graph, create the matching edge or edges
2208 // in the caller graph
2209 Set sCallee = ogCallee.id2hrn.entrySet();
2210 Iterator iCallee = sCallee.iterator();
2211 while( iCallee.hasNext() ) {
2212 Map.Entry meCallee = (Map.Entry)iCallee.next();
2213 Integer idCallee = (Integer) meCallee.getKey();
2214 HeapRegionNode hrnCallee = (HeapRegionNode) meCallee.getValue();
2216 Iterator<ReferenceEdge> heapRegionsItrCallee = hrnCallee.iteratorToReferencees();
2217 while( heapRegionsItrCallee.hasNext() ) {
2218 ReferenceEdge edgeCallee = heapRegionsItrCallee.next();
2219 HeapRegionNode hrnChildCallee = edgeCallee.getDst();
2220 Integer idChildCallee = hrnChildCallee.getID();
2222 // only address this edge if it is not a special reflexive edge
2223 if( !edgeCallee.isInitialParam() ) {
2225 // now we know that in the callee method's ownership graph
2226 // there is a heap region->heap region reference edge given
2227 // by heap region pointers:
2228 // hrnCallee -> heapChildCallee
2230 // or by the ownership-graph independent ID's:
2231 // idCallee -> idChildCallee
2233 // make the edge with src and dst so beta info is
2234 // calculated once, then copy it for each new edge in caller
2235 ReferenceEdge edgeNewInCallerTemplate = new ReferenceEdge(null,
2237 edgeCallee.getType(),
2238 edgeCallee.getField(),
2240 toShadowTokens(ogCallee,
2241 edgeCallee.getBeta() )
2243 rewriteCallerReachability(bogusIndex,
2245 edgeNewInCallerTemplate,
2246 edgeNewInCallerTemplate.getBeta(),
2247 paramIndex2rewrite_d,
2248 paramIndex2rewriteD,
2250 paramToken2paramIndex,
2251 paramTokenPlus2paramIndex,
2252 paramTokenStar2paramIndex,
2256 edgeNewInCallerTemplate.applyBetaNew();
2259 // So now make a set of possible source heaps in the caller graph
2260 // and a set of destination heaps in the caller graph, and make
2261 // a reference edge in the caller for every possible (src,dst) pair
2262 HashSet<HeapRegionNode> possibleCallerSrcs =
2263 getHRNSetThatPossiblyMapToCalleeHRN(ogCallee,
2264 (HeapRegionNode) edgeCallee.getSrc(),
2265 paramIndex2reachableCallerNodes);
2267 HashSet<HeapRegionNode> possibleCallerDsts =
2268 getHRNSetThatPossiblyMapToCalleeHRN(ogCallee,
2269 edgeCallee.getDst(),
2270 paramIndex2reachableCallerNodes);
2273 // make every possible pair of {srcSet} -> {dstSet} edges in the caller
2274 Iterator srcItr = possibleCallerSrcs.iterator();
2275 while( srcItr.hasNext() ) {
2276 HeapRegionNode src = (HeapRegionNode) srcItr.next();
2278 if( !hasMatchingField(src, edgeCallee) ) {
2279 // prune this source node possibility
2283 Iterator dstItr = possibleCallerDsts.iterator();
2284 while( dstItr.hasNext() ) {
2285 HeapRegionNode dst = (HeapRegionNode) dstItr.next();
2287 if( !hasMatchingType(edgeCallee, dst) ) {
2292 // otherwise the caller src and dst pair can match the edge, so make it
2293 ReferenceEdge edgeNewInCaller = edgeNewInCallerTemplate.copy();
2294 edgeNewInCaller.setSrc(src);
2295 edgeNewInCaller.setDst(dst);
2297 ReferenceEdge edgeExisting = src.getReferenceTo(dst,
2298 edgeNewInCaller.getType(),
2299 edgeNewInCaller.getField() );
2300 if( edgeExisting == null ) {
2301 // if this edge doesn't exist in the caller, create it
2302 addReferenceEdge(src, dst, edgeNewInCaller);
2305 // if it already exists, merge with it
2306 edgeExisting.setBeta(edgeExisting.getBeta().union(edgeNewInCaller.getBeta() ) );
2315 // return value may need to be assigned in caller
2316 TempDescriptor returnTemp = fc.getReturnTemp();
2317 if( returnTemp != null && !returnTemp.getType().isImmutable() ) {
2319 LabelNode lnLhsCaller = getLabelNodeFromTemp(returnTemp);
2320 clearReferenceEdgesFrom(lnLhsCaller, null, null, true);
2322 LabelNode lnReturnCallee = ogCallee.getLabelNodeFromTemp(tdReturn);
2323 Iterator<ReferenceEdge> edgeCalleeItr = lnReturnCallee.iteratorToReferencees();
2324 while( edgeCalleeItr.hasNext() ) {
2325 ReferenceEdge edgeCallee = edgeCalleeItr.next();
2327 ReferenceEdge edgeNewInCallerTemplate = new ReferenceEdge(null,
2329 edgeCallee.getType(),
2330 edgeCallee.getField(),
2332 toShadowTokens(ogCallee,
2333 edgeCallee.getBeta() )
2335 rewriteCallerReachability(bogusIndex,
2337 edgeNewInCallerTemplate,
2338 edgeNewInCallerTemplate.getBeta(),
2339 paramIndex2rewrite_d,
2340 paramIndex2rewriteD,
2342 paramToken2paramIndex,
2343 paramTokenPlus2paramIndex,
2344 paramTokenStar2paramIndex,
2348 edgeNewInCallerTemplate.applyBetaNew();
2351 HashSet<HeapRegionNode> assignCallerRhs =
2352 getHRNSetThatPossiblyMapToCalleeHRN(ogCallee,
2353 edgeCallee.getDst(),
2354 paramIndex2reachableCallerNodes);
2356 Iterator<HeapRegionNode> itrHrn = assignCallerRhs.iterator();
2357 while( itrHrn.hasNext() ) {
2358 HeapRegionNode hrnCaller = itrHrn.next();
2360 if( !hasMatchingType(edgeCallee, hrnCaller) ) {
2365 // otherwise caller node can match callee edge, so make it
2366 ReferenceEdge edgeNewInCaller = edgeNewInCallerTemplate.copy();
2367 edgeNewInCaller.setSrc(lnLhsCaller);
2368 edgeNewInCaller.setDst(hrnCaller);
2370 ReferenceEdge edgeExisting = lnLhsCaller.getReferenceTo(hrnCaller,
2371 edgeNewInCaller.getType(),
2372 edgeNewInCaller.getField() );
2373 if( edgeExisting == null ) {
2375 // if this edge doesn't exist in the caller, create it
2376 addReferenceEdge(lnLhsCaller, hrnCaller, edgeNewInCaller);
2378 // if it already exists, merge with it
2379 edgeExisting.setBeta(edgeExisting.getBeta().union(edgeNewInCaller.getBeta() ) );
2386 // merge the shadow nodes of allocation sites back down to normal capacity
2387 Iterator<AllocationSite> allocItr = ogCallee.allocationSites.iterator();
2388 while( allocItr.hasNext() ) {
2389 AllocationSite as = allocItr.next();
2391 // first age each allocation site enough times to make room for the shadow nodes
2392 for( int i = 0; i < as.getAllocationDepth(); ++i ) {
2396 // then merge the shadow summary into the normal summary
2397 HeapRegionNode hrnSummary = getSummaryNode(as);
2398 assert hrnSummary != null;
2400 HeapRegionNode hrnSummaryShadow = getShadowSummaryNode(as);
2401 assert hrnSummaryShadow != null;
2403 mergeIntoSummary(hrnSummaryShadow, hrnSummary);
2405 // then clear off after merge
2406 clearReferenceEdgesFrom(hrnSummaryShadow, null, null, true);
2407 clearReferenceEdgesTo(hrnSummaryShadow, null, null, true);
2408 hrnSummaryShadow.setAlpha(new ReachabilitySet().makeCanonical() );
2410 // then transplant shadow nodes onto the now clean normal nodes
2411 for( int i = 0; i < as.getAllocationDepth(); ++i ) {
2413 Integer idIth = as.getIthOldest(i);
2414 HeapRegionNode hrnIth = id2hrn.get(idIth);
2416 Integer idIthShadow = as.getIthOldestShadow(i);
2417 HeapRegionNode hrnIthShadow = id2hrn.get(idIthShadow);
2419 transferOnto(hrnIthShadow, hrnIth);
2421 // clear off shadow nodes after transfer
2422 clearReferenceEdgesFrom(hrnIthShadow, null, null, true);
2423 clearReferenceEdgesTo(hrnIthShadow, null, null, true);
2424 hrnIthShadow.setAlpha(new ReachabilitySet().makeCanonical() );
2427 // finally, globally change shadow tokens into normal tokens
2428 Iterator itrAllLabelNodes = td2ln.entrySet().iterator();
2429 while( itrAllLabelNodes.hasNext() ) {
2430 Map.Entry me = (Map.Entry)itrAllLabelNodes.next();
2431 LabelNode ln = (LabelNode) me.getValue();
2433 Iterator<ReferenceEdge> itrEdges = ln.iteratorToReferencees();
2434 while( itrEdges.hasNext() ) {
2435 unshadowTokens(as, itrEdges.next() );
2439 Iterator itrAllHRNodes = id2hrn.entrySet().iterator();
2440 while( itrAllHRNodes.hasNext() ) {
2441 Map.Entry me = (Map.Entry)itrAllHRNodes.next();
2442 HeapRegionNode hrnToAge = (HeapRegionNode) me.getValue();
2444 unshadowTokens(as, hrnToAge);
2446 Iterator<ReferenceEdge> itrEdges = hrnToAge.iteratorToReferencees();
2447 while( itrEdges.hasNext() ) {
2448 unshadowTokens(as, itrEdges.next() );
2454 if( mc.getDescriptor().getSymbol().equals( debugCaller ) &&
2455 fm.getMethod().getSymbol().equals( debugCallee ) ) {
2457 writeGraph( "debug2JustBeforeSweep", true, true, true, false, false );
2458 } catch( IOException e ) {}
2462 // improve reachability as much as possible
2466 if( mc.getDescriptor().getSymbol().equals( debugCaller ) &&
2467 fm.getMethod().getSymbol().equals( debugCallee ) ) {
2469 writeGraph( "debug9endResolveCall", true, true, true, false, false );
2470 } catch( IOException e ) {}
2471 System.out.println( " "+mc+" done calling "+fm );
2477 protected boolean hasMatchingField(HeapRegionNode src, ReferenceEdge edge) {
2479 // if no type, then it's a match-everything region
2480 TypeDescriptor tdSrc = src.getType();
2481 if( tdSrc == null ) {
2485 if( tdSrc.isArray() ) {
2486 TypeDescriptor td = edge.getType();
2489 TypeDescriptor tdSrcDeref = tdSrc.dereference();
2490 assert tdSrcDeref != null;
2492 if( !typeUtil.isSuperorType( tdSrcDeref, td ) ) {
2496 return edge.getField().equals( OwnershipAnalysis.arrayElementFieldName );
2499 // if it's not a class, it doesn't have any fields to match
2500 if( !tdSrc.isClass() ) {
2504 Iterator fieldsSrcItr = tdSrc.getClassDesc().getFields();
2505 while( fieldsSrcItr.hasNext() ) {
2506 FieldDescriptor fd = (FieldDescriptor) fieldsSrcItr.next();
2507 if( fd.getType().equals( edge.getType() ) &&
2508 fd.getSymbol().equals( edge.getField() ) ) {
2513 // otherwise it is a class with fields
2514 // but we didn't find a match
2519 protected boolean hasMatchingType(ReferenceEdge edge, HeapRegionNode dst) {
2521 // if the region has no type, matches everything
2522 TypeDescriptor tdDst = dst.getType();
2523 if( tdDst == null ) {
2527 // if the type is not a class or an array, don't
2528 // match because primitives are copied, no aliases
2529 ClassDescriptor cdDst = tdDst.getClassDesc();
2530 if( cdDst == null && !tdDst.isArray() ) {
2534 // if the edge type is null, it matches everything
2535 TypeDescriptor tdEdge = edge.getType();
2536 if( tdEdge == null ) {
2540 return typeUtil.isSuperorType(tdEdge, tdDst);
2545 protected void unshadowTokens(AllocationSite as, ReferenceEdge edge) {
2546 edge.setBeta(edge.getBeta().unshadowTokens(as) );
2549 protected void unshadowTokens(AllocationSite as, HeapRegionNode hrn) {
2550 hrn.setAlpha(hrn.getAlpha().unshadowTokens(as) );
2554 private ReachabilitySet toShadowTokens(OwnershipGraph ogCallee,
2555 ReachabilitySet rsIn) {
2557 ReachabilitySet rsOut = new ReachabilitySet(rsIn).makeCanonical();
2559 Iterator<AllocationSite> allocItr = ogCallee.allocationSites.iterator();
2560 while( allocItr.hasNext() ) {
2561 AllocationSite as = allocItr.next();
2563 rsOut = rsOut.toShadowTokens(as);
2566 return rsOut.makeCanonical();
2570 private void rewriteCallerReachability(Integer paramIndex,
2573 ReachabilitySet rules,
2574 Hashtable<Integer, ReachabilitySet> paramIndex2rewrite_d,
2575 Hashtable<Integer, ReachabilitySet> paramIndex2rewriteD,
2577 Hashtable<TokenTuple, Integer> paramToken2paramIndex,
2578 Hashtable<TokenTuple, Integer> paramTokenPlus2paramIndex,
2579 Hashtable<TokenTuple, Integer> paramTokenStar2paramIndex,
2580 boolean makeChangeSet,
2581 Hashtable<ReferenceEdge, ChangeTupleSet> edgePlannedChanges) {
2583 assert(hrn == null && edge != null) ||
2584 (hrn != null && edge == null);
2586 assert rules != null;
2589 ReachabilitySet callerReachabilityCurrent;
2591 callerReachabilityCurrent = edge.getBeta();
2593 callerReachabilityCurrent = hrn.getAlpha();
2596 ReachabilitySet callerReachabilityNew = new ReachabilitySet().makeCanonical();
2598 // for initializing structures in this method
2599 TokenTupleSet ttsEmpty = new TokenTupleSet().makeCanonical();
2601 // use this to construct a change set if required; the idea is to
2602 // map every partially rewritten token tuple set to the set of
2603 // caller-context token tuple sets that were used to generate it
2604 Hashtable<TokenTupleSet, HashSet<TokenTupleSet> > rewritten2source =
2605 new Hashtable<TokenTupleSet, HashSet<TokenTupleSet> >();
2606 rewritten2source.put(ttsEmpty, new HashSet<TokenTupleSet>() );
2609 Iterator<TokenTupleSet> rulesItr = rules.iterator();
2610 while(rulesItr.hasNext()) {
2611 TokenTupleSet rule = rulesItr.next();
2613 ReachabilitySet rewrittenRule = new ReachabilitySet(ttsEmpty).makeCanonical();
2615 Iterator<TokenTuple> ruleItr = rule.iterator();
2616 while(ruleItr.hasNext()) {
2617 TokenTuple ttCallee = ruleItr.next();
2619 // compute the possibilities for rewriting this callee token
2620 ReachabilitySet ttCalleeRewrites = null;
2621 boolean callerSourceUsed = false;
2623 if( ttCallee.equals(p_i) ) {
2624 // replace the arity-one token of the current parameter with the reachability
2625 // information from the caller edge
2626 ttCalleeRewrites = callerReachabilityCurrent;
2627 callerSourceUsed = true;
2629 } else if( paramToken2paramIndex.containsKey(ttCallee) ) {
2631 Integer paramIndex_j = paramToken2paramIndex.get(ttCallee);
2632 assert paramIndex_j != null;
2633 ttCalleeRewrites = paramIndex2rewrite_d.get(paramIndex_j);
2634 assert ttCalleeRewrites != null;
2636 } else if( paramTokenPlus2paramIndex.containsKey(ttCallee) ) {
2638 Integer paramIndex_j = paramTokenPlus2paramIndex.get(ttCallee);
2639 assert paramIndex_j != null;
2640 ttCalleeRewrites = paramIndex2rewriteD.get(paramIndex_j);
2641 assert ttCalleeRewrites != null;
2643 } else if( paramTokenStar2paramIndex.containsKey(ttCallee) ) {
2645 Integer paramIndex_j = paramTokenStar2paramIndex.get(ttCallee);
2646 assert paramIndex_j != null;
2647 ttCalleeRewrites = paramIndex2rewriteD.get(paramIndex_j);
2648 assert ttCalleeRewrites != null;
2651 // otherwise there's no need for a rewrite, just pass this one on
2652 TokenTupleSet ttsCaller = new TokenTupleSet(ttCallee).makeCanonical();
2653 ttCalleeRewrites = new ReachabilitySet(ttsCaller).makeCanonical();
2656 // branch every version of the working rewritten rule with
2657 // the possibilities for rewriting the current callee token
2658 ReachabilitySet rewrittenRuleWithTTCallee = new ReachabilitySet().makeCanonical();
2660 Iterator<TokenTupleSet> rewrittenRuleItr = rewrittenRule.iterator();
2661 while( rewrittenRuleItr.hasNext() ) {
2662 TokenTupleSet ttsRewritten = rewrittenRuleItr.next();
2664 Iterator<TokenTupleSet> ttCalleeRewritesItr = ttCalleeRewrites.iterator();
2665 while( ttCalleeRewritesItr.hasNext() ) {
2666 TokenTupleSet ttsBranch = ttCalleeRewritesItr.next();
2668 TokenTupleSet ttsRewrittenNext = ttsRewritten.unionUpArity(ttsBranch);
2670 if( makeChangeSet ) {
2671 // in order to keep the list of source token tuple sets
2672 // start with the sets used to make the partially rewritten
2673 // rule up to this point
2674 HashSet<TokenTupleSet> sourceSets = rewritten2source.get(ttsRewritten);
2675 assert sourceSets != null;
2677 // make a shallow copy for possible modification
2678 sourceSets = (HashSet<TokenTupleSet>)sourceSets.clone();
2680 // if we used something from the caller to rewrite it, remember
2681 if( callerSourceUsed ) {
2682 sourceSets.add(ttsBranch);
2685 // set mapping for the further rewritten rule
2686 rewritten2source.put(ttsRewrittenNext, sourceSets);
2689 rewrittenRuleWithTTCallee =
2690 rewrittenRuleWithTTCallee.union(ttsRewrittenNext);
2694 // now the rewritten rule's possibilities have been extended by
2695 // rewriting the current callee token, remember result
2696 rewrittenRule = rewrittenRuleWithTTCallee;
2699 // the rule has been entirely rewritten into the caller context
2700 // now, so add it to the new reachability information
2701 callerReachabilityNew =
2702 callerReachabilityNew.union(rewrittenRule);
2705 if( makeChangeSet ) {
2706 ChangeTupleSet callerChangeSet = new ChangeTupleSet().makeCanonical();
2708 // each possibility for the final reachability should have a set of
2709 // caller sources mapped to it, use to create the change set
2710 Iterator<TokenTupleSet> callerReachabilityItr = callerReachabilityNew.iterator();
2711 while( callerReachabilityItr.hasNext() ) {
2712 TokenTupleSet ttsRewrittenFinal = callerReachabilityItr.next();
2713 HashSet<TokenTupleSet> sourceSets = rewritten2source.get(ttsRewrittenFinal);
2714 assert sourceSets != null;
2716 Iterator<TokenTupleSet> sourceSetsItr = sourceSets.iterator();
2717 while( sourceSetsItr.hasNext() ) {
2718 TokenTupleSet ttsSource = sourceSetsItr.next();
2721 callerChangeSet.union(new ChangeTuple(ttsSource, ttsRewrittenFinal) );
2725 assert edgePlannedChanges != null;
2726 edgePlannedChanges.put(edge, callerChangeSet);
2730 edge.setBetaNew(edge.getBetaNew().union(callerReachabilityNew) );
2732 hrn.setAlphaNew(hrn.getAlphaNew().union(callerReachabilityNew) );
2738 private HashSet<HeapRegionNode>
2739 getHRNSetThatPossiblyMapToCalleeHRN(OwnershipGraph ogCallee,
2740 HeapRegionNode hrnCallee,
2741 Hashtable<Integer, HashSet<HeapRegionNode> > paramIndex2reachableCallerNodes
2744 HashSet<HeapRegionNode> possibleCallerHRNs = new HashSet<HeapRegionNode>();
2746 Set<Integer> paramIndicesCallee = ogCallee.id2paramIndexSet.get( hrnCallee.getID() );
2748 if( paramIndicesCallee == null ) {
2749 // this is a node allocated in the callee then and it has
2750 // exactly one shadow node in the caller to map to
2751 AllocationSite as = hrnCallee.getAllocationSite();
2754 int age = as.getAgeCategory(hrnCallee.getID() );
2755 assert age != AllocationSite.AGE_notInThisSite;
2758 if( age == AllocationSite.AGE_summary ) {
2759 idCaller = as.getSummaryShadow();
2760 } else if( age == AllocationSite.AGE_oldest ) {
2761 idCaller = as.getOldestShadow();
2763 assert age == AllocationSite.AGE_in_I;
2765 Integer I = as.getAge(hrnCallee.getID() );
2768 idCaller = as.getIthOldestShadow(I);
2771 assert id2hrn.containsKey(idCaller);
2772 HeapRegionNode hrnCaller = id2hrn.get(idCaller);
2773 possibleCallerHRNs.add(hrnCaller);
2776 // this is a node that was created to represent a parameter
2777 // so it maps to a whole mess of heap regions
2778 Iterator<Integer> itrIndex = paramIndicesCallee.iterator();
2779 while( itrIndex.hasNext() ) {
2780 Integer paramIndexCallee = itrIndex.next();
2781 assert paramIndex2reachableCallerNodes.containsKey(paramIndexCallee);
2782 possibleCallerHRNs.addAll( paramIndex2reachableCallerNodes.get(paramIndexCallee) );
2786 return possibleCallerHRNs;
2788 return new HashSet<HeapRegionNode>();
2793 ////////////////////////////////////////////////////
2795 // This global sweep is an optional step to prune
2796 // reachability sets that are not internally
2797 // consistent with the global graph. It should be
2798 // invoked after strong updates or method calls.
2800 ////////////////////////////////////////////////////
2801 public void globalSweep() {
2803 // boldB is part of the phase 1 sweep
2804 Hashtable< Integer, Hashtable<ReferenceEdge, ReachabilitySet> > boldB =
2805 new Hashtable< Integer, Hashtable<ReferenceEdge, ReachabilitySet> >();
2807 // visit every heap region to initialize alphaNew and calculate boldB
2808 Set hrns = id2hrn.entrySet();
2809 Iterator itrHrns = hrns.iterator();
2810 while( itrHrns.hasNext() ) {
2811 Map.Entry me = (Map.Entry)itrHrns.next();
2812 Integer token = (Integer) me.getKey();
2813 HeapRegionNode hrn = (HeapRegionNode) me.getValue();
2815 // assert that this node and incoming edges have clean alphaNew
2816 // and betaNew sets, respectively
2817 ReachabilitySet rsEmpty = new ReachabilitySet().makeCanonical();
2818 assert rsEmpty.equals( hrn.getAlphaNew() );
2820 Iterator<ReferenceEdge> itrRers = hrn.iteratorToReferencers();
2821 while( itrRers.hasNext() ) {
2822 ReferenceEdge edge = itrRers.next();
2823 assert rsEmpty.equals( edge.getBetaNew() );
2826 // calculate boldB for this flagged node
2827 if( hrn.isFlagged() || hrn.isParameter() ) {
2829 Hashtable<ReferenceEdge, ReachabilitySet> boldB_f =
2830 new Hashtable<ReferenceEdge, ReachabilitySet>();
2832 Set<ReferenceEdge> workSetEdges = new HashSet<ReferenceEdge>();
2834 // initial boldB_f constraints
2835 Iterator<ReferenceEdge> itrRees = hrn.iteratorToReferencees();
2836 while( itrRees.hasNext() ) {
2837 ReferenceEdge edge = itrRees.next();
2839 assert !boldB.containsKey( edge );
2840 boldB_f.put( edge, edge.getBeta() );
2842 assert !workSetEdges.contains( edge );
2843 workSetEdges.add( edge );
2846 // enforce the boldB_f constraint at edges until we reach a fixed point
2847 while( !workSetEdges.isEmpty() ) {
2848 ReferenceEdge edge = workSetEdges.iterator().next();
2849 workSetEdges.remove( edge );
2851 Iterator<ReferenceEdge> itrPrime = edge.getDst().iteratorToReferencees();
2852 while( itrPrime.hasNext() ) {
2853 ReferenceEdge edgePrime = itrPrime.next();
2855 ReachabilitySet prevResult = boldB_f.get( edgePrime );
2856 ReachabilitySet intersection = boldB_f.get( edge ).intersection( edgePrime.getBeta() );
2858 if( prevResult == null ||
2859 prevResult.union( intersection ).size() > prevResult.size() ) {
2861 if( prevResult == null ) {
2862 boldB_f.put( edgePrime, edgePrime.getBeta().union( intersection ) );
2864 boldB_f.put( edgePrime, prevResult.union( intersection ) );
2866 workSetEdges.add( edgePrime );
2871 boldB.put( token, boldB_f );
2876 // use boldB to prune tokens from alpha states that are impossible
2877 // and propagate the differences backwards across edges
2878 HashSet<ReferenceEdge> edgesForPropagation = new HashSet<ReferenceEdge>();
2880 Hashtable<ReferenceEdge, ChangeTupleSet> edgePlannedChanges =
2881 new Hashtable<ReferenceEdge, ChangeTupleSet>();
2883 hrns = id2hrn.entrySet();
2884 itrHrns = hrns.iterator();
2885 while( itrHrns.hasNext() ) {
2886 Map.Entry me = (Map.Entry)itrHrns.next();
2887 Integer token = (Integer) me.getKey();
2888 HeapRegionNode hrn = (HeapRegionNode) me.getValue();
2890 // never remove the identity token from a flagged region
2891 // because it is trivially satisfied
2892 TokenTuple ttException = new TokenTuple( token, !hrn.isSingleObject(), TokenTuple.ARITY_ONE ).makeCanonical();
2894 ChangeTupleSet cts = new ChangeTupleSet().makeCanonical();
2896 // mark tokens for removal
2897 Iterator<TokenTupleSet> stateItr = hrn.getAlpha().iterator();
2898 while( stateItr.hasNext() ) {
2899 TokenTupleSet ttsOld = stateItr.next();
2901 TokenTupleSet markedTokens = new TokenTupleSet().makeCanonical();
2903 Iterator<TokenTuple> ttItr = ttsOld.iterator();
2904 while( ttItr.hasNext() ) {
2905 TokenTuple ttOld = ttItr.next();
2907 // never remove the identity token from a flagged region
2908 // because it is trivially satisfied
2909 if( hrn.isFlagged() || hrn.isParameter() ) {
2910 if( ttOld == ttException ) {
2915 // does boldB_ttOld allow this token?
2916 boolean foundState = false;
2917 Iterator<ReferenceEdge> incidentEdgeItr = hrn.iteratorToReferencers();
2918 while( incidentEdgeItr.hasNext() ) {
2919 ReferenceEdge incidentEdge = incidentEdgeItr.next();
2921 // if it isn't allowed, mark for removal
2922 ReachabilitySet boldB_ttOld_incident = boldB.get( ttOld.getToken() ).get( incidentEdge );
2923 if( boldB_ttOld_incident != null &&
2924 boldB_ttOld_incident.contains( ttsOld ) ) {
2930 markedTokens = markedTokens.add( ttOld );
2934 // if there is nothing marked, just move on
2935 if( markedTokens.isEmpty() ) {
2936 hrn.setAlphaNew( hrn.getAlphaNew().union( ttsOld ) );
2940 // remove all marked tokens and establish a change set that should
2941 // propagate backwards over edges from this node
2942 TokenTupleSet ttsPruned = new TokenTupleSet().makeCanonical();
2943 ttItr = ttsOld.iterator();
2944 while( ttItr.hasNext() ) {
2945 TokenTuple ttOld = ttItr.next();
2947 if( !markedTokens.containsTuple( ttOld ) ) {
2948 ttsPruned = ttsPruned.union( ttOld );
2951 assert !ttsOld.equals( ttsPruned );
2953 hrn.setAlphaNew( hrn.getAlphaNew().union( ttsPruned ) );
2954 ChangeTuple ct = new ChangeTuple( ttsOld, ttsPruned ).makeCanonical();
2955 cts = cts.union( ct );
2958 // throw change tuple set on all incident edges
2959 if( !cts.isEmpty() ) {
2960 Iterator<ReferenceEdge> incidentEdgeItr = hrn.iteratorToReferencers();
2961 while( incidentEdgeItr.hasNext() ) {
2962 ReferenceEdge incidentEdge = incidentEdgeItr.next();
2964 edgesForPropagation.add( incidentEdge );
2966 if( edgePlannedChanges.get( incidentEdge ) == null ) {
2967 edgePlannedChanges.put( incidentEdge, cts );
2969 edgePlannedChanges.put(
2971 edgePlannedChanges.get( incidentEdge ).union( cts )
2978 HashSet<ReferenceEdge> edgesUpdated = new HashSet<ReferenceEdge>();
2980 propagateTokensOverEdges( edgesForPropagation,
2984 // at the end of the 1st phase reference edges have
2985 // beta, betaNew that correspond to beta and betaR
2987 // commit beta<-betaNew, so beta=betaR and betaNew
2988 // will represent the beta' calculation in 2nd phase
2990 // commit alpha<-alphaNew because it won't change
2991 HashSet<ReferenceEdge> res = new HashSet<ReferenceEdge>();
2993 Iterator<HeapRegionNode> nodeItr = id2hrn.values().iterator();
2994 while( nodeItr.hasNext() ) {
2995 HeapRegionNode hrn = nodeItr.next();
2996 hrn.applyAlphaNew();
2997 Iterator<ReferenceEdge> itrRes = hrn.iteratorToReferencers();
2998 while( itrRes.hasNext() ) {
2999 res.add( itrRes.next() );
3005 Iterator<ReferenceEdge> edgeItr = res.iterator();
3006 while( edgeItr.hasNext() ) {
3007 ReferenceEdge edge = edgeItr.next();
3008 HeapRegionNode hrn = edge.getDst();
3010 // commit results of last phase
3011 if( edgesUpdated.contains( edge ) ) {
3012 edge.applyBetaNew();
3015 // compute intial condition of 2nd phase
3016 edge.setBetaNew( edge.getBeta().intersection( hrn.getAlpha() ) );
3019 // every edge in the graph is the initial workset
3020 Set<ReferenceEdge> edgeWorkSet = (Set) res.clone();
3021 while( !edgeWorkSet.isEmpty() ) {
3022 ReferenceEdge edgePrime = edgeWorkSet.iterator().next();
3023 edgeWorkSet.remove( edgePrime );
3025 OwnershipNode on = edgePrime.getSrc();
3026 if( !(on instanceof HeapRegionNode) ) {
3029 HeapRegionNode hrn = (HeapRegionNode) on;
3031 Iterator<ReferenceEdge> itrEdge = hrn.iteratorToReferencers();
3032 while( itrEdge.hasNext() ) {
3033 ReferenceEdge edge = itrEdge.next();
3035 ReachabilitySet prevResult = edge.getBetaNew();
3036 assert prevResult != null;
3038 ReachabilitySet intersection = edge.getBeta().intersection( edgePrime.getBetaNew() );
3040 if( prevResult.union( intersection ).size() > prevResult.size() ) {
3041 edge.setBetaNew( prevResult.union( intersection ) );
3042 edgeWorkSet.add( edge );
3047 // commit beta' (beta<-betaNew)
3048 edgeItr = res.iterator();
3049 while( edgeItr.hasNext() ) {
3050 edgeItr.next().applyBetaNew();
3056 ////////////////////////////////////////////////////
3057 // in merge() and equals() methods the suffix A
3058 // represents the passed in graph and the suffix
3059 // B refers to the graph in this object
3060 // Merging means to take the incoming graph A and
3061 // merge it into B, so after the operation graph B
3062 // is the final result.
3063 ////////////////////////////////////////////////////
3064 public void merge(OwnershipGraph og) {
3070 mergeOwnershipNodes(og);
3071 mergeReferenceEdges(og);
3072 mergeParamIndexMappings(og);
3073 mergeAllocationSites(og);
3077 protected void mergeOwnershipNodes(OwnershipGraph og) {
3078 Set sA = og.id2hrn.entrySet();
3079 Iterator iA = sA.iterator();
3080 while( iA.hasNext() ) {
3081 Map.Entry meA = (Map.Entry)iA.next();
3082 Integer idA = (Integer) meA.getKey();
3083 HeapRegionNode hrnA = (HeapRegionNode) meA.getValue();
3085 // if this graph doesn't have a node the
3086 // incoming graph has, allocate it
3087 if( !id2hrn.containsKey(idA) ) {
3088 HeapRegionNode hrnB = hrnA.copy();
3089 id2hrn.put(idA, hrnB);
3092 // otherwise this is a node present in both graphs
3093 // so make the new reachability set a union of the
3094 // nodes' reachability sets
3095 HeapRegionNode hrnB = id2hrn.get(idA);
3096 hrnB.setAlpha(hrnB.getAlpha().union(hrnA.getAlpha() ) );
3100 // now add any label nodes that are in graph B but
3102 sA = og.td2ln.entrySet();
3104 while( iA.hasNext() ) {
3105 Map.Entry meA = (Map.Entry)iA.next();
3106 TempDescriptor tdA = (TempDescriptor) meA.getKey();
3107 LabelNode lnA = (LabelNode) meA.getValue();
3109 // if the label doesn't exist in B, allocate and add it
3110 LabelNode lnB = getLabelNodeFromTemp(tdA);
3114 protected void mergeReferenceEdges(OwnershipGraph og) {
3117 Set sA = og.id2hrn.entrySet();
3118 Iterator iA = sA.iterator();
3119 while( iA.hasNext() ) {
3120 Map.Entry meA = (Map.Entry)iA.next();
3121 Integer idA = (Integer) meA.getKey();
3122 HeapRegionNode hrnA = (HeapRegionNode) meA.getValue();
3124 Iterator<ReferenceEdge> heapRegionsItrA = hrnA.iteratorToReferencees();
3125 while( heapRegionsItrA.hasNext() ) {
3126 ReferenceEdge edgeA = heapRegionsItrA.next();
3127 HeapRegionNode hrnChildA = edgeA.getDst();
3128 Integer idChildA = hrnChildA.getID();
3130 // at this point we know an edge in graph A exists
3131 // idA -> idChildA, does this exist in B?
3132 assert id2hrn.containsKey(idA);
3133 HeapRegionNode hrnB = id2hrn.get(idA);
3134 ReferenceEdge edgeToMerge = null;
3136 Iterator<ReferenceEdge> heapRegionsItrB = hrnB.iteratorToReferencees();
3137 while( heapRegionsItrB.hasNext() &&
3138 edgeToMerge == null ) {
3140 ReferenceEdge edgeB = heapRegionsItrB.next();
3141 HeapRegionNode hrnChildB = edgeB.getDst();
3142 Integer idChildB = hrnChildB.getID();
3144 // don't use the ReferenceEdge.equals() here because
3145 // we're talking about existence between graphs
3146 if( idChildB.equals( idChildA ) &&
3147 edgeB.typeAndFieldEquals( edgeA ) ) {
3149 edgeToMerge = edgeB;
3153 // if the edge from A was not found in B,
3155 if( edgeToMerge == null ) {
3156 assert id2hrn.containsKey(idChildA);
3157 HeapRegionNode hrnChildB = id2hrn.get(idChildA);
3158 edgeToMerge = edgeA.copy();
3159 edgeToMerge.setSrc(hrnB);
3160 edgeToMerge.setDst(hrnChildB);
3161 addReferenceEdge(hrnB, hrnChildB, edgeToMerge);
3163 // otherwise, the edge already existed in both graphs
3164 // so merge their reachability sets
3166 // just replace this beta set with the union
3167 assert edgeToMerge != null;
3168 edgeToMerge.setBeta(
3169 edgeToMerge.getBeta().union(edgeA.getBeta() )
3171 if( !edgeA.isInitialParam() ) {
3172 edgeToMerge.setIsInitialParam(false);
3178 // and then again with label nodes
3179 sA = og.td2ln.entrySet();
3181 while( iA.hasNext() ) {
3182 Map.Entry meA = (Map.Entry)iA.next();
3183 TempDescriptor tdA = (TempDescriptor) meA.getKey();
3184 LabelNode lnA = (LabelNode) meA.getValue();
3186 Iterator<ReferenceEdge> heapRegionsItrA = lnA.iteratorToReferencees();
3187 while( heapRegionsItrA.hasNext() ) {
3188 ReferenceEdge edgeA = heapRegionsItrA.next();
3189 HeapRegionNode hrnChildA = edgeA.getDst();
3190 Integer idChildA = hrnChildA.getID();
3192 // at this point we know an edge in graph A exists
3193 // tdA -> idChildA, does this exist in B?
3194 assert td2ln.containsKey(tdA);
3195 LabelNode lnB = td2ln.get(tdA);
3196 ReferenceEdge edgeToMerge = null;
3198 Iterator<ReferenceEdge> heapRegionsItrB = lnB.iteratorToReferencees();
3199 while( heapRegionsItrB.hasNext() &&
3200 edgeToMerge == null ) {
3202 ReferenceEdge edgeB = heapRegionsItrB.next();
3203 HeapRegionNode hrnChildB = edgeB.getDst();
3204 Integer idChildB = hrnChildB.getID();
3206 // don't use the ReferenceEdge.equals() here because
3207 // we're talking about existence between graphs
3208 if( idChildB.equals( idChildA ) &&
3209 edgeB.typeAndFieldEquals( edgeA ) ) {
3211 edgeToMerge = edgeB;
3215 // if the edge from A was not found in B,
3217 if( edgeToMerge == null ) {
3218 assert id2hrn.containsKey(idChildA);
3219 HeapRegionNode hrnChildB = id2hrn.get(idChildA);
3220 edgeToMerge = edgeA.copy();
3221 edgeToMerge.setSrc(lnB);
3222 edgeToMerge.setDst(hrnChildB);
3223 addReferenceEdge(lnB, hrnChildB, edgeToMerge);
3225 // otherwise, the edge already existed in both graphs
3226 // so merge their reachability sets
3228 // just replace this beta set with the union
3229 edgeToMerge.setBeta(
3230 edgeToMerge.getBeta().union(edgeA.getBeta() )
3232 if( !edgeA.isInitialParam() ) {
3233 edgeToMerge.setIsInitialParam(false);
3240 // you should only merge ownership graphs that have the
3241 // same number of parameters, or if one or both parameter
3242 // index tables are empty
3243 protected void mergeParamIndexMappings(OwnershipGraph og) {
3245 if( idPrimary2paramIndexSet.size() == 0 ) {
3247 idPrimary2paramIndexSet = og.idPrimary2paramIndexSet;
3248 paramIndex2idPrimary = og.paramIndex2idPrimary;
3250 idSecondary2paramIndexSet = og.idSecondary2paramIndexSet;
3251 paramIndex2idSecondary = og.paramIndex2idSecondary;
3253 paramIndex2tdQ = og.paramIndex2tdQ;
3254 paramIndex2tdR = og.paramIndex2tdR;
3256 paramTokenPrimary2paramIndex = og.paramTokenPrimary2paramIndex;
3257 paramIndex2paramTokenPrimary = og.paramIndex2paramTokenPrimary;
3258 paramTokenPrimaryPlus2paramIndex = og.paramTokenPrimaryPlus2paramIndex;
3259 paramIndex2paramTokenPrimaryPlus = og.paramIndex2paramTokenPrimaryPlus;
3260 paramTokenPrimaryStar2paramIndex = og.paramTokenPrimaryStar2paramIndex;
3261 paramIndex2paramTokenPrimaryStar = og.paramIndex2paramTokenPrimaryStar;
3263 paramTokenSecondary2paramIndex = og.paramTokenSecondary2paramIndex;
3264 paramIndex2paramTokenSecondary = og.paramIndex2paramTokenSecondary;
3265 paramTokenSecondaryPlus2paramIndex = og.paramTokenSecondaryPlus2paramIndex;
3266 paramIndex2paramTokenSecondaryPlus = og.paramIndex2paramTokenSecondaryPlus;
3267 paramTokenSecondaryStar2paramIndex = og.paramTokenSecondaryStar2paramIndex;
3268 paramIndex2paramTokenSecondaryStar = og.paramIndex2paramTokenSecondaryStar;
3273 if( og.idPrimary2paramIndexSet.size() == 0 ) {
3277 assert idPrimary2paramIndexSet.size() == og.idPrimary2paramIndexSet.size();
3278 assert idSecondary2paramIndexSet.size() == og.idSecondary2paramIndexSet.size();
3281 protected void mergeAllocationSites(OwnershipGraph og) {
3282 allocationSites.addAll(og.allocationSites);
3287 // it is necessary in the equals() member functions
3288 // to "check both ways" when comparing the data
3289 // structures of two graphs. For instance, if all
3290 // edges between heap region nodes in graph A are
3291 // present and equal in graph B it is not sufficient
3292 // to say the graphs are equal. Consider that there
3293 // may be edges in graph B that are not in graph A.
3294 // the only way to know that all edges in both graphs
3295 // are equally present is to iterate over both data
3296 // structures and compare against the other graph.
3297 public boolean equals(OwnershipGraph og) {
3303 if( !areHeapRegionNodesEqual(og) ) {
3307 if( !areLabelNodesEqual(og) ) {
3311 if( !areReferenceEdgesEqual(og) ) {
3315 if( !areParamIndexMappingsEqual(og) ) {
3319 // if everything is equal up to this point,
3320 // assert that allocationSites is also equal--
3321 // this data is redundant and kept for efficiency
3322 assert allocationSites.equals(og.allocationSites);
3327 protected boolean areHeapRegionNodesEqual(OwnershipGraph og) {
3329 if( !areallHRNinAalsoinBandequal(this, og) ) {
3333 if( !areallHRNinAalsoinBandequal(og, this) ) {
3340 static protected boolean areallHRNinAalsoinBandequal(OwnershipGraph ogA,
3341 OwnershipGraph ogB) {
3342 Set sA = ogA.id2hrn.entrySet();
3343 Iterator iA = sA.iterator();
3344 while( iA.hasNext() ) {
3345 Map.Entry meA = (Map.Entry)iA.next();
3346 Integer idA = (Integer) meA.getKey();
3347 HeapRegionNode hrnA = (HeapRegionNode) meA.getValue();
3349 if( !ogB.id2hrn.containsKey(idA) ) {
3353 HeapRegionNode hrnB = ogB.id2hrn.get(idA);
3354 if( !hrnA.equalsIncludingAlpha(hrnB) ) {
3363 protected boolean areLabelNodesEqual(OwnershipGraph og) {
3365 if( !areallLNinAalsoinBandequal(this, og) ) {
3369 if( !areallLNinAalsoinBandequal(og, this) ) {
3376 static protected boolean areallLNinAalsoinBandequal(OwnershipGraph ogA,
3377 OwnershipGraph ogB) {
3378 Set sA = ogA.td2ln.entrySet();
3379 Iterator iA = sA.iterator();
3380 while( iA.hasNext() ) {
3381 Map.Entry meA = (Map.Entry)iA.next();
3382 TempDescriptor tdA = (TempDescriptor) meA.getKey();
3384 if( !ogB.td2ln.containsKey(tdA) ) {
3393 protected boolean areReferenceEdgesEqual(OwnershipGraph og) {
3394 if( !areallREinAandBequal(this, og) ) {
3401 static protected boolean areallREinAandBequal(OwnershipGraph ogA,
3402 OwnershipGraph ogB) {
3404 // check all the heap region->heap region edges
3405 Set sA = ogA.id2hrn.entrySet();
3406 Iterator iA = sA.iterator();
3407 while( iA.hasNext() ) {
3408 Map.Entry meA = (Map.Entry)iA.next();
3409 Integer idA = (Integer) meA.getKey();
3410 HeapRegionNode hrnA = (HeapRegionNode) meA.getValue();
3412 // we should have already checked that the same
3413 // heap regions exist in both graphs
3414 assert ogB.id2hrn.containsKey(idA);
3416 if( !areallREfromAequaltoB(ogA, hrnA, ogB) ) {
3420 // then check every edge in B for presence in A, starting
3421 // from the same parent HeapRegionNode
3422 HeapRegionNode hrnB = ogB.id2hrn.get(idA);
3424 if( !areallREfromAequaltoB(ogB, hrnB, ogA) ) {
3429 // then check all the label->heap region edges
3430 sA = ogA.td2ln.entrySet();
3432 while( iA.hasNext() ) {
3433 Map.Entry meA = (Map.Entry)iA.next();
3434 TempDescriptor tdA = (TempDescriptor) meA.getKey();
3435 LabelNode lnA = (LabelNode) meA.getValue();
3437 // we should have already checked that the same
3438 // label nodes exist in both graphs
3439 assert ogB.td2ln.containsKey(tdA);
3441 if( !areallREfromAequaltoB(ogA, lnA, ogB) ) {
3445 // then check every edge in B for presence in A, starting
3446 // from the same parent LabelNode
3447 LabelNode lnB = ogB.td2ln.get(tdA);
3449 if( !areallREfromAequaltoB(ogB, lnB, ogA) ) {
3458 static protected boolean areallREfromAequaltoB(OwnershipGraph ogA,
3460 OwnershipGraph ogB) {
3462 Iterator<ReferenceEdge> itrA = onA.iteratorToReferencees();
3463 while( itrA.hasNext() ) {
3464 ReferenceEdge edgeA = itrA.next();
3465 HeapRegionNode hrnChildA = edgeA.getDst();
3466 Integer idChildA = hrnChildA.getID();
3468 assert ogB.id2hrn.containsKey(idChildA);
3470 // at this point we know an edge in graph A exists
3471 // onA -> idChildA, does this exact edge exist in B?
3472 boolean edgeFound = false;
3474 OwnershipNode onB = null;
3475 if( onA instanceof HeapRegionNode ) {
3476 HeapRegionNode hrnA = (HeapRegionNode) onA;
3477 onB = ogB.id2hrn.get(hrnA.getID() );
3479 LabelNode lnA = (LabelNode) onA;
3480 onB = ogB.td2ln.get(lnA.getTempDescriptor() );
3483 Iterator<ReferenceEdge> itrB = onB.iteratorToReferencees();
3484 while( itrB.hasNext() ) {
3485 ReferenceEdge edgeB = itrB.next();
3486 HeapRegionNode hrnChildB = edgeB.getDst();
3487 Integer idChildB = hrnChildB.getID();
3489 if( idChildA.equals( idChildB ) &&
3490 edgeA.typeAndFieldEquals( edgeB ) ) {
3492 // there is an edge in the right place with the right field,
3493 // but do they have the same attributes?
3494 if( edgeA.getBeta().equals(edgeB.getBeta() ) ) {
3509 protected boolean areParamIndexMappingsEqual(OwnershipGraph og) {
3511 if( idPrimary2paramIndexSet.size() != og.idPrimary2paramIndexSet.size() ) {
3515 if( idSecondary2paramIndexSet.size() != og.idSecondary2paramIndexSet.size() ) {
3523 public Set<HeapRegionNode> hasPotentialAlias( HeapRegionNode hrn1, HeapRegionNode hrn2 ) {
3525 assert hrn1 != null;
3526 assert hrn2 != null;
3528 // then get the various tokens for these heap regions
3529 TokenTuple h1 = new TokenTuple(hrn1.getID(),
3530 !hrn1.isSingleObject(),
3531 TokenTuple.ARITY_ONE).makeCanonical();
3533 TokenTuple h1plus = new TokenTuple(hrn1.getID(),
3534 !hrn1.isSingleObject(),
3535 TokenTuple.ARITY_ONEORMORE).makeCanonical();
3537 TokenTuple h1star = new TokenTuple(hrn1.getID(),
3538 !hrn1.isSingleObject(),
3539 TokenTuple.ARITY_ZEROORMORE).makeCanonical();
3541 TokenTuple h2 = new TokenTuple(hrn2.getID(),
3542 !hrn2.isSingleObject(),
3543 TokenTuple.ARITY_ONE).makeCanonical();
3545 TokenTuple h2plus = new TokenTuple(hrn2.getID(),
3546 !hrn2.isSingleObject(),
3547 TokenTuple.ARITY_ONEORMORE).makeCanonical();
3549 TokenTuple h2star = new TokenTuple(hrn2.getID(),
3550 !hrn2.isSingleObject(),
3551 TokenTuple.ARITY_ZEROORMORE).makeCanonical();
3553 // then get the merged beta of all out-going edges from these heap regions
3554 ReachabilitySet beta1 = new ReachabilitySet();
3555 Iterator<ReferenceEdge> itrEdge = hrn1.iteratorToReferencees();
3556 while( itrEdge.hasNext() ) {
3557 ReferenceEdge edge = itrEdge.next();
3558 beta1 = beta1.union( edge.getBeta() );
3561 ReachabilitySet beta2 = new ReachabilitySet();
3562 itrEdge = hrn2.iteratorToReferencees();
3563 while( itrEdge.hasNext() ) {
3564 ReferenceEdge edge = itrEdge.next();
3565 beta2 = beta2.union( edge.getBeta() );
3568 boolean aliasDetected = false;
3570 // only do this one if they are different tokens
3572 beta1.containsTupleSetWithBoth(h1, h2) ) {
3573 aliasDetected = true;
3575 if( beta1.containsTupleSetWithBoth(h1plus, h2) ) {
3576 aliasDetected = true;
3578 if( beta1.containsTupleSetWithBoth(h1star, h2) ) {
3579 aliasDetected = true;
3581 if( beta1.containsTupleSetWithBoth(h1, h2plus) ) {
3582 aliasDetected = true;
3584 if( beta1.containsTupleSetWithBoth(h1plus, h2plus) ) {
3585 aliasDetected = true;
3587 if( beta1.containsTupleSetWithBoth(h1star, h2plus) ) {
3588 aliasDetected = true;
3590 if( beta1.containsTupleSetWithBoth(h1, h2star) ) {
3591 aliasDetected = true;
3593 if( beta1.containsTupleSetWithBoth(h1plus, h2star) ) {
3594 aliasDetected = true;
3596 if( beta1.containsTupleSetWithBoth(h1star, h2star) ) {
3597 aliasDetected = true;
3601 beta2.containsTupleSetWithBoth(h1, h2) ) {
3602 aliasDetected = true;
3604 if( beta2.containsTupleSetWithBoth(h1plus, h2) ) {
3605 aliasDetected = true;
3607 if( beta2.containsTupleSetWithBoth(h1star, h2) ) {
3608 aliasDetected = true;
3610 if( beta2.containsTupleSetWithBoth(h1, h2plus) ) {
3611 aliasDetected = true;
3613 if( beta2.containsTupleSetWithBoth(h1plus, h2plus) ) {
3614 aliasDetected = true;
3616 if( beta2.containsTupleSetWithBoth(h1star, h2plus) ) {
3617 aliasDetected = true;
3619 if( beta2.containsTupleSetWithBoth(h1, h2star) ) {
3620 aliasDetected = true;
3622 if( beta2.containsTupleSetWithBoth(h1plus, h2star) ) {
3623 aliasDetected = true;
3625 if( beta2.containsTupleSetWithBoth(h1star, h2star) ) {
3626 aliasDetected = true;
3629 Set<HeapRegionNode> common = new HashSet<HeapRegionNode>();
3630 if( aliasDetected ) {
3631 common = findCommonReachableNodes( hrn1, hrn2 );
3632 assert !common.isEmpty();
3637 return new HashSet<HeapRegionNode>();
3641 public Set<HeapRegionNode> hasPotentialAlias(Integer paramIndex1, Integer paramIndex2) {
3643 // get parameter's heap region
3644 assert paramIndex2id.containsKey(paramIndex1);
3645 Integer idParam1 = paramIndex2id.get(paramIndex1);
3647 assert id2hrn.containsKey(idParam1);
3648 HeapRegionNode hrnParam1 = id2hrn.get(idParam1);
3649 assert hrnParam1 != null;
3652 // get tokens for the other parameter
3653 assert paramIndex2id.containsKey(paramIndex2);
3654 Integer idParam2 = paramIndex2id.get(paramIndex2);
3656 assert id2hrn.containsKey(idParam2);
3657 HeapRegionNode hrnParam2 = id2hrn.get(idParam2);
3658 assert hrnParam2 != null;
3660 return hasPotentialAlias( hrnParam1, hrnParam2 );
3662 return new HashSet<HeapRegionNode>();
3666 public Set<HeapRegionNode> hasPotentialAlias(Integer paramIndex, AllocationSite as) {
3668 // get parameter's heap region
3669 assert paramIndex2id.containsKey(paramIndex);
3670 Integer idParam = paramIndex2id.get(paramIndex);
3672 assert id2hrn.containsKey(idParam);
3673 HeapRegionNode hrnParam = id2hrn.get(idParam);
3674 assert hrnParam != null;
3677 assert id2hrn.containsKey( as.getSummary() );
3678 HeapRegionNode hrnSummary = id2hrn.get( as.getSummary() );
3679 assert hrnSummary != null;
3681 Set<HeapRegionNode> common = hasPotentialAlias( hrnParam, hrnSummary );
3682 if( !common.isEmpty() ) {
3686 // check for other nodes
3687 for( int i = 0; i < as.getAllocationDepth(); ++i ) {
3689 assert id2hrn.containsKey( as.getIthOldest( i ) );
3690 HeapRegionNode hrnIthOldest = id2hrn.get( as.getIthOldest( i ) );
3691 assert hrnIthOldest != null;
3693 common = hasPotentialAlias( hrnParam, hrnIthOldest );
3694 if( !common.isEmpty() ) {
3699 return new HashSet<HeapRegionNode>();
3703 public Set<HeapRegionNode> hasPotentialAlias(AllocationSite as1, AllocationSite as2) {
3705 // get summary node 1's alpha
3706 Integer idSum1 = as1.getSummary();
3707 assert id2hrn.containsKey(idSum1);
3708 HeapRegionNode hrnSum1 = id2hrn.get(idSum1);
3709 assert hrnSum1 != null;
3711 // get summary node 2's alpha
3712 Integer idSum2 = as2.getSummary();
3713 assert id2hrn.containsKey(idSum2);
3714 HeapRegionNode hrnSum2 = id2hrn.get(idSum2);
3715 assert hrnSum2 != null;
3717 Set<HeapRegionNode> common = hasPotentialAlias( hrnSum1, hrnSum2 );
3718 if( !common.isEmpty() ) {
3722 // check sum2 against alloc1 nodes
3723 for( int i = 0; i < as1.getAllocationDepth(); ++i ) {
3724 Integer idI1 = as1.getIthOldest(i);
3725 assert id2hrn.containsKey(idI1);
3726 HeapRegionNode hrnI1 = id2hrn.get(idI1);
3727 assert hrnI1 != null;
3729 common = hasPotentialAlias( hrnI1, hrnSum2 );
3730 if( !common.isEmpty() ) {
3735 // check sum1 against alloc2 nodes
3736 for( int i = 0; i < as2.getAllocationDepth(); ++i ) {
3737 Integer idI2 = as2.getIthOldest(i);
3738 assert id2hrn.containsKey(idI2);
3739 HeapRegionNode hrnI2 = id2hrn.get(idI2);
3740 assert hrnI2 != null;
3742 common = hasPotentialAlias( hrnSum1, hrnI2 );
3743 if( common.isEmpty() ) {
3747 // while we're at it, do an inner loop for alloc2 vs alloc1 nodes
3748 for( int j = 0; j < as1.getAllocationDepth(); ++j ) {
3749 Integer idI1 = as1.getIthOldest(j);
3751 // if these are the same site, don't look for the same token, no alias.
3752 // different tokens of the same site could alias together though
3753 if( idI1.equals( idI2 ) ) {
3757 HeapRegionNode hrnI1 = id2hrn.get(idI1);
3759 common = hasPotentialAlias( hrnI1, hrnI2 );
3760 if( !common.isEmpty() ) {
3766 return new HashSet<HeapRegionNode>();
3770 public Set<HeapRegionNode> findCommonReachableNodes( HeapRegionNode hrn1,
3771 HeapRegionNode hrn2 ) {
3772 //assert hrn1 != hrn2;
3774 Set<HeapRegionNode> reachableNodes1 = new HashSet<HeapRegionNode>();
3775 Set<HeapRegionNode> reachableNodes2 = new HashSet<HeapRegionNode>();
3777 Set<HeapRegionNode> todoNodes1 = new HashSet<HeapRegionNode>();
3778 todoNodes1.add( hrn1 );
3780 Set<HeapRegionNode> todoNodes2 = new HashSet<HeapRegionNode>();
3781 todoNodes2.add( hrn2 );
3783 // follow links until all reachable nodes have been found
3784 while( !todoNodes1.isEmpty() ) {
3785 HeapRegionNode hrn = todoNodes1.iterator().next();
3786 todoNodes1.remove( hrn );
3787 reachableNodes1.add(hrn);
3789 Iterator<ReferenceEdge> edgeItr = hrn.iteratorToReferencees();
3790 while( edgeItr.hasNext() ) {
3791 ReferenceEdge edge = edgeItr.next();
3793 if( !reachableNodes1.contains( edge.getDst() ) ) {
3794 todoNodes1.add( edge.getDst() );
3799 while( !todoNodes2.isEmpty() ) {
3800 HeapRegionNode hrn = todoNodes2.iterator().next();
3801 todoNodes2.remove( hrn );
3802 reachableNodes2.add(hrn);
3804 Iterator<ReferenceEdge> edgeItr = hrn.iteratorToReferencees();
3805 while( edgeItr.hasNext() ) {
3806 ReferenceEdge edge = edgeItr.next();
3808 if( !reachableNodes2.contains( edge.getDst() ) ) {
3809 todoNodes2.add( edge.getDst() );
3814 Set<HeapRegionNode> intersection =
3815 new HashSet<HeapRegionNode>( reachableNodes1 );
3817 intersection.retainAll( reachableNodes2 );
3819 return intersection;
3823 // for writing ownership graphs to dot files
3824 public void writeGraph(MethodContext mc,
3826 boolean writeLabels,
3827 boolean labelSelect,
3828 boolean pruneGarbage,
3829 boolean writeReferencers,
3830 boolean writeParamMappings
3831 ) throws java.io.IOException {
3843 public void writeGraph(MethodContext mc,
3844 boolean writeLabels,
3845 boolean labelSelect,
3846 boolean pruneGarbage,
3847 boolean writeReferencers,
3848 boolean writeParamMappings
3849 ) throws java.io.IOException {
3851 writeGraph(mc+"COMPLETE",
3860 public void writeGraph(MethodContext mc,
3862 boolean writeLabels,
3863 boolean labelSelect,
3864 boolean pruneGarbage,
3865 boolean writeReferencers,
3866 boolean writeParamMappings
3867 ) throws java.io.IOException {
3871 writeGraph(mc+"COMPLETE"+String.format("%05d", numUpdate),
3880 public void writeGraph(String graphName,
3881 boolean writeLabels,
3882 boolean labelSelect,
3883 boolean pruneGarbage,
3884 boolean writeReferencers,
3885 boolean writeParamMappings
3886 ) throws java.io.IOException {
3888 // remove all non-word characters from the graph name so
3889 // the filename and identifier in dot don't cause errors
3890 graphName = graphName.replaceAll("[\\W]", "");
3892 BufferedWriter bw = new BufferedWriter(new FileWriter(graphName+".dot") );
3893 bw.write("digraph "+graphName+" {\n");
3895 HashSet<HeapRegionNode> visited = new HashSet<HeapRegionNode>();
3897 // then visit every heap region node
3898 Set s = id2hrn.entrySet();
3899 Iterator i = s.iterator();
3900 while( i.hasNext() ) {
3901 Map.Entry me = (Map.Entry)i.next();
3902 HeapRegionNode hrn = (HeapRegionNode) me.getValue();
3904 if( !pruneGarbage ||
3905 (hrn.isFlagged() && hrn.getID() > 0) ||
3906 hrn.getDescription().startsWith("param")
3909 if( !visited.contains(hrn) ) {
3910 traverseHeapRegionNodes(VISIT_HRN_WRITE_FULL,
3920 bw.write(" graphTitle[label=\""+graphName+"\",shape=box];\n");
3922 if( writeParamMappings ) {
3924 Set df = paramIndex2id.entrySet();
3925 Iterator ih = df.iterator();
3926 while( ih.hasNext() ) {
3927 Map.Entry meh = (Map.Entry)ih.next();
3928 Integer pi = (Integer) meh.getKey();
3929 Integer id = (Integer) meh.getValue();
3930 bw.write(" pindex"+pi+"[label=\""+pi+" to "+id+"\",shape=box];\n");
3935 // then visit every label node, useful for debugging
3937 s = td2ln.entrySet();
3939 while( i.hasNext() ) {
3940 Map.Entry me = (Map.Entry)i.next();
3941 LabelNode ln = (LabelNode) me.getValue();
3944 String labelStr = ln.getTempDescriptorString();
3945 if( labelStr.startsWith("___temp") ||
3946 labelStr.startsWith("___dst") ||
3947 labelStr.startsWith("___srctmp") ||
3948 labelStr.startsWith("___neverused") ||
3949 labelStr.contains(qString) ||
3950 labelStr.contains(rString) ||
3951 labelStr.contains(blobString)
3957 //bw.write(" "+ln.toString() + ";\n");
3959 Iterator<ReferenceEdge> heapRegionsItr = ln.iteratorToReferencees();
3960 while( heapRegionsItr.hasNext() ) {
3961 ReferenceEdge edge = heapRegionsItr.next();
3962 HeapRegionNode hrn = edge.getDst();
3964 if( pruneGarbage && !visited.contains(hrn) ) {
3965 traverseHeapRegionNodes(VISIT_HRN_WRITE_FULL,
3973 bw.write(" " + ln.toString() +
3974 " -> " + hrn.toString() +
3975 "[label=\"" + edge.toGraphEdgeString() +
3986 protected void traverseHeapRegionNodes(int mode,
3990 HashSet<HeapRegionNode> visited,
3991 boolean writeReferencers
3992 ) throws java.io.IOException {
3994 if( visited.contains(hrn) ) {
4000 case VISIT_HRN_WRITE_FULL:
4002 String attributes = "[";
4004 if( hrn.isSingleObject() ) {
4005 attributes += "shape=box";
4007 attributes += "shape=Msquare";
4010 if( hrn.isFlagged() ) {
4011 attributes += ",style=filled,fillcolor=lightgrey";
4014 attributes += ",label=\"ID" +
4018 if( hrn.getType() != null ) {
4019 attributes += hrn.getType() + "\\n";
4022 attributes += hrn.getDescription() +
4024 hrn.getAlphaString() +
4027 bw.write(" " + hrn.toString() + attributes + ";\n");
4032 // useful for debugging
4035 if( writeReferencers ) {
4036 OwnershipNode onRef = null;
4037 Iterator refItr = hrn.iteratorToReferencers();
4038 while( refItr.hasNext() ) {
4039 onRef = (OwnershipNode) refItr.next();
4042 case VISIT_HRN_WRITE_FULL:
4043 bw.write(" " + hrn.toString() +
4044 " -> " + onRef.toString() +
4045 "[color=lightgray];\n");
4052 Iterator<ReferenceEdge> childRegionsItr = hrn.iteratorToReferencees();
4053 while( childRegionsItr.hasNext() ) {
4054 ReferenceEdge edge = childRegionsItr.next();
4055 HeapRegionNode hrnChild = edge.getDst();
4058 case VISIT_HRN_WRITE_FULL:
4059 bw.write(" " + hrn.toString() +
4060 " -> " + hrnChild.toString() +
4061 "[label=\"" + edge.toGraphEdgeString() +
4066 traverseHeapRegionNodes(mode,