Changed allocation depth to default to minimum possible so graphs are
[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
12     // there was already one other very similar reason
13     // for traversing heap nodes that is no longer needed
14     // instead of writing a new heap region visitor, use
15     // the existing method with a new mode to describe what
16     // actions to take during the traversal
17     protected static final int VISIT_HRN_WRITE_FULL = 0;
18
19
20     public Hashtable<Integer,        HeapRegionNode> id2hrn;
21     public Hashtable<TempDescriptor, LabelNode     > td2ln;
22     public Hashtable<Integer,        Integer       > id2paramIndex;
23     public Hashtable<Integer,        Integer       > paramIndex2id;
24
25     public HashSet<AllocationSite> allocationSites;
26
27
28     public OwnershipGraph( int allocationDepth ) {
29         this.allocationDepth = allocationDepth;
30         
31         id2hrn        = new Hashtable<Integer,        HeapRegionNode>();
32         td2ln         = new Hashtable<TempDescriptor, LabelNode     >();
33         id2paramIndex = new Hashtable<Integer,        Integer       >();
34         paramIndex2id = new Hashtable<Integer,        Integer       >();
35
36         allocationSites = new HashSet <AllocationSite>();
37     }
38
39
40     // label nodes are much easier to deal with than
41     // heap region nodes.  Whenever there is a request
42     // for the label node that is associated with a
43     // temp descriptor we can either find it or make a
44     // new one and return it.  This is because temp
45     // descriptors are globally unique and every label
46     // node is mapped to exactly one temp descriptor.
47     protected LabelNode getLabelNodeFromTemp( TempDescriptor td ) {
48         assert td != null;
49         
50         if( !td2ln.containsKey( td ) ) {
51             td2ln.put( td, new LabelNode( td ) );
52         }
53
54         return td2ln.get( td );
55     }
56
57
58     // the reason for this method is to have the option
59     // creating new heap regions with specific IDs, or
60     // duplicating heap regions with specific IDs (especially
61     // in the merge() operation) or to create new heap
62     // regions with a new unique ID.
63     protected HeapRegionNode 
64         createNewHeapRegionNode( Integer         id,
65                                  boolean         isSingleObject,
66                                  boolean         isFlagged,
67                                  boolean         isNewSummary,
68                                  boolean         isParameter,
69                                  AllocationSite  allocSite,
70                                  ReachabilitySet alpha,
71                                  String          description ) {
72
73         if( id == null ) {
74             id = OwnershipAnalysis.generateUniqueHeapRegionNodeID();
75         }
76
77         if( alpha == null ) {
78             if( isFlagged || isParameter ) {
79                 alpha = new ReachabilitySet( new TokenTuple( id, 
80                                                              !isSingleObject,
81                                                              TokenTuple.ARITY_ONE )
82                                            ).makeCanonical();
83             } else {
84                 alpha = new ReachabilitySet( new TokenTupleSet() 
85                                            ).makeCanonical();
86             }
87         }
88
89         HeapRegionNode hrn = new HeapRegionNode( id,
90                                                  isSingleObject,
91                                                  isFlagged,
92                                                  isNewSummary,
93                                                  allocSite,
94                                                  alpha,
95                                                  description );
96         id2hrn.put( id, hrn );
97         return hrn;
98     }
99
100     
101
102     ////////////////////////////////////////////////
103     //
104     //  Low-level referencee and referencer methods
105     // 
106     //  These methods provide the lowest level for
107     //  creating references between ownership nodes
108     //  and handling the details of maintaining both
109     //  list of referencers and referencees.
110     // 
111     ////////////////////////////////////////////////
112     protected void addReferenceEdge( OwnershipNode  referencer,
113                                      HeapRegionNode referencee,
114                                      ReferenceEdge  edge ) {
115         assert referencer != null;
116         assert referencee != null;
117         assert edge       != null;
118         assert edge.getSrc() == referencer;
119         assert edge.getDst() == referencee;
120
121         referencer.addReferencee( edge );
122         referencee.addReferencer( edge );
123     }
124
125     protected void removeReferenceEdge( OwnershipNode   referencer,
126                                         HeapRegionNode  referencee,
127                                         FieldDescriptor fieldDesc ) {
128         assert referencer != null;
129         assert referencee != null;
130
131         ReferenceEdge edge = referencer.getReferenceTo( referencee,
132                                                         fieldDesc );
133         assert edge != null;
134         assert edge == referencee.getReferenceFrom( referencer,
135                                                     fieldDesc );
136         
137         referencer.removeReferencee( edge );
138         referencee.removeReferencer( edge );
139     }
140
141     protected void clearReferenceEdgesFrom( OwnershipNode   referencer,
142                                             FieldDescriptor fieldDesc,
143                                             boolean         removeAll ) {
144         assert referencer != null;
145
146         // get a copy of the set to iterate over, otherwise
147         // we will be trying to take apart the set as we
148         // are iterating over it, which won't work
149         Iterator<ReferenceEdge> i = referencer.iteratorToReferenceesClone();
150         while( i.hasNext() ) {
151             ReferenceEdge edge = i.next();
152
153             if( removeAll || edge.getFieldDesc() == fieldDesc ) {
154                 HeapRegionNode referencee = edge.getDst();
155
156                 removeReferenceEdge( referencer,
157                                      referencee,
158                                      edge.getFieldDesc() );
159             }
160         }    
161     }
162
163     protected void clearReferenceEdgesTo( HeapRegionNode  referencee,
164                                           FieldDescriptor fieldDesc,
165                                           boolean         removeAll ) {
166         assert referencee != null;
167
168         // get a copy of the set to iterate over, otherwise
169         // we will be trying to take apart the set as we
170         // are iterating over it, which won't work
171         Iterator<ReferenceEdge> i = referencee.iteratorToReferencersClone();
172         while( i.hasNext() ) {
173             ReferenceEdge edge = i.next();
174
175             if( removeAll || edge.getFieldDesc() == fieldDesc ) {
176                 OwnershipNode referencer = edge.getSrc();
177                 removeReferenceEdge( referencer,
178                                      referencee,
179                                      edge.getFieldDesc() );
180             }    
181         }
182     }
183     
184
185     protected void propagateTokensOverNodes( HeapRegionNode          nPrime,
186                                              ChangeTupleSet          c0,
187                                              HashSet<HeapRegionNode> nodesWithNewAlpha,
188                                              HashSet<ReferenceEdge>  edgesWithNewBeta ) {       
189
190         HashSet<HeapRegionNode> todoNodes
191             = new HashSet<HeapRegionNode>();
192         todoNodes.add( nPrime );
193
194         HashSet<ReferenceEdge> todoEdges 
195             = new HashSet<ReferenceEdge>();
196         
197         Hashtable<HeapRegionNode, ChangeTupleSet> nodePlannedChanges 
198             = new Hashtable<HeapRegionNode, ChangeTupleSet>();
199         nodePlannedChanges.put( nPrime, c0 );
200
201         Hashtable<ReferenceEdge, ChangeTupleSet> edgePlannedChanges 
202             = new Hashtable<ReferenceEdge, ChangeTupleSet>();
203         
204
205         while( !todoNodes.isEmpty() ) {
206             HeapRegionNode n = todoNodes.iterator().next();        
207             ChangeTupleSet C = nodePlannedChanges.get( n );
208
209             Iterator itrC = C.iterator();
210             while( itrC.hasNext() ) {
211                 ChangeTuple c = (ChangeTuple) itrC.next();
212
213                 if( n.getAlpha().contains( c.getSetToMatch() ) ) {
214                     ReachabilitySet withChange = n.getAlpha().union( c.getSetToAdd() );
215                     n.setAlphaNew( n.getAlphaNew().union( withChange ) );
216                     nodesWithNewAlpha.add( n );
217                 }
218             }
219
220             Iterator<ReferenceEdge> referItr = n.iteratorToReferencers();
221             while( referItr.hasNext() ) {
222                 ReferenceEdge edge = referItr.next();
223                 todoEdges.add( edge );
224
225                 if( !edgePlannedChanges.containsKey( edge ) ) {
226                     edgePlannedChanges.put( edge, new ChangeTupleSet().makeCanonical() );
227                 }
228
229                 edgePlannedChanges.put( edge, edgePlannedChanges.get( edge ).union( C ) );
230             }
231
232             Iterator<ReferenceEdge> refeeItr = n.iteratorToReferencees();
233             while( refeeItr.hasNext() ) {
234                 ReferenceEdge  edgeF = refeeItr.next();
235                 HeapRegionNode m     = edgeF.getDst();
236
237                 ChangeTupleSet changesToPass = new ChangeTupleSet().makeCanonical();
238
239                 Iterator<ChangeTuple> itrCprime = C.iterator();
240                 while( itrCprime.hasNext() ) {
241                     ChangeTuple c = itrCprime.next();
242                     if( edgeF.getBeta().contains( c.getSetToMatch() ) ) {
243                         changesToPass = changesToPass.union( c );
244                     }
245                 }
246
247                 if( !changesToPass.isEmpty() ) {
248                     if( !nodePlannedChanges.containsKey( m ) ) {
249                         nodePlannedChanges.put( m, new ChangeTupleSet().makeCanonical() );
250                     }
251
252                     ChangeTupleSet currentChanges = nodePlannedChanges.get( m );
253
254                     if( !changesToPass.isSubset( currentChanges ) ) {
255
256                         nodePlannedChanges.put( m, currentChanges.union( changesToPass ) );
257                         todoNodes.add( m );
258                     }
259                 }
260             }
261
262             todoNodes.remove( n );
263         }
264
265         propagateTokensOverEdges( todoEdges, edgePlannedChanges, nodesWithNewAlpha, edgesWithNewBeta );
266     }
267
268
269     protected void propagateTokensOverEdges( 
270          HashSet<ReferenceEdge>                   todoEdges,
271          Hashtable<ReferenceEdge, ChangeTupleSet> edgePlannedChanges,
272          HashSet<HeapRegionNode>                  nodesWithNewAlpha,
273          HashSet<ReferenceEdge>                   edgesWithNewBeta ) {
274        
275
276         while( !todoEdges.isEmpty() ) {
277             ReferenceEdge edgeE = todoEdges.iterator().next();
278             todoEdges.remove( edgeE );
279
280             if( !edgePlannedChanges.containsKey( edgeE ) ) {
281                 edgePlannedChanges.put( edgeE, new ChangeTupleSet().makeCanonical() );
282             }
283             
284             ChangeTupleSet C = edgePlannedChanges.get( edgeE );
285
286             ChangeTupleSet changesToPass = new ChangeTupleSet().makeCanonical();
287
288             Iterator<ChangeTuple> itrC = C.iterator();
289             while( itrC.hasNext() ) {
290                 ChangeTuple c = itrC.next();
291                 if( edgeE.getBeta().contains( c.getSetToMatch() ) ) {
292                     ReachabilitySet withChange = edgeE.getBeta().union( c.getSetToAdd() );
293                     edgeE.setBetaNew( edgeE.getBetaNew().union( withChange ) );
294                     edgesWithNewBeta.add( edgeE );
295                     changesToPass = changesToPass.union( c );
296                 }
297             }
298
299             OwnershipNode onSrc = edgeE.getSrc();
300
301             if( !changesToPass.isEmpty() && onSrc instanceof HeapRegionNode ) {         
302                 HeapRegionNode n = (HeapRegionNode) onSrc;
303
304                 Iterator<ReferenceEdge> referItr = n.iteratorToReferencers();
305                 while( referItr.hasNext() ) {
306                     ReferenceEdge edgeF = referItr.next();
307                     
308                     if( !edgePlannedChanges.containsKey( edgeF ) ) {
309                         edgePlannedChanges.put( edgeF, new ChangeTupleSet().makeCanonical() );
310                     }
311                   
312                     ChangeTupleSet currentChanges = edgePlannedChanges.get( edgeF );
313                 
314                     if( !changesToPass.isSubset( currentChanges ) ) {
315                         todoEdges.add( edgeF );
316                         edgePlannedChanges.put( edgeF, currentChanges.union( changesToPass ) );
317                     }
318                 }
319             }       
320         }       
321     }
322
323
324     ////////////////////////////////////////////////////
325     //
326     //  Assignment Operation Methods
327     //
328     //  These methods are high-level operations for
329     //  modeling program assignment statements using 
330     //  the low-level reference create/remove methods
331     //  above.
332     //
333     //  The destination in an assignment statement is
334     //  going to have new references.  The method of
335     //  determining the references depends on the type
336     //  of the FlatNode assignment and the predicates
337     //  of the nodes and edges involved.
338     //
339     ////////////////////////////////////////////////////
340     public void assignTempYToTempX( TempDescriptor y, 
341                                     TempDescriptor x ) {
342
343         LabelNode lnX = getLabelNodeFromTemp( x );
344         LabelNode lnY = getLabelNodeFromTemp( y );
345
346         clearReferenceEdgesFrom( lnX, null, true );
347
348         Iterator<ReferenceEdge> itrYhrn = lnY.iteratorToReferencees();
349         while( itrYhrn.hasNext() ) {
350             ReferenceEdge  edgeY       = itrYhrn.next();
351             HeapRegionNode referencee = edgeY.getDst();
352             ReferenceEdge  edgeNew    = edgeY.copy();
353             edgeNew.setSrc( lnX );
354
355             addReferenceEdge( lnX, referencee, edgeNew );
356         }
357     }
358
359
360     public void assignTempYFieldFToTempX( TempDescriptor  y,
361                                           FieldDescriptor f,
362                                           TempDescriptor  x ) {
363
364         LabelNode lnX = getLabelNodeFromTemp( x );
365         LabelNode lnY = getLabelNodeFromTemp( y );
366
367         clearReferenceEdgesFrom( lnX, null, true );
368
369         Iterator<ReferenceEdge> itrYhrn = lnY.iteratorToReferencees();
370         while( itrYhrn.hasNext() ) {
371             ReferenceEdge   edgeY = itrYhrn.next();
372             HeapRegionNode  hrnY  = edgeY.getDst();
373             ReachabilitySet betaY = edgeY.getBeta();
374
375             Iterator<ReferenceEdge> itrHrnFhrn = hrnY.iteratorToReferencees();
376             while( itrHrnFhrn.hasNext() ) {
377                 ReferenceEdge   edgeHrn = itrHrnFhrn.next();
378                 HeapRegionNode  hrnHrn  = edgeHrn.getDst();
379                 ReachabilitySet betaHrn = edgeHrn.getBeta();
380
381                 if( edgeHrn.getFieldDesc() == null ||
382                     edgeHrn.getFieldDesc() == f ) {
383
384                     ReferenceEdge edgeNew = new ReferenceEdge( lnX,
385                                                                hrnHrn,
386                                                                f,
387                                                                false,
388                                                                betaY.intersection( betaHrn ) );
389                                     
390                     addReferenceEdge( lnX, hrnHrn, edgeNew );
391                 }
392             }
393         }
394     }
395
396
397     public void assignTempYToTempXFieldF( TempDescriptor  y,
398                                           TempDescriptor  x,
399                                           FieldDescriptor f ) {
400
401         LabelNode lnX = getLabelNodeFromTemp( x );
402         LabelNode lnY = getLabelNodeFromTemp( y );
403
404         HashSet<HeapRegionNode> nodesWithNewAlpha = new HashSet<HeapRegionNode>();
405         HashSet<ReferenceEdge>  edgesWithNewBeta  = new HashSet<ReferenceEdge>();
406
407         Iterator<ReferenceEdge> itrXhrn = lnX.iteratorToReferencees();
408         while( itrXhrn.hasNext() ) {
409             ReferenceEdge   edgeX = itrXhrn.next();
410             HeapRegionNode  hrnX  = edgeX.getDst();
411             ReachabilitySet betaX = edgeX.getBeta();
412
413             ReachabilitySet R = hrnX.getAlpha().intersection( edgeX.getBeta() );
414
415             Iterator<ReferenceEdge> itrYhrn = lnY.iteratorToReferencees();
416             while( itrYhrn.hasNext() ) {
417                 ReferenceEdge   edgeY = itrYhrn.next();
418                 HeapRegionNode  hrnY  = edgeY.getDst();         
419                 ReachabilitySet O     = edgeY.getBeta();
420
421
422                 // propagate tokens over nodes starting from hrnSrc, and it will
423                 // take care of propagating back up edges from any touched nodes
424                 ChangeTupleSet Cy = O.unionUpArityToChangeSet( R );
425                 propagateTokensOverNodes( hrnY, Cy, nodesWithNewAlpha, edgesWithNewBeta );
426
427
428                 // then propagate back just up the edges from hrn
429                 ChangeTupleSet Cx = R.unionUpArityToChangeSet( O );
430
431                 HashSet<ReferenceEdge> todoEdges = new HashSet<ReferenceEdge>();
432
433                 Hashtable<ReferenceEdge, ChangeTupleSet> edgePlannedChanges =
434                     new Hashtable<ReferenceEdge, ChangeTupleSet>();
435
436                 Iterator<ReferenceEdge> referItr = hrnX.iteratorToReferencers();
437                 while( referItr.hasNext() ) {
438                     ReferenceEdge edgeUpstream = referItr.next();
439                     todoEdges.add( edgeUpstream );
440                     edgePlannedChanges.put( edgeUpstream, Cx );
441                 }
442
443                 propagateTokensOverEdges( todoEdges, 
444                                           edgePlannedChanges,
445                                           nodesWithNewAlpha,
446                                           edgesWithNewBeta );
447
448
449
450                 //System.out.println( edgeY.getBetaNew() + "\nbeing pruned by\n" + hrnX.getAlpha() );
451
452                 // create the actual reference edge hrnX.f -> hrnY
453                 ReferenceEdge edgeNew = new ReferenceEdge( hrnX,
454                                                            hrnY,
455                                                            f,
456                                                            false,
457                                                            edgeY.getBetaNew().pruneBy( hrnX.getAlpha() )
458                                                            //edgeY.getBeta().pruneBy( hrnX.getAlpha() )
459                                                          );
460                 addReferenceEdge( hrnX, hrnY, edgeNew );
461
462                 /*
463                 if( f != null ) {
464                     // we can do a strong update here if one of two cases holds
465                     // SAVE FOR LATER, WITHOUT STILL CORRECT
466                     if( (hrnX.getNumReferencers() == 1)                           ||
467                         ( lnX.getNumReferencees() == 1 && hrnX.isSingleObject() )
468                       ) {
469                         clearReferenceEdgesFrom( hrnX, f, false );
470                     }   
471
472                     addReferenceEdge( hrnX, hrnY, edgeNew );
473
474                 } else {
475                     // if the field is null, or "any" field, then
476                     // look to see if an any field already exists
477                     // and merge with it, otherwise just add the edge
478                     ReferenceEdge edgeExisting = hrnX.getReferenceTo( hrnY, f );
479
480                     if( edgeExisting != null ) {
481                         edgeExisting.setBetaNew( 
482                           edgeExisting.getBetaNew().union( edgeNew.getBeta() ) 
483                                                );
484                         // a new edge here cannot be reflexive, so existing will
485                         // always be also not reflexive anymore
486                         edgeExisting.setIsInitialParamReflexive( false );
487                         
488                     } else {
489                         addReferenceEdge( hrnX, hrnY, edgeNew );
490                     }
491                 }
492                 */
493             }
494         }       
495
496         Iterator<HeapRegionNode> nodeItr = nodesWithNewAlpha.iterator();
497         while( nodeItr.hasNext() ) {
498             nodeItr.next().applyAlphaNew();
499         }
500
501         Iterator<ReferenceEdge> edgeItr = edgesWithNewBeta.iterator();
502         while( edgeItr.hasNext() ) {
503             edgeItr.next().applyBetaNew();
504         }
505     }
506
507
508     public void assignParameterAllocationToTemp( boolean        isTask,
509                                                  TempDescriptor td,
510                                                  Integer        paramIndex ) {
511         assert td != null;
512
513         LabelNode      lnParam = getLabelNodeFromTemp( td );
514         HeapRegionNode hrn     = createNewHeapRegionNode( null, 
515                                                           false,
516                                                           isTask,
517                                                           false,
518                                                           true,
519                                                           null,
520                                                           null,
521                                                           "param" + paramIndex );
522
523         // keep track of heap regions that were created for
524         // parameter labels, the index of the parameter they
525         // are for is important when resolving method calls
526         Integer newID = hrn.getID();
527         assert !id2paramIndex.containsKey  ( newID );
528         assert !id2paramIndex.containsValue( paramIndex );
529         id2paramIndex.put( newID, paramIndex );
530         paramIndex2id.put( paramIndex, newID );
531
532         ReachabilitySet beta = new ReachabilitySet( new TokenTuple( newID, 
533                                                                     true,
534                                                                     TokenTuple.ARITY_ONE ) );
535
536         // heap regions for parameters are always multiple object (see above)
537         // and have a reference to themselves, because we can't know the
538         // structure of memory that is passed into the method.  We're assuming
539         // the worst here.
540
541         ReferenceEdge edgeFromLabel = 
542             new ReferenceEdge( lnParam, hrn, null, false, beta );
543
544         ReferenceEdge edgeReflexive = 
545             new ReferenceEdge( hrn,     hrn, null, true,  beta );
546
547         addReferenceEdge( lnParam, hrn, edgeFromLabel );
548         addReferenceEdge( hrn,     hrn, edgeReflexive );
549     }
550
551     
552     public void assignNewAllocationToTempX( TempDescriptor x,
553                                             AllocationSite as ) {
554         assert x  != null;
555         assert as != null;
556
557         age( as );
558
559         // after the age operation the newest (or zero-ith oldest)
560         // node associated with the allocation site should have
561         // no references to it as if it were a newly allocated
562         // heap region, so make a reference to it to complete
563         // this operation
564
565         Integer        idNewest  = as.getIthOldest( 0 );
566         HeapRegionNode hrnNewest = id2hrn.get( idNewest );
567         assert hrnNewest != null;
568
569         LabelNode lnX = getLabelNodeFromTemp( x );      
570         clearReferenceEdgesFrom( lnX, null, true );
571
572         ReferenceEdge edgeNew = 
573             new ReferenceEdge( lnX, hrnNewest, null, false, hrnNewest.getAlpha() );     
574         
575         addReferenceEdge( lnX, hrnNewest, edgeNew );
576     }
577
578
579     // use the allocation site (unique to entire analysis) to
580     // locate the heap region nodes in this ownership graph
581     // that should be aged.  The process models the allocation
582     // of new objects and collects all the oldest allocations
583     // in a summary node to allow for a finite analysis
584     //
585     // There is an additional property of this method.  After
586     // running it on a particular ownership graph (many graphs
587     // may have heap regions related to the same allocation site)
588     // the heap region node objects in this ownership graph will be
589     // allocated.  Therefore, after aging a graph for an allocation
590     // site, attempts to retrieve the heap region nodes using the
591     // integer id's contained in the allocation site should always
592     // return non-null heap regions.
593     public void age( AllocationSite as ) {
594
595         // aging adds this allocation site to the graph's
596         // list of sites that exist in the graph, or does
597         // nothing if the site is already in the list
598         allocationSites.add( as );
599
600         // get the summary node for the allocation site in the context
601         // of this particular ownership graph
602         HeapRegionNode hrnSummary = getSummaryNode( as );
603
604         // merge oldest node into summary
605         Integer        idK  = as.getOldest();
606         HeapRegionNode hrnK = id2hrn.get( idK );
607         mergeIntoSummary( hrnK, hrnSummary );
608         
609         // move down the line of heap region nodes
610         // clobbering the ith and transferring all references
611         // to and from i-1 to node i.  Note that this clobbers
612         // the oldest node (hrnK) that was just merged into
613         // the summary
614         for( int i = allocationDepth - 1; i > 0; --i ) {            
615
616             // move references from the i-1 oldest to the ith oldest
617             Integer        idIth     = as.getIthOldest( i );
618             HeapRegionNode hrnI      = id2hrn.get( idIth );
619             Integer        idImin1th = as.getIthOldest( i - 1 );
620             HeapRegionNode hrnImin1  = id2hrn.get( idImin1th );
621
622             transferOnto( hrnImin1, hrnI );
623         }
624
625         // as stated above, the newest node should have had its
626         // references moved over to the second oldest, so we wipe newest
627         // in preparation for being the new object to assign something to
628         Integer        id0th = as.getIthOldest( 0 );
629         HeapRegionNode hrn0  = id2hrn.get( id0th );
630         assert hrn0 != null;
631
632         // clear all references in and out of newest node
633         clearReferenceEdgesFrom( hrn0, null, true );
634         clearReferenceEdgesTo  ( hrn0, null, true );
635         
636         
637         // now tokens in reachability sets need to "age" also
638         Iterator itrAllLabelNodes = td2ln.entrySet().iterator();
639         while( itrAllLabelNodes.hasNext() ) {
640             Map.Entry me = (Map.Entry) itrAllLabelNodes.next();
641             LabelNode ln = (LabelNode) me.getValue();
642
643             Iterator<ReferenceEdge> itrEdges = ln.iteratorToReferencees();
644             while( itrEdges.hasNext() ) {
645                 ageTokens( as, itrEdges.next() );
646             }
647         }
648
649         Iterator itrAllHRNodes = id2hrn.entrySet().iterator();
650         while( itrAllHRNodes.hasNext() ) {
651             Map.Entry      me       = (Map.Entry)      itrAllHRNodes.next();
652             HeapRegionNode hrnToAge = (HeapRegionNode) me.getValue();
653
654             ageTokens( as, hrnToAge );
655
656             Iterator<ReferenceEdge> itrEdges = hrnToAge.iteratorToReferencees();
657             while( itrEdges.hasNext() ) {
658                 ageTokens( as, itrEdges.next() );
659             }
660         }
661
662
663         // after tokens have been aged, reset newest node's reachability
664         if( hrn0.isFlagged() ) {
665             hrn0.setAlpha( new ReachabilitySet( new TokenTupleSet( 
666                                                                   new TokenTuple( hrn0 ) 
667                                                                  ) 
668                                               ).makeCanonical() 
669                          );
670         } else {
671             hrn0.setAlpha( new ReachabilitySet( new TokenTupleSet()                                             
672                                               ).makeCanonical() 
673                          ); 
674         }
675     }
676  
677
678     protected HeapRegionNode getSummaryNode( AllocationSite as ) {
679         
680         Integer        idSummary  = as.getSummary();
681         HeapRegionNode hrnSummary = id2hrn.get( idSummary );
682
683         // If this is null then we haven't touched this allocation site
684         // in the context of the current ownership graph, so allocate
685         // heap region nodes appropriate for the entire allocation site.
686         // This should only happen once per ownership graph per allocation site,
687         // and a particular integer id can be used to locate the heap region
688         // in different ownership graphs that represents the same part of an
689         // allocation site.
690         if( hrnSummary == null ) {
691
692             boolean hasFlags = false;
693             if( as.getType().isClass() ) {
694                 hasFlags = as.getType().getClassDesc().hasFlags();
695             }
696
697             hrnSummary = createNewHeapRegionNode( idSummary,
698                                                   false,
699                                                   hasFlags,
700                                                   true,
701                                                   false,
702                                                   as,
703                                                   null,
704                                                   as + "\\n" + as.getType() + "\\nsummary" );
705
706             for( int i = 0; i < as.getAllocationDepth(); ++i ) {
707                 Integer idIth = as.getIthOldest( i );
708                 assert !id2hrn.containsKey( idIth );
709                 createNewHeapRegionNode( idIth,
710                                          true,
711                                          hasFlags,
712                                          false,
713                                          false,
714                                          as,
715                                          null,
716                                          as + "\\n" + as.getType() + "\\n" + i + " oldest" );
717             }
718         }
719
720         return hrnSummary;
721     }
722
723
724     protected HeapRegionNode getShadowSummaryNode( AllocationSite as ) {
725         
726         Integer        idShadowSummary  = -(as.getSummary());
727         HeapRegionNode hrnShadowSummary = id2hrn.get( idShadowSummary );
728
729         if( hrnShadowSummary == null ) {
730
731             boolean hasFlags = false;
732             if( as.getType().isClass() ) {
733                 hasFlags = as.getType().getClassDesc().hasFlags();
734             }
735
736             hrnShadowSummary = createNewHeapRegionNode( idShadowSummary,
737                                                         false,
738                                                         hasFlags,
739                                                         true,
740                                                         false,
741                                                         as,
742                                                         null,
743                                                         as + "\\n" + as.getType() + "\\nshadowSum" );
744
745             for( int i = 0; i < as.getAllocationDepth(); ++i ) {
746                 Integer idShadowIth = -(as.getIthOldest( i ));
747                 assert !id2hrn.containsKey( idShadowIth );
748                 createNewHeapRegionNode( idShadowIth,
749                                          true,
750                                          hasFlags,
751                                          false,
752                                          false,
753                                          as,
754                                          null,
755                                          as + "\\n" + as.getType() + "\\n" + i + " shadow" );
756             }
757         }
758
759         return hrnShadowSummary;
760     }
761
762
763     protected void mergeIntoSummary( HeapRegionNode hrn, HeapRegionNode hrnSummary ) {
764         assert hrnSummary.isNewSummary();
765
766         // transfer references _from_ hrn over to hrnSummary
767         Iterator<ReferenceEdge> itrReferencee = hrn.iteratorToReferencees();
768         while( itrReferencee.hasNext() ) {
769             ReferenceEdge edge       = itrReferencee.next();
770             ReferenceEdge edgeMerged = edge.copy();
771             edgeMerged.setSrc( hrnSummary );
772
773             HeapRegionNode hrnReferencee = edge.getDst();
774             ReferenceEdge  edgeSummary   = hrnSummary.getReferenceTo( hrnReferencee, edge.getFieldDesc() );
775
776             if( edgeSummary == null ) {     
777                 // the merge is trivial, nothing to be done
778             } else {
779                 // otherwise an edge from the referencer to hrnSummary exists already
780                 // and the edge referencer->hrn should be merged with it
781                 edgeMerged.setBeta( edgeMerged.getBeta().union( edgeSummary.getBeta() ) );
782             }
783
784             addReferenceEdge( hrnSummary, hrnReferencee, edgeMerged );
785         }
786         
787         // next transfer references _to_ hrn over to hrnSummary
788         Iterator<ReferenceEdge> itrReferencer = hrn.iteratorToReferencers();
789         while( itrReferencer.hasNext() ) {
790             ReferenceEdge edge         = itrReferencer.next();
791             ReferenceEdge edgeMerged   = edge.copy();
792             edgeMerged.setDst( hrnSummary );
793
794             OwnershipNode onReferencer = edge.getSrc();
795             ReferenceEdge edgeSummary  = onReferencer.getReferenceTo( hrnSummary, edge.getFieldDesc() );
796                 
797             if( edgeSummary == null ) {     
798                 // the merge is trivial, nothing to be done
799             } else {
800                 // otherwise an edge from the referencer to alpha_S exists already
801                 // and the edge referencer->alpha_K should be merged with it
802                 edgeMerged.setBeta( edgeMerged.getBeta().union( edgeSummary.getBeta() ) );
803             }
804             
805             addReferenceEdge( onReferencer, hrnSummary, edgeMerged );
806         }       
807
808         // then merge hrn reachability into hrnSummary
809         hrnSummary.setAlpha( hrnSummary.getAlpha().union( hrn.getAlpha() ) );
810     }
811
812
813     protected void transferOnto( HeapRegionNode hrnA, HeapRegionNode hrnB ) {
814
815         // clear references in and out of node i
816         clearReferenceEdgesFrom( hrnB, null, true );
817         clearReferenceEdgesTo  ( hrnB, null, true );
818         
819         // copy each edge in and out of A to B
820         Iterator<ReferenceEdge> itrReferencee = hrnA.iteratorToReferencees();
821         while( itrReferencee.hasNext() ) {
822             ReferenceEdge  edge          = itrReferencee.next();
823             HeapRegionNode hrnReferencee = edge.getDst();
824             ReferenceEdge  edgeNew       = edge.copy();
825             edgeNew.setSrc( hrnB );
826
827             addReferenceEdge( hrnB, hrnReferencee, edgeNew );
828         }
829         
830         Iterator<ReferenceEdge> itrReferencer = hrnA.iteratorToReferencers();
831         while( itrReferencer.hasNext() ) {
832             ReferenceEdge edge         = itrReferencer.next();
833             OwnershipNode onReferencer = edge.getSrc();
834             ReferenceEdge edgeNew      = edge.copy();
835             edgeNew.setDst( hrnB );
836                     
837             addReferenceEdge( onReferencer, hrnB, edgeNew );
838         }           
839         
840         // replace hrnB reachability with hrnA's
841         hrnB.setAlpha( hrnA.getAlpha() );
842     }
843
844
845     protected void ageTokens( AllocationSite as, ReferenceEdge edge ) {
846         edge.setBeta( edge.getBeta().ageTokens( as ) );
847     }
848
849     protected void ageTokens( AllocationSite as, HeapRegionNode hrn ) {
850         hrn.setAlpha( hrn.getAlpha().ageTokens( as ) );
851     }
852
853     protected void majorAgeTokens( AllocationSite as, ReferenceEdge edge ) {
854         //edge.setBeta( edge.getBeta().majorAgeTokens( as ) );
855     }
856
857     protected void majorAgeTokens( AllocationSite as, HeapRegionNode hrn ) {
858         //hrn.setAlpha( hrn.getAlpha().majorAgeTokens( as ) );
859     }
860
861     
862     public void resolveMethodCall( FlatCall       fc,
863                                    boolean        isStatic,
864                                    FlatMethod     fm,
865                                    OwnershipGraph ogCallee ) {
866
867         /*
868         // verify the existence of allocation sites and their
869         // shadows from the callee in the context of this caller graph
870         Iterator<AllocationSite> asItr = ogCallee.allocationSites.iterator();
871         while( asItr.hasNext() ) {
872             AllocationSite allocSite        = asItr.next();    
873             HeapRegionNode hrnSummary       = getSummaryNode      ( allocSite );
874             HeapRegionNode hrnShadowSummary = getShadowSummaryNode( allocSite );
875         }      
876
877         // in non-static methods there is a "this" pointer
878         // that should be taken into account
879         if( isStatic ) {
880             assert fc.numArgs()     == fm.numParameters();
881         } else {
882             assert fc.numArgs() + 1 == fm.numParameters();
883         }
884
885         // make a change set to translate callee tokens into caller tokens
886         ChangeTupleSet C = new ChangeTupleSet().makeCanonical();
887
888         for( int i = 0; i < fm.numParameters(); ++i ) {
889             
890             Integer indexParam = new Integer( i );
891
892             System.out.println( "In method "+fm+ " on param "+indexParam );
893
894             assert ogCallee.paramIndex2id.containsKey( indexParam );        
895             Integer idParam = ogCallee.paramIndex2id.get( indexParam );
896
897             assert ogCallee.id2hrn.containsKey( idParam );
898             HeapRegionNode hrnParam = ogCallee.id2hrn.get( idParam );
899             assert hrnParam != null;
900
901             TokenTupleSet calleeTokenToMatch = 
902                 new TokenTupleSet( new TokenTuple( hrnParam ) ).makeCanonical();
903
904             
905             // now depending on whether the callee is static or not
906             // we need to account for a "this" argument in order to
907             // find the matching argument in the caller context
908             TempDescriptor argTemp;
909             if( isStatic ) {
910                 argTemp = fc.getArg( indexParam );
911             } else {
912                 if( indexParam == 0 ) {
913                     argTemp = fc.getThis();
914                 } else {
915                     argTemp = fc.getArg( indexParam - 1 );
916                 }
917             }
918             
919             LabelNode argLabel = getLabelNodeFromTemp( argTemp );
920             Iterator argHeapRegionsItr = argLabel.setIteratorToReferencedRegions();
921             while( argHeapRegionsItr.hasNext() ) {
922                 Map.Entry meArg                = (Map.Entry)               argHeapRegionsItr.next();
923                 HeapRegionNode argHeapRegion   = (HeapRegionNode)          meArg.getKey();
924                 ReferenceEdgeProperties repArg = (ReferenceEdgeProperties) meArg.getValue();
925                 
926                 Iterator<TokenTupleSet> ttsItr = repArg.getBeta().iterator();
927                 while( ttsItr.hasNext() ) {
928                     TokenTupleSet callerTokensToReplace = ttsItr.next();
929
930                     ChangeTuple ct = new ChangeTuple( calleeTokenToMatch,
931                                                       callerTokensToReplace ).makeCanonical();
932
933                     C = C.union( ct );
934                 }
935             }
936         }
937
938         System.out.println( "Applying method call "+fm );
939         System.out.println( "  Change: "+C );
940
941
942         // the heap regions represented by the arguments (caller graph)
943         // and heap regions for the parameters (callee graph)
944         // don't correspond to each other by heap region ID.  In fact,
945         // an argument label node can be referencing several heap regions
946         // so the parameter label always references a multiple-object
947         // heap region in order to handle the range of possible contexts
948         // for a method call.  This means we need to make a special mapping
949         // of argument->parameter regions in order to update the caller graph
950
951         // for every heap region->heap region edge in the
952         // callee graph, create the matching edge or edges
953         // in the caller graph
954         Set      sCallee = ogCallee.id2hrn.entrySet();
955         Iterator iCallee = sCallee.iterator();
956         while( iCallee.hasNext() ) {
957             Map.Entry      meCallee  = (Map.Entry)      iCallee.next();
958             Integer        idCallee  = (Integer)        meCallee.getKey();
959             HeapRegionNode hrnCallee = (HeapRegionNode) meCallee.getValue();
960
961             HeapRegionNode hrnChildCallee = null;
962             Iterator heapRegionsItrCallee = hrnCallee.setIteratorToReferencedRegions();     
963             while( heapRegionsItrCallee.hasNext() ) {
964                 Map.Entry me                 = (Map.Entry)               heapRegionsItrCallee.next();
965                 hrnChildCallee               = (HeapRegionNode)          me.getKey();
966                 ReferenceEdgeProperties repC = (ReferenceEdgeProperties) me.getValue();
967
968                 Integer idChildCallee = hrnChildCallee.getID();
969
970                 // only address this edge if it is not a special reflexive edge
971                 if( !repC.isInitialParamReflexive() ) {
972                 
973                     // now we know that in the callee method's ownership graph
974                     // there is a heap region->heap region reference edge given
975                     // by heap region pointers:
976                     // hrnCallee -> heapChildCallee
977                     //
978                     // or by the ownership-graph independent ID's:
979                     // idCallee -> idChildCallee                
980                     //
981                     // So now make a set of possible source heaps in the caller graph
982                     // and a set of destination heaps in the caller graph, and make
983                     // a reference edge in the caller for every possible (src,dst) pair 
984                     HashSet<HeapRegionNode> possibleCallerSrcs =  
985                         getHRNSetThatPossiblyMapToCalleeHRN( ogCallee,
986                                                              idCallee,
987                                                              fc,
988                                                              isStatic );
989
990                     HashSet<HeapRegionNode> possibleCallerDsts = 
991                         getHRNSetThatPossiblyMapToCalleeHRN( ogCallee,
992                                                              idChildCallee,
993                                                              fc,
994                                                              isStatic );
995
996                     // make every possible pair of {srcSet} -> {dstSet} edges in the caller
997                     Iterator srcItr = possibleCallerSrcs.iterator();
998                     while( srcItr.hasNext() ) {
999                         HeapRegionNode src = (HeapRegionNode) srcItr.next();
1000
1001                         Iterator dstItr = possibleCallerDsts.iterator();
1002                         while( dstItr.hasNext() ) {
1003                             HeapRegionNode dst = (HeapRegionNode) dstItr.next();
1004
1005                             addReferenceEdge( src, dst, repC.copy() );
1006                         }
1007                     }
1008                 }
1009             } 
1010         }
1011         */      
1012     }
1013
1014     /*
1015     private HashSet<HeapRegionNode> getHRNSetThatPossiblyMapToCalleeHRN( OwnershipGraph ogCallee,
1016                                                                          Integer        idCallee,
1017                                                                          FlatCall       fc,
1018                                                                          boolean        isStatic ) {
1019
1020         HashSet<HeapRegionNode> possibleCallerHRNs = new HashSet<HeapRegionNode>();
1021
1022         if( ogCallee.id2paramIndex.containsKey( idCallee ) ) {
1023             // the heap region that is part of this
1024             // reference edge won't have a matching ID in the
1025             // caller graph because it is specifically allocated
1026             // for a particular parameter.  Use that information
1027             // to find the corresponding argument label in the
1028             // caller in order to create the proper reference edge
1029             // or edges.
1030             assert !id2hrn.containsKey( idCallee );
1031             
1032             Integer paramIndex = ogCallee.id2paramIndex.get( idCallee );
1033             TempDescriptor argTemp;
1034             
1035             // now depending on whether the callee is static or not
1036             // we need to account for a "this" argument in order to
1037             // find the matching argument in the caller context
1038             if( isStatic ) {
1039                 argTemp = fc.getArg( paramIndex );
1040             } else {
1041                 if( paramIndex == 0 ) {
1042                     argTemp = fc.getThis();
1043                 } else {
1044                     argTemp = fc.getArg( paramIndex - 1 );
1045                 }
1046             }
1047             
1048             LabelNode argLabel = getLabelNodeFromTemp( argTemp );
1049             Iterator argHeapRegionsItr = argLabel.setIteratorToReferencedRegions();
1050             while( argHeapRegionsItr.hasNext() ) {
1051                 Map.Entry meArg                = (Map.Entry)               argHeapRegionsItr.next();
1052                 HeapRegionNode argHeapRegion   = (HeapRegionNode)          meArg.getKey();
1053                 ReferenceEdgeProperties repArg = (ReferenceEdgeProperties) meArg.getValue();
1054                 
1055                 possibleCallerHRNs.add( (HeapRegionNode) argHeapRegion );
1056             }
1057             
1058         } else {
1059             // this heap region is not a parameter, so it should
1060             // have a matching heap region in the caller graph              
1061             assert id2hrn.containsKey( idCallee );
1062             possibleCallerHRNs.add( id2hrn.get( idCallee ) );
1063         }
1064
1065         return possibleCallerHRNs;
1066     }
1067     */    
1068
1069
1070     ////////////////////////////////////////////////////
1071     // in merge() and equals() methods the suffix A 
1072     // represents the passed in graph and the suffix
1073     // B refers to the graph in this object
1074     // Merging means to take the incoming graph A and
1075     // merge it into B, so after the operation graph B
1076     // is the final result.
1077     ////////////////////////////////////////////////////
1078     public void merge( OwnershipGraph og ) {
1079
1080         if( og == null ) {
1081           return;
1082         }
1083
1084         mergeOwnershipNodes ( og );
1085         mergeReferenceEdges ( og );
1086         mergeId2paramIndex  ( og );     
1087         mergeAllocationSites( og );
1088     }
1089
1090
1091     protected void mergeOwnershipNodes( OwnershipGraph og ) {
1092         Set      sA = og.id2hrn.entrySet();
1093         Iterator iA = sA.iterator();
1094         while( iA.hasNext() ) {
1095             Map.Entry      meA  = (Map.Entry)      iA.next();
1096             Integer        idA  = (Integer)        meA.getKey();
1097             HeapRegionNode hrnA = (HeapRegionNode) meA.getValue();
1098             
1099             // if this graph doesn't have a node the
1100             // incoming graph has, allocate it
1101             if( !id2hrn.containsKey( idA ) ) {
1102                 HeapRegionNode hrnB = hrnA.copy();
1103                 id2hrn.put( idA, hrnB );
1104                 
1105             } else {
1106                 // otherwise this is a node present in both graphs
1107                 // so make the new reachability set a union of the
1108                 // nodes' reachability sets
1109                 HeapRegionNode hrnB = id2hrn.get( idA );
1110                 hrnB.setAlpha( hrnB.getAlpha().union( hrnA.getAlpha() ) );
1111             }
1112         }
1113
1114         // now add any label nodes that are in graph B but
1115         // not in A
1116         sA = og.td2ln.entrySet();
1117         iA = sA.iterator();
1118         while( iA.hasNext() ) {
1119             Map.Entry      meA = (Map.Entry)      iA.next();
1120             TempDescriptor tdA = (TempDescriptor) meA.getKey();
1121             LabelNode      lnA = (LabelNode)      meA.getValue();
1122
1123             // if the label doesn't exist in B, allocate and add it
1124             LabelNode lnB = getLabelNodeFromTemp( tdA );
1125         }
1126     }
1127
1128     protected void mergeReferenceEdges( OwnershipGraph og ) {
1129
1130         // heap regions
1131         Set      sA = og.id2hrn.entrySet();
1132         Iterator iA = sA.iterator();
1133         while( iA.hasNext() ) {
1134             Map.Entry      meA  = (Map.Entry)      iA.next();
1135             Integer        idA  = (Integer)        meA.getKey();
1136             HeapRegionNode hrnA = (HeapRegionNode) meA.getValue();
1137
1138             Iterator<ReferenceEdge> heapRegionsItrA = hrnA.iteratorToReferencees();         
1139             while( heapRegionsItrA.hasNext() ) {
1140                 ReferenceEdge  edgeA     = heapRegionsItrA.next();
1141                 HeapRegionNode hrnChildA = edgeA.getDst();
1142                 Integer        idChildA  = hrnChildA.getID();
1143
1144                 // at this point we know an edge in graph A exists
1145                 // idA -> idChildA, does this exist in B?
1146                 assert id2hrn.containsKey( idA );
1147                 HeapRegionNode hrnB        = id2hrn.get( idA );
1148                 ReferenceEdge  edgeToMerge = null;
1149
1150                 Iterator<ReferenceEdge> heapRegionsItrB = hrnB.iteratorToReferencees();
1151                 while( heapRegionsItrB.hasNext() &&
1152                        edgeToMerge == null          ) {
1153
1154                     ReferenceEdge  edgeB     = heapRegionsItrB.next();
1155                     HeapRegionNode hrnChildB = edgeB.getDst();
1156                     Integer        idChildB  = hrnChildB.getID();
1157
1158                     // don't use the ReferenceEdge.equals() here because
1159                     // we're talking about existence between graphs
1160                     if( idChildB.equals( idChildA ) &&
1161                         edgeB.getFieldDesc() == edgeA.getFieldDesc() ) {
1162                         edgeToMerge = edgeB;
1163                     }
1164                 }
1165
1166                 // if the edge from A was not found in B,
1167                 // add it to B.
1168                 if( edgeToMerge == null ) {
1169                     assert id2hrn.containsKey( idChildA );
1170                     HeapRegionNode hrnChildB = id2hrn.get( idChildA );
1171                     edgeToMerge = edgeA.copy();
1172                     edgeToMerge.setSrc( hrnB );
1173                     edgeToMerge.setDst( hrnChildB );
1174                     addReferenceEdge( hrnB, hrnChildB, edgeToMerge );
1175                 }
1176                 // otherwise, the edge already existed in both graphs
1177                 // so merge their reachability sets
1178                 else {
1179                     // just replace this beta set with the union
1180                     assert edgeToMerge != null;
1181                     edgeToMerge.setBeta( 
1182                       edgeToMerge.getBeta().union( edgeA.getBeta() ) 
1183                                        );
1184                     if( !edgeA.isInitialParamReflexive() ) {
1185                         edgeToMerge.setIsInitialParamReflexive( false );
1186                     }
1187                 }  
1188             } 
1189         }
1190
1191         // and then again with label nodes
1192         sA = og.td2ln.entrySet();
1193         iA = sA.iterator();
1194         while( iA.hasNext() ) {
1195             Map.Entry      meA = (Map.Entry)      iA.next();
1196             TempDescriptor tdA = (TempDescriptor) meA.getKey();
1197             LabelNode      lnA = (LabelNode)      meA.getValue();
1198
1199             Iterator<ReferenceEdge> heapRegionsItrA = lnA.iteratorToReferencees();          
1200             while( heapRegionsItrA.hasNext() ) {
1201                 ReferenceEdge  edgeA     = heapRegionsItrA.next();
1202                 HeapRegionNode hrnChildA = edgeA.getDst();
1203                 Integer        idChildA  = hrnChildA.getID();           
1204
1205                 // at this point we know an edge in graph A exists
1206                 // tdA -> idChildA, does this exist in B?
1207                 assert td2ln.containsKey( tdA );
1208                 LabelNode     lnB         = td2ln.get( tdA );
1209                 ReferenceEdge edgeToMerge = null;
1210
1211                 // labels never have edges with a field
1212                 //assert edgeA.getFieldDesc() == null;
1213
1214                 Iterator<ReferenceEdge> heapRegionsItrB = lnB.iteratorToReferencees();
1215                 while( heapRegionsItrB.hasNext() &&
1216                        edgeToMerge == null          ) {
1217
1218                     ReferenceEdge  edgeB     = heapRegionsItrB.next();
1219                     HeapRegionNode hrnChildB = edgeB.getDst();
1220                     Integer        idChildB  = hrnChildB.getID();
1221
1222                     // labels never have edges with a field
1223                     //assert edgeB.getFieldDesc() == null;
1224
1225                     // don't use the ReferenceEdge.equals() here because
1226                     // we're talking about existence between graphs
1227                     if( idChildB.equals( idChildA ) &&
1228                         edgeB.getFieldDesc() == edgeA.getFieldDesc() ) {
1229                         edgeToMerge = edgeB;
1230                     }
1231                 }
1232
1233                 // if the edge from A was not found in B,
1234                 // add it to B.
1235                 if( edgeToMerge == null ) {
1236                     assert id2hrn.containsKey( idChildA );
1237                     HeapRegionNode hrnChildB = id2hrn.get( idChildA );
1238                     edgeToMerge = edgeA.copy();
1239                     edgeToMerge.setSrc( lnB );
1240                     edgeToMerge.setDst( hrnChildB );
1241                     addReferenceEdge( lnB, hrnChildB, edgeToMerge );
1242                 }
1243                 // otherwise, the edge already existed in both graphs
1244                 // so merge their reachability sets
1245                 else {
1246                     // just replace this beta set with the union
1247                     edgeToMerge.setBeta( 
1248                       edgeToMerge.getBeta().union( edgeA.getBeta() ) 
1249                                        );
1250                     if( !edgeA.isInitialParamReflexive() ) {
1251                         edgeToMerge.setIsInitialParamReflexive( false );
1252                     }
1253                 }  
1254             } 
1255         }
1256     }
1257
1258     // you should only merge ownership graphs that have the
1259     // same number of parameters, or if one or both parameter
1260     // index tables are empty
1261     protected void mergeId2paramIndex( OwnershipGraph og ) {
1262         if( id2paramIndex.size() == 0 ) {
1263             id2paramIndex = og.id2paramIndex;
1264             paramIndex2id = og.paramIndex2id;
1265             return;
1266         }
1267
1268         if( og.id2paramIndex.size() == 0 ) {
1269             return;
1270         }
1271
1272         assert id2paramIndex.size() == og.id2paramIndex.size();
1273     }
1274
1275     protected void mergeAllocationSites( OwnershipGraph og ) {
1276         allocationSites.addAll( og.allocationSites );
1277     }
1278
1279
1280
1281     // it is necessary in the equals() member functions
1282     // to "check both ways" when comparing the data
1283     // structures of two graphs.  For instance, if all
1284     // edges between heap region nodes in graph A are
1285     // present and equal in graph B it is not sufficient
1286     // to say the graphs are equal.  Consider that there
1287     // may be edges in graph B that are not in graph A.
1288     // the only way to know that all edges in both graphs
1289     // are equally present is to iterate over both data
1290     // structures and compare against the other graph.
1291     public boolean equals( OwnershipGraph og ) {
1292
1293         if( og == null ) {
1294           return false;
1295         }
1296         
1297         if( !areHeapRegionNodesEqual( og ) ) {
1298             return false;
1299         }
1300
1301         if( !areLabelNodesEqual( og ) ) {
1302             return false;
1303         }
1304
1305         if( !areReferenceEdgesEqual( og ) ) {
1306             return false;
1307         }
1308
1309         if( !areId2paramIndexEqual( og ) ) {
1310             return false;
1311         }
1312
1313         // if everything is equal up to this point,
1314         // assert that allocationSites is also equal--
1315         // this data is redundant and kept for efficiency
1316         assert allocationSites.equals( og.allocationSites );
1317
1318         return true;
1319     }
1320
1321     protected boolean areHeapRegionNodesEqual( OwnershipGraph og ) {       
1322
1323         if( !areallHRNinAalsoinBandequal( this, og ) ) {
1324             return false;
1325         }
1326
1327         if( !areallHRNinAalsoinBandequal( og, this ) ) {
1328             return false;
1329         }
1330
1331         return true;
1332     }
1333
1334     static protected boolean areallHRNinAalsoinBandequal( OwnershipGraph ogA,
1335                                                           OwnershipGraph ogB ) {
1336         Set      sA = ogA.id2hrn.entrySet();
1337         Iterator iA = sA.iterator();
1338         while( iA.hasNext() ) {
1339             Map.Entry      meA  = (Map.Entry)      iA.next();
1340             Integer        idA  = (Integer)        meA.getKey();
1341             HeapRegionNode hrnA = (HeapRegionNode) meA.getValue();
1342             
1343             if( !ogB.id2hrn.containsKey( idA ) ) {
1344                 return false;
1345             }
1346
1347             HeapRegionNode hrnB = ogB.id2hrn.get( idA );            
1348             if( !hrnA.equalsIncludingAlpha( hrnB ) ) {
1349                 return false;
1350             }       
1351         }
1352
1353         return true;
1354     }
1355
1356
1357     protected boolean areLabelNodesEqual( OwnershipGraph og ) {
1358
1359         if( !areallLNinAalsoinBandequal( this, og ) ) {
1360             return false;
1361         }
1362
1363         if( !areallLNinAalsoinBandequal( og, this ) ) {
1364             return false;
1365         }
1366
1367         return true;
1368     }
1369
1370     static protected boolean areallLNinAalsoinBandequal( OwnershipGraph ogA,
1371                                                          OwnershipGraph ogB ) {
1372         Set      sA = ogA.td2ln.entrySet();
1373         Iterator iA = sA.iterator();
1374         while( iA.hasNext() ) {
1375             Map.Entry      meA = (Map.Entry)      iA.next();
1376             TempDescriptor tdA = (TempDescriptor) meA.getKey();
1377
1378             if( !ogB.td2ln.containsKey( tdA ) ) {
1379                 return false;
1380             }
1381         }
1382         
1383         return true;
1384     }
1385
1386
1387     protected boolean areReferenceEdgesEqual( OwnershipGraph og ) {
1388         if( !areallREinAandBequal( this, og ) ) {
1389             return false;
1390         }
1391
1392         return true;
1393     }
1394
1395     static protected boolean areallREinAandBequal( OwnershipGraph ogA,
1396                                                    OwnershipGraph ogB ) {
1397
1398         // check all the heap region->heap region edges
1399         Set      sA = ogA.id2hrn.entrySet();
1400         Iterator iA = sA.iterator();
1401         while( iA.hasNext() ) {
1402             Map.Entry      meA  = (Map.Entry)      iA.next();
1403             Integer        idA  = (Integer)        meA.getKey();
1404             HeapRegionNode hrnA = (HeapRegionNode) meA.getValue();
1405
1406             // we should have already checked that the same
1407             // heap regions exist in both graphs
1408             assert ogB.id2hrn.containsKey( idA );
1409
1410             if( !areallREfromAequaltoB( ogA, hrnA, ogB ) ) {
1411                 return false;
1412             }
1413
1414             // then check every edge in B for presence in A, starting
1415             // from the same parent HeapRegionNode
1416             HeapRegionNode hrnB = ogB.id2hrn.get( idA );
1417
1418             if( !areallREfromAequaltoB( ogB, hrnB, ogA ) ) {
1419                 return false;
1420             }
1421         }
1422
1423         // then check all the label->heap region edges
1424         sA = ogA.td2ln.entrySet();
1425         iA = sA.iterator();
1426         while( iA.hasNext() ) {
1427             Map.Entry      meA = (Map.Entry)      iA.next();
1428             TempDescriptor tdA = (TempDescriptor) meA.getKey();
1429             LabelNode      lnA = (LabelNode)      meA.getValue();
1430
1431             // we should have already checked that the same
1432             // label nodes exist in both graphs
1433             assert ogB.td2ln.containsKey( tdA );
1434
1435             if( !areallREfromAequaltoB( ogA, lnA, ogB ) ) {
1436                 return false;
1437             }
1438
1439             // then check every edge in B for presence in A, starting
1440             // from the same parent LabelNode
1441             LabelNode lnB = ogB.td2ln.get( tdA );
1442
1443             if( !areallREfromAequaltoB( ogB, lnB, ogA ) ) {
1444                 return false;
1445             }
1446         }
1447
1448         return true;
1449     }
1450
1451
1452     static protected boolean areallREfromAequaltoB( OwnershipGraph ogA,
1453                                                     OwnershipNode  onA,
1454                                                     OwnershipGraph ogB ) {
1455         
1456         Iterator<ReferenceEdge> itrA = onA.iteratorToReferencees();
1457         while( itrA.hasNext() ) {
1458             ReferenceEdge  edgeA     = itrA.next();
1459             HeapRegionNode hrnChildA = edgeA.getDst();
1460             Integer        idChildA  = hrnChildA.getID();
1461
1462             assert ogB.id2hrn.containsKey( idChildA );
1463
1464             // at this point we know an edge in graph A exists
1465             // onA -> idChildA, does this exact edge exist in B?
1466             boolean edgeFound = false;
1467
1468             OwnershipNode onB = null;       
1469             if( onA instanceof HeapRegionNode ) {
1470                 HeapRegionNode hrnA = (HeapRegionNode) onA;
1471                 onB = ogB.id2hrn.get( hrnA.getID() );
1472             } else {
1473                 LabelNode lnA = (LabelNode) onA;
1474                 onB = ogB.td2ln.get( lnA.getTempDescriptor() );
1475             }
1476
1477             Iterator<ReferenceEdge> itrB = onB.iteratorToReferencees();
1478             while( itrB.hasNext() ) {
1479                 ReferenceEdge  edgeB     = itrB.next();
1480                 HeapRegionNode hrnChildB = edgeB.getDst();
1481                 Integer        idChildB  = hrnChildB.getID();
1482
1483                 if( idChildA.equals( idChildB ) &&
1484                     edgeA.getFieldDesc() == edgeB.getFieldDesc() ) {
1485
1486                     // there is an edge in the right place with the right field,
1487                     // but do they have the same attributes?
1488                     if( edgeA.getBeta().equals( edgeB.getBeta() ) ) {
1489                         
1490                         edgeFound = true;
1491                         //} else {
1492                         //return false;
1493                     }
1494                 }
1495             }
1496
1497             if( !edgeFound ) {
1498                 return false;
1499             }           
1500         }
1501         
1502         return true;
1503     }
1504
1505
1506     protected boolean areId2paramIndexEqual( OwnershipGraph og ) {
1507         return id2paramIndex.size() == og.id2paramIndex.size();
1508     }
1509
1510
1511     /*
1512     // given a set B of heap region node ID's, return the set of heap
1513     // region node ID's that is reachable from B
1514     public HashSet<Integer> getReachableSet( HashSet<Integer> idSetB ) {
1515
1516         HashSet<HeapRegionNode> toVisit = new HashSet<HeapRegionNode>();
1517         HashSet<HeapRegionNode> visited = new HashSet<HeapRegionNode>();
1518
1519         // initial nodes to visit are from set B
1520         Iterator initialItr = idSetB.iterator();
1521         while( initialItr.hasNext() ) {
1522             Integer idInitial = (Integer) initialItr.next();
1523             assert id2hrn.contains( idInitial );
1524             HeapRegionNode hrnInitial = id2hrn.get( idInitial );
1525             toVisit.add( hrnInitial );
1526         }
1527
1528         HashSet<Integer> idSetReachableFromB = new HashSet<Integer>();
1529
1530         // do a heap traversal
1531         while( !toVisit.isEmpty() ) {
1532             HeapRegionNode hrnVisited = (HeapRegionNode) toVisit.iterator().next();
1533             toVisit.remove( hrnVisited );
1534             visited.add   ( hrnVisited );
1535
1536             // for every node visited, add it to the total
1537             // reachable set
1538             idSetReachableFromB.add( hrnVisited.getID() );
1539
1540             // find other reachable nodes
1541             Iterator referenceeItr = hrnVisited.setIteratorToReferencedRegions();
1542             while( referenceeItr.hasNext() ) {
1543                 Map.Entry me                 = (Map.Entry)               referenceeItr.next();
1544                 HeapRegionNode hrnReferencee = (HeapRegionNode)          me.getKey();
1545                 ReferenceEdgeProperties rep  = (ReferenceEdgeProperties) me.getValue();
1546
1547                 if( !visited.contains( hrnReferencee ) ) {
1548                     toVisit.add( hrnReferencee );
1549                 }
1550             }
1551         }
1552
1553         return idSetReachableFromB;
1554     }
1555
1556
1557     // used to find if a heap region can possibly have a reference to
1558     // any of the heap regions in the given set
1559     // if the id supplied is in the set, then a self-referencing edge
1560     // would return true, but that special case is specifically allowed
1561     // meaning that it isn't an external alias
1562     public boolean canIdReachSet( Integer id, HashSet<Integer> idSet ) {
1563
1564         assert id2hrn.contains( id );
1565         HeapRegionNode hrn = id2hrn.get( id );
1566
1567         
1568         //HashSet<HeapRegionNode> hrnSet = new HashSet<HeapRegionNode>();
1569
1570         //Iterator i = idSet.iterator();
1571         //while( i.hasNext() ) {
1572         //    Integer idFromSet = (Integer) i.next();
1573         //   assert id2hrn.contains( idFromSet );
1574         //    hrnSet.add( id2hrn.get( idFromSet ) );
1575         //}
1576         
1577
1578         // do a traversal from hrn and see if any of the
1579         // heap regions from the set come up during that
1580         HashSet<HeapRegionNode> toVisit = new HashSet<HeapRegionNode>();
1581         HashSet<HeapRegionNode> visited = new HashSet<HeapRegionNode>();
1582         
1583         toVisit.add( hrn );
1584         while( !toVisit.isEmpty() ) {
1585             HeapRegionNode hrnVisited = (HeapRegionNode) toVisit.iterator().next();
1586             toVisit.remove( hrnVisited );
1587             visited.add   ( hrnVisited );
1588
1589             Iterator referenceeItr = hrnVisited.setIteratorToReferencedRegions();
1590             while( referenceeItr.hasNext() ) {
1591                 Map.Entry me                 = (Map.Entry)               referenceeItr.next();
1592                 HeapRegionNode hrnReferencee = (HeapRegionNode)          me.getKey();
1593                 ReferenceEdgeProperties rep  = (ReferenceEdgeProperties) me.getValue();
1594
1595                 if( idSet.contains( hrnReferencee.getID() ) ) {
1596                     if( !id.equals( hrnReferencee.getID() ) ) {
1597                         return true;
1598                     }
1599                 }
1600
1601                 if( !visited.contains( hrnReferencee ) ) {
1602                     toVisit.add( hrnReferencee );
1603                 }
1604             }
1605         }
1606
1607         return false;
1608     }
1609     */   
1610
1611
1612     // for writing ownership graphs to dot files
1613     public void writeGraph( Descriptor methodDesc,
1614                             FlatNode   fn,
1615                             boolean    writeLabels,
1616                             boolean    labelSelect,
1617                             boolean    pruneGarbage,
1618                             boolean    writeReferencers 
1619                             ) throws java.io.IOException {
1620         writeGraph(
1621                    methodDesc.getSymbol() +
1622                    methodDesc.getNum() +
1623                    fn.toString(),
1624                    writeLabels,
1625                    labelSelect,
1626                    pruneGarbage,
1627                    writeReferencers
1628                    );
1629     }
1630
1631     public void writeGraph( Descriptor methodDesc,
1632                             FlatNode   fn,
1633                             boolean    writeLabels,
1634                             boolean    writeReferencers 
1635                             ) throws java.io.IOException {
1636         writeGraph(
1637                    methodDesc.getSymbol() +
1638                    methodDesc.getNum() +
1639                    fn.toString(),
1640                    writeLabels,
1641                    false,
1642                    false,
1643                    writeReferencers
1644                    );
1645     }
1646
1647     public void writeGraph( Descriptor methodDesc,
1648                             boolean    writeLabels,
1649                             boolean    writeReferencers 
1650                             ) throws java.io.IOException {
1651         writeGraph( 
1652                    methodDesc.getSymbol() +
1653                    methodDesc.getNum() +
1654                    "COMPLETE",
1655                    writeLabels,
1656                    false,
1657                    false,
1658                    writeReferencers
1659                     );
1660     }
1661
1662     public void writeGraph( Descriptor methodDesc,
1663                             boolean    writeLabels,
1664                             boolean    labelSelect,
1665                             boolean    pruneGarbage,
1666                             boolean    writeReferencers 
1667                             ) throws java.io.IOException {
1668         writeGraph( 
1669                    methodDesc.getSymbol() +
1670                    methodDesc.getNum() +
1671                    "COMPLETE",
1672                    writeLabels,
1673                    labelSelect,
1674                    pruneGarbage,
1675                    writeReferencers
1676                     );
1677     }
1678
1679     public void writeGraph( String graphName,
1680                             boolean writeLabels,
1681                             boolean labelSelect,
1682                             boolean pruneGarbage,
1683                             boolean writeReferencers 
1684                             ) throws java.io.IOException {
1685
1686         // remove all non-word characters from the graph name so
1687         // the filename and identifier in dot don't cause errors
1688         graphName = graphName.replaceAll( "[\\W]", "" );
1689
1690         BufferedWriter bw = new BufferedWriter( new FileWriter( graphName+".dot" ) );
1691         bw.write( "digraph "+graphName+" {\n" );
1692         //bw.write( "  size=\"7.5,10\";\n" );
1693
1694         HashSet<HeapRegionNode> visited = new HashSet<HeapRegionNode>();
1695
1696         // then visit every heap region node
1697         if( !pruneGarbage ) {       
1698             Set      s = id2hrn.entrySet();
1699             Iterator i = s.iterator();
1700             while( i.hasNext() ) {
1701                 Map.Entry      me  = (Map.Entry)      i.next();
1702                 HeapRegionNode hrn = (HeapRegionNode) me.getValue();
1703                 if( !visited.contains( hrn ) ) {
1704                     traverseHeapRegionNodes( VISIT_HRN_WRITE_FULL, 
1705                                              hrn, 
1706                                              bw, 
1707                                              null, 
1708                                              visited, 
1709                                              writeReferencers );
1710                 }
1711             }
1712         }
1713
1714         bw.write( "  graphTitle[label=\""+graphName+"\",shape=box];\n" );
1715
1716
1717         // then visit every label node, useful for debugging
1718         if( writeLabels ) {
1719             Set      s = td2ln.entrySet();
1720             Iterator i = s.iterator();
1721             while( i.hasNext() ) {
1722                 Map.Entry me = (Map.Entry) i.next();
1723                 LabelNode ln = (LabelNode) me.getValue();
1724                 
1725                 if( labelSelect ) {
1726                     String labelStr = ln.getTempDescriptorString();
1727                     if( labelStr.startsWith( "___temp"      ) ||
1728                         labelStr.startsWith( "___dst"       ) ||
1729                         labelStr.startsWith( "___srctmp"   ) ||
1730                         labelStr.startsWith( "___neverused" )   ) {
1731                         continue;
1732                     }
1733                 }
1734
1735                 bw.write( ln.toString() + ";\n" );
1736
1737                 Iterator<ReferenceEdge> heapRegionsItr = ln.iteratorToReferencees();
1738                 while( heapRegionsItr.hasNext() ) {
1739                     ReferenceEdge  edge = heapRegionsItr.next();
1740                     HeapRegionNode hrn  = edge.getDst();
1741
1742                     if( pruneGarbage && !visited.contains( hrn ) ) {
1743                         traverseHeapRegionNodes( VISIT_HRN_WRITE_FULL, 
1744                                                  hrn, 
1745                                                  bw, 
1746                                                  null, 
1747                                                  visited, 
1748                                                  writeReferencers );
1749                     }
1750                     
1751                     bw.write( "  "        + ln.toString() +
1752                               " -> "      + hrn.toString() +
1753                               "[label=\"" + edge.toGraphEdgeString() +
1754                               "\",decorate];\n" );
1755                 }
1756             }
1757         }
1758
1759         
1760         bw.write( "}\n" );
1761         bw.close();
1762     }
1763
1764     protected void traverseHeapRegionNodes( int mode,
1765                                             HeapRegionNode hrn,
1766                                             BufferedWriter bw,
1767                                             TempDescriptor td,
1768                                             HashSet<HeapRegionNode> visited,
1769                                             boolean writeReferencers
1770                                             ) throws java.io.IOException {
1771
1772         if( visited.contains( hrn ) ) {
1773             return;
1774         }
1775         visited.add( hrn );
1776
1777         switch( mode ) {
1778         case VISIT_HRN_WRITE_FULL:
1779             
1780             String attributes = "[";
1781             
1782             if( hrn.isSingleObject() ) {
1783                 attributes += "shape=box";
1784             } else {
1785                 attributes += "shape=Msquare";
1786             }
1787
1788             if( hrn.isFlagged() ) {
1789                 attributes += ",style=filled,fillcolor=lightgrey";
1790             }
1791
1792             attributes += ",label=\"ID"        +
1793                           hrn.getID()          +
1794                           "\\n"                +
1795                           hrn.getDescription() + 
1796                           "\\n"                +
1797                           hrn.getAlphaString() +
1798                           "\"]";
1799
1800             bw.write( "  " + hrn.toString() + attributes + ";\n" );
1801             break;
1802         }
1803
1804
1805         // useful for debugging
1806         if( writeReferencers ) {
1807             OwnershipNode onRef  = null;
1808             Iterator      refItr = hrn.iteratorToReferencers();
1809             while( refItr.hasNext() ) {
1810                 onRef = (OwnershipNode) refItr.next();
1811                 
1812                 switch( mode ) {
1813                 case VISIT_HRN_WRITE_FULL:
1814                     bw.write( "  "                    + hrn.toString() + 
1815                               " -> "                  + onRef.toString() + 
1816                               "[color=lightgray];\n" );
1817                     break;
1818                 }
1819             }
1820         }
1821
1822         Iterator<ReferenceEdge> childRegionsItr = hrn.iteratorToReferencees();
1823         while( childRegionsItr.hasNext() ) {
1824             ReferenceEdge  edge     = childRegionsItr.next();
1825             HeapRegionNode hrnChild = edge.getDst();
1826
1827             switch( mode ) {
1828             case VISIT_HRN_WRITE_FULL:
1829                 bw.write( "  "        + hrn.toString() +
1830                           " -> "      + hrnChild.toString() +
1831                           "[label=\"" + edge.toGraphEdgeString() +
1832                           "\",decorate];\n" );
1833                 break;
1834             }
1835
1836             traverseHeapRegionNodes( mode,
1837                                      hrnChild,
1838                                      bw,
1839                                      td,
1840                                      visited,
1841                                      writeReferencers );
1842         }
1843     }
1844 }