6684415753748b96e25413dfbadb8ba1b9f406ae
[IRC.git] / Robust / src / Analysis / OwnershipAnalysis / OwnershipGraph.java
1 package Analysis.OwnershipAnalysis;
2
3 import IR.*;
4 import IR.Flat.*;
5 import java.util.*;
6 import java.io.*;
7
8 public class OwnershipGraph {
9
10   private int allocationDepth;
11   private TypeUtil typeUtil;
12
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;
19
20   protected static TempDescriptor tdReturn = new TempDescriptor("_Return___");
21
22
23   public Hashtable<Integer,        HeapRegionNode> id2hrn;
24   public Hashtable<TempDescriptor, LabelNode     > td2ln;
25   public Hashtable<Integer,        Integer       > id2paramIndex;
26   public Hashtable<Integer,        Integer       > paramIndex2id;
27   public Hashtable<Integer,        TempDescriptor> paramIndex2tdQ;
28
29   public HashSet<AllocationSite> allocationSites;
30
31
32
33
34   public OwnershipGraph(int allocationDepth, TypeUtil typeUtil) {
35     this.allocationDepth = allocationDepth;
36     this.typeUtil        = typeUtil;
37
38     id2hrn         = new Hashtable<Integer,        HeapRegionNode>();
39     td2ln          = new Hashtable<TempDescriptor, LabelNode     >();
40     id2paramIndex  = new Hashtable<Integer,        Integer       >();
41     paramIndex2id  = new Hashtable<Integer,        Integer       >();
42     paramIndex2tdQ = new Hashtable<Integer,        TempDescriptor>();
43
44     allocationSites = new HashSet <AllocationSite>();
45   }
46
47
48   // label nodes are much easier to deal with than
49   // heap region nodes.  Whenever there is a request
50   // for the label node that is associated with a
51   // temp descriptor we can either find it or make a
52   // new one and return it.  This is because temp
53   // descriptors are globally unique and every label
54   // node is mapped to exactly one temp descriptor.
55   protected LabelNode getLabelNodeFromTemp(TempDescriptor td) {
56     assert td != null;
57
58     if( !td2ln.containsKey(td) ) {
59       td2ln.put(td, new LabelNode(td) );
60     }
61
62     return td2ln.get(td);
63   }
64
65
66   // the reason for this method is to have the option
67   // creating new heap regions with specific IDs, or
68   // duplicating heap regions with specific IDs (especially
69   // in the merge() operation) or to create new heap
70   // regions with a new unique ID.
71   protected HeapRegionNode
72   createNewHeapRegionNode(Integer id,
73                           boolean isSingleObject,
74                           boolean isFlagged,
75                           boolean isNewSummary,
76                           boolean isParameter,
77                           AllocationSite allocSite,
78                           ReachabilitySet alpha,
79                           String description) {
80
81     if( id == null ) {
82       id = OwnershipAnalysis.generateUniqueHeapRegionNodeID();
83     }
84
85     if( alpha == null ) {
86       if( isFlagged || isParameter ) {
87         alpha = new ReachabilitySet(new TokenTuple(id,
88                                                    !isSingleObject,
89                                                    TokenTuple.ARITY_ONE)
90                                     ).makeCanonical();
91       } else {
92         alpha = new ReachabilitySet(new TokenTupleSet()
93                                     ).makeCanonical();
94       }
95     }
96
97     HeapRegionNode hrn = new HeapRegionNode(id,
98                                             isSingleObject,
99                                             isFlagged,
100                                             isNewSummary,
101                                             allocSite,
102                                             alpha,
103                                             description);
104     id2hrn.put(id, hrn);
105     return hrn;
106   }
107
108
109
110   ////////////////////////////////////////////////
111   //
112   //  Low-level referencee and referencer methods
113   //
114   //  These methods provide the lowest level for
115   //  creating references between ownership nodes
116   //  and handling the details of maintaining both
117   //  list of referencers and referencees.
118   //
119   ////////////////////////////////////////////////
120   protected void addReferenceEdge(OwnershipNode referencer,
121                                   HeapRegionNode referencee,
122                                   ReferenceEdge edge) {
123     assert referencer != null;
124     assert referencee != null;
125     assert edge       != null;
126     assert edge.getSrc() == referencer;
127     assert edge.getDst() == referencee;
128
129     referencer.addReferencee(edge);
130     referencee.addReferencer(edge);
131   }
132
133   protected void removeReferenceEdge(OwnershipNode referencer,
134                                      HeapRegionNode referencee,
135                                      FieldDescriptor fieldDesc) {
136     assert referencer != null;
137     assert referencee != null;
138
139     ReferenceEdge edge = referencer.getReferenceTo(referencee,
140                                                    fieldDesc);
141     assert edge != null;
142     assert edge == referencee.getReferenceFrom(referencer,
143                                                fieldDesc);
144
145     referencer.removeReferencee(edge);
146     referencee.removeReferencer(edge);
147   }
148
149   protected void clearReferenceEdgesFrom(OwnershipNode referencer,
150                                          FieldDescriptor fieldDesc,
151                                          boolean removeAll) {
152     assert referencer != null;
153
154     // get a copy of the set to iterate over, otherwise
155     // we will be trying to take apart the set as we
156     // are iterating over it, which won't work
157     Iterator<ReferenceEdge> i = referencer.iteratorToReferenceesClone();
158     while( i.hasNext() ) {
159       ReferenceEdge edge = i.next();
160
161       if( removeAll || edge.getFieldDesc() == fieldDesc ) {
162         HeapRegionNode referencee = edge.getDst();
163
164         removeReferenceEdge(referencer,
165                             referencee,
166                             edge.getFieldDesc() );
167       }
168     }
169   }
170
171   protected void clearReferenceEdgesTo(HeapRegionNode referencee,
172                                        FieldDescriptor fieldDesc,
173                                        boolean removeAll) {
174     assert referencee != null;
175
176     // get a copy of the set to iterate over, otherwise
177     // we will be trying to take apart the set as we
178     // are iterating over it, which won't work
179     Iterator<ReferenceEdge> i = referencee.iteratorToReferencersClone();
180     while( i.hasNext() ) {
181       ReferenceEdge edge = i.next();
182
183       if( removeAll || edge.getFieldDesc() == fieldDesc ) {
184         OwnershipNode referencer = edge.getSrc();
185         removeReferenceEdge(referencer,
186                             referencee,
187                             edge.getFieldDesc() );
188       }
189     }
190   }
191
192
193   protected void propagateTokensOverNodes(HeapRegionNode nPrime,
194                                           ChangeTupleSet c0,
195                                           HashSet<HeapRegionNode> nodesWithNewAlpha,
196                                           HashSet<ReferenceEdge>  edgesWithNewBeta) {
197
198     HashSet<HeapRegionNode> todoNodes
199     = new HashSet<HeapRegionNode>();
200     todoNodes.add(nPrime);
201
202     HashSet<ReferenceEdge> todoEdges
203     = new HashSet<ReferenceEdge>();
204
205     Hashtable<HeapRegionNode, ChangeTupleSet> nodePlannedChanges
206     = new Hashtable<HeapRegionNode, ChangeTupleSet>();
207     nodePlannedChanges.put(nPrime, c0);
208
209     Hashtable<ReferenceEdge, ChangeTupleSet> edgePlannedChanges
210     = new Hashtable<ReferenceEdge, ChangeTupleSet>();
211
212
213     while( !todoNodes.isEmpty() ) {
214       HeapRegionNode n = todoNodes.iterator().next();
215       ChangeTupleSet C = nodePlannedChanges.get(n);
216
217       Iterator itrC = C.iterator();
218       while( itrC.hasNext() ) {
219         ChangeTuple c = (ChangeTuple) itrC.next();
220
221         if( n.getAlpha().contains(c.getSetToMatch() ) ) {
222           ReachabilitySet withChange = n.getAlpha().union(c.getSetToAdd() );
223           n.setAlphaNew(n.getAlphaNew().union(withChange) );
224           nodesWithNewAlpha.add(n);
225         }
226       }
227
228       Iterator<ReferenceEdge> referItr = n.iteratorToReferencers();
229       while( referItr.hasNext() ) {
230         ReferenceEdge edge = referItr.next();
231         todoEdges.add(edge);
232
233         if( !edgePlannedChanges.containsKey(edge) ) {
234           edgePlannedChanges.put(edge, new ChangeTupleSet().makeCanonical() );
235         }
236
237         edgePlannedChanges.put(edge, edgePlannedChanges.get(edge).union(C) );
238       }
239
240       Iterator<ReferenceEdge> refeeItr = n.iteratorToReferencees();
241       while( refeeItr.hasNext() ) {
242         ReferenceEdge edgeF = refeeItr.next();
243         HeapRegionNode m     = edgeF.getDst();
244
245         ChangeTupleSet changesToPass = new ChangeTupleSet().makeCanonical();
246
247         Iterator<ChangeTuple> itrCprime = C.iterator();
248         while( itrCprime.hasNext() ) {
249           ChangeTuple c = itrCprime.next();
250           if( edgeF.getBeta().contains(c.getSetToMatch() ) ) {
251             changesToPass = changesToPass.union(c);
252           }
253         }
254
255         if( !changesToPass.isEmpty() ) {
256           if( !nodePlannedChanges.containsKey(m) ) {
257             nodePlannedChanges.put(m, new ChangeTupleSet().makeCanonical() );
258           }
259
260           ChangeTupleSet currentChanges = nodePlannedChanges.get(m);
261
262           if( !changesToPass.isSubset(currentChanges) ) {
263
264             nodePlannedChanges.put(m, currentChanges.union(changesToPass) );
265             todoNodes.add(m);
266           }
267         }
268       }
269
270       todoNodes.remove(n);
271     }
272
273     propagateTokensOverEdges(todoEdges, edgePlannedChanges, edgesWithNewBeta);
274   }
275
276
277   protected void propagateTokensOverEdges(
278     HashSet<ReferenceEdge>                   todoEdges,
279     Hashtable<ReferenceEdge, ChangeTupleSet> edgePlannedChanges,
280     HashSet<ReferenceEdge>                   edgesWithNewBeta) {
281
282
283     while( !todoEdges.isEmpty() ) {
284       ReferenceEdge edgeE = todoEdges.iterator().next();
285       todoEdges.remove(edgeE);
286
287       if( !edgePlannedChanges.containsKey(edgeE) ) {
288         edgePlannedChanges.put(edgeE, new ChangeTupleSet().makeCanonical() );
289       }
290
291       ChangeTupleSet C = edgePlannedChanges.get(edgeE);
292
293       ChangeTupleSet changesToPass = new ChangeTupleSet().makeCanonical();
294
295       Iterator<ChangeTuple> itrC = C.iterator();
296       while( itrC.hasNext() ) {
297         ChangeTuple c = itrC.next();
298         if( edgeE.getBeta().contains(c.getSetToMatch() ) ) {
299           ReachabilitySet withChange = edgeE.getBeta().union(c.getSetToAdd() );
300           edgeE.setBetaNew(edgeE.getBetaNew().union(withChange) );
301           edgesWithNewBeta.add(edgeE);
302           changesToPass = changesToPass.union(c);
303         }
304       }
305
306       OwnershipNode onSrc = edgeE.getSrc();
307
308       if( !changesToPass.isEmpty() && onSrc instanceof HeapRegionNode ) {
309         HeapRegionNode n = (HeapRegionNode) onSrc;
310
311         Iterator<ReferenceEdge> referItr = n.iteratorToReferencers();
312         while( referItr.hasNext() ) {
313           ReferenceEdge edgeF = referItr.next();
314
315           if( !edgePlannedChanges.containsKey(edgeF) ) {
316             edgePlannedChanges.put(edgeF, new ChangeTupleSet().makeCanonical() );
317           }
318
319           ChangeTupleSet currentChanges = edgePlannedChanges.get(edgeF);
320
321           if( !changesToPass.isSubset(currentChanges) ) {
322             todoEdges.add(edgeF);
323             edgePlannedChanges.put(edgeF, currentChanges.union(changesToPass) );
324           }
325         }
326       }
327     }
328   }
329
330
331   ////////////////////////////////////////////////////
332   //
333   //  Assignment Operation Methods
334   //
335   //  These methods are high-level operations for
336   //  modeling program assignment statements using
337   //  the low-level reference create/remove methods
338   //  above.
339   //
340   //  The destination in an assignment statement is
341   //  going to have new references.  The method of
342   //  determining the references depends on the type
343   //  of the FlatNode assignment and the predicates
344   //  of the nodes and edges involved.
345   //
346   ////////////////////////////////////////////////////
347   public void assignTempXEqualToTempY(TempDescriptor x,
348                                       TempDescriptor y) {
349
350     LabelNode lnX = getLabelNodeFromTemp(x);
351     LabelNode lnY = getLabelNodeFromTemp(y);
352
353     clearReferenceEdgesFrom(lnX, null, true);
354
355     Iterator<ReferenceEdge> itrYhrn = lnY.iteratorToReferencees();
356     while( itrYhrn.hasNext() ) {
357       ReferenceEdge edgeY       = itrYhrn.next();
358       HeapRegionNode referencee = edgeY.getDst();
359       ReferenceEdge edgeNew    = edgeY.copy();
360       edgeNew.setSrc(lnX);
361
362       addReferenceEdge(lnX, referencee, edgeNew);
363     }
364   }
365
366
367   public void assignTempXEqualToTempYFieldF(TempDescriptor x,
368                                             TempDescriptor y,
369                                             FieldDescriptor f) {
370     LabelNode lnX = getLabelNodeFromTemp(x);
371     LabelNode lnY = getLabelNodeFromTemp(y);
372
373     clearReferenceEdgesFrom(lnX, null, true);
374
375     Iterator<ReferenceEdge> itrYhrn = lnY.iteratorToReferencees();
376     while( itrYhrn.hasNext() ) {
377       ReferenceEdge edgeY = itrYhrn.next();
378       HeapRegionNode hrnY  = edgeY.getDst();
379       ReachabilitySet betaY = edgeY.getBeta();
380
381       Iterator<ReferenceEdge> itrHrnFhrn = hrnY.iteratorToReferencees();
382       while( itrHrnFhrn.hasNext() ) {
383         ReferenceEdge edgeHrn = itrHrnFhrn.next();
384         HeapRegionNode hrnHrn  = edgeHrn.getDst();
385         ReachabilitySet betaHrn = edgeHrn.getBeta();
386
387         if( edgeHrn.getFieldDesc() == null ||
388             edgeHrn.getFieldDesc() == f ) {
389
390           ReferenceEdge edgeNew = new ReferenceEdge(lnX,
391                                                     hrnHrn,
392                                                     f,
393                                                     false,
394                                                     betaY.intersection(betaHrn) );
395
396           addReferenceEdge(lnX, hrnHrn, edgeNew);
397         }
398       }
399     }
400   }
401
402
403   public void assignTempXFieldFEqualToTempY(TempDescriptor x,
404                                             FieldDescriptor f,
405                                             TempDescriptor y) {
406     LabelNode lnX = getLabelNodeFromTemp(x);
407     LabelNode lnY = getLabelNodeFromTemp(y);
408
409     HashSet<HeapRegionNode> nodesWithNewAlpha = new HashSet<HeapRegionNode>();
410     HashSet<ReferenceEdge>  edgesWithNewBeta  = new HashSet<ReferenceEdge>();
411
412     Iterator<ReferenceEdge> itrXhrn = lnX.iteratorToReferencees();
413     while( itrXhrn.hasNext() ) {
414       ReferenceEdge edgeX = itrXhrn.next();
415       HeapRegionNode hrnX  = edgeX.getDst();
416       ReachabilitySet betaX = edgeX.getBeta();
417
418       ReachabilitySet R = hrnX.getAlpha().intersection(edgeX.getBeta() );
419
420       Iterator<ReferenceEdge> itrYhrn = lnY.iteratorToReferencees();
421       while( itrYhrn.hasNext() ) {
422         ReferenceEdge edgeY = itrYhrn.next();
423         HeapRegionNode hrnY  = edgeY.getDst();
424         ReachabilitySet O     = edgeY.getBeta();
425
426
427         // propagate tokens over nodes starting from hrnSrc, and it will
428         // take care of propagating back up edges from any touched nodes
429         ChangeTupleSet Cy = O.unionUpArityToChangeSet(R);
430         propagateTokensOverNodes(hrnY, Cy, nodesWithNewAlpha, edgesWithNewBeta);
431
432
433         // then propagate back just up the edges from hrn
434         ChangeTupleSet Cx = R.unionUpArityToChangeSet(O);
435
436
437         HashSet<ReferenceEdge> todoEdges = new HashSet<ReferenceEdge>();
438
439         Hashtable<ReferenceEdge, ChangeTupleSet> edgePlannedChanges =
440           new Hashtable<ReferenceEdge, ChangeTupleSet>();
441
442         Iterator<ReferenceEdge> referItr = hrnX.iteratorToReferencers();
443         while( referItr.hasNext() ) {
444           ReferenceEdge edgeUpstream = referItr.next();
445           todoEdges.add(edgeUpstream);
446           edgePlannedChanges.put(edgeUpstream, Cx);
447         }
448
449         propagateTokensOverEdges(todoEdges,
450                                  edgePlannedChanges,
451                                  edgesWithNewBeta);
452
453
454         if( edgeY.getBetaNew().equals( new ReachabilitySet() ) ) {
455           edgeY.setBetaNew( new ReachabilitySet( new TokenTupleSet().makeCanonical() ).makeCanonical() );
456         }
457
458         /*
459         System.out.println( "---------------------------\n" +
460                             edgeY.getBetaNew() + 
461                             "\nbeing pruned by\n" + 
462                             hrnX.getAlpha() + 
463                             "\nis\n" + 
464                             edgeY.getBetaNew().pruneBy(hrnX.getAlpha())
465                             );
466         */
467
468         // create the actual reference edge hrnX.f -> hrnY
469         ReferenceEdge edgeNew = new ReferenceEdge(hrnX,
470                                                   hrnY,
471                                                   f,
472                                                   false,
473                                                   edgeY.getBetaNew().pruneBy(hrnX.getAlpha() )
474                                                   //edgeY.getBeta().pruneBy( hrnX.getAlpha() )
475                                                   );
476         addReferenceEdge(hrnX, hrnY, edgeNew);
477
478         /*
479            if( f != null ) {
480             // we can do a strong update here if one of two cases holds
481             // SAVE FOR LATER, WITHOUT STILL CORRECT
482             if( (hrnX.getNumReferencers() == 1)                           ||
483                 ( lnX.getNumReferencees() == 1 && hrnX.isSingleObject() )
484               ) {
485                 clearReferenceEdgesFrom( hrnX, f, false );
486             }
487
488             addReferenceEdge( hrnX, hrnY, edgeNew );
489
490            } else {
491             // if the field is null, or "any" field, then
492             // look to see if an any field already exists
493             // and merge with it, otherwise just add the edge
494             ReferenceEdge edgeExisting = hrnX.getReferenceTo( hrnY, f );
495
496             if( edgeExisting != null ) {
497                 edgeExisting.setBetaNew(
498                   edgeExisting.getBetaNew().union( edgeNew.getBeta() )
499                                        );
500                 // a new edge here cannot be reflexive, so existing will
501                 // always be also not reflexive anymore
502                 edgeExisting.setIsInitialParamReflexive( false );
503
504             } else {
505                 addReferenceEdge( hrnX, hrnY, edgeNew );
506             }
507            }
508          */
509       }
510     }
511
512     Iterator<HeapRegionNode> nodeItr = nodesWithNewAlpha.iterator();
513     while( nodeItr.hasNext() ) {
514       nodeItr.next().applyAlphaNew();
515     }
516
517     Iterator<ReferenceEdge> edgeItr = edgesWithNewBeta.iterator();
518     while( edgeItr.hasNext() ) {
519       edgeItr.next().applyBetaNew();
520     }
521   }
522
523
524   public void assignTempEqualToParamAlloc(TempDescriptor td,
525                                           boolean isTask,
526                                           Integer paramIndex) {
527     assert td != null;
528
529     LabelNode lnParam = getLabelNodeFromTemp(td);
530     HeapRegionNode hrn = createNewHeapRegionNode(null,
531                                                  false,
532                                                  isTask,
533                                                  false,
534                                                  true,
535                                                  null,
536                                                  null,
537                                                  "param" + paramIndex);
538
539     // this is a non-program-accessible label that picks up beta
540     // info to be used for fixing a caller of this method
541     TempDescriptor tdParamQ = new TempDescriptor(td+"specialQ");
542     LabelNode lnParamQ = getLabelNodeFromTemp(tdParamQ);
543
544     // keep track of heap regions that were created for
545     // parameter labels, the index of the parameter they
546     // are for is important when resolving method calls
547     Integer newID = hrn.getID();
548     assert !id2paramIndex.containsKey(newID);
549     assert !id2paramIndex.containsValue(paramIndex);
550     id2paramIndex.put(newID, paramIndex);
551     paramIndex2id.put(paramIndex, newID);
552     paramIndex2tdQ.put(paramIndex, tdParamQ);
553
554     ReachabilitySet beta = new ReachabilitySet(new TokenTuple(newID,
555                                                               true,
556                                                               TokenTuple.ARITY_ONE) );
557
558     // heap regions for parameters are always multiple object (see above)
559     // and have a reference to themselves, because we can't know the
560     // structure of memory that is passed into the method.  We're assuming
561     // the worst here.
562
563     ReferenceEdge edgeFromLabel =
564       new ReferenceEdge(lnParam, hrn, null, false, beta);
565
566     ReferenceEdge edgeFromLabelQ =
567       new ReferenceEdge(lnParamQ, hrn, null, false, beta);
568
569     ReferenceEdge edgeReflexive =
570       new ReferenceEdge(hrn,     hrn, null, true,  beta);
571
572     addReferenceEdge(lnParam,  hrn, edgeFromLabel);
573     addReferenceEdge(lnParamQ, hrn, edgeFromLabelQ);
574     addReferenceEdge(hrn,      hrn, edgeReflexive);
575   }
576
577
578   public void assignReturnEqualToTemp(TempDescriptor x) {
579
580     LabelNode lnR = getLabelNodeFromTemp(tdReturn);
581     LabelNode lnX = getLabelNodeFromTemp(x);
582
583     clearReferenceEdgesFrom(lnR, null, true);
584
585     Iterator<ReferenceEdge> itrXhrn = lnX.iteratorToReferencees();
586     while( itrXhrn.hasNext() ) {
587       ReferenceEdge edgeX       = itrXhrn.next();
588       HeapRegionNode referencee = edgeX.getDst();
589       ReferenceEdge edgeNew    = edgeX.copy();
590       edgeNew.setSrc(lnR);
591
592       addReferenceEdge(lnR, referencee, edgeNew);
593     }
594   }
595
596
597   public void assignTempEqualToNewAlloc(TempDescriptor x,
598                                         AllocationSite as) {
599     assert x  != null;
600     assert as != null;
601
602     age(as);
603
604     // after the age operation the newest (or zero-ith oldest)
605     // node associated with the allocation site should have
606     // no references to it as if it were a newly allocated
607     // heap region, so make a reference to it to complete
608     // this operation
609
610     Integer idNewest  = as.getIthOldest(0);
611     HeapRegionNode hrnNewest = id2hrn.get(idNewest);
612     assert hrnNewest != null;
613
614     LabelNode lnX = getLabelNodeFromTemp(x);
615     clearReferenceEdgesFrom(lnX, null, true);
616
617     ReferenceEdge edgeNew =
618       new ReferenceEdge(lnX, hrnNewest, null, false, hrnNewest.getAlpha() );
619
620     addReferenceEdge(lnX, hrnNewest, edgeNew);
621   }
622
623
624   // use the allocation site (unique to entire analysis) to
625   // locate the heap region nodes in this ownership graph
626   // that should be aged.  The process models the allocation
627   // of new objects and collects all the oldest allocations
628   // in a summary node to allow for a finite analysis
629   //
630   // There is an additional property of this method.  After
631   // running it on a particular ownership graph (many graphs
632   // may have heap regions related to the same allocation site)
633   // the heap region node objects in this ownership graph will be
634   // allocated.  Therefore, after aging a graph for an allocation
635   // site, attempts to retrieve the heap region nodes using the
636   // integer id's contained in the allocation site should always
637   // return non-null heap regions.
638   public void age(AllocationSite as) {
639
640     // aging adds this allocation site to the graph's
641     // list of sites that exist in the graph, or does
642     // nothing if the site is already in the list
643     allocationSites.add(as);
644
645     // get the summary node for the allocation site in the context
646     // of this particular ownership graph
647     HeapRegionNode hrnSummary = getSummaryNode(as);
648
649     // merge oldest node into summary
650     Integer idK  = as.getOldest();
651     HeapRegionNode hrnK = id2hrn.get(idK);
652     mergeIntoSummary(hrnK, hrnSummary);
653
654     // move down the line of heap region nodes
655     // clobbering the ith and transferring all references
656     // to and from i-1 to node i.  Note that this clobbers
657     // the oldest node (hrnK) that was just merged into
658     // the summary
659     for( int i = allocationDepth - 1; i > 0; --i ) {
660
661       // move references from the i-1 oldest to the ith oldest
662       Integer idIth     = as.getIthOldest(i);
663       HeapRegionNode hrnI      = id2hrn.get(idIth);
664       Integer idImin1th = as.getIthOldest(i - 1);
665       HeapRegionNode hrnImin1  = id2hrn.get(idImin1th);
666
667       transferOnto(hrnImin1, hrnI);
668     }
669
670     // as stated above, the newest node should have had its
671     // references moved over to the second oldest, so we wipe newest
672     // in preparation for being the new object to assign something to
673     Integer id0th = as.getIthOldest(0);
674     HeapRegionNode hrn0  = id2hrn.get(id0th);
675     assert hrn0 != null;
676
677     // clear all references in and out of newest node
678     clearReferenceEdgesFrom(hrn0, null, true);
679     clearReferenceEdgesTo(hrn0, null, true);
680
681
682     // now tokens in reachability sets need to "age" also
683     Iterator itrAllLabelNodes = td2ln.entrySet().iterator();
684     while( itrAllLabelNodes.hasNext() ) {
685       Map.Entry me = (Map.Entry)itrAllLabelNodes.next();
686       LabelNode ln = (LabelNode) me.getValue();
687
688       Iterator<ReferenceEdge> itrEdges = ln.iteratorToReferencees();
689       while( itrEdges.hasNext() ) {
690         ageTokens(as, itrEdges.next() );
691       }
692     }
693
694     Iterator itrAllHRNodes = id2hrn.entrySet().iterator();
695     while( itrAllHRNodes.hasNext() ) {
696       Map.Entry me       = (Map.Entry)itrAllHRNodes.next();
697       HeapRegionNode hrnToAge = (HeapRegionNode) me.getValue();
698
699       ageTokens(as, hrnToAge);
700
701       Iterator<ReferenceEdge> itrEdges = hrnToAge.iteratorToReferencees();
702       while( itrEdges.hasNext() ) {
703         ageTokens(as, itrEdges.next() );
704       }
705     }
706
707
708     // after tokens have been aged, reset newest node's reachability
709     if( hrn0.isFlagged() ) {
710       hrn0.setAlpha(new ReachabilitySet(new TokenTupleSet(
711                                           new TokenTuple(hrn0)
712                                           )
713                                         ).makeCanonical()
714                     );
715     } else {
716       hrn0.setAlpha(new ReachabilitySet(new TokenTupleSet()
717                                         ).makeCanonical()
718                     );
719     }
720   }
721
722
723   protected HeapRegionNode getSummaryNode(AllocationSite as) {
724
725     Integer idSummary  = as.getSummary();
726     HeapRegionNode hrnSummary = id2hrn.get(idSummary);
727
728     // If this is null then we haven't touched this allocation site
729     // in the context of the current ownership graph, so allocate
730     // heap region nodes appropriate for the entire allocation site.
731     // This should only happen once per ownership graph per allocation site,
732     // and a particular integer id can be used to locate the heap region
733     // in different ownership graphs that represents the same part of an
734     // allocation site.
735     if( hrnSummary == null ) {
736
737       boolean hasFlags = false;
738       if( as.getType().isClass() ) {
739         hasFlags = as.getType().getClassDesc().hasFlags();
740       }
741
742       hrnSummary = createNewHeapRegionNode(idSummary,
743                                            false,
744                                            hasFlags,
745                                            true,
746                                            false,
747                                            as,
748                                            null,
749                                            as + "\\n" + as.getType() + "\\nsummary");
750
751       for( int i = 0; i < as.getAllocationDepth(); ++i ) {
752         Integer idIth = as.getIthOldest(i);
753         assert !id2hrn.containsKey(idIth);
754         createNewHeapRegionNode(idIth,
755                                 true,
756                                 hasFlags,
757                                 false,
758                                 false,
759                                 as,
760                                 null,
761                                 as + "\\n" + as.getType() + "\\n" + i + " oldest");
762       }
763     }
764
765     return hrnSummary;
766   }
767
768
769   protected HeapRegionNode getShadowSummaryNode(AllocationSite as) {
770
771     Integer idShadowSummary  = as.getSummaryShadow();
772     HeapRegionNode hrnShadowSummary = id2hrn.get(idShadowSummary);
773
774     if( hrnShadowSummary == null ) {
775
776       boolean hasFlags = false;
777       if( as.getType().isClass() ) {
778         hasFlags = as.getType().getClassDesc().hasFlags();
779       }
780
781       hrnShadowSummary = createNewHeapRegionNode(idShadowSummary,
782                                                  false,
783                                                  hasFlags,
784                                                  true,
785                                                  false,
786                                                  as,
787                                                  null,
788                                                  as + "\\n" + as.getType() + "\\nshadowSum");
789
790       for( int i = 0; i < as.getAllocationDepth(); ++i ) {
791         Integer idShadowIth = as.getIthOldestShadow(i);
792         assert !id2hrn.containsKey(idShadowIth);
793         createNewHeapRegionNode(idShadowIth,
794                                 true,
795                                 hasFlags,
796                                 false,
797                                 false,
798                                 as,
799                                 null,
800                                 as + "\\n" + as.getType() + "\\n" + i + " shadow");
801       }
802     }
803
804     return hrnShadowSummary;
805   }
806
807
808   protected void mergeIntoSummary(HeapRegionNode hrn, HeapRegionNode hrnSummary) {
809     assert hrnSummary.isNewSummary();
810
811     // transfer references _from_ hrn over to hrnSummary
812     Iterator<ReferenceEdge> itrReferencee = hrn.iteratorToReferencees();
813     while( itrReferencee.hasNext() ) {
814       ReferenceEdge edge       = itrReferencee.next();
815       ReferenceEdge edgeMerged = edge.copy();
816       edgeMerged.setSrc(hrnSummary);
817
818       HeapRegionNode hrnReferencee = edge.getDst();
819       ReferenceEdge edgeSummary   = hrnSummary.getReferenceTo(hrnReferencee, edge.getFieldDesc() );
820
821       if( edgeSummary == null ) {
822         // the merge is trivial, nothing to be done
823       } else {
824         // otherwise an edge from the referencer to hrnSummary exists already
825         // and the edge referencer->hrn should be merged with it
826         edgeMerged.setBeta(edgeMerged.getBeta().union(edgeSummary.getBeta() ) );
827       }
828
829       addReferenceEdge(hrnSummary, hrnReferencee, edgeMerged);
830     }
831
832     // next transfer references _to_ hrn over to hrnSummary
833     Iterator<ReferenceEdge> itrReferencer = hrn.iteratorToReferencers();
834     while( itrReferencer.hasNext() ) {
835       ReferenceEdge edge         = itrReferencer.next();
836       ReferenceEdge edgeMerged   = edge.copy();
837       edgeMerged.setDst(hrnSummary);
838
839       OwnershipNode onReferencer = edge.getSrc();
840       ReferenceEdge edgeSummary  = onReferencer.getReferenceTo(hrnSummary, edge.getFieldDesc() );
841
842       if( edgeSummary == null ) {
843         // the merge is trivial, nothing to be done
844       } else {
845         // otherwise an edge from the referencer to alpha_S exists already
846         // and the edge referencer->alpha_K should be merged with it
847         edgeMerged.setBeta(edgeMerged.getBeta().union(edgeSummary.getBeta() ) );
848       }
849
850       addReferenceEdge(onReferencer, hrnSummary, edgeMerged);
851     }
852
853     // then merge hrn reachability into hrnSummary
854     hrnSummary.setAlpha(hrnSummary.getAlpha().union(hrn.getAlpha() ) );
855   }
856
857
858   protected void transferOnto(HeapRegionNode hrnA, HeapRegionNode hrnB) {
859
860     // clear references in and out of node i
861     clearReferenceEdgesFrom(hrnB, null, true);
862     clearReferenceEdgesTo(hrnB, null, true);
863
864     // copy each edge in and out of A to B
865     Iterator<ReferenceEdge> itrReferencee = hrnA.iteratorToReferencees();
866     while( itrReferencee.hasNext() ) {
867       ReferenceEdge edge          = itrReferencee.next();
868       HeapRegionNode hrnReferencee = edge.getDst();
869       ReferenceEdge edgeNew       = edge.copy();
870       edgeNew.setSrc(hrnB);
871
872       addReferenceEdge(hrnB, hrnReferencee, edgeNew);
873     }
874
875     Iterator<ReferenceEdge> itrReferencer = hrnA.iteratorToReferencers();
876     while( itrReferencer.hasNext() ) {
877       ReferenceEdge edge         = itrReferencer.next();
878       OwnershipNode onReferencer = edge.getSrc();
879       ReferenceEdge edgeNew      = edge.copy();
880       edgeNew.setDst(hrnB);
881
882       addReferenceEdge(onReferencer, hrnB, edgeNew);
883     }
884
885     // replace hrnB reachability with hrnA's
886     hrnB.setAlpha(hrnA.getAlpha() );
887   }
888
889
890   protected void ageTokens(AllocationSite as, ReferenceEdge edge) {
891     edge.setBeta(edge.getBeta().ageTokens(as) );
892   }
893
894   protected void ageTokens(AllocationSite as, HeapRegionNode hrn) {
895     hrn.setAlpha(hrn.getAlpha().ageTokens(as) );
896   }
897
898
899   public void resolveMethodCall(FlatCall fc,
900                                 boolean isStatic,
901                                 FlatMethod fm,
902                                 OwnershipGraph ogCallee) {
903
904     // define rewrite rules and other structures to organize
905     // data by parameter/argument index
906     Hashtable<Integer, ReachabilitySet> paramIndex2rewriteH =
907       new Hashtable<Integer, ReachabilitySet>();
908
909     Hashtable<Integer, ReachabilitySet> paramIndex2rewriteJ =
910       new Hashtable<Integer, ReachabilitySet>();
911
912     Hashtable<Integer, ReachabilitySet> paramIndex2rewriteK =
913       new Hashtable<Integer, ReachabilitySet>();
914
915     Hashtable<Integer, ReachabilitySet> paramIndex2rewrite_d =
916       new Hashtable<Integer, ReachabilitySet>();
917
918     Hashtable<Integer, ReachabilitySet> paramIndex2rewriteD =
919       new Hashtable<Integer, ReachabilitySet>();
920
921     // helpful structures
922     Hashtable<TokenTuple, Integer> paramToken2paramIndex =
923       new Hashtable<TokenTuple, Integer>();
924
925     Hashtable<Integer, TokenTuple> paramIndex2paramToken =
926       new Hashtable<Integer, TokenTuple>();
927
928     Hashtable<TokenTuple, Integer> paramTokenStar2paramIndex =
929       new Hashtable<TokenTuple, Integer>();
930
931     Hashtable<Integer, TokenTuple> paramIndex2paramTokenStar =
932       new Hashtable<Integer, TokenTuple>();
933
934     Hashtable<Integer, LabelNode> paramIndex2ln =
935       new Hashtable<Integer, LabelNode>();
936
937     Hashtable<Integer, HashSet<HeapRegionNode> > paramIndex2reachableCallerNodes =
938       new Hashtable<Integer, HashSet<HeapRegionNode> >();
939
940
941     // add a bogus entry with the identity rule for easy rewrite
942     // of new callee nodes and edges, doesn't belong to any parameter
943     Integer bogusID = new Integer(-1);
944     Integer bogusIndex = new Integer(-1);
945     TokenTuple bogusToken = new TokenTuple(bogusID, true, TokenTuple.ARITY_ONE);
946     TokenTuple bogusTokenStar = new TokenTuple(bogusID, true, TokenTuple.ARITY_MANY);
947     ReachabilitySet rsIdentity =
948       new ReachabilitySet(new TokenTupleSet(bogusToken).makeCanonical() ).makeCanonical();
949
950     paramIndex2rewriteH.put(bogusIndex, rsIdentity);
951     paramIndex2rewriteJ.put(bogusIndex, rsIdentity);
952     paramToken2paramIndex.put(bogusToken, bogusIndex);
953     paramIndex2paramToken.put(bogusIndex, bogusToken);
954     paramTokenStar2paramIndex.put(bogusTokenStar, bogusIndex);
955     paramIndex2paramTokenStar.put(bogusIndex, bogusTokenStar);
956
957
958     for( int i = 0; i < fm.numParameters(); ++i ) {
959       Integer paramIndex = new Integer(i);
960
961       assert ogCallee.paramIndex2id.containsKey(paramIndex);
962       Integer idParam = ogCallee.paramIndex2id.get(paramIndex);
963
964       assert ogCallee.id2hrn.containsKey(idParam);
965       HeapRegionNode hrnParam = ogCallee.id2hrn.get(idParam);
966       assert hrnParam != null;
967       paramIndex2rewriteH.put(paramIndex,
968
969                               toShadowTokens(ogCallee, hrnParam.getAlpha() )
970                               );
971
972       ReferenceEdge edgeReflexive_i = hrnParam.getReferenceTo(hrnParam, null);
973       assert edgeReflexive_i != null;
974       paramIndex2rewriteJ.put(paramIndex,
975                               toShadowTokens(ogCallee, edgeReflexive_i.getBeta() )
976                               );
977
978       TempDescriptor tdParamQ = ogCallee.paramIndex2tdQ.get(paramIndex);
979       assert tdParamQ != null;
980       LabelNode lnParamQ = ogCallee.td2ln.get(tdParamQ);
981       assert lnParamQ != null;
982       ReferenceEdge edgeSpecialQ_i = lnParamQ.getReferenceTo(hrnParam, null);
983       assert edgeSpecialQ_i != null;
984       paramIndex2rewriteK.put(paramIndex,
985                               toShadowTokens(ogCallee, edgeSpecialQ_i.getBeta() )
986                               );
987
988       TokenTuple p_i = new TokenTuple(hrnParam.getID(),
989                                       true,
990                                       TokenTuple.ARITY_ONE).makeCanonical();
991       paramToken2paramIndex.put(p_i, paramIndex);
992       paramIndex2paramToken.put(paramIndex, p_i);
993
994       TokenTuple p_i_star = new TokenTuple(hrnParam.getID(),
995                                            true,
996                                            TokenTuple.ARITY_MANY).makeCanonical();
997       paramTokenStar2paramIndex.put(p_i_star, paramIndex);
998       paramIndex2paramTokenStar.put(paramIndex, p_i_star);
999
1000       // now depending on whether the callee is static or not
1001       // we need to account for a "this" argument in order to
1002       // find the matching argument in the caller context
1003       TempDescriptor argTemp_i;
1004       if( isStatic ) {
1005         argTemp_i = fc.getArg(paramIndex);
1006       } else {
1007         if( paramIndex.equals( 0 ) ) {
1008           argTemp_i = fc.getThis();
1009         } else {
1010           argTemp_i = fc.getArg(paramIndex - 1);
1011         }
1012       }
1013
1014       // in non-static methods there is a "this" pointer
1015       // that should be taken into account
1016       if( isStatic ) {
1017         assert fc.numArgs()     == fm.numParameters();
1018       } else {
1019         assert fc.numArgs() + 1 == fm.numParameters();
1020       }
1021
1022       LabelNode argLabel_i = getLabelNodeFromTemp(argTemp_i);
1023       paramIndex2ln.put(paramIndex, argLabel_i);
1024
1025       ReachabilitySet d_i = new ReachabilitySet().makeCanonical();
1026       Iterator<ReferenceEdge> edgeItr = argLabel_i.iteratorToReferencees();
1027       while( edgeItr.hasNext() ) {
1028         ReferenceEdge edge = edgeItr.next();
1029         d_i = d_i.union(edge.getBeta());
1030       }
1031       paramIndex2rewrite_d.put(paramIndex, d_i);
1032
1033       ReachabilitySet D_i = d_i.exhaustiveArityCombinations();
1034       paramIndex2rewriteD.put(paramIndex, D_i);
1035     }
1036
1037
1038     HashSet<HeapRegionNode> nodesWithNewAlpha = new HashSet<HeapRegionNode>();
1039     HashSet<ReferenceEdge>  edgesWithNewBeta  = new HashSet<ReferenceEdge>();
1040
1041     HashSet<ReferenceEdge>  edgesReachable    = new HashSet<ReferenceEdge>();
1042     HashSet<ReferenceEdge>  edgesUpstream     = new HashSet<ReferenceEdge>();
1043
1044     Iterator lnArgItr = paramIndex2ln.entrySet().iterator();
1045     while( lnArgItr.hasNext() ) {
1046       Map.Entry me      = (Map.Entry)lnArgItr.next();
1047       Integer index   = (Integer)   me.getKey();
1048       LabelNode lnArg_i = (LabelNode) me.getValue();
1049
1050       // rewrite alpha for the nodes reachable from argument label i
1051       HashSet<HeapRegionNode> reachableNodes = new HashSet<HeapRegionNode>();
1052       HashSet<HeapRegionNode> todoNodes = new HashSet<HeapRegionNode>();
1053
1054       // to find all reachable nodes, start with label referencees
1055       Iterator<ReferenceEdge> edgeArgItr = lnArg_i.iteratorToReferencees();
1056       while( edgeArgItr.hasNext() ) {
1057         ReferenceEdge edge = edgeArgItr.next();
1058         todoNodes.add(edge.getDst() );
1059       }
1060
1061       // then follow links until all reachable nodes have been found
1062       while( !todoNodes.isEmpty() ) {
1063         HeapRegionNode hrn = todoNodes.iterator().next();
1064         todoNodes.remove(hrn);
1065         reachableNodes.add(hrn);
1066
1067         Iterator<ReferenceEdge> edgeItr = hrn.iteratorToReferencees();
1068         while( edgeItr.hasNext() ) {
1069           ReferenceEdge edge = edgeItr.next();
1070
1071           if( !reachableNodes.contains(edge.getDst() ) ) {
1072             todoNodes.add(edge.getDst() );
1073           }
1074         }
1075       }
1076
1077       // save for later
1078       paramIndex2reachableCallerNodes.put(index, reachableNodes);
1079
1080       // now iterate over reachable nodes to update their alpha, and
1081       // classify edges found as "argument reachable" or "upstream"
1082       Iterator<HeapRegionNode> hrnItr = reachableNodes.iterator();
1083       while( hrnItr.hasNext() ) {
1084         HeapRegionNode hrn = hrnItr.next();
1085
1086         rewriteCallerReachability(index,
1087                                   hrn,
1088                                   null,
1089                                   paramIndex2rewriteH.get(index),
1090                                   paramIndex2rewrite_d,
1091                                   paramIndex2rewriteD,
1092                                   paramIndex2paramToken.get(index),
1093                                   paramToken2paramIndex,
1094                                   paramTokenStar2paramIndex,
1095                                   false,
1096                                   null);
1097
1098         nodesWithNewAlpha.add(hrn);
1099
1100         // look at all incoming edges to the reachable nodes
1101         // and sort them as edges reachable from the argument
1102         // label node, or upstream edges
1103         Iterator<ReferenceEdge> edgeItr = hrn.iteratorToReferencers();
1104         while( edgeItr.hasNext() ) {
1105           ReferenceEdge edge = edgeItr.next();
1106
1107           OwnershipNode on = edge.getSrc();
1108
1109           if( on instanceof LabelNode ) {
1110
1111             LabelNode ln0 = (LabelNode) on;
1112             if( ln0.equals(lnArg_i) ) {
1113               edgesReachable.add(edge);
1114             } else {
1115               edgesUpstream.add(edge);
1116             }
1117
1118           } else {
1119
1120             HeapRegionNode hrn0 = (HeapRegionNode) on;
1121             if( reachableNodes.contains(hrn0) ) {
1122               edgesReachable.add(edge);
1123             } else {
1124               edgesUpstream.add(edge);
1125             }
1126           }
1127         }
1128       }
1129
1130       // update reachable edges
1131       Iterator<ReferenceEdge> edgeReachableItr = edgesReachable.iterator();
1132       while( edgeReachableItr.hasNext() ) {
1133         ReferenceEdge edgeReachable = edgeReachableItr.next();
1134
1135         rewriteCallerReachability(index,
1136                                   null,
1137                                   edgeReachable,
1138                                   paramIndex2rewriteJ.get(index),
1139                                   paramIndex2rewrite_d,
1140                                   paramIndex2rewriteD,
1141                                   paramIndex2paramToken.get(index),
1142                                   paramToken2paramIndex,
1143                                   paramTokenStar2paramIndex,
1144                                   false,
1145                                   null);
1146
1147         edgesWithNewBeta.add(edgeReachable);
1148       }
1149
1150       // update upstream edges
1151       Hashtable<ReferenceEdge, ChangeTupleSet> edgeUpstreamPlannedChanges =
1152         new Hashtable<ReferenceEdge, ChangeTupleSet>();
1153
1154       Iterator<ReferenceEdge> edgeUpstreamItr = edgesUpstream.iterator();
1155       while( edgeUpstreamItr.hasNext() ) {
1156         ReferenceEdge edgeUpstream = edgeUpstreamItr.next();
1157
1158         rewriteCallerReachability(index,
1159                                   null,
1160                                   edgeUpstream,
1161                                   paramIndex2rewriteK.get(index),
1162                                   paramIndex2rewrite_d,
1163                                   paramIndex2rewriteD,
1164                                   paramIndex2paramToken.get(index),
1165                                   paramToken2paramIndex,
1166                                   paramTokenStar2paramIndex,
1167                                   true,
1168                                   edgeUpstreamPlannedChanges);
1169
1170         edgesWithNewBeta.add(edgeUpstream);
1171       }
1172
1173       propagateTokensOverEdges(edgesUpstream,
1174                                edgeUpstreamPlannedChanges,
1175                                edgesWithNewBeta);
1176     }
1177
1178
1179     // commit changes to alpha and beta
1180     Iterator<HeapRegionNode> nodeItr = nodesWithNewAlpha.iterator();
1181     while( nodeItr.hasNext() ) {
1182       nodeItr.next().applyAlphaNew();
1183     }
1184
1185     Iterator<ReferenceEdge> edgeItr = edgesWithNewBeta.iterator();
1186     while( edgeItr.hasNext() ) {
1187       edgeItr.next().applyBetaNew();
1188     }
1189
1190
1191     // verify the existence of allocation sites and their
1192     // shadows from the callee in the context of this caller graph
1193     // then map allocated nodes of callee onto the caller shadows
1194     // of them
1195     Iterator<AllocationSite> asItr = ogCallee.allocationSites.iterator();
1196     while( asItr.hasNext() ) {
1197       AllocationSite allocSite  = asItr.next();
1198       HeapRegionNode hrnSummary = getSummaryNode(allocSite);
1199
1200       // assert that the shadow nodes have no reference edges
1201       // because they're brand new to the graph, or last time
1202       // they were used they should have been cleared of edges
1203       HeapRegionNode hrnShadowSummary = getShadowSummaryNode(allocSite);
1204       assert hrnShadowSummary.getNumReferencers() == 0;
1205       assert hrnShadowSummary.getNumReferencees() == 0;
1206
1207       // then bring g_ij onto g'_ij and rewrite
1208       transferOnto(hrnSummary, hrnShadowSummary);
1209
1210       HeapRegionNode hrnSummaryCallee = ogCallee.getSummaryNode(allocSite);
1211       hrnShadowSummary.setAlpha(toShadowTokens(ogCallee, hrnSummaryCallee.getAlpha() ) );
1212
1213       // shadow nodes only are touched by a rewrite one time,
1214       // so rewrite and immediately commit--and they don't belong
1215       // to a particular parameter, so use a bogus param index
1216       // that pulls a self-rewrite out of H
1217       rewriteCallerReachability(bogusIndex,
1218                                 hrnShadowSummary,
1219                                 null,
1220                                 hrnShadowSummary.getAlpha(),
1221                                 paramIndex2rewrite_d,
1222                                 paramIndex2rewriteD,
1223                                 bogusToken,
1224                                 paramToken2paramIndex,
1225                                 paramTokenStar2paramIndex,
1226                                 false,
1227                                 null);
1228
1229       hrnShadowSummary.applyAlphaNew();
1230
1231
1232       for( int i = 0; i < allocSite.getAllocationDepth(); ++i ) {
1233         Integer idIth = allocSite.getIthOldest(i);
1234         assert id2hrn.containsKey(idIth);
1235         HeapRegionNode hrnIth = id2hrn.get(idIth);
1236
1237         Integer idShadowIth = -(allocSite.getIthOldest(i));
1238         assert id2hrn.containsKey(idShadowIth);
1239         HeapRegionNode hrnIthShadow = id2hrn.get(idShadowIth);
1240         assert hrnIthShadow.getNumReferencers() == 0;
1241         assert hrnIthShadow.getNumReferencees() == 0;
1242
1243         transferOnto(hrnIth, hrnIthShadow);
1244
1245         assert ogCallee.id2hrn.containsKey(idIth);
1246         HeapRegionNode hrnIthCallee = ogCallee.id2hrn.get(idIth);
1247         hrnIthShadow.setAlpha(toShadowTokens(ogCallee, hrnIthCallee.getAlpha() ) );
1248
1249         rewriteCallerReachability(bogusIndex,
1250                                   hrnIthShadow,
1251                                   null,
1252                                   hrnIthShadow.getAlpha(),
1253                                   paramIndex2rewrite_d,
1254                                   paramIndex2rewriteD,
1255                                   bogusToken,
1256                                   paramToken2paramIndex,
1257                                   paramTokenStar2paramIndex,
1258                                   false,
1259                                   null);
1260
1261         hrnIthShadow.applyAlphaNew();
1262       }
1263     }
1264
1265
1266     // for every heap region->heap region edge in the
1267     // callee graph, create the matching edge or edges
1268     // in the caller graph
1269     Set sCallee = ogCallee.id2hrn.entrySet();
1270     Iterator iCallee = sCallee.iterator();
1271     while( iCallee.hasNext() ) {
1272       Map.Entry meCallee  = (Map.Entry)iCallee.next();
1273       Integer idCallee  = (Integer)        meCallee.getKey();
1274       HeapRegionNode hrnCallee = (HeapRegionNode) meCallee.getValue();
1275
1276       Iterator<ReferenceEdge> heapRegionsItrCallee = hrnCallee.iteratorToReferencees();
1277       while( heapRegionsItrCallee.hasNext() ) {
1278         ReferenceEdge edgeCallee      =  heapRegionsItrCallee.next();
1279         HeapRegionNode hrnChildCallee = edgeCallee.getDst();
1280         Integer idChildCallee         = hrnChildCallee.getID();
1281
1282         // only address this edge if it is not a special reflexive edge
1283         if( !edgeCallee.isInitialParamReflexive() ) {
1284
1285           // now we know that in the callee method's ownership graph
1286           // there is a heap region->heap region reference edge given
1287           // by heap region pointers:
1288           // hrnCallee -> heapChildCallee
1289           //
1290           // or by the ownership-graph independent ID's:
1291           // idCallee -> idChildCallee
1292
1293           // make the edge with src and dst so beta info is
1294           // calculated once, then copy it for each new edge in caller
1295           ReferenceEdge edgeNewInCallerTemplate = new ReferenceEdge(null,
1296                                                                     null,
1297                                                                     edgeCallee.getFieldDesc(),
1298                                                                     false,
1299                                                                     toShadowTokens(ogCallee, edgeCallee.getBeta() )
1300                                                                     );
1301           rewriteCallerReachability(bogusIndex,
1302                                     null,
1303                                     edgeNewInCallerTemplate,
1304                                     edgeNewInCallerTemplate.getBeta(),
1305                                     paramIndex2rewrite_d,
1306                                     paramIndex2rewriteD,
1307                                     bogusToken,
1308                                     paramToken2paramIndex,
1309                                     paramTokenStar2paramIndex,
1310                                     false,
1311                                     null);
1312
1313           edgeNewInCallerTemplate.applyBetaNew();
1314
1315
1316           // So now make a set of possible source heaps in the caller graph
1317           // and a set of destination heaps in the caller graph, and make
1318           // a reference edge in the caller for every possible (src,dst) pair
1319           HashSet<HeapRegionNode> possibleCallerSrcs =
1320             getHRNSetThatPossiblyMapToCalleeHRN(ogCallee,
1321                                                 (HeapRegionNode) edgeCallee.getSrc(),
1322                                                 paramIndex2reachableCallerNodes);
1323
1324           HashSet<HeapRegionNode> possibleCallerDsts =
1325             getHRNSetThatPossiblyMapToCalleeHRN(ogCallee,
1326                                                 edgeCallee.getDst(),
1327                                                 paramIndex2reachableCallerNodes);
1328
1329
1330           // make every possible pair of {srcSet} -> {dstSet} edges in the caller
1331           Iterator srcItr = possibleCallerSrcs.iterator();
1332           while( srcItr.hasNext() ) {
1333             HeapRegionNode src = (HeapRegionNode) srcItr.next();
1334
1335             if( !hasMatchingField(src, edgeCallee) ) {
1336               // prune this source node possibility
1337               continue;
1338             }
1339
1340             Iterator dstItr = possibleCallerDsts.iterator();
1341             while( dstItr.hasNext() ) {
1342               HeapRegionNode dst = (HeapRegionNode) dstItr.next();
1343
1344               if( !hasMatchingType(edgeCallee, dst) ) {
1345                 // prune
1346                 continue;
1347               }
1348
1349               // otherwise the caller src and dst pair can match the edge, so make it
1350               ReferenceEdge edgeNewInCaller = edgeNewInCallerTemplate.copy();
1351               edgeNewInCaller.setSrc(src);
1352               edgeNewInCaller.setDst(dst);
1353
1354               ReferenceEdge edgeExisting = src.getReferenceTo(dst, edgeNewInCaller.getFieldDesc() );
1355               if( edgeExisting == null ) {
1356                 // if this edge doesn't exist in the caller, create it
1357                 addReferenceEdge(src, dst, edgeNewInCaller);
1358               } else {
1359                 // if it already exists, merge with it
1360                 edgeExisting.setBeta(edgeExisting.getBeta().union(edgeNewInCaller.getBeta() ) );
1361               }
1362             }
1363           }
1364         }
1365       }
1366     }
1367
1368
1369     // return value may need to be assigned in caller
1370     TempDescriptor returnTemp = fc.getReturnTemp();
1371     if( returnTemp != null && !returnTemp.getType().isImmutable() ) {
1372
1373       LabelNode lnLhsCaller = getLabelNodeFromTemp(returnTemp);
1374       clearReferenceEdgesFrom(lnLhsCaller, null, true);
1375
1376       LabelNode lnReturnCallee = ogCallee.getLabelNodeFromTemp(tdReturn);
1377       Iterator<ReferenceEdge> edgeCalleeItr = lnReturnCallee.iteratorToReferencees();
1378       while( edgeCalleeItr.hasNext() ) {
1379         ReferenceEdge edgeCallee = edgeCalleeItr.next();
1380
1381         ReferenceEdge edgeNewInCallerTemplate = new ReferenceEdge(null,
1382                                                                   null,
1383                                                                   edgeCallee.getFieldDesc(),
1384                                                                   false,
1385                                                                   toShadowTokens(ogCallee, edgeCallee.getBeta() )
1386                                                                   );
1387         rewriteCallerReachability(bogusIndex,
1388                                   null,
1389                                   edgeNewInCallerTemplate,
1390                                   edgeNewInCallerTemplate.getBeta(),
1391                                   paramIndex2rewrite_d,
1392                                   paramIndex2rewriteD,
1393                                   bogusToken,
1394                                   paramToken2paramIndex,
1395                                   paramTokenStar2paramIndex,
1396                                   false,
1397                                   null);
1398
1399         edgeNewInCallerTemplate.applyBetaNew();
1400
1401
1402         HashSet<HeapRegionNode> assignCallerRhs =
1403           getHRNSetThatPossiblyMapToCalleeHRN(ogCallee,
1404                                               edgeCallee.getDst(),
1405                                               paramIndex2reachableCallerNodes);
1406
1407         Iterator<HeapRegionNode> itrHrn = assignCallerRhs.iterator();
1408         while( itrHrn.hasNext() ) {
1409           HeapRegionNode hrnCaller = itrHrn.next();
1410
1411           if( !hasMatchingType(edgeCallee, hrnCaller) ) {
1412             // prune
1413             continue;
1414           }
1415
1416           // otherwise caller node can match callee edge, so make it
1417           ReferenceEdge edgeNewInCaller = edgeNewInCallerTemplate.copy();
1418           edgeNewInCaller.setSrc(lnLhsCaller);
1419           edgeNewInCaller.setDst(hrnCaller);
1420
1421           ReferenceEdge edgeExisting = lnLhsCaller.getReferenceTo(hrnCaller, edgeNewInCaller.getFieldDesc() );
1422           if( edgeExisting == null ) {
1423
1424             // if this edge doesn't exist in the caller, create it
1425             addReferenceEdge(lnLhsCaller, hrnCaller, edgeNewInCaller);
1426           } else {
1427             // if it already exists, merge with it
1428             edgeExisting.setBeta(edgeExisting.getBeta().union(edgeNewInCaller.getBeta() ) );
1429           }
1430         }
1431       }
1432     }
1433
1434
1435     // merge the shadow nodes of allocation sites back down to normal capacity
1436     Iterator<AllocationSite> allocItr = ogCallee.allocationSites.iterator();
1437     while( allocItr.hasNext() ) {
1438       AllocationSite as = allocItr.next();
1439
1440       // first age each allocation site enough times to make room for the shadow nodes
1441       for( int i = 0; i < as.getAllocationDepth(); ++i ) {
1442         age(as);
1443       }
1444
1445       // then merge the shadow summary into the normal summary
1446       HeapRegionNode hrnSummary = getSummaryNode(as);
1447       assert hrnSummary != null;
1448
1449       HeapRegionNode hrnSummaryShadow = getShadowSummaryNode(as);
1450       assert hrnSummaryShadow != null;
1451
1452       mergeIntoSummary(hrnSummaryShadow, hrnSummary);
1453
1454       // then clear off after merge
1455       clearReferenceEdgesFrom(hrnSummaryShadow, null, true);
1456       clearReferenceEdgesTo(hrnSummaryShadow, null, true);
1457       hrnSummaryShadow.setAlpha(new ReachabilitySet().makeCanonical() );
1458
1459       // then transplant shadow nodes onto the now clean normal nodes
1460       for( int i = 0; i < as.getAllocationDepth(); ++i ) {
1461
1462         Integer idIth = as.getIthOldest(i);
1463         HeapRegionNode hrnIth = id2hrn.get(idIth);
1464
1465         Integer idIthShadow = as.getIthOldestShadow(i);
1466         HeapRegionNode hrnIthShadow = id2hrn.get(idIthShadow);
1467
1468         transferOnto(hrnIthShadow, hrnIth);
1469
1470         // clear off shadow nodes after transfer
1471         clearReferenceEdgesFrom(hrnIthShadow, null, true);
1472         clearReferenceEdgesTo(hrnIthShadow, null, true);
1473         hrnIthShadow.setAlpha(new ReachabilitySet().makeCanonical() );
1474       }
1475
1476       // finally, globally change shadow tokens into normal tokens
1477       Iterator itrAllLabelNodes = td2ln.entrySet().iterator();
1478       while( itrAllLabelNodes.hasNext() ) {
1479         Map.Entry me = (Map.Entry)itrAllLabelNodes.next();
1480         LabelNode ln = (LabelNode) me.getValue();
1481
1482         Iterator<ReferenceEdge> itrEdges = ln.iteratorToReferencees();
1483         while( itrEdges.hasNext() ) {
1484           unshadowTokens(as, itrEdges.next() );
1485         }
1486       }
1487
1488       Iterator itrAllHRNodes = id2hrn.entrySet().iterator();
1489       while( itrAllHRNodes.hasNext() ) {
1490         Map.Entry me       = (Map.Entry)itrAllHRNodes.next();
1491         HeapRegionNode hrnToAge = (HeapRegionNode) me.getValue();
1492
1493         unshadowTokens(as, hrnToAge);
1494
1495         Iterator<ReferenceEdge> itrEdges = hrnToAge.iteratorToReferencees();
1496         while( itrEdges.hasNext() ) {
1497           unshadowTokens(as, itrEdges.next() );
1498         }
1499       }
1500     }
1501   }
1502
1503
1504   protected boolean hasMatchingField(HeapRegionNode src, ReferenceEdge edge) {
1505
1506     // if no allocation site, then it's a match-everything region
1507     AllocationSite asSrc = src.getAllocationSite();
1508     if( asSrc == null ) {
1509       return true;
1510     }
1511
1512     TypeDescriptor tdSrc = asSrc.getType();
1513     assert tdSrc != null;
1514
1515     // if it's not a class, it doesn't have any fields to match
1516     if( !tdSrc.isClass() ) {
1517       return false;
1518     }
1519
1520     Iterator fieldsSrcItr = tdSrc.getClassDesc().getFields();
1521     while( fieldsSrcItr.hasNext() ) {
1522       FieldDescriptor fd = (FieldDescriptor) fieldsSrcItr.next();
1523       if( fd == edge.getFieldDesc() ) {
1524         return true;
1525       }
1526     }
1527
1528     // otherwise it is a class with fields
1529     // but we didn't find a match
1530     return false;
1531   }
1532
1533
1534   protected boolean hasMatchingType(ReferenceEdge edge, HeapRegionNode dst) {
1535
1536     // if the region has no type, matches everything
1537     AllocationSite asDst = dst.getAllocationSite();
1538     if( asDst == null ) {
1539       return true;
1540     }
1541
1542     TypeDescriptor tdDst = asDst.getType();
1543     assert tdDst != null;
1544
1545     // if the type is not a class don't match because
1546     // primitives are copied, no memory aliases
1547     ClassDescriptor cdDst = tdDst.getClassDesc();
1548     if( cdDst == null ) {
1549       return false;
1550     }
1551
1552     // if the field is null, it matches everything
1553     FieldDescriptor fd = edge.getFieldDesc();
1554     if( fd == null ) {
1555       return true;
1556     }
1557     TypeDescriptor tdFd = fd.getType();
1558     assert tdFd != null;
1559
1560     return typeUtil.isSuperorType(tdFd, tdDst);
1561   }
1562
1563
1564
1565   protected void unshadowTokens(AllocationSite as, ReferenceEdge edge) {
1566     edge.setBeta(edge.getBeta().unshadowTokens(as) );
1567   }
1568
1569   protected void unshadowTokens(AllocationSite as, HeapRegionNode hrn) {
1570     hrn.setAlpha(hrn.getAlpha().unshadowTokens(as) );
1571   }
1572
1573
1574   private ReachabilitySet toShadowTokens(OwnershipGraph ogCallee,
1575                                          ReachabilitySet rsIn) {
1576
1577     ReachabilitySet rsOut = new ReachabilitySet(rsIn);
1578
1579     Iterator<AllocationSite> allocItr = ogCallee.allocationSites.iterator();
1580     while( allocItr.hasNext() ) {
1581       AllocationSite as = allocItr.next();
1582
1583       rsOut = rsOut.toShadowTokens(as);
1584     }
1585
1586     return rsOut.makeCanonical();
1587   }
1588
1589
1590   private void rewriteCallerReachability(Integer paramIndex,
1591                                          HeapRegionNode hrn,
1592                                          ReferenceEdge edge,
1593                                          ReachabilitySet rules,
1594                                          Hashtable<Integer, ReachabilitySet> paramIndex2rewrite_d,
1595                                          Hashtable<Integer, ReachabilitySet> paramIndex2rewriteD,
1596                                          TokenTuple p_i,
1597                                          Hashtable<TokenTuple, Integer> paramToken2paramIndex,
1598                                          Hashtable<TokenTuple, Integer> paramTokenStar2paramIndex,
1599                                          boolean makeChangeSet,
1600                                          Hashtable<ReferenceEdge, ChangeTupleSet> edgePlannedChanges) {
1601     assert (hrn == null && edge != null) || 
1602            (hrn != null && edge == null);
1603
1604     assert rules != null;
1605     assert p_i != null;
1606
1607     ReachabilitySet callerReachabilityCurrent;
1608     if( hrn == null ) {
1609       callerReachabilityCurrent = edge.getBeta();
1610     } else {
1611       callerReachabilityCurrent = hrn.getAlpha();
1612     }
1613
1614     ReachabilitySet callerReachabilityNew = new ReachabilitySet().makeCanonical();
1615
1616     // for initializing structures in this method
1617     TokenTupleSet ttsEmpty = new TokenTupleSet().makeCanonical();
1618
1619     // use this to construct a change set if required; the idea is to
1620     // map every partially rewritten token tuple set to the set of 
1621     // caller-context token tuple sets that were used to generate it
1622     Hashtable<TokenTupleSet, HashSet<TokenTupleSet> > rewritten2source =
1623       new Hashtable<TokenTupleSet, HashSet<TokenTupleSet> >();
1624     rewritten2source.put(ttsEmpty, new HashSet<TokenTupleSet>() );
1625
1626
1627     Iterator<TokenTupleSet> rulesItr = rules.iterator();
1628     while(rulesItr.hasNext()) {
1629       TokenTupleSet rule = rulesItr.next();
1630
1631       ReachabilitySet rewrittenRule = new ReachabilitySet(ttsEmpty).makeCanonical();
1632
1633       Iterator<TokenTuple> ruleItr = rule.iterator();
1634       while(ruleItr.hasNext()) {
1635         TokenTuple ttCallee = ruleItr.next();
1636
1637         // compute the possibilities for rewriting this callee token
1638         ReachabilitySet ttCalleeRewrites = null;
1639         boolean callerSourceUsed = false;
1640
1641         if( ttCallee.equals( p_i ) ) {
1642           // replace the arity-one token of the current parameter with the reachability
1643           // information from the caller edge
1644           ttCalleeRewrites = callerReachabilityCurrent;
1645           callerSourceUsed = true;
1646           
1647         } else if( paramToken2paramIndex.containsKey( ttCallee ) ) {
1648           // use little d
1649           Integer paramIndex_j = paramToken2paramIndex.get( ttCallee );
1650           assert paramIndex_j != null;
1651           ttCalleeRewrites = paramIndex2rewrite_d.get( paramIndex_j );
1652           assert ttCalleeRewrites != null;
1653
1654         } else if( paramTokenStar2paramIndex.containsKey( ttCallee ) ) {
1655           // worse, use big D
1656           Integer paramIndex_j = paramTokenStar2paramIndex.get( ttCallee );
1657           assert paramIndex_j != null;
1658           ttCalleeRewrites = paramIndex2rewriteD.get( paramIndex_j );
1659           assert ttCalleeRewrites != null;
1660
1661         } else {
1662           // otherwise there's no need for a rewrite, just pass this one on
1663           TokenTupleSet ttsCaller = new TokenTupleSet(ttCallee).makeCanonical();
1664           ttCalleeRewrites = new ReachabilitySet(ttsCaller).makeCanonical();
1665         }
1666        
1667         // branch every version of the working rewritten rule with 
1668         // the possibilities for rewriting the current callee token
1669         ReachabilitySet rewrittenRuleWithTTCallee = new ReachabilitySet().makeCanonical();
1670
1671         Iterator<TokenTupleSet> rewrittenRuleItr = rewrittenRule.iterator();
1672         while( rewrittenRuleItr.hasNext() ) {
1673           TokenTupleSet ttsRewritten = rewrittenRuleItr.next();
1674
1675           Iterator<TokenTupleSet> ttCalleeRewritesItr = ttCalleeRewrites.iterator();
1676           while( ttCalleeRewritesItr.hasNext() ) {
1677             TokenTupleSet ttsBranch = ttCalleeRewritesItr.next();
1678
1679             TokenTupleSet ttsRewrittenNext = ttsRewritten.unionUpArity( ttsBranch );
1680
1681             if( makeChangeSet ) {
1682               // in order to keep the list of source token tuple sets
1683               // start with the sets used to make the partially rewritten
1684               // rule up to this point
1685               HashSet<TokenTupleSet> sourceSets = rewritten2source.get( ttsRewritten );
1686               assert sourceSets != null;
1687
1688               // make a shallow copy for possible modification
1689               sourceSets = (HashSet<TokenTupleSet>) sourceSets.clone();
1690
1691               // if we used something from the caller to rewrite it, remember
1692               if( callerSourceUsed ) {
1693                 sourceSets.add( ttsBranch );
1694               }
1695
1696               // set mapping for the further rewritten rule
1697               rewritten2source.put( ttsRewrittenNext, sourceSets );
1698             }
1699           
1700             rewrittenRuleWithTTCallee = 
1701               rewrittenRuleWithTTCallee.union( ttsRewrittenNext );
1702           }
1703         }
1704
1705         // now the rewritten rule's possibilities have been extended by
1706         // rewriting the current callee token, remember result
1707         rewrittenRule = rewrittenRuleWithTTCallee;
1708       }
1709
1710       // the rule has been entirely rewritten into the caller context
1711       // now, so add it to the new reachability information
1712       callerReachabilityNew =
1713         callerReachabilityNew.union( rewrittenRule );
1714     }
1715
1716     if( makeChangeSet ) {
1717       ChangeTupleSet callerChangeSet = new ChangeTupleSet().makeCanonical();
1718       
1719       // each possibility for the final reachability should have a set of
1720       // caller sources mapped to it, use to create the change set
1721       Iterator<TokenTupleSet> callerReachabilityItr = callerReachabilityNew.iterator();
1722       while( callerReachabilityItr.hasNext() ) {
1723         TokenTupleSet ttsRewrittenFinal = callerReachabilityItr.next();
1724         HashSet<TokenTupleSet> sourceSets = rewritten2source.get( ttsRewrittenFinal );
1725         assert sourceSets != null;
1726
1727         Iterator<TokenTupleSet> sourceSetsItr = sourceSets.iterator();
1728         while( sourceSetsItr.hasNext() ) {
1729           TokenTupleSet ttsSource = sourceSetsItr.next();      
1730
1731           callerChangeSet =
1732             callerChangeSet.union( new ChangeTuple( ttsSource, ttsRewrittenFinal ) );
1733         }
1734       }
1735
1736       assert edgePlannedChanges != null;
1737       edgePlannedChanges.put(edge, callerChangeSet);
1738     }
1739
1740     if( hrn == null ) {
1741       edge.setBetaNew(edge.getBetaNew().union(callerReachabilityNew) );
1742     } else {
1743       hrn.setAlphaNew(hrn.getAlphaNew().union(callerReachabilityNew) );
1744     }
1745   }
1746
1747
1748
1749   private HashSet<HeapRegionNode>
1750   getHRNSetThatPossiblyMapToCalleeHRN(OwnershipGraph ogCallee,
1751                                       HeapRegionNode hrnCallee,
1752                                       Hashtable<Integer, HashSet<HeapRegionNode> > paramIndex2reachableCallerNodes
1753                                       ) {
1754
1755     HashSet<HeapRegionNode> possibleCallerHRNs = new HashSet<HeapRegionNode>();
1756
1757     Integer paramIndexCallee = ogCallee.id2paramIndex.get(hrnCallee.getID() );
1758
1759     if( paramIndexCallee == null ) {
1760       // this is a node allocated in the callee then and it has
1761       // exactly one shadow node in the caller to map to
1762       AllocationSite as = hrnCallee.getAllocationSite();
1763       assert as != null;
1764
1765       int age = as.getAgeCategory(hrnCallee.getID() );
1766       assert age != AllocationSite.AGE_notInThisSite;
1767
1768       Integer idCaller;
1769       if( age == AllocationSite.AGE_summary ) {
1770         idCaller = as.getSummaryShadow();
1771       } else if( age == AllocationSite.AGE_oldest ) {
1772         idCaller = as.getOldestShadow();
1773       } else {
1774         assert age == AllocationSite.AGE_in_I;
1775
1776         Integer I = as.getAge(hrnCallee.getID() );
1777         assert I != null;
1778
1779         idCaller = as.getIthOldestShadow(I);
1780       }
1781
1782       assert id2hrn.containsKey(idCaller);
1783       HeapRegionNode hrnCaller = id2hrn.get(idCaller);
1784       possibleCallerHRNs.add(hrnCaller);
1785
1786     } else {
1787       // this is a node that was created to represent a parameter
1788       // so it maps to a whole mess of heap regions
1789       assert paramIndex2reachableCallerNodes.containsKey(paramIndexCallee);
1790       possibleCallerHRNs = paramIndex2reachableCallerNodes.get(paramIndexCallee);
1791     }
1792
1793     return possibleCallerHRNs;
1794   }
1795
1796
1797
1798   ////////////////////////////////////////////////////
1799   // in merge() and equals() methods the suffix A
1800   // represents the passed in graph and the suffix
1801   // B refers to the graph in this object
1802   // Merging means to take the incoming graph A and
1803   // merge it into B, so after the operation graph B
1804   // is the final result.
1805   ////////////////////////////////////////////////////
1806   public void merge(OwnershipGraph og) {
1807
1808     if( og == null ) {
1809       return;
1810     }
1811
1812     mergeOwnershipNodes(og);
1813     mergeReferenceEdges(og);
1814     mergeId2paramIndex(og);
1815     mergeAllocationSites(og);
1816   }
1817
1818
1819   protected void mergeOwnershipNodes(OwnershipGraph og) {
1820     Set sA = og.id2hrn.entrySet();
1821     Iterator iA = sA.iterator();
1822     while( iA.hasNext() ) {
1823       Map.Entry meA  = (Map.Entry)iA.next();
1824       Integer idA  = (Integer)        meA.getKey();
1825       HeapRegionNode hrnA = (HeapRegionNode) meA.getValue();
1826
1827       // if this graph doesn't have a node the
1828       // incoming graph has, allocate it
1829       if( !id2hrn.containsKey(idA) ) {
1830         HeapRegionNode hrnB = hrnA.copy();
1831         id2hrn.put(idA, hrnB);
1832
1833       } else {
1834         // otherwise this is a node present in both graphs
1835         // so make the new reachability set a union of the
1836         // nodes' reachability sets
1837         HeapRegionNode hrnB = id2hrn.get(idA);
1838         hrnB.setAlpha(hrnB.getAlpha().union(hrnA.getAlpha() ) );
1839       }
1840     }
1841
1842     // now add any label nodes that are in graph B but
1843     // not in A
1844     sA = og.td2ln.entrySet();
1845     iA = sA.iterator();
1846     while( iA.hasNext() ) {
1847       Map.Entry meA = (Map.Entry)iA.next();
1848       TempDescriptor tdA = (TempDescriptor) meA.getKey();
1849       LabelNode lnA = (LabelNode)      meA.getValue();
1850
1851       // if the label doesn't exist in B, allocate and add it
1852       LabelNode lnB = getLabelNodeFromTemp(tdA);
1853     }
1854   }
1855
1856   protected void mergeReferenceEdges(OwnershipGraph og) {
1857
1858     // heap regions
1859     Set sA = og.id2hrn.entrySet();
1860     Iterator iA = sA.iterator();
1861     while( iA.hasNext() ) {
1862       Map.Entry meA  = (Map.Entry)iA.next();
1863       Integer idA  = (Integer)        meA.getKey();
1864       HeapRegionNode hrnA = (HeapRegionNode) meA.getValue();
1865
1866       Iterator<ReferenceEdge> heapRegionsItrA = hrnA.iteratorToReferencees();
1867       while( heapRegionsItrA.hasNext() ) {
1868         ReferenceEdge edgeA     = heapRegionsItrA.next();
1869         HeapRegionNode hrnChildA = edgeA.getDst();
1870         Integer idChildA  = hrnChildA.getID();
1871
1872         // at this point we know an edge in graph A exists
1873         // idA -> idChildA, does this exist in B?
1874         assert id2hrn.containsKey(idA);
1875         HeapRegionNode hrnB        = id2hrn.get(idA);
1876         ReferenceEdge edgeToMerge = null;
1877
1878         Iterator<ReferenceEdge> heapRegionsItrB = hrnB.iteratorToReferencees();
1879         while( heapRegionsItrB.hasNext() &&
1880                edgeToMerge == null          ) {
1881
1882           ReferenceEdge edgeB     = heapRegionsItrB.next();
1883           HeapRegionNode hrnChildB = edgeB.getDst();
1884           Integer idChildB  = hrnChildB.getID();
1885
1886           // don't use the ReferenceEdge.equals() here because
1887           // we're talking about existence between graphs
1888           if( idChildB.equals(idChildA) &&
1889               edgeB.getFieldDesc() == edgeA.getFieldDesc() ) {
1890             edgeToMerge = edgeB;
1891           }
1892         }
1893
1894         // if the edge from A was not found in B,
1895         // add it to B.
1896         if( edgeToMerge == null ) {
1897           assert id2hrn.containsKey(idChildA);
1898           HeapRegionNode hrnChildB = id2hrn.get(idChildA);
1899           edgeToMerge = edgeA.copy();
1900           edgeToMerge.setSrc(hrnB);
1901           edgeToMerge.setDst(hrnChildB);
1902           addReferenceEdge(hrnB, hrnChildB, edgeToMerge);
1903         }
1904         // otherwise, the edge already existed in both graphs
1905         // so merge their reachability sets
1906         else {
1907           // just replace this beta set with the union
1908           assert edgeToMerge != null;
1909           edgeToMerge.setBeta(
1910             edgeToMerge.getBeta().union(edgeA.getBeta() )
1911             );
1912           if( !edgeA.isInitialParamReflexive() ) {
1913             edgeToMerge.setIsInitialParamReflexive(false);
1914           }
1915         }
1916       }
1917     }
1918
1919     // and then again with label nodes
1920     sA = og.td2ln.entrySet();
1921     iA = sA.iterator();
1922     while( iA.hasNext() ) {
1923       Map.Entry meA = (Map.Entry)iA.next();
1924       TempDescriptor tdA = (TempDescriptor) meA.getKey();
1925       LabelNode lnA = (LabelNode)      meA.getValue();
1926
1927       Iterator<ReferenceEdge> heapRegionsItrA = lnA.iteratorToReferencees();
1928       while( heapRegionsItrA.hasNext() ) {
1929         ReferenceEdge edgeA     = heapRegionsItrA.next();
1930         HeapRegionNode hrnChildA = edgeA.getDst();
1931         Integer idChildA  = hrnChildA.getID();
1932
1933         // at this point we know an edge in graph A exists
1934         // tdA -> idChildA, does this exist in B?
1935         assert td2ln.containsKey(tdA);
1936         LabelNode lnB         = td2ln.get(tdA);
1937         ReferenceEdge edgeToMerge = null;
1938
1939         // labels never have edges with a field
1940         //assert edgeA.getFieldDesc() == null;
1941
1942         Iterator<ReferenceEdge> heapRegionsItrB = lnB.iteratorToReferencees();
1943         while( heapRegionsItrB.hasNext() &&
1944                edgeToMerge == null          ) {
1945
1946           ReferenceEdge edgeB     = heapRegionsItrB.next();
1947           HeapRegionNode hrnChildB = edgeB.getDst();
1948           Integer idChildB  = hrnChildB.getID();
1949
1950           // labels never have edges with a field
1951           //assert edgeB.getFieldDesc() == null;
1952
1953           // don't use the ReferenceEdge.equals() here because
1954           // we're talking about existence between graphs
1955           if( idChildB.equals(idChildA) &&
1956               edgeB.getFieldDesc() == edgeA.getFieldDesc() ) {
1957             edgeToMerge = edgeB;
1958           }
1959         }
1960
1961         // if the edge from A was not found in B,
1962         // add it to B.
1963         if( edgeToMerge == null ) {
1964           assert id2hrn.containsKey(idChildA);
1965           HeapRegionNode hrnChildB = id2hrn.get(idChildA);
1966           edgeToMerge = edgeA.copy();
1967           edgeToMerge.setSrc(lnB);
1968           edgeToMerge.setDst(hrnChildB);
1969           addReferenceEdge(lnB, hrnChildB, edgeToMerge);
1970         }
1971         // otherwise, the edge already existed in both graphs
1972         // so merge their reachability sets
1973         else {
1974           // just replace this beta set with the union
1975           edgeToMerge.setBeta(
1976             edgeToMerge.getBeta().union(edgeA.getBeta() )
1977             );
1978           if( !edgeA.isInitialParamReflexive() ) {
1979             edgeToMerge.setIsInitialParamReflexive(false);
1980           }
1981         }
1982       }
1983     }
1984   }
1985
1986   // you should only merge ownership graphs that have the
1987   // same number of parameters, or if one or both parameter
1988   // index tables are empty
1989   protected void mergeId2paramIndex(OwnershipGraph og) {
1990     if( id2paramIndex.size() == 0 ) {
1991       id2paramIndex  = og.id2paramIndex;
1992       paramIndex2id  = og.paramIndex2id;
1993       paramIndex2tdQ = og.paramIndex2tdQ;
1994       return;
1995     }
1996
1997     if( og.id2paramIndex.size() == 0 ) {
1998       return;
1999     }
2000
2001     assert id2paramIndex.size() == og.id2paramIndex.size();
2002   }
2003
2004   protected void mergeAllocationSites(OwnershipGraph og) {
2005     allocationSites.addAll(og.allocationSites);
2006   }
2007
2008
2009
2010   // it is necessary in the equals() member functions
2011   // to "check both ways" when comparing the data
2012   // structures of two graphs.  For instance, if all
2013   // edges between heap region nodes in graph A are
2014   // present and equal in graph B it is not sufficient
2015   // to say the graphs are equal.  Consider that there
2016   // may be edges in graph B that are not in graph A.
2017   // the only way to know that all edges in both graphs
2018   // are equally present is to iterate over both data
2019   // structures and compare against the other graph.
2020   public boolean equals(OwnershipGraph og) {
2021
2022     if( og == null ) {
2023       return false;
2024     }
2025
2026     if( !areHeapRegionNodesEqual(og) ) {
2027       return false;
2028     }
2029
2030     if( !areLabelNodesEqual(og) ) {
2031       return false;
2032     }
2033
2034     if( !areReferenceEdgesEqual(og) ) {
2035       return false;
2036     }
2037
2038     if( !areId2paramIndexEqual(og) ) {
2039       return false;
2040     }
2041
2042     // if everything is equal up to this point,
2043     // assert that allocationSites is also equal--
2044     // this data is redundant and kept for efficiency
2045     assert allocationSites.equals(og.allocationSites);
2046
2047     return true;
2048   }
2049
2050   protected boolean areHeapRegionNodesEqual(OwnershipGraph og) {
2051
2052     if( !areallHRNinAalsoinBandequal(this, og) ) {
2053       return false;
2054     }
2055
2056     if( !areallHRNinAalsoinBandequal(og, this) ) {
2057       return false;
2058     }
2059
2060     return true;
2061   }
2062
2063   static protected boolean areallHRNinAalsoinBandequal(OwnershipGraph ogA,
2064                                                        OwnershipGraph ogB) {
2065     Set sA = ogA.id2hrn.entrySet();
2066     Iterator iA = sA.iterator();
2067     while( iA.hasNext() ) {
2068       Map.Entry meA  = (Map.Entry)iA.next();
2069       Integer idA  = (Integer)        meA.getKey();
2070       HeapRegionNode hrnA = (HeapRegionNode) meA.getValue();
2071
2072       if( !ogB.id2hrn.containsKey(idA) ) {
2073         return false;
2074       }
2075
2076       HeapRegionNode hrnB = ogB.id2hrn.get(idA);
2077       if( !hrnA.equalsIncludingAlpha(hrnB) ) {
2078         return false;
2079       }
2080     }
2081
2082     return true;
2083   }
2084
2085
2086   protected boolean areLabelNodesEqual(OwnershipGraph og) {
2087
2088     if( !areallLNinAalsoinBandequal(this, og) ) {
2089       return false;
2090     }
2091
2092     if( !areallLNinAalsoinBandequal(og, this) ) {
2093       return false;
2094     }
2095
2096     return true;
2097   }
2098
2099   static protected boolean areallLNinAalsoinBandequal(OwnershipGraph ogA,
2100                                                       OwnershipGraph ogB) {
2101     Set sA = ogA.td2ln.entrySet();
2102     Iterator iA = sA.iterator();
2103     while( iA.hasNext() ) {
2104       Map.Entry meA = (Map.Entry)iA.next();
2105       TempDescriptor tdA = (TempDescriptor) meA.getKey();
2106
2107       if( !ogB.td2ln.containsKey(tdA) ) {
2108         return false;
2109       }
2110     }
2111
2112     return true;
2113   }
2114
2115
2116   protected boolean areReferenceEdgesEqual(OwnershipGraph og) {
2117     if( !areallREinAandBequal(this, og) ) {
2118       return false;
2119     }
2120
2121     return true;
2122   }
2123
2124   static protected boolean areallREinAandBequal(OwnershipGraph ogA,
2125                                                 OwnershipGraph ogB) {
2126
2127     // check all the heap region->heap region edges
2128     Set sA = ogA.id2hrn.entrySet();
2129     Iterator iA = sA.iterator();
2130     while( iA.hasNext() ) {
2131       Map.Entry meA  = (Map.Entry)iA.next();
2132       Integer idA  = (Integer)        meA.getKey();
2133       HeapRegionNode hrnA = (HeapRegionNode) meA.getValue();
2134
2135       // we should have already checked that the same
2136       // heap regions exist in both graphs
2137       assert ogB.id2hrn.containsKey(idA);
2138
2139       if( !areallREfromAequaltoB(ogA, hrnA, ogB) ) {
2140         return false;
2141       }
2142
2143       // then check every edge in B for presence in A, starting
2144       // from the same parent HeapRegionNode
2145       HeapRegionNode hrnB = ogB.id2hrn.get(idA);
2146
2147       if( !areallREfromAequaltoB(ogB, hrnB, ogA) ) {
2148         return false;
2149       }
2150     }
2151
2152     // then check all the label->heap region edges
2153     sA = ogA.td2ln.entrySet();
2154     iA = sA.iterator();
2155     while( iA.hasNext() ) {
2156       Map.Entry meA = (Map.Entry)iA.next();
2157       TempDescriptor tdA = (TempDescriptor) meA.getKey();
2158       LabelNode lnA = (LabelNode)      meA.getValue();
2159
2160       // we should have already checked that the same
2161       // label nodes exist in both graphs
2162       assert ogB.td2ln.containsKey(tdA);
2163
2164       if( !areallREfromAequaltoB(ogA, lnA, ogB) ) {
2165         return false;
2166       }
2167
2168       // then check every edge in B for presence in A, starting
2169       // from the same parent LabelNode
2170       LabelNode lnB = ogB.td2ln.get(tdA);
2171
2172       if( !areallREfromAequaltoB(ogB, lnB, ogA) ) {
2173         return false;
2174       }
2175     }
2176
2177     return true;
2178   }
2179
2180
2181   static protected boolean areallREfromAequaltoB(OwnershipGraph ogA,
2182                                                  OwnershipNode onA,
2183                                                  OwnershipGraph ogB) {
2184
2185     Iterator<ReferenceEdge> itrA = onA.iteratorToReferencees();
2186     while( itrA.hasNext() ) {
2187       ReferenceEdge edgeA     = itrA.next();
2188       HeapRegionNode hrnChildA = edgeA.getDst();
2189       Integer idChildA  = hrnChildA.getID();
2190
2191       assert ogB.id2hrn.containsKey(idChildA);
2192
2193       // at this point we know an edge in graph A exists
2194       // onA -> idChildA, does this exact edge exist in B?
2195       boolean edgeFound = false;
2196
2197       OwnershipNode onB = null;
2198       if( onA instanceof HeapRegionNode ) {
2199         HeapRegionNode hrnA = (HeapRegionNode) onA;
2200         onB = ogB.id2hrn.get(hrnA.getID() );
2201       } else {
2202         LabelNode lnA = (LabelNode) onA;
2203         onB = ogB.td2ln.get(lnA.getTempDescriptor() );
2204       }
2205
2206       Iterator<ReferenceEdge> itrB = onB.iteratorToReferencees();
2207       while( itrB.hasNext() ) {
2208         ReferenceEdge edgeB     = itrB.next();
2209         HeapRegionNode hrnChildB = edgeB.getDst();
2210         Integer idChildB  = hrnChildB.getID();
2211
2212         if( idChildA.equals(idChildB) &&
2213             edgeA.getFieldDesc() == edgeB.getFieldDesc() ) {
2214
2215           // there is an edge in the right place with the right field,
2216           // but do they have the same attributes?
2217           if( edgeA.getBeta().equals(edgeB.getBeta() ) ) {
2218
2219             edgeFound = true;
2220             //} else {
2221             //return false;
2222           }
2223         }
2224       }
2225
2226       if( !edgeFound ) {
2227         return false;
2228       }
2229     }
2230
2231     return true;
2232   }
2233
2234
2235   protected boolean areId2paramIndexEqual(OwnershipGraph og) {
2236     return id2paramIndex.size() == og.id2paramIndex.size();
2237   }
2238
2239
2240   public boolean hasPotentialAlias(Integer paramIndex1, Integer paramIndex2) {
2241
2242     // get parameter's heap region
2243     assert paramIndex2id.containsKey(paramIndex1);
2244     Integer idParam1 = paramIndex2id.get(paramIndex1);
2245
2246     assert id2hrn.containsKey(idParam1);
2247     HeapRegionNode hrnParam1 = id2hrn.get(idParam1);
2248     assert hrnParam1 != null;
2249
2250     // get tokens for this parameter
2251     TokenTuple p1 = new TokenTuple(hrnParam1.getID(),
2252                                    true,
2253                                    TokenTuple.ARITY_ONE).makeCanonical();
2254
2255     TokenTuple pStar1 = new TokenTuple(hrnParam1.getID(),
2256                                        true,
2257                                        TokenTuple.ARITY_MANY).makeCanonical();
2258
2259
2260     // get tokens for the other parameter
2261     assert paramIndex2id.containsKey(paramIndex2);
2262     Integer idParam2 = paramIndex2id.get(paramIndex2);
2263
2264     assert id2hrn.containsKey(idParam2);
2265     HeapRegionNode hrnParam2 = id2hrn.get(idParam2);
2266     assert hrnParam2 != null;
2267
2268     TokenTuple p2 = new TokenTuple(hrnParam2.getID(),
2269                                    true,
2270                                    TokenTuple.ARITY_ONE).makeCanonical();
2271
2272     TokenTuple pStar2 = new TokenTuple(hrnParam2.getID(),
2273                                        true,
2274                                        TokenTuple.ARITY_MANY).makeCanonical();
2275
2276
2277     // get special label p_q for first parameter
2278     TempDescriptor tdParamQ1 = paramIndex2tdQ.get(paramIndex1);
2279     assert tdParamQ1 != null;
2280     LabelNode lnParamQ1 = td2ln.get(tdParamQ1);
2281     assert lnParamQ1 != null;
2282
2283     // then get the edge from label q to parameter's hrn
2284     ReferenceEdge edgeSpecialQ1 = lnParamQ1.getReferenceTo(hrnParam1, null);
2285     assert edgeSpecialQ1 != null;
2286
2287     // if the beta of this edge has tokens from both parameters in one
2288     // token tuple set, then there is a potential alias between them
2289     ReachabilitySet beta1 = edgeSpecialQ1.getBeta();
2290     assert beta1 != null;
2291
2292     if( beta1.containsTupleSetWithBoth(p1,     p2) ) {
2293       return true;
2294     }
2295     if( beta1.containsTupleSetWithBoth(pStar1, p2) ) {
2296       return true;
2297     }
2298     if( beta1.containsTupleSetWithBoth(p1,     pStar2) ) {
2299       return true;
2300     }
2301     if( beta1.containsTupleSetWithBoth(pStar1, pStar2) ) {
2302       return true;
2303     }
2304
2305     return false;
2306   }
2307
2308
2309   public boolean hasPotentialAlias(Integer paramIndex, AllocationSite as) {
2310
2311     // get parameter's heap region
2312     assert paramIndex2id.containsKey(paramIndex);
2313     Integer idParam = paramIndex2id.get(paramIndex);
2314
2315     assert id2hrn.containsKey(idParam);
2316     HeapRegionNode hrnParam = id2hrn.get(idParam);
2317     assert hrnParam != null;
2318
2319     // get tokens for this parameter
2320     TokenTuple p = new TokenTuple(hrnParam.getID(),
2321                                   true,
2322                                   TokenTuple.ARITY_ONE).makeCanonical();
2323
2324     TokenTuple pStar = new TokenTuple(hrnParam.getID(),
2325                                       true,
2326                                       TokenTuple.ARITY_MANY).makeCanonical();
2327
2328     // get special label p_q
2329     TempDescriptor tdParamQ = paramIndex2tdQ.get(paramIndex);
2330     assert tdParamQ != null;
2331     LabelNode lnParamQ = td2ln.get(tdParamQ);
2332     assert lnParamQ != null;
2333
2334     // then get the edge from label q to parameter's hrn
2335     ReferenceEdge edgeSpecialQ = lnParamQ.getReferenceTo(hrnParam, null);
2336     assert edgeSpecialQ != null;
2337
2338     // look through this beta set for potential aliases
2339     ReachabilitySet beta = edgeSpecialQ.getBeta();
2340     assert beta != null;
2341
2342
2343     // get tokens for summary node
2344     TokenTuple gs = new TokenTuple(as.getSummary(),
2345                                    true,
2346                                    TokenTuple.ARITY_ONE).makeCanonical();
2347
2348     TokenTuple gsStar = new TokenTuple(as.getSummary(),
2349                                        true,
2350                                        TokenTuple.ARITY_MANY).makeCanonical();
2351
2352     if( beta.containsTupleSetWithBoth(p,     gs) ) {
2353       return true;
2354     }
2355     if( beta.containsTupleSetWithBoth(pStar, gs) ) {
2356       return true;
2357     }
2358     if( beta.containsTupleSetWithBoth(p,     gsStar) ) {
2359       return true;
2360     }
2361     if( beta.containsTupleSetWithBoth(pStar, gsStar) ) {
2362       return true;
2363     }
2364
2365     // check for other nodes
2366     for( int i = 0; i < as.getAllocationDepth(); ++i ) {
2367
2368       // the other nodes of an allocation site are single, no stars
2369       TokenTuple gi = new TokenTuple(as.getIthOldest(i),
2370                                      false,
2371                                      TokenTuple.ARITY_ONE).makeCanonical();
2372
2373       if( beta.containsTupleSetWithBoth(p,     gi) ) {
2374         return true;
2375       }
2376       if( beta.containsTupleSetWithBoth(pStar, gi) ) {
2377         return true;
2378       }
2379     }
2380
2381     return false;
2382   }
2383
2384
2385   public boolean hasPotentialAlias(AllocationSite as1, AllocationSite as2) {
2386
2387     // get tokens for summary nodes
2388     TokenTuple gs1 = new TokenTuple(as1.getSummary(),
2389                                     true,
2390                                     TokenTuple.ARITY_ONE).makeCanonical();
2391
2392     TokenTuple gsStar1 = new TokenTuple(as1.getSummary(),
2393                                         true,
2394                                         TokenTuple.ARITY_MANY).makeCanonical();
2395
2396     // get summary node's alpha
2397     Integer idSum1 = as1.getSummary();
2398     assert id2hrn.containsKey(idSum1);
2399     HeapRegionNode hrnSum1 = id2hrn.get(idSum1);
2400     assert hrnSum1 != null;
2401     ReachabilitySet alphaSum1 = hrnSum1.getAlpha();
2402     assert alphaSum1 != null;
2403
2404
2405     // and for the other one
2406     TokenTuple gs2 = new TokenTuple(as2.getSummary(),
2407                                     true,
2408                                     TokenTuple.ARITY_ONE).makeCanonical();
2409
2410     TokenTuple gsStar2 = new TokenTuple(as2.getSummary(),
2411                                         true,
2412                                         TokenTuple.ARITY_MANY).makeCanonical();
2413
2414     // get summary node's alpha
2415     Integer idSum2 = as2.getSummary();
2416     assert id2hrn.containsKey(idSum2);
2417     HeapRegionNode hrnSum2 = id2hrn.get(idSum2);
2418     assert hrnSum2 != null;
2419     ReachabilitySet alphaSum2 = hrnSum2.getAlpha();
2420     assert alphaSum2 != null;
2421
2422     // does either one report reachability from the other tokens?
2423     if( alphaSum1.containsTuple(gsStar2) ) {
2424       return true;
2425     }
2426     if( alphaSum2.containsTuple(gsStar1) ) {
2427       return true;
2428     }
2429
2430     // only check non-star token if they are different sites
2431     if( as1 != as2 ) {
2432       if( alphaSum1.containsTuple(gs2) ) {
2433         return true;
2434       }
2435       if( alphaSum2.containsTuple(gs1) ) {
2436         return true;
2437       }
2438     }
2439
2440
2441     // check sum2 against alloc1 nodes
2442     for( int i = 0; i < as1.getAllocationDepth(); ++i ) {
2443       Integer idI1 = as1.getIthOldest(i);
2444       assert id2hrn.containsKey(idI1);
2445       HeapRegionNode hrnI1 = id2hrn.get(idI1);
2446       assert hrnI1 != null;
2447       ReachabilitySet alphaI1 = hrnI1.getAlpha();
2448       assert alphaI1 != null;
2449
2450       // the other nodes of an allocation site are single, no stars
2451       TokenTuple gi1 = new TokenTuple(as1.getIthOldest(i),
2452                                       false,
2453                                       TokenTuple.ARITY_ONE).makeCanonical();
2454
2455       if( alphaSum2.containsTuple(gi1) ) {
2456         return true;
2457       }
2458       if( alphaI1.containsTuple(gs2) ) {
2459         return true;
2460       }
2461       if( alphaI1.containsTuple(gsStar2) ) {
2462         return true;
2463       }
2464     }
2465
2466     // check sum1 against alloc2 nodes
2467     for( int i = 0; i < as2.getAllocationDepth(); ++i ) {
2468       Integer idI2 = as2.getIthOldest(i);
2469       assert id2hrn.containsKey(idI2);
2470       HeapRegionNode hrnI2 = id2hrn.get(idI2);
2471       assert hrnI2 != null;
2472       ReachabilitySet alphaI2 = hrnI2.getAlpha();
2473       assert alphaI2 != null;
2474
2475       TokenTuple gi2 = new TokenTuple(as2.getIthOldest(i),
2476                                       false,
2477                                       TokenTuple.ARITY_ONE).makeCanonical();
2478
2479       if( alphaSum1.containsTuple(gi2) ) {
2480         return true;
2481       }
2482       if( alphaI2.containsTuple(gs1) ) {
2483         return true;
2484       }
2485       if( alphaI2.containsTuple(gsStar1) ) {
2486         return true;
2487       }
2488
2489       // while we're at it, do an inner loop for alloc2 vs alloc1 nodes
2490       for( int j = 0; j < as1.getAllocationDepth(); ++j ) {
2491         Integer idI1 = as1.getIthOldest(j);
2492
2493         // if these are the same site, don't look for the same token, no alias
2494         // different tokens of the same site could alias together though
2495         if( idI1 == idI2 ) {
2496           continue;
2497         }
2498
2499         HeapRegionNode hrnI1 = id2hrn.get(idI1);
2500         ReachabilitySet alphaI1 = hrnI1.getAlpha();
2501         TokenTuple gi1 = new TokenTuple(as1.getIthOldest(j),
2502                                         false,
2503                                         TokenTuple.ARITY_ONE).makeCanonical();
2504         if( alphaI2.containsTuple(gi1) ) {
2505           return true;
2506         }
2507         if( alphaI1.containsTuple(gi2) ) {
2508           return true;
2509         }
2510       }
2511     }
2512
2513     return false;
2514   }
2515
2516
2517   // for writing ownership graphs to dot files
2518   public void writeGraph(Descriptor methodDesc,
2519                          FlatNode fn,
2520                          boolean writeLabels,
2521                          boolean labelSelect,
2522                          boolean pruneGarbage,
2523                          boolean writeReferencers,
2524                          boolean writeParamMappings
2525                          ) throws java.io.IOException {
2526     writeGraph(
2527       methodDesc.getSymbol() +
2528       methodDesc.getNum() +
2529       fn.toString(),
2530       writeLabels,
2531       labelSelect,
2532       pruneGarbage,
2533       writeReferencers,
2534       writeParamMappings
2535       );
2536   }
2537
2538   public void writeGraph(Descriptor methodDesc,
2539                          boolean writeLabels,
2540                          boolean labelSelect,
2541                          boolean pruneGarbage,
2542                          boolean writeReferencers,
2543                          boolean writeParamMappings
2544                          ) throws java.io.IOException {
2545
2546     writeGraph(methodDesc+"COMPLETE",
2547                writeLabels,
2548                labelSelect,
2549                pruneGarbage,
2550                writeReferencers,
2551                writeParamMappings
2552                );
2553   }
2554
2555   public void writeGraph(Descriptor methodDesc,
2556                          Integer numUpdate,
2557                          boolean writeLabels,
2558                          boolean labelSelect,
2559                          boolean pruneGarbage,
2560                          boolean writeReferencers,
2561                          boolean writeParamMappings
2562                          ) throws java.io.IOException {
2563
2564     writeGraph(methodDesc+"COMPLETE"+String.format("%05d", numUpdate),
2565                writeLabels,
2566                labelSelect,
2567                pruneGarbage,
2568                writeReferencers,
2569                writeParamMappings
2570                );
2571   }
2572
2573   public void writeGraph(String graphName,
2574                          boolean writeLabels,
2575                          boolean labelSelect,
2576                          boolean pruneGarbage,
2577                          boolean writeReferencers,
2578                          boolean writeParamMappings
2579                          ) throws java.io.IOException {
2580
2581     // remove all non-word characters from the graph name so
2582     // the filename and identifier in dot don't cause errors
2583     graphName = graphName.replaceAll("[\\W]", "");
2584
2585     BufferedWriter bw = new BufferedWriter(new FileWriter(graphName+".dot") );
2586     bw.write("digraph "+graphName+" {\n");
2587
2588     HashSet<HeapRegionNode> visited = new HashSet<HeapRegionNode>();
2589
2590     // then visit every heap region node
2591     Set s = id2hrn.entrySet();
2592     Iterator i = s.iterator();
2593     while( i.hasNext() ) {
2594       Map.Entry me  = (Map.Entry)i.next();
2595       HeapRegionNode hrn = (HeapRegionNode) me.getValue();
2596       if( !pruneGarbage ||
2597           hrn.isFlagged() ||
2598           hrn.getDescription().startsWith( "param" )
2599         ) {
2600         
2601         if( !visited.contains(hrn) ) {
2602           traverseHeapRegionNodes(VISIT_HRN_WRITE_FULL,
2603                                   hrn,
2604                                   bw,
2605                                   null,
2606                                   visited,
2607                                   writeReferencers);
2608         }
2609       }
2610     }
2611     
2612     bw.write("  graphTitle[label=\""+graphName+"\",shape=box];\n");
2613
2614     if( writeParamMappings ) {
2615       Set df = paramIndex2id.entrySet();
2616       Iterator ih = df.iterator();
2617       while( ih.hasNext() ) {
2618         Map.Entry meh = (Map.Entry)ih.next();
2619         Integer pi = (Integer) meh.getKey();
2620         Integer id = (Integer) meh.getValue();
2621         bw.write("  pindex"+pi+"[label=\""+pi+" to "+id+"\",shape=box];\n");
2622       }
2623     }
2624
2625     // then visit every label node, useful for debugging
2626     if( writeLabels ) {
2627       s = td2ln.entrySet();
2628       i = s.iterator();
2629       while( i.hasNext() ) {
2630         Map.Entry me = (Map.Entry)i.next();
2631         LabelNode ln = (LabelNode) me.getValue();
2632
2633         if( labelSelect ) {
2634           String labelStr = ln.getTempDescriptorString();
2635           if( labelStr.startsWith("___temp") ||
2636               labelStr.startsWith("___dst") ||
2637               labelStr.startsWith("___srctmp") ||
2638               labelStr.startsWith("___neverused")   ) {
2639             continue;
2640           }
2641         }
2642
2643         //bw.write("  "+ln.toString() + ";\n");
2644
2645         Iterator<ReferenceEdge> heapRegionsItr = ln.iteratorToReferencees();
2646         while( heapRegionsItr.hasNext() ) {
2647           ReferenceEdge edge = heapRegionsItr.next();
2648           HeapRegionNode hrn  = edge.getDst();
2649
2650           if( pruneGarbage && !visited.contains(hrn) ) {
2651             traverseHeapRegionNodes(VISIT_HRN_WRITE_FULL,
2652                                     hrn,
2653                                     bw,
2654                                     null,
2655                                     visited,
2656                                     writeReferencers);
2657           }
2658
2659           bw.write("  "        + ln.toString() +
2660                    " -> "      + hrn.toString() +
2661                    "[label=\"" + edge.toGraphEdgeString() +
2662                    "\",decorate];\n");
2663         }
2664       }
2665     }
2666
2667
2668     bw.write("}\n");
2669     bw.close();
2670   }
2671
2672   protected void traverseHeapRegionNodes(int mode,
2673                                          HeapRegionNode hrn,
2674                                          BufferedWriter bw,
2675                                          TempDescriptor td,
2676                                          HashSet<HeapRegionNode> visited,
2677                                          boolean writeReferencers
2678                                          ) throws java.io.IOException {
2679
2680     if( visited.contains(hrn) ) {
2681       return;
2682     }
2683     visited.add(hrn);
2684
2685     switch( mode ) {
2686     case VISIT_HRN_WRITE_FULL:
2687
2688       String attributes = "[";
2689
2690       if( hrn.isSingleObject() ) {
2691         attributes += "shape=box";
2692       } else {
2693         attributes += "shape=Msquare";
2694       }
2695
2696       if( hrn.isFlagged() ) {
2697         attributes += ",style=filled,fillcolor=lightgrey";
2698       }
2699
2700       attributes += ",label=\"ID"        +
2701                     hrn.getID()          +
2702                     "\\n"                +
2703                     hrn.getDescription() +
2704                     "\\n"                +
2705                     hrn.getAlphaString() +
2706                     "\"]";
2707
2708       bw.write("  " + hrn.toString() + attributes + ";\n");
2709       break;
2710     }
2711
2712
2713     // useful for debugging
2714     if( writeReferencers ) {
2715       OwnershipNode onRef  = null;
2716       Iterator refItr = hrn.iteratorToReferencers();
2717       while( refItr.hasNext() ) {
2718         onRef = (OwnershipNode) refItr.next();
2719
2720         switch( mode ) {
2721         case VISIT_HRN_WRITE_FULL:
2722           bw.write("  "                    + hrn.toString() +
2723                    " -> "                  + onRef.toString() +
2724                    "[color=lightgray];\n");
2725           break;
2726         }
2727       }
2728     }
2729
2730     Iterator<ReferenceEdge> childRegionsItr = hrn.iteratorToReferencees();
2731     while( childRegionsItr.hasNext() ) {
2732       ReferenceEdge edge     = childRegionsItr.next();
2733       HeapRegionNode hrnChild = edge.getDst();
2734
2735       switch( mode ) {
2736       case VISIT_HRN_WRITE_FULL:
2737         bw.write("  "        + hrn.toString() +
2738                  " -> "      + hrnChild.toString() +
2739                  "[label=\"" + edge.toGraphEdgeString() +
2740                  "\",decorate];\n");
2741         break;
2742       }
2743
2744       traverseHeapRegionNodes(mode,
2745                               hrnChild,
2746                               bw,
2747                               td,
2748                               visited,
2749                               writeReferencers);
2750     }
2751   }
2752 }