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