1 package Analysis.Disjoint;
9 ////////////////////////////////////////////////
11 // important note! The static operations in this class that take
12 // canonicals and produce a canonical result sometimes need a
13 // "working copy" that IS NOT CANONICAL. So, even though it isn't
14 // perfectly clean, Canonical constructors have been changed from
15 // private to protected and they may be used in this file--however,
16 // only use a constructor for an object that will mutate during the
17 // calculation--use the factory method to obtain everything else!
20 // What this boils down to is that the only normally constructed
21 // object in a canonical operation should be the result out.
23 ////////////////////////////////////////////////
26 abstract public class Canonical {
28 // for generating unique canonical values
29 private static int canonicalCount = 1;
31 // the canon of objects
32 private static Hashtable<Canonical, Canonical>
33 canon = new Hashtable<Canonical, Canonical>();
37 public static Canonical makeCanonical( Canonical c ) {
39 if( c.isCanonical() ) {
40 assert canon.containsKey( c );
41 return canon.get( c );
44 c.canonicalValue = canonicalCount;
51 // any Canonical with value still 0 is NOT CANONICAL!
52 private int canonicalValue = 0;
54 public boolean isCanonical() {
55 return canonicalValue != 0;
58 public int getCanonicalValue() {
60 return canonicalValue;
64 // canonical objects should never be modified
65 // and therefore have changing hash codes, so
66 // use a standard canonical hash code method to
67 // enforce this, and define a specific hash code
68 // method each specific subclass should implement
69 abstract public int hashCodeSpecific();
71 private boolean hasHash = false;
73 final public int hashCode() {
74 int hash = hashCodeSpecific();
77 if( oldHash != hash ) {
78 throw new Error( "A CANONICAL HASH CHANGED" );
91 // mapping of a non-trivial operation to its result
92 private static Hashtable<CanonicalOp, Canonical>
93 op2result = new Hashtable<CanonicalOp, Canonical>();
97 ///////////////////////////////////////////////////////////
99 // Everything below are static methods that implement
100 // "mutating" operations on Canonical objects by returning
101 // the canonical result. If the op is non-trivial the
102 // canonical result is hashed by its defining CononicalOp
104 ///////////////////////////////////////////////////////////
107 // not weighty, don't bother with caching
108 public static ReachTuple unionArity( ReachTuple rt1,
112 assert rt1.isCanonical();
113 assert rt2.isCanonical();
114 assert rt1.hrnID == rt2.hrnID;
115 assert rt1.isMultiObject == rt2.isMultiObject;
119 if( rt1.isMultiObject ) {
120 // on two non-ZERO arity multi regions, union arity is always
122 out = ReachTuple.factory( rt1.hrnID,
124 ReachTuple.ARITY_ZEROORMORE );
127 // a single object region can only be ARITY_ONE (or zero by
129 assert rt1.arity == ReachTuple.ARITY_ONE;
133 assert out.isCanonical();
137 // not weighty, no caching
138 public static ReachTuple changeHrnIDTo( ReachTuple rt,
139 Integer hrnIDToChangeTo ) {
141 assert hrnIDToChangeTo != null;
143 ReachTuple out = ReachTuple.factory( hrnIDToChangeTo,
147 assert out.isCanonical();
152 public static ReachState union( ReachState rs1,
156 assert rs1.isCanonical();
157 assert rs2.isCanonical();
160 new CanonicalOp( CanonicalOp.REACHSTATE_UNION_REACHSTATE,
164 Canonical result = op2result.get( op );
165 if( result != null ) {
166 return (ReachState) result;
169 // otherwise, no cached result...
170 ReachState out = new ReachState();
171 out.reachTuples.addAll( rs1.reachTuples );
172 out.reachTuples.addAll( rs2.reachTuples );
174 out = (ReachState) makeCanonical( out );
175 op2result.put( op, out );
179 // this is just a convenience version of above
180 public static ReachState union( ReachState rs,
186 new CanonicalOp( CanonicalOp.REACHSTATE_UNION_REACHTUPLE,
190 Canonical result = op2result.get( op );
191 if( result != null ) {
192 return (ReachState) result;
195 // otherwise, no cached result...
196 ReachState out = new ReachState();
197 out.reachTuples.addAll( rs.reachTuples );
198 out.reachTuples.add( rt );
200 out = (ReachState) makeCanonical( out );
201 op2result.put( op, out );
206 public static ReachState unionUpArity( ReachState rs1,
210 assert rs1.isCanonical();
211 assert rs2.isCanonical();
214 new CanonicalOp( CanonicalOp.REACHSTATE_UNIONUPARITY_REACHSTATE,
218 Canonical result = op2result.get( op );
219 if( result != null ) {
220 return (ReachState) result;
223 // otherwise, no cached result...
224 ReachState out = new ReachState();
226 Iterator<ReachTuple> rtItr = rs1.iterator();
227 while( rtItr.hasNext() ) {
228 ReachTuple rt1 = rtItr.next();
229 ReachTuple rt2 = rs2.containsHrnID( rt1.getHrnID() );
232 out.reachTuples.add( unionArity( rt1, rt2 ) );
234 out.reachTuples.add( rt1 );
238 rtItr = rs2.iterator();
239 while( rtItr.hasNext() ) {
240 ReachTuple rt2 = rtItr.next();
241 ReachTuple rto = out.containsHrnID( rt2.getHrnID() );
244 out.reachTuples.add( rto );
248 out = (ReachState) makeCanonical( out );
249 op2result.put( op, out );
253 public static ReachState add( ReachState rs, ReachTuple rt ) {
254 return union( rs, rt );
257 public static ReachState remove( ReachState rs, ReachTuple rt ) {
262 new CanonicalOp( CanonicalOp.REACHSTATE_REMOVE_REACHTUPLE,
266 Canonical result = op2result.get( op );
267 if( result != null ) {
268 return (ReachState) result;
271 // otherwise, no cached result...
272 ReachState out = new ReachState();
273 out.reachTuples.addAll( rs.reachTuples );
274 out.reachTuples.remove( rt );
276 out = (ReachState) makeCanonical( out );
277 op2result.put( op, out );
282 public static ReachState ageTuplesFrom( ReachState rs,
286 assert rs.isCanonical();
287 assert as.isCanonical();
290 new CanonicalOp( CanonicalOp.REACHSTATE_AGETUPLESFROM_ALLOCSITE,
294 Canonical result = op2result.get( op );
295 if( result != null ) {
296 return (ReachState) result;
299 // otherwise, no cached result...
300 ReachState out = new ReachState();
302 ReachTuple rtSummary = null;
303 ReachTuple rtOldest = null;
305 Iterator<ReachTuple> rtItr = rs.iterator();
306 while( rtItr.hasNext() ) {
307 ReachTuple rt = rtItr.next();
308 Integer hrnID = rt.getHrnID();
309 int age = as.getAgeCategory( hrnID );
311 // hrnIDs not associated with
312 // the site should be left alone
313 if( age == AllocSite.AGE_notInThisSite ) {
314 out.reachTuples.add( rt );
316 } else if( age == AllocSite.AGE_summary ) {
317 // remember the summary tuple, but don't add it
318 // we may combine it with the oldest tuple
321 } else if( age == AllocSite.AGE_oldest ) {
322 // found an oldest hrnID, again just remember
327 assert age == AllocSite.AGE_in_I;
329 Integer I = as.getAge( hrnID );
332 // otherwise, we change this hrnID to the
334 Integer hrnIDToChangeTo = as.getIthOldest( I + 1 );
336 Canonical.changeHrnIDTo( rt, hrnIDToChangeTo );
337 out.reachTuples.add( rtAged );
341 // there are four cases to consider here
342 // 1. we found a summary tuple and no oldest tuple
343 // Here we just pass the summary unchanged
344 // 2. we found an oldest tuple, no summary
345 // Make a new, arity-one summary tuple
346 // 3. we found both a summary and an oldest
347 // Merge them by arity
348 // 4. (not handled) we found neither, do nothing
349 if( rtSummary != null && rtOldest == null ) {
350 out.reachTuples.add( rtSummary );
352 } else if( rtSummary == null && rtOldest != null ) {
353 out.reachTuples.add( ReachTuple.factory( as.getSummary(),
359 } else if( rtSummary != null && rtOldest != null ) {
360 out.reachTuples.add( Canonical.unionArity( rtSummary,
361 ReachTuple.factory( as.getSummary(),
369 out = (ReachState) makeCanonical( out );
370 op2result.put( op, out );
376 public static ReachSet union( ReachSet rs1,
380 assert rs1.isCanonical();
381 assert rs2.isCanonical();
384 new CanonicalOp( CanonicalOp.REACHSET_UNION_REACHSET,
388 Canonical result = op2result.get( op );
389 if( result != null ) {
390 return (ReachSet) result;
393 // otherwise, no cached result...
394 ReachSet out = new ReachSet();
395 out.reachStates.addAll( rs1.reachStates );
396 out.reachStates.addAll( rs2.reachStates );
398 out = (ReachSet) makeCanonical( out );
399 op2result.put( op, out );
403 public static ReachSet union( ReachSet rs,
407 assert state != null;
408 assert rs.isCanonical();
409 assert state.isCanonical();
412 new CanonicalOp( CanonicalOp.REACHSET_UNION_REACHSTATE,
416 Canonical result = op2result.get( op );
417 if( result != null ) {
418 return (ReachSet) result;
421 // otherwise, no cached result...
422 ReachSet out = new ReachSet();
423 out.reachStates.addAll( rs.reachStates );
424 out.reachStates.add( state );
426 out = (ReachSet) makeCanonical( out );
427 op2result.put( op, out );
431 public static ReachSet intersection( ReachSet rs1,
435 assert rs1.isCanonical();
436 assert rs2.isCanonical();
439 new CanonicalOp( CanonicalOp.REACHSET_INTERSECTION_REACHSET,
443 Canonical result = op2result.get( op );
444 if( result != null ) {
445 return (ReachSet) result;
448 // otherwise, no cached result...
449 ReachSet out = new ReachSet();
450 Iterator<ReachState> itr = rs1.iterator();
451 while( itr.hasNext() ) {
452 ReachState state = (ReachState) itr.next();
453 if( rs2.reachStates.contains( state ) ) {
454 out.reachStates.add( state );
458 out = (ReachSet) makeCanonical( out );
459 op2result.put( op, out );
464 public static ReachSet add( ReachSet rs,
466 return union( rs, state );
469 public static ReachSet remove( ReachSet rs,
472 assert state != null;
473 assert rs.isCanonical();
474 assert state.isCanonical();
477 new CanonicalOp( CanonicalOp.REACHSET_REMOVE_REACHSTATE,
481 Canonical result = op2result.get( op );
482 if( result != null ) {
483 return (ReachSet) result;
486 // otherwise, no cached result...
487 ReachSet out = new ReachSet();
488 out.reachStates.addAll( rs.reachStates );
489 out.reachStates.remove( state );
491 out = (ReachSet) makeCanonical( out );
492 op2result.put( op, out );
497 public static ReachSet applyChangeSet( ReachSet rs,
499 boolean keepSourceState ) {
502 assert rs.isCanonical();
503 assert cs.isCanonical();
505 // this primitive operand stuff is just a way to
506 // ensure distinct inputs to a CanonicalOp
508 if( keepSourceState ) {
515 new CanonicalOp( CanonicalOp.REACHSET_APPLY_CHANGESET,
520 Canonical result = op2result.get( op );
521 if( result != null ) {
522 return (ReachSet) result;
525 // otherwise, no cached result...
526 ReachSet out = new ReachSet();
528 Iterator<ReachState> stateItr = rs.iterator();
529 while( stateItr.hasNext() ) {
530 ReachState state = stateItr.next();
532 boolean changeFound = false;
534 Iterator<ChangeTuple> ctItr = cs.iterator();
535 while( ctItr.hasNext() ) {
536 ChangeTuple ct = ctItr.next();
538 if( state.equals( ct.getSetToMatch() ) ) {
539 out.reachStates.add( ct.getSetToAdd() );
544 if( keepSourceState || !changeFound ) {
545 out.reachStates.add( state );
549 out = (ReachSet) makeCanonical( out );
550 op2result.put( op, out );
555 public static ChangeSet unionUpArityToChangeSet( ReachSet rsO,
559 assert rsO.isCanonical();
560 assert rsR.isCanonical();
563 new CanonicalOp( CanonicalOp.REACHSET_UNIONTOCHANGESET_REACHSET,
567 Canonical result = op2result.get( op );
568 if( result != null ) {
569 return (ChangeSet) result;
572 // otherwise, no cached result...
573 ChangeSet out = new ChangeSet();
575 Iterator<ReachState> itrO = rsO.iterator();
576 while( itrO.hasNext() ) {
577 ReachState o = itrO.next();
579 Iterator<ReachState> itrR = rsR.iterator();
580 while( itrR.hasNext() ) {
581 ReachState r = itrR.next();
583 ReachState theUnion = ReachState.factory();
585 Iterator<ReachTuple> itrRelement = r.iterator();
586 while( itrRelement.hasNext() ) {
587 ReachTuple rtR = itrRelement.next();
588 ReachTuple rtO = o.containsHrnID( rtR.getHrnID() );
591 theUnion = Canonical.union( theUnion,
592 Canonical.unionArity( rtR,
597 theUnion = Canonical.union( theUnion,
603 Iterator<ReachTuple> itrOelement = o.iterator();
604 while( itrOelement.hasNext() ) {
605 ReachTuple rtO = itrOelement.next();
606 ReachTuple rtR = theUnion.containsHrnID( rtO.getHrnID() );
609 theUnion = Canonical.union( theUnion,
615 if( !theUnion.isEmpty() ) {
617 Canonical.union( out,
619 ChangeTuple.factory( o, theUnion )
626 out = (ChangeSet) makeCanonical( out );
627 op2result.put( op, out );
632 public static ReachSet ageTuplesFrom( ReachSet rs,
636 assert rs.isCanonical();
637 assert as.isCanonical();
640 new CanonicalOp( CanonicalOp.REACHSET_AGETUPLESFROM_ALLOCSITE,
644 Canonical result = op2result.get( op );
645 if( result != null ) {
646 return (ReachSet) result;
649 // otherwise, no cached result...
650 ReachSet out = new ReachSet();
652 Iterator<ReachState> itrS = rs.iterator();
653 while( itrS.hasNext() ) {
654 ReachState state = itrS.next();
655 out.reachStates.add( Canonical.ageTuplesFrom( state, as ) );
658 out = (ReachSet) makeCanonical( out );
659 op2result.put( op, out );
664 public static ReachSet pruneBy( ReachSet rsO,
668 assert rsO.isCanonical();
669 assert rsP.isCanonical();
672 new CanonicalOp( CanonicalOp.REACHSET_PRUNEBY_REACHSET,
676 Canonical result = op2result.get( op );
677 if( result != null ) {
678 return (ReachSet) result;
681 // otherwise, no cached result...
682 ReachSet out = new ReachSet();
684 Iterator<ReachState> itrO = rsO.iterator();
685 while( itrO.hasNext() ) {
686 ReachState stateO = itrO.next();
688 boolean subsetExists = false;
690 Iterator<ReachState> itrP = rsP.iterator();
691 while( itrP.hasNext() && !subsetExists ) {
692 ReachState stateP = itrP.next();
694 if( stateP.isSubset( stateO ) ) {
700 out.reachStates.add( stateO );
704 out = (ReachSet) makeCanonical( out );
705 op2result.put( op, out );
710 public static ChangeSet union( ChangeSet cs1,
714 assert cs1.isCanonical();
715 assert cs2.isCanonical();
718 new CanonicalOp( CanonicalOp.CHANGESET_UNION_CHANGESET,
722 Canonical result = op2result.get( op );
723 if( result != null ) {
724 return (ChangeSet) result;
727 // otherwise, no cached result...
728 ChangeSet out = new ChangeSet();
729 out.changeTuples.addAll( cs1.changeTuples );
730 out.changeTuples.addAll( cs2.changeTuples );
732 out = (ChangeSet) makeCanonical( out );
733 op2result.put( op, out );
737 public static ChangeSet union( ChangeSet cs,
741 assert cs.isCanonical();
742 assert ct.isCanonical();
745 new CanonicalOp( CanonicalOp.CHANGESET_UNION_CHANGETUPLE,
749 Canonical result = op2result.get( op );
750 if( result != null ) {
751 return (ChangeSet) result;
754 // otherwise, no cached result...
755 ChangeSet out = new ChangeSet();
756 out.changeTuples.addAll( cs.changeTuples );
757 out.changeTuples.add( ct );
759 out = (ChangeSet) makeCanonical( out );
760 op2result.put( op, out );
766 public static ExistPredSet join( ExistPredSet eps1,
767 ExistPredSet eps2 ) {
771 assert eps1.isCanonical();
772 assert eps2.isCanonical();
775 new CanonicalOp( CanonicalOp.EXISTPREDSET_JOIN_EXISTPREDSET,
779 Canonical result = op2result.get( op );
780 if( result != null ) {
781 return (ExistPredSet) result;
784 // otherwise, no cached result...
785 ExistPredSet out = new ExistPredSet();
786 out.preds.addAll( eps1.preds );
787 out.preds.addAll( eps2.preds );
789 out = (ExistPredSet) makeCanonical( out );
790 op2result.put( op, out );
794 public static ExistPredSet add( ExistPredSet eps,
800 assert eps.isCanonical();
801 assert ep.isCanonical();
804 new CanonicalOp( CanonicalOp.EXISTPREDSET_ADD_EXISTPRED,
808 Canonical result = op2result.get( op );
809 if( result != null ) {
810 return (ExistPredSet) result;
813 // otherwise, no cached result...
814 ExistPredSet out = new ExistPredSet();
815 out.preds.addAll( eps.preds );
818 out = (ExistPredSet) makeCanonical( out );
819 op2result.put( op, out );