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