1 package Analysis.OwnershipAnalysis;
8 public class OwnershipGraph {
10 private int allocationDepth;
11 private TypeUtil typeUtil;
13 // there was already one other very similar reason
14 // for traversing heap nodes that is no longer needed
15 // instead of writing a new heap region visitor, use
16 // the existing method with a new mode to describe what
17 // actions to take during the traversal
18 protected static final int VISIT_HRN_WRITE_FULL = 0;
20 protected static final String qString = new String( "Q_spec_" );
21 protected static final String rString = new String( "R_spec_" );
22 protected static final String blobString = new String( "_AliasBlob___" );
24 protected static final TempDescriptor tdReturn = new TempDescriptor( "_Return___" );
25 protected static final TempDescriptor tdAliasBlob = new TempDescriptor( blobString );
27 protected static final TokenTupleSet ttsEmpty = new TokenTupleSet().makeCanonical();
28 protected static final ReachabilitySet rsEmpty = new ReachabilitySet().makeCanonical();
29 protected static final ReachabilitySet rsWttsEmpty = new ReachabilitySet( ttsEmpty ).makeCanonical();
31 // add a bogus entry with the identity rule for easy rewrite
32 // of new callee nodes and edges, doesn't belong to any parameter
33 protected static final int bogusParamIndexInt = -2;
34 protected static final Integer bogusID = new Integer( bogusParamIndexInt );
35 protected static final Integer bogusIndex = new Integer( bogusParamIndexInt );
36 protected static final TokenTuple bogusToken = new TokenTuple( bogusID, true, TokenTuple.ARITY_ONE ).makeCanonical();
37 protected static final TokenTuple bogusTokenPlus = new TokenTuple( bogusID, true, TokenTuple.ARITY_ONEORMORE ).makeCanonical();
38 protected static final TokenTuple bogusTokenStar = new TokenTuple( bogusID, true, TokenTuple.ARITY_ZEROORMORE ).makeCanonical();
39 protected static final ReachabilitySet rsIdentity =
40 new ReachabilitySet( new TokenTupleSet( bogusToken ).makeCanonical() ).makeCanonical();
43 public Hashtable<Integer, HeapRegionNode> id2hrn;
44 public Hashtable<TempDescriptor, LabelNode > td2ln;
46 public Hashtable<Integer, Set<Integer> > idPrimary2paramIndexSet;
47 public Hashtable<Integer, Integer > paramIndex2idPrimary;
49 public Hashtable<Integer, Set<Integer> > idSecondary2paramIndexSet;
50 public Hashtable<Integer, Integer > paramIndex2idSecondary;
52 public Hashtable<Integer, TempDescriptor> paramIndex2tdQ;
53 public Hashtable<Integer, TempDescriptor> paramIndex2tdR;
56 public HashSet<AllocationSite> allocationSites;
59 public Hashtable<TokenTuple, Integer> paramTokenPrimary2paramIndex;
60 public Hashtable<Integer, TokenTuple> paramIndex2paramTokenPrimary;
62 public Hashtable<TokenTuple, Integer> paramTokenSecondary2paramIndex;
63 public Hashtable<Integer, TokenTuple> paramIndex2paramTokenSecondary;
64 public Hashtable<TokenTuple, Integer> paramTokenSecondaryPlus2paramIndex;
65 public Hashtable<Integer, TokenTuple> paramIndex2paramTokenSecondaryPlus;
66 public Hashtable<TokenTuple, Integer> paramTokenSecondaryStar2paramIndex;
67 public Hashtable<Integer, TokenTuple> paramIndex2paramTokenSecondaryStar;
70 public OwnershipGraph(int allocationDepth, TypeUtil typeUtil) {
71 this.allocationDepth = allocationDepth;
72 this.typeUtil = typeUtil;
74 id2hrn = new Hashtable<Integer, HeapRegionNode>();
75 td2ln = new Hashtable<TempDescriptor, LabelNode >();
76 idPrimary2paramIndexSet = new Hashtable<Integer, Set<Integer> >();
77 paramIndex2idPrimary = new Hashtable<Integer, Integer >();
78 idSecondary2paramIndexSet = new Hashtable<Integer, Set<Integer> >();
79 paramIndex2idSecondary = new Hashtable<Integer, Integer >();
80 paramIndex2tdQ = new Hashtable<Integer, TempDescriptor>();
81 paramIndex2tdR = new Hashtable<Integer, TempDescriptor>();
83 paramTokenPrimary2paramIndex = new Hashtable<TokenTuple, Integer >();
84 paramIndex2paramTokenPrimary = new Hashtable<Integer, TokenTuple >();
86 paramTokenSecondary2paramIndex = new Hashtable<TokenTuple, Integer >();
87 paramIndex2paramTokenSecondary = new Hashtable<Integer, TokenTuple >();
88 paramTokenSecondaryPlus2paramIndex = new Hashtable<TokenTuple, Integer >();
89 paramIndex2paramTokenSecondaryPlus = new Hashtable<Integer, TokenTuple >();
90 paramTokenSecondaryStar2paramIndex = new Hashtable<TokenTuple, Integer >();
91 paramIndex2paramTokenSecondaryStar = new Hashtable<Integer, TokenTuple >();
93 allocationSites = new HashSet <AllocationSite>();
97 // label nodes are much easier to deal with than
98 // heap region nodes. Whenever there is a request
99 // for the label node that is associated with a
100 // temp descriptor we can either find it or make a
101 // new one and return it. This is because temp
102 // descriptors are globally unique and every label
103 // node is mapped to exactly one temp descriptor.
104 protected LabelNode getLabelNodeFromTemp(TempDescriptor td) {
107 if( !td2ln.containsKey(td) ) {
108 td2ln.put(td, new LabelNode(td) );
111 return td2ln.get(td);
115 // the reason for this method is to have the option
116 // creating new heap regions with specific IDs, or
117 // duplicating heap regions with specific IDs (especially
118 // in the merge() operation) or to create new heap
119 // regions with a new unique ID.
120 protected HeapRegionNode
121 createNewHeapRegionNode(Integer id,
122 boolean isSingleObject,
123 boolean isNewSummary,
127 AllocationSite allocSite,
128 ReachabilitySet alpha,
129 String description) {
131 boolean markForAnalysis = isFlagged || isParameter;
133 TypeDescriptor typeToUse = null;
134 if( allocSite != null ) {
135 typeToUse = allocSite.getType();
140 if( allocSite != null && allocSite.getDisjointId() != null ) {
141 markForAnalysis = true;
145 id = OwnershipAnalysis.generateUniqueHeapRegionNodeID();
148 if( alpha == null ) {
149 if( markForAnalysis ) {
150 alpha = new ReachabilitySet(
157 alpha = new ReachabilitySet(
158 new TokenTupleSet().makeCanonical()
163 HeapRegionNode hrn = new HeapRegionNode(id,
178 ////////////////////////////////////////////////
180 // Low-level referencee and referencer methods
182 // These methods provide the lowest level for
183 // creating references between ownership nodes
184 // and handling the details of maintaining both
185 // list of referencers and referencees.
187 ////////////////////////////////////////////////
188 protected void addReferenceEdge(OwnershipNode referencer,
189 HeapRegionNode referencee,
190 ReferenceEdge edge) {
191 assert referencer != null;
192 assert referencee != null;
194 assert edge.getSrc() == referencer;
195 assert edge.getDst() == referencee;
197 referencer.addReferencee(edge);
198 referencee.addReferencer(edge);
201 protected void removeReferenceEdge(OwnershipNode referencer,
202 HeapRegionNode referencee,
205 assert referencer != null;
206 assert referencee != null;
208 ReferenceEdge edge = referencer.getReferenceTo(referencee,
212 assert edge == referencee.getReferenceFrom(referencer,
216 referencer.removeReferencee(edge);
217 referencee.removeReferencer(edge);
220 protected void clearReferenceEdgesFrom(OwnershipNode referencer,
224 assert referencer != null;
226 // get a copy of the set to iterate over, otherwise
227 // we will be trying to take apart the set as we
228 // are iterating over it, which won't work
229 Iterator<ReferenceEdge> i = referencer.iteratorToReferenceesClone();
230 while( i.hasNext() ) {
231 ReferenceEdge edge = i.next();
234 (type != null && edge.getType() .equals( type )) ||
235 (field != null && edge.getField().equals( field ))
238 HeapRegionNode referencee = edge.getDst();
240 removeReferenceEdge(referencer,
248 protected void clearReferenceEdgesTo(HeapRegionNode referencee,
252 assert referencee != null;
254 // get a copy of the set to iterate over, otherwise
255 // we will be trying to take apart the set as we
256 // are iterating over it, which won't work
257 Iterator<ReferenceEdge> i = referencee.iteratorToReferencersClone();
258 while( i.hasNext() ) {
259 ReferenceEdge edge = i.next();
262 (type != null && edge.getType() .equals( type )) ||
263 (field != null && edge.getField().equals( field ))
266 OwnershipNode referencer = edge.getSrc();
268 removeReferenceEdge(referencer,
277 ////////////////////////////////////////////////////
279 // Assignment Operation Methods
281 // These methods are high-level operations for
282 // modeling program assignment statements using
283 // the low-level reference create/remove methods
286 // The destination in an assignment statement is
287 // going to have new references. The method of
288 // determining the references depends on the type
289 // of the FlatNode assignment and the predicates
290 // of the nodes and edges involved.
292 ////////////////////////////////////////////////////
293 public void assignTempXEqualToTempY(TempDescriptor x,
296 LabelNode lnX = getLabelNodeFromTemp(x);
297 LabelNode lnY = getLabelNodeFromTemp(y);
299 clearReferenceEdgesFrom(lnX, null, null, true);
301 Iterator<ReferenceEdge> itrYhrn = lnY.iteratorToReferencees();
302 while( itrYhrn.hasNext() ) {
303 ReferenceEdge edgeY = itrYhrn.next();
304 HeapRegionNode referencee = edgeY.getDst();
305 ReferenceEdge edgeNew = edgeY.copy();
308 addReferenceEdge(lnX, referencee, edgeNew);
313 public void assignTypedTempXEqualToTempY(TempDescriptor x,
315 TypeDescriptor type) {
317 LabelNode lnX = getLabelNodeFromTemp(x);
318 LabelNode lnY = getLabelNodeFromTemp(y);
320 clearReferenceEdgesFrom(lnX, null, null, true);
322 Iterator<ReferenceEdge> itrYhrn = lnY.iteratorToReferencees();
323 while( itrYhrn.hasNext() ) {
324 ReferenceEdge edgeY = itrYhrn.next();
325 HeapRegionNode referencee = edgeY.getDst();
326 ReferenceEdge edgeNew = edgeY.copy();
327 edgeNew.setSrc( lnX );
328 edgeNew.setType( type );
329 edgeNew.setField( null );
331 addReferenceEdge(lnX, referencee, edgeNew);
336 public void assignTempXEqualToTempYFieldF(TempDescriptor x,
339 LabelNode lnX = getLabelNodeFromTemp(x);
340 LabelNode lnY = getLabelNodeFromTemp(y);
342 clearReferenceEdgesFrom(lnX, null, null, true);
344 Iterator<ReferenceEdge> itrYhrn = lnY.iteratorToReferencees();
345 while( itrYhrn.hasNext() ) {
346 ReferenceEdge edgeY = itrYhrn.next();
347 HeapRegionNode hrnY = edgeY.getDst();
348 ReachabilitySet betaY = edgeY.getBeta();
350 Iterator<ReferenceEdge> itrHrnFhrn = hrnY.iteratorToReferencees();
351 while( itrHrnFhrn.hasNext() ) {
352 ReferenceEdge edgeHrn = itrHrnFhrn.next();
353 HeapRegionNode hrnHrn = edgeHrn.getDst();
354 ReachabilitySet betaHrn = edgeHrn.getBeta();
356 if( edgeHrn.getType() == null ||
357 edgeHrn.getType().equals( f.getType() ) ) {
359 ReferenceEdge edgeNew = new ReferenceEdge(lnX,
364 betaY.intersection(betaHrn) );
366 addReferenceEdge(lnX, hrnHrn, edgeNew);
373 public void assignTempXFieldFEqualToTempY(TempDescriptor x,
376 LabelNode lnX = getLabelNodeFromTemp(x);
377 LabelNode lnY = getLabelNodeFromTemp(y);
379 HashSet<HeapRegionNode> nodesWithNewAlpha = new HashSet<HeapRegionNode>();
380 HashSet<ReferenceEdge> edgesWithNewBeta = new HashSet<ReferenceEdge>();
383 // first look for possible strong updates and remove those edges
384 boolean strongUpdate = false;
386 Iterator<ReferenceEdge> itrXhrn = lnX.iteratorToReferencees();
387 while( itrXhrn.hasNext() ) {
388 ReferenceEdge edgeX = itrXhrn.next();
389 HeapRegionNode hrnX = edgeX.getDst();
391 Iterator<ReferenceEdge> itrYhrn = lnY.iteratorToReferencees();
392 while( itrYhrn.hasNext() ) {
393 ReferenceEdge edgeY = itrYhrn.next();
394 HeapRegionNode hrnY = edgeY.getDst();
396 // we can do a strong update here if one of two cases holds
398 f != OwnershipAnalysis.getArrayField( f.getType() ) &&
399 hrnX.isSingleObject() &&
400 ( (hrnX.getNumReferencers() == 1) ||
401 ( lnX.getNumReferencees() == 1)
405 clearReferenceEdgesFrom( hrnX, f.getType(), f.getSymbol(), false );
410 // then do all token propagation
411 itrXhrn = lnX.iteratorToReferencees();
412 while( itrXhrn.hasNext() ) {
413 ReferenceEdge edgeX = itrXhrn.next();
414 HeapRegionNode hrnX = edgeX.getDst();
415 ReachabilitySet betaX = edgeX.getBeta();
417 ReachabilitySet R = hrnX.getAlpha().intersection(edgeX.getBeta() );
419 Iterator<ReferenceEdge> itrYhrn = lnY.iteratorToReferencees();
420 while( itrYhrn.hasNext() ) {
421 ReferenceEdge edgeY = itrYhrn.next();
422 HeapRegionNode hrnY = edgeY.getDst();
423 ReachabilitySet O = edgeY.getBeta();
426 // propagate tokens over nodes starting from hrnSrc, and it will
427 // take care of propagating back up edges from any touched nodes
428 ChangeTupleSet Cy = O.unionUpArityToChangeSet(R);
429 propagateTokensOverNodes(hrnY, Cy, nodesWithNewAlpha, edgesWithNewBeta);
432 // then propagate back just up the edges from hrn
433 ChangeTupleSet Cx = R.unionUpArityToChangeSet(O);
436 HashSet<ReferenceEdge> todoEdges = new HashSet<ReferenceEdge>();
438 Hashtable<ReferenceEdge, ChangeTupleSet> edgePlannedChanges =
439 new Hashtable<ReferenceEdge, ChangeTupleSet>();
441 Iterator<ReferenceEdge> referItr = hrnX.iteratorToReferencers();
442 while( referItr.hasNext() ) {
443 ReferenceEdge edgeUpstream = referItr.next();
444 todoEdges.add(edgeUpstream);
445 edgePlannedChanges.put(edgeUpstream, Cx);
448 propagateTokensOverEdges(todoEdges,
455 // apply the updates to reachability
456 Iterator<HeapRegionNode> nodeItr = nodesWithNewAlpha.iterator();
457 while( nodeItr.hasNext() ) {
458 nodeItr.next().applyAlphaNew();
461 Iterator<ReferenceEdge> edgeItr = edgesWithNewBeta.iterator();
462 while( edgeItr.hasNext() ) {
463 edgeItr.next().applyBetaNew();
466 // then go back through and add the new edges
467 itrXhrn = lnX.iteratorToReferencees();
468 while( itrXhrn.hasNext() ) {
469 ReferenceEdge edgeX = itrXhrn.next();
470 HeapRegionNode hrnX = edgeX.getDst();
472 Iterator<ReferenceEdge> itrYhrn = lnY.iteratorToReferencees();
473 while( itrYhrn.hasNext() ) {
474 ReferenceEdge edgeY = itrYhrn.next();
475 HeapRegionNode hrnY = edgeY.getDst();
477 // prepare the new reference edge hrnX.f -> hrnY
478 ReferenceEdge edgeNew = new ReferenceEdge(hrnX,
483 edgeY.getBeta().pruneBy( hrnX.getAlpha() )
486 // look to see if an edge with same field exists
487 // and merge with it, otherwise just add the edge
488 ReferenceEdge edgeExisting = hrnX.getReferenceTo( hrnY,
492 if( edgeExisting != null ) {
493 edgeExisting.setBeta(
494 edgeExisting.getBeta().union( edgeNew.getBeta() )
496 // a new edge here cannot be reflexive, so existing will
497 // always be also not reflexive anymore
498 edgeExisting.setIsInitialParam( false );
500 addReferenceEdge( hrnX, hrnY, edgeNew );
505 // if there was a strong update, make sure to improve
506 // reachability with a global sweep
513 // the parameter model is to use a single-object heap region
514 // for the primary parameter, and a multiple-object heap
515 // region for the secondary objects reachable through the
516 // primary object, if necessary
517 public void assignTempEqualToParamAlloc( TempDescriptor td,
519 Integer paramIndex ) {
522 TypeDescriptor typeParam = td.getType();
523 assert typeParam != null;
525 // either the parameter is an array or a class to be in this method
526 assert typeParam.isArray() || typeParam.isClass();
528 // discover some info from the param type and use it below
529 // to get parameter model as precise as we can
530 boolean createSecondaryRegion = false;
531 Set<FieldDescriptor> primary2primaryFields = new HashSet<FieldDescriptor>();
532 Set<FieldDescriptor> primary2secondaryFields = new HashSet<FieldDescriptor>();
534 // there might be an element reference for array types
535 if( typeParam.isArray() ) {
536 // only bother with this if the dereferenced type can
537 // affect reachability
538 TypeDescriptor typeDeref = typeParam.dereference();
539 if( !typeDeref.isImmutable() || typeDeref.isArray() ) {
540 primary2secondaryFields.add(
541 OwnershipAnalysis.getArrayField( typeDeref )
543 createSecondaryRegion = true;
545 // also handle a special case where an array of objects
546 // can point back to the array, which is an object!
547 if( typeParam.toPrettyString().equals( "Object[]" ) &&
548 typeDeref.toPrettyString().equals( "Object" ) ) {
550 primary2primaryFields.add(
551 OwnershipAnalysis.getArrayField( typeDeref )
557 // there might be member references for class types
558 if( typeParam.isClass() ) {
559 ClassDescriptor cd = typeParam.getClassDesc();
560 while( cd != null ) {
562 Iterator fieldItr = cd.getFields();
563 while( fieldItr.hasNext() ) {
565 FieldDescriptor fd = (FieldDescriptor) fieldItr.next();
566 TypeDescriptor typeField = fd.getType();
567 assert typeField != null;
569 if( !typeField.isImmutable() || typeField.isArray() ) {
570 primary2secondaryFields.add( fd );
571 createSecondaryRegion = true;
574 if( typeUtil.isSuperorType( typeField, typeParam ) ) {
575 primary2primaryFields.add( fd );
579 cd = cd.getSuperDesc();
584 // now build everything we need
585 LabelNode lnParam = getLabelNodeFromTemp( td );
586 HeapRegionNode hrnPrimary = createNewHeapRegionNode( null, // id or null to generate a new one
587 true, // single object?
590 true, // is a parameter?
592 null, // allocation site
593 null, // reachability set
594 "param"+paramIndex+" obj" );
596 // this is a non-program-accessible label that picks up beta
597 // info to be used for fixing a caller of this method
598 TempDescriptor tdParamQ = new TempDescriptor( td+qString );
599 paramIndex2tdQ.put( paramIndex, tdParamQ );
600 LabelNode lnParamQ = getLabelNodeFromTemp( tdParamQ );
602 // keep track of heap regions that were created for
603 // parameter labels, the index of the parameter they
604 // are for is important when resolving method calls
605 Integer newPrimaryID = hrnPrimary.getID();
606 assert !idPrimary2paramIndexSet.containsKey( newPrimaryID );
607 Set<Integer> s = new HashSet<Integer>();
609 idPrimary2paramIndexSet.put( newPrimaryID, s );
610 paramIndex2idPrimary.put( paramIndex, newPrimaryID );
613 TokenTuple ttPrimary = new TokenTuple( newPrimaryID,
614 false, // multi-object
615 TokenTuple.ARITY_ONE ).makeCanonical();
616 //TokenTuple ttPrimary = new TokenTuple( hrnPrimary ).makeCanonical();
619 HeapRegionNode hrnSecondary = null;
620 Integer newSecondaryID = null;
621 TokenTuple ttSecondary = null;
622 TempDescriptor tdParamR = null;
623 LabelNode lnParamR = null;
625 if( createSecondaryRegion ) {
626 tdParamR = new TempDescriptor( td+rString );
627 paramIndex2tdR.put( paramIndex, tdParamR );
628 lnParamR = getLabelNodeFromTemp( tdParamR );
630 hrnSecondary = createNewHeapRegionNode( null, // id or null to generate a new one
631 false, // single object?
634 true, // is a parameter?
636 null, // allocation site
637 null, // reachability set
638 "param"+paramIndex+" reachable" );
640 newSecondaryID = hrnSecondary.getID();
641 assert !idSecondary2paramIndexSet.containsKey( newSecondaryID );
642 Set<Integer> s2 = new HashSet<Integer>();
643 s2.add( paramIndex );
644 idSecondary2paramIndexSet.put( newSecondaryID, s2 );
645 paramIndex2idSecondary.put( paramIndex, newSecondaryID );
648 ttSecondary = new TokenTuple( newSecondaryID,
649 true, // multi-object
650 TokenTuple.ARITY_ONE ).makeCanonical();
651 //ttSecondary = new TokenTuple( hrnSecondary ).makeCanonical();
654 // use a beta that has everything and put it all over the
655 // parameter model, then use a global sweep later to fix
656 // it up, since parameters can have different shapes
657 TokenTupleSet tts0 = new TokenTupleSet( ttPrimary ).makeCanonical();
658 ReachabilitySet betaSoup;
659 if( createSecondaryRegion ) {
660 TokenTupleSet tts1 = new TokenTupleSet( ttSecondary ).makeCanonical();
661 TokenTupleSet tts2 = new TokenTupleSet( ttPrimary ).union( ttSecondary );
662 betaSoup = new ReachabilitySet().union( tts0 ).union( tts1 ).union( tts2 );
664 betaSoup = new ReachabilitySet().union( tts0 );
667 ReferenceEdge edgeFromLabel =
668 new ReferenceEdge( lnParam, // src
672 false, // special param initial (not needed on label->node)
673 betaSoup ); // reachability
674 addReferenceEdge( lnParam, hrnPrimary, edgeFromLabel );
676 ReferenceEdge edgeFromLabelQ =
677 new ReferenceEdge( lnParamQ, // src
681 false, // special param initial (not needed on label->node)
682 betaSoup ); // reachability
683 addReferenceEdge( lnParamQ, hrnPrimary, edgeFromLabelQ );
685 ReferenceEdge edgeSecondaryReflexive;
686 if( createSecondaryRegion ) {
687 edgeSecondaryReflexive =
688 new ReferenceEdge( hrnSecondary, // src
690 null, // match all types
691 null, // match all fields
692 true, // special param initial
693 betaSoup ); // reachability
694 addReferenceEdge( hrnSecondary, hrnSecondary, edgeSecondaryReflexive );
696 ReferenceEdge edgeSecondary2Primary =
697 new ReferenceEdge( hrnSecondary, // src
699 null, // match all types
700 null, // match all fields
701 true, // special param initial
702 betaSoup ); // reachability
703 addReferenceEdge( hrnSecondary, hrnPrimary, edgeSecondary2Primary );
705 ReferenceEdge edgeFromLabelR =
706 new ReferenceEdge( lnParamR, // src
710 false, // special param initial (not needed on label->node)
711 betaSoup ); // reachability
712 addReferenceEdge( lnParamR, hrnSecondary, edgeFromLabelR );
715 Iterator<FieldDescriptor> fieldItr = primary2primaryFields.iterator();
716 while( fieldItr.hasNext() ) {
717 FieldDescriptor fd = fieldItr.next();
719 ReferenceEdge edgePrimaryReflexive =
720 new ReferenceEdge( hrnPrimary, // src
722 fd.getType(), // type
723 fd.getSymbol(), // field
724 true, // special param initial
725 betaSoup ); // reachability
726 addReferenceEdge( hrnPrimary, hrnPrimary, edgePrimaryReflexive );
729 fieldItr = primary2secondaryFields.iterator();
730 while( fieldItr.hasNext() ) {
731 FieldDescriptor fd = fieldItr.next();
733 ReferenceEdge edgePrimary2Secondary =
734 new ReferenceEdge( hrnPrimary, // src
736 fd.getType(), // type
737 fd.getSymbol(), // field
738 true, // special param initial
739 betaSoup ); // reachability
740 addReferenceEdge( hrnPrimary, hrnSecondary, edgePrimary2Secondary );
745 public void makeAliasedParamHeapRegionNode() {
747 LabelNode lnBlob = getLabelNodeFromTemp( tdAliasBlob );
748 HeapRegionNode hrn = createNewHeapRegionNode( null, // id or null to generate a new one
749 false, // single object?
752 true, // is a parameter?
754 null, // allocation site
755 null, // reachability set
759 ReachabilitySet beta = new ReachabilitySet( new TokenTuple( hrn.getID(),
761 TokenTuple.ARITY_ONE).makeCanonical()
764 //ReachabilitySet beta = new ReachabilitySet( new TokenTuple( hrn ).makeCanonical()
765 // ).makeCanonical();
767 ReferenceEdge edgeFromLabel =
768 new ReferenceEdge( lnBlob, hrn, null, null, false, beta );
770 ReferenceEdge edgeReflexive =
771 new ReferenceEdge( hrn, hrn, null, null, true, beta );
773 addReferenceEdge( lnBlob, hrn, edgeFromLabel );
774 addReferenceEdge( hrn, hrn, edgeReflexive );
778 public void assignTempEqualToAliasedParam( TempDescriptor tdParam,
779 Integer paramIndex ) {
780 assert tdParam != null;
782 TypeDescriptor typeParam = tdParam.getType();
783 assert typeParam != null;
785 LabelNode lnParam = getLabelNodeFromTemp( tdParam );
786 LabelNode lnAliased = getLabelNodeFromTemp( tdAliasBlob );
788 // this is a non-program-accessible label that picks up beta
789 // info to be used for fixing a caller of this method
790 TempDescriptor tdParamQ = new TempDescriptor( tdParam+qString );
791 TempDescriptor tdParamR = new TempDescriptor( tdParam+rString );
793 paramIndex2tdQ.put( paramIndex, tdParamQ );
794 paramIndex2tdR.put( paramIndex, tdParamR );
796 LabelNode lnParamQ = getLabelNodeFromTemp( tdParamQ );
797 LabelNode lnParamR = getLabelNodeFromTemp( tdParamR );
799 // the lnAliased should always only reference one node, and that
800 // heap region node is the aliased param blob
801 assert lnAliased.getNumReferencees() == 1;
802 HeapRegionNode hrnAliasBlob = lnAliased.iteratorToReferencees().next().getDst();
803 Integer idAliased = hrnAliasBlob.getID();
806 TokenTuple ttAliased = new TokenTuple( idAliased,
807 true, // multi-object
808 TokenTuple.ARITY_ONE ).makeCanonical();
809 //TokenTuple ttAliased = new TokenTuple( hrnAliasBlob ).makeCanonical();
812 HeapRegionNode hrnPrimary = createNewHeapRegionNode( null, // id or null to generate a new one
813 true, // single object?
816 true, // is a parameter?
818 null, // allocation site
819 null, // reachability set
820 "param"+paramIndex+" obj" );
822 Integer newPrimaryID = hrnPrimary.getID();
823 assert !idPrimary2paramIndexSet.containsKey( newPrimaryID );
824 Set<Integer> s1 = new HashSet<Integer>();
825 s1.add( paramIndex );
826 idPrimary2paramIndexSet.put( newPrimaryID, s1 );
827 paramIndex2idPrimary.put( paramIndex, newPrimaryID );
829 Set<Integer> s2 = idSecondary2paramIndexSet.get( idAliased );
831 s2 = new HashSet<Integer>();
833 s2.add( paramIndex );
834 idSecondary2paramIndexSet.put( idAliased, s2 );
835 paramIndex2idSecondary.put( paramIndex, idAliased );
839 TokenTuple ttPrimary = new TokenTuple( newPrimaryID,
840 false, // multi-object
841 TokenTuple.ARITY_ONE ).makeCanonical();
842 //TokenTuple ttPrimary = new TokenTuple( hrnPrimary ).makeCanonical();
846 TokenTupleSet tts0 = new TokenTupleSet( ttPrimary ).makeCanonical();
847 TokenTupleSet tts1 = new TokenTupleSet( ttAliased ).makeCanonical();
848 TokenTupleSet tts2 = new TokenTupleSet( ttPrimary ).union( ttAliased );
849 ReachabilitySet betaSoup = new ReachabilitySet().union( tts0 ).union( tts1 ).union( tts2 );
852 ReferenceEdge edgeFromLabel =
853 new ReferenceEdge( lnParam, // src
857 false, // special param initial (not needed on label->node)
858 betaSoup ); // reachability
859 addReferenceEdge( lnParam, hrnPrimary, edgeFromLabel );
861 ReferenceEdge edgeFromLabelQ =
862 new ReferenceEdge( lnParamQ, // src
866 false, // special param initial (not needed on label->node)
867 betaSoup ); // reachability
868 addReferenceEdge( lnParamQ, hrnPrimary, edgeFromLabelQ );
870 ReferenceEdge edgeAliased2Primary =
871 new ReferenceEdge( hrnAliasBlob, // src
873 null, // match all types
874 null, // match all fields
875 true, // special param initial
876 betaSoup ); // reachability
877 addReferenceEdge( hrnAliasBlob, hrnPrimary, edgeAliased2Primary );
879 ReferenceEdge edgeFromLabelR =
880 new ReferenceEdge( lnParamR, // src
884 false, // special param initial (not needed on label->node)
885 betaSoup ); // reachability
886 addReferenceEdge( lnParamR, hrnAliasBlob, edgeFromLabelR );
890 public void addParam2ParamAliasEdges( FlatMethod fm,
891 Set<Integer> aliasedParamIndices ) {
893 LabelNode lnAliased = getLabelNodeFromTemp( tdAliasBlob );
895 // the lnAliased should always only reference one node, and that
896 // heap region node is the aliased param blob
897 assert lnAliased.getNumReferencees() == 1;
898 HeapRegionNode hrnAliasBlob = lnAliased.iteratorToReferencees().next().getDst();
899 Integer idAliased = hrnAliasBlob.getID();
902 TokenTuple ttAliased = new TokenTuple( idAliased,
903 true, // multi-object
904 TokenTuple.ARITY_ONE ).makeCanonical();
905 //TokenTuple ttAliased = new TokenTuple( hrnAliasBlob ).makeCanonical();
908 Iterator<Integer> apItrI = aliasedParamIndices.iterator();
909 while( apItrI.hasNext() ) {
910 Integer i = apItrI.next();
911 TempDescriptor tdParamI = fm.getParameter( i );
912 TypeDescriptor typeI = tdParamI.getType();
913 LabelNode lnParamI = getLabelNodeFromTemp( tdParamI );
915 Integer idPrimaryI = paramIndex2idPrimary.get( i );
916 assert idPrimaryI != null;
917 HeapRegionNode primaryI = id2hrn.get( idPrimaryI );
921 System.out.println( " **idPrimaryI="+idPrimaryI );
923 writeGraph( "paramProblem", true, true, true, false, false );
924 } catch( IOException e ) {}
928 assert primaryI != null;
930 TokenTuple ttPrimaryI = new TokenTuple( idPrimaryI,
931 false, // multi-object
932 TokenTuple.ARITY_ONE ).makeCanonical();
934 TokenTupleSet ttsI = new TokenTupleSet( ttPrimaryI ).makeCanonical();
935 TokenTupleSet ttsA = new TokenTupleSet( ttAliased ).makeCanonical();
936 TokenTupleSet ttsIA = new TokenTupleSet( ttPrimaryI ).union( ttAliased );
937 ReachabilitySet betaSoup = new ReachabilitySet().union( ttsI ).union( ttsA ).union( ttsIA );
940 // calculate whether fields of this aliased parameter are able to
941 // reference its own primary object, the blob, or other parameter's
943 Set<FieldDescriptor> primary2primaryFields = new HashSet<FieldDescriptor>();
944 Set<FieldDescriptor> primary2secondaryFields = new HashSet<FieldDescriptor>();
946 // there might be an element reference for array types
947 if( typeI.isArray() ) {
948 // only bother with this if the dereferenced type can
949 // affect reachability
950 TypeDescriptor typeDeref = typeI.dereference();
952 // for this parameter to be aliased the following must be true
953 assert !typeDeref.isImmutable() || typeDeref.isArray();
955 primary2secondaryFields.add(
956 OwnershipAnalysis.getArrayField( typeDeref )
959 // also handle a special case where an array of objects
960 // can point back to the array, which is an object!
961 if( typeI .toPrettyString().equals( "Object[]" ) &&
962 typeDeref.toPrettyString().equals( "Object" ) ) {
963 primary2primaryFields.add(
964 OwnershipAnalysis.getArrayField( typeDeref )
969 // there might be member references for class types
970 if( typeI.isClass() ) {
971 ClassDescriptor cd = typeI.getClassDesc();
972 while( cd != null ) {
974 Iterator fieldItr = cd.getFields();
975 while( fieldItr.hasNext() ) {
977 FieldDescriptor fd = (FieldDescriptor) fieldItr.next();
978 TypeDescriptor typeField = fd.getType();
979 assert typeField != null;
981 if( !typeField.isImmutable() || typeField.isArray() ) {
982 primary2secondaryFields.add( fd );
985 if( typeUtil.isSuperorType( typeField, typeI ) ) {
986 primary2primaryFields.add( fd );
990 cd = cd.getSuperDesc();
994 Iterator<FieldDescriptor> fieldItr = primary2primaryFields.iterator();
995 while( fieldItr.hasNext() ) {
996 FieldDescriptor fd = fieldItr.next();
998 ReferenceEdge edgePrimaryReflexive =
999 new ReferenceEdge( primaryI, // src
1001 fd.getType(), // type
1002 fd.getSymbol(), // field
1003 true, // special param initial
1004 betaSoup ); // reachability
1005 addReferenceEdge( primaryI, primaryI, edgePrimaryReflexive );
1008 fieldItr = primary2secondaryFields.iterator();
1009 while( fieldItr.hasNext() ) {
1010 FieldDescriptor fd = fieldItr.next();
1011 TypeDescriptor typeField = fd.getType();
1012 assert typeField != null;
1014 ReferenceEdge edgePrimary2Secondary =
1015 new ReferenceEdge( primaryI, // src
1016 hrnAliasBlob, // dst
1017 fd.getType(), // type
1018 fd.getSymbol(), // field
1019 true, // special param initial
1020 betaSoup ); // reachability
1021 addReferenceEdge( primaryI, hrnAliasBlob, edgePrimary2Secondary );
1023 // ask whether these fields might match any of the other aliased
1024 // parameters and make those edges too
1025 Iterator<Integer> apItrJ = aliasedParamIndices.iterator();
1026 while( apItrJ.hasNext() ) {
1027 Integer j = apItrJ.next();
1028 TempDescriptor tdParamJ = fm.getParameter( j );
1029 TypeDescriptor typeJ = tdParamJ.getType();
1031 if( !i.equals( j ) && typeUtil.isSuperorType( typeField, typeJ ) ) {
1033 Integer idPrimaryJ = paramIndex2idPrimary.get( j );
1034 assert idPrimaryJ != null;
1035 HeapRegionNode primaryJ = id2hrn.get( idPrimaryJ );
1036 assert primaryJ != null;
1038 TokenTuple ttPrimaryJ = new TokenTuple( idPrimaryJ,
1039 false, // multi-object
1040 TokenTuple.ARITY_ONE ).makeCanonical();
1042 TokenTupleSet ttsJ = new TokenTupleSet( ttPrimaryJ ).makeCanonical();
1043 TokenTupleSet ttsIJ = ttsI.union( ttsJ );
1044 TokenTupleSet ttsAJ = ttsA.union( ttsJ );
1045 TokenTupleSet ttsIAJ = ttsIA.union( ttsJ );
1046 ReachabilitySet betaSoupWJ = new ReachabilitySet().union( ttsJ ).union( ttsIJ ).union( ttsAJ ).union( ttsIAJ );
1048 ReferenceEdge edgePrimaryI2PrimaryJ =
1049 new ReferenceEdge( primaryI, // src
1051 fd.getType(), // type
1052 fd.getSymbol(), // field
1053 true, // special param initial
1054 betaSoupWJ ); // reachability
1055 addReferenceEdge( primaryI, primaryJ, edgePrimaryI2PrimaryJ );
1061 // look at whether aliased parameters i and j can
1062 // possibly be the same primary object, add edges
1063 Iterator<Integer> apItrJ = aliasedParamIndices.iterator();
1064 while( apItrJ.hasNext() ) {
1065 Integer j = apItrJ.next();
1066 TempDescriptor tdParamJ = fm.getParameter( j );
1067 TypeDescriptor typeJ = tdParamJ.getType();
1068 LabelNode lnParamJ = getLabelNodeFromTemp( tdParamJ );
1070 if( !i.equals( j ) && typeUtil.isSuperorType( typeI, typeJ ) ) {
1072 Integer idPrimaryJ = paramIndex2idPrimary.get( j );
1073 assert idPrimaryJ != null;
1074 HeapRegionNode primaryJ = id2hrn.get( idPrimaryJ );
1075 assert primaryJ != null;
1077 ReferenceEdge lnJ2PrimaryJ = lnParamJ.getReferenceTo( primaryJ,
1080 assert lnJ2PrimaryJ != null;
1082 ReferenceEdge lnI2PrimaryJ = lnJ2PrimaryJ.copy();
1083 lnI2PrimaryJ.setSrc( lnParamI );
1084 lnI2PrimaryJ.setType( tdParamI.getType() );
1085 addReferenceEdge( lnParamI, primaryJ, lnI2PrimaryJ );
1091 public void prepareParamTokenMaps( FlatMethod fm ) {
1093 // always add the bogus mappings that are used to
1094 // rewrite "with respect to no parameter"
1095 paramTokenPrimary2paramIndex.put( bogusToken, bogusIndex );
1096 paramIndex2paramTokenPrimary.put( bogusIndex, bogusToken );
1098 paramTokenSecondary2paramIndex.put( bogusToken, bogusIndex );
1099 paramIndex2paramTokenSecondary.put( bogusIndex, bogusToken );
1100 paramTokenSecondaryPlus2paramIndex.put( bogusTokenPlus, bogusIndex );
1101 paramIndex2paramTokenSecondaryPlus.put( bogusIndex, bogusTokenPlus );
1102 paramTokenSecondaryStar2paramIndex.put( bogusTokenStar, bogusIndex );
1103 paramIndex2paramTokenSecondaryStar.put( bogusIndex, bogusTokenStar );
1105 for( int i = 0; i < fm.numParameters(); ++i ) {
1106 Integer paramIndex = new Integer( i );
1108 // immutable objects have no primary regions
1109 if( paramIndex2idPrimary.containsKey( paramIndex ) ) {
1110 Integer idPrimary = paramIndex2idPrimary.get( paramIndex );
1112 assert id2hrn.containsKey( idPrimary );
1113 HeapRegionNode hrnPrimary = id2hrn.get( idPrimary );
1115 TokenTuple p_i = new TokenTuple( hrnPrimary.getID(),
1116 false, // multiple-object?
1117 TokenTuple.ARITY_ONE ).makeCanonical();
1118 paramTokenPrimary2paramIndex.put( p_i, paramIndex );
1119 paramIndex2paramTokenPrimary.put( paramIndex, p_i );
1122 // any parameter object, by type, may have no secondary region
1123 if( paramIndex2idSecondary.containsKey( paramIndex ) ) {
1124 Integer idSecondary = paramIndex2idSecondary.get( paramIndex );
1126 assert id2hrn.containsKey( idSecondary );
1127 HeapRegionNode hrnSecondary = id2hrn.get( idSecondary );
1129 TokenTuple s_i = new TokenTuple( hrnSecondary.getID(),
1130 true, // multiple-object?
1131 TokenTuple.ARITY_ONE ).makeCanonical();
1132 paramTokenSecondary2paramIndex.put( s_i, paramIndex );
1133 paramIndex2paramTokenSecondary.put( paramIndex, s_i );
1135 TokenTuple s_i_plus = new TokenTuple( hrnSecondary.getID(),
1136 true, // multiple-object?
1137 TokenTuple.ARITY_ONEORMORE ).makeCanonical();
1138 paramTokenSecondaryPlus2paramIndex.put( s_i_plus, paramIndex );
1139 paramIndex2paramTokenSecondaryPlus.put( paramIndex, s_i_plus );
1141 TokenTuple s_i_star = new TokenTuple( hrnSecondary.getID(),
1142 true, // multiple-object?
1143 TokenTuple.ARITY_ZEROORMORE ).makeCanonical();
1144 paramTokenSecondaryStar2paramIndex.put( s_i_star, paramIndex );
1145 paramIndex2paramTokenSecondaryStar.put( paramIndex, s_i_star );
1152 public void assignReturnEqualToTemp(TempDescriptor x) {
1154 LabelNode lnR = getLabelNodeFromTemp(tdReturn);
1155 LabelNode lnX = getLabelNodeFromTemp(x);
1157 clearReferenceEdgesFrom(lnR, null, null, true);
1159 Iterator<ReferenceEdge> itrXhrn = lnX.iteratorToReferencees();
1160 while( itrXhrn.hasNext() ) {
1161 ReferenceEdge edgeX = itrXhrn.next();
1162 HeapRegionNode referencee = edgeX.getDst();
1163 ReferenceEdge edgeNew = edgeX.copy();
1164 edgeNew.setSrc(lnR);
1166 addReferenceEdge(lnR, referencee, edgeNew);
1171 public void assignTempEqualToNewAlloc(TempDescriptor x,
1172 AllocationSite as) {
1178 // after the age operation the newest (or zero-ith oldest)
1179 // node associated with the allocation site should have
1180 // no references to it as if it were a newly allocated
1181 // heap region, so make a reference to it to complete
1184 Integer idNewest = as.getIthOldest(0);
1185 HeapRegionNode hrnNewest = id2hrn.get(idNewest);
1186 assert hrnNewest != null;
1188 LabelNode lnX = getLabelNodeFromTemp(x);
1189 clearReferenceEdgesFrom(lnX, null, null, true);
1191 ReferenceEdge edgeNew =
1192 new ReferenceEdge(lnX, hrnNewest, null, null, false, hrnNewest.getAlpha() );
1194 addReferenceEdge(lnX, hrnNewest, edgeNew);
1198 // use the allocation site (unique to entire analysis) to
1199 // locate the heap region nodes in this ownership graph
1200 // that should be aged. The process models the allocation
1201 // of new objects and collects all the oldest allocations
1202 // in a summary node to allow for a finite analysis
1204 // There is an additional property of this method. After
1205 // running it on a particular ownership graph (many graphs
1206 // may have heap regions related to the same allocation site)
1207 // the heap region node objects in this ownership graph will be
1208 // allocated. Therefore, after aging a graph for an allocation
1209 // site, attempts to retrieve the heap region nodes using the
1210 // integer id's contained in the allocation site should always
1211 // return non-null heap regions.
1212 public void age(AllocationSite as) {
1214 // aging adds this allocation site to the graph's
1215 // list of sites that exist in the graph, or does
1216 // nothing if the site is already in the list
1217 allocationSites.add(as);
1219 // get the summary node for the allocation site in the context
1220 // of this particular ownership graph
1221 HeapRegionNode hrnSummary = getSummaryNode(as);
1223 // merge oldest node into summary
1224 Integer idK = as.getOldest();
1225 HeapRegionNode hrnK = id2hrn.get(idK);
1226 mergeIntoSummary(hrnK, hrnSummary);
1228 // move down the line of heap region nodes
1229 // clobbering the ith and transferring all references
1230 // to and from i-1 to node i. Note that this clobbers
1231 // the oldest node (hrnK) that was just merged into
1233 for( int i = allocationDepth - 1; i > 0; --i ) {
1235 // move references from the i-1 oldest to the ith oldest
1236 Integer idIth = as.getIthOldest(i);
1237 HeapRegionNode hrnI = id2hrn.get(idIth);
1238 Integer idImin1th = as.getIthOldest(i - 1);
1239 HeapRegionNode hrnImin1 = id2hrn.get(idImin1th);
1241 transferOnto(hrnImin1, hrnI);
1244 // as stated above, the newest node should have had its
1245 // references moved over to the second oldest, so we wipe newest
1246 // in preparation for being the new object to assign something to
1247 Integer id0th = as.getIthOldest(0);
1248 HeapRegionNode hrn0 = id2hrn.get(id0th);
1249 assert hrn0 != null;
1251 // clear all references in and out of newest node
1252 clearReferenceEdgesFrom(hrn0, null, null, true);
1253 clearReferenceEdgesTo(hrn0, null, null, true);
1256 // now tokens in reachability sets need to "age" also
1257 Iterator itrAllLabelNodes = td2ln.entrySet().iterator();
1258 while( itrAllLabelNodes.hasNext() ) {
1259 Map.Entry me = (Map.Entry)itrAllLabelNodes.next();
1260 LabelNode ln = (LabelNode) me.getValue();
1262 Iterator<ReferenceEdge> itrEdges = ln.iteratorToReferencees();
1263 while( itrEdges.hasNext() ) {
1264 ageTokens(as, itrEdges.next() );
1268 Iterator itrAllHRNodes = id2hrn.entrySet().iterator();
1269 while( itrAllHRNodes.hasNext() ) {
1270 Map.Entry me = (Map.Entry)itrAllHRNodes.next();
1271 HeapRegionNode hrnToAge = (HeapRegionNode) me.getValue();
1273 ageTokens(as, hrnToAge);
1275 Iterator<ReferenceEdge> itrEdges = hrnToAge.iteratorToReferencees();
1276 while( itrEdges.hasNext() ) {
1277 ageTokens(as, itrEdges.next() );
1282 // after tokens have been aged, reset newest node's reachability
1283 if( hrn0.isFlagged() ) {
1284 hrn0.setAlpha(new ReachabilitySet(
1286 new TokenTuple(hrn0).makeCanonical()
1291 hrn0.setAlpha(new ReachabilitySet(
1292 new TokenTupleSet().makeCanonical()
1299 protected HeapRegionNode getSummaryNode(AllocationSite as) {
1301 Integer idSummary = as.getSummary();
1302 HeapRegionNode hrnSummary = id2hrn.get(idSummary);
1304 // If this is null then we haven't touched this allocation site
1305 // in the context of the current ownership graph, so allocate
1306 // heap region nodes appropriate for the entire allocation site.
1307 // This should only happen once per ownership graph per allocation site,
1308 // and a particular integer id can be used to locate the heap region
1309 // in different ownership graphs that represents the same part of an
1311 if( hrnSummary == null ) {
1313 boolean hasFlags = false;
1314 if( as.getType().isClass() ) {
1315 hasFlags = as.getType().getClassDesc().hasFlags();
1318 hrnSummary = createNewHeapRegionNode(idSummary, // id or null to generate a new one
1319 false, // single object?
1321 hasFlags, // flagged?
1322 false, // is a parameter?
1323 as.getType(), // type
1324 as, // allocation site
1325 null, // reachability set
1326 as.toStringForDOT() + "\\nsummary");
1328 for( int i = 0; i < as.getAllocationDepth(); ++i ) {
1329 Integer idIth = as.getIthOldest(i);
1330 assert !id2hrn.containsKey(idIth);
1331 createNewHeapRegionNode(idIth, // id or null to generate a new one
1332 true, // single object?
1334 hasFlags, // flagged?
1335 false, // is a parameter?
1336 as.getType(), // type
1337 as, // allocation site
1338 null, // reachability set
1339 as.toStringForDOT() + "\\n" + i + " oldest");
1347 protected HeapRegionNode getShadowSummaryNode(AllocationSite as) {
1349 Integer idShadowSummary = as.getSummaryShadow();
1350 HeapRegionNode hrnShadowSummary = id2hrn.get(idShadowSummary);
1352 if( hrnShadowSummary == null ) {
1354 boolean hasFlags = false;
1355 if( as.getType().isClass() ) {
1356 hasFlags = as.getType().getClassDesc().hasFlags();
1359 hrnShadowSummary = createNewHeapRegionNode(idShadowSummary, // id or null to generate a new one
1360 false, // single object?
1362 hasFlags, // flagged?
1363 false, // is a parameter?
1364 as.getType(), // type
1365 as, // allocation site
1366 null, // reachability set
1367 as + "\\n" + as.getType() + "\\nshadowSum");
1369 for( int i = 0; i < as.getAllocationDepth(); ++i ) {
1370 Integer idShadowIth = as.getIthOldestShadow(i);
1371 assert !id2hrn.containsKey(idShadowIth);
1372 createNewHeapRegionNode(idShadowIth, // id or null to generate a new one
1373 true, // single object?
1375 hasFlags, // flagged?
1376 false, // is a parameter?
1377 as.getType(), // type
1378 as, // allocation site
1379 null, // reachability set
1380 as + "\\n" + as.getType() + "\\n" + i + " shadow");
1384 return hrnShadowSummary;
1388 protected void mergeIntoSummary(HeapRegionNode hrn, HeapRegionNode hrnSummary) {
1389 assert hrnSummary.isNewSummary();
1391 // transfer references _from_ hrn over to hrnSummary
1392 Iterator<ReferenceEdge> itrReferencee = hrn.iteratorToReferencees();
1393 while( itrReferencee.hasNext() ) {
1394 ReferenceEdge edge = itrReferencee.next();
1395 ReferenceEdge edgeMerged = edge.copy();
1396 edgeMerged.setSrc(hrnSummary);
1398 HeapRegionNode hrnReferencee = edge.getDst();
1399 ReferenceEdge edgeSummary = hrnSummary.getReferenceTo(hrnReferencee,
1403 if( edgeSummary == null ) {
1404 // the merge is trivial, nothing to be done
1406 // otherwise an edge from the referencer to hrnSummary exists already
1407 // and the edge referencer->hrn should be merged with it
1408 edgeMerged.setBeta(edgeMerged.getBeta().union(edgeSummary.getBeta() ) );
1411 addReferenceEdge(hrnSummary, hrnReferencee, edgeMerged);
1414 // next transfer references _to_ hrn over to hrnSummary
1415 Iterator<ReferenceEdge> itrReferencer = hrn.iteratorToReferencers();
1416 while( itrReferencer.hasNext() ) {
1417 ReferenceEdge edge = itrReferencer.next();
1418 ReferenceEdge edgeMerged = edge.copy();
1419 edgeMerged.setDst(hrnSummary);
1421 OwnershipNode onReferencer = edge.getSrc();
1422 ReferenceEdge edgeSummary = onReferencer.getReferenceTo(hrnSummary,
1426 if( edgeSummary == null ) {
1427 // the merge is trivial, nothing to be done
1429 // otherwise an edge from the referencer to alpha_S exists already
1430 // and the edge referencer->alpha_K should be merged with it
1431 edgeMerged.setBeta(edgeMerged.getBeta().union(edgeSummary.getBeta() ) );
1434 addReferenceEdge(onReferencer, hrnSummary, edgeMerged);
1437 // then merge hrn reachability into hrnSummary
1438 hrnSummary.setAlpha(hrnSummary.getAlpha().union(hrn.getAlpha() ) );
1442 protected void transferOnto(HeapRegionNode hrnA, HeapRegionNode hrnB) {
1444 // clear references in and out of node b
1445 clearReferenceEdgesFrom(hrnB, null, null, true);
1446 clearReferenceEdgesTo(hrnB, null, null, true);
1448 // copy each edge in and out of A to B
1449 Iterator<ReferenceEdge> itrReferencee = hrnA.iteratorToReferencees();
1450 while( itrReferencee.hasNext() ) {
1451 ReferenceEdge edge = itrReferencee.next();
1452 HeapRegionNode hrnReferencee = edge.getDst();
1453 ReferenceEdge edgeNew = edge.copy();
1454 edgeNew.setSrc(hrnB);
1456 addReferenceEdge(hrnB, hrnReferencee, edgeNew);
1459 Iterator<ReferenceEdge> itrReferencer = hrnA.iteratorToReferencers();
1460 while( itrReferencer.hasNext() ) {
1461 ReferenceEdge edge = itrReferencer.next();
1462 OwnershipNode onReferencer = edge.getSrc();
1463 ReferenceEdge edgeNew = edge.copy();
1464 edgeNew.setDst(hrnB);
1466 addReferenceEdge(onReferencer, hrnB, edgeNew);
1469 // replace hrnB reachability with hrnA's
1470 hrnB.setAlpha(hrnA.getAlpha() );
1474 protected void ageTokens(AllocationSite as, ReferenceEdge edge) {
1475 edge.setBeta(edge.getBeta().ageTokens(as) );
1478 protected void ageTokens(AllocationSite as, HeapRegionNode hrn) {
1479 hrn.setAlpha(hrn.getAlpha().ageTokens(as) );
1484 protected void propagateTokensOverNodes(HeapRegionNode nPrime,
1486 HashSet<HeapRegionNode> nodesWithNewAlpha,
1487 HashSet<ReferenceEdge> edgesWithNewBeta) {
1489 HashSet<HeapRegionNode> todoNodes
1490 = new HashSet<HeapRegionNode>();
1491 todoNodes.add(nPrime);
1493 HashSet<ReferenceEdge> todoEdges
1494 = new HashSet<ReferenceEdge>();
1496 Hashtable<HeapRegionNode, ChangeTupleSet> nodePlannedChanges
1497 = new Hashtable<HeapRegionNode, ChangeTupleSet>();
1498 nodePlannedChanges.put(nPrime, c0);
1500 Hashtable<ReferenceEdge, ChangeTupleSet> edgePlannedChanges
1501 = new Hashtable<ReferenceEdge, ChangeTupleSet>();
1503 // first propagate change sets everywhere they can go
1504 while( !todoNodes.isEmpty() ) {
1505 HeapRegionNode n = todoNodes.iterator().next();
1506 ChangeTupleSet C = nodePlannedChanges.get(n);
1508 Iterator<ReferenceEdge> referItr = n.iteratorToReferencers();
1509 while( referItr.hasNext() ) {
1510 ReferenceEdge edge = referItr.next();
1511 todoEdges.add(edge);
1513 if( !edgePlannedChanges.containsKey(edge) ) {
1514 edgePlannedChanges.put(edge, new ChangeTupleSet().makeCanonical() );
1517 edgePlannedChanges.put(edge, edgePlannedChanges.get(edge).union(C) );
1520 Iterator<ReferenceEdge> refeeItr = n.iteratorToReferencees();
1521 while( refeeItr.hasNext() ) {
1522 ReferenceEdge edgeF = refeeItr.next();
1523 HeapRegionNode m = edgeF.getDst();
1525 ChangeTupleSet changesToPass = new ChangeTupleSet().makeCanonical();
1527 Iterator<ChangeTuple> itrCprime = C.iterator();
1528 while( itrCprime.hasNext() ) {
1529 ChangeTuple c = itrCprime.next();
1530 if( edgeF.getBeta().contains( c.getSetToMatch() ) ) {
1531 changesToPass = changesToPass.union(c);
1535 if( !changesToPass.isEmpty() ) {
1536 if( !nodePlannedChanges.containsKey(m) ) {
1537 nodePlannedChanges.put(m, new ChangeTupleSet().makeCanonical() );
1540 ChangeTupleSet currentChanges = nodePlannedChanges.get(m);
1542 if( !changesToPass.isSubset(currentChanges) ) {
1544 nodePlannedChanges.put(m, currentChanges.union(changesToPass) );
1550 todoNodes.remove(n);
1553 // then apply all of the changes for each node at once
1554 Iterator itrMap = nodePlannedChanges.entrySet().iterator();
1555 while( itrMap.hasNext() ) {
1556 Map.Entry me = (Map.Entry) itrMap.next();
1557 HeapRegionNode n = (HeapRegionNode) me.getKey();
1558 ChangeTupleSet C = (ChangeTupleSet) me.getValue();
1560 n.setAlphaNew( n.getAlpha().applyChangeSet( C, false ) );
1561 nodesWithNewAlpha.add( n );
1564 propagateTokensOverEdges(todoEdges, edgePlannedChanges, edgesWithNewBeta);
1568 protected void propagateTokensOverEdges(
1569 HashSet<ReferenceEdge> todoEdges,
1570 Hashtable<ReferenceEdge, ChangeTupleSet> edgePlannedChanges,
1571 HashSet<ReferenceEdge> edgesWithNewBeta) {
1573 // first propagate all change tuples everywhere they can go
1574 while( !todoEdges.isEmpty() ) {
1575 ReferenceEdge edgeE = todoEdges.iterator().next();
1576 todoEdges.remove(edgeE);
1578 if( !edgePlannedChanges.containsKey(edgeE) ) {
1579 edgePlannedChanges.put(edgeE, new ChangeTupleSet().makeCanonical() );
1582 ChangeTupleSet C = edgePlannedChanges.get(edgeE);
1584 ChangeTupleSet changesToPass = new ChangeTupleSet().makeCanonical();
1587 Iterator<ChangeTuple> itrC = C.iterator();
1588 while( itrC.hasNext() ) {
1589 ChangeTuple c = itrC.next();
1590 if( edgeE.getBeta().contains( c.getSetToMatch() ) ) {
1591 changesToPass = changesToPass.union(c);
1595 OwnershipNode onSrc = edgeE.getSrc();
1597 if( !changesToPass.isEmpty() && onSrc instanceof HeapRegionNode ) {
1598 HeapRegionNode n = (HeapRegionNode) onSrc;
1600 Iterator<ReferenceEdge> referItr = n.iteratorToReferencers();
1601 while( referItr.hasNext() ) {
1602 ReferenceEdge edgeF = referItr.next();
1604 if( !edgePlannedChanges.containsKey(edgeF) ) {
1605 edgePlannedChanges.put(edgeF, new ChangeTupleSet().makeCanonical() );
1608 ChangeTupleSet currentChanges = edgePlannedChanges.get(edgeF);
1610 if( !changesToPass.isSubset(currentChanges) ) {
1611 todoEdges.add(edgeF);
1612 edgePlannedChanges.put(edgeF, currentChanges.union(changesToPass) );
1618 // then apply all of the changes for each edge at once
1619 Iterator itrMap = edgePlannedChanges.entrySet().iterator();
1620 while( itrMap.hasNext() ) {
1621 Map.Entry me = (Map.Entry) itrMap.next();
1622 ReferenceEdge e = (ReferenceEdge) me.getKey();
1623 ChangeTupleSet C = (ChangeTupleSet) me.getValue();
1625 e.setBetaNew( e.getBeta().applyChangeSet( C, true ) );
1626 edgesWithNewBeta.add( e );
1631 public Set<Integer> calculateAliasedParamSet( FlatCall fc,
1635 Hashtable<Integer, LabelNode> paramIndex2ln =
1636 new Hashtable<Integer, LabelNode>();
1638 Hashtable<Integer, HashSet<HeapRegionNode> > paramIndex2reachableCallerNodes =
1639 new Hashtable<Integer, HashSet<HeapRegionNode> >();
1641 for( int i = 0; i < fm.numParameters(); ++i ) {
1642 Integer paramIndex = new Integer( i );
1643 TempDescriptor tdParam = fm.getParameter( i );
1644 TypeDescriptor typeParam = tdParam.getType();
1646 if( typeParam.isImmutable() && !typeParam.isArray() ) {
1647 // don't bother with this primitive parameter, it
1648 // cannot affect reachability
1652 // now depending on whether the callee is static or not
1653 // we need to account for a "this" argument in order to
1654 // find the matching argument in the caller context
1655 TempDescriptor argTemp_i;
1657 argTemp_i = fc.getArg(paramIndex);
1659 if( paramIndex.equals(0) ) {
1660 argTemp_i = fc.getThis();
1662 argTemp_i = fc.getArg(paramIndex - 1);
1666 // in non-static methods there is a "this" pointer
1667 // that should be taken into account
1669 assert fc.numArgs() == fm.numParameters();
1671 assert fc.numArgs() + 1 == fm.numParameters();
1674 LabelNode argLabel_i = getLabelNodeFromTemp(argTemp_i);
1675 paramIndex2ln.put(paramIndex, argLabel_i);
1678 Iterator lnArgItr = paramIndex2ln.entrySet().iterator();
1679 while( lnArgItr.hasNext() ) {
1680 Map.Entry me = (Map.Entry)lnArgItr.next();
1681 Integer index = (Integer) me.getKey();
1682 LabelNode lnArg_i = (LabelNode) me.getValue();
1684 HashSet<HeapRegionNode> reachableNodes = new HashSet<HeapRegionNode>();
1685 HashSet<HeapRegionNode> todoNodes = new HashSet<HeapRegionNode>();
1687 // to find all reachable nodes, start with label referencees
1688 Iterator<ReferenceEdge> edgeArgItr = lnArg_i.iteratorToReferencees();
1689 while( edgeArgItr.hasNext() ) {
1690 ReferenceEdge edge = edgeArgItr.next();
1691 todoNodes.add( edge.getDst() );
1694 // then follow links until all reachable nodes have been found
1695 while( !todoNodes.isEmpty() ) {
1696 HeapRegionNode hrn = todoNodes.iterator().next();
1697 todoNodes.remove(hrn);
1698 reachableNodes.add(hrn);
1700 Iterator<ReferenceEdge> edgeItr = hrn.iteratorToReferencees();
1701 while( edgeItr.hasNext() ) {
1702 ReferenceEdge edge = edgeItr.next();
1704 if( !reachableNodes.contains(edge.getDst() ) ) {
1705 todoNodes.add(edge.getDst() );
1711 paramIndex2reachableCallerNodes.put(index, reachableNodes);
1714 Set<Integer> aliasedIndices = new HashSet<Integer>();
1716 // check for arguments that are aliased
1717 for( int i = 0; i < fm.numParameters(); ++i ) {
1718 for( int j = 0; j < i; ++j ) {
1719 HashSet<HeapRegionNode> s1 = paramIndex2reachableCallerNodes.get( i );
1720 HashSet<HeapRegionNode> s2 = paramIndex2reachableCallerNodes.get( j );
1722 // some parameters are immutable or primitive, so skip em
1723 if( s1 == null || s2 == null ) {
1727 Set<HeapRegionNode> intersection = new HashSet<HeapRegionNode>(s1);
1728 intersection.retainAll(s2);
1730 if( !intersection.isEmpty() ) {
1731 aliasedIndices.add( new Integer( i ) );
1732 aliasedIndices.add( new Integer( j ) );
1737 return aliasedIndices;
1741 private String makeMapKey( Integer i, Integer j, String field ) {
1742 return i+","+j+","+field;
1745 private String makeMapKey( Integer i, String field ) {
1749 // these hashtables are used during the mapping procedure to say that
1750 // with respect to some argument i there is an edge placed into some
1751 // category for mapping with respect to another argument index j
1752 // so the key into the hashtable is i, the value is a two-element vector
1753 // that contains in 0 the edge and in 1 the Integer index j
1754 private void ensureEmptyEdgeIndexPair( Hashtable< Integer, Set<Vector> > edge_index_pairs,
1757 Set<Vector> ei = edge_index_pairs.get( indexI );
1759 ei = new HashSet<Vector>();
1761 edge_index_pairs.put( indexI, ei );
1764 private void addEdgeIndexPair( Hashtable< Integer, Set<Vector> > edge_index_pairs,
1769 Vector v = new Vector(); v.setSize( 2 );
1771 v.set( 1 , indexJ );
1772 Set<Vector> ei = edge_index_pairs.get( indexI );
1774 ei = new HashSet<Vector>();
1777 edge_index_pairs.put( indexI, ei );
1780 private ReachabilitySet funcScriptR( ReachabilitySet rsIn,
1781 OwnershipGraph ogCallee,
1782 MethodContext mc ) {
1784 ReachabilitySet rsOut = new ReachabilitySet( rsIn );
1786 Iterator itr = ogCallee.paramIndex2paramTokenPrimary.entrySet().iterator();
1787 while( itr.hasNext() ) {
1788 Map.Entry me = (Map.Entry) itr.next();
1789 Integer i = (Integer) me.getKey();
1790 TokenTuple p_i = (TokenTuple) me.getValue();
1791 TokenTuple s_i = ogCallee.paramIndex2paramTokenSecondary.get( i );
1793 // skip this if there is no secondary token or the parameter
1794 // is part of the aliasing context
1795 if( s_i == null || mc.getAliasedParamIndices().contains( i ) ) {
1799 rsOut = rsOut.removeTokenAIfTokenB( p_i, s_i );
1805 public void resolveMethodCall(FlatCall fc,
1808 OwnershipGraph ogCallee,
1820 System.out.println( " In mapping proc" );
1825 String debugCaller = "foo";
1826 String debugCallee = "bar";
1828 if( mc.getDescriptor().getSymbol().equals( debugCaller ) &&
1829 fm.getMethod().getSymbol().equals( debugCallee ) ) {
1832 writeGraph( "debug1Before", true, true, true, false, false );
1833 ogCallee.writeGraph( "debug0Callee", true, true, true, false, false );
1834 } catch( IOException e ) {}
1836 System.out.println( " "+mc+" is calling "+fm );
1840 // define rewrite rules and other structures to organize data by parameter/argument index
1841 Hashtable<Integer, ReachabilitySet> paramIndex2rewriteH_p = new Hashtable<Integer, ReachabilitySet>();
1842 Hashtable<Integer, ReachabilitySet> paramIndex2rewriteH_s = new Hashtable<Integer, ReachabilitySet>();
1844 Hashtable<String, ReachabilitySet> paramIndex2rewriteJ_p2p = new Hashtable<String, ReachabilitySet>(); // select( i, j, f )
1845 Hashtable<String, ReachabilitySet> paramIndex2rewriteJ_p2s = new Hashtable<String, ReachabilitySet>(); // select( i, f )
1846 Hashtable<Integer, ReachabilitySet> paramIndex2rewriteJ_s2p = new Hashtable<Integer, ReachabilitySet>();
1847 Hashtable<Integer, ReachabilitySet> paramIndex2rewriteJ_s2s = new Hashtable<Integer, ReachabilitySet>();
1849 Hashtable<Integer, ReachabilitySet> paramIndex2rewriteK_p = new Hashtable<Integer, ReachabilitySet>();
1850 Hashtable<Integer, ReachabilitySet> paramIndex2rewriteK_p2 = new Hashtable<Integer, ReachabilitySet>();
1851 Hashtable<Integer, ReachabilitySet> paramIndex2rewriteK_s = new Hashtable<Integer, ReachabilitySet>();
1853 Hashtable<Integer, ReachabilitySet> paramIndex2rewrite_d_p = new Hashtable<Integer, ReachabilitySet>();
1854 Hashtable<Integer, ReachabilitySet> paramIndex2rewrite_d_s = new Hashtable<Integer, ReachabilitySet>();
1856 Hashtable<Integer, ReachabilitySet> paramIndex2rewriteD = new Hashtable<Integer, ReachabilitySet>();
1859 Hashtable<Integer, LabelNode> paramIndex2ln = new Hashtable<Integer, LabelNode>();
1862 paramIndex2rewriteH_p.put( bogusIndex, rsIdentity );
1863 paramIndex2rewriteH_s.put( bogusIndex, rsIdentity );
1865 paramIndex2rewriteJ_p2p.put( bogusIndex.toString(), rsIdentity );
1866 paramIndex2rewriteJ_p2s.put( bogusIndex.toString(), rsIdentity );
1867 paramIndex2rewriteJ_s2p.put( bogusIndex, rsIdentity );
1868 paramIndex2rewriteJ_s2s.put( bogusIndex, rsIdentity );
1871 for( int i = 0; i < fm.numParameters(); ++i ) {
1872 Integer paramIndex = new Integer(i);
1874 if( !ogCallee.paramIndex2idPrimary.containsKey( paramIndex ) ) {
1875 // skip this immutable parameter
1879 // setup H (primary)
1880 Integer idPrimary = ogCallee.paramIndex2idPrimary.get( paramIndex );
1881 assert ogCallee.id2hrn.containsKey( idPrimary );
1882 HeapRegionNode hrnPrimary = ogCallee.id2hrn.get( idPrimary );
1883 assert hrnPrimary != null;
1884 paramIndex2rewriteH_p.put( paramIndex, toShadowTokens( ogCallee, hrnPrimary.getAlpha() ) );
1886 // setup J (primary->X)
1887 Iterator<ReferenceEdge> p2xItr = hrnPrimary.iteratorToReferencees();
1888 while( p2xItr.hasNext() ) {
1889 ReferenceEdge p2xEdge = p2xItr.next();
1891 // we only care about initial parameter edges here
1892 if( !p2xEdge.isInitialParam() ) { continue; }
1894 HeapRegionNode hrnDst = p2xEdge.getDst();
1896 if( ogCallee.idPrimary2paramIndexSet.containsKey( hrnDst.getID() ) ) {
1897 Iterator<Integer> jItr = ogCallee.idPrimary2paramIndexSet.get( hrnDst.getID() ).iterator();
1898 while( jItr.hasNext() ) {
1899 Integer j = jItr.next();
1900 paramIndex2rewriteJ_p2p.put( makeMapKey( i, j, p2xEdge.getField() ),
1901 toShadowTokens( ogCallee, p2xEdge.getBeta() ) );
1905 assert ogCallee.idSecondary2paramIndexSet.containsKey( hrnDst.getID() );
1906 paramIndex2rewriteJ_p2s.put( makeMapKey( i, p2xEdge.getField() ),
1907 toShadowTokens( ogCallee, p2xEdge.getBeta() ) );
1911 // setup K (primary)
1912 TempDescriptor tdParamQ = ogCallee.paramIndex2tdQ.get( paramIndex );
1913 assert tdParamQ != null;
1914 LabelNode lnParamQ = ogCallee.td2ln.get( tdParamQ );
1915 assert lnParamQ != null;
1916 ReferenceEdge edgeSpecialQ_i = lnParamQ.getReferenceTo( hrnPrimary, null, null );
1917 assert edgeSpecialQ_i != null;
1918 ReachabilitySet qBeta = toShadowTokens( ogCallee, edgeSpecialQ_i.getBeta() );
1920 TokenTuple p_i = ogCallee.paramIndex2paramTokenPrimary .get( paramIndex );
1921 TokenTuple s_i = ogCallee.paramIndex2paramTokenSecondary.get( paramIndex );
1923 ReachabilitySet K_p = new ReachabilitySet().makeCanonical();
1924 ReachabilitySet K_p2 = new ReachabilitySet().makeCanonical();
1928 // sort qBeta into K_p1 and K_p2
1929 Iterator<TokenTupleSet> ttsItr = qBeta.iterator();
1930 while( ttsItr.hasNext() ) {
1931 TokenTupleSet tts = ttsItr.next();
1932 if( s_i != null && tts.containsBoth( p_i, s_i ) ) {
1933 K_p2 = K_p2.union( tts );
1935 K_p = K_p.union( tts );
1939 paramIndex2rewriteK_p .put( paramIndex, K_p );
1940 paramIndex2rewriteK_p2.put( paramIndex, K_p2 );
1943 // if there is a secondary node, compute the rest of the rewrite rules
1944 if( ogCallee.paramIndex2idSecondary.containsKey( paramIndex ) ) {
1946 // setup H (secondary)
1947 Integer idSecondary = ogCallee.paramIndex2idSecondary.get( paramIndex );
1948 assert ogCallee.id2hrn.containsKey( idSecondary );
1949 HeapRegionNode hrnSecondary = ogCallee.id2hrn.get( idSecondary );
1950 assert hrnSecondary != null;
1951 paramIndex2rewriteH_s.put( paramIndex, toShadowTokens( ogCallee, hrnSecondary.getAlpha() ) );
1953 // setup J (secondary->X)
1954 Iterator<ReferenceEdge> s2xItr = hrnSecondary.iteratorToReferencees();
1955 while( s2xItr.hasNext() ) {
1956 ReferenceEdge s2xEdge = s2xItr.next();
1958 if( !s2xEdge.isInitialParam() ) { continue; }
1960 HeapRegionNode hrnDst = s2xEdge.getDst();
1962 if( ogCallee.idPrimary2paramIndexSet.containsKey( hrnDst.getID() ) ) {
1963 Iterator<Integer> jItr = ogCallee.idPrimary2paramIndexSet.get( hrnDst.getID() ).iterator();
1964 while( jItr.hasNext() ) {
1965 Integer j = jItr.next();
1966 paramIndex2rewriteJ_s2p.put( i, toShadowTokens( ogCallee, s2xEdge.getBeta() ) );
1970 assert ogCallee.idSecondary2paramIndexSet.containsKey( hrnDst.getID() );
1971 paramIndex2rewriteJ_s2s.put( i, toShadowTokens( ogCallee, s2xEdge.getBeta() ) );
1975 // setup K (secondary)
1976 TempDescriptor tdParamR = ogCallee.paramIndex2tdR.get( paramIndex );
1977 assert tdParamR != null;
1978 LabelNode lnParamR = ogCallee.td2ln.get( tdParamR );
1979 assert lnParamR != null;
1980 ReferenceEdge edgeSpecialR_i = lnParamR.getReferenceTo( hrnSecondary, null, null );
1981 assert edgeSpecialR_i != null;
1982 paramIndex2rewriteK_s.put( paramIndex,
1983 toShadowTokens( ogCallee, edgeSpecialR_i.getBeta() ) );
1987 // now depending on whether the callee is static or not
1988 // we need to account for a "this" argument in order to
1989 // find the matching argument in the caller context
1990 TempDescriptor argTemp_i;
1992 argTemp_i = fc.getArg( paramIndex );
1994 if( paramIndex.equals( 0 ) ) {
1995 argTemp_i = fc.getThis();
1997 argTemp_i = fc.getArg( paramIndex - 1 );
2001 // in non-static methods there is a "this" pointer
2002 // that should be taken into account
2004 assert fc.numArgs() == fm.numParameters();
2006 assert fc.numArgs() + 1 == fm.numParameters();
2009 // remember which caller arg label maps to param index
2010 LabelNode argLabel_i = getLabelNodeFromTemp( argTemp_i );
2011 paramIndex2ln.put( paramIndex, argLabel_i );
2013 ReachabilitySet d_i_p = new ReachabilitySet().makeCanonical();
2014 ReachabilitySet d_i_s = new ReachabilitySet().makeCanonical();
2015 Iterator<ReferenceEdge> edgeItr = argLabel_i.iteratorToReferencees();
2016 while( edgeItr.hasNext() ) {
2017 ReferenceEdge edge = edgeItr.next();
2019 d_i_p = d_i_p.union( edge.getBeta().intersection( edge.getDst().getAlpha() ) );
2020 d_i_s = d_i_s.union( edge.getBeta() );
2022 paramIndex2rewrite_d_p.put( paramIndex, d_i_p );
2023 paramIndex2rewrite_d_s.put( paramIndex, d_i_s );
2025 // TODO: we should only do this when we need it, and then
2026 // memoize it for the rest of the mapping procedure
2027 ReachabilitySet D_i = d_i_s.exhaustiveArityCombinations();
2028 paramIndex2rewriteD.put( paramIndex, D_i );
2032 // with respect to each argument, map parameter effects into caller
2033 HashSet<HeapRegionNode> nodesWithNewAlpha = new HashSet<HeapRegionNode>();
2034 HashSet<ReferenceEdge> edgesWithNewBeta = new HashSet<ReferenceEdge>();
2036 Hashtable<Integer, Set<HeapRegionNode> > pi2dr =
2037 new Hashtable<Integer, Set<HeapRegionNode> >();
2039 Hashtable<Integer, Set<HeapRegionNode> > pi2r =
2040 new Hashtable<Integer, Set<HeapRegionNode> >();
2042 Set<HeapRegionNode> defParamObj = new HashSet<HeapRegionNode>();
2044 Iterator lnArgItr = paramIndex2ln.entrySet().iterator();
2045 while( lnArgItr.hasNext() ) {
2046 Map.Entry me = (Map.Entry) lnArgItr.next();
2047 Integer index = (Integer) me.getKey();
2048 LabelNode lnArg_i = (LabelNode) me.getValue();
2050 Set<HeapRegionNode> dr = new HashSet<HeapRegionNode>();
2051 Set<HeapRegionNode> r = new HashSet<HeapRegionNode>();
2052 Set<HeapRegionNode> todo = new HashSet<HeapRegionNode>();
2054 // find all reachable nodes starting with label referencees
2055 Iterator<ReferenceEdge> edgeArgItr = lnArg_i.iteratorToReferencees();
2056 while( edgeArgItr.hasNext() ) {
2057 ReferenceEdge edge = edgeArgItr.next();
2058 HeapRegionNode hrn = edge.getDst();
2062 if( lnArg_i.getNumReferencees() == 1 && hrn.isSingleObject() ) {
2063 defParamObj.add( hrn );
2066 Iterator<ReferenceEdge> edgeHrnItr = hrn.iteratorToReferencees();
2067 while( edgeHrnItr.hasNext() ) {
2068 ReferenceEdge edger = edgeHrnItr.next();
2069 todo.add( edger.getDst() );
2072 // then follow links until all reachable nodes have been found
2073 while( !todo.isEmpty() ) {
2074 HeapRegionNode hrnr = todo.iterator().next();
2075 todo.remove( hrnr );
2079 Iterator<ReferenceEdge> edgeItr = hrnr.iteratorToReferencees();
2080 while( edgeItr.hasNext() ) {
2081 ReferenceEdge edger = edgeItr.next();
2082 if( !r.contains( edger.getDst() ) ) {
2083 todo.add( edger.getDst() );
2088 if( hrn.isSingleObject() ) {
2093 pi2dr.put( index, dr );
2094 pi2r .put( index, r );
2097 assert defParamObj.size() <= fm.numParameters();
2100 // now iterate over reachable nodes to rewrite their alpha, and
2101 // classify edges found for beta rewrite
2102 Hashtable<TokenTuple, ReachabilitySet> tokens2states = new Hashtable<TokenTuple, ReachabilitySet>();
2104 Hashtable< Integer, Set<Vector> > edges_p2p = new Hashtable< Integer, Set<Vector> >();
2105 Hashtable< Integer, Set<Vector> > edges_p2s = new Hashtable< Integer, Set<Vector> >();
2106 Hashtable< Integer, Set<Vector> > edges_s2p = new Hashtable< Integer, Set<Vector> >();
2107 Hashtable< Integer, Set<Vector> > edges_s2s = new Hashtable< Integer, Set<Vector> >();
2108 Hashtable< Integer, Set<Vector> > edges_up_dr = new Hashtable< Integer, Set<Vector> >();
2109 Hashtable< Integer, Set<Vector> > edges_up_r = new Hashtable< Integer, Set<Vector> >();
2112 // so again, with respect to some arg i...
2113 lnArgItr = paramIndex2ln.entrySet().iterator();
2114 while( lnArgItr.hasNext() ) {
2115 Map.Entry me = (Map.Entry) lnArgItr.next();
2116 Integer index = (Integer) me.getKey();
2117 LabelNode lnArg_i = (LabelNode) me.getValue();
2119 TokenTuple p_i = ogCallee.paramIndex2paramTokenPrimary.get( index );
2120 TokenTuple s_i = ogCallee.paramIndex2paramTokenSecondary.get( index );
2123 ensureEmptyEdgeIndexPair( edges_p2p, index );
2124 ensureEmptyEdgeIndexPair( edges_p2s, index );
2125 ensureEmptyEdgeIndexPair( edges_s2p, index );
2126 ensureEmptyEdgeIndexPair( edges_s2s, index );
2127 ensureEmptyEdgeIndexPair( edges_up_dr, index );
2128 ensureEmptyEdgeIndexPair( edges_up_r, index );
2130 Set<HeapRegionNode> dr = pi2dr.get( index );
2131 Iterator<HeapRegionNode> hrnItr = dr.iterator();
2132 while( hrnItr.hasNext() ) {
2133 // this heap region is definitely an "a_i" or primary by virtue of being in dr
2134 HeapRegionNode hrn = hrnItr.next();
2136 tokens2states.clear();
2137 tokens2states.put( p_i, hrn.getAlpha() );
2139 rewriteCallerReachability( index,
2142 paramIndex2rewriteH_p.get( index ),
2144 paramIndex2rewrite_d_p,
2145 paramIndex2rewrite_d_s,
2146 paramIndex2rewriteD,
2151 nodesWithNewAlpha.add( hrn );
2154 Iterator<ReferenceEdge> edgeItr = hrn.iteratorToReferencers();
2155 while( edgeItr.hasNext() ) {
2156 ReferenceEdge edge = edgeItr.next();
2157 OwnershipNode on = edge.getSrc();
2159 boolean edge_classified = false;
2161 if( on instanceof HeapRegionNode ) {
2162 // hrn0 may be "a_j" and/or "r_j" or even neither
2163 HeapRegionNode hrn0 = (HeapRegionNode) on;
2165 Iterator itr = pi2dr.entrySet().iterator();
2166 while( itr.hasNext() ) {
2167 Map.Entry mo = (Map.Entry) itr.next();
2168 Integer pi = (Integer) mo.getKey();
2169 Set<HeapRegionNode> dr_i = (Set<HeapRegionNode>) mo.getValue();
2171 if( dr_i.contains( hrn0 ) ) {
2172 addEdgeIndexPair( edges_p2p, pi, edge, index );
2173 edge_classified = true;
2177 itr = pi2r.entrySet().iterator();
2178 while( itr.hasNext() ) {
2179 Map.Entry mo = (Map.Entry) itr.next();
2180 Integer pi = (Integer) mo.getKey();
2181 Set<HeapRegionNode> r_i = (Set<HeapRegionNode>) mo.getValue();
2183 if( r_i.contains( hrn0 ) ) {
2184 addEdgeIndexPair( edges_s2p, pi, edge, index );
2185 edge_classified = true;
2190 // all of these edges are upstream of directly reachable objects
2191 if( !edge_classified ) {
2192 addEdgeIndexPair( edges_up_dr, index, edge, index );
2198 Set<HeapRegionNode> r = pi2r.get( index );
2199 hrnItr = r.iterator();
2200 while( hrnItr.hasNext() ) {
2201 // this heap region is definitely an "r_i" or secondary by virtue of being in r
2202 HeapRegionNode hrn = hrnItr.next();
2205 if( paramIndex2rewriteH_s.contains( index ) ) {
2207 tokens2states.clear();
2208 tokens2states.put( p_i, new ReachabilitySet().makeCanonical() );
2209 tokens2states.put( s_i, hrn.getAlpha() );
2211 rewriteCallerReachability( index,
2214 paramIndex2rewriteH_s.get( index ),
2216 paramIndex2rewrite_d_p,
2217 paramIndex2rewrite_d_s,
2218 paramIndex2rewriteD,
2223 nodesWithNewAlpha.add( hrn );
2227 Iterator<ReferenceEdge> edgeItr = hrn.iteratorToReferencers();
2228 while( edgeItr.hasNext() ) {
2229 ReferenceEdge edge = edgeItr.next();
2230 OwnershipNode on = edge.getSrc();
2232 boolean edge_classified = false;
2234 if( on instanceof HeapRegionNode ) {
2235 // hrn0 may be "a_j" and/or "r_j" or even neither
2236 HeapRegionNode hrn0 = (HeapRegionNode) on;
2238 Iterator itr = pi2dr.entrySet().iterator();
2239 while( itr.hasNext() ) {
2240 Map.Entry mo = (Map.Entry) itr.next();
2241 Integer pi = (Integer) mo.getKey();
2242 Set<HeapRegionNode> dr_i = (Set<HeapRegionNode>) mo.getValue();
2244 if( dr_i.contains( hrn0 ) ) {
2245 addEdgeIndexPair( edges_p2s, pi, edge, index );
2246 edge_classified = true;
2250 itr = pi2r.entrySet().iterator();
2251 while( itr.hasNext() ) {
2252 Map.Entry mo = (Map.Entry) itr.next();
2253 Integer pi = (Integer) mo.getKey();
2254 Set<HeapRegionNode> r_i = (Set<HeapRegionNode>) mo.getValue();
2256 if( r_i.contains( hrn0 ) ) {
2257 addEdgeIndexPair( edges_s2s, pi, edge, index );
2258 edge_classified = true;
2263 // these edges are all upstream of some reachable node
2264 if( !edge_classified ) {
2265 addEdgeIndexPair( edges_up_r, index, edge, index );
2272 // and again, with respect to some arg i...
2273 lnArgItr = paramIndex2ln.entrySet().iterator();
2274 while( lnArgItr.hasNext() ) {
2275 Map.Entry me = (Map.Entry) lnArgItr.next();
2276 Integer index = (Integer) me.getKey();
2277 LabelNode lnArg_i = (LabelNode) me.getValue();
2280 // update reachable edges
2281 Iterator edgeItr = edges_p2p.get( index ).iterator();
2282 while( edgeItr.hasNext() ) {
2283 Vector mo = (Vector) edgeItr.next();
2284 ReferenceEdge edge = (ReferenceEdge) mo.get( 0 );
2285 Integer indexJ = (Integer) mo.get( 1 );
2287 if( !paramIndex2rewriteJ_p2p.contains( makeMapKey( index,
2289 edge.getField() ) ) ) {
2293 TokenTuple p_j = ogCallee.paramIndex2paramTokenPrimary.get( indexJ );
2296 tokens2states.clear();
2297 tokens2states.put( p_j, edge.getBeta() );
2299 rewriteCallerReachability( index,
2302 paramIndex2rewriteJ_p2p.get( makeMapKey( index,
2304 edge.getField() ) ),
2306 paramIndex2rewrite_d_p,
2307 paramIndex2rewrite_d_s,
2308 paramIndex2rewriteD,
2313 edgesWithNewBeta.add( edge );
2317 edgeItr = edges_p2s.get( index ).iterator();
2318 while( edgeItr.hasNext() ) {
2319 Vector mo = (Vector) edgeItr.next();
2320 ReferenceEdge edge = (ReferenceEdge) mo.get( 0 );
2321 Integer indexJ = (Integer) mo.get( 1 );
2323 if( !paramIndex2rewriteJ_p2s.contains( makeMapKey( index,
2324 edge.getField() ) ) ) {
2328 TokenTuple s_j = ogCallee.paramIndex2paramTokenSecondary.get( indexJ );
2331 tokens2states.clear();
2332 tokens2states.put( s_j, edge.getBeta() );
2334 rewriteCallerReachability( index,
2337 paramIndex2rewriteJ_p2s.get( makeMapKey( index,
2338 edge.getField() ) ),
2340 paramIndex2rewrite_d_p,
2341 paramIndex2rewrite_d_s,
2342 paramIndex2rewriteD,
2347 edgesWithNewBeta.add( edge );
2351 edgeItr = edges_s2p.get( index ).iterator();
2352 while( edgeItr.hasNext() ) {
2353 Vector mo = (Vector) edgeItr.next();
2354 ReferenceEdge edge = (ReferenceEdge) mo.get( 0 );
2355 Integer indexJ = (Integer) mo.get( 1 );
2357 if( !paramIndex2rewriteJ_s2p.contains( index ) ) {
2361 TokenTuple p_j = ogCallee.paramIndex2paramTokenPrimary.get( indexJ );
2364 tokens2states.clear();
2365 tokens2states.put( p_j, edge.getBeta() );
2367 rewriteCallerReachability( index,
2370 paramIndex2rewriteJ_s2p.get( index ),
2372 paramIndex2rewrite_d_p,
2373 paramIndex2rewrite_d_s,
2374 paramIndex2rewriteD,
2379 edgesWithNewBeta.add( edge );
2383 edgeItr = edges_s2s.get( index ).iterator();
2384 while( edgeItr.hasNext() ) {
2385 Vector mo = (Vector) edgeItr.next();
2386 ReferenceEdge edge = (ReferenceEdge) mo.get( 0 );
2387 Integer indexJ = (Integer) mo.get( 1 );
2389 if( !paramIndex2rewriteJ_s2s.contains( index ) ) {
2393 TokenTuple s_j = ogCallee.paramIndex2paramTokenSecondary.get( indexJ );
2396 tokens2states.clear();
2397 tokens2states.put( s_j, edge.getBeta() );
2399 rewriteCallerReachability( index,
2402 paramIndex2rewriteJ_s2s.get( index ),
2404 paramIndex2rewrite_d_p,
2405 paramIndex2rewrite_d_s,
2406 paramIndex2rewriteD,
2411 edgesWithNewBeta.add( edge );
2415 // update directly upstream edges
2416 Hashtable<ReferenceEdge, ChangeTupleSet> edgeUpstreamPlannedChanges =
2417 new Hashtable<ReferenceEdge, ChangeTupleSet>();
2419 HashSet<ReferenceEdge> edgesDirectlyUpstream =
2420 new HashSet<ReferenceEdge>();
2422 edgeItr = edges_up_dr.get( index ).iterator();
2423 while( edgeItr.hasNext() ) {
2424 Vector mo = (Vector) edgeItr.next();
2425 ReferenceEdge edge = (ReferenceEdge) mo.get( 0 );
2426 Integer indexJ = (Integer) mo.get( 1 );
2428 edgesDirectlyUpstream.add( edge );
2430 TokenTuple p_j = ogCallee.paramIndex2paramTokenPrimary.get( indexJ );
2433 // start with K_p2 and p_j
2434 tokens2states.clear();
2435 tokens2states.put( p_j, edge.getBeta() );
2437 rewriteCallerReachability( index,
2440 paramIndex2rewriteK_p2.get( index ),
2442 paramIndex2rewrite_d_p,
2443 paramIndex2rewrite_d_s,
2444 paramIndex2rewriteD,
2447 edgeUpstreamPlannedChanges );
2449 // and add in s_j, if required, and do K_p
2450 TokenTuple s_j = ogCallee.paramIndex2paramTokenSecondary.get( indexJ );
2452 tokens2states.put( s_j, edge.getBeta() );
2455 rewriteCallerReachability( index,
2458 paramIndex2rewriteK_p.get( index ),
2460 paramIndex2rewrite_d_p,
2461 paramIndex2rewrite_d_s,
2462 paramIndex2rewriteD,
2465 edgeUpstreamPlannedChanges );
2467 edgesWithNewBeta.add( edge );
2470 propagateTokensOverEdges( edgesDirectlyUpstream,
2471 edgeUpstreamPlannedChanges,
2475 // update upstream edges
2476 edgeUpstreamPlannedChanges =
2477 new Hashtable<ReferenceEdge, ChangeTupleSet>();
2479 HashSet<ReferenceEdge> edgesUpstream =
2480 new HashSet<ReferenceEdge>();
2482 edgeItr = edges_up_r.get( index ).iterator();
2483 while( edgeItr.hasNext() ) {
2484 Vector mo = (Vector) edgeItr.next();
2485 ReferenceEdge edge = (ReferenceEdge) mo.get( 0 );
2486 Integer indexJ = (Integer) mo.get( 1 );
2488 if( !paramIndex2rewriteK_s.contains( index ) ) {
2492 edgesUpstream.add( edge );
2494 TokenTuple p_j = ogCallee.paramIndex2paramTokenPrimary.get( indexJ );
2497 TokenTuple s_j = ogCallee.paramIndex2paramTokenSecondary.get( indexJ );
2500 tokens2states.clear();
2501 tokens2states.put( p_j, rsWttsEmpty );
2502 tokens2states.put( s_j, edge.getBeta() );
2504 rewriteCallerReachability( index,
2507 paramIndex2rewriteK_s.get( index ),
2509 paramIndex2rewrite_d_p,
2510 paramIndex2rewrite_d_s,
2511 paramIndex2rewriteD,
2514 edgeUpstreamPlannedChanges );
2516 edgesWithNewBeta.add( edge );
2519 propagateTokensOverEdges( edgesUpstream,
2520 edgeUpstreamPlannedChanges,
2523 } // end effects per argument/parameter map
2526 // commit changes to alpha and beta
2527 Iterator<HeapRegionNode> nodeItr = nodesWithNewAlpha.iterator();
2528 while( nodeItr.hasNext() ) {
2529 nodeItr.next().applyAlphaNew();
2532 Iterator<ReferenceEdge> edgeItr = edgesWithNewBeta.iterator();
2533 while( edgeItr.hasNext() ) {
2534 edgeItr.next().applyBetaNew();
2538 // verify the existence of allocation sites and their
2539 // shadows from the callee in the context of this caller graph
2540 // then map allocated nodes of callee onto the caller shadows
2542 Hashtable<TokenTuple, ReachabilitySet> tokens2statesEmpty = new Hashtable<TokenTuple, ReachabilitySet>();
2544 Iterator<AllocationSite> asItr = ogCallee.allocationSites.iterator();
2545 while( asItr.hasNext() ) {
2546 AllocationSite allocSite = asItr.next();
2548 // grab the summary in the caller just to make sure
2549 // the allocation site has nodes in the caller
2550 HeapRegionNode hrnSummary = getSummaryNode( allocSite );
2552 // assert that the shadow nodes have no reference edges
2553 // because they're brand new to the graph, or last time
2554 // they were used they should have been cleared of edges
2555 HeapRegionNode hrnShadowSummary = getShadowSummaryNode( allocSite );
2556 assert hrnShadowSummary.getNumReferencers() == 0;
2557 assert hrnShadowSummary.getNumReferencees() == 0;
2559 // then bring g_ij onto g'_ij and rewrite
2560 HeapRegionNode hrnSummaryCallee = ogCallee.getSummaryNode( allocSite );
2561 hrnShadowSummary.setAlpha( toShadowTokens( ogCallee, hrnSummaryCallee.getAlpha() ) );
2563 // shadow nodes only are touched by a rewrite one time,
2564 // so rewrite and immediately commit--and they don't belong
2565 // to a particular parameter, so use a bogus param index
2566 // that pulls a self-rewrite out of H
2567 rewriteCallerReachability( bogusIndex,
2570 funcScriptR( hrnShadowSummary.getAlpha(), ogCallee, mc ),
2572 paramIndex2rewrite_d_p,
2573 paramIndex2rewrite_d_s,
2574 paramIndex2rewriteD,
2579 hrnShadowSummary.applyAlphaNew();
2582 for( int i = 0; i < allocSite.getAllocationDepth(); ++i ) {
2583 Integer idIth = allocSite.getIthOldest(i);
2584 assert id2hrn.containsKey(idIth);
2585 HeapRegionNode hrnIth = id2hrn.get(idIth);
2587 Integer idShadowIth = -(allocSite.getIthOldest(i));
2588 assert id2hrn.containsKey(idShadowIth);
2589 HeapRegionNode hrnIthShadow = id2hrn.get(idShadowIth);
2590 assert hrnIthShadow.getNumReferencers() == 0;
2591 assert hrnIthShadow.getNumReferencees() == 0;
2593 assert ogCallee.id2hrn.containsKey(idIth);
2594 HeapRegionNode hrnIthCallee = ogCallee.id2hrn.get(idIth);
2595 hrnIthShadow.setAlpha(toShadowTokens(ogCallee, hrnIthCallee.getAlpha() ) );
2597 rewriteCallerReachability( bogusIndex,
2600 funcScriptR( hrnIthShadow.getAlpha(), ogCallee, mc ),
2602 paramIndex2rewrite_d_p,
2603 paramIndex2rewrite_d_s,
2604 paramIndex2rewriteD,
2609 hrnIthShadow.applyAlphaNew();
2614 // for every heap region->heap region edge in the
2615 // callee graph, create the matching edge or edges
2616 // in the caller graph
2617 Set sCallee = ogCallee.id2hrn.entrySet();
2618 Iterator iCallee = sCallee.iterator();
2619 while( iCallee.hasNext() ) {
2620 Map.Entry meCallee = (Map.Entry) iCallee.next();
2621 Integer idCallee = (Integer) meCallee.getKey();
2622 HeapRegionNode hrnCallee = (HeapRegionNode) meCallee.getValue();
2624 Iterator<ReferenceEdge> heapRegionsItrCallee = hrnCallee.iteratorToReferencees();
2625 while( heapRegionsItrCallee.hasNext() ) {
2626 ReferenceEdge edgeCallee = heapRegionsItrCallee.next();
2627 HeapRegionNode hrnChildCallee = edgeCallee.getDst();
2628 Integer idChildCallee = hrnChildCallee.getID();
2630 // only address this edge if it is not a special initial edge
2631 if( !edgeCallee.isInitialParam() ) {
2633 // now we know that in the callee method's ownership graph
2634 // there is a heap region->heap region reference edge given
2635 // by heap region pointers:
2636 // hrnCallee -> heapChildCallee
2638 // or by the ownership-graph independent ID's:
2639 // idCallee -> idChildCallee
2641 // make the edge with src and dst so beta info is
2642 // calculated once, then copy it for each new edge in caller
2643 ReferenceEdge edgeNewInCallerTemplate = new ReferenceEdge( null,
2645 edgeCallee.getType(),
2646 edgeCallee.getField(),
2648 funcScriptR( toShadowTokens( ogCallee,
2649 edgeCallee.getBeta()
2655 rewriteCallerReachability( bogusIndex,
2657 edgeNewInCallerTemplate,
2658 edgeNewInCallerTemplate.getBeta(),
2660 paramIndex2rewrite_d_p,
2661 paramIndex2rewrite_d_s,
2662 paramIndex2rewriteD,
2667 edgeNewInCallerTemplate.applyBetaNew();
2670 // So now make a set of possible source heaps in the caller graph
2671 // and a set of destination heaps in the caller graph, and make
2672 // a reference edge in the caller for every possible (src,dst) pair
2673 HashSet<HeapRegionNode> possibleCallerSrcs =
2674 getHRNSetThatPossiblyMapToCalleeHRN( ogCallee,
2675 (HeapRegionNode) edgeCallee.getSrc(),
2679 HashSet<HeapRegionNode> possibleCallerDsts =
2680 getHRNSetThatPossiblyMapToCalleeHRN( ogCallee,
2681 edgeCallee.getDst(),
2685 // make every possible pair of {srcSet} -> {dstSet} edges in the caller
2686 Iterator srcItr = possibleCallerSrcs.iterator();
2687 while( srcItr.hasNext() ) {
2688 HeapRegionNode src = (HeapRegionNode) srcItr.next();
2690 if( !hasMatchingField( src, edgeCallee ) ) {
2691 // prune this source node possibility
2695 Iterator dstItr = possibleCallerDsts.iterator();
2696 while( dstItr.hasNext() ) {
2697 HeapRegionNode dst = (HeapRegionNode) dstItr.next();
2699 if( !hasMatchingType( edgeCallee, dst ) ) {
2704 // otherwise the caller src and dst pair can match the edge, so make it
2705 ReferenceEdge edgeNewInCaller = edgeNewInCallerTemplate.copy();
2706 edgeNewInCaller.setSrc( src );
2707 edgeNewInCaller.setDst( dst );
2709 ReferenceEdge edgeExisting = src.getReferenceTo( dst,
2710 edgeNewInCaller.getType(),
2711 edgeNewInCaller.getField() );
2712 if( edgeExisting == null ) {
2713 // if this edge doesn't exist in the caller, create it
2714 addReferenceEdge( src, dst, edgeNewInCaller );
2717 // if it already exists, merge with it
2718 edgeExisting.setBeta( edgeExisting.getBeta().union( edgeNewInCaller.getBeta() ) );
2727 // return value may need to be assigned in caller
2728 TempDescriptor returnTemp = fc.getReturnTemp();
2729 if( returnTemp != null && !returnTemp.getType().isImmutable() ) {
2731 LabelNode lnLhsCaller = getLabelNodeFromTemp( returnTemp );
2732 clearReferenceEdgesFrom( lnLhsCaller, null, null, true );
2734 LabelNode lnReturnCallee = ogCallee.getLabelNodeFromTemp( tdReturn );
2735 Iterator<ReferenceEdge> edgeCalleeItr = lnReturnCallee.iteratorToReferencees();
2736 while( edgeCalleeItr.hasNext() ) {
2737 ReferenceEdge edgeCallee = edgeCalleeItr.next();
2739 ReferenceEdge edgeNewInCallerTemplate = new ReferenceEdge( null,
2741 edgeCallee.getType(),
2742 edgeCallee.getField(),
2744 funcScriptR( toShadowTokens(ogCallee,
2745 edgeCallee.getBeta() ),
2749 rewriteCallerReachability( bogusIndex,
2751 edgeNewInCallerTemplate,
2752 edgeNewInCallerTemplate.getBeta(),
2754 paramIndex2rewrite_d_p,
2755 paramIndex2rewrite_d_s,
2756 paramIndex2rewriteD,
2761 edgeNewInCallerTemplate.applyBetaNew();
2764 HashSet<HeapRegionNode> assignCallerRhs =
2765 getHRNSetThatPossiblyMapToCalleeHRN( ogCallee,
2766 edgeCallee.getDst(),
2770 Iterator<HeapRegionNode> itrHrn = assignCallerRhs.iterator();
2771 while( itrHrn.hasNext() ) {
2772 HeapRegionNode hrnCaller = itrHrn.next();
2774 if( !hasMatchingType( edgeCallee, hrnCaller ) ) {
2779 // otherwise caller node can match callee edge, so make it
2780 ReferenceEdge edgeNewInCaller = edgeNewInCallerTemplate.copy();
2781 edgeNewInCaller.setSrc( lnLhsCaller );
2782 edgeNewInCaller.setDst( hrnCaller );
2784 ReferenceEdge edgeExisting = lnLhsCaller.getReferenceTo( hrnCaller,
2785 edgeNewInCaller.getType(),
2786 edgeNewInCaller.getField() );
2787 if( edgeExisting == null ) {
2789 // if this edge doesn't exist in the caller, create it
2790 addReferenceEdge( lnLhsCaller, hrnCaller, edgeNewInCaller );
2792 // if it already exists, merge with it
2793 edgeExisting.setBeta( edgeExisting.getBeta().union( edgeNewInCaller.getBeta() ) );
2800 // merge the shadow nodes of allocation sites back down to normal capacity
2801 Iterator<AllocationSite> allocItr = ogCallee.allocationSites.iterator();
2802 while( allocItr.hasNext() ) {
2803 AllocationSite as = allocItr.next();
2805 // first age each allocation site enough times to make room for the shadow nodes
2806 for( int i = 0; i < as.getAllocationDepth(); ++i ) {
2810 // then merge the shadow summary into the normal summary
2811 HeapRegionNode hrnSummary = getSummaryNode( as );
2812 assert hrnSummary != null;
2814 HeapRegionNode hrnSummaryShadow = getShadowSummaryNode( as );
2815 assert hrnSummaryShadow != null;
2817 mergeIntoSummary( hrnSummaryShadow, hrnSummary );
2819 // then clear off after merge
2820 clearReferenceEdgesFrom( hrnSummaryShadow, null, null, true );
2821 clearReferenceEdgesTo ( hrnSummaryShadow, null, null, true );
2822 hrnSummaryShadow.setAlpha( new ReachabilitySet().makeCanonical() );
2824 // then transplant shadow nodes onto the now clean normal nodes
2825 for( int i = 0; i < as.getAllocationDepth(); ++i ) {
2827 Integer idIth = as.getIthOldest( i );
2828 HeapRegionNode hrnIth = id2hrn.get( idIth );
2829 Integer idIthShadow = as.getIthOldestShadow( i );
2830 HeapRegionNode hrnIthShadow = id2hrn.get( idIthShadow );
2832 transferOnto( hrnIthShadow, hrnIth );
2834 // clear off shadow nodes after transfer
2835 clearReferenceEdgesFrom( hrnIthShadow, null, null, true );
2836 clearReferenceEdgesTo ( hrnIthShadow, null, null, true );
2837 hrnIthShadow.setAlpha( new ReachabilitySet().makeCanonical() );
2840 // finally, globally change shadow tokens into normal tokens
2841 Iterator itrAllLabelNodes = td2ln.entrySet().iterator();
2842 while( itrAllLabelNodes.hasNext() ) {
2843 Map.Entry me = (Map.Entry) itrAllLabelNodes.next();
2844 LabelNode ln = (LabelNode) me.getValue();
2846 Iterator<ReferenceEdge> itrEdges = ln.iteratorToReferencees();
2847 while( itrEdges.hasNext() ) {
2848 unshadowTokens( as, itrEdges.next() );
2852 Iterator itrAllHRNodes = id2hrn.entrySet().iterator();
2853 while( itrAllHRNodes.hasNext() ) {
2854 Map.Entry me = (Map.Entry) itrAllHRNodes.next();
2855 HeapRegionNode hrnToAge = (HeapRegionNode) me.getValue();
2857 unshadowTokens( as, hrnToAge );
2859 Iterator<ReferenceEdge> itrEdges = hrnToAge.iteratorToReferencees();
2860 while( itrEdges.hasNext() ) {
2861 unshadowTokens( as, itrEdges.next() );
2867 if( mc.getDescriptor().getSymbol().equals( debugCaller ) &&
2868 fm.getMethod().getSymbol().equals( debugCallee ) ) {
2870 writeGraph( "debug2JustBeforeSweep", true, true, true, false, false );
2871 } catch( IOException e ) {}
2875 // improve reachability as much as possible
2880 if( mc.getDescriptor().getSymbol().equals( debugCaller ) &&
2881 fm.getMethod().getSymbol().equals( debugCallee ) ) {
2883 writeGraph( "debug9endResolveCall", true, true, true, false, false );
2884 } catch( IOException e ) {}
2885 System.out.println( " "+mc+" done calling "+fm );
2891 System.out.println( " End mapping proc" );
2897 protected boolean hasMatchingField(HeapRegionNode src, ReferenceEdge edge) {
2899 // if no type, then it's a match-everything region
2900 TypeDescriptor tdSrc = src.getType();
2901 if( tdSrc == null ) {
2905 if( tdSrc.isArray() ) {
2906 TypeDescriptor td = edge.getType();
2909 TypeDescriptor tdSrcDeref = tdSrc.dereference();
2910 assert tdSrcDeref != null;
2912 if( !typeUtil.isSuperorType( tdSrcDeref, td ) ) {
2916 return edge.getField().equals( OwnershipAnalysis.arrayElementFieldName );
2919 // if it's not a class, it doesn't have any fields to match
2920 if( !tdSrc.isClass() ) {
2924 Iterator fieldsSrcItr = tdSrc.getClassDesc().getFields();
2925 while( fieldsSrcItr.hasNext() ) {
2926 FieldDescriptor fd = (FieldDescriptor) fieldsSrcItr.next();
2927 if( fd.getType().equals( edge.getType() ) &&
2928 fd.getSymbol().equals( edge.getField() ) ) {
2933 // otherwise it is a class with fields
2934 // but we didn't find a match
2939 protected boolean hasMatchingType(ReferenceEdge edge, HeapRegionNode dst) {
2941 // if the region has no type, matches everything
2942 TypeDescriptor tdDst = dst.getType();
2943 if( tdDst == null ) {
2947 // if the type is not a class or an array, don't
2948 // match because primitives are copied, no aliases
2949 ClassDescriptor cdDst = tdDst.getClassDesc();
2950 if( cdDst == null && !tdDst.isArray() ) {
2954 // if the edge type is null, it matches everything
2955 TypeDescriptor tdEdge = edge.getType();
2956 if( tdEdge == null ) {
2960 return typeUtil.isSuperorType(tdEdge, tdDst);
2965 protected void unshadowTokens(AllocationSite as, ReferenceEdge edge) {
2966 edge.setBeta(edge.getBeta().unshadowTokens(as) );
2969 protected void unshadowTokens(AllocationSite as, HeapRegionNode hrn) {
2970 hrn.setAlpha(hrn.getAlpha().unshadowTokens(as) );
2974 private ReachabilitySet toShadowTokens(OwnershipGraph ogCallee,
2975 ReachabilitySet rsIn) {
2977 ReachabilitySet rsOut = new ReachabilitySet(rsIn).makeCanonical();
2979 Iterator<AllocationSite> allocItr = ogCallee.allocationSites.iterator();
2980 while( allocItr.hasNext() ) {
2981 AllocationSite as = allocItr.next();
2983 rsOut = rsOut.toShadowTokens(as);
2986 return rsOut.makeCanonical();
2990 private void rewriteCallerReachability(Integer paramIndex,
2993 ReachabilitySet rules,
2994 Hashtable<TokenTuple, ReachabilitySet> tokens2states,
2995 Hashtable<Integer, ReachabilitySet> paramIndex2rewrite_d_p,
2996 Hashtable<Integer, ReachabilitySet> paramIndex2rewrite_d_s,
2997 Hashtable<Integer, ReachabilitySet> paramIndex2rewriteD,
2998 OwnershipGraph ogCallee,
2999 boolean makeChangeSet,
3000 Hashtable<ReferenceEdge, ChangeTupleSet> edgePlannedChanges) {
3002 assert(hrn == null && edge != null) ||
3003 (hrn != null && edge == null);
3005 assert rules != null;
3006 assert tokens2states != null;
3008 ReachabilitySet callerReachabilityNew = new ReachabilitySet().makeCanonical();
3010 // for initializing structures in this method
3011 TokenTupleSet ttsEmpty = new TokenTupleSet().makeCanonical();
3013 // use this to construct a change set if required; the idea is to
3014 // map every partially rewritten token tuple set to the set of
3015 // caller-context token tuple sets that were used to generate it
3016 Hashtable<TokenTupleSet, HashSet<TokenTupleSet> > rewritten2source =
3017 new Hashtable<TokenTupleSet, HashSet<TokenTupleSet> >();
3018 rewritten2source.put( ttsEmpty, new HashSet<TokenTupleSet>() );
3021 Iterator<TokenTupleSet> rulesItr = rules.iterator();
3022 while(rulesItr.hasNext()) {
3023 TokenTupleSet rule = rulesItr.next();
3025 ReachabilitySet rewrittenRule = new ReachabilitySet(ttsEmpty).makeCanonical();
3027 Iterator<TokenTuple> ruleItr = rule.iterator();
3028 while(ruleItr.hasNext()) {
3029 TokenTuple ttCallee = ruleItr.next();
3031 // compute the possibilities for rewriting this callee token
3032 ReachabilitySet ttCalleeRewrites = null;
3033 boolean callerSourceUsed = false;
3035 if( tokens2states.containsKey( ttCallee ) ) {
3036 callerSourceUsed = true;
3037 ttCalleeRewrites = tokens2states.get( ttCallee );
3038 assert ttCalleeRewrites != null;
3040 } else if( ogCallee.paramTokenPrimary2paramIndex.containsKey( ttCallee ) ) {
3042 Integer paramIndex_j = ogCallee.paramTokenPrimary2paramIndex.get( ttCallee );
3043 assert paramIndex_j != null;
3044 ttCalleeRewrites = paramIndex2rewrite_d_p.get( paramIndex_j );
3045 assert ttCalleeRewrites != null;
3047 } else if( ogCallee.paramTokenSecondary2paramIndex.containsKey( ttCallee ) ) {
3049 Integer paramIndex_j = ogCallee.paramTokenSecondary2paramIndex.get( ttCallee );
3050 assert paramIndex_j != null;
3051 ttCalleeRewrites = paramIndex2rewrite_d_s.get( paramIndex_j );
3052 assert ttCalleeRewrites != null;
3054 } else if( ogCallee.paramTokenSecondaryPlus2paramIndex.containsKey( ttCallee ) ) {
3056 Integer paramIndex_j = ogCallee.paramTokenSecondaryPlus2paramIndex.get( ttCallee );
3057 assert paramIndex_j != null;
3058 ttCalleeRewrites = paramIndex2rewriteD.get( paramIndex_j );
3059 assert ttCalleeRewrites != null;
3061 } else if( ogCallee.paramTokenSecondaryStar2paramIndex.containsKey( ttCallee ) ) {
3063 Integer paramIndex_j = ogCallee.paramTokenSecondaryStar2paramIndex.get( ttCallee );
3064 assert paramIndex_j != null;
3065 ttCalleeRewrites = paramIndex2rewriteD.get( paramIndex_j );
3066 assert ttCalleeRewrites != null;
3069 // otherwise there's no need for a rewrite, just pass this one on
3070 TokenTupleSet ttsCaller = new TokenTupleSet( ttCallee ).makeCanonical();
3071 ttCalleeRewrites = new ReachabilitySet( ttsCaller ).makeCanonical();
3074 // branch every version of the working rewritten rule with
3075 // the possibilities for rewriting the current callee token
3076 ReachabilitySet rewrittenRuleWithTTCallee = new ReachabilitySet().makeCanonical();
3078 Iterator<TokenTupleSet> rewrittenRuleItr = rewrittenRule.iterator();
3079 while( rewrittenRuleItr.hasNext() ) {
3080 TokenTupleSet ttsRewritten = rewrittenRuleItr.next();
3082 Iterator<TokenTupleSet> ttCalleeRewritesItr = ttCalleeRewrites.iterator();
3083 while( ttCalleeRewritesItr.hasNext() ) {
3084 TokenTupleSet ttsBranch = ttCalleeRewritesItr.next();
3086 TokenTupleSet ttsRewrittenNext = ttsRewritten.unionUpArity( ttsBranch );
3088 if( makeChangeSet ) {
3089 // in order to keep the list of source token tuple sets
3090 // start with the sets used to make the partially rewritten
3091 // rule up to this point
3092 HashSet<TokenTupleSet> sourceSets = rewritten2source.get( ttsRewritten );
3093 assert sourceSets != null;
3095 // make a shallow copy for possible modification
3096 sourceSets = (HashSet<TokenTupleSet>) sourceSets.clone();
3098 // if we used something from the caller to rewrite it, remember
3099 if( callerSourceUsed ) {
3100 sourceSets.add( ttsBranch );
3103 // set mapping for the further rewritten rule
3104 rewritten2source.put( ttsRewrittenNext, sourceSets );
3107 rewrittenRuleWithTTCallee =
3108 rewrittenRuleWithTTCallee.union( ttsRewrittenNext );
3112 // now the rewritten rule's possibilities have been extended by
3113 // rewriting the current callee token, remember result
3114 rewrittenRule = rewrittenRuleWithTTCallee;
3117 // the rule has been entirely rewritten into the caller context
3118 // now, so add it to the new reachability information
3119 callerReachabilityNew =
3120 callerReachabilityNew.union( rewrittenRule );
3123 if( makeChangeSet ) {
3124 ChangeTupleSet callerChangeSet = new ChangeTupleSet().makeCanonical();
3126 // each possibility for the final reachability should have a set of
3127 // caller sources mapped to it, use to create the change set
3128 Iterator<TokenTupleSet> callerReachabilityItr = callerReachabilityNew.iterator();
3129 while( callerReachabilityItr.hasNext() ) {
3130 TokenTupleSet ttsRewrittenFinal = callerReachabilityItr.next();
3131 HashSet<TokenTupleSet> sourceSets = rewritten2source.get( ttsRewrittenFinal );
3132 assert sourceSets != null;
3134 Iterator<TokenTupleSet> sourceSetsItr = sourceSets.iterator();
3135 while( sourceSetsItr.hasNext() ) {
3136 TokenTupleSet ttsSource = sourceSetsItr.next();
3139 callerChangeSet.union( new ChangeTuple( ttsSource, ttsRewrittenFinal ) );
3143 assert edgePlannedChanges != null;
3144 edgePlannedChanges.put( edge, callerChangeSet );
3148 edge.setBetaNew( edge.getBetaNew().union( callerReachabilityNew ) );
3150 hrn.setAlphaNew( hrn.getAlphaNew().union( callerReachabilityNew ) );
3156 private HashSet<HeapRegionNode>
3157 getHRNSetThatPossiblyMapToCalleeHRN( OwnershipGraph ogCallee,
3158 HeapRegionNode hrnCallee,
3159 Hashtable<Integer, Set<HeapRegionNode> > pi2dr,
3160 Hashtable<Integer, Set<HeapRegionNode> > pi2r
3163 HashSet<HeapRegionNode> possibleCallerHRNs = new HashSet<HeapRegionNode>();
3165 Set<Integer> paramIndicesCallee_p = ogCallee.idPrimary2paramIndexSet .get( hrnCallee.getID() );
3166 Set<Integer> paramIndicesCallee_s = ogCallee.idSecondary2paramIndexSet.get( hrnCallee.getID() );
3168 if( paramIndicesCallee_p == null &&
3169 paramIndicesCallee_s == null ) {
3170 // this is a node allocated in the callee and it has
3171 // exactly one shadow node in the caller to map to
3172 AllocationSite as = hrnCallee.getAllocationSite();
3175 int age = as.getAgeCategory( hrnCallee.getID() );
3176 assert age != AllocationSite.AGE_notInThisSite;
3179 if( age == AllocationSite.AGE_summary ) {
3180 idCaller = as.getSummaryShadow();
3182 } else if( age == AllocationSite.AGE_oldest ) {
3183 idCaller = as.getOldestShadow();
3186 assert age == AllocationSite.AGE_in_I;
3188 Integer I = as.getAge( hrnCallee.getID() );
3191 idCaller = as.getIthOldestShadow( I );
3194 assert id2hrn.containsKey( idCaller );
3195 possibleCallerHRNs.add( id2hrn.get( idCaller ) );
3197 return possibleCallerHRNs;
3200 // find out what primary objects this might be
3201 if( paramIndicesCallee_p != null ) {
3202 // this is a node that was created to represent a parameter
3203 // so it maps to some regions directly reachable from the arg labels
3204 Iterator<Integer> itrIndex = paramIndicesCallee_p.iterator();
3205 while( itrIndex.hasNext() ) {
3206 Integer paramIndexCallee = itrIndex.next();
3207 assert pi2dr.containsKey( paramIndexCallee );
3208 possibleCallerHRNs.addAll( pi2dr.get( paramIndexCallee ) );
3212 // find out what secondary objects this might be
3213 if( paramIndicesCallee_s != null ) {
3214 // this is a node that was created to represent objs reachable from
3215 // some parameter, so it maps to regions reachable from the arg labels
3216 Iterator<Integer> itrIndex = paramIndicesCallee_s.iterator();
3217 while( itrIndex.hasNext() ) {
3218 Integer paramIndexCallee = itrIndex.next();
3219 assert pi2r.containsKey( paramIndexCallee );
3220 possibleCallerHRNs.addAll( pi2r.get( paramIndexCallee ) );
3224 // TODO: is this true?
3225 // one of the two cases above should have put something in here
3226 //assert !possibleCallerHRNs.isEmpty();
3228 return possibleCallerHRNs;
3233 ////////////////////////////////////////////////////
3235 // This global sweep is an optional step to prune
3236 // reachability sets that are not internally
3237 // consistent with the global graph. It should be
3238 // invoked after strong updates or method calls.
3240 ////////////////////////////////////////////////////
3243 static boolean printDebug = false;
3246 public void globalSweep() {
3251 System.out.println( " In global sweep" );
3256 // boldB is part of the phase 1 sweep
3257 Hashtable< Integer, Hashtable<ReferenceEdge, ReachabilitySet> > boldB =
3258 new Hashtable< Integer, Hashtable<ReferenceEdge, ReachabilitySet> >();
3260 // visit every heap region to initialize alphaNew and calculate boldB
3261 Set hrns = id2hrn.entrySet();
3262 Iterator itrHrns = hrns.iterator();
3263 while( itrHrns.hasNext() ) {
3264 Map.Entry me = (Map.Entry)itrHrns.next();
3265 Integer token = (Integer) me.getKey();
3266 HeapRegionNode hrn = (HeapRegionNode) me.getValue();
3268 // assert that this node and incoming edges have clean alphaNew
3269 // and betaNew sets, respectively
3270 assert rsEmpty.equals( hrn.getAlphaNew() );
3272 Iterator<ReferenceEdge> itrRers = hrn.iteratorToReferencers();
3273 while( itrRers.hasNext() ) {
3274 ReferenceEdge edge = itrRers.next();
3275 assert rsEmpty.equals( edge.getBetaNew() );
3278 // calculate boldB for this flagged node
3279 if( hrn.isFlagged() || hrn.isParameter() ) {
3281 Hashtable<ReferenceEdge, ReachabilitySet> boldB_f =
3282 new Hashtable<ReferenceEdge, ReachabilitySet>();
3284 Set<ReferenceEdge> workSetEdges = new HashSet<ReferenceEdge>();
3286 // initial boldB_f constraints
3287 Iterator<ReferenceEdge> itrRees = hrn.iteratorToReferencees();
3288 while( itrRees.hasNext() ) {
3289 ReferenceEdge edge = itrRees.next();
3291 assert !boldB.containsKey( edge );
3292 boldB_f.put( edge, edge.getBeta() );
3294 assert !workSetEdges.contains( edge );
3295 workSetEdges.add( edge );
3298 // enforce the boldB_f constraint at edges until we reach a fixed point
3299 while( !workSetEdges.isEmpty() ) {
3300 ReferenceEdge edge = workSetEdges.iterator().next();
3301 workSetEdges.remove( edge );
3303 Iterator<ReferenceEdge> itrPrime = edge.getDst().iteratorToReferencees();
3304 while( itrPrime.hasNext() ) {
3305 ReferenceEdge edgePrime = itrPrime.next();
3307 ReachabilitySet prevResult = boldB_f.get( edgePrime );
3308 ReachabilitySet intersection = boldB_f.get( edge ).intersection( edgePrime.getBeta() );
3310 if( prevResult == null ||
3311 prevResult.union( intersection ).size() > prevResult.size() ) {
3313 if( prevResult == null ) {
3314 boldB_f.put( edgePrime, edgePrime.getBeta().union( intersection ) );
3316 boldB_f.put( edgePrime, prevResult .union( intersection ) );
3318 workSetEdges.add( edgePrime );
3323 boldB.put( token, boldB_f );
3328 // use boldB to prune tokens from alpha states that are impossible
3329 // and propagate the differences backwards across edges
3330 HashSet<ReferenceEdge> edgesForPropagation = new HashSet<ReferenceEdge>();
3332 Hashtable<ReferenceEdge, ChangeTupleSet> edgePlannedChanges =
3333 new Hashtable<ReferenceEdge, ChangeTupleSet>();
3335 hrns = id2hrn.entrySet();
3336 itrHrns = hrns.iterator();
3337 while( itrHrns.hasNext() ) {
3338 Map.Entry me = (Map.Entry)itrHrns.next();
3339 Integer token = (Integer) me.getKey();
3340 HeapRegionNode hrn = (HeapRegionNode) me.getValue();
3342 // never remove the identity token from a flagged region
3343 // because it is trivially satisfied
3344 TokenTuple ttException = new TokenTuple( token,
3345 !hrn.isSingleObject(),
3346 TokenTuple.ARITY_ONE ).makeCanonical();
3348 ChangeTupleSet cts = new ChangeTupleSet().makeCanonical();
3350 // mark tokens for removal
3351 Iterator<TokenTupleSet> stateItr = hrn.getAlpha().iterator();
3352 while( stateItr.hasNext() ) {
3353 TokenTupleSet ttsOld = stateItr.next();
3355 TokenTupleSet markedTokens = new TokenTupleSet().makeCanonical();
3357 Iterator<TokenTuple> ttItr = ttsOld.iterator();
3358 while( ttItr.hasNext() ) {
3359 TokenTuple ttOld = ttItr.next();
3361 // never remove the identity token from a flagged region
3362 // because it is trivially satisfied
3363 if( hrn.isFlagged() || hrn.isParameter() ) {
3364 if( ttOld == ttException ) {
3369 // does boldB_ttOld allow this token?
3370 boolean foundState = false;
3371 Iterator<ReferenceEdge> incidentEdgeItr = hrn.iteratorToReferencers();
3372 while( incidentEdgeItr.hasNext() ) {
3373 ReferenceEdge incidentEdge = incidentEdgeItr.next();
3375 // if it isn't allowed, mark for removal
3376 Integer idOld = ttOld.getToken();
3377 assert id2hrn.containsKey( idOld );
3378 Hashtable<ReferenceEdge, ReachabilitySet> B = boldB.get( idOld );
3379 ReachabilitySet boldB_ttOld_incident = B.get( incidentEdge );// B is NULL!
3380 if( boldB_ttOld_incident != null &&
3381 boldB_ttOld_incident.contains( ttsOld ) ) {
3387 markedTokens = markedTokens.add( ttOld );
3391 // if there is nothing marked, just move on
3392 if( markedTokens.isEmpty() ) {
3393 hrn.setAlphaNew( hrn.getAlphaNew().union( ttsOld ) );
3397 // remove all marked tokens and establish a change set that should
3398 // propagate backwards over edges from this node
3399 TokenTupleSet ttsPruned = new TokenTupleSet().makeCanonical();
3400 ttItr = ttsOld.iterator();
3401 while( ttItr.hasNext() ) {
3402 TokenTuple ttOld = ttItr.next();
3404 if( !markedTokens.containsTuple( ttOld ) ) {
3405 ttsPruned = ttsPruned.union( ttOld );
3408 assert !ttsOld.equals( ttsPruned );
3410 hrn.setAlphaNew( hrn.getAlphaNew().union( ttsPruned ) );
3411 ChangeTuple ct = new ChangeTuple( ttsOld, ttsPruned ).makeCanonical();
3412 cts = cts.union( ct );
3415 // throw change tuple set on all incident edges
3416 if( !cts.isEmpty() ) {
3417 Iterator<ReferenceEdge> incidentEdgeItr = hrn.iteratorToReferencers();
3418 while( incidentEdgeItr.hasNext() ) {
3419 ReferenceEdge incidentEdge = incidentEdgeItr.next();
3421 edgesForPropagation.add( incidentEdge );
3423 if( edgePlannedChanges.get( incidentEdge ) == null ) {
3424 edgePlannedChanges.put( incidentEdge, cts );
3426 edgePlannedChanges.put(
3428 edgePlannedChanges.get( incidentEdge ).union( cts )
3435 HashSet<ReferenceEdge> edgesUpdated = new HashSet<ReferenceEdge>();
3437 propagateTokensOverEdges( edgesForPropagation,
3441 // at the end of the 1st phase reference edges have
3442 // beta, betaNew that correspond to beta and betaR
3444 // commit beta<-betaNew, so beta=betaR and betaNew
3445 // will represent the beta' calculation in 2nd phase
3447 // commit alpha<-alphaNew because it won't change
3448 HashSet<ReferenceEdge> res = new HashSet<ReferenceEdge>();
3450 Iterator<HeapRegionNode> nodeItr = id2hrn.values().iterator();
3451 while( nodeItr.hasNext() ) {
3452 HeapRegionNode hrn = nodeItr.next();
3453 hrn.applyAlphaNew();
3454 Iterator<ReferenceEdge> itrRes = hrn.iteratorToReferencers();
3455 while( itrRes.hasNext() ) {
3456 res.add( itrRes.next() );
3462 Iterator<ReferenceEdge> edgeItr = res.iterator();
3463 while( edgeItr.hasNext() ) {
3464 ReferenceEdge edge = edgeItr.next();
3465 HeapRegionNode hrn = edge.getDst();
3467 // commit results of last phase
3468 if( edgesUpdated.contains( edge ) ) {
3469 edge.applyBetaNew();
3472 // compute intial condition of 2nd phase
3473 edge.setBetaNew( edge.getBeta().intersection( hrn.getAlpha() ) );
3476 // every edge in the graph is the initial workset
3477 Set<ReferenceEdge> edgeWorkSet = (Set) res.clone();
3478 while( !edgeWorkSet.isEmpty() ) {
3479 ReferenceEdge edgePrime = edgeWorkSet.iterator().next();
3480 edgeWorkSet.remove( edgePrime );
3482 OwnershipNode on = edgePrime.getSrc();
3483 if( !(on instanceof HeapRegionNode) ) {
3486 HeapRegionNode hrn = (HeapRegionNode) on;
3488 Iterator<ReferenceEdge> itrEdge = hrn.iteratorToReferencers();
3489 while( itrEdge.hasNext() ) {
3490 ReferenceEdge edge = itrEdge.next();
3492 ReachabilitySet prevResult = edge.getBetaNew();
3493 assert prevResult != null;
3495 ReachabilitySet intersection = edge.getBeta().intersection( edgePrime.getBetaNew() );
3497 if( prevResult.union( intersection ).size() > prevResult.size() ) {
3498 edge.setBetaNew( prevResult.union( intersection ) );
3499 edgeWorkSet.add( edge );
3504 // commit beta' (beta<-betaNew)
3505 edgeItr = res.iterator();
3506 while( edgeItr.hasNext() ) {
3507 edgeItr.next().applyBetaNew();
3512 System.out.println( " End global sweep" );
3519 ////////////////////////////////////////////////////
3520 // in merge() and equals() methods the suffix A
3521 // represents the passed in graph and the suffix
3522 // B refers to the graph in this object
3523 // Merging means to take the incoming graph A and
3524 // merge it into B, so after the operation graph B
3525 // is the final result.
3526 ////////////////////////////////////////////////////
3527 public void merge(OwnershipGraph og) {
3533 mergeOwnershipNodes(og);
3534 mergeReferenceEdges(og);
3535 mergeParamIndexMappings(og);
3536 mergeAllocationSites(og);
3540 protected void mergeOwnershipNodes(OwnershipGraph og) {
3541 Set sA = og.id2hrn.entrySet();
3542 Iterator iA = sA.iterator();
3543 while( iA.hasNext() ) {
3544 Map.Entry meA = (Map.Entry)iA.next();
3545 Integer idA = (Integer) meA.getKey();
3546 HeapRegionNode hrnA = (HeapRegionNode) meA.getValue();
3548 // if this graph doesn't have a node the
3549 // incoming graph has, allocate it
3550 if( !id2hrn.containsKey(idA) ) {
3551 HeapRegionNode hrnB = hrnA.copy();
3552 id2hrn.put(idA, hrnB);
3555 // otherwise this is a node present in both graphs
3556 // so make the new reachability set a union of the
3557 // nodes' reachability sets
3558 HeapRegionNode hrnB = id2hrn.get(idA);
3559 hrnB.setAlpha(hrnB.getAlpha().union(hrnA.getAlpha() ) );
3563 // now add any label nodes that are in graph B but
3565 sA = og.td2ln.entrySet();
3567 while( iA.hasNext() ) {
3568 Map.Entry meA = (Map.Entry)iA.next();
3569 TempDescriptor tdA = (TempDescriptor) meA.getKey();
3570 LabelNode lnA = (LabelNode) meA.getValue();
3572 // if the label doesn't exist in B, allocate and add it
3573 LabelNode lnB = getLabelNodeFromTemp(tdA);
3577 protected void mergeReferenceEdges(OwnershipGraph og) {
3580 Set sA = og.id2hrn.entrySet();
3581 Iterator iA = sA.iterator();
3582 while( iA.hasNext() ) {
3583 Map.Entry meA = (Map.Entry)iA.next();
3584 Integer idA = (Integer) meA.getKey();
3585 HeapRegionNode hrnA = (HeapRegionNode) meA.getValue();
3587 Iterator<ReferenceEdge> heapRegionsItrA = hrnA.iteratorToReferencees();
3588 while( heapRegionsItrA.hasNext() ) {
3589 ReferenceEdge edgeA = heapRegionsItrA.next();
3590 HeapRegionNode hrnChildA = edgeA.getDst();
3591 Integer idChildA = hrnChildA.getID();
3593 // at this point we know an edge in graph A exists
3594 // idA -> idChildA, does this exist in B?
3595 assert id2hrn.containsKey(idA);
3596 HeapRegionNode hrnB = id2hrn.get(idA);
3597 ReferenceEdge edgeToMerge = null;
3599 Iterator<ReferenceEdge> heapRegionsItrB = hrnB.iteratorToReferencees();
3600 while( heapRegionsItrB.hasNext() &&
3601 edgeToMerge == null ) {
3603 ReferenceEdge edgeB = heapRegionsItrB.next();
3604 HeapRegionNode hrnChildB = edgeB.getDst();
3605 Integer idChildB = hrnChildB.getID();
3607 // don't use the ReferenceEdge.equals() here because
3608 // we're talking about existence between graphs
3609 if( idChildB.equals( idChildA ) &&
3610 edgeB.typeAndFieldEquals( edgeA ) ) {
3612 edgeToMerge = edgeB;
3616 // if the edge from A was not found in B,
3618 if( edgeToMerge == null ) {
3619 assert id2hrn.containsKey(idChildA);
3620 HeapRegionNode hrnChildB = id2hrn.get(idChildA);
3621 edgeToMerge = edgeA.copy();
3622 edgeToMerge.setSrc(hrnB);
3623 edgeToMerge.setDst(hrnChildB);
3624 addReferenceEdge(hrnB, hrnChildB, edgeToMerge);
3626 // otherwise, the edge already existed in both graphs
3627 // so merge their reachability sets
3629 // just replace this beta set with the union
3630 assert edgeToMerge != null;
3631 edgeToMerge.setBeta(
3632 edgeToMerge.getBeta().union(edgeA.getBeta() )
3634 if( !edgeA.isInitialParam() ) {
3635 edgeToMerge.setIsInitialParam(false);
3641 // and then again with label nodes
3642 sA = og.td2ln.entrySet();
3644 while( iA.hasNext() ) {
3645 Map.Entry meA = (Map.Entry)iA.next();
3646 TempDescriptor tdA = (TempDescriptor) meA.getKey();
3647 LabelNode lnA = (LabelNode) meA.getValue();
3649 Iterator<ReferenceEdge> heapRegionsItrA = lnA.iteratorToReferencees();
3650 while( heapRegionsItrA.hasNext() ) {
3651 ReferenceEdge edgeA = heapRegionsItrA.next();
3652 HeapRegionNode hrnChildA = edgeA.getDst();
3653 Integer idChildA = hrnChildA.getID();
3655 // at this point we know an edge in graph A exists
3656 // tdA -> idChildA, does this exist in B?
3657 assert td2ln.containsKey(tdA);
3658 LabelNode lnB = td2ln.get(tdA);
3659 ReferenceEdge edgeToMerge = null;
3661 Iterator<ReferenceEdge> heapRegionsItrB = lnB.iteratorToReferencees();
3662 while( heapRegionsItrB.hasNext() &&
3663 edgeToMerge == null ) {
3665 ReferenceEdge edgeB = heapRegionsItrB.next();
3666 HeapRegionNode hrnChildB = edgeB.getDst();
3667 Integer idChildB = hrnChildB.getID();
3669 // don't use the ReferenceEdge.equals() here because
3670 // we're talking about existence between graphs
3671 if( idChildB.equals( idChildA ) &&
3672 edgeB.typeAndFieldEquals( edgeA ) ) {
3674 edgeToMerge = edgeB;
3678 // if the edge from A was not found in B,
3680 if( edgeToMerge == null ) {
3681 assert id2hrn.containsKey(idChildA);
3682 HeapRegionNode hrnChildB = id2hrn.get(idChildA);
3683 edgeToMerge = edgeA.copy();
3684 edgeToMerge.setSrc(lnB);
3685 edgeToMerge.setDst(hrnChildB);
3686 addReferenceEdge(lnB, hrnChildB, edgeToMerge);
3688 // otherwise, the edge already existed in both graphs
3689 // so merge their reachability sets
3691 // just replace this beta set with the union
3692 edgeToMerge.setBeta(
3693 edgeToMerge.getBeta().union(edgeA.getBeta() )
3695 if( !edgeA.isInitialParam() ) {
3696 edgeToMerge.setIsInitialParam(false);
3703 // you should only merge ownership graphs that have the
3704 // same number of parameters, or if one or both parameter
3705 // index tables are empty
3706 protected void mergeParamIndexMappings(OwnershipGraph og) {
3708 if( idPrimary2paramIndexSet.size() == 0 ) {
3710 idPrimary2paramIndexSet = og.idPrimary2paramIndexSet;
3711 paramIndex2idPrimary = og.paramIndex2idPrimary;
3713 idSecondary2paramIndexSet = og.idSecondary2paramIndexSet;
3714 paramIndex2idSecondary = og.paramIndex2idSecondary;
3716 paramIndex2tdQ = og.paramIndex2tdQ;
3717 paramIndex2tdR = og.paramIndex2tdR;
3719 paramTokenPrimary2paramIndex = og.paramTokenPrimary2paramIndex;
3720 paramIndex2paramTokenPrimary = og.paramIndex2paramTokenPrimary;
3722 paramTokenSecondary2paramIndex = og.paramTokenSecondary2paramIndex;
3723 paramIndex2paramTokenSecondary = og.paramIndex2paramTokenSecondary;
3724 paramTokenSecondaryPlus2paramIndex = og.paramTokenSecondaryPlus2paramIndex;
3725 paramIndex2paramTokenSecondaryPlus = og.paramIndex2paramTokenSecondaryPlus;
3726 paramTokenSecondaryStar2paramIndex = og.paramTokenSecondaryStar2paramIndex;
3727 paramIndex2paramTokenSecondaryStar = og.paramIndex2paramTokenSecondaryStar;
3732 if( og.idPrimary2paramIndexSet.size() == 0 ) {
3734 og.idPrimary2paramIndexSet = idPrimary2paramIndexSet;
3735 og.paramIndex2idPrimary = paramIndex2idPrimary;
3737 og.idSecondary2paramIndexSet = idSecondary2paramIndexSet;
3738 og.paramIndex2idSecondary = paramIndex2idSecondary;
3740 og.paramIndex2tdQ = paramIndex2tdQ;
3741 og.paramIndex2tdR = paramIndex2tdR;
3743 og.paramTokenPrimary2paramIndex = paramTokenPrimary2paramIndex;
3744 og.paramIndex2paramTokenPrimary = paramIndex2paramTokenPrimary;
3746 og.paramTokenSecondary2paramIndex = paramTokenSecondary2paramIndex;
3747 og.paramIndex2paramTokenSecondary = paramIndex2paramTokenSecondary;
3748 og.paramTokenSecondaryPlus2paramIndex = paramTokenSecondaryPlus2paramIndex;
3749 og.paramIndex2paramTokenSecondaryPlus = paramIndex2paramTokenSecondaryPlus;
3750 og.paramTokenSecondaryStar2paramIndex = paramTokenSecondaryStar2paramIndex;
3751 og.paramIndex2paramTokenSecondaryStar = paramIndex2paramTokenSecondaryStar;
3756 assert idPrimary2paramIndexSet.size() == og.idPrimary2paramIndexSet.size();
3757 assert idSecondary2paramIndexSet.size() == og.idSecondary2paramIndexSet.size();
3760 protected void mergeAllocationSites(OwnershipGraph og) {
3761 allocationSites.addAll(og.allocationSites);
3766 // it is necessary in the equals() member functions
3767 // to "check both ways" when comparing the data
3768 // structures of two graphs. For instance, if all
3769 // edges between heap region nodes in graph A are
3770 // present and equal in graph B it is not sufficient
3771 // to say the graphs are equal. Consider that there
3772 // may be edges in graph B that are not in graph A.
3773 // the only way to know that all edges in both graphs
3774 // are equally present is to iterate over both data
3775 // structures and compare against the other graph.
3776 public boolean equals(OwnershipGraph og) {
3782 if( !areHeapRegionNodesEqual(og) ) {
3786 if( !areLabelNodesEqual(og) ) {
3790 if( !areReferenceEdgesEqual(og) ) {
3794 if( !areParamIndexMappingsEqual(og) ) {
3798 // if everything is equal up to this point,
3799 // assert that allocationSites is also equal--
3800 // this data is redundant and kept for efficiency
3801 assert allocationSites.equals(og.allocationSites);
3806 protected boolean areHeapRegionNodesEqual(OwnershipGraph og) {
3808 if( !areallHRNinAalsoinBandequal(this, og) ) {
3812 if( !areallHRNinAalsoinBandequal(og, this) ) {
3819 static protected boolean areallHRNinAalsoinBandequal(OwnershipGraph ogA,
3820 OwnershipGraph ogB) {
3821 Set sA = ogA.id2hrn.entrySet();
3822 Iterator iA = sA.iterator();
3823 while( iA.hasNext() ) {
3824 Map.Entry meA = (Map.Entry)iA.next();
3825 Integer idA = (Integer) meA.getKey();
3826 HeapRegionNode hrnA = (HeapRegionNode) meA.getValue();
3828 if( !ogB.id2hrn.containsKey(idA) ) {
3832 HeapRegionNode hrnB = ogB.id2hrn.get(idA);
3833 if( !hrnA.equalsIncludingAlpha(hrnB) ) {
3842 protected boolean areLabelNodesEqual(OwnershipGraph og) {
3844 if( !areallLNinAalsoinBandequal(this, og) ) {
3848 if( !areallLNinAalsoinBandequal(og, this) ) {
3855 static protected boolean areallLNinAalsoinBandequal(OwnershipGraph ogA,
3856 OwnershipGraph ogB) {
3857 Set sA = ogA.td2ln.entrySet();
3858 Iterator iA = sA.iterator();
3859 while( iA.hasNext() ) {
3860 Map.Entry meA = (Map.Entry)iA.next();
3861 TempDescriptor tdA = (TempDescriptor) meA.getKey();
3863 if( !ogB.td2ln.containsKey(tdA) ) {
3872 protected boolean areReferenceEdgesEqual(OwnershipGraph og) {
3873 if( !areallREinAandBequal(this, og) ) {
3880 static protected boolean areallREinAandBequal(OwnershipGraph ogA,
3881 OwnershipGraph ogB) {
3883 // check all the heap region->heap region edges
3884 Set sA = ogA.id2hrn.entrySet();
3885 Iterator iA = sA.iterator();
3886 while( iA.hasNext() ) {
3887 Map.Entry meA = (Map.Entry)iA.next();
3888 Integer idA = (Integer) meA.getKey();
3889 HeapRegionNode hrnA = (HeapRegionNode) meA.getValue();
3891 // we should have already checked that the same
3892 // heap regions exist in both graphs
3893 assert ogB.id2hrn.containsKey(idA);
3895 if( !areallREfromAequaltoB(ogA, hrnA, ogB) ) {
3899 // then check every edge in B for presence in A, starting
3900 // from the same parent HeapRegionNode
3901 HeapRegionNode hrnB = ogB.id2hrn.get(idA);
3903 if( !areallREfromAequaltoB(ogB, hrnB, ogA) ) {
3908 // then check all the label->heap region edges
3909 sA = ogA.td2ln.entrySet();
3911 while( iA.hasNext() ) {
3912 Map.Entry meA = (Map.Entry)iA.next();
3913 TempDescriptor tdA = (TempDescriptor) meA.getKey();
3914 LabelNode lnA = (LabelNode) meA.getValue();
3916 // we should have already checked that the same
3917 // label nodes exist in both graphs
3918 assert ogB.td2ln.containsKey(tdA);
3920 if( !areallREfromAequaltoB(ogA, lnA, ogB) ) {
3924 // then check every edge in B for presence in A, starting
3925 // from the same parent LabelNode
3926 LabelNode lnB = ogB.td2ln.get(tdA);
3928 if( !areallREfromAequaltoB(ogB, lnB, ogA) ) {
3937 static protected boolean areallREfromAequaltoB(OwnershipGraph ogA,
3939 OwnershipGraph ogB) {
3941 Iterator<ReferenceEdge> itrA = onA.iteratorToReferencees();
3942 while( itrA.hasNext() ) {
3943 ReferenceEdge edgeA = itrA.next();
3944 HeapRegionNode hrnChildA = edgeA.getDst();
3945 Integer idChildA = hrnChildA.getID();
3947 assert ogB.id2hrn.containsKey(idChildA);
3949 // at this point we know an edge in graph A exists
3950 // onA -> idChildA, does this exact edge exist in B?
3951 boolean edgeFound = false;
3953 OwnershipNode onB = null;
3954 if( onA instanceof HeapRegionNode ) {
3955 HeapRegionNode hrnA = (HeapRegionNode) onA;
3956 onB = ogB.id2hrn.get(hrnA.getID() );
3958 LabelNode lnA = (LabelNode) onA;
3959 onB = ogB.td2ln.get(lnA.getTempDescriptor() );
3962 Iterator<ReferenceEdge> itrB = onB.iteratorToReferencees();
3963 while( itrB.hasNext() ) {
3964 ReferenceEdge edgeB = itrB.next();
3965 HeapRegionNode hrnChildB = edgeB.getDst();
3966 Integer idChildB = hrnChildB.getID();
3968 if( idChildA.equals( idChildB ) &&
3969 edgeA.typeAndFieldEquals( edgeB ) ) {
3971 // there is an edge in the right place with the right field,
3972 // but do they have the same attributes?
3973 if( edgeA.getBeta().equals(edgeB.getBeta() ) ) {
3988 protected boolean areParamIndexMappingsEqual(OwnershipGraph og) {
3990 if( idPrimary2paramIndexSet.size() != og.idPrimary2paramIndexSet.size() ) {
3994 if( idSecondary2paramIndexSet.size() != og.idSecondary2paramIndexSet.size() ) {
4002 public Set<HeapRegionNode> hasPotentialAlias( HeapRegionNode hrn1, HeapRegionNode hrn2 ) {
4003 assert hrn1 != null;
4004 assert hrn2 != null;
4006 // then get the various tokens for these heap regions
4007 TokenTuple h1 = new TokenTuple(hrn1.getID(),
4008 !hrn1.isSingleObject(),
4009 TokenTuple.ARITY_ONE).makeCanonical();
4011 TokenTuple h1plus = new TokenTuple(hrn1.getID(),
4012 !hrn1.isSingleObject(),
4013 TokenTuple.ARITY_ONEORMORE).makeCanonical();
4015 TokenTuple h1star = new TokenTuple(hrn1.getID(),
4016 !hrn1.isSingleObject(),
4017 TokenTuple.ARITY_ZEROORMORE).makeCanonical();
4019 TokenTuple h2 = new TokenTuple(hrn2.getID(),
4020 !hrn2.isSingleObject(),
4021 TokenTuple.ARITY_ONE).makeCanonical();
4023 TokenTuple h2plus = new TokenTuple(hrn2.getID(),
4024 !hrn2.isSingleObject(),
4025 TokenTuple.ARITY_ONEORMORE).makeCanonical();
4027 TokenTuple h2star = new TokenTuple(hrn2.getID(),
4028 !hrn2.isSingleObject(),
4029 TokenTuple.ARITY_ZEROORMORE).makeCanonical();
4031 // then get the merged beta of all out-going edges from these heap regions
4032 ReachabilitySet beta1 = new ReachabilitySet();
4033 Iterator<ReferenceEdge> itrEdge = hrn1.iteratorToReferencees();
4034 while( itrEdge.hasNext() ) {
4035 ReferenceEdge edge = itrEdge.next();
4036 beta1 = beta1.union( edge.getBeta() );
4039 ReachabilitySet beta2 = new ReachabilitySet();
4040 itrEdge = hrn2.iteratorToReferencees();
4041 while( itrEdge.hasNext() ) {
4042 ReferenceEdge edge = itrEdge.next();
4043 beta2 = beta2.union( edge.getBeta() );
4046 boolean aliasDetected = false;
4048 // only do this one if they are different tokens
4050 beta1.containsTupleSetWithBoth(h1, h2) ) {
4051 aliasDetected = true;
4053 if( beta1.containsTupleSetWithBoth(h1plus, h2) ) {
4054 aliasDetected = true;
4056 if( beta1.containsTupleSetWithBoth(h1star, h2) ) {
4057 aliasDetected = true;
4059 if( beta1.containsTupleSetWithBoth(h1, h2plus) ) {
4060 aliasDetected = true;
4062 if( beta1.containsTupleSetWithBoth(h1plus, h2plus) ) {
4063 aliasDetected = true;
4065 if( beta1.containsTupleSetWithBoth(h1star, h2plus) ) {
4066 aliasDetected = true;
4068 if( beta1.containsTupleSetWithBoth(h1, h2star) ) {
4069 aliasDetected = true;
4071 if( beta1.containsTupleSetWithBoth(h1plus, h2star) ) {
4072 aliasDetected = true;
4074 if( beta1.containsTupleSetWithBoth(h1star, h2star) ) {
4075 aliasDetected = true;
4079 beta2.containsTupleSetWithBoth(h1, h2) ) {
4080 aliasDetected = true;
4082 if( beta2.containsTupleSetWithBoth(h1plus, h2) ) {
4083 aliasDetected = true;
4085 if( beta2.containsTupleSetWithBoth(h1star, h2) ) {
4086 aliasDetected = true;
4088 if( beta2.containsTupleSetWithBoth(h1, h2plus) ) {
4089 aliasDetected = true;
4091 if( beta2.containsTupleSetWithBoth(h1plus, h2plus) ) {
4092 aliasDetected = true;
4094 if( beta2.containsTupleSetWithBoth(h1star, h2plus) ) {
4095 aliasDetected = true;
4097 if( beta2.containsTupleSetWithBoth(h1, h2star) ) {
4098 aliasDetected = true;
4100 if( beta2.containsTupleSetWithBoth(h1plus, h2star) ) {
4101 aliasDetected = true;
4103 if( beta2.containsTupleSetWithBoth(h1star, h2star) ) {
4104 aliasDetected = true;
4107 Set<HeapRegionNode> common = new HashSet<HeapRegionNode>();
4108 if( aliasDetected ) {
4109 common = findCommonReachableNodes( hrn1, hrn2 );
4110 assert !common.isEmpty();
4117 public Set<HeapRegionNode> hasPotentialAlias(Integer paramIndex1, Integer paramIndex2) {
4119 // get parameter 1's heap regions
4120 assert paramIndex2idPrimary.containsKey(paramIndex1);
4121 Integer idParamPri1 = paramIndex2idPrimary.get(paramIndex1);
4123 assert id2hrn.containsKey(idParamPri1);
4124 HeapRegionNode hrnParamPri1 = id2hrn.get(idParamPri1);
4125 assert hrnParamPri1 != null;
4127 HeapRegionNode hrnParamSec1 = null;
4128 if( paramIndex2idSecondary.containsKey(paramIndex1) ) {
4129 Integer idParamSec1 = paramIndex2idSecondary.get(paramIndex1);
4131 assert id2hrn.containsKey(idParamSec1);
4132 hrnParamSec1 = id2hrn.get(idParamSec1);
4133 assert hrnParamSec1 != null;
4137 // get the other parameter
4138 assert paramIndex2idPrimary.containsKey(paramIndex2);
4139 Integer idParamPri2 = paramIndex2idPrimary.get(paramIndex2);
4141 assert id2hrn.containsKey(idParamPri2);
4142 HeapRegionNode hrnParamPri2 = id2hrn.get(idParamPri2);
4143 assert hrnParamPri2 != null;
4145 HeapRegionNode hrnParamSec2 = null;
4146 if( paramIndex2idSecondary.containsKey(paramIndex2) ) {
4147 Integer idParamSec2 = paramIndex2idSecondary.get(paramIndex2);
4149 assert id2hrn.containsKey(idParamSec2);
4150 hrnParamSec2 = id2hrn.get(idParamSec2);
4151 assert hrnParamSec2 != null;
4154 Set<HeapRegionNode> common = new HashSet<HeapRegionNode>();
4155 common.addAll( hasPotentialAlias( hrnParamPri1, hrnParamPri2 ) );
4157 if( hrnParamSec1 != null ) {
4158 common.addAll( hasPotentialAlias( hrnParamSec1, hrnParamPri2 ) );
4161 if( hrnParamSec2 != null ) {
4162 common.addAll( hasPotentialAlias( hrnParamSec2, hrnParamPri1 ) );
4165 if( hrnParamSec1 != null && hrnParamSec2 != null ) {
4166 common.addAll( hasPotentialAlias( hrnParamSec1, hrnParamSec2 ) );
4173 public Set<HeapRegionNode> hasPotentialAlias(Integer paramIndex, AllocationSite as) {
4175 // get parameter's heap regions
4176 assert paramIndex2idPrimary.containsKey(paramIndex);
4177 Integer idParamPri = paramIndex2idPrimary.get(paramIndex);
4179 assert id2hrn.containsKey(idParamPri);
4180 HeapRegionNode hrnParamPri = id2hrn.get(idParamPri);
4181 assert hrnParamPri != null;
4183 HeapRegionNode hrnParamSec = null;
4184 if( paramIndex2idSecondary.containsKey(paramIndex) ) {
4185 Integer idParamSec = paramIndex2idSecondary.get(paramIndex);
4187 assert id2hrn.containsKey(idParamSec);
4188 hrnParamSec = id2hrn.get(idParamSec);
4189 assert hrnParamSec != null;
4193 assert id2hrn.containsKey( as.getSummary() );
4194 HeapRegionNode hrnSummary = id2hrn.get( as.getSummary() );
4195 assert hrnSummary != null;
4197 Set<HeapRegionNode> common = hasPotentialAlias( hrnParamPri, hrnSummary );
4199 if( hrnParamSec != null ) {
4200 common.addAll( hasPotentialAlias( hrnParamSec, hrnSummary ) );
4203 // check for other nodes
4204 for( int i = 0; i < as.getAllocationDepth(); ++i ) {
4206 assert id2hrn.containsKey( as.getIthOldest( i ) );
4207 HeapRegionNode hrnIthOldest = id2hrn.get( as.getIthOldest( i ) );
4208 assert hrnIthOldest != null;
4210 common = hasPotentialAlias( hrnParamPri, hrnIthOldest );
4212 if( hrnParamSec != null ) {
4213 common.addAll( hasPotentialAlias( hrnParamSec, hrnIthOldest ) );
4221 public Set<HeapRegionNode> hasPotentialAlias(AllocationSite as1, AllocationSite as2) {
4223 // get summary node 1's alpha
4224 Integer idSum1 = as1.getSummary();
4225 assert id2hrn.containsKey(idSum1);
4226 HeapRegionNode hrnSum1 = id2hrn.get(idSum1);
4227 assert hrnSum1 != null;
4229 // get summary node 2's alpha
4230 Integer idSum2 = as2.getSummary();
4231 assert id2hrn.containsKey(idSum2);
4232 HeapRegionNode hrnSum2 = id2hrn.get(idSum2);
4233 assert hrnSum2 != null;
4235 Set<HeapRegionNode> common = hasPotentialAlias( hrnSum1, hrnSum2 );
4237 // check sum2 against alloc1 nodes
4238 for( int i = 0; i < as1.getAllocationDepth(); ++i ) {
4239 Integer idI1 = as1.getIthOldest(i);
4240 assert id2hrn.containsKey(idI1);
4241 HeapRegionNode hrnI1 = id2hrn.get(idI1);
4242 assert hrnI1 != null;
4244 common.addAll( hasPotentialAlias( hrnI1, hrnSum2 ) );
4247 // check sum1 against alloc2 nodes
4248 for( int i = 0; i < as2.getAllocationDepth(); ++i ) {
4249 Integer idI2 = as2.getIthOldest(i);
4250 assert id2hrn.containsKey(idI2);
4251 HeapRegionNode hrnI2 = id2hrn.get(idI2);
4252 assert hrnI2 != null;
4254 common.addAll( hasPotentialAlias( hrnSum1, hrnI2 ) );
4256 // while we're at it, do an inner loop for alloc2 vs alloc1 nodes
4257 for( int j = 0; j < as1.getAllocationDepth(); ++j ) {
4258 Integer idI1 = as1.getIthOldest(j);
4260 // if these are the same site, don't look for the same token, no alias.
4261 // different tokens of the same site could alias together though
4262 if( idI1.equals( idI2 ) ) {
4266 HeapRegionNode hrnI1 = id2hrn.get(idI1);
4268 common.addAll( hasPotentialAlias( hrnI1, hrnI2 ) );
4276 public Set<HeapRegionNode> findCommonReachableNodes( HeapRegionNode hrn1,
4277 HeapRegionNode hrn2 ) {
4279 Set<HeapRegionNode> reachableNodes1 = new HashSet<HeapRegionNode>();
4280 Set<HeapRegionNode> reachableNodes2 = new HashSet<HeapRegionNode>();
4282 Set<HeapRegionNode> todoNodes1 = new HashSet<HeapRegionNode>();
4283 todoNodes1.add( hrn1 );
4285 Set<HeapRegionNode> todoNodes2 = new HashSet<HeapRegionNode>();
4286 todoNodes2.add( hrn2 );
4288 // follow links until all reachable nodes have been found
4289 while( !todoNodes1.isEmpty() ) {
4290 HeapRegionNode hrn = todoNodes1.iterator().next();
4291 todoNodes1.remove( hrn );
4292 reachableNodes1.add(hrn);
4294 Iterator<ReferenceEdge> edgeItr = hrn.iteratorToReferencees();
4295 while( edgeItr.hasNext() ) {
4296 ReferenceEdge edge = edgeItr.next();
4298 if( !reachableNodes1.contains( edge.getDst() ) ) {
4299 todoNodes1.add( edge.getDst() );
4304 while( !todoNodes2.isEmpty() ) {
4305 HeapRegionNode hrn = todoNodes2.iterator().next();
4306 todoNodes2.remove( hrn );
4307 reachableNodes2.add(hrn);
4309 Iterator<ReferenceEdge> edgeItr = hrn.iteratorToReferencees();
4310 while( edgeItr.hasNext() ) {
4311 ReferenceEdge edge = edgeItr.next();
4313 if( !reachableNodes2.contains( edge.getDst() ) ) {
4314 todoNodes2.add( edge.getDst() );
4319 Set<HeapRegionNode> intersection =
4320 new HashSet<HeapRegionNode>( reachableNodes1 );
4322 intersection.retainAll( reachableNodes2 );
4324 return intersection;
4328 // for writing ownership graphs to dot files
4329 public void writeGraph(MethodContext mc,
4331 boolean writeLabels,
4332 boolean labelSelect,
4333 boolean pruneGarbage,
4334 boolean writeReferencers,
4335 boolean writeParamMappings
4336 ) throws java.io.IOException {
4348 public void writeGraph(MethodContext mc,
4349 boolean writeLabels,
4350 boolean labelSelect,
4351 boolean pruneGarbage,
4352 boolean writeReferencers,
4353 boolean writeParamMappings
4354 ) throws java.io.IOException {
4356 writeGraph(mc+"COMPLETE",
4365 public void writeGraph(MethodContext mc,
4367 boolean writeLabels,
4368 boolean labelSelect,
4369 boolean pruneGarbage,
4370 boolean writeReferencers,
4371 boolean writeParamMappings
4372 ) throws java.io.IOException {
4376 writeGraph(mc+"COMPLETE"+String.format("%05d", numUpdate),
4385 public void writeGraph(String graphName,
4386 boolean writeLabels,
4387 boolean labelSelect,
4388 boolean pruneGarbage,
4389 boolean writeReferencers,
4390 boolean writeParamMappings
4391 ) throws java.io.IOException {
4393 // remove all non-word characters from the graph name so
4394 // the filename and identifier in dot don't cause errors
4395 graphName = graphName.replaceAll("[\\W]", "");
4397 BufferedWriter bw = new BufferedWriter(new FileWriter(graphName+".dot") );
4398 bw.write("digraph "+graphName+" {\n");
4400 HashSet<HeapRegionNode> visited = new HashSet<HeapRegionNode>();
4402 // then visit every heap region node
4403 Set s = id2hrn.entrySet();
4404 Iterator i = s.iterator();
4405 while( i.hasNext() ) {
4406 Map.Entry me = (Map.Entry)i.next();
4407 HeapRegionNode hrn = (HeapRegionNode) me.getValue();
4409 if( !pruneGarbage ||
4410 (hrn.isFlagged() && hrn.getID() > 0) ||
4411 hrn.getDescription().startsWith("param")
4414 if( !visited.contains(hrn) ) {
4415 traverseHeapRegionNodes(VISIT_HRN_WRITE_FULL,
4425 bw.write(" graphTitle[label=\""+graphName+"\",shape=box];\n");
4427 if( writeParamMappings ) {
4429 Set df = paramIndex2id.entrySet();
4430 Iterator ih = df.iterator();
4431 while( ih.hasNext() ) {
4432 Map.Entry meh = (Map.Entry)ih.next();
4433 Integer pi = (Integer) meh.getKey();
4434 Integer id = (Integer) meh.getValue();
4435 bw.write(" pindex"+pi+"[label=\""+pi+" to "+id+"\",shape=box];\n");
4440 // then visit every label node, useful for debugging
4442 s = td2ln.entrySet();
4444 while( i.hasNext() ) {
4445 Map.Entry me = (Map.Entry)i.next();
4446 LabelNode ln = (LabelNode) me.getValue();
4449 String labelStr = ln.getTempDescriptorString();
4450 if( labelStr.startsWith("___temp") ||
4451 labelStr.startsWith("___dst") ||
4452 labelStr.startsWith("___srctmp") ||
4453 labelStr.startsWith("___neverused") ||
4454 labelStr.contains(qString) ||
4455 labelStr.contains(rString) ||
4456 labelStr.contains(blobString)
4462 //bw.write(" "+ln.toString() + ";\n");
4464 Iterator<ReferenceEdge> heapRegionsItr = ln.iteratorToReferencees();
4465 while( heapRegionsItr.hasNext() ) {
4466 ReferenceEdge edge = heapRegionsItr.next();
4467 HeapRegionNode hrn = edge.getDst();
4469 if( pruneGarbage && !visited.contains(hrn) ) {
4470 traverseHeapRegionNodes(VISIT_HRN_WRITE_FULL,
4478 bw.write(" " + ln.toString() +
4479 " -> " + hrn.toString() +
4480 "[label=\"" + edge.toGraphEdgeString() +
4491 protected void traverseHeapRegionNodes(int mode,
4495 HashSet<HeapRegionNode> visited,
4496 boolean writeReferencers
4497 ) throws java.io.IOException {
4499 if( visited.contains(hrn) ) {
4505 case VISIT_HRN_WRITE_FULL:
4507 String attributes = "[";
4509 if( hrn.isSingleObject() ) {
4510 attributes += "shape=box";
4512 attributes += "shape=Msquare";
4515 if( hrn.isFlagged() ) {
4516 attributes += ",style=filled,fillcolor=lightgrey";
4519 attributes += ",label=\"ID" +
4523 if( hrn.getType() != null ) {
4524 attributes += hrn.getType().toPrettyString() + "\\n";
4527 attributes += hrn.getDescription() +
4529 hrn.getAlphaString() +
4532 bw.write(" " + hrn.toString() + attributes + ";\n");
4537 // useful for debugging
4540 if( writeReferencers ) {
4541 OwnershipNode onRef = null;
4542 Iterator refItr = hrn.iteratorToReferencers();
4543 while( refItr.hasNext() ) {
4544 onRef = (OwnershipNode) refItr.next();
4547 case VISIT_HRN_WRITE_FULL:
4548 bw.write(" " + hrn.toString() +
4549 " -> " + onRef.toString() +
4550 "[color=lightgray];\n");
4557 Iterator<ReferenceEdge> childRegionsItr = hrn.iteratorToReferencees();
4558 while( childRegionsItr.hasNext() ) {
4559 ReferenceEdge edge = childRegionsItr.next();
4560 HeapRegionNode hrnChild = edge.getDst();
4563 case VISIT_HRN_WRITE_FULL:
4564 bw.write(" " + hrn.toString() +
4565 " -> " + hrnChild.toString() +
4566 "[label=\"" + edge.toGraphEdgeString() +
4571 traverseHeapRegionNodes(mode,