implementing
[IRC.git] / Robust / src / Analysis / Disjoint / ReachState.java
1 package Analysis.Disjoint;
2
3 import IR.*;
4 import IR.Flat.*;
5 import java.util.*;
6 import java.io.*;
7
8
9 public class ReachState extends Canonical {
10
11   private HashSet<ReachTuple> tokenTuples;
12
13
14   public ReachState() {
15     tokenTuples = new HashSet<ReachTuple>();
16   }
17
18   public ReachState(ReachTuple tt) {
19     this();
20     assert tt != null;
21     tokenTuples.add(tt);
22   }
23
24   public ReachState(ReachState tts) {
25     assert tts != null;
26     // okay to clone, ReachTuple and ReachState should be canonical
27     tokenTuples = (HashSet<ReachTuple>)tts.tokenTuples.clone();
28   }
29
30
31   public ReachState makeCanonical() {
32     return (ReachState) Canonical.makeCanonical(this);
33   }
34
35   public Iterator iterator() {
36     return tokenTuples.iterator();
37   }
38
39   public boolean isEmpty() {
40     return tokenTuples.isEmpty();
41   }
42
43   public boolean isSubset(ReachState ttsIn) {
44     assert ttsIn != null;
45     return ttsIn.tokenTuples.containsAll(this.tokenTuples);
46   }
47
48   public boolean containsTuple(ReachTuple tt) {
49     assert tt != null;
50     return tokenTuples.contains(tt);
51   }
52
53   public boolean containsBoth(ReachTuple tt1, ReachTuple tt2) {
54     return containsTuple(tt1) && containsTuple(tt2);
55   }
56
57   public boolean containsWithZeroes(ReachState tts) {
58     assert tts != null;
59
60     // first establish that every token tuple from tts is
61     // also in this set
62     Iterator<ReachTuple> ttItrIn = tts.iterator();
63     while( ttItrIn.hasNext() ) {
64       ReachTuple ttIn   = ttItrIn.next();
65       ReachTuple ttThis = this.containsToken(ttIn.getToken() );
66
67       if( ttThis == null ) {
68         return false;
69       }
70     }    
71     
72     // then establish that anything in this set that is
73     // not in tts is a zero-arity token tuple, which is okay    
74     Iterator<ReachTuple> ttItrThis = this.iterator();
75     while( ttItrThis.hasNext() ) {
76       ReachTuple ttThis = ttItrThis.next();
77       ReachTuple ttIn   = tts.containsToken(ttThis.getToken() );
78
79       if( ttIn == null && 
80           ttThis.getArity() != ReachTuple.ARITY_ZEROORMORE ) {
81         return false;
82       }
83     }    
84
85     // if so this set contains tts with zeroes
86     return true;
87   }
88
89   public ReachState union(ReachTuple ttIn) {
90     assert ttIn != null;
91     ReachOperation ro=new ReachOperation(this, ttIn);
92     if (unionhash.containsKey(ro))
93         return (ReachState) unionhash.get(ro).c;
94     else {
95         ReachState ttsOut = new ReachState(this);
96         ttsOut.tokenTuples.add(ttIn);
97         ro.c=ttsOut=ttsOut.makeCanonical();
98         unionhash.put(ro,ro);
99         return ttsOut;
100     }
101   }
102
103   public ReachState union(ReachState ttsIn) {
104     assert ttsIn != null;
105     ReachOperation ro=new ReachOperation(this, ttsIn);
106     if (unionhash.containsKey(ro)) {
107         return (ReachState) unionhash.get(ro).c;
108     } else {
109         ReachState ttsOut = new ReachState(this);
110         ttsOut.tokenTuples.addAll(ttsIn.tokenTuples);
111         ro.c=ttsOut=ttsOut.makeCanonical();
112         unionhash.put(ro,ro);
113         return ttsOut;
114     }
115   }
116
117
118   public ReachState unionUpArity(ReachState ttsIn) {
119     assert ttsIn != null;
120     ReachState ttsOut = new ReachState();
121
122     Iterator<ReachTuple> ttItr = this.iterator();
123     while( ttItr.hasNext() ) {
124       ReachTuple ttThis = ttItr.next();
125       ReachTuple ttIn   = ttsIn.containsToken(ttThis.getToken() );
126
127       if( ttIn != null ) {
128         ttsOut.tokenTuples.add(ttThis.unionArity(ttIn) );
129       } else {
130         ttsOut.tokenTuples.add(ttThis);
131       }
132     }
133
134     ttItr = ttsIn.iterator();
135     while( ttItr.hasNext() ) {
136       ReachTuple ttIn   = ttItr.next();
137       ReachTuple ttThis = ttsOut.containsToken(ttIn.getToken() );
138
139       if( ttThis == null ) {
140         ttsOut.tokenTuples.add(ttIn);
141       }
142     }
143
144     return ttsOut.makeCanonical();
145   }
146
147
148   public ReachState add(ReachTuple tt) {
149     assert tt != null;
150     return this.union(tt);
151   }
152
153
154   public ReachState remove(ReachTuple tt) {
155     assert tt != null;
156     ReachState ttsOut = new ReachState(this);
157     ttsOut.tokenTuples.remove(tt);
158     return ttsOut.makeCanonical();
159   }
160
161
162   public boolean equals(Object o) {
163     if( o == null ) {
164       return false;
165     }
166
167     if( !(o instanceof ReachState) ) {
168       return false;
169     }
170
171     ReachState tts = (ReachState) o;
172     return tokenTuples.equals(tts.tokenTuples);
173   }
174
175     boolean hashcodecomputed=false;
176     int ourhashcode=0;
177
178
179   public int hashCode() {
180       if (hashcodecomputed)
181           return ourhashcode;
182       else {
183           ourhashcode=tokenTuples.hashCode();
184           hashcodecomputed=true;
185           return ourhashcode;
186       }
187   }
188
189
190   // this should be a hash table so we can do this by key
191   public ReachTuple containsToken(Integer token) {
192     assert token != null;
193
194     Iterator itr = tokenTuples.iterator();
195     while( itr.hasNext() ) {
196       ReachTuple tt = (ReachTuple) itr.next();
197       if( token.equals(tt.getToken() ) ) {
198         return tt;
199       }
200     }
201     return null;
202   }
203
204
205   public ReachState ageTokens(AllocSite as) {
206     assert as != null;
207
208     ReachState ttsOut = new ReachState();
209
210     ReachTuple ttSummary = null;
211     ReachTuple ttOldest  = null;
212
213     Iterator itrT = this.iterator();
214     while( itrT.hasNext() ) {
215       ReachTuple tt = (ReachTuple) itrT.next();
216
217       Integer token = tt.getToken();
218       int age = as.getAgeCategory(token);
219
220       // tokens not associated with
221       // the site should be left alone
222       if( age == AllocSite.AGE_notInThisSite ) {
223         ttsOut.tokenTuples.add(tt);
224
225       } else if( age == AllocSite.AGE_summary ) {
226         // remember the summary tuple, but don't add it
227         // we may combine it with the oldest tuple
228         ttSummary = tt;
229
230       } else if( age == AllocSite.AGE_oldest ) {
231         // found an oldest token, again just remember
232         // for later
233         ttOldest = tt;
234
235       } else {
236         assert age == AllocSite.AGE_in_I;
237
238         Integer I = as.getAge(token);
239         assert I != null;
240
241         // otherwise, we change this token to the
242         // next older token
243         Integer tokenToChangeTo = as.getIthOldest(I + 1);
244         ReachTuple ttAged       = tt.changeTokenTo(tokenToChangeTo);
245         ttsOut.tokenTuples.add(ttAged);
246       }
247     }
248
249     // there are four cases to consider here
250     // 1. we found a summary tuple and no oldest tuple
251     //    Here we just pass the summary unchanged
252     // 2. we found an oldest tuple, no summary
253     //    Make a new, arity-one summary tuple
254     // 3. we found both a summary and an oldest
255     //    Merge them by arity
256     // 4. (not handled) we found neither, do nothing
257     if       ( ttSummary != null && ttOldest == null ) {
258       ttsOut.tokenTuples.add(ttSummary);
259
260     } else if( ttSummary == null && ttOldest != null ) {
261       ttsOut.tokenTuples.add(new ReachTuple(as.getSummary(),
262                                             true,
263                                             ttOldest.getArity()
264                                             ).makeCanonical()
265                              );
266
267     } else if( ttSummary != null && ttOldest != null ) {
268       ttsOut.tokenTuples.add(ttSummary.unionArity(new ReachTuple(as.getSummary(),
269                                                                  true,
270                                                                  ttOldest.getArity()
271                                                                  ).makeCanonical()
272                                                   )
273                              );
274     }
275
276     return ttsOut.makeCanonical();
277   }
278
279
280   public ReachState unshadowTokens(AllocSite as) {
281     assert as != null;
282
283     ReachState ttsOut = new ReachState();
284
285     ReachTuple ttSummary       = null;
286     ReachTuple ttShadowSummary = null;
287
288     Iterator itrT = this.iterator();
289     while( itrT.hasNext() ) {
290       ReachTuple tt = (ReachTuple) itrT.next();
291
292       Integer token = tt.getToken();
293       int shadowAge = as.getShadowAgeCategory(token);
294
295       if( shadowAge == AllocSite.AGE_summary ) {
296         // remember the summary tuple, but don't add it
297         // we may combine it with the oldest tuple
298         ttSummary = tt;
299
300       } else if( shadowAge == AllocSite.SHADOWAGE_notInThisSite ) {
301         ttsOut.tokenTuples.add(tt);
302
303       } else if( shadowAge == AllocSite.SHADOWAGE_summary ) {
304         // found the shadow summary token, again just remember
305         // for later
306         ttShadowSummary = tt;
307
308       } else if( shadowAge == AllocSite.SHADOWAGE_oldest ) {
309         Integer tokenToChangeTo = as.getOldest();
310         ReachTuple ttNormal = tt.changeTokenTo(tokenToChangeTo);
311         ttsOut.tokenTuples.add(ttNormal);
312
313       } else {
314         assert shadowAge == AllocSite.SHADOWAGE_in_I;
315
316         Integer I = as.getShadowAge(token);
317         assert I != null;
318
319         Integer tokenToChangeTo = as.getIthOldest(-I);
320         ReachTuple ttNormal = tt.changeTokenTo(tokenToChangeTo);
321         ttsOut.tokenTuples.add(ttNormal);
322       }
323     }
324
325     if       ( ttSummary != null && ttShadowSummary == null ) {
326       ttsOut.tokenTuples.add(ttSummary);
327
328     } else if( ttSummary == null && ttShadowSummary != null ) {
329       ttsOut.tokenTuples.add(new ReachTuple(as.getSummary(),
330                                             true,
331                                             ttShadowSummary.getArity()
332                                             ).makeCanonical()
333                              );
334
335     } else if( ttSummary != null && ttShadowSummary != null ) {
336       ttsOut.tokenTuples.add(ttSummary.unionArity(new ReachTuple(as.getSummary(),
337                                                                  true,
338                                                                  ttShadowSummary.getArity()
339                                                                  ).makeCanonical()
340                                                   )
341                              );
342     }
343
344     return ttsOut.makeCanonical();
345   }
346
347
348   public ReachState toShadowTokens(AllocSite as) {
349     assert as != null;
350
351     ReachState ttsOut = new ReachState().makeCanonical();
352
353     Iterator itrT = this.iterator();
354     while( itrT.hasNext() ) {
355       ReachTuple tt = (ReachTuple) itrT.next();
356
357       Integer token = tt.getToken();
358       int age = as.getAgeCategory(token);
359
360       // summary tokens and tokens not associated with
361       // the site should be left alone
362       if( age == AllocSite.AGE_notInThisSite ) {
363         ttsOut = ttsOut.union(tt);
364
365       } else if( age == AllocSite.AGE_summary ) {
366         ttsOut = ttsOut.union(tt.changeTokenTo(as.getSummaryShadow() ));
367
368       } else if( age == AllocSite.AGE_oldest ) {
369         ttsOut = ttsOut.union(tt.changeTokenTo(as.getOldestShadow() ));
370
371       } else {
372         assert age == AllocSite.AGE_in_I;
373
374         Integer I = as.getAge(token);
375         assert I != null;
376
377         ttsOut = ttsOut.union(tt.changeTokenTo(as.getIthOldestShadow(I) ));
378       }
379     }
380
381     return ttsOut.makeCanonical();
382   }
383
384
385   public ReachSet rewriteToken(ReachTuple tokenToRewrite,
386                                       ReachSet replacements,
387                                       boolean makeChangeSet,
388                                       Hashtable<ReachState, HashSet<ReachState> > forChangeSet) {
389
390     ReachSet rsOut = new ReachSet().makeCanonical();
391
392     if( !tokenTuples.contains(tokenToRewrite) ) {
393       rsOut = rsOut.add(this);
394
395     } else {
396       ReachState ttsMinusToken = new ReachState(this);
397       ttsMinusToken.tokenTuples.remove(tokenToRewrite);
398
399       Iterator<ReachState> replaceItr = replacements.iterator();
400       while( replaceItr.hasNext() ) {
401         ReachState replacement = replaceItr.next();
402         ReachState replaced = new ReachState(ttsMinusToken).makeCanonical();
403         replaced = replaced.unionUpArity(replacement);
404         rsOut = rsOut.add(replaced);
405
406         if( makeChangeSet ) {
407           assert forChangeSet != null;
408
409           if( forChangeSet.get(this) == null ) {
410             forChangeSet.put(this, new HashSet<ReachState>() );
411           }
412
413           forChangeSet.get(this).add(replaced);
414         }
415       }
416     }
417
418     return rsOut.makeCanonical();
419   }
420
421
422   public ReachState makeArityZeroOrMore() {
423     ReachState ttsOut = new ReachState().makeCanonical();
424
425     Iterator<ReachTuple> itrThis = this.iterator();
426     while( itrThis.hasNext() ) {
427       ReachTuple tt = itrThis.next();
428
429       ttsOut = ttsOut.union(new ReachTuple(tt.getToken(),
430                                            tt.isMultiObject(),
431                                            ReachTuple.ARITY_ZEROORMORE
432                                            ).makeCanonical()
433                             );
434     }
435
436     return ttsOut.makeCanonical();
437   }
438
439   public String toString() {
440     return tokenTuples.toString();
441   }
442 }