Starting remote thread : Just test
[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         Set runmethodset=null;
321         if (nodemd.isStatic()||nodemd.getReturnType()==null) {
322             methodset=new HashSet();
323             methodset.add(nodemd);
324         } else {
325             methodset=callgraph.getMethods(nodemd, fc.getThis().getType());
326             // Build start -> run link
327             if (nodemd.getClassDesc().getSymbol().equals(TypeUtil.ThreadClass)&&
328                 nodemd.getSymbol().equals("start")&&!nodemd.getModifiers().isStatic()&&
329                 nodemd.numParameters()==1&&nodemd.getParamType(0).isInt()) {
330                 assert(nodemd.getModifiers().isNative());
331                 
332                 MethodDescriptor runmd=null;
333                 for(Iterator methodit=nodemd.getClassDesc().getMethodTable().getSet("run").iterator();methodit.hasNext();) {
334                     MethodDescriptor md=(MethodDescriptor) methodit.next();
335                     if (md.numParameters()!=0||md.getModifiers().isStatic())
336                         continue;
337                     runmd=md;
338                     break;
339                 }
340                 if (runmd!=null) {
341                     runmethodset=callgraph.getMethods(runmd,fc.getThis().getType());
342                     methodset.addAll(runmethodset);
343                 } else throw new Error("Can't find run method");
344             }
345         }
346         Integer currreturnval=EITHER; //Start off with the either value
347         for(Iterator methodit=methodset.iterator();methodit.hasNext();) {
348             MethodDescriptor md=(MethodDescriptor) methodit.next();
349             boolean isnative=md.getModifiers().isNative();
350
351             LocalityBinding lb=new LocalityBinding(md, isatomic);
352             if (isnative&&isatomic) {
353                 System.out.println("Don't call native methods in atomic blocks!");
354             }
355             if (runmethodset==null||!runmethodset.contains(md)) {
356                 //Skip this part if it is a run method
357                 for(int i=0;i<fc.numArgs();i++) {
358                     TempDescriptor arg=fc.getArg(i);
359                     if(isnative&&(currtable.get(arg).equals(GLOBAL)||
360                                   currtable.get(arg).equals(CONFLICT)))
361                         throw new Error("Potential call to native method "+md+" with global parameter:\n"+currlb.getExplanation());
362                     lb.setGlobal(i,currtable.get(arg));
363                 }
364             }
365
366
367             if (fc.getThis()!=null) {
368                 Integer thistype=currtable.get(fc.getThis());
369                 if (thistype==null)
370                     thistype=EITHER;
371
372                 if(runmethodset!=null&&runmethodset.contains(md)&&thistype.equals(LOCAL))
373                     throw new Error("Starting thread on local object not allowed in context:\n"+currlb.getExplanation());
374                 if(thistype.equals(CONFLICT))
375                     throw new Error("Using type that can be either local or global in context:\n"+currlb.getExplanation());
376                 if(runmethodset==null&&thistype.equals(GLOBAL)&&!isatomic)
377                     throw new Error("Using global object outside of transaction in context:\n"+currlb.getExplanation());
378                 if (runmethodset==null&&isnative&&thistype.equals(GLOBAL))
379                     throw new Error("Potential call to native method "+md+" on global objects:\n"+currlb.getExplanation());
380                 lb.setGlobalThis(thistype);
381             } 
382             //lb is built
383             if (!discovered.containsKey(lb)) {
384                 if (isnative)
385                     lb.setGlobalReturn(LOCAL);
386                 else
387                     lb.setGlobalReturn(EITHER);
388                 lb.setParent(currlb);
389                 lbtovisit.add(lb);
390                 discovered.put(lb, lb);
391                 if (!classtolb.containsKey(lb.getMethod().getClassDesc()))
392                     classtolb.put(lb.getMethod().getClassDesc(), new HashSet<LocalityBinding>());
393                 classtolb.get(lb.getMethod().getClassDesc()).add(lb);
394                 if (!methodtolb.containsKey(lb.getMethod()))
395                     methodtolb.put(lb.getMethod(), new HashSet<LocalityBinding>());
396                 methodtolb.get(lb.getMethod()).add(lb);
397             } else
398                 lb=discovered.get(lb);
399             Integer returnval=lb.getGlobalReturn();
400             currreturnval=merge(returnval, currreturnval);
401             if (!dependence.containsKey(lb))
402                 dependence.put(lb, new HashSet<LocalityBinding>());
403             dependence.get(lb).add(currlb);
404         }
405         if (fc.getReturnTemp()!=null) {
406             currtable.put(fc.getReturnTemp(), currreturnval);
407         }
408     }
409
410     void processFieldNode(LocalityBinding lb, FlatFieldNode ffn, boolean transaction, Hashtable<TempDescriptor, Integer> currtable) {
411         Integer type=currtable.get(ffn.getSrc());
412         TempDescriptor dst=ffn.getDst();
413         if (type.equals(LOCAL)) {
414             if (ffn.getField().isGlobal())
415                 currtable.put(dst,GLOBAL);
416             else
417                 currtable.put(dst,LOCAL);
418         } else if (type.equals(GLOBAL)) {
419             if (!transaction)
420                 throw new Error("Global access outside of a transaction in context:\n"+lb.getExplanation());
421             if (ffn.getField().getType().isPrimitive())
422                 currtable.put(dst, LOCAL); // primitives are local
423             else
424                 currtable.put(dst, GLOBAL);
425         } else if (type.equals(EITHER)) {
426             if (ffn.getField().getType().isPrimitive())
427                 currtable.put(dst, LOCAL); // primitives are local
428             else if (ffn.getField().isGlobal())
429                 currtable.put(dst, GLOBAL);
430             else
431                 currtable.put(dst, EITHER);
432         } else if (type.equals(CONFLICT)) {
433             throw new Error("Access to object that could be either global or local in context:\n"+lb.getExplanation());
434         }
435     }
436
437     //need to handle primitives
438     void processSetFieldNode(LocalityBinding lb, FlatSetFieldNode fsfn, boolean transaction, Hashtable<TempDescriptor, Integer> currtable) {
439         Integer srctype=currtable.get(fsfn.getSrc());
440         Integer dsttype=currtable.get(fsfn.getDst());
441         
442         if (dsttype.equals(LOCAL)) {
443             if (fsfn.getField().isGlobal()) {
444                 if (!(srctype.equals(GLOBAL)||srctype.equals(EITHER)))
445                     throw new Error("Writing possible local reference to global field in context: \n"+lb.getExplanation());
446             } else {
447                 if (!(srctype.equals(LOCAL)||srctype.equals(EITHER)))
448                     throw new Error("Writing possible global reference to local object in context: \n"+lb.getExplanation());
449             }
450         } else if (dsttype.equals(GLOBAL)) {
451             if (!transaction)
452                 throw new Error("Global access outside of a transaction in context:\n"+lb.getExplanation());
453             //okay to store primitives in global object
454             if (srctype.equals(LOCAL) && fsfn.getField().getType().isPrimitive())
455                 return;
456             if (!(srctype.equals(GLOBAL)||srctype.equals(EITHER)))
457                 throw new Error("Writing possible local reference to global object in context:\n"+lb.getExplanation());
458         } else if (dsttype.equals(EITHER)) {
459             if (srctype.equals(CONFLICT))
460                 throw new Error("Using reference that could be local or global in context:\n"+lb.getExplanation());
461         } else if (dsttype.equals(CONFLICT)) {
462             throw new Error("Access to object that could be either global or local in context:\n"+lb.getExplanation());
463         }
464     }
465
466     void processNew(LocalityBinding lb, FlatNew fn, boolean transaction, Hashtable<TempDescriptor, Integer> currtable) {
467         if (fn.isGlobal()&&!transaction) {
468             throw new Error("Allocating global object outside of transaction in context:"+lb.getExplanation());
469         }
470         if (fn.isGlobal())
471             currtable.put(fn.getDst(), GLOBAL);
472         else
473             currtable.put(fn.getDst(), LOCAL);
474     }
475
476     void processOpNode(FlatOpNode fon, Hashtable<TempDescriptor, Integer> currtable) {
477         /* Just propagate value */
478         currtable.put(fon.getDest(), currtable.get(fon.getLeft()));
479     }
480
481     void processCastNode(FlatCastNode fcn, Hashtable<TempDescriptor, Integer> currtable) {
482         currtable.put(fcn.getDst(), currtable.get(fcn.getSrc()));
483     }
484
485     void processLiteralNode(FlatLiteralNode fln, Hashtable<TempDescriptor, Integer> currtable) {
486         //null is either
487         if (fln.getValue()==null)
488             currtable.put(fln.getDst(), EITHER);
489         else
490             currtable.put(fln.getDst(), LOCAL);
491     }
492
493     void processReturnNode(LocalityBinding lb, FlatReturnNode frn, Hashtable<TempDescriptor, Integer> currtable) {
494         if(frn.getReturnTemp()!=null) {
495             Integer returntype=currtable.get(frn.getReturnTemp());
496             lb.setGlobalReturn(merge(returntype, lb.getGlobalReturn()));
497         }
498     }
499
500     void processSetElementNode(LocalityBinding lb, FlatSetElementNode fsen, Hashtable<TempDescriptor, Integer> currtable, boolean isatomic) {
501         Integer srctype=currtable.get(fsen.getSrc());
502         Integer dsttype=currtable.get(fsen.getDst());
503
504         if (dsttype.equals(LOCAL)) {
505             if (!(srctype.equals(LOCAL)||srctype.equals(EITHER)))
506                 throw new Error("Writing possible global reference to local object in context:\n"+lb.getExplanation());
507         } else if (dsttype.equals(GLOBAL)) {
508             if (!(srctype.equals(GLOBAL)||srctype.equals(EITHER)))
509                 throw new Error("Writing possible local reference to global object in context:\n"+lb.getExplanation());
510             if (!isatomic)
511                 throw new Error("Global access outside of a transaction in context:\n"+lb.getExplanation());
512         } else if (dsttype.equals(EITHER)) {
513             if (srctype.equals(CONFLICT))
514                 throw new Error("Using reference that could be local or global in context:\n"+lb.getExplanation());
515         } else if (dsttype.equals(CONFLICT)) {
516             throw new Error("Access to object that could be either global or local in context:\n"+lb.getExplanation());
517         }
518     }
519
520     void processElementNode(LocalityBinding lb, FlatElementNode fen, Hashtable<TempDescriptor, Integer> currtable, boolean isatomic) {
521         Integer type=currtable.get(fen.getSrc());
522         TempDescriptor dst=fen.getDst();
523         if (type.equals(LOCAL)) {
524             currtable.put(dst,LOCAL);
525         } else if (type.equals(GLOBAL)) {
526             if (!isatomic)
527                 throw new Error("Global access outside of a transaction in context:\n"+lb.getExplanation());
528             currtable.put(dst, GLOBAL);
529         } else if (type.equals(EITHER)) {
530             currtable.put(dst, EITHER);
531         } else if (type.equals(CONFLICT)) {
532             throw new Error("Access to object that could be either global or local in context:\n"+lb.getExplanation());
533         }
534     }
535
536     void processAtomicEnterNode(FlatAtomicEnterNode fen, Hashtable<FlatNode, Integer> atomictable) {
537         int atomic=atomictable.get(fen).intValue();
538         atomictable.put(fen, new Integer(atomic+1));
539     }
540
541     void processAtomicExitNode(FlatAtomicExitNode fen, Hashtable<FlatNode, Integer> atomictable) {
542         int atomic=atomictable.get(fen).intValue();
543         atomictable.put(fen, new Integer(atomic-1));
544     }
545
546     private Hashtable<FlatNode, Set<TempDescriptor>> computeLiveTemps(FlatMethod fm) {
547         Hashtable<FlatNode, Set<TempDescriptor>> nodetotemps=new Hashtable<FlatNode, Set<TempDescriptor>>();
548
549         Set<FlatNode> toprocess=fm.getNodeSet();
550
551         while(!toprocess.isEmpty()) {
552             FlatNode fn=toprocess.iterator().next();
553             toprocess.remove(fn);
554
555             List<TempDescriptor> reads=Arrays.asList(fn.readsTemps());
556             List<TempDescriptor> writes=Arrays.asList(fn.readsTemps());
557
558             HashSet<TempDescriptor> tempset=new HashSet<TempDescriptor>();
559             for(int i=0;i<fn.numNext();i++) {
560                 FlatNode fnnext=fn.getNext(i);
561                 if (nodetotemps.containsKey(fnnext))
562                     tempset.addAll(nodetotemps.get(fnnext));
563             }
564             tempset.removeAll(writes);
565             tempset.addAll(reads);
566             if (!nodetotemps.containsKey(fn)||
567                 nodetotemps.get(fn).equals(tempset)) {
568                 nodetotemps.put(fn, tempset);
569                 for(int i=0;i<fn.numPrev();i++)
570                     toprocess.add(fn.getPrev(i));
571             }
572         }
573         return nodetotemps;
574     }
575
576     private void computeTempstoSave() {
577         for(Iterator<LocalityBinding> lbit=getLocalityBindings().iterator();lbit.hasNext();) {
578             LocalityBinding lb=lbit.next();
579             computeTempstoSave(lb);
580         }
581     }
582
583     /* Need to checkpoint all temps that could be read from along any
584      * path that are either:
585        1) Written to by any assignment inside the transaction
586        2) Read from a global temp.
587
588        Generate tempstosave map from
589        localitybinding->flatatomicenternode->Set<TempDescriptors>
590     */
591
592     private void computeTempstoSave(LocalityBinding lb) {
593         if (lb.isAtomic())
594             return;
595         Hashtable<FlatNode, Integer> atomictab=getAtomic(lb);
596         Hashtable<FlatNode, Hashtable<TempDescriptor, Integer>> temptab=getNodeTempInfo(lb);
597         MethodDescriptor md=lb.getMethod();
598         FlatMethod fm=state.getMethodFlat(md);
599
600         Hashtable<FlatNode, Set<TempDescriptor>> nodetotemps=computeLiveTemps(fm);
601         Hashtable<FlatAtomicEnterNode, Set<TempDescriptor>> nodetosavetemps=new Hashtable<FlatAtomicEnterNode, Set<TempDescriptor>>();
602         tempstosave.put(lb, nodetosavetemps);
603
604         Hashtable<FlatNode, FlatAtomicEnterNode> nodemap=new Hashtable<FlatNode, FlatAtomicEnterNode>();
605         
606         HashSet<FlatNode> toprocess=new HashSet<FlatNode>();
607         HashSet<FlatNode> discovered=new HashSet<FlatNode>();
608         toprocess.add(fm);
609         discovered.add(fm);
610         while(!toprocess.isEmpty()) {
611             FlatNode fn=toprocess.iterator().next();
612             toprocess.remove(fn);
613             boolean isatomic=atomictab.get(fn).intValue()>0;
614             if (isatomic&&
615                 atomictab.get(fn.getPrev(0)).intValue()==0) {
616                 assert(fn.getPrev(0).kind()==FKind.FlatAtomicEnterNode);
617                 nodemap.put(fn, (FlatAtomicEnterNode)fn);
618                 nodetosavetemps.put((FlatAtomicEnterNode)fn, new HashSet<TempDescriptor>());
619             } else if (isatomic) {
620                 FlatAtomicEnterNode atomicnode=nodemap.get(fn);
621                 Set<TempDescriptor> livetemps=nodetotemps.get(fn);
622                 List<TempDescriptor> reads=Arrays.asList(fn.readsTemps());
623                 List<TempDescriptor> writes=Arrays.asList(fn.readsTemps());
624
625                 for(Iterator<TempDescriptor> tempit=livetemps.iterator();tempit.hasNext();) {
626                     TempDescriptor tmp=tempit.next();
627                     if (writes.contains(tmp)) {
628                         nodetosavetemps.get(atomicnode).add(tmp);
629                     } else if (reads.contains(tmp)&&temptab.get(fn).get(tmp)==GLOBAL) {
630                         nodetosavetemps.get(atomicnode).add(tmp);
631                     }
632                 }
633             }
634             for(int i=0;i<fn.numNext();i++) {
635                 FlatNode fnnext=fn.getNext(i);
636                 if (!discovered.contains(fnnext)) {
637                     discovered.add(fnnext);
638                     toprocess.add(fnnext);
639                     if(isatomic) {
640                         nodemap.put(fnnext, nodemap.get(fn));
641                     }
642                 }
643             }
644         }
645     }
646 }