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