check in locality analysis
authorbdemsky <bdemsky>
Fri, 20 Jul 2007 19:21:58 +0000 (19:21 +0000)
committerbdemsky <bdemsky>
Fri, 20 Jul 2007 19:21:58 +0000 (19:21 +0000)
Robust/src/Analysis/Locality/LocalityAnalysis.java [new file with mode: 0644]
Robust/src/Analysis/Locality/LocalityBinding.java [new file with mode: 0644]

diff --git a/Robust/src/Analysis/Locality/LocalityAnalysis.java b/Robust/src/Analysis/Locality/LocalityAnalysis.java
new file mode 100644 (file)
index 0000000..8d74ae3
--- /dev/null
@@ -0,0 +1,311 @@
+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 Analysis.CallGraph.CallGraph;
+import IR.SymbolTable;
+import IR.State;
+import IR.MethodDescriptor;
+import IR.Flat.*;
+
+public class LocalityAnalysis {
+    State state;
+    Stack tovisit;
+    Hashtable<LocalityBinding,LocalityBinding> discovered;
+    Hashtable<MethodDescriptor, MethodDescriptor> dependence;
+    CallGraph callgraph;
+    TypeUtil typeutil;
+    public static final Integer LOCAL=new Integer(0);
+    public static final Integer GLOBAL=new Integer(1);
+    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.state=state;
+       this.discovered=new Hashtable<LocalityBinding,LocalityBinding>();
+       this.dependence=new Hashtable<MethodDescriptor, MethodDescriptor>();
+       this.tovisit=new Stack();
+       this.callgraph=callgraph;
+       doAnalysis();
+    }
+
+    private void doAnalysis() {
+       computeLocalityBindings();
+    }
+    
+    private void computeLocalityBindings() {
+       LocalityBinding lb=new LocalityBinding(typeutil.getMain(), false);
+       tovisit.add(lb);
+       discovered.put(lb, lb);
+
+       while(!tovisit.empty()) {
+           LocalityBinding lb=(LocalityBinding) tovisit.pop();
+           MethodDescriptor md=lb.getMethod();
+           computeCallsFlags(md, lb);
+       }
+    }
+    
+    public Hashtable<FlatNode, Hashtable<TempDescriptor,Integer>> computeCallsFlags(MethodDescriptor md, LocalityBinding lb) {
+       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++) {
+               TempDescriptor temp=fm.getParameter(i);
+               b=lb.isGlobal(i);
+               table.put(temp,b);
+           }
+       }
+       
+       while(!tovisit.isEmpty()) {
+           FlatNode fn=tovisit.iterator().next();
+           Hashtable<TempDescriptor, Integer> currtable=new Hashtable<TempDescriptor, Integer>();
+           for(int i=0;i<fn.numPrev();i++) {
+               FlatNode prevnode=fn.getPrev(i);
+               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 newint=merge(tmpint, oldint);
+                   currtable.put(temp, newint);
+               }
+           }
+           // Process this node
+           switch(fn.kind()) {
+           case FlatCall:
+               processCall(md, (FlatCall)fn, currtable);
+               break;
+           case FlatFieldNode:
+               processFieldNode((FlatFieldNode)fn, currtable);
+               break;
+           case FlatSetFieldNode:
+               processSetFieldNode((FlatSetFieldNode)fn, currtable);
+               break;
+           case FlatNew:
+               processNew((FlatNew)fn, currtable);
+               break;
+           case FlatOpNode:
+               processOpNode((FlatOpNode)fn, currtable);
+               break;
+           case FlatCastNode:
+               processCastNode((FlatCastNode)fn, currtable);
+               break;
+           case FlatLiteralNode:
+               processLiteralNode((FlatLiteralNode)fn, currtable);
+               break;
+           case FlatReturnNode:
+               processReturnNode((FlatReturnNode)fn, currtable);
+               break;
+           case FlatSetElementNode:
+               processSetElement((FlatSetElementNode)fn, currtable);
+               break;
+           case FlatElementNode:
+               processElement((FlatElementNode)fn, currtable);
+               break;
+
+           case FlatCondBranch:
+           case FlatBackEdge:
+           case FlatNop:
+               //No action needed for these
+               break;
+           case FlatFlagActionNode:
+           case FlatCheckNode:
+           case FlatTagDeclaration:
+               throw new Error("Incompatible with tasks!");
+           case FlatMethod:
+           default:
+               throw new Error();
+           }
+           Hashtable<TempDescriptor,Integer> oldtable=temptable.get(fn);
+           if (oldtable==null||!oldtable.equals(currtable)) {
+               // Update table for this node
+               temptable.put(fn, currtable);
+               for(int i=0;i<fn.numNext();i++) {
+                   tovisit.add(fn.next(i));
+               }
+           }
+       }
+    }
+
+    private static Integer merge(Integer a, Integer b) {
+       if (a==null||a.equals(EITHER))
+           return b;
+       if (b==null||b.equals(EITHER))
+           return a;
+       if (a.equals(b))
+           return a;
+       return CONFLICT;
+    }
+       
+    void processCall(LocalityBinding currlb, FlatCall fc, boolean transaction, Hashtable<TempDescriptor, Integer> currtable) {
+       MethodDescriptor nodemd=fc.getMethod();
+       Set methodset=fc.getThis()==null?callgraph.getMethods(nodemd):
+           callgraph.getMethods(nodemd, fc.getThis().getType());
+       Integer currreturnval=null;
+       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));
+           }
+           if (fc.getThis()!=null) {
+               Integer thistype=currtable.get(fc.getThis());
+               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");
+               lb.setGlobalThis(thistype);
+           } else
+               lb.setGlobalThis(EITHER);//default value
+           //lb is built
+           if (!discovered.containsKey(lb)) {
+               lb.setGlobalReturn(EITHER);
+               tovisit.add(lb);
+               discovered.put(lb, lb);
+           } else
+               lb=discovered.get(lb);
+           Integer returnval=lb.getGlobalReturn();
+           currreturnval=merge(returnval, currreturnval);
+           dependence.put(md, currlb.getMethod()); 
+       }
+       currtable.put(fc.getReturnTemp(), currreturnval);
+    }
+
+    void processFieldNode(LocalityBinding lb, FlatFieldNode ffn, boolean transaction, Hashtable<TempDescriptor, Integer> currtable) {
+       Integer type=currtable.get(ffn.getSrc());
+       TempDescriptor dst=ffn.getDst();
+       if (type.equals(LOCAL)) {
+           if (ffn.getField().isGlobal())
+               currtable.put(dst,GLOBAL);
+           else
+               currtable.put(dst,LOCAL);                   
+       } else if (type.equals(GLOBAL)) {
+           if (!transaction)
+               throw Error("Global access outside of a transaction");
+           if (ffn.getField().getType().isPrimitive())
+               currtable.put(dst, LOCAL); // primitives are local
+           else
+               currtable.put(dst, GLOBAL);
+       } else if (type.equals(EITHER)) {
+           if (ffn.getField().getType().isPrimitive())
+               currtable.put(dst, LOCAL); // primitives are local
+           else
+               currtable.put(dst, EITHER);
+       } else if (type.equals(CONFLICT)) {
+           throw new Error("Access to object that could be either global or local");
+       }
+    }
+
+    //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());
+
+       if (dsttype.equals(LOCAL)) {
+           if (ffn.getField().isGlobal()) {
+               if (!(srctype.equals(GLOBAL)||srctype.equals(EITHER)))
+                   throw new Error("Writing possible local reference to global field");
+           } else {
+               if (!(srctype.equals(LOCAL)||srctype.equals(EITHER)))
+                   throw new Error("Writing possible global reference to local object");
+           }
+       } else if (dsttype.equals(GLOBAL)) {
+           if (!transaction)
+               throw Error("Global access outside of a transaction");
+           //okay to store primitives in global object
+           if (srctype.equals(LOCAL) && fsfn.getField().getType().isPrimitive())
+               return;
+           if (!(srctype.equals(GLOBAL)||srctype.equals(EITHER)))
+               throw new Error("Writing possible local reference to global object");
+       } else if (dsttype.equals(EITHER)) {
+           if (srctype.equals(CONFLICT))
+               throw new Error("Using reference that could be local or global");
+       } else if (dsttype.equals(CONFLICT)) {
+           throw new Error("Access to object that could be either global or local");
+       }
+    }
+
+    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");
+       }
+       if (fn.isGlobal())
+           currtable.put(fn.getDst(), GLOBAL);
+       else
+           currtable.put(fn.getDst(), LOCAL);
+    }
+
+    void processOpNode(FlatOpNode fon, Hashtable<TempDescriptor, Integer> currtable) {
+       /* Just propagate value */
+       currtable.put(fon.getDest(), currtable.get(fon.getLeft()));
+    }
+
+    void processCastNode(FlatCastNode fcn, Hashtable<TempDescriptor, Integer> currtable) {
+       currtable.put(fon.getDest(), currtable.get(fon.getSrc()));
+    }
+
+    void processLiteralNode(FlatLiteralNode fln, Hashtable<TempDescriptor, Integer> currtable) {
+       //null is either
+       if (fln.getValue()==null)
+           currtable.put(fln.getDst(), EITHER);
+       else
+           currtable.put(fln.getDst(), LOCAL);
+    }
+
+    void processReturnNode(LocalityBinding lb, FlatReturnNode frn, Hashtable<TempDescriptor, Integer> currtable) {
+       if(frn.getReturnTemp()!=null) {
+           Integer returntype=currtable.get(frn.getReturnTemp());
+           lb.setGlobalReturn(merge(returntype, lb.getGlobalReturn()));
+       }
+    }
+
+    void processSetElementNode(FlatSetElementNode fsen, Hashtable<TempDescriptor, Integer> currtable) {
+       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");
+       } else if (dsttype.equals(GLOBAL)) {
+           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");
+       } else if (dsttype.equals(EITHER)) {
+           if (srctype.equals(CONFLICT))
+               throw new Error("Using reference that could be local or global");
+       } else if (dsttype.equals(CONFLICT)) {
+           throw new Error("Access to object that could be either global or local");
+       }
+    }
+
+    void processElementNode(FlatElementNode fen, Hashtable<TempDescriptor, Integer> currtable) {
+       Integer type=currtable.get(fen.getSrc());
+       TempDescriptor dst=fen.getDst();
+       if (type.equals(LOCAL)) {
+           currtable.put(dst,LOCAL);               
+       } else if (type.equals(GLOBAL)) {
+           if (!transaction)
+               throw Error("Global access outside of a transaction");
+           currtable.put(dst, GLOBAL);
+       } else if (type.equals(EITHER)) {
+           currtable.put(dst, EITHER);
+       } else if (type.equals(CONFLICT)) {
+           throw new Error("Access to object that could be either global or local");
+       }
+    }
+}
diff --git a/Robust/src/Analysis/Locality/LocalityBinding.java b/Robust/src/Analysis/Locality/LocalityBinding.java
new file mode 100644 (file)
index 0000000..5df96d9
--- /dev/null
@@ -0,0 +1,82 @@
+package Analysis.Locality;
+import IR.MethodDescriptor;
+
+public class LocalityBinding {
+    private MethodDescriptor md;
+    private Integer[] isglobal;
+    private boolean istransaction;
+    private Integer isglobalreturn;
+    private Integer isglobalthis;
+
+    public LocalityBinding(MethodDescriptor md, boolean transaction) {
+       this.md=md;
+       isglobal=new boolean[md.numParameters()];
+       istransaction=transaction;
+    }
+
+    public String toString() {
+       String st=md.toString()+" ";
+       for(int i=0;i<isglobal.length;i++)
+           if (isglobal[i])
+               st+="global ";
+           else
+               st+="local ";
+       return st;
+    }
+
+    public void setGlobal(int i, Integer global) {
+       isglobal[i]=global;
+    }
+
+    public Integer isGlobal(int i) {
+       return isglobal[i];
+    }
+
+    public void setGlobalReturn(Integer global) {
+       isglobalreturn=global;
+    }
+
+    public Integer getGlobalReturn() {
+       return isglobalreturn;
+    }
+
+    public void setGlobalThis(Integer global) {
+       isglobalthis=global;
+    }
+
+    public Integer getGlobalThis() {
+       return isglobalthis;
+    }
+
+    public MethodDescriptor getMethod() {
+       return md;
+    }
+
+    public boolean isTransaction() {
+       return istransaction;
+    }
+
+    public boolean equals(Object o) {
+       if (o instanceof LocalityBinding) {
+           LocalityBinding lb=(LocalityBinding)o;
+           if (md!=lb.md)
+               return false;
+           for(int i=0;i<isglobal.length;i++)
+               if (!isglobal[i].equals(lb.isglobal[i]))
+                   return false;
+           if (!isglobalthis.equals(lb.isglobalthis))
+               return false;
+           return !istransaction.equals(lb.istransaction);
+       }
+       return false;
+    }
+
+    public int hashCode() {
+       int hashcode=md.hashCode();
+       for(int i=0;i<isglobal.length;i++) {
+           hashcode=hashcode*31+(isglobal[i]?0:1);
+       }
+       hashcode=hashcode*31+(istransaction?0:1);
+       return hashcode;
+    }
+}