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