start of new file
[IRC.git] / Robust / src / Analysis / Locality / LocalityAnalysis.java
index 8d74ae3935be8de645cbe1b2cc298510adc94bf3..adac83f89e7079dd898ee64bb95e61856b00994c 100644 (file)
@@ -1,22 +1,28 @@
 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 tovisit;
+    Stack lbtovisit;
     Hashtable<LocalityBinding,LocalityBinding> discovered;
-    Hashtable<MethodDescriptor, MethodDescriptor> dependence;
+    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;
     public static final Integer LOCAL=new Integer(0);
@@ -24,108 +30,319 @@ public class LocalityAnalysis {
     public static final Integer EITHER=new Integer(2);
     public static final Integer CONFLICT=new Integer(3);
 
-
     public LocalityAnalysis(State state, CallGraph callgraph, TypeUtil typeutil) {
+       this.typeutil=typeutil;
        this.state=state;
        this.discovered=new Hashtable<LocalityBinding,LocalityBinding>();
-       this.dependence=new Hashtable<MethodDescriptor, MethodDescriptor>();
-       this.tovisit=new Stack();
+       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 lb=new LocalityBinding(typeutil.getMain(), false);
-       tovisit.add(lb);
-       discovered.put(lb, lb);
+       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(!tovisit.empty()) {
-           LocalityBinding lb=(LocalityBinding) tovisit.pop();
+       while(!lbtovisit.empty()) {
+           LocalityBinding lb=(LocalityBinding) lbtovisit.pop();
+           Integer returnglobal=lb.getGlobalReturn();
            MethodDescriptor md=lb.getMethod();
-           computeCallsFlags(md, lb);
+           Hashtable<FlatNode,Hashtable<TempDescriptor, Integer>> temptable=new Hashtable<FlatNode,Hashtable<TempDescriptor, Integer>>();
+           Hashtable<FlatNode, Integer> atomictable=new Hashtable<FlatNode, Integer>();
+           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.getReturnType()!=null&&!returnglobal.equals(lb.getGlobalReturn())) {
+               //return type is more precise now
+               //rerun everything that call us
+               lbtovisit.addAll(dependence.get(lb));
+           }
        }
     }
-    
-    public Hashtable<FlatNode, Hashtable<TempDescriptor,Integer>> computeCallsFlags(MethodDescriptor md, LocalityBinding 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>();
-       Hashtable<FlatNode,Hashtable<TempDescriptor, Integer>> temptable=new Hashtable<FlatNode,Hashtable<TempDescriptor, Integer>>();
        tovisit.add(fm.getNext(0));
-       
        {
            // Build table for initial node
            Hashtable<TempDescriptor,Integer> table=new Hashtable<TempDescriptor,Integer>();
            temptable.put(fm, table);
-           for(int i=0;i<fm.numParameters();i++) {
+           atomictable.put(fm, lb.isAtomic()?1:0);
+           int offset=md.isStatic()?0:1;
+           if (!md.isStatic()) {
+               table.put(fm.getParameter(0), lb.getGlobalThis());
+           }
+           for(int i=offset;i<fm.numParameters();i++) {
                TempDescriptor temp=fm.getParameter(i);
-               b=lb.isGlobal(i);
+               Integer b=lb.isGlobal(i-offset);
                table.put(temp,b);
            }
        }
-       
+
        while(!tovisit.isEmpty()) {
            FlatNode fn=tovisit.iterator().next();
+           tovisit.remove(fn);
            Hashtable<TempDescriptor, Integer> currtable=new Hashtable<TempDescriptor, Integer>();
+           int atomicstate=0;
            for(int i=0;i<fn.numPrev();i++) {
                FlatNode prevnode=fn.getPrev(i);
+               if (atomictable.containsKey(prevnode)) {
+                   atomicstate=atomictable.get(prevnode).intValue();
+               }
                if (!temptable.containsKey(prevnode))
                    continue;
                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):null;
+                   Integer oldint=currtable.containsKey(temp)?currtable.get(temp):EITHER;
                    Integer newint=merge(tmpint, oldint);
                    currtable.put(temp, newint);
                }
            }
+           atomictable.put(fn, atomicstate);
            // Process this node
            switch(fn.kind()) {
-           case FlatCall:
-               processCall(md, (FlatCall)fn, currtable);
+           case FKind.FlatAtomicEnterNode:
+               processAtomicEnterNode((FlatAtomicEnterNode)fn, atomictable);
+               if (!lb.isAtomic())
+                   lb.setHasAtomic();
                break;
-           case FlatFieldNode:
-               processFieldNode((FlatFieldNode)fn, currtable);
+           case FKind.FlatAtomicExitNode:
+               processAtomicExitNode((FlatAtomicExitNode)fn, atomictable);
                break;
-           case FlatSetFieldNode:
-               processSetFieldNode((FlatSetFieldNode)fn, currtable);
+           case FKind.FlatCall:
+               processCallNode(lb, (FlatCall)fn, currtable, isAtomic(atomictable, fn));
                break;
-           case FlatNew:
-               processNew((FlatNew)fn, currtable);
+           case FKind.FlatFieldNode:
+               processFieldNode(lb, (FlatFieldNode)fn, isAtomic(atomictable, fn), currtable);
                break;
-           case FlatOpNode:
+           case FKind.FlatSetFieldNode:
+               processSetFieldNode(lb, (FlatSetFieldNode)fn, isAtomic(atomictable,fn), currtable);
+               break;
+           case FKind.FlatNew:
+               processNew(lb, (FlatNew)fn, isAtomic(atomictable, fn), currtable);
+               break;
+           case FKind.FlatOpNode:
                processOpNode((FlatOpNode)fn, currtable);
                break;
-           case FlatCastNode:
+           case FKind.FlatCastNode:
                processCastNode((FlatCastNode)fn, currtable);
                break;
-           case FlatLiteralNode:
+           case FKind.FlatLiteralNode:
                processLiteralNode((FlatLiteralNode)fn, currtable);
                break;
-           case FlatReturnNode:
-               processReturnNode((FlatReturnNode)fn, currtable);
+           case FKind.FlatReturnNode:
+               processReturnNode(lb, (FlatReturnNode)fn, currtable);
                break;
-           case FlatSetElementNode:
-               processSetElement((FlatSetElementNode)fn, currtable);
+           case FKind.FlatSetElementNode:
+               processSetElementNode(lb, (FlatSetElementNode)fn, currtable, isAtomic(atomictable, fn));
                break;
-           case FlatElementNode:
-               processElement((FlatElementNode)fn, currtable);
+           case FKind.FlatElementNode:
+               processElementNode(lb, (FlatElementNode)fn, currtable, isAtomic(atomictable, fn));
                break;
-
-           case FlatCondBranch:
-           case FlatBackEdge:
-           case FlatNop:
+           case FKind.FlatCondBranch:
+           case FKind.FlatBackEdge:
+           case FKind.FlatNop:
+           case FKind.FlatPrefetchNode:
                //No action needed for these
                break;
-           case FlatFlagActionNode:
-           case FlatCheckNode:
-           case FlatTagDeclaration:
+           case FKind.FlatFlagActionNode:
+           case FKind.FlatCheckNode:
+           case FKind.FlatTagDeclaration:
                throw new Error("Incompatible with tasks!");
-           case FlatMethod:
+           case FKind.FlatMethod:
            default:
                throw new Error();
            }
@@ -134,12 +351,16 @@ public class LocalityAnalysis {
                // Update table for this node
                temptable.put(fn, currtable);
                for(int i=0;i<fn.numNext();i++) {
-                   tovisit.add(fn.next(i));
+                   tovisit.add(fn.getNext(i));
                }
            }
        }
     }
 
