patches to:
[IRC.git] / Robust / src / Analysis / Locality / LocalityAnalysis.java
1 package Analysis.Locality;
2
3 import java.util.*;
4 import Analysis.CallGraph.CallGraph;
5 import IR.SymbolTable;
6 import IR.State;
7 import IR.TypeUtil;
8 import IR.MethodDescriptor;
9 import IR.Flat.*;
10 import IR.ClassDescriptor;
11
12 public class LocalityAnalysis {
13     State state;
14     Stack lbtovisit;
15     Hashtable<LocalityBinding,LocalityBinding> discovered;
16     Hashtable<LocalityBinding, Set<LocalityBinding>> dependence;
17     Hashtable<LocalityBinding, Set<LocalityBinding>> calldep;
18     Hashtable<LocalityBinding, Hashtable<FlatNode,Hashtable<TempDescriptor, Integer>>> temptab;
19     Hashtable<LocalityBinding, Hashtable<FlatNode, Integer>> atomictab;
20     Hashtable<LocalityBinding, Hashtable<FlatAtomicEnterNode, Set<TempDescriptor>>> tempstosave;
21     Hashtable<ClassDescriptor, Set<LocalityBinding>> classtolb;
22     Hashtable<MethodDescriptor, Set<LocalityBinding>> methodtolb;
23     private LocalityBinding lbmain;
24     private LocalityBinding lbrun;
25
26     CallGraph callgraph;
27     TypeUtil typeutil;
28     public static final Integer LOCAL=new Integer(0);
29     public static final Integer GLOBAL=new Integer(1);
30     public static final Integer EITHER=new Integer(2);
31     public static final Integer CONFLICT=new Integer(3);
32
33     public LocalityAnalysis(State state, CallGraph callgraph, TypeUtil typeutil) {
34         this.typeutil=typeutil;
35         this.state=state;
36         this.discovered=new Hashtable<LocalityBinding,LocalityBinding>();
37         this.dependence=new Hashtable<LocalityBinding, Set<LocalityBinding>>();
38         this.calldep=new Hashtable<LocalityBinding, Set<LocalityBinding>>();
39         this.temptab=new Hashtable<LocalityBinding, Hashtable<FlatNode,Hashtable<TempDescriptor, Integer>>>();
40         this.atomictab=new Hashtable<LocalityBinding, Hashtable<FlatNode, Integer>>();
41         this.lbtovisit=new Stack();
42         this.callgraph=callgraph;
43         this.tempstosave=new Hashtable<LocalityBinding, Hashtable<FlatAtomicEnterNode, Set<TempDescriptor>>>();
44         this.classtolb=new Hashtable<ClassDescriptor, Set<LocalityBinding>>();
45         this.methodtolb=new Hashtable<MethodDescriptor, Set<LocalityBinding>>();
46         doAnalysis();
47     }
48
49     public LocalityBinding getMain() {
50         return lbmain;
51     }
52
53     /** This method returns the set of LocalityBindings that a given
54      * flatcall could invoke */
55
56     public LocalityBinding getBinding(LocalityBinding currlb, FlatCall fc) {
57         boolean isatomic=getAtomic(currlb).get(fc).intValue()>0;
58         Hashtable<TempDescriptor, Integer> currtable=getNodePreTempInfo(currlb,fc);
59         MethodDescriptor md=fc.getMethod();
60         
61         boolean isnative=md.getModifiers().isNative();
62         
63         LocalityBinding lb=new LocalityBinding(md, isatomic);
64         
65         for(int i=0;i<fc.numArgs();i++) {
66             TempDescriptor arg=fc.getArg(i);
67             lb.setGlobal(i,currtable.get(arg));
68         }
69         if (fc.getThis()!=null) {
70             Integer thistype=currtable.get(fc.getThis());
71             if (thistype==null)
72                 thistype=EITHER;
73             lb.setGlobalThis(thistype);
74         }// else
75         // lb.setGlobalThis(EITHER);//default value
76         if (discovered.containsKey(lb))
77             lb=discovered.get(lb);
78         else throw new Error();
79         return lb;
80     }
81
82
83     /** This method returns a set of LocalityBindings for the parameter class. */
84     public Set<LocalityBinding> getClassBindings(ClassDescriptor cd) {
85         return classtolb.get(cd);
86     }
87
88     /** This method returns a set of LocalityBindings for the parameter method. */
89         
90     public Set<LocalityBinding> getMethodBindings(MethodDescriptor md) {
91         return methodtolb.get(md);
92     }
93
94     /** This method returns a set of LocalityBindings.  A
95      * LocalityBinding specifies a context a method can be invoked in.
96      * It specifies whether the method is in a transaction and whether
97      * its parameter objects are locals or globals.  */
98
99     public Set<LocalityBinding> getLocalityBindings() {
100         return discovered.keySet();
101     }
102
103     /** This method returns a hashtable for a given LocalityBinding
104      * that tells the current local/global status of temps at the each
105      * node in the flat representation. */
106
107     public Hashtable<FlatNode, Hashtable<TempDescriptor, Integer>> getNodeTempInfo(LocalityBinding lb) {
108         return temptab.get(lb);
109     }
110
111     /** This method returns a hashtable for a given LocalityBinding
112      * that tells the current local/global status of temps at the
113      * beginning of each node in the flat representation. */
114
115     public Hashtable<TempDescriptor, Integer> getNodePreTempInfo(LocalityBinding lb, FlatNode fn) {
116         Hashtable<TempDescriptor, Integer> currtable=new Hashtable<TempDescriptor, Integer>();
117         Hashtable<FlatNode, Hashtable<TempDescriptor, Integer>> temptable=getNodeTempInfo(lb);
118
119         for(int i=0;i<fn.numPrev();i++) {
120             FlatNode prevnode=fn.getPrev(i);
121             Hashtable<TempDescriptor, Integer> prevtable=temptable.get(prevnode);
122             for(Iterator<TempDescriptor> tempit=prevtable.keySet().iterator();tempit.hasNext();) {
123                 TempDescriptor temp=tempit.next();
124                 Integer tmpint=prevtable.get(temp);
125                 Integer oldint=currtable.containsKey(temp)?currtable.get(temp):EITHER;
126                 Integer newint=merge(tmpint, oldint);
127                 currtable.put(temp, newint);
128             }
129         }
130         return currtable;
131     }
132
133     /** This method returns an hashtable for a given LocalitBinding
134      * that tells whether a node in the flat represenation is in a
135      * transaction or not.  Integer values greater than 0 indicate
136      * that the node is in a transaction and give the nesting depth.
137      * The outermost AtomicEnterNode will have a value of 1 and the
138      * outermost AtomicExitNode will have a value of 0. */
139     
140     public Hashtable<FlatNode, Integer> getAtomic(LocalityBinding lb) {
141         return atomictab.get(lb);
142     }
143
144     /** This methods returns a hashtable for a given LocalityBinding
145      * that tells which temps needs to be saved for each
146      * AtomicEnterNode.  */
147
148     public Hashtable<FlatAtomicEnterNode, Set<TempDescriptor>> getTemps(LocalityBinding lb) {
149         return tempstosave.get(lb);
150     }
151
152     public Set<TempDescriptor> getTempSet(LocalityBinding lb) {
153         HashSet<TempDescriptor> set=new HashSet<TempDescriptor>();
154         Hashtable<FlatAtomicEnterNode, Set<TempDescriptor>> table=getTemps(lb);
155         if (table!=null)
156             for(Iterator<FlatAtomicEnterNode> faenit=table.keySet().iterator();faenit.hasNext();) {
157                 FlatAtomicEnterNode faen=faenit.next();
158                 set.addAll(table.get(faen));
159             }
160         return set;
161     }
162
163     private void doAnalysis() {
164         computeLocalityBindings();
165         computeTempstoSave();
166         cleanSets();
167     }
168
169     private void cleanSets() {
170         HashSet<LocalityBinding> lbset=new HashSet<LocalityBinding>();
171         Stack<LocalityBinding> lbstack=new Stack<LocalityBinding>();
172         lbstack.add(lbmain);
173         lbstack.add(lbrun);
174         lbset.add(lbmain);
175         lbset.add(lbrun);
176         while(!lbstack.isEmpty()) {
177             LocalityBinding lb=lbstack.pop();
178             if (calldep.containsKey(lb)) {
179                 Set<LocalityBinding> set=new HashSet<LocalityBinding>();
180                 set.addAll(calldep.get(lb));
181                 set.removeAll(lbset);
182                 lbstack.addAll(set);
183                 lbset.addAll(set);
184             }
185         }
186         for(Iterator<LocalityBinding> lbit=discovered.keySet().iterator();lbit.hasNext();) {
187             LocalityBinding lb=lbit.next();
188             if (!lbset.contains(lb)) {
189                 lbit.remove();
190                 classtolb.get(lb.getMethod().getClassDesc()).remove(lb);
191                 methodtolb.get(lb.getMethod()).remove(lb);
192             }
193         }
194     }
195     
196     private void computeLocalityBindings() {
197         lbmain=new LocalityBinding(typeutil.getMain(), false);
198         lbmain.setGlobalReturn(EITHER);
199         lbmain.setGlobal(0, LOCAL);
200         lbtovisit.add(lbmain);
201         discovered.put(lbmain, lbmain);
202         if (!classtolb.containsKey(lbmain.getMethod().getClassDesc()))
203             classtolb.put(lbmain.getMethod().getClassDesc(), new HashSet<LocalityBinding>());
204         classtolb.get(lbmain.getMethod().getClassDesc()).add(lbmain);
205
206         if (!methodtolb.containsKey(lbmain.getMethod()))
207             methodtolb.put(lbmain.getMethod(), new HashSet<LocalityBinding>());
208         methodtolb.get(lbmain.getMethod()).add(lbmain);
209
210         //Do this to force a virtual table number for the run method
211         lbrun=new LocalityBinding(typeutil.getRun(), false);
212         lbrun.setGlobalReturn(EITHER);
213         lbrun.setGlobalThis(GLOBAL);
214         lbtovisit.add(lbrun);
215         discovered.put(lbrun, lbrun);
216         if (!classtolb.containsKey(lbrun.getMethod().getClassDesc()))
217             classtolb.put(lbrun.getMethod().getClassDesc(), new HashSet<LocalityBinding>());
218         classtolb.get(lbrun.getMethod().getClassDesc()).add(lbrun);
219
220         if (!methodtolb.containsKey(lbrun.getMethod()))
221             methodtolb.put(lbrun.getMethod(), new HashSet<LocalityBinding>());
222         methodtolb.get(lbrun.getMethod()).add(lbrun);
223
224         while(!lbtovisit.empty()) {
225             LocalityBinding lb=(LocalityBinding) lbtovisit.pop();
226             Integer returnglobal=lb.getGlobalReturn();
227             MethodDescriptor md=lb.getMethod();
228             Hashtable<FlatNode,Hashtable<TempDescriptor, Integer>> temptable=new Hashtable<FlatNode,Hashtable<TempDescriptor, Integer>>();
229             Hashtable<FlatNode, Integer> atomictable=new Hashtable<FlatNode, Integer>();
230             calldep.remove(lb);
231             try {
232                 computeCallsFlags(md, lb, temptable, atomictable);
233             } catch (Error e) {
234                 System.out.println("Error in "+md+" context "+lb);
235                 e.printStackTrace();
236                 System.exit(-1);
237             }
238             atomictab.put(lb, atomictable);
239             temptab.put(lb, temptable);
240
241             if (md.getReturnType()!=null&&!returnglobal.equals(lb.getGlobalReturn())) {
242                 //return type is more precise now
243                 //rerun everything that call us
244                 lbtovisit.addAll(dependence.get(lb));
245             }
246         }
247     }
248
249     public void computeCallsFlags(MethodDescriptor md, LocalityBinding lb, Hashtable<FlatNode, Hashtable<TempDescriptor, Integer>> temptable, Hashtable<FlatNode, Integer> atomictable) {
250         FlatMethod fm=state.getMethodFlat(md);
251         HashSet<FlatNode> tovisit=new HashSet<FlatNode>();
252         tovisit.add(fm.getNext(0));
253         {
254             // Build table for initial node
255             Hashtable<TempDescriptor,Integer> table=new Hashtable<TempDescriptor,Integer>();
256             temptable.put(fm, table);
257             atomictable.put(fm, lb.isAtomic()?1:0);
258             int offset=md.isStatic()?0:1;
259             if (!md.isStatic()) {
260                 table.put(fm.getParameter(0), lb.getGlobalThis());
261             }
262             for(int i=offset;i<fm.numParameters();i++) {
263                 TempDescriptor temp=fm.getParameter(i);
264                 Integer b=lb.isGlobal(i-offset);
265                 table.put(temp,b);
266             }
267         }
268
269         while(!tovisit.isEmpty()) {
270             FlatNode fn=tovisit.iterator().next();
271             tovisit.remove(fn);
272             Hashtable<TempDescriptor, Integer> currtable=new Hashtable<TempDescriptor, Integer>();
273             int atomicstate=0;
274             for(int i=0;i<fn.numPrev();i++) {
275                 FlatNode prevnode=fn.getPrev(i);
276                 if (atomictable.containsKey(prevnode)) {
277                     atomicstate=atomictable.get(prevnode).intValue();
278                 }
279                 if (!temptable.containsKey(prevnode))
280                     continue;
281                 Hashtable<TempDescriptor, Integer> prevtable=temptable.get(prevnode);
282                 for(Iterator<TempDescriptor> tempit=prevtable.keySet().iterator();tempit.hasNext();) {
283                     TempDescriptor temp=tempit.next();
284                     Integer tmpint=prevtable.get(temp);
285                     Integer oldint=currtable.containsKey(temp)?currtable.get(temp):EITHER;
286                     Integer newint=merge(tmpint, oldint);
287                     currtable.put(temp, newint);
288                 }
289             }
290             atomictable.put(fn, atomicstate);
291             // Process this node
292             switch(fn.kind()) {
293             case FKind.FlatAtomicEnterNode:
294                 processAtomicEnterNode((FlatAtomicEnterNode)fn, atomictable);
295                 if (!lb.isAtomic())
296                     lb.setHasAtomic();
297                 break;
298             case FKind.FlatAtomicExitNode:
299                 processAtomicExitNode((FlatAtomicExitNode)fn, atomictable);
300                 break;
301             case FKind.FlatCall:
302                 processCallNode(lb, (FlatCall)fn, currtable, isAtomic(atomictable, fn));
303                 break;
304             case FKind.FlatFieldNode:
305                 processFieldNode(lb, (FlatFieldNode)fn, isAtomic(atomictable, fn), currtable);
306                 break;
307             case FKind.FlatSetFieldNode:
308                 processSetFieldNode(lb, (FlatSetFieldNode)fn, isAtomic(atomictable,fn), currtable);
309                 break;
310             case FKind.FlatNew:
311                 processNew(lb, (FlatNew)fn, isAtomic(atomictable, fn), currtable);
312                 break;
313             case FKind.FlatOpNode:
314                 processOpNode((FlatOpNode)fn, currtable);
315                 break;
316             case FKind.FlatCastNode:
317                 processCastNode((FlatCastNode)fn, currtable);
318                 break;
319             case FKind.FlatLiteralNode:
320                 processLiteralNode((FlatLiteralNode)fn, currtable);
321                 break;
322             case FKind.FlatReturnNode:
323                 processReturnNode(lb, (FlatReturnNode)fn, currtable);
324                 break;
325             case FKind.FlatSetElementNode:
326                 processSetElementNode(lb, (FlatSetElementNode)fn, currtable, isAtomic(atomictable, fn));
327                 break;
328             case FKind.FlatElementNode:
329                 processElementNode(lb, (FlatElementNode)fn, currtable, isAtomic(atomictable, fn));
330                 break;
331             case FKind.FlatCondBranch:
332             case FKind.FlatBackEdge:
333             case FKind.FlatNop:
334             case FKind.FlatPrefetchNode:
335                 //No action needed for these
336                 break;
337             case FKind.FlatFlagActionNode:
338             case FKind.FlatCheckNode:
339             case FKind.FlatTagDeclaration:
340                 throw new Error("Incompatible with tasks!");
341             case FKind.FlatMethod:
342             default:
343                 throw new Error();
344             }
345             Hashtable<TempDescriptor,Integer> oldtable=temptable.get(fn);
346             if (oldtable==null||!oldtable.equals(currtable)) {
347                 // Update table for this node
348                 temptable.put(fn, currtable);
349                 for(int i=0;i<fn.numNext();i++) {
350                     tovisit.add(fn.getNext(i));
351                 }
352             }
353         }
354     }
355
356     private static boolean isAtomic(Hashtable<FlatNode, Integer> atomictable, FlatNode fn) {
357         return atomictable.get(fn).intValue()>0;
358     }
359
360     private static Integer merge(Integer a, Integer b) {
361         if (a==null||a.equals(EITHER))
362             return b;
363         if (b==null||b.equals(EITHER))
364             return a;
365         if (a.equals(b))
366             return a;
367         return CONFLICT;
368     }
369
370     void processCallNode(LocalityBinding currlb, FlatCall fc, Hashtable<TempDescriptor, Integer> currtable, boolean isatomic) {
371         MethodDescriptor nodemd=fc.getMethod();
372         Set methodset=null;
373         Set runmethodset=null;
374
375         if (nodemd.isStatic()||nodemd.getReturnType()==null) {
376             methodset=new HashSet();
377             methodset.add(nodemd);
378         } else {
379             methodset=callgraph.getMethods(nodemd, fc.getThis().getType());
380             // Build start -> run link
381             if (nodemd.getClassDesc().getSymbol().equals(TypeUtil.ThreadClass)&&
382                 nodemd.getSymbol().equals("start")&&!nodemd.getModifiers().isStatic()&&
383                 nodemd.numParameters()==1&&nodemd.getParamType(0).isInt()) {
384                 assert(nodemd.getModifiers().isNative());
385                 
386                 MethodDescriptor runmd=null;
387                 for(Iterator methodit=nodemd.getClassDesc().getMethodTable().getSet("run").iterator();methodit.hasNext();) {
388                     MethodDescriptor md=(MethodDescriptor) methodit.next();
389                     if (md.numParameters()!=0||md.getModifiers().isStatic())
390                         continue;
391                     runmd=md;
392                     break;
393                 }
394                 if (runmd!=null) {
395                     runmethodset=callgraph.getMethods(runmd,fc.getThis().getType());
396                     methodset.addAll(runmethodset);
397                 } else throw new Error("Can't find run method");
398             }
399         }
400
401         Integer currreturnval=EITHER; //Start off with the either value
402         for(Iterator methodit=methodset.iterator();methodit.hasNext();) {
403             MethodDescriptor md=(MethodDescriptor) methodit.next();
404
405             boolean isnative=md.getModifiers().isNative();
406             boolean isjoin = md.getClassDesc().getSymbol().equals(TypeUtil.ThreadClass)&&!nodemd.getModifiers().isStatic()&&nodemd.numParameters()==0&&md.getSymbol().equals("join");
407             
408             LocalityBinding lb=new LocalityBinding(md, isatomic);
409             if (isnative&&isatomic) {
410                 System.out.println("Don't call native methods in atomic blocks!"+currlb.getMethod());
411             }
412             if (runmethodset==null||!runmethodset.contains(md)) {
413                 //Skip this part if it is a run method
414                 for(int i=0;i<fc.numArgs();i++) {
415                     TempDescriptor arg=fc.getArg(i);
416                     if(isnative&&(currtable.get(arg).equals(GLOBAL)||
417                                   currtable.get(arg).equals(CONFLICT)))
418                         throw new Error("Potential call to native method "+md+" with global parameter:\n"+currlb.getExplanation());
419                     lb.setGlobal(i,currtable.get(arg));
420                 }
421             }
422
423             if (fc.getThis()!=null) {
424                 Integer thistype=currtable.get(fc.getThis());
425                 if (thistype==null)
426                     thistype=EITHER;
427
428                 if(runmethodset!=null&&runmethodset.contains(md)&&thistype.equals(LOCAL))
429                     throw new Error("Starting thread on local object not allowed in context:\n"+currlb.getExplanation());
430                 if(isjoin&&thistype.equals(LOCAL))
431                     throw new Error("Joining thread on local object not allowed in context:\n"+currlb.getExplanation());
432                 if(thistype.equals(CONFLICT))
433                     throw new Error("Using type that can be either local or global in context:\n"+currlb.getExplanation());
434                 if(runmethodset==null&&thistype.equals(GLOBAL)&&!isatomic && !isjoin) 
435                     throw new Error("Using global object outside of transaction in context:\n"+currlb.getExplanation());
436                 if (runmethodset==null&&isnative&&thistype.equals(GLOBAL) && !isjoin)
437                     throw new Error("Potential call to native method "+md+" on global objects:\n"+currlb.getExplanation());
438                 lb.setGlobalThis(thistype);
439             } 
440             //lb is built
441             if (!discovered.containsKey(lb)) {
442                 if (isnative)
443                     lb.setGlobalReturn(LOCAL);
444                 else
445                     lb.setGlobalReturn(EITHER);
446                 lb.setParent(currlb);
447                 lbtovisit.add(lb);
448                 discovered.put(lb, lb);
449                 if (!classtolb.containsKey(lb.getMethod().getClassDesc()))
450                     classtolb.put(lb.getMethod().getClassDesc(), new HashSet<LocalityBinding>());
451                 classtolb.get(lb.getMethod().getClassDesc()).add(lb);
452                 if (!methodtolb.containsKey(lb.getMethod()))
453                     methodtolb.put(lb.getMethod(), new HashSet<LocalityBinding>());
454                 methodtolb.get(lb.getMethod()).add(lb);
455             } else
456                 lb=discovered.get(lb);
457             Integer returnval=lb.getGlobalReturn();
458             currreturnval=merge(returnval, currreturnval);
459             if (!dependence.containsKey(lb))
460                 dependence.put(lb, new HashSet<LocalityBinding>());
461             dependence.get(lb).add(currlb);
462
463             if (!calldep.containsKey(currlb))
464                 calldep.put(currlb, new HashSet<LocalityBinding>());
465             calldep.get(currlb).add(lb);
466         }
467         if (fc.getReturnTemp()!=null) {
468             currtable.put(fc.getReturnTemp(), currreturnval);
469         }
470     }
471
472     void processFieldNode(LocalityBinding lb, FlatFieldNode ffn, boolean transaction, Hashtable<TempDescriptor, Integer> currtable) {
473         Integer type=currtable.get(ffn.getSrc());
474         TempDescriptor dst=ffn.getDst();
475         if (type.equals(LOCAL)) {
476             if (ffn.getField().isGlobal())
477                 currtable.put(dst,GLOBAL);
478             else
479                 currtable.put(dst,LOCAL);
480         } else if (type.equals(GLOBAL)) {
481             if (!transaction)
482                 throw new Error("Global access outside of a transaction in context:\n"+lb.getExplanation());
483             if (ffn.getField().getType().isPrimitive()&&!ffn.getField().getType().isArray())
484                 currtable.put(dst, LOCAL); // primitives are local
485             else
486                 currtable.put(dst, GLOBAL);
487         } else if (type.equals(EITHER)) {
488             if (ffn.getField().getType().isPrimitive()&&!ffn.getField().getType().isArray())
489                 currtable.put(dst, LOCAL); // primitives are local
490             else if (ffn.getField().isGlobal())
491                 currtable.put(dst, GLOBAL);
492             else
493                 currtable.put(dst, EITHER);
494         } else if (type.equals(CONFLICT)) {
495             throw new Error("Access to object that could be either global or local in context:\n"+lb.getExplanation());
496         }
497     }
498
499     //need to handle primitives
500     void processSetFieldNode(LocalityBinding lb, FlatSetFieldNode fsfn, boolean transaction, Hashtable<TempDescriptor, Integer> currtable) {
501         Integer srctype=currtable.get(fsfn.getSrc());
502         Integer dsttype=currtable.get(fsfn.getDst());
503
504         if (dsttype.equals(LOCAL)) {
505             if (fsfn.getField().isGlobal()) {
506                 if (!(srctype.equals(GLOBAL)||srctype.equals(EITHER)))
507                     throw new Error("Writing possible local reference to global field in context: \n"+lb.getExplanation());
508             } else {
509                 if (!(srctype.equals(LOCAL)||srctype.equals(EITHER)))
510                     throw new Error("Writing possible global reference to local object in context: \n"+lb.getExplanation());
511             }
512         } else if (dsttype.equals(GLOBAL)) {
513             if (!transaction)
514                 throw new Error("Global access outside of a transaction in context:\n"+lb.getExplanation());
515             //okay to store primitives in global object
516             if (srctype.equals(LOCAL) && fsfn.getField().getType().isPrimitive() && ! fsfn.getField().getType().isArray())
517                 return;
518             if (!(srctype.equals(GLOBAL)||srctype.equals(EITHER)))
519                 throw new Error("Writing possible local reference to global object in context:\n"+lb.getExplanation()+" for FlatFieldNode "+fsfn);
520         } else if (dsttype.equals(EITHER)) {
521             if (srctype.equals(CONFLICT))
522                 throw new Error("Using reference that could be local or global in context:\n"+lb.getExplanation());
523         } else if (dsttype.equals(CONFLICT)) {
524             throw new Error("Access to object that could be either global or local in context:\n"+lb.getExplanation());
525         }
526     }
527
528     void processNew(LocalityBinding lb, FlatNew fn, boolean transaction, Hashtable<TempDescriptor, Integer> currtable) {
529         if (fn.isGlobal()&&!transaction) {
530             throw new Error("Allocating global object outside of transaction in context:"+lb.getExplanation());
531         }
532         if (fn.isGlobal())
533             currtable.put(fn.getDst(), GLOBAL);
534         else
535             currtable.put(fn.getDst(), LOCAL);
536     }
537
538     void processOpNode(FlatOpNode fon, Hashtable<TempDescriptor, Integer> currtable) {
539         /* Just propagate value */
540         Integer srcvalue=currtable.get(fon.getLeft());
541
542         if (srcvalue==null) {
543             if (!fon.getLeft().getType().isPtr()) {
544                 srcvalue=LOCAL;
545             } else
546                 throw new Error(fon.getLeft()+" is undefined!");
547         }
548         currtable.put(fon.getDest(), srcvalue);
549     }
550
551     void processCastNode(FlatCastNode fcn, Hashtable<TempDescriptor, Integer> currtable) {
552         currtable.put(fcn.getDst(), currtable.get(fcn.getSrc()));
553     }
554
555     void processLiteralNode(FlatLiteralNode fln, Hashtable<TempDescriptor, Integer> currtable) {
556         //null is either
557         if (fln.getValue()==null)
558             currtable.put(fln.getDst(), EITHER);
559         else
560             currtable.put(fln.getDst(), LOCAL);
561     }
562
563     void processReturnNode(LocalityBinding lb, FlatReturnNode frn, Hashtable<TempDescriptor, Integer> currtable) {
564         if(frn.getReturnTemp()!=null) {
565             Integer returntype=currtable.get(frn.getReturnTemp());
566             lb.setGlobalReturn(merge(returntype, lb.getGlobalReturn()));
567         }
568     }
569
570     void processSetElementNode(LocalityBinding lb, FlatSetElementNode fsen, Hashtable<TempDescriptor, Integer> currtable, boolean isatomic) {
571         Integer srctype=currtable.get(fsen.getSrc());
572         Integer dsttype=currtable.get(fsen.getDst());
573
574         if (dsttype.equals(LOCAL)) {
575             if (!(srctype.equals(LOCAL)||srctype.equals(EITHER)))
576                 throw new Error("Writing possible global reference to local object in context:\n"+lb.getExplanation()+fsen);
577         } else if (dsttype.equals(GLOBAL)) {
578             if (srctype.equals(LOCAL) && fsen.getDst().getType().dereference().isPrimitive() && ! fsen.getDst().getType().dereference().isArray())
579                 return;
580             if (!(srctype.equals(GLOBAL)||srctype.equals(EITHER)))
581                 throw new Error("Writing possible local reference to global object in context:\n"+lb.getExplanation());
582             if (!isatomic)
583                 throw new Error("Global access outside of a transaction in context:\n"+lb.getExplanation());
584         } else if (dsttype.equals(EITHER)) {
585             if (srctype.equals(CONFLICT))
586                 throw new Error("Using reference that could be local or global in context:\n"+lb.getExplanation());
587         } else if (dsttype.equals(CONFLICT)) {
588             throw new Error("Access to object that could be either global or local in context:\n"+lb.getExplanation());
589         }
590     }
591
592     void processElementNode(LocalityBinding lb, FlatElementNode fen, Hashtable<TempDescriptor, Integer> currtable, boolean isatomic) {
593         Integer type=currtable.get(fen.getSrc());
594         TempDescriptor dst=fen.getDst();
595         if (type.equals(LOCAL)) {
596             currtable.put(dst,LOCAL);
597         } else if (type.equals(GLOBAL)) {
598             if (!isatomic)
599                 throw new Error("Global access outside of a transaction in context:\n"+lb.getExplanation());
600             if(fen.getSrc().getType().dereference().isPrimitive()&&
601                !fen.getSrc().getType().dereference().isArray())
602                 currtable.put(dst, LOCAL);
603             else
604                 currtable.put(dst, GLOBAL);
605         } else if (type.equals(EITHER)) {
606             if(fen.getSrc().getType().dereference().isPrimitive()&&
607                !fen.getSrc().getType().dereference().isArray())
608                 currtable.put(dst, LOCAL);
609             else
610                 currtable.put(dst, EITHER);
611         } else if (type.equals(CONFLICT)) {
612             throw new Error("Access to object that could be either global or local in context:\n"+lb.getExplanation());
613         }
614     }
615
616     void processAtomicEnterNode(FlatAtomicEnterNode fen, Hashtable<FlatNode, Integer> atomictable) {
617         int atomic=atomictable.get(fen).intValue();
618         atomictable.put(fen, new Integer(atomic+1));
619     }
620
621     void processAtomicExitNode(FlatAtomicExitNode fen, Hashtable<FlatNode, Integer> atomictable) {
622         int atomic=atomictable.get(fen).intValue();
623         atomictable.put(fen, new Integer(atomic-1));
624     }
625
626     private Hashtable<FlatNode, Set<TempDescriptor>> computeLiveTemps(FlatMethod fm) {
627         Hashtable<FlatNode, Set<TempDescriptor>> nodetotemps=new Hashtable<FlatNode, Set<TempDescriptor>>();
628
629         Set<FlatNode> toprocess=fm.getNodeSet();
630
631         while(!toprocess.isEmpty()) {
632             FlatNode fn=toprocess.iterator().next();
633             toprocess.remove(fn);
634
635             List<TempDescriptor> reads=Arrays.asList(fn.readsTemps());
636             List<TempDescriptor> writes=Arrays.asList(fn.writesTemps());
637
638             HashSet<TempDescriptor> tempset=new HashSet<TempDescriptor>();
639             for(int i=0;i<fn.numNext();i++) {
640                 FlatNode fnnext=fn.getNext(i);
641                 if (nodetotemps.containsKey(fnnext))
642                     tempset.addAll(nodetotemps.get(fnnext));
643             }
644             tempset.removeAll(writes);
645             tempset.addAll(reads);
646             if (!nodetotemps.containsKey(fn)||
647                 !nodetotemps.get(fn).equals(tempset)) {
648                 nodetotemps.put(fn, tempset);
649                 for(int i=0;i<fn.numPrev();i++)
650                     toprocess.add(fn.getPrev(i));
651             }
652         }
653         return nodetotemps;
654     }
655
656     private void computeTempstoSave() {
657         for(Iterator<LocalityBinding> lbit=getLocalityBindings().iterator();lbit.hasNext();) {
658             LocalityBinding lb=lbit.next();
659             computeTempstoSave(lb);
660         }
661     }
662
663     /* Need to checkpoint all temps that could be read from along any
664      * path that are either:
665        1) Written to by any assignment inside the transaction
666        2) Read from a global temp.
667
668        Generate tempstosave map from
669        localitybinding->flatatomicenternode->Set<TempDescriptors>
670     */
671
672     private void computeTempstoSave(LocalityBinding lb) {
673         if (lb.isAtomic())
674             return;
675         Hashtable<FlatNode, Integer> atomictab=getAtomic(lb);
676         Hashtable<FlatNode, Hashtable<TempDescriptor, Integer>> temptab=getNodeTempInfo(lb);
677         MethodDescriptor md=lb.getMethod();
678         FlatMethod fm=state.getMethodFlat(md);
679         Hashtable<FlatNode, Set<TempDescriptor>> nodetotemps=computeLiveTemps(fm);
680         Hashtable<FlatAtomicEnterNode, Set<TempDescriptor>> nodetosavetemps=new Hashtable<FlatAtomicEnterNode, Set<TempDescriptor>>();
681         tempstosave.put(lb, nodetosavetemps);
682         Hashtable<FlatNode, FlatAtomicEnterNode> nodemap=new Hashtable<FlatNode, FlatAtomicEnterNode>();
683         HashSet<FlatNode> toprocess=new HashSet<FlatNode>();
684         HashSet<FlatNode> discovered=new HashSet<FlatNode>();
685         toprocess.add(fm);
686         discovered.add(fm);
687         while(!toprocess.isEmpty()) {
688             FlatNode fn=toprocess.iterator().next();
689             toprocess.remove(fn);
690             boolean isatomic=atomictab.get(fn).intValue()>0;
691             if (isatomic&&
692                 atomictab.get(fn.getPrev(0)).intValue()==0) {
693                 assert(fn.getPrev(0).kind()==FKind.FlatAtomicEnterNode);
694                 nodemap.put(fn, (FlatAtomicEnterNode)fn);
695                 nodetosavetemps.put((FlatAtomicEnterNode)fn, new HashSet<TempDescriptor>());
696             } else if (isatomic) {
697                 FlatAtomicEnterNode atomicnode=nodemap.get(fn);
698                 Set<TempDescriptor> livetemps=nodetotemps.get(fn);
699                 List<TempDescriptor> reads=Arrays.asList(fn.readsTemps());
700                 List<TempDescriptor> writes=Arrays.asList(fn.readsTemps());
701
702                 for(Iterator<TempDescriptor> tempit=livetemps.iterator();tempit.hasNext();) {
703                     TempDescriptor tmp=tempit.next();
704                     if (writes.contains(tmp)) {
705                         nodetosavetemps.get(atomicnode).add(tmp);
706                     } else if (reads.contains(tmp)&&temptab.get(fn).get(tmp)==GLOBAL) {
707                         nodetosavetemps.get(atomicnode).add(tmp);
708                     }
709                 }
710             }
711             for(int i=0;i<fn.numNext();i++) {
712                 FlatNode fnnext=fn.getNext(i);
713                 if (!discovered.contains(fnnext)) {
714                     discovered.add(fnnext);
715                     toprocess.add(fnnext);
716                     if(isatomic) {
717                         nodemap.put(fnnext, nodemap.get(fn));
718                     }
719                 }
720             }
721         }
722     }
723 }