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