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