package Analysis.Locality;
-import java.util.Hashtable;
-import java.util.Stack;
-import java.util.Set;
-import java.util.HashSet;
-import java.util.Iterator;
-import java.util.Arrays;
+import java.util.*;
import Analysis.CallGraph.CallGraph;
import IR.SymbolTable;
import IR.State;
import IR.TypeUtil;
import IR.MethodDescriptor;
import IR.Flat.*;
+import IR.ClassDescriptor;
public class LocalityAnalysis {
State state;
Stack lbtovisit;
Hashtable<LocalityBinding,LocalityBinding> discovered;
Hashtable<LocalityBinding, Set<LocalityBinding>> dependence;
+ Hashtable<LocalityBinding, Set<LocalityBinding>> calldep;
Hashtable<LocalityBinding, Hashtable<FlatNode,Hashtable<TempDescriptor, Integer>>> temptab;
Hashtable<LocalityBinding, Hashtable<FlatNode, Integer>> atomictab;
-
+ Hashtable<LocalityBinding, Hashtable<FlatAtomicEnterNode, Set<TempDescriptor>>> tempstosave;
+ Hashtable<ClassDescriptor, Set<LocalityBinding>> classtolb;
+ Hashtable<MethodDescriptor, Set<LocalityBinding>> methodtolb;
+ private LocalityBinding lbmain;
+ private LocalityBinding lbrun;
CallGraph callgraph;
TypeUtil typeutil;
this.state=state;
this.discovered=new Hashtable<LocalityBinding,LocalityBinding>();
this.dependence=new Hashtable<LocalityBinding, Set<LocalityBinding>>();
+ this.calldep=new Hashtable<LocalityBinding, Set<LocalityBinding>>();
this.temptab=new Hashtable<LocalityBinding, Hashtable<FlatNode,Hashtable<TempDescriptor, Integer>>>();
this.atomictab=new Hashtable<LocalityBinding, Hashtable<FlatNode, Integer>>();
this.lbtovisit=new Stack();
this.callgraph=callgraph;
+ this.tempstosave=new Hashtable<LocalityBinding, Hashtable<FlatAtomicEnterNode, Set<TempDescriptor>>>();
+ this.classtolb=new Hashtable<ClassDescriptor, Set<LocalityBinding>>();
+ this.methodtolb=new Hashtable<MethodDescriptor, Set<LocalityBinding>>();
doAnalysis();
}
+ public LocalityBinding getMain() {
+ return lbmain;
+ }
+
+ /** This method returns the set of LocalityBindings that a given
+ * flatcall could invoke */
+
+ public LocalityBinding getBinding(LocalityBinding currlb, FlatCall fc) {
+ boolean isatomic=getAtomic(currlb).get(fc).intValue()>0;
+ Hashtable<TempDescriptor, Integer> currtable=getNodePreTempInfo(currlb,fc);
+ MethodDescriptor md=fc.getMethod();
+
+ boolean isnative=md.getModifiers().isNative();
+
+ LocalityBinding lb=new LocalityBinding(md, isatomic);
+
+ for(int i=0;i<fc.numArgs();i++) {
+ TempDescriptor arg=fc.getArg(i);
+ lb.setGlobal(i,currtable.get(arg));
+ }
+ if (fc.getThis()!=null) {
+ Integer thistype=currtable.get(fc.getThis());
+ if (thistype==null)
+ thistype=EITHER;
+ lb.setGlobalThis(thistype);
+ }// else
+ // lb.setGlobalThis(EITHER);//default value
+ if (discovered.containsKey(lb))
+ lb=discovered.get(lb);
+ else throw new Error();
+ return lb;
+ }
+
+
+ /** This method returns a set of LocalityBindings for the parameter class. */
+ public Set<LocalityBinding> getClassBindings(ClassDescriptor cd) {
+ return classtolb.get(cd);
+ }
+
+ /** This method returns a set of LocalityBindings for the parameter method. */
+
+ public Set<LocalityBinding> getMethodBindings(MethodDescriptor md) {
+ return methodtolb.get(md);
+ }
+
+ public Set<MethodDescriptor> getMethods() {
+ return methodtolb.keySet();
+ }
+
+ /** This method returns a set of LocalityBindings. A
+ * LocalityBinding specifies a context a method can be invoked in.
+ * It specifies whether the method is in a transaction and whether
+ * its parameter objects are locals or globals. */
+
+ public Set<LocalityBinding> getLocalityBindings() {
+ return discovered.keySet();
+ }
+
+ /** This method returns a hashtable for a given LocalityBinding
+ * that tells the current local/global status of temps at the each
+ * node in the flat representation. */
+
+ public Hashtable<FlatNode, Hashtable<TempDescriptor, Integer>> getNodeTempInfo(LocalityBinding lb) {
+ return temptab.get(lb);
+ }
+
+ /** This method returns a hashtable for a given LocalityBinding
+ * that tells the current local/global status of temps at the
+ * beginning of each node in the flat representation. */
+
+ public Hashtable<TempDescriptor, Integer> getNodePreTempInfo(LocalityBinding lb, FlatNode fn) {
+ Hashtable<TempDescriptor, Integer> currtable=new Hashtable<TempDescriptor, Integer>();
+ Hashtable<FlatNode, Hashtable<TempDescriptor, Integer>> temptable=getNodeTempInfo(lb);
+
+ for(int i=0;i<fn.numPrev();i++) {
+ FlatNode prevnode=fn.getPrev(i);
+ Hashtable<TempDescriptor, Integer> prevtable=temptable.get(prevnode);
+ for(Iterator<TempDescriptor> tempit=prevtable.keySet().iterator();tempit.hasNext();) {
+ TempDescriptor temp=tempit.next();
+ Integer tmpint=prevtable.get(temp);
+ Integer oldint=currtable.containsKey(temp)?currtable.get(temp):EITHER;
+ Integer newint=merge(tmpint, oldint);
+ currtable.put(temp, newint);
+ }
+ }
+ return currtable;
+ }
+
+ /** This method returns an hashtable for a given LocalitBinding
+ * that tells whether a node in the flat represenation is in a
+ * transaction or not. Integer values greater than 0 indicate
+ * that the node is in a transaction and give the nesting depth.
+ * The outermost AtomicEnterNode will have a value of 1 and the
+ * outermost AtomicExitNode will have a value of 0. */
+
+ public Hashtable<FlatNode, Integer> getAtomic(LocalityBinding lb) {
+ return atomictab.get(lb);
+ }
+
+ /** This methods returns a hashtable for a given LocalityBinding
+ * that tells which temps needs to be saved for each
+ * AtomicEnterNode. */
+
+ public Hashtable<FlatAtomicEnterNode, Set<TempDescriptor>> getTemps(LocalityBinding lb) {
+ return tempstosave.get(lb);
+ }
+
+ public Set<TempDescriptor> getTempSet(LocalityBinding lb) {
+ HashSet<TempDescriptor> set=new HashSet<TempDescriptor>();
+ Hashtable<FlatAtomicEnterNode, Set<TempDescriptor>> table=getTemps(lb);
+ if (table!=null)
+ for(Iterator<FlatAtomicEnterNode> faenit=table.keySet().iterator();faenit.hasNext();) {
+ FlatAtomicEnterNode faen=faenit.next();
+ set.addAll(table.get(faen));
+ }
+ return set;
+ }
+
private void doAnalysis() {
computeLocalityBindings();
+ computeTempstoSave();
+ cleanSets();
+ }
+
+ private void cleanSets() {
+ HashSet<LocalityBinding> lbset=new HashSet<LocalityBinding>();
+ Stack<LocalityBinding> lbstack=new Stack<LocalityBinding>();
+ lbstack.add(lbmain);
+ lbstack.add(lbrun);
+ lbset.add(lbmain);
+ lbset.add(lbrun);
+ while(!lbstack.isEmpty()) {
+ LocalityBinding lb=lbstack.pop();
+ if (calldep.containsKey(lb)) {
+ Set<LocalityBinding> set=new HashSet<LocalityBinding>();
+ set.addAll(calldep.get(lb));
+ set.removeAll(lbset);
+ lbstack.addAll(set);
+ lbset.addAll(set);
+ }
+ }
+ for(Iterator<LocalityBinding> lbit=discovered.keySet().iterator();lbit.hasNext();) {
+ LocalityBinding lb=lbit.next();
+ if (!lbset.contains(lb)) {
+ lbit.remove();
+ classtolb.get(lb.getMethod().getClassDesc()).remove(lb);
+ methodtolb.get(lb.getMethod()).remove(lb);
+ }
+ }
}
private void computeLocalityBindings() {
- LocalityBinding lbmain=new LocalityBinding(typeutil.getMain(), false);
+ lbmain=new LocalityBinding(typeutil.getMain(), false);
+ lbmain.setGlobalReturn(EITHER);
lbmain.setGlobal(0, LOCAL);
lbtovisit.add(lbmain);
discovered.put(lbmain, lbmain);
-
+ if (!classtolb.containsKey(lbmain.getMethod().getClassDesc()))
+ classtolb.put(lbmain.getMethod().getClassDesc(), new HashSet<LocalityBinding>());
+ classtolb.get(lbmain.getMethod().getClassDesc()).add(lbmain);
+
+ if (!methodtolb.containsKey(lbmain.getMethod()))
+ methodtolb.put(lbmain.getMethod(), new HashSet<LocalityBinding>());
+ methodtolb.get(lbmain.getMethod()).add(lbmain);
+
+ //Do this to force a virtual table number for the run method
+ lbrun=new LocalityBinding(typeutil.getRun(), false);
+ lbrun.setGlobalReturn(EITHER);
+ lbrun.setGlobalThis(GLOBAL);
+ lbtovisit.add(lbrun);
+ discovered.put(lbrun, lbrun);
+ if (!classtolb.containsKey(lbrun.getMethod().getClassDesc()))
+ classtolb.put(lbrun.getMethod().getClassDesc(), new HashSet<LocalityBinding>());
+ classtolb.get(lbrun.getMethod().getClassDesc()).add(lbrun);
+
+ if (!methodtolb.containsKey(lbrun.getMethod()))
+ methodtolb.put(lbrun.getMethod(), new HashSet<LocalityBinding>());
+ methodtolb.get(lbrun.getMethod()).add(lbrun);
+
while(!lbtovisit.empty()) {
LocalityBinding lb=(LocalityBinding) lbtovisit.pop();
Integer returnglobal=lb.getGlobalReturn();
MethodDescriptor md=lb.getMethod();
Hashtable<FlatNode,Hashtable<TempDescriptor, Integer>> temptable=new Hashtable<FlatNode,Hashtable<TempDescriptor, Integer>>();
Hashtable<FlatNode, Integer> atomictable=new Hashtable<FlatNode, Integer>();
- computeCallsFlags(md, lb, temptable, atomictable);
+ calldep.remove(lb);
+ try {
+ computeCallsFlags(md, lb, temptable, atomictable);
+ } catch (Error e) {
+ System.out.println("Error in "+md+" context "+lb);
+ e.printStackTrace();
+ System.exit(-1);
+ }
atomictab.put(lb, atomictable);
temptab.put(lb, temptable);
- if (!md.isStatic()&&!returnglobal.equals(lb.getGlobalReturn())) {
+ if (md.getReturnType()!=null&&!returnglobal.equals(lb.getGlobalReturn())) {
//return type is more precise now
//rerun everything that call us
lbtovisit.addAll(dependence.get(lb));
}
}
-
public void computeCallsFlags(MethodDescriptor md, LocalityBinding lb, Hashtable<FlatNode, Hashtable<TempDescriptor, Integer>> temptable, Hashtable<FlatNode, Integer> atomictable) {
FlatMethod fm=state.getMethodFlat(md);
HashSet<FlatNode> tovisit=new HashSet<FlatNode>();
switch(fn.kind()) {
case FKind.FlatAtomicEnterNode:
processAtomicEnterNode((FlatAtomicEnterNode)fn, atomictable);
+ if (!lb.isAtomic())
+ lb.setHasAtomic();
break;
case FKind.FlatAtomicExitNode:
processAtomicExitNode((FlatAtomicExitNode)fn, atomictable);
case FKind.FlatCondBranch:
case FKind.FlatBackEdge:
case FKind.FlatNop:
+ case FKind.FlatPrefetchNode:
//No action needed for these
break;
case FKind.FlatFlagActionNode:
void processCallNode(LocalityBinding currlb, FlatCall fc, Hashtable<TempDescriptor, Integer> currtable, boolean isatomic) {
MethodDescriptor nodemd=fc.getMethod();
- Set methodset=fc.getThis()==null?callgraph.getMethods(nodemd):
- callgraph.getMethods(nodemd, fc.getThis().getType());
+ Set methodset=null;
+ Set runmethodset=null;
+
+ if (nodemd.isStatic()||nodemd.getReturnType()==null) {
+ methodset=new HashSet();
+ methodset.add(nodemd);
+ } else {
+ methodset=callgraph.getMethods(nodemd, fc.getThis().getType());
+ // Build start -> run link
+ if (nodemd.getClassDesc().getSymbol().equals(TypeUtil.ThreadClass)&&
+ nodemd.getSymbol().equals("start")&&!nodemd.getModifiers().isStatic()&&
+ nodemd.numParameters()==1&&nodemd.getParamType(0).isInt()) {
+ assert(nodemd.getModifiers().isNative());
+
+ MethodDescriptor runmd=null;
+ for(Iterator methodit=nodemd.getClassDesc().getMethodTable().getSet("run").iterator();methodit.hasNext();) {
+ MethodDescriptor md=(MethodDescriptor) methodit.next();
+ if (md.numParameters()!=0||md.getModifiers().isStatic())
+ continue;
+ runmd=md;
+ break;
+ }
+ if (runmd!=null) {
+ runmethodset=callgraph.getMethods(runmd,fc.getThis().getType());
+ methodset.addAll(runmethodset);
+ } else throw new Error("Can't find run method");
+ }
+ }
+
Integer currreturnval=EITHER; //Start off with the either value
for(Iterator methodit=methodset.iterator();methodit.hasNext();) {
MethodDescriptor md=(MethodDescriptor) methodit.next();
+
+ boolean isnative=md.getModifiers().isNative();
+ boolean isjoin = md.getClassDesc().getSymbol().equals(TypeUtil.ThreadClass)&&!nodemd.getModifiers().isStatic()&&nodemd.numParameters()==0&&md.getSymbol().equals("join");
+
LocalityBinding lb=new LocalityBinding(md, isatomic);
- for(int i=0;i<fc.numArgs();i++) {
- TempDescriptor arg=fc.getArg(i);
- lb.setGlobal(i,currtable.get(arg));
+ if (isnative&&isatomic) {
+ System.out.println("Don't call native methods in atomic blocks!"+currlb.getMethod());
+ }
+ if (runmethodset==null||!runmethodset.contains(md)) {
+ //Skip this part if it is a run method
+ for(int i=0;i<fc.numArgs();i++) {
+ TempDescriptor arg=fc.getArg(i);
+ if(isnative&&(currtable.get(arg).equals(GLOBAL)||
+ currtable.get(arg).equals(CONFLICT)))
+ throw new Error("Potential call to native method "+md+" with global parameter:\n"+currlb.getExplanation());
+ lb.setGlobal(i,currtable.get(arg));
+ }
}
+
if (fc.getThis()!=null) {
Integer thistype=currtable.get(fc.getThis());
if (thistype==null)
thistype=EITHER;
+
+ if(runmethodset!=null&&runmethodset.contains(md)&&thistype.equals(LOCAL))
+ throw new Error("Starting thread on local object not allowed in context:\n"+currlb.getExplanation());
+ if(isjoin&&thistype.equals(LOCAL))
+ throw new Error("Joining thread on local object not allowed in context:\n"+currlb.getExplanation());
if(thistype.equals(CONFLICT))
throw new Error("Using type that can be either local or global in context:\n"+currlb.getExplanation());
- if(thistype.equals(GLOBAL)&&!isatomic)
+ if(runmethodset==null&&thistype.equals(GLOBAL)&&!isatomic && !isjoin)
throw new Error("Using global object outside of transaction in context:\n"+currlb.getExplanation());
+ if (runmethodset==null&&isnative&&thistype.equals(GLOBAL) && !isjoin)
+ throw new Error("Potential call to native method "+md+" on global objects:\n"+currlb.getExplanation());
lb.setGlobalThis(thistype);
- } else
- lb.setGlobalThis(EITHER);//default value
+ }
//lb is built
if (!discovered.containsKey(lb)) {
- lb.setGlobalReturn(EITHER);
+ if (isnative)
+ lb.setGlobalReturn(LOCAL);
+ else
+ lb.setGlobalReturn(EITHER);
lb.setParent(currlb);
lbtovisit.add(lb);
discovered.put(lb, lb);
+ if (!classtolb.containsKey(lb.getMethod().getClassDesc()))
+ classtolb.put(lb.getMethod().getClassDesc(), new HashSet<LocalityBinding>());
+ classtolb.get(lb.getMethod().getClassDesc()).add(lb);
+ if (!methodtolb.containsKey(lb.getMethod()))
+ methodtolb.put(lb.getMethod(), new HashSet<LocalityBinding>());
+ methodtolb.get(lb.getMethod()).add(lb);
} else
lb=discovered.get(lb);
Integer returnval=lb.getGlobalReturn();
if (!dependence.containsKey(lb))
dependence.put(lb, new HashSet<LocalityBinding>());
dependence.get(lb).add(currlb);
+
+ if (!calldep.containsKey(currlb))
+ calldep.put(currlb, new HashSet<LocalityBinding>());
+ calldep.get(currlb).add(lb);
}
if (fc.getReturnTemp()!=null) {
currtable.put(fc.getReturnTemp(), currreturnval);
} else if (type.equals(GLOBAL)) {
if (!transaction)
throw new Error("Global access outside of a transaction in context:\n"+lb.getExplanation());
- if (ffn.getField().getType().isPrimitive())
+ if (ffn.getField().getType().isPrimitive()&&!ffn.getField().getType().isArray())
currtable.put(dst, LOCAL); // primitives are local
else
currtable.put(dst, GLOBAL);
} else if (type.equals(EITHER)) {
- if (ffn.getField().getType().isPrimitive())
+ if (ffn.getField().getType().isPrimitive()&&!ffn.getField().getType().isArray())
currtable.put(dst, LOCAL); // primitives are local
+ else if (ffn.getField().isGlobal())
+ currtable.put(dst, GLOBAL);
else
currtable.put(dst, EITHER);
} else if (type.equals(CONFLICT)) {
void processSetFieldNode(LocalityBinding lb, FlatSetFieldNode fsfn, boolean transaction, Hashtable<TempDescriptor, Integer> currtable) {
Integer srctype=currtable.get(fsfn.getSrc());
Integer dsttype=currtable.get(fsfn.getDst());
-
+
if (dsttype.equals(LOCAL)) {
if (fsfn.getField().isGlobal()) {
if (!(srctype.equals(GLOBAL)||srctype.equals(EITHER)))
if (!transaction)
throw new Error("Global access outside of a transaction in context:\n"+lb.getExplanation());
//okay to store primitives in global object
- if (srctype.equals(LOCAL) && fsfn.getField().getType().isPrimitive())
+ if (srctype.equals(LOCAL) && fsfn.getField().getType().isPrimitive() && ! fsfn.getField().getType().isArray())
return;
if (!(srctype.equals(GLOBAL)||srctype.equals(EITHER)))
- throw new Error("Writing possible local reference to global object in context:\n"+lb.getExplanation());
+ throw new Error("Writing possible local reference to global object in context:\n"+lb.getExplanation()+" for FlatFieldNode "+fsfn);
} else if (dsttype.equals(EITHER)) {
if (srctype.equals(CONFLICT))
throw new Error("Using reference that could be local or global in context:\n"+lb.getExplanation());
void processOpNode(FlatOpNode fon, Hashtable<TempDescriptor, Integer> currtable) {
/* Just propagate value */
- currtable.put(fon.getDest(), currtable.get(fon.getLeft()));
+ Integer srcvalue=currtable.get(fon.getLeft());
+
+ if (srcvalue==null) {
+ if (!fon.getLeft().getType().isPtr()) {
+ srcvalue=LOCAL;
+ } else
+ throw new Error(fon.getLeft()+" is undefined!");
+ }
+ currtable.put(fon.getDest(), srcvalue);
}
void processCastNode(FlatCastNode fcn, Hashtable<TempDescriptor, Integer> currtable) {
if (dsttype.equals(LOCAL)) {
if (!(srctype.equals(LOCAL)||srctype.equals(EITHER)))
- throw new Error("Writing possible global reference to local object in context:\n"+lb.getExplanation());
+ throw new Error("Writing possible global reference to local object in context:\n"+lb.getExplanation()+fsen);
} else if (dsttype.equals(GLOBAL)) {
+ if (srctype.equals(LOCAL) && fsen.getDst().getType().dereference().isPrimitive() && ! fsen.getDst().getType().dereference().isArray())
+ return;
if (!(srctype.equals(GLOBAL)||srctype.equals(EITHER)))
throw new Error("Writing possible local reference to global object in context:\n"+lb.getExplanation());
if (!isatomic)
} else if (type.equals(GLOBAL)) {
if (!isatomic)
throw new Error("Global access outside of a transaction in context:\n"+lb.getExplanation());
- currtable.put(dst, GLOBAL);
+ if(fen.getSrc().getType().dereference().isPrimitive()&&
+ !fen.getSrc().getType().dereference().isArray())
+ currtable.put(dst, LOCAL);
+ else
+ currtable.put(dst, GLOBAL);
} else if (type.equals(EITHER)) {
- currtable.put(dst, EITHER);
+ if(fen.getSrc().getType().dereference().isPrimitive()&&
+ !fen.getSrc().getType().dereference().isArray())
+ currtable.put(dst, LOCAL);
+ else
+ currtable.put(dst, EITHER);
} else if (type.equals(CONFLICT)) {
throw new Error("Access to object that could be either global or local in context:\n"+lb.getExplanation());
}
int atomic=atomictable.get(fen).intValue();
atomictable.put(fen, new Integer(atomic-1));
}
+
+ private Hashtable<FlatNode, Set<TempDescriptor>> computeLiveTemps(FlatMethod fm) {
+ Hashtable<FlatNode, Set<TempDescriptor>> nodetotemps=new Hashtable<FlatNode, Set<TempDescriptor>>();
+
+ Set<FlatNode> toprocess=fm.getNodeSet();
+
+ while(!toprocess.isEmpty()) {
+ FlatNode fn=toprocess.iterator().next();
+ toprocess.remove(fn);
+
+ List<TempDescriptor> reads=Arrays.asList(fn.readsTemps());
+ List<TempDescriptor> writes=Arrays.asList(fn.writesTemps());
+
+ HashSet<TempDescriptor> tempset=new HashSet<TempDescriptor>();
+ for(int i=0;i<fn.numNext();i++) {
+ FlatNode fnnext=fn.getNext(i);
+ if (nodetotemps.containsKey(fnnext))
+ tempset.addAll(nodetotemps.get(fnnext));
+ }
+ tempset.removeAll(writes);
+ tempset.addAll(reads);
+ if (!nodetotemps.containsKey(fn)||
+ !nodetotemps.get(fn).equals(tempset)) {
+ nodetotemps.put(fn, tempset);
+ for(int i=0;i<fn.numPrev();i++)
+ toprocess.add(fn.getPrev(i));
+ }
+ }
+ return nodetotemps;
+ }
+
+ private void computeTempstoSave() {
+ for(Iterator<LocalityBinding> lbit=getLocalityBindings().iterator();lbit.hasNext();) {
+ LocalityBinding lb=lbit.next();
+ computeTempstoSave(lb);
+ }
+ }
+
+ /* Need to checkpoint all temps that could be read from along any
+ * path that are either:
+ 1) Written to by any assignment inside the transaction
+ 2) Read from a global temp.
+
+ Generate tempstosave map from
+ localitybinding->flatatomicenternode->Set<TempDescriptors>
+ */
+
+ private void computeTempstoSave(LocalityBinding lb) {
+ if (lb.isAtomic())
+ return;
+ Hashtable<FlatNode, Integer> atomictab=getAtomic(lb);
+ Hashtable<FlatNode, Hashtable<TempDescriptor, Integer>> temptab=getNodeTempInfo(lb);
+ MethodDescriptor md=lb.getMethod();
+ FlatMethod fm=state.getMethodFlat(md);
+ Hashtable<FlatNode, Set<TempDescriptor>> nodetotemps=computeLiveTemps(fm);
+ Hashtable<FlatAtomicEnterNode, Set<TempDescriptor>> nodetosavetemps=new Hashtable<FlatAtomicEnterNode, Set<TempDescriptor>>();
+ tempstosave.put(lb, nodetosavetemps);
+ Hashtable<FlatNode, FlatAtomicEnterNode> nodemap=new Hashtable<FlatNode, FlatAtomicEnterNode>();
+ HashSet<FlatNode> toprocess=new HashSet<FlatNode>();
+ HashSet<FlatNode> discovered=new HashSet<FlatNode>();
+ toprocess.add(fm);
+ discovered.add(fm);
+ while(!toprocess.isEmpty()) {
+ FlatNode fn=toprocess.iterator().next();
+ toprocess.remove(fn);
+ boolean isatomic=atomictab.get(fn).intValue()>0;
+ if (isatomic&&
+ atomictab.get(fn.getPrev(0)).intValue()==0) {
+ assert(fn.getPrev(0).kind()==FKind.FlatAtomicEnterNode);
+ nodemap.put(fn, (FlatAtomicEnterNode)fn);
+ nodetosavetemps.put((FlatAtomicEnterNode)fn, new HashSet<TempDescriptor>());
+ } else if (isatomic) {
+ FlatAtomicEnterNode atomicnode=nodemap.get(fn);
+ Set<TempDescriptor> livetemps=nodetotemps.get(fn);
+ List<TempDescriptor> reads=Arrays.asList(fn.readsTemps());
+ List<TempDescriptor> writes=Arrays.asList(fn.readsTemps());
+
+ for(Iterator<TempDescriptor> tempit=livetemps.iterator();tempit.hasNext();) {
+ TempDescriptor tmp=tempit.next();
+ if (writes.contains(tmp)) {
+ nodetosavetemps.get(atomicnode).add(tmp);
+ } else if (reads.contains(tmp)&&temptab.get(fn).get(tmp)==GLOBAL) {
+ nodetosavetemps.get(atomicnode).add(tmp);
+ }
+ }
+ }
+ for(int i=0;i<fn.numNext();i++) {
+ FlatNode fnnext=fn.getNext(i);
+ if (!discovered.contains(fnnext)) {
+ discovered.add(fnnext);
+ toprocess.add(fnnext);
+ if(isatomic) {
+ nodemap.put(fnnext, nodemap.get(fn));
+ }
+ }
+ }
+ }
+ }
}