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( canon.containsKey( c ) ) {
40 return canon.get( c );
43 c.canonicalValue = canonicalCount;
50 // any Canonical with value still 0 is NOT CANONICAL!
51 private int canonicalValue = 0;
53 public boolean isCanonical() {
54 return canonicalValue != 0;
57 public int getCanonicalValue() {
59 return canonicalValue;
64 abstract public boolean equalsSpecific( Object o );
66 final public boolean equals( Object o ) {
71 if( !(o instanceof Canonical) ) {
75 Canonical c = (Canonical) o;
77 if( this.canonicalValue == 0 ||
80 return equalsSpecific( o );
83 return this.canonicalValue == c.canonicalValue;
87 // canonical objects should never be modified
88 // and therefore have changing hash codes, so
89 // use a standard canonical hash code method to
90 // enforce this, and define a specific hash code
91 // method each specific subclass should implement
92 abstract public int hashCodeSpecific();
94 private boolean hasHash = false;
96 final public int hashCode() {
99 if( DisjointAnalysis.releaseMode && hasHash ) {
104 int hash = hashCodeSpecific();
107 if( oldHash != hash ) {
108 throw new Error( "A CANONICAL HASH CHANGED" );
119 // mapping of a non-trivial operation to its result
120 private static Hashtable<CanonicalOp, Canonical>
121 op2result = new Hashtable<CanonicalOp, Canonical>();
125 ///////////////////////////////////////////////////////////
127 // Everything below are static methods that implement
128 // "mutating" operations on Canonical objects by returning
129 // the canonical result. If the op is non-trivial the
130 // canonical result is hashed by its defining CononicalOp
132 ///////////////////////////////////////////////////////////
135 // not weighty, don't bother with caching
136 public static ReachTuple unionUpArity( ReachTuple rt1,
140 assert rt1.isCanonical();
141 assert rt2.isCanonical();
142 assert rt1.hrnID == rt2.hrnID;
143 assert rt1.isMultiObject == rt2.isMultiObject;
144 assert rt1.isOutOfContext == rt2.isOutOfContext;
148 if( rt1.isMultiObject ) {
149 // on two non-ZERO arity multi regions, union arity is always
151 out = ReachTuple.factory( rt1.hrnID,
153 ReachTuple.ARITY_ZEROORMORE,
154 rt1.isOutOfContext );
157 // a single object region can only be ARITY_ONE (or zero by
159 assert rt1.arity == ReachTuple.ARITY_ONE;
163 assert out.isCanonical();
167 // not weighty, no caching
168 public static ReachTuple changeHrnIDTo( ReachTuple rt,
169 Integer hrnIDToChangeTo ) {
171 assert hrnIDToChangeTo != null;
173 ReachTuple out = ReachTuple.factory( hrnIDToChangeTo,
178 assert out.isCanonical();
183 public static ReachState attach( ReachState rs,
184 ExistPredSet preds ) {
186 assert preds != null;
187 assert rs.isCanonical();
188 assert preds.isCanonical();
191 new CanonicalOp( CanonicalOp.REACHSTATE_ATTACH_EXISTPREDSET,
195 Canonical result = op2result.get( op );
196 if( result != null ) {
197 return (ReachState) result;
200 // otherwise, no cached result...
201 ReachState out = new ReachState();
202 out.reachTuples.addAll( rs.reachTuples );
203 out.preds = Canonical.join( rs.preds,
206 out = (ReachState) makeCanonical( out );
207 op2result.put( op, out );
212 public static ReachState add( ReachState rs,
217 // this is only safe if we are certain the new tuple's
218 // ID doesn't already appear in the reach state
219 assert rs.containsHrnID( rt.getHrnID(),
220 rt.isOutOfContext() ) == null;
223 new CanonicalOp( CanonicalOp.REACHSTATE_ADD_REACHTUPLE,
227 Canonical result = op2result.get( op );
228 if( result != null ) {
229 return (ReachState) result;
232 // otherwise, no cached result...
233 ReachState out = new ReachState();
234 out.reachTuples.addAll( rs.reachTuples );
235 out.reachTuples.add( rt );
236 out.preds = rs.preds;
238 out = (ReachState) makeCanonical( out );
239 op2result.put( op, out );
244 public static ReachState unionUpArity( ReachState rs1,
248 assert rs1.isCanonical();
249 assert rs2.isCanonical();
252 new CanonicalOp( CanonicalOp.REACHSTATE_UNIONUPARITY_REACHSTATE,
256 Canonical result = op2result.get( op );
257 if( result != null ) {
258 return (ReachState) result;
261 // otherwise, no cached result...
262 ReachState out = new ReachState();
264 // first add everything from 1, and if it is
265 // also in 2 take the union of the tuple arities
266 Iterator<ReachTuple> rtItr = rs1.iterator();
267 while( rtItr.hasNext() ) {
268 ReachTuple rt1 = rtItr.next();
269 ReachTuple rt2 = rs2.containsHrnID( rt1.getHrnID(),
273 out.reachTuples.add( unionUpArity( rt1, rt2 ) );
275 out.reachTuples.add( rt1 );
279 // then add everything in 2 that wasn't in 1
280 rtItr = rs2.iterator();
281 while( rtItr.hasNext() ) {
282 ReachTuple rt2 = rtItr.next();
283 ReachTuple rt1 = rs1.containsHrnID( rt2.getHrnID(),
287 out.reachTuples.add( rt2 );
291 out.preds = Canonical.join( rs1.getPreds(),
295 out = (ReachState) makeCanonical( out );
296 op2result.put( op, out );
301 public static ReachState remove( ReachState rs, ReachTuple rt ) {
306 new CanonicalOp( CanonicalOp.REACHSTATE_REMOVE_REACHTUPLE,
310 Canonical result = op2result.get( op );
311 if( result != null ) {
312 return (ReachState) result;
315 // otherwise, no cached result...
316 ReachState out = new ReachState();
317 out.reachTuples.addAll( rs.reachTuples );
318 out.reachTuples.remove( rt );
319 out.preds = rs.preds;
321 out = (ReachState) makeCanonical( out );
322 op2result.put( op, out );
327 public static ReachState ageTuplesFrom( ReachState rs,
331 assert rs.isCanonical();
332 assert as.isCanonical();
335 new CanonicalOp( CanonicalOp.REACHSTATE_AGETUPLESFROM_ALLOCSITE,
339 Canonical result = op2result.get( op );
340 if( result != null ) {
341 return (ReachState) result;
344 // otherwise, no cached result...
345 ReachState out = new ReachState();
347 ReachTuple rtSummary = null;
348 ReachTuple rtOldest = null;
350 Iterator<ReachTuple> rtItr = rs.iterator();
351 while( rtItr.hasNext() ) {
352 ReachTuple rt = rtItr.next();
353 Integer hrnID = rt.getHrnID();
354 int age = as.getAgeCategory( hrnID );
356 // hrnIDs not associated with
357 // the site should be left alone, and
358 // those from this site but out-of-context
359 if( age == AllocSite.AGE_notInThisSite ||
362 out.reachTuples.add( rt );
364 } else if( age == AllocSite.AGE_summary ) {
365 // remember the summary tuple, but don't add it
366 // we may combine it with the oldest tuple
369 } else if( age == AllocSite.AGE_oldest ) {
370 // found an oldest hrnID, again just remember
375 assert age == AllocSite.AGE_in_I;
377 Integer I = as.getAge( hrnID );
380 // otherwise, we change this hrnID to the
382 Integer hrnIDToChangeTo = as.getIthOldest( I + 1 );
384 Canonical.changeHrnIDTo( rt, hrnIDToChangeTo );
385 out.reachTuples.add( rtAged );
389 // there are four cases to consider here
390 // 1. we found a summary tuple and no oldest tuple
391 // Here we just pass the summary unchanged
392 // 2. we found an oldest tuple, no summary
393 // Make a new, arity-one summary tuple
394 // 3. we found both a summary and an oldest
395 // Merge them by arity
396 // 4. (not handled) we found neither, do nothing
397 if( rtSummary != null && rtOldest == null ) {
398 out.reachTuples.add( rtSummary );
400 } else if( rtSummary == null && rtOldest != null ) {
401 out.reachTuples.add( ReachTuple.factory( as.getSummary(),
404 false // out-of-context
408 } else if( rtSummary != null && rtOldest != null ) {
409 out.reachTuples.add( Canonical.unionUpArity( rtSummary,
410 ReachTuple.factory( as.getSummary(),
413 false // out-of-context
419 out.preds = rs.preds;
421 out = (ReachState) makeCanonical( out );
422 op2result.put( op, out );
428 public static ReachSet unionORpreds( ReachSet rs1,
432 assert rs1.isCanonical();
433 assert rs2.isCanonical();
436 new CanonicalOp( CanonicalOp.REACHSET_UNIONORPREDS_REACHSET,
440 Canonical result = op2result.get( op );
441 if( result != null ) {
442 return (ReachSet) result;
445 // otherwise, no cached result...
446 ReachSet out = new ReachSet();
448 // first add everything from 1, and if it was also in 2
449 // take the OR of the predicates
450 Iterator<ReachState> stateItr = rs1.iterator();
451 while( stateItr.hasNext() ) {
452 ReachState state1 = stateItr.next();
453 ReachState state2 = rs2.containsIgnorePreds( state1 );
455 if( state2 != null ) {
456 out.reachStates.add( ReachState.factory( state1.reachTuples,
457 Canonical.join( state1.preds,
462 out.reachStates.add( state1 );
466 // then add everything in 2 that wasn't in 1
467 stateItr = rs2.iterator();
468 while( stateItr.hasNext() ) {
469 ReachState state2 = stateItr.next();
470 ReachState state1 = rs1.containsIgnorePreds( state2 );
472 if( state1 == null ) {
473 out.reachStates.add( state2 );
477 out = (ReachSet) makeCanonical( out );
478 op2result.put( op, out );
483 // NOTE: when taking the intersection of two reach sets it
484 // is possible for a reach state to be in both sets, but
485 // have different predicates. Conceptully the best new
486 // predicate is an AND of the source predicates, but to
487 // avoid eploding states we'll take an overapproximation
488 // by preferring the predicates from the state in the FIRST
489 // set, so order of arguments matters
490 public static ReachSet intersection( ReachSet rs1,
494 assert rs1.isCanonical();
495 assert rs2.isCanonical();
498 new CanonicalOp( CanonicalOp.REACHSET_INTERSECTION_REACHSET,
502 Canonical result = op2result.get( op );
503 if( result != null ) {
504 return (ReachSet) result;
507 // otherwise, no cached result...
508 ReachSet out = new ReachSet();
509 Iterator<ReachState> itr = rs1.iterator();
510 while( itr.hasNext() ) {
511 ReachState state1 = (ReachState) itr.next();
512 ReachState state2 = rs2.containsIgnorePreds( state1 );
513 if( state2 != null ) {
514 // prefer the predicates on state1, an overapproximation
515 // of state1 preds AND state2 preds
516 out.reachStates.add( state1 );
520 out = (ReachSet) makeCanonical( out );
521 op2result.put( op, out );
526 public static ReachSet add( ReachSet rs,
528 return unionORpreds( rs,
529 ReachSet.factory( state )
533 public static ReachSet remove( ReachSet rs,
536 assert state != null;
537 assert rs.isCanonical();
538 assert state.isCanonical();
541 new CanonicalOp( CanonicalOp.REACHSET_REMOVE_REACHSTATE,
545 Canonical result = op2result.get( op );
546 if( result != null ) {
547 return (ReachSet) result;
550 // otherwise, no cached result...
551 ReachSet out = new ReachSet();
552 out.reachStates.addAll( rs.reachStates );
553 out.reachStates.remove( state );
555 out = (ReachSet) makeCanonical( out );
556 op2result.put( op, out );
561 public static ReachSet applyChangeSet( ReachSet rs,
563 boolean keepSourceState ) {
566 assert rs.isCanonical();
567 assert cs.isCanonical();
569 // this primitive operand stuff is just a way to
570 // ensure distinct inputs to a CanonicalOp
572 if( keepSourceState ) {
579 new CanonicalOp( CanonicalOp.REACHSET_APPLY_CHANGESET,
584 Canonical result = op2result.get( op );
585 if( result != null ) {
586 return (ReachSet) result;
589 // otherwise, no cached result...
590 ReachSet out = new ReachSet();
592 Iterator<ReachState> stateItr = rs.iterator();
593 while( stateItr.hasNext() ) {
594 ReachState stateOrig = stateItr.next();
596 boolean changeFound = false;
598 Iterator<ChangeTuple> ctItr = cs.iterator();
599 while( ctItr.hasNext() ) {
600 ChangeTuple ct = ctItr.next();
602 if( stateOrig.equalsIgnorePreds( ct.getStateToMatch() ) ) {
603 // use the new state, but the original predicates
604 ReachState stateNew =
605 ReachState.factory( ct.getStateToAdd().reachTuples,
608 out.reachStates.add( stateNew );
613 if( keepSourceState || !changeFound ) {
614 out.reachStates.add( stateOrig );
618 out = (ReachSet) makeCanonical( out );
619 op2result.put( op, out );
624 public static ChangeSet unionUpArityToChangeSet( ReachSet rsO,
628 assert rsO.isCanonical();
629 assert rsR.isCanonical();
632 new CanonicalOp( CanonicalOp.REACHSET_UNIONTOCHANGESET_REACHSET,
636 Canonical result = op2result.get( op );
637 if( result != null ) {
638 return (ChangeSet) result;
641 // otherwise, no cached result...
642 ChangeSet out = ChangeSet.factory();
644 Iterator<ReachState> itrO = rsO.iterator();
645 while( itrO.hasNext() ) {
646 ReachState o = itrO.next();
648 Iterator<ReachState> itrR = rsR.iterator();
649 while( itrR.hasNext() ) {
650 ReachState r = itrR.next();
652 ReachState theUnion = ReachState.factory();
654 Iterator<ReachTuple> itrRelement = r.iterator();
655 while( itrRelement.hasNext() ) {
656 ReachTuple rtR = itrRelement.next();
657 ReachTuple rtO = o.containsHrnID( rtR.getHrnID(),
661 theUnion = Canonical.add( theUnion,
662 Canonical.unionUpArity( rtR,
667 theUnion = Canonical.add( theUnion,
673 Iterator<ReachTuple> itrOelement = o.iterator();
674 while( itrOelement.hasNext() ) {
675 ReachTuple rtO = itrOelement.next();
676 ReachTuple rtR = theUnion.containsHrnID( rtO.getHrnID(),
680 theUnion = Canonical.add( theUnion,
686 if( !theUnion.isEmpty() ) {
688 Canonical.union( out,
690 ChangeTuple.factory( o, theUnion )
697 assert out.isCanonical();
698 op2result.put( op, out );
703 public static ReachSet ageTuplesFrom( ReachSet rs,
707 assert rs.isCanonical();
708 assert as.isCanonical();
711 new CanonicalOp( CanonicalOp.REACHSET_AGETUPLESFROM_ALLOCSITE,
715 Canonical result = op2result.get( op );
716 if( result != null ) {
717 return (ReachSet) result;
720 // otherwise, no cached result...
721 ReachSet out = new ReachSet();
723 Iterator<ReachState> itrS = rs.iterator();
724 while( itrS.hasNext() ) {
725 ReachState state = itrS.next();
726 out.reachStates.add( Canonical.ageTuplesFrom( state, as ) );
729 out = (ReachSet) makeCanonical( out );
730 op2result.put( op, out );
735 public static ReachSet pruneBy( ReachSet rsO,
739 assert rsO.isCanonical();
740 assert rsP.isCanonical();
743 new CanonicalOp( CanonicalOp.REACHSET_PRUNEBY_REACHSET,
747 Canonical result = op2result.get( op );
748 if( result != null ) {
749 return (ReachSet) result;
752 // otherwise, no cached result...
753 ReachSet out = new ReachSet();
755 Iterator<ReachState> itrO = rsO.iterator();
756 while( itrO.hasNext() ) {
757 ReachState stateO = itrO.next();
759 boolean subsetExists = false;
761 Iterator<ReachState> itrP = rsP.iterator();
762 while( itrP.hasNext() && !subsetExists ) {
763 ReachState stateP = itrP.next();
765 if( stateP.isSubset( stateO ) ) {
771 out.reachStates.add( stateO );
775 out = (ReachSet) makeCanonical( out );
776 op2result.put( op, out );
781 public static ChangeSet union( ChangeSet cs1,
785 assert cs1.isCanonical();
786 assert cs2.isCanonical();
789 new CanonicalOp( CanonicalOp.CHANGESET_UNION_CHANGESET,
793 Canonical result = op2result.get( op );
794 if( result != null ) {
795 return (ChangeSet) result;
798 // otherwise, no cached result...
799 ChangeSet out = new ChangeSet();
800 out.changeTuples.addAll( cs1.changeTuples );
801 out.changeTuples.addAll( cs2.changeTuples );
803 out = (ChangeSet) makeCanonical( out );
804 op2result.put( op, out );
808 public static ChangeSet add( ChangeSet cs,
812 assert cs.isCanonical();
813 assert ct.isCanonical();
816 new CanonicalOp( CanonicalOp.CHANGESET_UNION_CHANGETUPLE,
820 Canonical result = op2result.get( op );
821 if( result != null ) {
822 return (ChangeSet) result;
825 // otherwise, no cached result...
826 ChangeSet out = new ChangeSet();
827 out.changeTuples.addAll( cs.changeTuples );
828 out.changeTuples.add( ct );
830 out = (ChangeSet) makeCanonical( out );
831 op2result.put( op, out );
837 public static ExistPredSet join( ExistPredSet eps1,
838 ExistPredSet eps2 ) {
842 assert eps1.isCanonical();
843 assert eps2.isCanonical();
846 new CanonicalOp( CanonicalOp.EXISTPREDSET_JOIN_EXISTPREDSET,
850 Canonical result = op2result.get( op );
851 if( result != null ) {
852 return (ExistPredSet) result;
855 // otherwise, no cached result...
856 ExistPredSet out = new ExistPredSet();
857 out.preds.addAll( eps1.preds );
858 out.preds.addAll( eps2.preds );
860 out = (ExistPredSet) makeCanonical( out );
861 op2result.put( op, out );
865 public static ExistPredSet add( ExistPredSet eps,
871 assert eps.isCanonical();
872 assert ep.isCanonical();
875 new CanonicalOp( CanonicalOp.EXISTPREDSET_ADD_EXISTPRED,
879 Canonical result = op2result.get( op );
880 if( result != null ) {
881 return (ExistPredSet) result;
884 // otherwise, no cached result...
885 ExistPredSet out = new ExistPredSet();
886 out.preds.addAll( eps.preds );
889 out = (ExistPredSet) makeCanonical( out );
890 op2result.put( op, out );
895 public static ReachSet toCallerContext( ReachSet rs,
899 assert rs.isCanonical();
900 assert as.isCanonical();
903 new CanonicalOp( CanonicalOp.REACHSET_TOCALLERCONTEXT_ALLOCSITE,
907 Canonical result = op2result.get( op );
908 if( result != null ) {
909 return (ReachSet) result;
912 // otherwise, no cached result...
913 ReachSet out = ReachSet.factory();
914 Iterator<ReachState> itr = rs.iterator();
915 while( itr.hasNext() ) {
916 ReachState state = itr.next();
917 out = Canonical.unionORpreds( out,
918 Canonical.toCallerContext( state, as )
922 assert out.isCanonical();
923 op2result.put( op, out );
928 public static ReachSet toCallerContext( ReachState state,
930 assert state != null;
932 assert state.isCanonical();
933 assert as.isCanonical();
936 new CanonicalOp( CanonicalOp.REACHSTATE_TOCALLERCONTEXT_ALLOCSITE,
940 Canonical result = op2result.get( op );
941 if( result != null ) {
942 return (ReachSet) result;
945 // otherwise, no cached result...
946 ReachSet out = ReachSet.factory();
948 // this method returns a ReachSet instead of a ReachState
949 // because the companion method, toCallee, translates
950 // symbols many-to-one, so state->state
951 // but this method does an ~inverse mapping, one-to-many
952 // so one state can split into a set of branched states
965 // 2S?* -> {2S*, 2S?*}
967 boolean found2Sooc = false;
969 ReachState baseState = ReachState.factory();
971 Iterator<ReachTuple> itr = state.iterator();
972 while( itr.hasNext() ) {
973 ReachTuple rt = itr.next();
975 int age = as.getAgeCategory( rt.getHrnID() );
977 if( age == AllocSite.AGE_notInThisSite ) {
978 // things not from the site just go back in
979 baseState = Canonical.add( baseState, rt );
981 } else if( age == AllocSite.AGE_summary ) {
983 if( rt.isOutOfContext() ) {
984 // if its out-of-context, we only deal here with the ZERO-OR-MORE
985 // arity, if ARITY-ONE we'll branch the base state after the loop
986 if( rt.getArity() == ReachTuple.ARITY_ZEROORMORE ) {
987 // add two overly conservative symbols to reach state (PUNTING)
988 baseState = Canonical.add( baseState,
989 ReachTuple.factory( as.getSummary(),
991 ReachTuple.ARITY_ZEROORMORE,
992 false // out-of-context
995 baseState = Canonical.add( baseState,
996 ReachTuple.factory( as.getSummary(),
998 ReachTuple.ARITY_ZEROORMORE,
999 true // out-of-context
1003 assert rt.getArity() == ReachTuple.ARITY_ONE;
1008 // the in-context just becomes shadow
1009 baseState = Canonical.add( baseState,
1010 ReachTuple.factory( as.getSummaryShadow(),
1013 false // out-of-context
1020 // otherwise age is in range [0, k]
1021 Integer I = as.getAge( rt.getHrnID() );
1023 assert !rt.isMultiObject();
1024 assert rt.getArity() == ReachTuple.ARITY_ONE;
1026 if( rt.isOutOfContext() ) {
1027 // becomes the in-context version
1028 baseState = Canonical.add( baseState,
1029 ReachTuple.factory( rt.getHrnID(),
1031 ReachTuple.ARITY_ONE,
1032 false // out-of-context
1037 // otherwise the ith symbol becomes shadowed
1038 baseState = Canonical.add( baseState,
1039 ReachTuple.factory( -rt.getHrnID(),
1041 ReachTuple.ARITY_ONE,
1042 false // out-of-context
1049 // now either make branches if we have 2S?, or
1050 // the current baseState is the only state we need
1052 // make a branch with every possibility of the one-to-many
1053 // mapping for 2S? appended to the baseState
1054 out = Canonical.add( out,
1055 Canonical.add( baseState,
1056 ReachTuple.factory( as.getSummary(),
1058 ReachTuple.ARITY_ONE,
1059 false // out-of-context
1064 out = Canonical.add( out,
1065 Canonical.add( baseState,
1066 ReachTuple.factory( as.getSummary(),
1068 ReachTuple.ARITY_ONE,
1069 true // out-of-context
1074 for( int i = 0; i < as.getAllocationDepth(); ++i ) {
1075 out = Canonical.add( out,
1076 Canonical.add( baseState,
1077 ReachTuple.factory( as.getIthOldest( i ),
1079 ReachTuple.ARITY_ONE,
1080 true // out-of-context
1087 // just use current baseState
1088 out = Canonical.add( out,
1093 assert out.isCanonical();
1094 op2result.put( op, out );
1099 public static ReachSet unshadow( ReachSet rs,
1103 assert rs.isCanonical();
1104 assert as.isCanonical();
1107 new CanonicalOp( CanonicalOp.REACHSET_UNSHADOW_ALLOCSITE,
1111 Canonical result = op2result.get( op );
1112 if( result != null ) {
1113 return (ReachSet) result;
1116 // otherwise, no cached result...
1117 ReachSet out = ReachSet.factory();
1118 Iterator<ReachState> itr = rs.iterator();
1119 while( itr.hasNext() ) {
1120 ReachState state = itr.next();
1121 out = Canonical.add( out,
1122 Canonical.unshadow( state, as )
1126 assert out.isCanonical();
1127 op2result.put( op, out );
1131 public static ReachState unshadow( ReachState state,
1133 assert state != null;
1135 assert state.isCanonical();
1136 assert as.isCanonical();
1139 new CanonicalOp( CanonicalOp.REACHSTATE_UNSHADOW_ALLOCSITE,
1143 Canonical result = op2result.get( op );
1144 if( result != null ) {
1145 return (ReachState) result;
1148 // this is the current mapping, where 0, 1, 2S were allocated
1149 // in the current context, 0?, 1? and 2S? were allocated in a
1150 // previous context, and we're translating to a future context
1156 // otherwise, no cached result...
1157 ReachState out = ReachState.factory();
1158 Iterator<ReachTuple> itr = state.iterator();
1159 while( itr.hasNext() ) {
1160 ReachTuple rt = itr.next();
1162 int age = as.getShadowAgeCategory( rt.getHrnID() );
1164 if( age == AllocSite.SHADOWAGE_notInThisSite ) {
1165 // things not from the site just go back in
1166 out = Canonical.add( out, rt );
1169 assert !rt.isOutOfContext();
1171 // otherwise unshadow it
1172 out = Canonical.add( out,
1173 ReachTuple.factory( -rt.getHrnID(),
1182 out = Canonical.attach( out,
1186 assert out.isCanonical();
1187 op2result.put( op, out );
1193 public static ReachState makePredsTrue( ReachState rs ) {
1195 assert rs.isCanonical();
1197 // ops require two canonicals, in this case always supply
1198 // the empty reach state as the second, it's never used,
1199 // but makes the hashing happy
1201 new CanonicalOp( CanonicalOp.REACHSTATE_MAKEPREDSTRUE,
1203 ReachState.factory() );
1205 Canonical result = op2result.get( op );
1206 if( result != null ) {
1207 return (ReachState) result;
1210 // otherwise, no cached result...
1211 ReachState out = new ReachState();
1213 // just remake state with the true predicate attached
1214 out.reachTuples.addAll( rs.reachTuples );
1215 out.preds = ExistPredSet.factory( ExistPred.factory() );
1217 out = (ReachState) makeCanonical( out );
1218 op2result.put( op, out );
1223 public static ReachSet makePredsTrue( ReachSet rs ) {
1225 assert rs.isCanonical();
1227 // ops require two canonicals, in this case always supply
1228 // the empty reach set as the second, it's never used,
1229 // but makes the hashing happy
1231 new CanonicalOp( CanonicalOp.REACHSET_MAKEPREDSTRUE,
1233 ReachSet.factory() );
1235 Canonical result = op2result.get( op );
1236 if( result != null ) {
1237 return (ReachSet) result;
1240 // otherwise, no cached result...
1241 ReachSet out = ReachSet.factory();
1242 Iterator<ReachState> itr = rs.iterator();
1243 while( itr.hasNext() ) {
1244 ReachState state = itr.next();
1245 out = Canonical.add( out,
1246 Canonical.makePredsTrue( state )
1250 out = (ReachSet) makeCanonical( out );
1251 op2result.put( op, out );
1256 public static Taint attach( Taint t,
1257 ExistPredSet preds ) {
1259 assert preds != null;
1260 assert t.isCanonical();
1261 assert preds.isCanonical();
1264 new CanonicalOp( CanonicalOp.TAINT_ATTACH_EXISTPREDSET,
1268 Canonical result = op2result.get( op );
1269 if( result != null ) {
1270 return (Taint) result;
1273 // otherwise, no cached result...
1274 Taint out = new Taint( t );
1275 out.preds = Canonical.join( t.preds,
1278 out = (Taint) makeCanonical( out );
1279 op2result.put( op, out );
1283 public static TaintSet add( TaintSet ts,
1287 assert ts.isCanonical();
1288 assert t.isCanonical();
1291 new CanonicalOp( CanonicalOp.TAINTSET_ADD_TAINT,
1295 Canonical result = op2result.get( op );
1296 if( result != null ) {
1297 return (TaintSet) result;
1300 // otherwise, no cached result...
1301 TaintSet out = new TaintSet();
1302 out.taints.addAll( ts.taints );
1303 out.taints.add( t );
1305 out = (TaintSet) makeCanonical( out );
1306 op2result.put( op, out );
1310 public static TaintSet union( TaintSet ts1,
1314 assert ts1.isCanonical();
1315 assert ts2.isCanonical();
1318 new CanonicalOp( CanonicalOp.TAINTSET_UNION_TAINTSET,
1322 Canonical result = op2result.get( op );
1323 if( result != null ) {
1324 return (TaintSet) result;
1327 // otherwise, no cached result...
1328 TaintSet out = new TaintSet();
1330 // first add everything from 1, and if it was also in 2
1331 // take the OR of the predicates
1332 Iterator<Taint> tItr = ts1.iterator();
1333 while( tItr.hasNext() ) {
1334 Taint t1 = tItr.next();
1335 Taint t2 = ts2.containsIgnorePreds( t1 );
1338 Taint tNew = new Taint( t1 );
1339 tNew.preds = Canonical.join( t1.preds,
1342 tNew = (Taint) makeCanonical( tNew );
1343 out.taints.add( tNew );
1345 out.taints.add( t1 );
1349 // then add everything in 2 that wasn't in 1
1350 tItr = ts2.iterator();
1351 while( tItr.hasNext() ) {
1352 Taint t2 = tItr.next();
1353 Taint t1 = ts1.containsIgnorePreds( t2 );
1356 out.taints.add( t2 );
1360 out = (TaintSet) makeCanonical( out );
1361 op2result.put( op, out );
1365 public static TaintSet unionORpreds( TaintSet ts1,
1369 assert ts1.isCanonical();
1370 assert ts2.isCanonical();
1373 new CanonicalOp( CanonicalOp.TAINTSET_UNIONORPREDS_TAINTSET,
1377 Canonical result = op2result.get( op );
1378 if( result != null ) {
1379 return (TaintSet) result;
1382 // otherwise, no cached result...
1383 TaintSet out = new TaintSet();
1385 // first add everything from 1, and if it was also in 2
1386 // take the OR of the predicates
1387 Iterator<Taint> tItr = ts1.iterator();
1388 while( tItr.hasNext() ) {
1389 Taint t1 = tItr.next();
1390 Taint t2 = ts2.containsIgnorePreds( t1 );
1393 Taint tNew = new Taint( t1 );
1394 tNew.preds = Canonical.join( t1.preds,
1397 tNew = (Taint) makeCanonical( tNew );
1398 out.taints.add( tNew );
1400 out.taints.add( t1 );
1404 // then add everything in 2 that wasn't in 1
1405 tItr = ts2.iterator();
1406 while( tItr.hasNext() ) {
1407 Taint t2 = tItr.next();
1408 Taint t1 = ts1.containsIgnorePreds( t2 );
1411 out.taints.add( t2 );
1415 out = (TaintSet) makeCanonical( out );
1416 op2result.put( op, out );
1421 // BOO, HISS! SESE (rblock) operand does NOT extend
1422 // Canonical, so we can't cache this op by its
1423 // canonical arguments--THINK ABOUT A BETTER WAY!
1424 public static TaintSet removeTaintsBy( TaintSet ts,
1425 FlatSESEEnterNode sese ) {
1427 assert ts.isCanonical();
1428 assert sese != null;
1430 // NEVER a cached result... (cry)
1431 TaintSet out = new TaintSet();
1433 Iterator<Taint> tItr = ts.iterator();
1434 while( tItr.hasNext() ) {
1435 Taint t = tItr.next();
1437 if( !t.getSESE().equals( sese ) ) {
1438 out.taints.add( t );
1442 out = (TaintSet) makeCanonical( out );
1443 //op2result.put( op, out ); CRY CRY
1448 public static Taint changePredsTo( Taint t, ExistPredSet preds ) {
1450 assert t.isCanonical();
1452 // ops require two canonicals, in this case always supply
1453 // the empty reach state as the second, it's never used,
1454 // but makes the hashing happy
1456 new CanonicalOp( CanonicalOp.TAINT_CHANGEPREDSTO,
1460 Canonical result = op2result.get( op );
1461 if( result != null ) {
1462 return (Taint) result;
1465 // otherwise, no cached result...
1466 Taint out = new Taint( t.sese,
1473 out = (Taint) makeCanonical( out );
1474 op2result.put( op, out );
1479 public static TaintSet changePredsTo( TaintSet ts, ExistPredSet preds ) {
1481 assert ts.isCanonical();
1483 // ops require two canonicals, in this case always supply
1484 // the empty reach set as the second, it's never used,
1485 // but makes the hashing happy
1487 new CanonicalOp( CanonicalOp.TAINTSET_CHANGEPREDSTO,
1491 Canonical result = op2result.get( op );
1492 if( result != null ) {
1493 return (TaintSet) result;
1496 // otherwise, no cached result...
1497 TaintSet out = TaintSet.factory();
1498 Iterator<Taint> itr = ts.iterator();
1499 while( itr.hasNext() ) {
1500 Taint t = itr.next();
1501 out = Canonical.add( out,
1502 Canonical.changePredsTo( t, preds )
1506 out = (TaintSet) makeCanonical( out );
1507 op2result.put( op, out );