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