changes
[IRC.git] / Robust / src / Analysis / Locality / LocalityAnalysis.java
1 package Analysis.Locality;
2
3 import java.util.*;
4 import Analysis.CallGraph.CallGraph;
5 import IR.SymbolTable;
6 import IR.State;
7 import IR.TypeUtil;
8 import IR.MethodDescriptor;
9 import IR.Flat.*;
10 import IR.ClassDescriptor;
11
12 public class LocalityAnalysis {
13   State state;
14   Stack lbtovisit;
15   Hashtable<LocalityBinding,LocalityBinding> discovered;
16   Hashtable<LocalityBinding, Set<LocalityBinding>> dependence;
17   Hashtable<LocalityBinding, Set<LocalityBinding>> calldep;
18   Hashtable<LocalityBinding, Hashtable<FlatNode,Hashtable<TempDescriptor, Integer>>> temptab;
19   Hashtable<LocalityBinding, Hashtable<FlatNode, Integer>> atomictab;
20   Hashtable<LocalityBinding, Hashtable<FlatAtomicEnterNode, Set<TempDescriptor>>> tempstosave;
21   Hashtable<ClassDescriptor, Set<LocalityBinding>> classtolb;
22   Hashtable<MethodDescriptor, Set<LocalityBinding>> methodtolb;
23   private LocalityBinding lbmain;
24   private LocalityBinding lbrun;
25
26   CallGraph callgraph;
27   TypeUtil typeutil;
28   public static final Integer LOCAL=new Integer(0);
29   public static final Integer GLOBAL=new Integer(1);
30   public static final Integer EITHER=new Integer(2);
31   public static final Integer CONFLICT=new Integer(3);
32
33   public static final Integer STMEITHER=new Integer(0);
34   public static final Integer SCRATCH=new Integer(4);
35   public static final Integer NORMAL=new Integer(8);
36   public static final Integer STMCONFLICT=new Integer(12);
37
38   public LocalityAnalysis(State state, CallGraph callgraph, TypeUtil typeutil) {
39     this.typeutil=typeutil;
40     this.state=state;
41     this.discovered=new Hashtable<LocalityBinding,LocalityBinding>();
42     this.dependence=new Hashtable<LocalityBinding, Set<LocalityBinding>>();
43     this.calldep=new Hashtable<LocalityBinding, Set<LocalityBinding>>();
44     this.temptab=new Hashtable<LocalityBinding, Hashtable<FlatNode,Hashtable<TempDescriptor, Integer>>>();
45     this.atomictab=new Hashtable<LocalityBinding, Hashtable<FlatNode, Integer>>();
46     this.lbtovisit=new Stack();
47     this.callgraph=callgraph;
48     this.tempstosave=new Hashtable<LocalityBinding, Hashtable<FlatAtomicEnterNode, Set<TempDescriptor>>>();
49     this.classtolb=new Hashtable<ClassDescriptor, Set<LocalityBinding>>();
50     this.methodtolb=new Hashtable<MethodDescriptor, Set<LocalityBinding>>();
51     doAnalysis();
52   }
53
54   public LocalityBinding getMain() {
55     return lbmain;
56   }
57
58   /** This method returns the set of LocalityBindings that a given
59    * flatcall could invoke */
60
61   public LocalityBinding getBinding(LocalityBinding currlb, FlatCall fc) {
62     boolean isatomic=getAtomic(currlb).get(fc).intValue()>0;
63     Hashtable<TempDescriptor, Integer> currtable=getNodePreTempInfo(currlb,fc);
64     MethodDescriptor md=fc.getMethod();
65
66     boolean isnative=md.getModifiers().isNative();
67
68     LocalityBinding lb=new LocalityBinding(md, isatomic);
69
70     for(int i=0; i<fc.numArgs(); i++) {
71       TempDescriptor arg=fc.getArg(i);
72       lb.setGlobal(i,currtable.get(arg));
73     }
74
75     if (state.DSM&&fc.getThis()!=null) {
76       Integer thistype=currtable.get(fc.getThis());
77       if (thistype==null)
78         thistype=EITHER;
79       lb.setGlobalThis(thistype);
80     } else if (state.SINGLETM&&fc.getThis()!=null) {
81       Integer thistype=currtable.get(fc.getThis());
82       if (thistype==null)
83         thistype=STMEITHER;
84       lb.setGlobalThis(thistype);
85     }
86     // else
87          // lb.setGlobalThis(EITHER);//default value
88     if (discovered.containsKey(lb))
89       lb=discovered.get(lb);
90     else throw new Error();
91     return lb;
92   }
93
94
95   /** This method returns a set of LocalityBindings for the parameter class. */
96   public Set<LocalityBinding> getClassBindings(ClassDescriptor cd) {
97     return classtolb.get(cd);
98   }
99
100   /** This method returns a set of LocalityBindings for the parameter method. */
101
102   public Set<LocalityBinding> getMethodBindings(MethodDescriptor md) {
103     return methodtolb.get(md);
104   }
105
106   public Set<MethodDescriptor> getMethods() {
107     return methodtolb.keySet();
108   }
109
110   /** This method returns a set of LocalityBindings.  A
111    * LocalityBinding specifies a context a method can be invoked in.
112    * It specifies whether the method is in a transaction and whether
113    * its parameter objects are locals or globals.  */
114
115   public Set<LocalityBinding> getLocalityBindings() {
116     return discovered.keySet();
117   }
118
119   /** This method returns a hashtable for a given LocalityBinding
120    * that tells the current local/global status of temps at the each
121    * node in the flat representation. */
122
123   public Hashtable<FlatNode, Hashtable<TempDescriptor, Integer>> getNodeTempInfo(LocalityBinding lb) {
124     return temptab.get(lb);
125   }
126
127   /** This method returns a hashtable for a given LocalityBinding
128    * that tells the current local/global status of temps at the
129    * beginning of each node in the flat representation. */
130
131   public Hashtable<TempDescriptor, Integer> getNodePreTempInfo(LocalityBinding lb, FlatNode fn) {
132     Hashtable<TempDescriptor, Integer> currtable=new Hashtable<TempDescriptor, Integer>();
133     Hashtable<FlatNode, Hashtable<TempDescriptor, Integer>> temptable=getNodeTempInfo(lb);
134
135     for(int i=0; i<fn.numPrev(); i++) {
136       FlatNode prevnode=fn.getPrev(i);
137       Hashtable<TempDescriptor, Integer> prevtable=temptable.get(prevnode);
138       for(Iterator<TempDescriptor> tempit=prevtable.keySet().iterator(); tempit.hasNext();) {
139         TempDescriptor temp=tempit.next();
140         Integer tmpint=prevtable.get(temp);
141         Integer oldint=currtable.containsKey(temp) ? currtable.get(temp) : (state.DSM?EITHER:STMEITHER);
142         Integer newint=state.DSM?merge(tmpint, oldint):mergestm(tmpint, oldint);
143         currtable.put(temp, newint);
144       }
145     }
146     return currtable;
147   }
148
149   /** This method returns an hashtable for a given LocalitBinding
150    * that tells whether a node in the flat represenation is in a
151    * transaction or not.  Integer values greater than 0 indicate
152    * that the node is in a transaction and give the nesting depth.
153    * The outermost AtomicEnterNode will have a value of 1 and the
154    * outermost AtomicExitNode will have a value of 0. */
155
156   public Hashtable<FlatNode, Integer> getAtomic(LocalityBinding lb) {
157     return atomictab.get(lb);
158   }
159
160   /** This methods returns a hashtable for a given LocalityBinding
161    * that tells which temps needs to be saved for each
162    * AtomicEnterNode.  */
163
164   public Hashtable<FlatAtomicEnterNode, Set<TempDescriptor>> getTemps(LocalityBinding lb) {
165     return tempstosave.get(lb);
166   }
167
168   public Set<TempDescriptor> getTempSet(LocalityBinding lb) {
169     HashSet<TempDescriptor> set=new HashSet<TempDescriptor>();
170     Hashtable<FlatAtomicEnterNode, Set<TempDescriptor>> table=getTemps(lb);
171     if (table!=null)
172       for(Iterator<FlatAtomicEnterNode> faenit=table.keySet().iterator(); faenit.hasNext();) {
173         FlatAtomicEnterNode faen=faenit.next();
174         set.addAll(table.get(faen));
175       }
176     return set;
177   }
178
179   private void doAnalysis() {
180     if (state.SINGLETM)
181       computeLocalityBindingsSTM();
182     else
183       computeLocalityBindings();
184     computeTempstoSave();
185     cleanSets();
186   }
187
188   private void cleanSets() {
189     HashSet<LocalityBinding> lbset=new HashSet<LocalityBinding>();
190     Stack<LocalityBinding> lbstack=new Stack<LocalityBinding>();
191     lbstack.add(lbmain);
192     lbstack.add(lbrun);
193     lbset.add(lbmain);
194     lbset.add(lbrun);
195     while(!lbstack.isEmpty()) {
196       LocalityBinding lb=lbstack.pop();
197       if (calldep.containsKey(lb)) {
198         Set<LocalityBinding> set=new HashSet<LocalityBinding>();
199         set.addAll(calldep.get(lb));
200         set.removeAll(lbset);
201         lbstack.addAll(set);
202         lbset.addAll(set);
203       }
204     }
205     for(Iterator<LocalityBinding> lbit=discovered.keySet().iterator(); lbit.hasNext();) {
206       LocalityBinding lb=lbit.next();
207       if (!lbset.contains(lb)) {
208         lbit.remove();
209         classtolb.get(lb.getMethod().getClassDesc()).remove(lb);
210         methodtolb.get(lb.getMethod()).remove(lb);
211       }
212     }
213   }
214
215   public MethodDescriptor getStart() {
216     ClassDescriptor cd=typeutil.getClass(TypeUtil.ThreadClass);
217     for(Iterator methodit=cd.getMethodTable().getSet("staticStart").iterator(); methodit
218 .hasNext();) {
219       MethodDescriptor md=(MethodDescriptor) methodit.next();
220       if (md.numParameters()!=1||!md.getModifiers().isStatic()||!md.getParamType(0).getSymbol().equals(TypeUtil.ThreadClass))
221         continue;
222       return md;
223     }
224     throw new Error("Can't find Thread.run");
225   }
226   
227   
228   private void computeLocalityBindingsSTM() {
229     lbmain=new LocalityBinding(typeutil.getMain(), false);
230     lbmain.setGlobalReturn(STMEITHER);
231     lbmain.setGlobal(0, NORMAL);
232     lbtovisit.add(lbmain);
233     discovered.put(lbmain, lbmain);
234     if (!classtolb.containsKey(lbmain.getMethod().getClassDesc()))
235       classtolb.put(lbmain.getMethod().getClassDesc(), new HashSet<LocalityBinding>());
236     classtolb.get(lbmain.getMethod().getClassDesc()).add(lbmain);
237
238     if (!methodtolb.containsKey(lbmain.getMethod()))
239       methodtolb.put(lbmain.getMethod(), new HashSet<LocalityBinding>());
240     methodtolb.get(lbmain.getMethod()).add(lbmain);
241
242     //Do this to force a virtual table number for the run method
243     lbrun=new LocalityBinding(getStart(), false);
244     lbrun.setGlobalReturn(STMEITHER);
245     lbrun.setGlobal(0,NORMAL);
246     lbtovisit.add(lbrun);
247     discovered.put(lbrun, lbrun);
248     if (!classtolb.containsKey(lbrun.getMethod().getClassDesc()))
249       classtolb.put(lbrun.getMethod().getClassDesc(), new HashSet<LocalityBinding>());
250     classtolb.get(lbrun.getMethod().getClassDesc()).add(lbrun);
251
252     if (!methodtolb.containsKey(lbrun.getMethod()))
253       methodtolb.put(lbrun.getMethod(), new HashSet<LocalityBinding>());
254     methodtolb.get(lbrun.getMethod()).add(lbrun);
255
256     while(!lbtovisit.empty()) {
257       LocalityBinding lb=(LocalityBinding) lbtovisit.pop();
258       Integer returnglobal=lb.getGlobalReturn();
259       MethodDescriptor md=lb.getMethod();
260       Hashtable<FlatNode,Hashtable<TempDescriptor, Integer>> temptable=new Hashtable<FlatNode,Hashtable<TempDescriptor, Integer>>();
261       Hashtable<FlatNode, Integer> atomictable=new Hashtable<FlatNode, Integer>();
262       calldep.remove(lb);
263       try {
264         computeCallsFlagsSTM(md, lb, temptable, atomictable);
265       } catch (Error e) {
266         System.out.println("Error in "+md+" context "+lb);
267         e.printStackTrace();
268         System.exit(-1);
269       }
270       temptab.put(lb, temptable);
271       atomictab.put(lb, atomictable);
272
273       if (md.getReturnType()!=null&&!returnglobal.equals(lb.getGlobalReturn())) {
274         //return type is more precise now
275         //rerun everything that call us
276         lbtovisit.addAll(dependence.get(lb));
277       }
278     }
279   }
280
281   private static Integer mergestm(Integer a, Integer b) {
282     if (a==null||a.equals(STMEITHER))
283       return b;
284     if (b==null||b.equals(STMEITHER))
285       return a;
286     if (a.equals(b))
287       return a;
288     return STMCONFLICT;
289   }
290
291   public void computeCallsFlagsSTM(MethodDescriptor md, LocalityBinding lb,  Hashtable<FlatNode, Hashtable<TempDescriptor, Integer>> temptable, Hashtable<FlatNode, Integer> atomictable) {
292     FlatMethod fm=state.getMethodFlat(md);
293     HashSet<FlatNode> tovisit=new HashSet<FlatNode>();
294     tovisit.add(fm.getNext(0));
295     {
296       // Build table for initial node
297       Hashtable<TempDescriptor,Integer> table=new Hashtable<TempDescriptor,Integer>();
298       temptable.put(fm, table);
299       atomictable.put(fm, lb.isAtomic() ? 1 : 0);
300       int offset=md.isStatic() ? 0 : 1;
301       if (!md.isStatic()) {
302         table.put(fm.getParameter(0), lb.getGlobalThis());
303       }
304       for(int i=offset; i<fm.numParameters(); i++) {
305         TempDescriptor temp=fm.getParameter(i);
306         Integer b=lb.isGlobal(i-offset);
307         table.put(temp,b);
308       }
309     }
310
311     while(!tovisit.isEmpty()) {
312       FlatNode fn=tovisit.iterator().next();
313       tovisit.remove(fn);
314       Hashtable<TempDescriptor, Integer> currtable=new Hashtable<TempDescriptor, Integer>();
315       int atomicstate=0;
316       for(int i=0; i<fn.numPrev(); i++) {
317         FlatNode prevnode=fn.getPrev(i);
318         if (atomictable.containsKey(prevnode)) {
319           atomicstate=atomictable.get(prevnode).intValue();
320         }
321         if (!temptable.containsKey(prevnode))
322           continue;
323         Hashtable<TempDescriptor, Integer> prevtable=temptable.get(prevnode);
324         for(Iterator<TempDescriptor> tempit=prevtable.keySet().iterator(); tempit.hasNext();) {
325           TempDescriptor temp=tempit.next();
326           Integer tmpint=prevtable.get(temp);
327           Integer oldint=currtable.containsKey(temp) ? currtable.get(temp) : STMEITHER;
328           Integer newint=mergestm(tmpint, oldint);
329           currtable.put(temp, newint);
330         }
331       }
332       atomictable.put(fn, atomicstate);
333
334       // Process this node
335       switch(fn.kind()) {
336       case FKind.FlatAtomicEnterNode:
337         processAtomicEnterNode((FlatAtomicEnterNode)fn, atomictable);
338         if (!lb.isAtomic())
339           lb.setHasAtomic();
340         break;
341
342       case FKind.FlatAtomicExitNode:
343         processAtomicExitNode((FlatAtomicExitNode)fn, atomictable);
344         break;
345
346       case FKind.FlatCall:
347         processCallNodeSTM(lb, (FlatCall)fn, isAtomic(atomictable, fn), currtable);
348         break;
349
350       case FKind.FlatNew:
351         processNewSTM(lb, (FlatNew) fn, currtable);
352         break;
353
354       case FKind.FlatFieldNode:
355         processFieldNodeSTM(lb, (FlatFieldNode) fn, currtable);
356         break;
357
358       case FKind.FlatSetFieldNode:
359         processSetFieldNodeSTM(lb, (FlatSetFieldNode) fn, currtable);
360         break;
361
362       case FKind.FlatSetElementNode:
363         processSetElementNodeSTM(lb, (FlatSetElementNode) fn, currtable);
364         break;
365
366       case FKind.FlatElementNode:
367         processElementNodeSTM(lb, (FlatElementNode) fn, currtable);
368         break;
369
370       case FKind.FlatOpNode:
371         processOpNodeSTM((FlatOpNode)fn, currtable);
372         break;
373
374       case FKind.FlatCastNode:
375         processCastNodeSTM((FlatCastNode)fn, currtable);
376         break;
377
378       case FKind.FlatReturnNode:
379         processReturnNodeSTM(lb, (FlatReturnNode)fn, currtable);
380         break;
381
382       case FKind.FlatLiteralNode:
383         processLiteralNodeSTM((FlatLiteralNode)fn, currtable);
384         break;
385
386       case FKind.FlatMethod:
387       case FKind.FlatOffsetNode:
388       case FKind.FlatInstanceOfNode:
389       case FKind.FlatCondBranch:
390       case FKind.FlatBackEdge:
391       case FKind.FlatNop:
392       case FKind.FlatPrefetchNode:
393       case FKind.FlatExit:
394         //No action needed for these
395         break;
396
397       case FKind.FlatFlagActionNode:
398       case FKind.FlatCheckNode:
399       case FKind.FlatTagDeclaration:
400         throw new Error("Incompatible with tasks!");
401
402       default:
403         throw new Error("In finding fn.kind()= " + fn.kind());
404       }
405       Hashtable<TempDescriptor,Integer> oldtable=temptable.get(fn);
406       if (oldtable==null||!oldtable.equals(currtable)) {
407         // Update table for this node
408         temptable.put(fn, currtable);
409         for(int i=0; i<fn.numNext(); i++) {
410           tovisit.add(fn.getNext(i));
411         }
412       }
413     }
414   }
415
416   void processNewSTM(LocalityBinding lb, FlatNew fn, Hashtable<TempDescriptor, Integer> currtable) {
417     if (fn.isScratch())
418       currtable.put(fn.getDst(), SCRATCH);
419     else
420       currtable.put(fn.getDst(), NORMAL);
421   }
422
423   void processCallNodeSTM(LocalityBinding currlb, FlatCall fc, boolean isatomic, Hashtable<TempDescriptor, Integer> currtable) {
424     MethodDescriptor nodemd=fc.getMethod();
425     Set methodset=null;
426     Set runmethodset=null;
427
428     if (nodemd.isStatic()||nodemd.getReturnType()==null) {
429       methodset=new HashSet();
430       methodset.add(nodemd);
431     } else {
432       methodset=callgraph.getMethods(nodemd, fc.getThis().getType());
433       // Build start -> run link
434       if (nodemd.getClassDesc().getSymbol().equals(TypeUtil.ThreadClass)&&
435           nodemd.getSymbol().equals("start")&&!nodemd.getModifiers().isStatic()&&
436           nodemd.numParameters()==0) {
437         assert(nodemd.getModifiers().isNative());
438
439         MethodDescriptor runmd=null;
440         for(Iterator methodit=nodemd.getClassDesc().getMethodTable().getSet("staticStart").iterator(); methodit.hasNext();) {
441           MethodDescriptor md=(MethodDescriptor) methodit.next();
442           if (md.numParameters()!=1||!md.getModifiers().isStatic()||!md.getParamType(0).getSymbol().equals(TypeUtil.ThreadClass))
443             continue;
444           runmd=md;
445           break;
446         }
447         if (runmd!=null) {
448           runmethodset=callgraph.getMethods(runmd,fc.getThis().getType());
449           methodset.addAll(runmethodset);
450         } else throw new Error("Can't find run method");
451       }
452     }
453
454     Integer currreturnval=STMEITHER;     //Start off with the either value
455     for(Iterator methodit=methodset.iterator(); methodit.hasNext();) {
456       MethodDescriptor md=(MethodDescriptor) methodit.next();
457
458       boolean isnative=md.getModifiers().isNative();
459       boolean isjoin = md.getClassDesc().getSymbol().equals(TypeUtil.ThreadClass)&&!nodemd.getModifiers().isStatic()&&nodemd.numParameters()==0&&md.getSymbol().equals("join");
460       boolean isObjectgetType = md.getClassDesc().getSymbol().equals("Object") && md.getSymbol().equals("getType");
461       boolean isObjecthashCode = md.getClassDesc().getSymbol().equals("Object") && md.getSymbol().equals("nativehashCode");
462
463       LocalityBinding lb=new LocalityBinding(md, isatomic);
464       if (isnative&&isatomic) {
465         System.out.println("Don't call native methods in atomic blocks!"+currlb.getMethod());
466       }
467
468       if (runmethodset==null||!runmethodset.contains(md)) {
469         for(int i=0; i<fc.numArgs(); i++) {
470           TempDescriptor arg=fc.getArg(i);
471           lb.setGlobal(i,currtable.get(arg));
472         }
473         if (fc.getThis()!=null) {
474           Integer thistype=currtable.get(fc.getThis());
475           if (thistype==null)
476             thistype=STMEITHER;
477           
478           if(thistype.equals(STMCONFLICT))
479             throw new Error("Using type that can be either normal or scratch in context:\n"+currlb.getExplanation());
480           lb.setGlobalThis(thistype);
481         }
482       } else {
483         Integer thistype=currtable.get(fc.getThis());
484         if (!thistype.equals(NORMAL)) {
485           throw new Error("Called start on possible scratch object");
486         }
487         lb.setGlobal(0,currtable.get(fc.getThis()));
488       }
489       //lb is built
490       if (!discovered.containsKey(lb)) {
491         if (isnative) {
492           if (nodemd.getReturnType()==null||!nodemd.getReturnType().isPtr())
493             lb.setGlobalReturn(SCRATCH);
494           else
495             lb.setGlobalReturn(NORMAL);
496         } else
497           lb.setGlobalReturn(STMEITHER);
498
499         lb.setParent(currlb);
500         lbtovisit.add(lb);
501         discovered.put(lb, lb);
502         if (!classtolb.containsKey(lb.getMethod().getClassDesc()))
503           classtolb.put(lb.getMethod().getClassDesc(), new HashSet<LocalityBinding>());
504         classtolb.get(lb.getMethod().getClassDesc()).add(lb);
505         if (!methodtolb.containsKey(lb.getMethod()))
506           methodtolb.put(lb.getMethod(), new HashSet<LocalityBinding>());
507         methodtolb.get(lb.getMethod()).add(lb);
508       } else
509         lb=discovered.get(lb);
510       Integer returnval=lb.getGlobalReturn();
511       currreturnval=mergestm(returnval, currreturnval);
512       if (!dependence.containsKey(lb))
513         dependence.put(lb, new HashSet<LocalityBinding>());
514       dependence.get(lb).add(currlb);
515
516       if (!calldep.containsKey(currlb))
517         calldep.put(currlb, new HashSet<LocalityBinding>());
518       calldep.get(currlb).add(lb);
519     }
520     if (fc.getReturnTemp()!=null) {
521       currtable.put(fc.getReturnTemp(), currreturnval);
522     }
523   }
524
525   void processFieldNodeSTM(LocalityBinding lb, FlatFieldNode ffn, Hashtable<TempDescriptor, Integer> currtable) {
526     Integer type=currtable.get(ffn.getSrc());
527     TempDescriptor dst=ffn.getDst();
528     if (type.equals(SCRATCH)) {
529       currtable.put(dst,SCRATCH);
530     } else if (type.equals(NORMAL)) {
531       if (ffn.getField().getType().isPrimitive()&&!ffn.getField().getType().isArray())
532         currtable.put(dst, SCRATCH);         // primitives are local
533       else
534         currtable.put(dst, NORMAL);
535     } else if (type.equals(STMEITHER)) {
536       if (ffn.getField().getType().isPrimitive()&&!ffn.getField().getType().isArray())
537         currtable.put(dst, SCRATCH);         // primitives are local
538       else
539         currtable.put(dst, STMEITHER);
540     } else if (type.equals(STMCONFLICT)) {
541       throw new Error("Access to object that could be either normal or scratch in context:\n"+ffn+"  "+lb.getExplanation());
542     }
543   }
544
545   //need to handle primitives
546   void processSetFieldNodeSTM(LocalityBinding lb, FlatSetFieldNode fsfn, Hashtable<TempDescriptor, Integer> currtable) {
547     Integer srctype=currtable.get(fsfn.getSrc());
548     Integer dsttype=currtable.get(fsfn.getDst());
549
550     if (dsttype.equals(SCRATCH)) {
551       if (srctype.equals(SCRATCH) && fsfn.getField().getType().isPrimitive() && !fsfn.getField().getType().isArray())
552         return;
553       if (!(srctype.equals(SCRATCH)||srctype.equals(STMEITHER)))
554         throw new Error("Writing possible normal reference to scratch object in context: \n"+lb.getExplanation());
555     } else if (dsttype.equals(NORMAL)) {
556       //okay to store primitives in global object
557       if (srctype.equals(SCRATCH) && fsfn.getField().getType().isPrimitive() && !fsfn.getField().getType().isArray())
558         return;
559       if (!(srctype.equals(NORMAL)||srctype.equals(STMEITHER)))
560         throw new Error("Writing possible scratch reference to normal object in context:\n"+lb.getExplanation()+" for FlatFieldNode "+fsfn);
561     } else if (dsttype.equals(STMEITHER)) {
562       if (srctype.equals(STMCONFLICT))
563         throw new Error("Using reference that could be scratch or normal in context:\n"+lb.getExplanation());
564     } else if (dsttype.equals(STMCONFLICT)) {
565       throw new Error("Access to object that could be either scratch or normal in context:\n"+lb.getExplanation());
566     }
567   }
568
569   void processSetElementNodeSTM(LocalityBinding lb, FlatSetElementNode fsen, Hashtable<TempDescriptor, Integer> currtable) {
570     Integer srctype=currtable.get(fsen.getSrc());
571     Integer dsttype=currtable.get(fsen.getDst());
572     
573     if (dsttype.equals(SCRATCH)) {
574       if (!(srctype.equals(SCRATCH)||srctype.equals(STMEITHER)))
575         throw new Error("Writing possible normal reference to scratch object in context:\n"+lb.getExplanation()+fsen);
576     } else if (dsttype.equals(NORMAL)) {
577       if (srctype.equals(SCRATCH) && fsen.getDst().getType().dereference().isPrimitive() && !fsen.getDst().getType().dereference().isArray())
578         return;
579       if (!(srctype.equals(NORMAL)||srctype.equals(STMEITHER)))
580         throw new Error("Writing possible scratch reference to normal object in context:\n"+lb.getExplanation());
581     } else if (dsttype.equals(STMEITHER)) {
582       if (srctype.equals(STMCONFLICT))
583         throw new Error("Using reference that could be scratch or normal in context:\n"+lb.getExplanation());
584     } else if (dsttype.equals(STMCONFLICT)) {
585       throw new Error("Access to object that could be either normal or scratch in context:\n"+lb.getExplanation());
586     }
587   }
588
589   void processOpNodeSTM(FlatOpNode fon, Hashtable<TempDescriptor, Integer> currtable) {
590     /* Just propagate value */
591     Integer srcvalue=currtable.get(fon.getLeft());
592     
593     if (srcvalue==null) {
594       if (!fon.getLeft().getType().isPtr()) {
595         srcvalue=SCRATCH;
596       } else
597         throw new Error(fon.getLeft()+" is undefined!");
598     }
599     currtable.put(fon.getDest(), srcvalue);
600   }
601   
602    void processCastNodeSTM(FlatCastNode fcn, Hashtable<TempDescriptor, Integer> currtable) {
603     currtable.put(fcn.getDst(), currtable.get(fcn.getSrc()));
604   }
605
606   void processReturnNodeSTM(LocalityBinding lb, FlatReturnNode frn, Hashtable<TempDescriptor, Integer> currtable) {
607     if(frn.getReturnTemp()!=null) {
608       Integer returntype=currtable.get(frn.getReturnTemp());
609       lb.setGlobalReturn(mergestm(returntype, lb.getGlobalReturn()));
610     }
611   }
612   
613    void processLiteralNodeSTM(FlatLiteralNode fln, Hashtable<TempDescriptor, Integer> currtable) {
614     //null is either
615      if (fln.getType().isNull())
616        currtable.put(fln.getDst(), STMEITHER);
617      else if (fln.getType().isPtr())
618        currtable.put(fln.getDst(), NORMAL);
619      else
620        currtable.put(fln.getDst(), SCRATCH);
621   }
622
623   void processElementNodeSTM(LocalityBinding lb, FlatElementNode fen, Hashtable<TempDescriptor, Integer> currtable) {
624     Integer type=currtable.get(fen.getSrc());
625     TempDescriptor dst=fen.getDst();
626     if (type.equals(SCRATCH)) {
627       currtable.put(dst,SCRATCH);
628     } else if (type.equals(NORMAL)) {
629       if(fen.getSrc().getType().dereference().isPrimitive()&&
630          !fen.getSrc().getType().dereference().isArray())
631         currtable.put(dst, SCRATCH);
632       else
633         currtable.put(dst, NORMAL);
634     } else if (type.equals(STMEITHER)) {
635       if(fen.getSrc().getType().dereference().isPrimitive()&&
636          !fen.getSrc().getType().dereference().isArray())
637         currtable.put(dst, SCRATCH);
638       else
639         currtable.put(dst, STMEITHER);
640     } else if (type.equals(STMCONFLICT)) {
641       throw new Error("Access to object that could be either global or local in context:\n"+lb.getExplanation());
642     }
643   }
644
645   private void computeLocalityBindings() {
646     lbmain=new LocalityBinding(typeutil.getMain(), false);
647     lbmain.setGlobalReturn(EITHER);
648     lbmain.setGlobal(0, LOCAL);
649     lbtovisit.add(lbmain);
650     discovered.put(lbmain, lbmain);
651     if (!classtolb.containsKey(lbmain.getMethod().getClassDesc()))
652       classtolb.put(lbmain.getMethod().getClassDesc(), new HashSet<LocalityBinding>());
653     classtolb.get(lbmain.getMethod().getClassDesc()).add(lbmain);
654
655     if (!methodtolb.containsKey(lbmain.getMethod()))
656       methodtolb.put(lbmain.getMethod(), new HashSet<LocalityBinding>());
657     methodtolb.get(lbmain.getMethod()).add(lbmain);
658
659     //Do this to force a virtual table number for the run method
660     lbrun=new LocalityBinding(typeutil.getRun(), false);
661     lbrun.setGlobalReturn(EITHER);
662     lbrun.setGlobalThis(GLOBAL);
663     lbtovisit.add(lbrun);
664     discovered.put(lbrun, lbrun);
665     if (!classtolb.containsKey(lbrun.getMethod().getClassDesc()))
666       classtolb.put(lbrun.getMethod().getClassDesc(), new HashSet<LocalityBinding>());
667     classtolb.get(lbrun.getMethod().getClassDesc()).add(lbrun);
668
669     if (!methodtolb.containsKey(lbrun.getMethod()))
670       methodtolb.put(lbrun.getMethod(), new HashSet<LocalityBinding>());
671     methodtolb.get(lbrun.getMethod()).add(lbrun);
672
673     while(!lbtovisit.empty()) {
674       LocalityBinding lb=(LocalityBinding) lbtovisit.pop();
675       Integer returnglobal=lb.getGlobalReturn();
676       MethodDescriptor md=lb.getMethod();
677       Hashtable<FlatNode,Hashtable<TempDescriptor, Integer>> temptable=new Hashtable<FlatNode,Hashtable<TempDescriptor, Integer>>();
678       Hashtable<FlatNode, Integer> atomictable=new Hashtable<FlatNode, Integer>();
679       calldep.remove(lb);
680       try {
681         computeCallsFlags(md, lb, temptable, atomictable);
682       } catch (Error e) {
683         System.out.println("Error in "+md+" context "+lb);
684         e.printStackTrace();
685         System.exit(-1);
686       }
687       temptab.put(lb, temptable);
688       atomictab.put(lb, atomictable);
689
690       if (md.getReturnType()!=null&&!returnglobal.equals(lb.getGlobalReturn())) {
691         //return type is more precise now
692         //rerun everything that call us
693         lbtovisit.addAll(dependence.get(lb));
694       }
695     }
696   }
697
698
699
700
701   public void computeCallsFlags(MethodDescriptor md, LocalityBinding lb, Hashtable<FlatNode, Hashtable<TempDescriptor, Integer>> temptable, Hashtable<FlatNode, Integer> atomictable) {
702     FlatMethod fm=state.getMethodFlat(md);
703     HashSet<FlatNode> tovisit=new HashSet<FlatNode>();
704     tovisit.add(fm.getNext(0));
705     {
706       // Build table for initial node
707       Hashtable<TempDescriptor,Integer> table=new Hashtable<TempDescriptor,Integer>();
708       temptable.put(fm, table);
709       atomictable.put(fm, lb.isAtomic() ? 1 : 0);
710       int offset=md.isStatic() ? 0 : 1;
711       if (!md.isStatic()) {
712         table.put(fm.getParameter(0), lb.getGlobalThis());
713       }
714       for(int i=offset; i<fm.numParameters(); i++) {
715         TempDescriptor temp=fm.getParameter(i);
716         Integer b=lb.isGlobal(i-offset);
717         table.put(temp,b);
718       }
719     }
720
721     while(!tovisit.isEmpty()) {
722       FlatNode fn=tovisit.iterator().next();
723       tovisit.remove(fn);
724       Hashtable<TempDescriptor, Integer> currtable=new Hashtable<TempDescriptor, Integer>();
725       int atomicstate=0;
726       for(int i=0; i<fn.numPrev(); i++) {
727         FlatNode prevnode=fn.getPrev(i);
728         if (atomictable.containsKey(prevnode)) {
729           atomicstate=atomictable.get(prevnode).intValue();
730         }
731         if (!temptable.containsKey(prevnode))
732           continue;
733         Hashtable<TempDescriptor, Integer> prevtable=temptable.get(prevnode);
734         for(Iterator<TempDescriptor> tempit=prevtable.keySet().iterator(); tempit.hasNext();) {
735           TempDescriptor temp=tempit.next();
736           Integer tmpint=prevtable.get(temp);
737           Integer oldint=currtable.containsKey(temp) ? currtable.get(temp) : EITHER;
738           Integer newint=merge(tmpint, oldint);
739           currtable.put(temp, newint);
740         }
741       }
742       atomictable.put(fn, atomicstate);
743       // Process this node
744       switch(fn.kind()) {
745       case FKind.FlatAtomicEnterNode:
746         processAtomicEnterNode((FlatAtomicEnterNode)fn, atomictable);
747         if (!lb.isAtomic())
748           lb.setHasAtomic();
749         break;
750
751       case FKind.FlatAtomicExitNode:
752         processAtomicExitNode((FlatAtomicExitNode)fn, atomictable);
753         break;
754
755       case FKind.FlatCall:
756         processCallNode(lb, (FlatCall)fn, currtable, isAtomic(atomictable, fn));
757         break;
758
759       case FKind.FlatFieldNode:
760         processFieldNode(lb, (FlatFieldNode)fn, isAtomic(atomictable, fn), currtable);
761         break;
762
763       case FKind.FlatSetFieldNode:
764         processSetFieldNode(lb, (FlatSetFieldNode)fn, isAtomic(atomictable,fn), currtable);
765         break;
766
767       case FKind.FlatNew:
768         processNew(lb, (FlatNew)fn, isAtomic(atomictable, fn), currtable);
769         break;
770
771       case FKind.FlatOpNode:
772         processOpNode((FlatOpNode)fn, currtable);
773         break;
774
775       case FKind.FlatCastNode:
776         processCastNode((FlatCastNode)fn, currtable);
777         break;
778
779       case FKind.FlatLiteralNode:
780         processLiteralNode((FlatLiteralNode)fn, currtable);
781         break;
782
783       case FKind.FlatReturnNode:
784         processReturnNode(lb, (FlatReturnNode)fn, currtable);
785         break;
786
787       case FKind.FlatSetElementNode:
788         processSetElementNode(lb, (FlatSetElementNode)fn, currtable, isAtomic(atomictable, fn));
789         break;
790
791       case FKind.FlatElementNode:
792         processElementNode(lb, (FlatElementNode)fn, currtable, isAtomic(atomictable, fn));
793         break;
794
795       case FKind.FlatInstanceOfNode:
796       case FKind.FlatCondBranch:
797       case FKind.FlatBackEdge:
798       case FKind.FlatNop:
799       case FKind.FlatExit:
800       case FKind.FlatPrefetchNode:
801         //No action needed for these
802         break;
803
804       case FKind.FlatFlagActionNode:
805       case FKind.FlatCheckNode:
806       case FKind.FlatTagDeclaration:
807         throw new Error("Incompatible with tasks!");
808
809       case FKind.FlatMethod:
810         break;
811
812       case FKind.FlatOffsetNode:
813         processOffsetNode((FlatOffsetNode)fn, currtable);
814         break;
815
816       default:
817         throw new Error("In finding fn.kind()= " + fn.kind());
818       }
819       Hashtable<TempDescriptor,Integer> oldtable=temptable.get(fn);
820       if (oldtable==null||!oldtable.equals(currtable)) {
821         // Update table for this node
822         temptable.put(fn, currtable);
823         for(int i=0; i<fn.numNext(); i++) {
824           tovisit.add(fn.getNext(i));
825         }
826       }
827     }
828   }
829
830   private static boolean isAtomic(Hashtable<FlatNode, Integer> atomictable, FlatNode fn) {
831     return atomictable.get(fn).intValue()>0;
832   }
833
834   private static Integer merge(Integer a, Integer b) {
835     if (a==null||a.equals(EITHER))
836       return b;
837     if (b==null||b.equals(EITHER))
838       return a;
839     if (a.equals(b))
840       return a;
841     return CONFLICT;
842   }
843
844   void processCallNode(LocalityBinding currlb, FlatCall fc, Hashtable<TempDescriptor, Integer> currtable, boolean isatomic) {
845     MethodDescriptor nodemd=fc.getMethod();
846     Set methodset=null;
847     Set runmethodset=null;
848
849     if (nodemd.isStatic()||nodemd.getReturnType()==null) {
850       methodset=new HashSet();
851       methodset.add(nodemd);
852     } else {
853       methodset=callgraph.getMethods(nodemd, fc.getThis().getType());
854       // Build start -> run link
855       if (nodemd.getClassDesc().getSymbol().equals(TypeUtil.ThreadClass)&&
856           nodemd.getSymbol().equals("start")&&!nodemd.getModifiers().isStatic()&&
857           nodemd.numParameters()==1&&nodemd.getParamType(0).isInt()) {
858         assert(nodemd.getModifiers().isNative());
859
860         MethodDescriptor runmd=null;
861         for(Iterator methodit=nodemd.getClassDesc().getMethodTable().getSet("run").iterator(); methodit.hasNext();) {
862           MethodDescriptor md=(MethodDescriptor) methodit.next();
863           if (md.numParameters()!=0||md.getModifiers().isStatic())
864             continue;
865           runmd=md;
866           break;
867         }
868         if (runmd!=null) {
869           runmethodset=callgraph.getMethods(runmd,fc.getThis().getType());
870           methodset.addAll(runmethodset);
871         } else throw new Error("Can't find run method");
872       }
873     }
874
875     Integer currreturnval=EITHER;     //Start off with the either value
876     for(Iterator methodit=methodset.iterator(); methodit.hasNext();) {
877       MethodDescriptor md=(MethodDescriptor) methodit.next();
878
879       boolean isnative=md.getModifiers().isNative();
880       boolean isjoin = md.getClassDesc().getSymbol().equals(TypeUtil.ThreadClass)&&!nodemd.getModifiers().isStatic()&&nodemd.numParameters()==0&&md.getSymbol().equals("join");
881       boolean isObjectgetType = md.getClassDesc().getSymbol().equals("Object") && md.getSymbol().equals("getType");
882       boolean isObjecthashCode = md.getClassDesc().getSymbol().equals("Object") && md.getSymbol().equals("nativehashCode");
883
884       LocalityBinding lb=new LocalityBinding(md, isatomic);
885       if (isnative&&isatomic) {
886         System.out.println("Don't call native methods in atomic blocks!"+currlb.getMethod());
887       }
888       if (runmethodset==null||!runmethodset.contains(md)) {
889         //Skip this part if it is a run method
890         for(int i=0; i<fc.numArgs(); i++) {
891           TempDescriptor arg=fc.getArg(i);
892           if(isnative&&(currtable.get(arg).equals(GLOBAL)||
893                         currtable.get(arg).equals(CONFLICT))&& !(nodemd.getSymbol().equals("rangePrefetch"))) {
894             throw new Error("Potential call to native method "+md+" with global parameter:\n"+currlb.getExplanation());
895           }
896           lb.setGlobal(i,currtable.get(arg));
897         }
898       }
899
900       if (fc.getThis()!=null) {
901         Integer thistype=currtable.get(fc.getThis());
902         if (thistype==null)
903           thistype=EITHER;
904
905         if(runmethodset!=null&&runmethodset.contains(md)&&thistype.equals(LOCAL))
906           throw new Error("Starting thread on local object not allowed in context:\n"+currlb.getExplanation());
907         if(isjoin&&thistype.equals(LOCAL))
908           throw new Error("Joining thread on local object not allowed in context:\n"+currlb.getExplanation());
909         if(thistype.equals(CONFLICT))
910           throw new Error("Using type that can be either local or global in context:\n"+currlb.getExplanation());
911         if(runmethodset==null&&thistype.equals(GLOBAL)&&!isatomic && !isjoin)
912           throw new Error("Using global object outside of transaction in context:\n"+currlb.getExplanation());
913         if (runmethodset==null&&isnative&&thistype.equals(GLOBAL) && !isjoin && !isObjectgetType && !isObjecthashCode)
914           throw new Error("Potential call to native method "+md+" on global objects:\n"+currlb.getExplanation());
915         lb.setGlobalThis(thistype);
916       }
917       //lb is built
918       if (!discovered.containsKey(lb)) {
919         if (isnative)
920           lb.setGlobalReturn(LOCAL);
921         else
922           lb.setGlobalReturn(EITHER);
923         lb.setParent(currlb);
924         lbtovisit.add(lb);
925         discovered.put(lb, lb);
926         if (!classtolb.containsKey(lb.getMethod().getClassDesc()))
927           classtolb.put(lb.getMethod().getClassDesc(), new HashSet<LocalityBinding>());
928         classtolb.get(lb.getMethod().getClassDesc()).add(lb);
929         if (!methodtolb.containsKey(lb.getMethod()))
930           methodtolb.put(lb.getMethod(), new HashSet<LocalityBinding>());
931         methodtolb.get(lb.getMethod()).add(lb);
932       } else
933         lb=discovered.get(lb);
934       Integer returnval=lb.getGlobalReturn();
935       currreturnval=merge(returnval, currreturnval);
936       if (!dependence.containsKey(lb))
937         dependence.put(lb, new HashSet<LocalityBinding>());
938       dependence.get(lb).add(currlb);
939
940       if (!calldep.containsKey(currlb))
941         calldep.put(currlb, new HashSet<LocalityBinding>());
942       calldep.get(currlb).add(lb);
943     }
944     if (fc.getReturnTemp()!=null) {
945       currtable.put(fc.getReturnTemp(), currreturnval);
946     }
947   }
948
949   void processFieldNode(LocalityBinding lb, FlatFieldNode ffn, boolean transaction, Hashtable<TempDescriptor, Integer> currtable) {
950     Integer type=currtable.get(ffn.getSrc());
951     TempDescriptor dst=ffn.getDst();
952     if (type.equals(LOCAL)) {
953       if (ffn.getField().isGlobal())
954         currtable.put(dst,GLOBAL);
955       else
956         currtable.put(dst,LOCAL);
957     } else if (type.equals(GLOBAL)) {
958       if (!transaction)
959         throw new Error("Global access outside of a transaction in context:\n"+lb.getExplanation());
960       if (ffn.getField().getType().isPrimitive()&&!ffn.getField().getType().isArray())
961         currtable.put(dst, LOCAL);         // primitives are local
962       else
963         currtable.put(dst, GLOBAL);
964     } else if (type.equals(EITHER)) {
965       if (ffn.getField().getType().isPrimitive()&&!ffn.getField().getType().isArray())
966         currtable.put(dst, LOCAL);         // primitives are local
967       else if (ffn.getField().isGlobal())
968         currtable.put(dst, GLOBAL);
969       else
970         currtable.put(dst, EITHER);
971     } else if (type.equals(CONFLICT)) {
972       throw new Error("Access to object that could be either global or local in context:\n"+lb.getExplanation());
973     }
974   }
975
976   //need to handle primitives
977   void processSetFieldNode(LocalityBinding lb, FlatSetFieldNode fsfn, boolean transaction, Hashtable<TempDescriptor, Integer> currtable) {
978     Integer srctype=currtable.get(fsfn.getSrc());
979     Integer dsttype=currtable.get(fsfn.getDst());
980
981     if (dsttype.equals(LOCAL)) {
982       if (fsfn.getField().isGlobal()) {
983         if (!(srctype.equals(GLOBAL)||srctype.equals(EITHER)))
984           throw new Error("Writing possible local reference to global field in context: \n"+lb.getExplanation());
985       } else {
986         if (!(srctype.equals(LOCAL)||srctype.equals(EITHER)))
987           throw new Error("Writing possible global reference to local object in context: \n"+lb.getExplanation());
988       }
989     } else if (dsttype.equals(GLOBAL)) {
990       if (!transaction)
991         throw new Error("Global access outside of a transaction in context:\n"+lb.getExplanation());
992       //okay to store primitives in global object
993       if (srctype.equals(LOCAL) && fsfn.getField().getType().isPrimitive() && !fsfn.getField().getType().isArray())
994         return;
995       if (!(srctype.equals(GLOBAL)||srctype.equals(EITHER)))
996         throw new Error("Writing possible local reference to global object in context:\n"+lb.getExplanation()+" for FlatFieldNode "+fsfn);
997     } else if (dsttype.equals(EITHER)) {
998       if (srctype.equals(CONFLICT))
999         throw new Error("Using reference that could be local or global in context:\n"+lb.getExplanation());
1000     } else if (dsttype.equals(CONFLICT)) {
1001       throw new Error("Access to object that could be either global or local in context:\n"+lb.getExplanation());
1002     }
1003   }
1004
1005   void processNew(LocalityBinding lb, FlatNew fn, boolean transaction, Hashtable<TempDescriptor, Integer> currtable) {
1006     if (fn.isGlobal()&&!transaction) {
1007       throw new Error("Allocating global object outside of transaction in context:"+lb.getExplanation());
1008     }
1009     if (fn.isGlobal())
1010       currtable.put(fn.getDst(), GLOBAL);
1011     else
1012       currtable.put(fn.getDst(), LOCAL);
1013   }
1014
1015   void processOpNode(FlatOpNode fon, Hashtable<TempDescriptor, Integer> currtable) {
1016     /* Just propagate value */
1017     Integer srcvalue=currtable.get(fon.getLeft());
1018
1019     if (srcvalue==null) {
1020       if (!fon.getLeft().getType().isPtr()) {
1021         srcvalue=LOCAL;
1022       } else
1023         throw new Error(fon.getLeft()+" is undefined!");
1024     }
1025     currtable.put(fon.getDest(), srcvalue);
1026   }
1027
1028   void processCastNode(FlatCastNode fcn, Hashtable<TempDescriptor, Integer> currtable) {
1029     currtable.put(fcn.getDst(), currtable.get(fcn.getSrc()));
1030   }
1031
1032   void processLiteralNode(FlatLiteralNode fln, Hashtable<TempDescriptor, Integer> currtable) {
1033     //null is either
1034     if (fln.getValue()==null)
1035       currtable.put(fln.getDst(), EITHER);
1036     else
1037       currtable.put(fln.getDst(), LOCAL);
1038   }
1039
1040   void processOffsetNode(FlatOffsetNode fln, Hashtable<TempDescriptor, Integer> currtable) {
1041     currtable.put(fln.getDst(), LOCAL);
1042   }
1043
1044   void processReturnNode(LocalityBinding lb, FlatReturnNode frn, Hashtable<TempDescriptor, Integer> currtable) {
1045     if(frn.getReturnTemp()!=null) {
1046       Integer returntype=currtable.get(frn.getReturnTemp());
1047       lb.setGlobalReturn(merge(returntype, lb.getGlobalReturn()));
1048     }
1049   }
1050
1051   void processSetElementNode(LocalityBinding lb, FlatSetElementNode fsen, Hashtable<TempDescriptor, Integer> currtable, boolean isatomic) {
1052     Integer srctype=currtable.get(fsen.getSrc());
1053     Integer dsttype=currtable.get(fsen.getDst());
1054
1055     if (dsttype.equals(LOCAL)) {
1056       if (!(srctype.equals(LOCAL)||srctype.equals(EITHER)))
1057         throw new Error("Writing possible global reference to local object in context:\n"+lb.getExplanation()+fsen);
1058     } else if (dsttype.equals(GLOBAL)) {
1059       if (srctype.equals(LOCAL) && fsen.getDst().getType().dereference().isPrimitive() && !fsen.getDst().getType().dereference().isArray())
1060         return;
1061       if (!(srctype.equals(GLOBAL)||srctype.equals(EITHER)))
1062         throw new Error("Writing possible local reference to global object in context:\n"+lb.getExplanation());
1063       if (!isatomic)
1064         throw new Error("Global access outside of a transaction in context:\n"+lb.getExplanation());
1065     } else if (dsttype.equals(EITHER)) {
1066       if (srctype.equals(CONFLICT))
1067         throw new Error("Using reference that could be local or global in context:\n"+lb.getExplanation());
1068     } else if (dsttype.equals(CONFLICT)) {
1069       throw new Error("Access to object that could be either global or local in context:\n"+lb.getExplanation());
1070     }
1071   }
1072
1073   void processElementNode(LocalityBinding lb, FlatElementNode fen, Hashtable<TempDescriptor, Integer> currtable, boolean isatomic) {
1074     Integer type=currtable.get(fen.getSrc());
1075     TempDescriptor dst=fen.getDst();
1076     if (type.equals(LOCAL)) {
1077       currtable.put(dst,LOCAL);
1078     } else if (type.equals(GLOBAL)) {
1079       if (!isatomic)
1080         throw new Error("Global access outside of a transaction in context:\n"+lb.getExplanation());
1081       if(fen.getSrc().getType().dereference().isPrimitive()&&
1082          !fen.getSrc().getType().dereference().isArray())
1083         currtable.put(dst, LOCAL);
1084       else
1085         currtable.put(dst, GLOBAL);
1086     } else if (type.equals(EITHER)) {
1087       if(fen.getSrc().getType().dereference().isPrimitive()&&
1088          !fen.getSrc().getType().dereference().isArray())
1089         currtable.put(dst, LOCAL);
1090       else
1091         currtable.put(dst, EITHER);
1092     } else if (type.equals(CONFLICT)) {
1093       throw new Error("Access to object that could be either global or local in context:\n"+lb.getExplanation());
1094     }
1095   }
1096
1097   void processAtomicEnterNode(FlatAtomicEnterNode fen, Hashtable<FlatNode, Integer> atomictable) {
1098     int atomic=atomictable.get(fen).intValue();
1099     atomictable.put(fen, new Integer(atomic+1));
1100   }
1101
1102   void processAtomicExitNode(FlatAtomicExitNode fen, Hashtable<FlatNode, Integer> atomictable) {
1103     int atomic=atomictable.get(fen).intValue();
1104     atomictable.put(fen, new Integer(atomic-1));
1105   }
1106     
1107   Hashtable<FlatNode, Set<TempDescriptor>> computeLiveTemps(FlatMethod fm) {
1108     Hashtable<FlatNode, Set<TempDescriptor>> nodetotemps=new Hashtable<FlatNode, Set<TempDescriptor>>();
1109
1110     Set<FlatNode> toprocess=fm.getNodeSet();
1111
1112     while(!toprocess.isEmpty()) {
1113       FlatNode fn=toprocess.iterator().next();
1114       toprocess.remove(fn);
1115
1116       List<TempDescriptor> reads=Arrays.asList(fn.readsTemps());
1117       List<TempDescriptor> writes=Arrays.asList(fn.writesTemps());
1118
1119       HashSet<TempDescriptor> tempset=new HashSet<TempDescriptor>();
1120       for(int i=0; i<fn.numNext(); i++) {
1121         FlatNode fnnext=fn.getNext(i);
1122         if (nodetotemps.containsKey(fnnext))
1123           tempset.addAll(nodetotemps.get(fnnext));
1124       }
1125       tempset.removeAll(writes);
1126       tempset.addAll(reads);
1127       if (!nodetotemps.containsKey(fn)||
1128           !nodetotemps.get(fn).equals(tempset)) {
1129         nodetotemps.put(fn, tempset);
1130         for(int i=0; i<fn.numPrev(); i++)
1131           toprocess.add(fn.getPrev(i));
1132       }
1133     }
1134     return nodetotemps;
1135   }
1136
1137   private void computeTempstoSave() {
1138     for(Iterator<LocalityBinding> lbit=getLocalityBindings().iterator(); lbit.hasNext();) {
1139       LocalityBinding lb=lbit.next();
1140       computeTempstoSave(lb);
1141     }
1142   }
1143
1144   /* Need to checkpoint all temps that could be read from along any
1145    * path that are either:
1146      1) Written to by any assignment inside the transaction
1147      2) Read from a global temp.
1148
1149      Generate tempstosave map from
1150      localitybinding->flatatomicenternode->Set<TempDescriptors>
1151    */
1152
1153   private void computeTempstoSave(LocalityBinding lb) {
1154     if (lb.isAtomic())
1155       return;
1156     Hashtable<FlatNode, Integer> atomictab=getAtomic(lb);
1157     Hashtable<FlatNode, Hashtable<TempDescriptor, Integer>> temptab=getNodeTempInfo(lb);
1158     MethodDescriptor md=lb.getMethod();
1159     FlatMethod fm=state.getMethodFlat(md);
1160     Hashtable<FlatNode, Set<TempDescriptor>> nodetotemps=computeLiveTemps(fm);
1161     Hashtable<FlatAtomicEnterNode, Set<TempDescriptor>> nodetosavetemps=new Hashtable<FlatAtomicEnterNode, Set<TempDescriptor>>();
1162     tempstosave.put(lb, nodetosavetemps);
1163     Hashtable<FlatNode, FlatAtomicEnterNode> nodemap=new Hashtable<FlatNode, FlatAtomicEnterNode>();
1164     HashSet<FlatNode> toprocess=new HashSet<FlatNode>();
1165     HashSet<FlatNode> discovered=new HashSet<FlatNode>();
1166     toprocess.add(fm);
1167     discovered.add(fm);
1168     while(!toprocess.isEmpty()) {
1169       FlatNode fn=toprocess.iterator().next();
1170       toprocess.remove(fn);
1171       boolean isatomic=atomictab.get(fn).intValue()>0;
1172       if (isatomic&&
1173           atomictab.get(fn.getPrev(0)).intValue()==0) {
1174         assert(fn.getPrev(0).kind()==FKind.FlatAtomicEnterNode);
1175         nodemap.put(fn, (FlatAtomicEnterNode)fn);
1176         nodetosavetemps.put((FlatAtomicEnterNode)fn, new HashSet<TempDescriptor>());
1177       } else if (isatomic) {
1178         FlatAtomicEnterNode atomicnode=nodemap.get(fn);
1179         Set<TempDescriptor> livetemps=nodetotemps.get(fn);
1180         List<TempDescriptor> reads=Arrays.asList(fn.readsTemps());
1181         List<TempDescriptor> writes=Arrays.asList(fn.readsTemps());
1182
1183         for(Iterator<TempDescriptor> tempit=livetemps.iterator(); tempit.hasNext();) {
1184           TempDescriptor tmp=tempit.next();
1185           if (writes.contains(tmp)) {
1186             nodetosavetemps.get(atomicnode).add(tmp);
1187           } else if (state.DSM) {
1188             if (reads.contains(tmp)&&temptab.get(fn).get(tmp)==GLOBAL) {
1189               nodetosavetemps.get(atomicnode).add(tmp);
1190             } 
1191           } else if (state.SINGLETM) {
1192             if (reads.contains(tmp)&&tmp.getType().isPtr()&&temptab.get(fn).get(tmp)==NORMAL) {
1193               nodetosavetemps.get(atomicnode).add(tmp);
1194             } 
1195           }
1196         }
1197       }
1198       for(int i=0; i<fn.numNext(); i++) {
1199         FlatNode fnnext=fn.getNext(i);
1200         if (!discovered.contains(fnnext)) {
1201           discovered.add(fnnext);
1202           toprocess.add(fnnext);
1203           if(isatomic) {
1204             nodemap.put(fnnext, nodemap.get(fn));
1205           }
1206         }
1207       }
1208     }
1209   }
1210 }