clearer error message
[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, temptable.get(fn));
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
406
407       
408       Hashtable<TempDescriptor,Integer> oldtable=temptable.get(fn);
409       if (oldtable==null||!oldtable.equals(currtable)) {
410         // Update table for this node
411         temptable.put(fn, currtable);
412         for(int i=0; i<fn.numNext(); i++) {
413           tovisit.add(fn.getNext(i));
414         }
415       }
416     }
417   }
418
419   void processNewSTM(LocalityBinding lb, FlatNew fn, Hashtable<TempDescriptor, Integer> currtable) {
420     if (fn.isScratch())
421       currtable.put(fn.getDst(), SCRATCH);
422     else
423       currtable.put(fn.getDst(), NORMAL);
424   }
425
426   void processCallNodeSTM(LocalityBinding currlb, FlatCall fc, boolean isatomic, Hashtable<TempDescriptor, Integer> currtable, Hashtable<TempDescriptor, Integer> oldtable) {
427     MethodDescriptor nodemd=fc.getMethod();
428     Set methodset=null;
429     Set runmethodset=null;
430
431     if (nodemd.isStatic()||nodemd.getReturnType()==null) {
432       methodset=new HashSet();
433       methodset.add(nodemd);
434     } else {
435       methodset=callgraph.getMethods(nodemd, fc.getThis().getType());
436       // Build start -> run link
437       if (nodemd.getClassDesc().getSymbol().equals(TypeUtil.ThreadClass)&&
438           nodemd.getSymbol().equals("start")&&!nodemd.getModifiers().isStatic()&&
439           nodemd.numParameters()==0) {
440         assert(nodemd.getModifiers().isNative());
441
442         MethodDescriptor runmd=null;
443         for(Iterator methodit=nodemd.getClassDesc().getMethodTable().getSet("staticStart").iterator(); methodit.hasNext();) {
444           MethodDescriptor md=(MethodDescriptor) methodit.next();
445           if (md.numParameters()!=1||!md.getModifiers().isStatic()||!md.getParamType(0).getSymbol().equals(TypeUtil.ThreadClass))
446             continue;
447           runmd=md;
448           break;
449         }
450         if (runmd!=null) {
451           runmethodset=callgraph.getMethods(runmd,fc.getThis().getType());
452           methodset.addAll(runmethodset);
453         } else throw new Error("Can't find run method");
454       }
455     }
456
457     Integer currreturnval=STMEITHER;     //Start off with the either value
458     if (oldtable!=null&&fc.getReturnTemp()!=null&&
459         oldtable.get(fc.getReturnTemp())!=null) {
460       //ensure termination
461       currreturnval=mergestm(currreturnval, oldtable.get(fc.getReturnTemp()));
462     }
463
464     for(Iterator methodit=methodset.iterator(); methodit.hasNext();) {
465       MethodDescriptor md=(MethodDescriptor) methodit.next();
466
467       boolean isnative=md.getModifiers().isNative();
468       boolean isjoin = md.getClassDesc().getSymbol().equals(TypeUtil.ThreadClass)&&!nodemd.getModifiers().isStatic()&&nodemd.numParameters()==0&&md.getSymbol().equals("join");
469       boolean isObjectgetType = md.getClassDesc().getSymbol().equals("Object") && md.getSymbol().equals("getType");
470       boolean isObjecthashCode = md.getClassDesc().getSymbol().equals("Object") && md.getSymbol().equals("nativehashCode");
471
472       LocalityBinding lb=new LocalityBinding(md, isatomic);
473       if (isnative&&isatomic) {
474         System.out.println("Don't call native methods in atomic blocks!"+currlb.getMethod());
475       }
476
477       if (runmethodset==null||!runmethodset.contains(md)) {
478         for(int i=0; i<fc.numArgs(); i++) {
479           TempDescriptor arg=fc.getArg(i);
480           lb.setGlobal(i,currtable.get(arg));
481         }
482         if (fc.getThis()!=null) {
483           Integer thistype=currtable.get(fc.getThis());
484           if (thistype==null)
485             thistype=STMEITHER;
486           
487           if(thistype.equals(STMCONFLICT))
488             throw new Error("Using type that can be either normal or scratch in context:\n"+currlb.getExplanation());
489           lb.setGlobalThis(thistype);
490         }
491       } else {
492         Integer thistype=currtable.get(fc.getThis());
493         if (!thistype.equals(NORMAL)) {
494           throw new Error("Called start on possible scratch object");
495         }
496         lb.setGlobal(0,currtable.get(fc.getThis()));
497       }
498       //lb is built
499       if (!discovered.containsKey(lb)) {
500         if (isnative) {
501           if (nodemd.getReturnType()==null||!nodemd.getReturnType().isPtr())
502             lb.setGlobalReturn(SCRATCH);
503           else
504             lb.setGlobalReturn(NORMAL);
505         } else
506           lb.setGlobalReturn(STMEITHER);
507
508         lb.setParent(currlb);
509         lbtovisit.add(lb);
510         discovered.put(lb, lb);
511         if (!classtolb.containsKey(lb.getMethod().getClassDesc()))
512           classtolb.put(lb.getMethod().getClassDesc(), new HashSet<LocalityBinding>());
513         classtolb.get(lb.getMethod().getClassDesc()).add(lb);
514         if (!methodtolb.containsKey(lb.getMethod()))
515           methodtolb.put(lb.getMethod(), new HashSet<LocalityBinding>());
516         methodtolb.get(lb.getMethod()).add(lb);
517       } else
518         lb=discovered.get(lb);
519       Integer returnval=lb.getGlobalReturn();
520       currreturnval=mergestm(returnval, currreturnval);
521       if (!dependence.containsKey(lb))
522         dependence.put(lb, new HashSet<LocalityBinding>());
523       dependence.get(lb).add(currlb);
524
525       if (!calldep.containsKey(currlb))
526         calldep.put(currlb, new HashSet<LocalityBinding>());
527       calldep.get(currlb).add(lb);
528     }
529     if (fc.getReturnTemp()!=null) {
530       currtable.put(fc.getReturnTemp(), currreturnval);
531     }
532   }
533
534   void processFieldNodeSTM(LocalityBinding lb, FlatFieldNode ffn, Hashtable<TempDescriptor, Integer> currtable) {
535     Integer type=currtable.get(ffn.getSrc());
536     TempDescriptor dst=ffn.getDst();
537     if (type.equals(SCRATCH)) {
538       currtable.put(dst,SCRATCH);
539     } else if (type.equals(NORMAL)) {
540       if (ffn.getField().getType().isPrimitive()&&!ffn.getField().getType().isArray())
541         currtable.put(dst, SCRATCH);         // primitives are local
542       else
543         currtable.put(dst, NORMAL);
544     } else if (type.equals(STMEITHER)) {
545       if (ffn.getField().getType().isPrimitive()&&!ffn.getField().getType().isArray())
546         currtable.put(dst, SCRATCH);         // primitives are local
547       else
548         currtable.put(dst, STMEITHER);
549     } else if (type.equals(STMCONFLICT)) {
550       throw new Error("Access to object that could be either normal or scratch in context:\n"+ffn+"  "+lb.getExplanation());
551     }
552   }
553
554   //need to handle primitives
555   void processSetFieldNodeSTM(LocalityBinding lb, FlatSetFieldNode fsfn, Hashtable<TempDescriptor, Integer> currtable) {
556     Integer srctype=currtable.get(fsfn.getSrc());
557     Integer dsttype=currtable.get(fsfn.getDst());
558
559     if (dsttype.equals(SCRATCH)) {
560       if (srctype.equals(SCRATCH) && fsfn.getField().getType().isPrimitive() && !fsfn.getField().getType().isArray())
561         return;
562       if (!(srctype.equals(SCRATCH)||srctype.equals(STMEITHER)))
563         throw new Error("Writing possible normal reference to scratch object in context: \n"+lb.getExplanation());
564     } else if (dsttype.equals(NORMAL)) {
565       //okay to store primitives in global object
566       if (srctype.equals(SCRATCH) && fsfn.getField().getType().isPrimitive() && !fsfn.getField().getType().isArray())
567         return;
568       if (!(srctype.equals(NORMAL)||srctype.equals(STMEITHER)))
569         throw new Error("Writing possible scratch reference to normal object in context:\n"+lb.getExplanation()+" for FlatFieldNode "+fsfn);
570     } else if (dsttype.equals(STMEITHER)) {
571       if (srctype.equals(STMCONFLICT))
572         throw new Error("Using reference that could be scratch or normal in context:\n"+lb.getExplanation());
573     } else if (dsttype.equals(STMCONFLICT)) {
574       throw new Error("Access to object that could be either scratch or normal in context:\n"+lb.getExplanation());
575     }
576   }
577
578   void processSetElementNodeSTM(LocalityBinding lb, FlatSetElementNode fsen, Hashtable<TempDescriptor, Integer> currtable) {
579     Integer srctype=currtable.get(fsen.getSrc());
580     Integer dsttype=currtable.get(fsen.getDst());
581
582     if (dsttype.equals(SCRATCH)) {
583       if (!(srctype.equals(SCRATCH)||srctype.equals(STMEITHER)))
584         throw new Error("Writing possible normal reference to scratch object in context:\n"+lb.getExplanation()+fsen);
585     } else if (dsttype.equals(NORMAL)) {
586       if (srctype.equals(SCRATCH) && fsen.getDst().getType().dereference().isPrimitive() && !fsen.getDst().getType().dereference().isArray())
587         return;
588       if (!(srctype.equals(NORMAL)||srctype.equals(STMEITHER)))
589         throw new Error("Writing possible scratch reference to normal object in context:\n"+lb.getExplanation());
590     } else if (dsttype.equals(STMEITHER)) {
591       if (srctype.equals(STMCONFLICT))
592         throw new Error("Using reference that could be scratch or normal in context:\n"+lb.getExplanation());
593     } else if (dsttype.equals(STMCONFLICT)) {
594       throw new Error("Access to object that could be either normal or scratch in context:\n"+lb.getExplanation());
595     }
596   }
597
598   void processOpNodeSTM(FlatOpNode fon, Hashtable<TempDescriptor, Integer> currtable) {
599     /* Just propagate value */
600     Integer srcvalue=currtable.get(fon.getLeft());
601     
602     if (srcvalue==null) {
603       if (!fon.getLeft().getType().isPtr()) {
604         srcvalue=SCRATCH;
605       } else
606         throw new Error(fon.getLeft()+" is undefined!");
607     }
608     currtable.put(fon.getDest(), srcvalue);
609   }
610   
611    void processCastNodeSTM(FlatCastNode fcn, Hashtable<TempDescriptor, Integer> currtable) {
612     currtable.put(fcn.getDst(), currtable.get(fcn.getSrc()));
613   }
614
615   void processReturnNodeSTM(LocalityBinding lb, FlatReturnNode frn, Hashtable<TempDescriptor, Integer> currtable) {
616     if(frn.getReturnTemp()!=null) {
617       Integer returntype=currtable.get(frn.getReturnTemp());
618       lb.setGlobalReturn(mergestm(returntype, lb.getGlobalReturn()));
619     }
620   }
621   
622    void processLiteralNodeSTM(FlatLiteralNode fln, Hashtable<TempDescriptor, Integer> currtable) {
623     //null is either
624      if (fln.getType().isNull())
625        currtable.put(fln.getDst(), STMEITHER);
626      else if (fln.getType().isPtr())
627        currtable.put(fln.getDst(), NORMAL);
628      else
629        currtable.put(fln.getDst(), SCRATCH);
630   }
631
632   void processElementNodeSTM(LocalityBinding lb, FlatElementNode fen, Hashtable<TempDescriptor, Integer> currtable) {
633     Integer type=currtable.get(fen.getSrc());
634     TempDescriptor dst=fen.getDst();
635
636     if (type==null) {
637       System.out.println(fen +" in "+lb+" may access undefined variable");
638       System.exit(-1);
639     } else if (type.equals(SCRATCH)) {
640       currtable.put(dst,SCRATCH);
641     } else if (type.equals(NORMAL)) {
642       if(fen.getSrc().getType().dereference().isPrimitive()&&
643          !fen.getSrc().getType().dereference().isArray())
644         currtable.put(dst, SCRATCH);
645       else
646         currtable.put(dst, NORMAL);
647     } else if (type.equals(STMEITHER)) {
648       if(fen.getSrc().getType().dereference().isPrimitive()&&
649          !fen.getSrc().getType().dereference().isArray())
650         currtable.put(dst, SCRATCH);
651       else
652         currtable.put(dst, STMEITHER);
653     } else if (type.equals(STMCONFLICT)) {
654       throw new Error("Access to object that could be either global or local in context:\n"+lb.getExplanation());
655     }
656   }
657
658   private void computeLocalityBindings() {
659     lbmain=new LocalityBinding(typeutil.getMain(), false);
660     lbmain.setGlobalReturn(EITHER);
661     lbmain.setGlobal(0, LOCAL);
662     lbtovisit.add(lbmain);
663     discovered.put(lbmain, lbmain);
664     if (!classtolb.containsKey(lbmain.getMethod().getClassDesc()))
665       classtolb.put(lbmain.getMethod().getClassDesc(), new HashSet<LocalityBinding>());
666     classtolb.get(lbmain.getMethod().getClassDesc()).add(lbmain);
667
668     if (!methodtolb.containsKey(lbmain.getMethod()))
669       methodtolb.put(lbmain.getMethod(), new HashSet<LocalityBinding>());
670     methodtolb.get(lbmain.getMethod()).add(lbmain);
671
672     //Do this to force a virtual table number for the run method
673     lbrun=new LocalityBinding(typeutil.getRun(), false);
674     lbrun.setGlobalReturn(EITHER);
675     lbrun.setGlobalThis(GLOBAL);
676     lbtovisit.add(lbrun);
677     discovered.put(lbrun, lbrun);
678     if (!classtolb.containsKey(lbrun.getMethod().getClassDesc()))
679       classtolb.put(lbrun.getMethod().getClassDesc(), new HashSet<LocalityBinding>());
680     classtolb.get(lbrun.getMethod().getClassDesc()).add(lbrun);
681
682     if (!methodtolb.containsKey(lbrun.getMethod()))
683       methodtolb.put(lbrun.getMethod(), new HashSet<LocalityBinding>());
684     methodtolb.get(lbrun.getMethod()).add(lbrun);
685
686     while(!lbtovisit.empty()) {
687       LocalityBinding lb=(LocalityBinding) lbtovisit.pop();
688       Integer returnglobal=lb.getGlobalReturn();
689       MethodDescriptor md=lb.getMethod();
690       Hashtable<FlatNode,Hashtable<TempDescriptor, Integer>> temptable=new Hashtable<FlatNode,Hashtable<TempDescriptor, Integer>>();
691       Hashtable<FlatNode, Integer> atomictable=new Hashtable<FlatNode, Integer>();
692       calldep.remove(lb);
693       try {
694         computeCallsFlags(md, lb, temptable, atomictable);
695       } catch (Error e) {
696         System.out.println("Error in "+md+" context "+lb);
697         e.printStackTrace();
698         System.exit(-1);
699       }
700       temptab.put(lb, temptable);
701       atomictab.put(lb, atomictable);
702
703       if (md.getReturnType()!=null&&!returnglobal.equals(lb.getGlobalReturn())) {
704         //return type is more precise now
705         //rerun everything that call us
706         lbtovisit.addAll(dependence.get(lb));
707       }
708     }
709   }
710
711
712
713
714   public void computeCallsFlags(MethodDescriptor md, LocalityBinding lb, Hashtable<FlatNode, Hashtable<TempDescriptor, Integer>> temptable, Hashtable<FlatNode, Integer> atomictable) {
715     FlatMethod fm=state.getMethodFlat(md);
716     HashSet<FlatNode> tovisit=new HashSet<FlatNode>();
717     tovisit.add(fm.getNext(0));
718     {
719       // Build table for initial node
720       Hashtable<TempDescriptor,Integer> table=new Hashtable<TempDescriptor,Integer>();
721       temptable.put(fm, table);
722       atomictable.put(fm, lb.isAtomic() ? 1 : 0);
723       int offset=md.isStatic() ? 0 : 1;
724       if (!md.isStatic()) {
725         table.put(fm.getParameter(0), lb.getGlobalThis());
726       }
727       for(int i=offset; i<fm.numParameters(); i++) {
728         TempDescriptor temp=fm.getParameter(i);
729         Integer b=lb.isGlobal(i-offset);
730         table.put(temp,b);
731       }
732     }
733
734     while(!tovisit.isEmpty()) {
735       FlatNode fn=tovisit.iterator().next();
736       tovisit.remove(fn);
737       Hashtable<TempDescriptor, Integer> currtable=new Hashtable<TempDescriptor, Integer>();
738       int atomicstate=0;
739       for(int i=0; i<fn.numPrev(); i++) {
740         FlatNode prevnode=fn.getPrev(i);
741         if (atomictable.containsKey(prevnode)) {
742           atomicstate=atomictable.get(prevnode).intValue();
743         }
744         if (!temptable.containsKey(prevnode))
745           continue;
746         Hashtable<TempDescriptor, Integer> prevtable=temptable.get(prevnode);
747         for(Iterator<TempDescriptor> tempit=prevtable.keySet().iterator(); tempit.hasNext();) {
748           TempDescriptor temp=tempit.next();
749           Integer tmpint=prevtable.get(temp);
750           Integer oldint=currtable.containsKey(temp) ? currtable.get(temp) : EITHER;
751           Integer newint=merge(tmpint, oldint);
752           currtable.put(temp, newint);
753         }
754       }
755       atomictable.put(fn, atomicstate);
756       // Process this node
757       switch(fn.kind()) {
758       case FKind.FlatAtomicEnterNode:
759         processAtomicEnterNode((FlatAtomicEnterNode)fn, atomictable);
760         if (!lb.isAtomic())
761           lb.setHasAtomic();
762         break;
763
764       case FKind.FlatAtomicExitNode:
765         processAtomicExitNode((FlatAtomicExitNode)fn, atomictable);
766         break;
767
768       case FKind.FlatCall:
769         processCallNode(lb, (FlatCall)fn, currtable, isAtomic(atomictable, fn));
770         break;
771
772       case FKind.FlatFieldNode:
773         processFieldNode(lb, (FlatFieldNode)fn, isAtomic(atomictable, fn), currtable);
774         break;
775
776       case FKind.FlatSetFieldNode:
777         processSetFieldNode(lb, (FlatSetFieldNode)fn, isAtomic(atomictable,fn), currtable);
778         break;
779
780       case FKind.FlatNew:
781         processNew(lb, (FlatNew)fn, isAtomic(atomictable, fn), currtable);
782         break;
783
784       case FKind.FlatOpNode:
785         processOpNode((FlatOpNode)fn, currtable);
786         break;
787
788       case FKind.FlatCastNode:
789         processCastNode((FlatCastNode)fn, currtable);
790         break;
791
792       case FKind.FlatLiteralNode:
793         processLiteralNode((FlatLiteralNode)fn, currtable);
794         break;
795
796       case FKind.FlatReturnNode:
797         processReturnNode(lb, (FlatReturnNode)fn, currtable);
798         break;
799
800       case FKind.FlatSetElementNode:
801         processSetElementNode(lb, (FlatSetElementNode)fn, currtable, isAtomic(atomictable, fn));
802         break;
803
804       case FKind.FlatElementNode:
805         processElementNode(lb, (FlatElementNode)fn, currtable, isAtomic(atomictable, fn));
806         break;
807
808       case FKind.FlatInstanceOfNode:
809       case FKind.FlatCondBranch:
810       case FKind.FlatBackEdge:
811       case FKind.FlatNop:
812       case FKind.FlatExit:
813       case FKind.FlatPrefetchNode:
814         //No action needed for these
815         break;
816
817       case FKind.FlatFlagActionNode:
818       case FKind.FlatCheckNode:
819       case FKind.FlatTagDeclaration:
820         throw new Error("Incompatible with tasks!");
821
822       case FKind.FlatMethod:
823         break;
824
825       case FKind.FlatOffsetNode:
826         processOffsetNode((FlatOffsetNode)fn, currtable);
827         break;
828
829       default:
830         throw new Error("In finding fn.kind()= " + fn.kind());
831       }
832       Hashtable<TempDescriptor,Integer> oldtable=temptable.get(fn);
833       if (oldtable==null||!oldtable.equals(currtable)) {
834         // Update table for this node
835         temptable.put(fn, currtable);
836         for(int i=0; i<fn.numNext(); i++) {
837           tovisit.add(fn.getNext(i));
838         }
839       }
840     }
841   }
842
843   private static boolean isAtomic(Hashtable<FlatNode, Integer> atomictable, FlatNode fn) {
844     return atomictable.get(fn).intValue()>0;
845   }
846
847   private static Integer merge(Integer a, Integer b) {
848     if (a==null||a.equals(EITHER))
849       return b;
850     if (b==null||b.equals(EITHER))
851       return a;
852     if (a.equals(b))
853       return a;
854     return CONFLICT;
855   }
856
857   void processCallNode(LocalityBinding currlb, FlatCall fc, Hashtable<TempDescriptor, Integer> currtable, boolean isatomic) {
858     MethodDescriptor nodemd=fc.getMethod();
859     Set methodset=null;
860     Set runmethodset=null;
861
862     if (nodemd.isStatic()||nodemd.getReturnType()==null) {
863       methodset=new HashSet();
864       methodset.add(nodemd);
865     } else {
866       methodset=callgraph.getMethods(nodemd, fc.getThis().getType());
867       // Build start -> run link
868       if (nodemd.getClassDesc().getSymbol().equals(TypeUtil.ThreadClass)&&
869           nodemd.getSymbol().equals("start")&&!nodemd.getModifiers().isStatic()&&
870           nodemd.numParameters()==1&&nodemd.getParamType(0).isInt()) {
871         assert(nodemd.getModifiers().isNative());
872
873         MethodDescriptor runmd=null;
874         for(Iterator methodit=nodemd.getClassDesc().getMethodTable().getSet("run").iterator(); methodit.hasNext();) {
875           MethodDescriptor md=(MethodDescriptor) methodit.next();
876           if (md.numParameters()!=0||md.getModifiers().isStatic())
877             continue;
878           runmd=md;
879           break;
880         }
881         if (runmd!=null) {
882           runmethodset=callgraph.getMethods(runmd,fc.getThis().getType());
883           methodset.addAll(runmethodset);
884         } else throw new Error("Can't find run method");
885       }
886     }
887
888     Integer currreturnval=EITHER;     //Start off with the either value
889     for(Iterator methodit=methodset.iterator(); methodit.hasNext();) {
890       MethodDescriptor md=(MethodDescriptor) methodit.next();
891
892       boolean isnative=md.getModifiers().isNative();
893       boolean isjoin = md.getClassDesc().getSymbol().equals(TypeUtil.ThreadClass)&&!nodemd.getModifiers().isStatic()&&nodemd.numParameters()==0&&md.getSymbol().equals("join");
894       boolean isObjectgetType = md.getClassDesc().getSymbol().equals("Object") && md.getSymbol().equals("getType");
895       boolean isObjecthashCode = md.getClassDesc().getSymbol().equals("Object") && md.getSymbol().equals("nativehashCode");
896
897       LocalityBinding lb=new LocalityBinding(md, isatomic);
898       if (isnative&&isatomic) {
899         System.out.println("Don't call native methods in atomic blocks!"+currlb.getMethod());
900       }
901       if (runmethodset==null||!runmethodset.contains(md)) {
902         //Skip this part if it is a run method
903         for(int i=0; i<fc.numArgs(); i++) {
904           TempDescriptor arg=fc.getArg(i);
905           if(isnative&&(currtable.get(arg).equals(GLOBAL)||
906                         currtable.get(arg).equals(CONFLICT))&& !(nodemd.getSymbol().equals("rangePrefetch"))) {
907             throw new Error("Potential call to native method "+md+" with global parameter:\n"+currlb.getExplanation());
908           }
909           lb.setGlobal(i,currtable.get(arg));
910         }
911       }
912
913       if (fc.getThis()!=null) {
914         Integer thistype=currtable.get(fc.getThis());
915         if (thistype==null)
916           thistype=EITHER;
917
918         if(runmethodset!=null&&runmethodset.contains(md)&&thistype.equals(LOCAL))
919           throw new Error("Starting thread on local object not allowed in context:\n"+currlb.getExplanation());
920         if(isjoin&&thistype.equals(LOCAL))
921           throw new Error("Joining thread on local object not allowed in context:\n"+currlb.getExplanation());
922         if(thistype.equals(CONFLICT))
923           throw new Error("Using type that can be either local or global in context:\n"+currlb.getExplanation());
924         if(runmethodset==null&&thistype.equals(GLOBAL)&&!isatomic && !isjoin)
925           throw new Error("Using global object outside of transaction in context:\n"+currlb.getExplanation());
926         if (runmethodset==null&&isnative&&thistype.equals(GLOBAL) && !isjoin && !isObjectgetType && !isObjecthashCode)
927           throw new Error("Potential call to native method "+md+" on global objects:\n"+currlb.getExplanation());
928         lb.setGlobalThis(thistype);
929       }
930       //lb is built
931       if (!discovered.containsKey(lb)) {
932         if (isnative)
933           lb.setGlobalReturn(LOCAL);
934         else
935           lb.setGlobalReturn(EITHER);
936         lb.setParent(currlb);
937         lbtovisit.add(lb);
938         discovered.put(lb, lb);
939         if (!classtolb.containsKey(lb.getMethod().getClassDesc()))
940           classtolb.put(lb.getMethod().getClassDesc(), new HashSet<LocalityBinding>());
941         classtolb.get(lb.getMethod().getClassDesc()).add(lb);
942         if (!methodtolb.containsKey(lb.getMethod()))
943           methodtolb.put(lb.getMethod(), new HashSet<LocalityBinding>());
944         methodtolb.get(lb.getMethod()).add(lb);
945       } else
946         lb=discovered.get(lb);
947       Integer returnval=lb.getGlobalReturn();
948       currreturnval=merge(returnval, currreturnval);
949       if (!dependence.containsKey(lb))
950         dependence.put(lb, new HashSet<LocalityBinding>());
951       dependence.get(lb).add(currlb);
952
953       if (!calldep.containsKey(currlb))
954         calldep.put(currlb, new HashSet<LocalityBinding>());
955       calldep.get(currlb).add(lb);
956     }
957     if (fc.getReturnTemp()!=null) {
958       currtable.put(fc.getReturnTemp(), currreturnval);
959     }
960   }
961
962   void processFieldNode(LocalityBinding lb, FlatFieldNode ffn, boolean transaction, Hashtable<TempDescriptor, Integer> currtable) {
963     Integer type=currtable.get(ffn.getSrc());
964     TempDescriptor dst=ffn.getDst();
965     if (type.equals(LOCAL)) {
966       if (ffn.getField().isGlobal())
967         currtable.put(dst,GLOBAL);
968       else
969         currtable.put(dst,LOCAL);
970     } else if (type.equals(GLOBAL)) {
971       if (!transaction)
972         throw new Error("Global access outside of a transaction in context:\n"+lb.getExplanation());
973       if (ffn.getField().getType().isPrimitive()&&!ffn.getField().getType().isArray())
974         currtable.put(dst, LOCAL);         // primitives are local
975       else
976         currtable.put(dst, GLOBAL);
977     } else if (type.equals(EITHER)) {
978       if (ffn.getField().getType().isPrimitive()&&!ffn.getField().getType().isArray())
979         currtable.put(dst, LOCAL);         // primitives are local
980       else if (ffn.getField().isGlobal())
981         currtable.put(dst, GLOBAL);
982       else
983         currtable.put(dst, EITHER);
984     } else if (type.equals(CONFLICT)) {
985       throw new Error("Access to object that could be either global or local in context:\n"+lb.getExplanation());
986     }
987   }
988
989   //need to handle primitives
990   void processSetFieldNode(LocalityBinding lb, FlatSetFieldNode fsfn, boolean transaction, Hashtable<TempDescriptor, Integer> currtable) {
991     Integer srctype=currtable.get(fsfn.getSrc());
992     Integer dsttype=currtable.get(fsfn.getDst());
993
994     if (dsttype.equals(LOCAL)) {
995       if (fsfn.getField().isGlobal()) {
996         if (!(srctype.equals(GLOBAL)||srctype.equals(EITHER)))
997           throw new Error("Writing possible local reference to global field in context: \n"+lb.getExplanation());
998       } else {
999         if (!(srctype.equals(LOCAL)||srctype.equals(EITHER)))
1000           throw new Error("Writing possible global reference to local object in context: \n"+lb.getExplanation());
1001       }
1002     } else if (dsttype.equals(GLOBAL)) {
1003       if (!transaction)
1004         throw new Error("Global access outside of a transaction in context:\n"+lb.getExplanation());
1005       //okay to store primitives in global object
1006       if (srctype.equals(LOCAL) && fsfn.getField().getType().isPrimitive() && !fsfn.getField().getType().isArray())
1007         return;
1008       if (!(srctype.equals(GLOBAL)||srctype.equals(EITHER)))
1009         throw new Error("Writing possible local reference to global object in context:\n"+lb.getExplanation()+" for FlatFieldNode "+fsfn);
1010     } else if (dsttype.equals(EITHER)) {
1011       if (srctype.equals(CONFLICT))
1012         throw new Error("Using reference that could be local or global in context:\n"+lb.getExplanation());
1013     } else if (dsttype.equals(CONFLICT)) {
1014       throw new Error("Access to object that could be either global or local in context:\n"+lb.getExplanation());
1015     }
1016   }
1017
1018   void processNew(LocalityBinding lb, FlatNew fn, boolean transaction, Hashtable<TempDescriptor, Integer> currtable) {
1019     if (fn.isGlobal()&&!transaction) {
1020       throw new Error("Allocating global object outside of transaction in context:"+lb.getExplanation());
1021     }
1022     if (fn.isGlobal())
1023       currtable.put(fn.getDst(), GLOBAL);
1024     else
1025       currtable.put(fn.getDst(), LOCAL);
1026   }
1027
1028   void processOpNode(FlatOpNode fon, Hashtable<TempDescriptor, Integer> currtable) {
1029     /* Just propagate value */
1030     Integer srcvalue=currtable.get(fon.getLeft());
1031
1032     if (srcvalue==null) {
1033       if (!fon.getLeft().getType().isPtr()) {
1034         srcvalue=LOCAL;
1035       } else
1036         throw new Error(fon.getLeft()+" is undefined!");
1037     }
1038     currtable.put(fon.getDest(), srcvalue);
1039   }
1040
1041   void processCastNode(FlatCastNode fcn, Hashtable<TempDescriptor, Integer> currtable) {
1042     currtable.put(fcn.getDst(), currtable.get(fcn.getSrc()));
1043   }
1044
1045   void processLiteralNode(FlatLiteralNode fln, Hashtable<TempDescriptor, Integer> currtable) {
1046     //null is either
1047     if (fln.getValue()==null)
1048       currtable.put(fln.getDst(), EITHER);
1049     else
1050       currtable.put(fln.getDst(), LOCAL);
1051   }
1052
1053   void processOffsetNode(FlatOffsetNode fln, Hashtable<TempDescriptor, Integer> currtable) {
1054     currtable.put(fln.getDst(), LOCAL);
1055   }
1056
1057   void processReturnNode(LocalityBinding lb, FlatReturnNode frn, Hashtable<TempDescriptor, Integer> currtable) {
1058     if(frn.getReturnTemp()!=null) {
1059       Integer returntype=currtable.get(frn.getReturnTemp());
1060       lb.setGlobalReturn(merge(returntype, lb.getGlobalReturn()));
1061     }
1062   }
1063
1064   void processSetElementNode(LocalityBinding lb, FlatSetElementNode fsen, Hashtable<TempDescriptor, Integer> currtable, boolean isatomic) {
1065     Integer srctype=currtable.get(fsen.getSrc());
1066     Integer dsttype=currtable.get(fsen.getDst());
1067
1068     if (dsttype.equals(LOCAL)) {
1069       if (!(srctype.equals(LOCAL)||srctype.equals(EITHER)))
1070         throw new Error("Writing possible global reference to local object in context:\n"+lb.getExplanation()+fsen);
1071     } else if (dsttype.equals(GLOBAL)) {
1072       if (srctype.equals(LOCAL) && fsen.getDst().getType().dereference().isPrimitive() && !fsen.getDst().getType().dereference().isArray())
1073         return;
1074       if (!(srctype.equals(GLOBAL)||srctype.equals(EITHER)))
1075         throw new Error("Writing possible local reference to global object in context:\n"+lb.getExplanation());
1076       if (!isatomic)
1077         throw new Error("Global access outside of a transaction in context:\n"+lb.getExplanation());
1078     } else if (dsttype.equals(EITHER)) {
1079       if (srctype.equals(CONFLICT))
1080         throw new Error("Using reference that could be local or global in context:\n"+lb.getExplanation());
1081     } else if (dsttype.equals(CONFLICT)) {
1082       throw new Error("Access to object that could be either global or local in context:\n"+lb.getExplanation());
1083     }
1084   }
1085
1086   void processElementNode(LocalityBinding lb, FlatElementNode fen, Hashtable<TempDescriptor, Integer> currtable, boolean isatomic) {
1087     Integer type=currtable.get(fen.getSrc());
1088     TempDescriptor dst=fen.getDst();
1089     if (type.equals(LOCAL)) {
1090       currtable.put(dst,LOCAL);
1091     } else if (type.equals(GLOBAL)) {
1092       if (!isatomic)
1093         throw new Error("Global access outside of a transaction in context:\n"+lb.getExplanation());
1094       if(fen.getSrc().getType().dereference().isPrimitive()&&
1095          !fen.getSrc().getType().dereference().isArray())
1096         currtable.put(dst, LOCAL);
1097       else
1098         currtable.put(dst, GLOBAL);
1099     } else if (type.equals(EITHER)) {
1100       if(fen.getSrc().getType().dereference().isPrimitive()&&
1101          !fen.getSrc().getType().dereference().isArray())
1102         currtable.put(dst, LOCAL);
1103       else
1104         currtable.put(dst, EITHER);
1105     } else if (type.equals(CONFLICT)) {
1106       throw new Error("Access to object that could be either global or local in context:\n"+lb.getExplanation());
1107     }
1108   }
1109
1110   void processAtomicEnterNode(FlatAtomicEnterNode fen, Hashtable<FlatNode, Integer> atomictable) {
1111     int atomic=atomictable.get(fen).intValue();
1112     atomictable.put(fen, new Integer(atomic+1));
1113   }
1114
1115   void processAtomicExitNode(FlatAtomicExitNode fen, Hashtable<FlatNode, Integer> atomictable) {
1116     int atomic=atomictable.get(fen).intValue();
1117     atomictable.put(fen, new Integer(atomic-1));
1118   }
1119     
1120   Hashtable<FlatNode, Set<TempDescriptor>> computeLiveTemps(FlatMethod fm) {
1121     Hashtable<FlatNode, Set<TempDescriptor>> nodetotemps=new Hashtable<FlatNode, Set<TempDescriptor>>();
1122
1123     Set<FlatNode> toprocess=fm.getNodeSet();
1124
1125     while(!toprocess.isEmpty()) {
1126       FlatNode fn=toprocess.iterator().next();
1127       toprocess.remove(fn);
1128
1129       List<TempDescriptor> reads=Arrays.asList(fn.readsTemps());
1130       List<TempDescriptor> writes=Arrays.asList(fn.writesTemps());
1131
1132       HashSet<TempDescriptor> tempset=new HashSet<TempDescriptor>();
1133       for(int i=0; i<fn.numNext(); i++) {
1134         FlatNode fnnext=fn.getNext(i);
1135         if (nodetotemps.containsKey(fnnext))
1136           tempset.addAll(nodetotemps.get(fnnext));
1137       }
1138       tempset.removeAll(writes);
1139       tempset.addAll(reads);
1140       if (!nodetotemps.containsKey(fn)||
1141           !nodetotemps.get(fn).equals(tempset)) {
1142         nodetotemps.put(fn, tempset);
1143         for(int i=0; i<fn.numPrev(); i++)
1144           toprocess.add(fn.getPrev(i));
1145       }
1146     }
1147     return nodetotemps;
1148   }
1149
1150   private void computeTempstoSave() {
1151     for(Iterator<LocalityBinding> lbit=getLocalityBindings().iterator(); lbit.hasNext();) {
1152       LocalityBinding lb=lbit.next();
1153       computeTempstoSave(lb);
1154     }
1155   }
1156
1157   /* Need to checkpoint all temps that could be read from along any
1158    * path that are either:
1159      1) Written to by any assignment inside the transaction
1160      2) Read from a global temp.
1161
1162      Generate tempstosave map from
1163      localitybinding->flatatomicenternode->Set<TempDescriptors>
1164    */
1165
1166   private void computeTempstoSave(LocalityBinding lb) {
1167     if (lb.isAtomic())
1168       return;
1169     Hashtable<FlatNode, Integer> atomictab=getAtomic(lb);
1170     Hashtable<FlatNode, Hashtable<TempDescriptor, Integer>> temptab=getNodeTempInfo(lb);
1171     MethodDescriptor md=lb.getMethod();
1172     FlatMethod fm=state.getMethodFlat(md);
1173     Hashtable<FlatNode, Set<TempDescriptor>> nodetotemps=computeLiveTemps(fm);
1174     Hashtable<FlatAtomicEnterNode, Set<TempDescriptor>> nodetosavetemps=new Hashtable<FlatAtomicEnterNode, Set<TempDescriptor>>();
1175     tempstosave.put(lb, nodetosavetemps);
1176     Hashtable<FlatNode, FlatAtomicEnterNode> nodemap=new Hashtable<FlatNode, FlatAtomicEnterNode>();
1177     HashSet<FlatNode> toprocess=new HashSet<FlatNode>();
1178     HashSet<FlatNode> discovered=new HashSet<FlatNode>();
1179     toprocess.add(fm);
1180     discovered.add(fm);
1181     while(!toprocess.isEmpty()) {
1182       FlatNode fn=toprocess.iterator().next();
1183       toprocess.remove(fn);
1184       boolean isatomic=atomictab.get(fn).intValue()>0;
1185       if (isatomic&&
1186           atomictab.get(fn.getPrev(0)).intValue()==0) {
1187         assert(fn.getPrev(0).kind()==FKind.FlatAtomicEnterNode);
1188         nodemap.put(fn, (FlatAtomicEnterNode)fn);
1189         nodetosavetemps.put((FlatAtomicEnterNode)fn, new HashSet<TempDescriptor>());
1190       } else if (isatomic) {
1191         FlatAtomicEnterNode atomicnode=nodemap.get(fn);
1192         Set<TempDescriptor> livetemps=nodetotemps.get(fn);
1193         List<TempDescriptor> reads=Arrays.asList(fn.readsTemps());
1194         List<TempDescriptor> writes=Arrays.asList(fn.readsTemps());
1195
1196         for(Iterator<TempDescriptor> tempit=livetemps.iterator(); tempit.hasNext();) {
1197           TempDescriptor tmp=tempit.next();
1198           if (writes.contains(tmp)) {
1199             nodetosavetemps.get(atomicnode).add(tmp);
1200           } else if (state.DSM) {
1201             if (reads.contains(tmp)&&temptab.get(fn).get(tmp)==GLOBAL) {
1202               nodetosavetemps.get(atomicnode).add(tmp);
1203             } 
1204           } else if (state.SINGLETM) {
1205             if (reads.contains(tmp)&&tmp.getType().isPtr()&&temptab.get(fn).get(tmp)==NORMAL) {
1206               nodetosavetemps.get(atomicnode).add(tmp);
1207             } 
1208           }
1209         }
1210       }
1211       for(int i=0; i<fn.numNext(); i++) {
1212         FlatNode fnnext=fn.getNext(i);
1213         if (!discovered.contains(fnnext)) {
1214           discovered.add(fnnext);
1215           toprocess.add(fnnext);
1216           if(isatomic) {
1217             nodemap.put(fnnext, nodemap.get(fn));
1218           }
1219         }
1220       }
1221     }
1222   }
1223 }