+    private static boolean isAtomic(Hashtable<FlatNode, Integer> atomictable, FlatNode fn) {
+       return atomictable.get(fn).intValue()>0;
+    }
+
     private static Integer merge(Integer a, Integer b) {
        if (a==null||a.equals(EITHER))
            return b;
@@ -149,40 +370,107 @@ public class LocalityAnalysis {
            return a;
        return CONFLICT;
     }
-       
-    void processCall(LocalityBinding currlb, FlatCall fc, boolean transaction, Hashtable<TempDescriptor, Integer> currtable) {
+
+    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());
-       Integer currreturnval=null;
+       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();
-           LocalityBinding lb=new LocalityBinding(md, transaction);
-           for(int i=0;i<fc.numArgs();i++) {
-               TempDescriptor arg=fc.getArg(i);
-               lb.setGlobal(i,currtable.get(arg));
+
+           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);
+           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");
-               if(thistype.equals(GLOBAL)&&!transaction)
-                   throw new Error("Using global object outside of transaction");
+                   throw new Error("Using type that can be either local or global in context:\n"+currlb.getExplanation());
+               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);
-               tovisit.add(lb);
+               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();
            currreturnval=merge(returnval, currreturnval);
-           dependence.put(md, currlb.getMethod()); 
+           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);
        }
