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