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