-       currtable.put(fc.getReturnTemp(), currreturnval);
     }
 
     void processFieldNode(LocalityBinding lb, FlatFieldNode ffn, boolean transaction, Hashtable<TempDescriptor, Integer> currtable) {
@@ -192,56 +480,58 @@ public class LocalityAnalysis {
            if (ffn.getField().isGlobal())
                currtable.put(dst,GLOBAL);
            else
-               currtable.put(dst,LOCAL);                   
+               currtable.put(dst,LOCAL);
        } else if (type.equals(GLOBAL)) {
            if (!transaction)
-               throw Error("Global access outside of a transaction");
-           if (ffn.getField().getType().isPrimitive())
+               throw new Error("Global access outside of a transaction in context:\n"+lb.getExplanation());
+           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)) {
-           throw new Error("Access to object that could be either global or local");
+           throw new Error("Access to object that could be either global or local in context:\n"+lb.getExplanation());
        }
     }
 
     //need to handle primitives
     void processSetFieldNode(LocalityBinding lb, FlatSetFieldNode fsfn, boolean transaction, Hashtable<TempDescriptor, Integer> currtable) {
-       Integer srctype=currtable.get(ffn.getSrc());
-       Integer dsttype=currtable.get(ffn.getDst());
+       Integer srctype=currtable.get(fsfn.getSrc());
+       Integer dsttype=currtable.get(fsfn.getDst());
 
        if (dsttype.equals(LOCAL)) {
-           if (ffn.getField().isGlobal()) {
+           if (fsfn.getField().isGlobal()) {
                if (!(srctype.equals(GLOBAL)||srctype.equals(EITHER)))
-                   throw new Error("Writing possible local reference to global field");
+                   throw new Error("Writing possible local reference to global field in context: \n"+lb.getExplanation());
            } else {
                if (!(srctype.equals(LOCAL)||srctype.equals(EITHER)))
-                   throw new Error("Writing possible global reference to local object");
+                   throw new Error("Writing possible global reference to local object in context: \n"+lb.getExplanation());
            }
        } else if (dsttype.equals(GLOBAL)) {
            if (!transaction)
-               throw Error("Global access outside of a 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");
+               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");
+               throw new Error("Using reference that could be local or global in context:\n"+lb.getExplanation());
        } else if (dsttype.equals(CONFLICT)) {
-           throw new Error("Access to object that could be either global or local");
+           throw new Error("Access to object that could be either global or local in context:\n"+lb.getExplanation());
        }
     }
 
     void processNew(LocalityBinding lb, FlatNew fn, boolean transaction, Hashtable<TempDescriptor, Integer> currtable) {
        if (fn.isGlobal()&&!transaction) {
-           throw new Error("Allocating global object outside of transaction");
+           throw new Error("Allocating global object outside of transaction in context:"+lb.getExplanation());
        }
        if (fn.isGlobal())
            currtable.put(fn.getDst(), GLOBAL);
@@ -251,11 +541,19 @@ public class LocalityAnalysis {
 
     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) {
-       currtable.put(fon.getDest(), currtable.get(fon.getSrc()));
+       currtable.put(fcn.getDst(), currtable.get(fcn.getSrc()));
     }
 
     void processLiteralNode(FlatLiteralNode fln, Hashtable<TempDescriptor, Integer> currtable) {
@@ -273,39 +571,157 @@ public class LocalityAnalysis {
        }
     }
 
-    void processSetElementNode(FlatSetElementNode fsen, Hashtable<TempDescriptor, Integer> currtable) {
+    void processSetElementNode(LocalityBinding lb, FlatSetElementNode fsen, Hashtable<TempDescriptor, Integer> currtable, boolean isatomic) {
        Integer srctype=currtable.get(fsen.getSrc());
        Integer dsttype=currtable.get(fsen.getDst());
 
        if (dsttype.equals(LOCAL)) {
            if (!(srctype.equals(LOCAL)||srctype.equals(EITHER)))
-               throw new Error("Writing possible global reference to local object");
+               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");
-           if (!transaction)
-               throw Error("Global access outside of a transaction");
+               throw new Error("Writing possible local reference to global object in context:\n"+lb.getExplanation());
+           if (!isatomic)
+               throw new Error("Global access outside of a transaction in context:\n"+lb.getExplanation());
        } else if (dsttype.equals(EITHER)) {
            if (srctype.equals(CONFLICT))
-               throw new Error("Using reference that could be local or global");
+               throw new Error("Using reference that could be local or global in context:\n"+lb.getExplanation());
        } else if (dsttype.equals(CONFLICT)) {
-           throw new Error("Access to object that could be either global or local");
+           throw new Error("Access to object that could be either global or local in context:\n"+lb.getExplanation());
        }
     }
 
-    void processElementNode(FlatElementNode fen, Hashtable<TempDescriptor, Integer> currtable) {
+    void processElementNode(LocalityBinding lb, FlatElementNode fen, Hashtable<TempDescriptor, Integer> currtable, boolean isatomic) {
        Integer type=currtable.get(fen.getSrc());
        TempDescriptor dst=fen.getDst();
        if (type.equals(LOCAL)) {
-           currtable.put(dst,LOCAL);               
+           currtable.put(dst,LOCAL);
        } else if (type.equals(GLOBAL)) {
-           if (!transaction)
-               throw Error("Global access outside of a transaction");
-           currtable.put(dst, GLOBAL);
+           if (!isatomic)
+               throw new Error("Global access outside of a transaction in context:\n"+lb.getExplanation());
+           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");
+           throw new Error("Access to object that could be either global or local in context:\n"+lb.getExplanation());
+       }
+    }
+
+    void processAtomicEnterNode(FlatAtomicEnterNode fen, Hashtable<FlatNode, Integer> atomictable) {
+       int atomic=atomictable.get(fen).intValue();
+       atomictable.put(fen, new Integer(atomic+1));
+    }
+
+    void processAtomicExitNode(FlatAtomicExitNode fen, Hashtable<FlatNode, Integer> atomictable) {
+       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));
+                   }
+               }
+           }
        }
     }
 }