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