my changes
[IRC.git] / Robust / src / Analysis / Locality / LocalityAnalysis.java
1 package Analysis.Locality;
2
3 import java.util.*;
4 import Analysis.CallGraph.CallGraph;
5 import IR.SymbolTable;
6 import IR.State;
7 import IR.TypeUtil;
8 import IR.MethodDescriptor;
9 import IR.Flat.*;
10 import IR.ClassDescriptor;
11
12 public class LocalityAnalysis {
13     State state;
14     Stack lbtovisit;
15     Hashtable<LocalityBinding,LocalityBinding> discovered;
16     Hashtable<LocalityBinding, Set<LocalityBinding>> dependence;
17     Hashtable<LocalityBinding, Hashtable<FlatNode,Hashtable<TempDescriptor, Integer>>> temptab;
18     Hashtable<LocalityBinding, Hashtable<FlatNode, Integer>> atomictab;
19     Hashtable<LocalityBinding, Hashtable<FlatAtomicEnterNode, Set<TempDescriptor>>> tempstosave;
20     Hashtable<ClassDescriptor, Set<LocalityBinding>> classtolb;
21     Hashtable<MethodDescriptor, Set<LocalityBinding>> methodtolb;
22     private LocalityBinding lbmain;
23
24     CallGraph callgraph;
25     TypeUtil typeutil;
26     public static final Integer LOCAL=new Integer(0);
27     public static final Integer GLOBAL=new Integer(1);
28     public static final Integer EITHER=new Integer(2);
29     public static final Integer CONFLICT=new Integer(3);
30
31     public LocalityAnalysis(State state, CallGraph callgraph, TypeUtil typeutil) {
32         this.typeutil=typeutil;
33         this.state=state;
34         this.discovered=new Hashtable<LocalityBinding,LocalityBinding>();
35         this.dependence=new Hashtable<LocalityBinding, Set<LocalityBinding>>();
36         this.temptab=new Hashtable<LocalityBinding, Hashtable<FlatNode,Hashtable<TempDescriptor, Integer>>>();
37         this.atomictab=new Hashtable<LocalityBinding, Hashtable<FlatNode, Integer>>();
38         this.lbtovisit=new Stack();
39         this.callgraph=callgraph;
40         this.tempstosave=new Hashtable<LocalityBinding, Hashtable<FlatAtomicEnterNode, Set<TempDescriptor>>>();
41         this.classtolb=new Hashtable<ClassDescriptor, Set<LocalityBinding>>();
42         this.methodtolb=new Hashtable<MethodDescriptor, Set<LocalityBinding>>();
43         doAnalysis();
44     }
45
46     public LocalityBinding getMain() {
47         return lbmain;
48     }
49
50     /** This method returns the set of LocalityBindings that a given
51      * flatcall could invoke */
52
53     public LocalityBinding getBinding(LocalityBinding currlb, FlatCall fc) {
54         boolean isatomic=getAtomic(currlb).get(fc).intValue()>0;
55         Hashtable<TempDescriptor, Integer> currtable=getNodeTempInfo(currlb).get(fc);
56         MethodDescriptor md=fc.getMethod();
57         
58         boolean isnative=md.getModifiers().isNative();
59         
60         LocalityBinding lb=new LocalityBinding(md, isatomic);
61         
62         for(int i=0;i<fc.numArgs();i++) {
63             TempDescriptor arg=fc.getArg(i);
64             lb.setGlobal(i,currtable.get(arg));
65         }
66         if (fc.getThis()!=null) {
67             Integer thistype=currtable.get(fc.getThis());
68             if (thistype==null)
69                 thistype=EITHER;
70             lb.setGlobalThis(thistype);
71         } else
72             lb.setGlobalThis(EITHER);//default value
73         if (discovered.containsKey(lb))
74             lb=discovered.get(lb);
75         else throw new Error();
76         return lb;
77     }
78
79
80     /** This method returns a set of LocalityBindings for the parameter class. */
81         
82     public Set<LocalityBinding> getClassBindings(ClassDescriptor cd) {
83         return classtolb.get(cd);
84     }
85
86     /** This method returns a set of LocalityBindings for the parameter method. */
87         
88     public Set<LocalityBinding> getMethodBindings(MethodDescriptor md) {
89         return methodtolb.get(md);
90     }
91
92     /** This method returns a set of LocalityBindings.  A
93      * LocalityBinding specifies a context a method can be invoked in.
94      * It specifies whether the method is in a transaction and whether
95      * its parameter objects are locals or globals.  */
96
97     public Set<LocalityBinding> getLocalityBindings() {
98         return discovered.keySet();
99     }
100
101     /** This method returns a hashtable for a given LocalityBinding
102      * that tells the current local/global status of temps at the each
103      * node in the flat representation. */
104
105     public Hashtable<FlatNode, Hashtable<TempDescriptor, Integer>> getNodeTempInfo(LocalityBinding lb) {
106         return temptab.get(lb);
107     }
108
109     /** This method returns an hashtable for a given LocalitBinding
110      * that tells whether a node in the flat represenation is in a
111      * transaction or not.  Integer values greater than 0 indicate
112      * that the node is in a transaction and give the nesting depth.
113      * The outermost AtomicEnterNode will have a value of 1 and the
114      * outermost AtomicExitNode will have a value of 0. */
115     
116     public Hashtable<FlatNode, Integer> getAtomic(LocalityBinding lb) {
117         return atomictab.get(lb);
118     }
119
120     /** This methods returns a hashtable for a given LocalityBinding
121      * that tells which temps needs to be saved for each
122      * AtomicEnterNode.  */
123
124     public Hashtable<FlatAtomicEnterNode, Set<TempDescriptor>> getTemps(LocalityBinding lb) {
125         return tempstosave.get(lb);
126     }
127
128     public Set<TempDescriptor> getTempSet(LocalityBinding lb) {
129         HashSet<TempDescriptor> set=new HashSet<TempDescriptor>();
130         Hashtable<FlatAtomicEnterNode, Set<TempDescriptor>> table=getTemps(lb);
131         if (table!=null)
132             for(Iterator<FlatAtomicEnterNode> faenit=table.keySet().iterator();faenit.hasNext();) {
133                 FlatAtomicEnterNode faen=faenit.next();
134                 set.addAll(table.get(faen));
135             }
136         return set;
137     }
138
139     private void doAnalysis() {
140         computeLocalityBindings();
141         computeTempstoSave();
142     }
143     
144     private void computeLocalityBindings() {
145         lbmain=new LocalityBinding(typeutil.getMain(), false);
146         lbmain.setGlobal(0, LOCAL);
147         lbtovisit.add(lbmain);
148         discovered.put(lbmain, lbmain);
149         if (!classtolb.containsKey(lbmain.getMethod().getClassDesc()))
150             classtolb.put(lbmain.getMethod().getClassDesc(), new HashSet<LocalityBinding>());
151         classtolb.get(lbmain.getMethod().getClassDesc()).add(lbmain);
152
153         if (!methodtolb.containsKey(lbmain.getMethod()))
154             methodtolb.put(lbmain.getMethod(), new HashSet<LocalityBinding>());
155         methodtolb.get(lbmain.getMethod()).add(lbmain);
156
157         while(!lbtovisit.empty()) {
158             LocalityBinding lb=(LocalityBinding) lbtovisit.pop();
159             Integer returnglobal=lb.getGlobalReturn();
160             MethodDescriptor md=lb.getMethod();
161             Hashtable<FlatNode,Hashtable<TempDescriptor, Integer>> temptable=new Hashtable<FlatNode,Hashtable<TempDescriptor, Integer>>();
162             Hashtable<FlatNode, Integer> atomictable=new Hashtable<FlatNode, Integer>();
163             computeCallsFlags(md, lb, temptable, atomictable);
164             atomictab.put(lb, atomictable);
165             temptab.put(lb, temptable);
166
167             if (!md.isStatic()&&!returnglobal.equals(lb.getGlobalReturn())) {
168                 //return type is more precise now
169                 //rerun everything that call us
170                 lbtovisit.addAll(dependence.get(lb));
171             }
172         }
173     }
174
175
176     public void computeCallsFlags(MethodDescriptor md, LocalityBinding lb, Hashtable<FlatNode, Hashtable<TempDescriptor, Integer>> temptable, Hashtable<FlatNode, Integer> atomictable) {
177         FlatMethod fm=state.getMethodFlat(md);
178         HashSet<FlatNode> tovisit=new HashSet<FlatNode>();
179         tovisit.add(fm.getNext(0));
180         {
181             // Build table for initial node
182             Hashtable<TempDescriptor,Integer> table=new Hashtable<TempDescriptor,Integer>();
183             temptable.put(fm, table);
184             atomictable.put(fm, lb.isAtomic()?1:0);
185             int offset=md.isStatic()?0:1;
186             if (!md.isStatic()) {
187                 table.put(fm.getParameter(0), lb.getGlobalThis());
188             }
189             for(int i=offset;i<fm.numParameters();i++) {
190                 TempDescriptor temp=fm.getParameter(i);
191                 Integer b=lb.isGlobal(i-offset);
192                 table.put(temp,b);
193             }
194         }
195
196         while(!tovisit.isEmpty()) {
197             FlatNode fn=tovisit.iterator().next();
198             tovisit.remove(fn);
199             Hashtable<TempDescriptor, Integer> currtable=new Hashtable<TempDescriptor, Integer>();
200             int atomicstate=0;
201             for(int i=0;i<fn.numPrev();i++) {
202                 FlatNode prevnode=fn.getPrev(i);
203                 if (atomictable.containsKey(prevnode)) {
204                     atomicstate=atomictable.get(prevnode).intValue();
205                 }
206                 if (!temptable.containsKey(prevnode))
207                     continue;
208                 Hashtable<TempDescriptor, Integer> prevtable=temptable.get(prevnode);
209                 for(Iterator<TempDescriptor> tempit=prevtable.keySet().iterator();tempit.hasNext();) {
210                     TempDescriptor temp=tempit.next();
211                     Integer tmpint=prevtable.get(temp);
212                     Integer oldint=currtable.containsKey(temp)?currtable.get(temp):EITHER;
213                     Integer newint=merge(tmpint, oldint);
214                     currtable.put(temp, newint);
215                 }
216             }
217             atomictable.put(fn, atomicstate);
218             // Process this node
219             switch(fn.kind()) {
220             case FKind.FlatAtomicEnterNode:
221                 processAtomicEnterNode((FlatAtomicEnterNode)fn, atomictable);
222                 if (!lb.isAtomic())
223                     lb.setHasAtomic();
224                 break;
225             case FKind.FlatAtomicExitNode:
226                 processAtomicExitNode((FlatAtomicExitNode)fn, atomictable);
227                 break;
228             case FKind.FlatCall:
229                 processCallNode(lb, (FlatCall)fn, currtable, isAtomic(atomictable, fn));
230                 break;
231             case FKind.FlatFieldNode:
232                 processFieldNode(lb, (FlatFieldNode)fn, isAtomic(atomictable, fn), currtable);
233                 break;
234             case FKind.FlatSetFieldNode:
235                 processSetFieldNode(lb, (FlatSetFieldNode)fn, isAtomic(atomictable,fn), currtable);
236                 break;
237             case FKind.FlatNew:
238                 processNew(lb, (FlatNew)fn, isAtomic(atomictable, fn), currtable);
239                 break;
240             case FKind.FlatOpNode:
241                 processOpNode((FlatOpNode)fn, currtable);
242                 break;
243             case FKind.FlatCastNode:
244                 processCastNode((FlatCastNode)fn, currtable);
245                 break;
246             case FKind.FlatLiteralNode:
247                 processLiteralNode((FlatLiteralNode)fn, currtable);
248                 break;
249             case FKind.FlatReturnNode:
250                 processReturnNode(lb, (FlatReturnNode)fn, currtable);
251                 break;
252             case FKind.FlatSetElementNode:
253                 processSetElementNode(lb, (FlatSetElementNode)fn, currtable, isAtomic(atomictable, fn));
254                 break;
255             case FKind.FlatElementNode:
256                 processElementNode(lb, (FlatElementNode)fn, currtable, isAtomic(atomictable, fn));
257                 break;
258             case FKind.FlatCondBranch:
259             case FKind.FlatBackEdge:
260             case FKind.FlatNop:
261                 //No action needed for these
262                 break;
263             case FKind.FlatFlagActionNode:
264             case FKind.FlatCheckNode:
265             case FKind.FlatTagDeclaration:
266                 throw new Error("Incompatible with tasks!");
267             case FKind.FlatMethod:
268             default:
269                 throw new Error();
270             }
271             Hashtable<TempDescriptor,Integer> oldtable=temptable.get(fn);
272             if (oldtable==null||!oldtable.equals(currtable)) {
273                 // Update table for this node
274                 temptable.put(fn, currtable);
275                 for(int i=0;i<fn.numNext();i++) {
276                     tovisit.add(fn.getNext(i));
277                 }
278             }
279         }
280     }
281
282     private static boolean isAtomic(Hashtable<FlatNode, Integer> atomictable, FlatNode fn) {
283         return atomictable.get(fn).intValue()>0;
284     }
285
286     private static Integer merge(Integer a, Integer b) {
287         if (a==null||a.equals(EITHER))
288             return b;
289         if (b==null||b.equals(EITHER))
290             return a;
291         if (a.equals(b))
292             return a;
293         return CONFLICT;
294     }
295
296     void processCallNode(LocalityBinding currlb, FlatCall fc, Hashtable<TempDescriptor, Integer> currtable, boolean isatomic) {
297         MethodDescriptor nodemd=fc.getMethod();
298         Set methodset=null;
299         if (nodemd.isStatic()||nodemd.getReturnType()==null) {
300             methodset=new HashSet();
301             methodset.add(nodemd);
302         } else {
303             methodset=callgraph.getMethods(nodemd, fc.getThis().getType());
304         }
305         Integer currreturnval=EITHER; //Start off with the either value
306         for(Iterator methodit=methodset.iterator();methodit.hasNext();) {
307             MethodDescriptor md=(MethodDescriptor) methodit.next();
308             boolean isnative=md.getModifiers().isNative();
309
310             LocalityBinding lb=new LocalityBinding(md, isatomic);
311             if (isnative&&isatomic) {
312                 System.out.println("Don't call native methods in atomic blocks!");
313             }
314             for(int i=0;i<fc.numArgs();i++) {
315                 TempDescriptor arg=fc.getArg(i);
316                 if(isnative&&(currtable.get(arg).equals(GLOBAL)||
317                               currtable.get(arg).equals(CONFLICT)))
318                    throw new Error("Potential call to native method "+md+" with global parameter:\n"+currlb.getExplanation());
319                 lb.setGlobal(i,currtable.get(arg));
320             }
321             if (fc.getThis()!=null) {
322                 Integer thistype=currtable.get(fc.getThis());
323                 if (thistype==null)
324                     thistype=EITHER;
325                 if(thistype.equals(CONFLICT))
326                     throw new Error("Using type that can be either local or global in context:\n"+currlb.getExplanation());
327                 if(thistype.equals(GLOBAL)&&!isatomic)
328                     throw new Error("Using global object outside of transaction in context:\n"+currlb.getExplanation());
329                 if (isnative&&thistype.equals(GLOBAL))
330                     throw new Error("Potential call to native method "+md+" on global objects:\n"+currlb.getExplanation());
331                 lb.setGlobalThis(thistype);
332             } else
333                 lb.setGlobalThis(EITHER);//default value
334                 
335             //lb is built
336             if (!discovered.containsKey(lb)) {
337                 if (isnative)
338                     lb.setGlobalReturn(LOCAL);
339                 else
340                     lb.setGlobalReturn(EITHER);
341                 lb.setParent(currlb);
342                 lbtovisit.add(lb);
343                 discovered.put(lb, lb);
344                 if (!classtolb.containsKey(lb.getMethod().getClassDesc()))
345                     classtolb.put(lb.getMethod().getClassDesc(), new HashSet<LocalityBinding>());
346                 classtolb.get(lb.getMethod().getClassDesc()).add(lb);
347                 if (!methodtolb.containsKey(lb.getMethod()))
348                     methodtolb.put(lb.getMethod(), new HashSet<LocalityBinding>());
349                 methodtolb.get(lb.getMethod()).add(lb);
350             } else
351                 lb=discovered.get(lb);
352             Integer returnval=lb.getGlobalReturn();
353             currreturnval=merge(returnval, currreturnval);
354             if (!dependence.containsKey(lb))
355                 dependence.put(lb, new HashSet<LocalityBinding>());
356             dependence.get(lb).add(currlb);
357         }
358         if (fc.getReturnTemp()!=null) {
359             currtable.put(fc.getReturnTemp(), currreturnval);
360         }
361     }
362
363     void processFieldNode(LocalityBinding lb, FlatFieldNode ffn, boolean transaction, Hashtable<TempDescriptor, Integer> currtable) {
364         Integer type=currtable.get(ffn.getSrc());
365         TempDescriptor dst=ffn.getDst();
366         if (type.equals(LOCAL)) {
367             if (ffn.getField().isGlobal())
368                 currtable.put(dst,GLOBAL);
369             else
370                 currtable.put(dst,LOCAL);
371         } else if (type.equals(GLOBAL)) {
372             if (!transaction)
373                 throw new Error("Global access outside of a transaction in context:\n"+lb.getExplanation());
374             if (ffn.getField().getType().isPrimitive())
375                 currtable.put(dst, LOCAL); // primitives are local
376             else
377                 currtable.put(dst, GLOBAL);
378         } else if (type.equals(EITHER)) {
379             if (ffn.getField().getType().isPrimitive())
380                 currtable.put(dst, LOCAL); // primitives are local
381             else if (ffn.getField().isGlobal())
382                 currtable.put(dst, GLOBAL);
383             else
384                 currtable.put(dst, EITHER);
385         } else if (type.equals(CONFLICT)) {
386             throw new Error("Access to object that could be either global or local in context:\n"+lb.getExplanation());
387         }
388     }
389
390     //need to handle primitives
391     void processSetFieldNode(LocalityBinding lb, FlatSetFieldNode fsfn, boolean transaction, Hashtable<TempDescriptor, Integer> currtable) {
392         Integer srctype=currtable.get(fsfn.getSrc());
393         Integer dsttype=currtable.get(fsfn.getDst());
394         
395         if (dsttype.equals(LOCAL)) {
396             if (fsfn.getField().isGlobal()) {
397                 if (!(srctype.equals(GLOBAL)||srctype.equals(EITHER)))
398                     throw new Error("Writing possible local reference to global field in context: \n"+lb.getExplanation());
399             } else {
400                 if (!(srctype.equals(LOCAL)||srctype.equals(EITHER)))
401                     throw new Error("Writing possible global reference to local object in context: \n"+lb.getExplanation());
402             }
403         } else if (dsttype.equals(GLOBAL)) {
404             if (!transaction)
405                 throw new Error("Global access outside of a transaction in context:\n"+lb.getExplanation());
406             //okay to store primitives in global object
407             if (srctype.equals(LOCAL) && fsfn.getField().getType().isPrimitive())
408                 return;
409             if (!(srctype.equals(GLOBAL)||srctype.equals(EITHER)))
410                 throw new Error("Writing possible local reference to global object in context:\n"+lb.getExplanation());
411         } else if (dsttype.equals(EITHER)) {
412             if (srctype.equals(CONFLICT))
413                 throw new Error("Using reference that could be local or global in context:\n"+lb.getExplanation());
414         } else if (dsttype.equals(CONFLICT)) {
415             throw new Error("Access to object that could be either global or local in context:\n"+lb.getExplanation());
416         }
417     }
418
419     void processNew(LocalityBinding lb, FlatNew fn, boolean transaction, Hashtable<TempDescriptor, Integer> currtable) {
420         if (fn.isGlobal()&&!transaction) {
421             throw new Error("Allocating global object outside of transaction in context:"+lb.getExplanation());
422         }
423         if (fn.isGlobal())
424             currtable.put(fn.getDst(), GLOBAL);
425         else
426             currtable.put(fn.getDst(), LOCAL);
427     }
428
429     void processOpNode(FlatOpNode fon, Hashtable<TempDescriptor, Integer> currtable) {
430         /* Just propagate value */
431         currtable.put(fon.getDest(), currtable.get(fon.getLeft()));
432     }
433
434     void processCastNode(FlatCastNode fcn, Hashtable<TempDescriptor, Integer> currtable) {
435         currtable.put(fcn.getDst(), currtable.get(fcn.getSrc()));
436     }
437
438     void processLiteralNode(FlatLiteralNode fln, Hashtable<TempDescriptor, Integer> currtable) {
439         //null is either
440         if (fln.getValue()==null)
441             currtable.put(fln.getDst(), EITHER);
442         else
443             currtable.put(fln.getDst(), LOCAL);
444     }
445
446     void processReturnNode(LocalityBinding lb, FlatReturnNode frn, Hashtable<TempDescriptor, Integer> currtable) {
447         if(frn.getReturnTemp()!=null) {
448             Integer returntype=currtable.get(frn.getReturnTemp());
449             lb.setGlobalReturn(merge(returntype, lb.getGlobalReturn()));
450         }
451     }
452
453     void processSetElementNode(LocalityBinding lb, FlatSetElementNode fsen, Hashtable<TempDescriptor, Integer> currtable, boolean isatomic) {
454         Integer srctype=currtable.get(fsen.getSrc());
455         Integer dsttype=currtable.get(fsen.getDst());
456
457         if (dsttype.equals(LOCAL)) {
458             if (!(srctype.equals(LOCAL)||srctype.equals(EITHER)))
459                 throw new Error("Writing possible global reference to local object in context:\n"+lb.getExplanation());
460         } else if (dsttype.equals(GLOBAL)) {
461             if (!(srctype.equals(GLOBAL)||srctype.equals(EITHER)))
462                 throw new Error("Writing possible local reference to global object in context:\n"+lb.getExplanation());
463             if (!isatomic)
464                 throw new Error("Global access outside of a transaction in context:\n"+lb.getExplanation());
465         } else if (dsttype.equals(EITHER)) {
466             if (srctype.equals(CONFLICT))
467                 throw new Error("Using reference that could be local or global in context:\n"+lb.getExplanation());
468         } else if (dsttype.equals(CONFLICT)) {
469             throw new Error("Access to object that could be either global or local in context:\n"+lb.getExplanation());
470         }
471     }
472
473     void processElementNode(LocalityBinding lb, FlatElementNode fen, Hashtable<TempDescriptor, Integer> currtable, boolean isatomic) {
474         Integer type=currtable.get(fen.getSrc());
475         TempDescriptor dst=fen.getDst();
476         if (type.equals(LOCAL)) {
477             currtable.put(dst,LOCAL);
478         } else if (type.equals(GLOBAL)) {
479             if (!isatomic)
480                 throw new Error("Global access outside of a transaction in context:\n"+lb.getExplanation());
481             currtable.put(dst, GLOBAL);
482         } else if (type.equals(EITHER)) {
483             currtable.put(dst, EITHER);
484         } else if (type.equals(CONFLICT)) {
485             throw new Error("Access to object that could be either global or local in context:\n"+lb.getExplanation());
486         }
487     }
488
489     void processAtomicEnterNode(FlatAtomicEnterNode fen, Hashtable<FlatNode, Integer> atomictable) {
490         int atomic=atomictable.get(fen).intValue();
491         atomictable.put(fen, new Integer(atomic+1));
492     }
493
494     void processAtomicExitNode(FlatAtomicExitNode fen, Hashtable<FlatNode, Integer> atomictable) {
495         int atomic=atomictable.get(fen).intValue();
496         atomictable.put(fen, new Integer(atomic-1));
497     }
498
499     private Hashtable<FlatNode, Set<TempDescriptor>> computeLiveTemps(FlatMethod fm) {
500         Hashtable<FlatNode, Set<TempDescriptor>> nodetotemps=new Hashtable<FlatNode, Set<TempDescriptor>>();
501
502         Set<FlatNode> toprocess=fm.getNodeSet();
503
504         while(!toprocess.isEmpty()) {
505             FlatNode fn=toprocess.iterator().next();
506             toprocess.remove(fn);
507
508             List<TempDescriptor> reads=Arrays.asList(fn.readsTemps());
509             List<TempDescriptor> writes=Arrays.asList(fn.readsTemps());
510
511             HashSet<TempDescriptor> tempset=new HashSet<TempDescriptor>();
512             for(int i=0;i<fn.numNext();i++) {
513                 FlatNode fnnext=fn.getNext(i);
514                 if (nodetotemps.containsKey(fnnext))
515                     tempset.addAll(nodetotemps.get(fnnext));
516             }
517             tempset.removeAll(writes);
518             tempset.addAll(reads);
519             if (!nodetotemps.containsKey(fn)||
520                 nodetotemps.get(fn).equals(tempset)) {
521                 nodetotemps.put(fn, tempset);
522                 for(int i=0;i<fn.numPrev();i++)
523                     toprocess.add(fn.getPrev(i));
524             }
525         }
526         return nodetotemps;
527     }
528
529     private void computeTempstoSave() {
530         for(Iterator<LocalityBinding> lbit=getLocalityBindings().iterator();lbit.hasNext();) {
531             LocalityBinding lb=lbit.next();
532             computeTempstoSave(lb);
533         }
534     }
535
536     /* Need to checkpoint all temps that could be read from along any
537      * path that are either:
538        1) Written to by any assignment inside the transaction
539        2) Read from a global temp.
540
541        Generate tempstosave map from
542        localitybinding->flatatomicenternode->Set<TempDescriptors>
543     */
544
545     private void computeTempstoSave(LocalityBinding lb) {
546         if (lb.isAtomic())
547             return;
548         Hashtable<FlatNode, Integer> atomictab=getAtomic(lb);
549         Hashtable<FlatNode, Hashtable<TempDescriptor, Integer>> temptab=getNodeTempInfo(lb);
550         MethodDescriptor md=lb.getMethod();
551         FlatMethod fm=state.getMethodFlat(md);
552
553         Hashtable<FlatNode, Set<TempDescriptor>> nodetotemps=computeLiveTemps(fm);
554         Hashtable<FlatAtomicEnterNode, Set<TempDescriptor>> nodetosavetemps=new Hashtable<FlatAtomicEnterNode, Set<TempDescriptor>>();
555         tempstosave.put(lb, nodetosavetemps);
556
557         Hashtable<FlatNode, FlatAtomicEnterNode> nodemap=new Hashtable<FlatNode, FlatAtomicEnterNode>();
558         
559         HashSet<FlatNode> toprocess=new HashSet<FlatNode>();
560         HashSet<FlatNode> discovered=new HashSet<FlatNode>();
561         toprocess.add(fm);
562         discovered.add(fm);
563         while(!toprocess.isEmpty()) {
564             FlatNode fn=toprocess.iterator().next();
565             toprocess.remove(fn);
566             boolean isatomic=atomictab.get(fn).intValue()>0;
567             if (isatomic&&
568                 atomictab.get(fn.getPrev(0)).intValue()==0) {
569                 assert(fn.getPrev(0).kind()==FKind.FlatAtomicEnterNode);
570                 nodemap.put(fn, (FlatAtomicEnterNode)fn);
571                 nodetosavetemps.put((FlatAtomicEnterNode)fn, new HashSet<TempDescriptor>());
572             } else if (isatomic) {
573                 FlatAtomicEnterNode atomicnode=nodemap.get(fn);
574                 Set<TempDescriptor> livetemps=nodetotemps.get(fn);
575                 List<TempDescriptor> reads=Arrays.asList(fn.readsTemps());
576                 List<TempDescriptor> writes=Arrays.asList(fn.readsTemps());
577
578                 for(Iterator<TempDescriptor> tempit=livetemps.iterator();tempit.hasNext();) {
579                     TempDescriptor tmp=tempit.next();
580                     if (writes.contains(tmp)) {
581                         nodetosavetemps.get(atomicnode).add(tmp);
582                     } else if (reads.contains(tmp)&&temptab.get(fn).get(tmp)==GLOBAL) {
583                         nodetosavetemps.get(atomicnode).add(tmp);
584                     }
585                 }
586             }
587             for(int i=0;i<fn.numNext();i++) {
588                 FlatNode fnnext=fn.getNext(i);
589                 if (!discovered.contains(fnnext)) {
590                     discovered.add(fnnext);
591                     toprocess.add(fnnext);
592                     if(isatomic) {
593                         nodemap.put(fnnext, nodemap.get(fn));
594                     }
595                 }
596             }
597         }
598     }
599 }