1 package Analysis.Locality;
3 import java.util.Hashtable;
4 import java.util.Stack;
6 import java.util.HashSet;
7 import java.util.Iterator;
8 import java.util.Arrays;
9 import Analysis.CallGraph.CallGraph;
10 import IR.SymbolTable;
13 import IR.MethodDescriptor;
16 public class LocalityAnalysis {
19 Hashtable<LocalityBinding,LocalityBinding> discovered;
20 Hashtable<MethodDescriptor, MethodDescriptor> dependence;
23 public static final Integer LOCAL=new Integer(0);
24 public static final Integer GLOBAL=new Integer(1);
25 public static final Integer EITHER=new Integer(2);
26 public static final Integer CONFLICT=new Integer(3);
29 public LocalityAnalysis(State state, CallGraph callgraph, TypeUtil typeutil) {
31 this.discovered=new Hashtable<LocalityBinding,LocalityBinding>();
32 this.dependence=new Hashtable<MethodDescriptor, MethodDescriptor>();
33 this.tovisit=new Stack();
34 this.callgraph=callgraph;
38 private void doAnalysis() {
39 computeLocalityBindings();
42 private void computeLocalityBindings() {
43 LocalityBinding lbmain=new LocalityBinding(typeutil.getMain(), false);
45 discovered.put(lbmain, lbmain);
47 while(!tovisit.empty()) {
48 LocalityBinding lb=(LocalityBinding) tovisit.pop();
49 MethodDescriptor md=lb.getMethod();
50 Hashtable<FlatNode,Hashtable<TempDescriptor, Integer>> temptable=new Hashtable<FlatNode,Hashtable<TempDescriptor, Integer>>();
51 Hashtable<FlatNode, Integer> atomictable=new Hashtable<FlatNode, Integer>();
52 computeCallsFlags(md, lb, temptable, atomictable);
56 public void computeCallsFlags(MethodDescriptor md, LocalityBinding lb, Hashtable<FlatNode, Hashtable<TempDescriptor, Integer>> temptable, Hashtable<FlatNode, Integer> atomictable) {
57 FlatMethod fm=state.getMethodFlat(md);
58 HashSet<FlatNode> tovisit=new HashSet<FlatNode>();
59 tovisit.add(fm.getNext(0));
62 // Build table for initial node
63 Hashtable<TempDescriptor,Integer> table=new Hashtable<TempDescriptor,Integer>();
64 temptable.put(fm, table);
65 atomictable.put(fm, lb.isAtomic()?1:0);
66 for(int i=0;i<fm.numParameters();i++) {
67 TempDescriptor temp=fm.getParameter(i);
68 Integer b=lb.isGlobal(i);
73 while(!tovisit.isEmpty()) {
74 FlatNode fn=tovisit.iterator().next();
75 Hashtable<TempDescriptor, Integer> currtable=new Hashtable<TempDescriptor, Integer>();
77 for(int i=0;i<fn.numPrev();i++) {
78 FlatNode prevnode=fn.getPrev(i);
79 if (atomictable.containsKey(prevnode)) {
80 atomicstate=atomictable.get(prevnode).intValue();
82 if (!temptable.containsKey(prevnode))
84 Hashtable<TempDescriptor, Integer> prevtable=temptable.get(prevnode);
85 for(Iterator<TempDescriptor> tempit=prevtable.keySet().iterator();tempit.hasNext();) {
86 TempDescriptor temp=tempit.next();
87 Integer tmpint=prevtable.get(temp);
88 Integer oldint=currtable.containsKey(temp)?currtable.get(temp):null;
89 Integer newint=merge(tmpint, oldint);
90 currtable.put(temp, newint);
93 atomictable.put(fn, atomicstate);
96 case FKind.FlatAtomicEnterNode:
97 processAtomicEnterNode((FlatAtomicEnterNode)fn, atomictable);
99 case FKind.FlatAtomicExitNode:
100 processAtomicExitNode((FlatAtomicExitNode)fn, atomictable);
103 processCall(lb, (FlatCall)fn, currtable, isAtomic(atomictable, fn));
105 case FKind.FlatFieldNode:
106 processFieldNode((FlatFieldNode)fn, isAtomic(atomictable, fn), currtable);
108 case FKind.FlatSetFieldNode:
109 processSetFieldNode((FlatSetFieldNode)fn, isAtomic(atomictable,fn), currtable);
112 processNew((FlatNew)fn, isAtomic(atomictable, fn), currtable);
114 case FKind.FlatOpNode:
115 processOpNode((FlatOpNode)fn, currtable);
117 case FKind.FlatCastNode:
118 processCastNode((FlatCastNode)fn, currtable);
120 case FKind.FlatLiteralNode:
121 processLiteralNode((FlatLiteralNode)fn, currtable);
123 case FKind.FlatReturnNode:
124 processReturnNode(lb, (FlatReturnNode)fn, currtable);
126 case FKind.FlatSetElementNode:
127 processSetElementNode((FlatSetElementNode)fn, currtable, isAtomic(atomictable, fn));
129 case FKind.FlatElementNode:
130 processElementNode((FlatElementNode)fn, currtable, isAtomic(atomictable, fn));
132 case FKind.FlatCondBranch:
133 case FKind.FlatBackEdge:
135 //No action needed for these
137 case FKind.FlatFlagActionNode:
138 case FKind.FlatCheckNode:
139 case FKind.FlatTagDeclaration:
140 throw new Error("Incompatible with tasks!");
141 case FKind.FlatMethod:
145 Hashtable<TempDescriptor,Integer> oldtable=temptable.get(fn);
146 if (oldtable==null||!oldtable.equals(currtable)) {
147 // Update table for this node
148 temptable.put(fn, currtable);
149 for(int i=0;i<fn.numNext();i++) {
150 tovisit.add(fn.getNext(i));
156 private static boolean isAtomic(Hashtable<FlatNode, Integer> atomictable, FlatNode fn) {
157 return atomictable.get(fn).intValue()>0;
160 private static Integer merge(Integer a, Integer b) {
161 if (a==null||a.equals(EITHER))
163 if (b==null||b.equals(EITHER))
170 void processCall(LocalityBinding currlb, FlatCall fc, Hashtable<TempDescriptor, Integer> currtable, boolean isatomic) {
171 MethodDescriptor nodemd=fc.getMethod();
172 Set methodset=fc.getThis()==null?callgraph.getMethods(nodemd):
173 callgraph.getMethods(nodemd, fc.getThis().getType());
174 Integer currreturnval=null;
175 for(Iterator methodit=methodset.iterator();methodit.hasNext();) {
176 MethodDescriptor md=(MethodDescriptor) methodit.next();
177 LocalityBinding lb=new LocalityBinding(md, isatomic);
178 for(int i=0;i<fc.numArgs();i++) {
179 TempDescriptor arg=fc.getArg(i);
180 lb.setGlobal(i,currtable.get(arg));
182 if (fc.getThis()!=null) {
183 Integer thistype=currtable.get(fc.getThis());
184 if(thistype.equals(CONFLICT))
185 throw new Error("Using type that can be either local or global");
186 if(thistype.equals(GLOBAL)&&!isatomic)
187 throw new Error("Using global object outside of transaction");
188 lb.setGlobalThis(thistype);
190 lb.setGlobalThis(EITHER);//default value
192 if (!discovered.containsKey(lb)) {
193 lb.setGlobalReturn(EITHER);
195 discovered.put(lb, lb);
197 lb=discovered.get(lb);
198 Integer returnval=lb.getGlobalReturn();
199 currreturnval=merge(returnval, currreturnval);
200 dependence.put(md, currlb.getMethod());
202 currtable.put(fc.getReturnTemp(), currreturnval);
205 void processFieldNode(FlatFieldNode ffn, boolean transaction, Hashtable<TempDescriptor, Integer> currtable) {
206 Integer type=currtable.get(ffn.getSrc());
207 TempDescriptor dst=ffn.getDst();
208 if (type.equals(LOCAL)) {
209 if (ffn.getField().isGlobal())
210 currtable.put(dst,GLOBAL);
212 currtable.put(dst,LOCAL);
213 } else if (type.equals(GLOBAL)) {
215 throw new Error("Global access outside of a transaction");
216 if (ffn.getField().getType().isPrimitive())
217 currtable.put(dst, LOCAL); // primitives are local
219 currtable.put(dst, GLOBAL);
220 } else if (type.equals(EITHER)) {
221 if (ffn.getField().getType().isPrimitive())
222 currtable.put(dst, LOCAL); // primitives are local
224 currtable.put(dst, EITHER);
225 } else if (type.equals(CONFLICT)) {
226 throw new Error("Access to object that could be either global or local");
230 //need to handle primitives
231 void processSetFieldNode(FlatSetFieldNode fsfn, boolean transaction, Hashtable<TempDescriptor, Integer> currtable) {
232 Integer srctype=currtable.get(fsfn.getSrc());
233 Integer dsttype=currtable.get(fsfn.getDst());
235 if (dsttype.equals(LOCAL)) {
236 if (fsfn.getField().isGlobal()) {
237 if (!(srctype.equals(GLOBAL)||srctype.equals(EITHER)))
238 throw new Error("Writing possible local reference to global field");
240 if (!(srctype.equals(LOCAL)||srctype.equals(EITHER)))
241 throw new Error("Writing possible global reference to local object");
243 } else if (dsttype.equals(GLOBAL)) {
245 throw new Error("Global access outside of a transaction");
246 //okay to store primitives in global object
247 if (srctype.equals(LOCAL) && fsfn.getField().getType().isPrimitive())
249 if (!(srctype.equals(GLOBAL)||srctype.equals(EITHER)))
250 throw new Error("Writing possible local reference to global object");
251 } else if (dsttype.equals(EITHER)) {
252 if (srctype.equals(CONFLICT))
253 throw new Error("Using reference that could be local or global");
254 } else if (dsttype.equals(CONFLICT)) {
255 throw new Error("Access to object that could be either global or local");
259 void processNew(FlatNew fn, boolean transaction, Hashtable<TempDescriptor, Integer> currtable) {
260 if (fn.isGlobal()&&!transaction) {
261 throw new Error("Allocating global object outside of transaction");
264 currtable.put(fn.getDst(), GLOBAL);
266 currtable.put(fn.getDst(), LOCAL);
269 void processOpNode(FlatOpNode fon, Hashtable<TempDescriptor, Integer> currtable) {
270 /* Just propagate value */
271 currtable.put(fon.getDest(), currtable.get(fon.getLeft()));
274 void processCastNode(FlatCastNode fcn, Hashtable<TempDescriptor, Integer> currtable) {
275 currtable.put(fcn.getDst(), currtable.get(fcn.getSrc()));
278 void processLiteralNode(FlatLiteralNode fln, Hashtable<TempDescriptor, Integer> currtable) {
280 if (fln.getValue()==null)
281 currtable.put(fln.getDst(), EITHER);
283 currtable.put(fln.getDst(), LOCAL);
286 void processReturnNode(LocalityBinding lb, FlatReturnNode frn, Hashtable<TempDescriptor, Integer> currtable) {
287 if(frn.getReturnTemp()!=null) {
288 Integer returntype=currtable.get(frn.getReturnTemp());
289 lb.setGlobalReturn(merge(returntype, lb.getGlobalReturn()));
293 void processSetElementNode(FlatSetElementNode fsen, Hashtable<TempDescriptor, Integer> currtable, boolean isatomic) {
294 Integer srctype=currtable.get(fsen.getSrc());
295 Integer dsttype=currtable.get(fsen.getDst());
297 if (dsttype.equals(LOCAL)) {
298 if (!(srctype.equals(LOCAL)||srctype.equals(EITHER)))
299 throw new Error("Writing possible global reference to local object");
300 } else if (dsttype.equals(GLOBAL)) {
301 if (!(srctype.equals(GLOBAL)||srctype.equals(EITHER)))
302 throw new Error("Writing possible local reference to global object");
304 throw new Error("Global access outside of a transaction");
305 } else if (dsttype.equals(EITHER)) {
306 if (srctype.equals(CONFLICT))
307 throw new Error("Using reference that could be local or global");
308 } else if (dsttype.equals(CONFLICT)) {
309 throw new Error("Access to object that could be either global or local");
313 void processElementNode(FlatElementNode fen, Hashtable<TempDescriptor, Integer> currtable, boolean isatomic) {
314 Integer type=currtable.get(fen.getSrc());
315 TempDescriptor dst=fen.getDst();
316 if (type.equals(LOCAL)) {
317 currtable.put(dst,LOCAL);
318 } else if (type.equals(GLOBAL)) {
320 throw new Error("Global access outside of a transaction");
321 currtable.put(dst, GLOBAL);
322 } else if (type.equals(EITHER)) {
323 currtable.put(dst, EITHER);
324 } else if (type.equals(CONFLICT)) {
325 throw new Error("Access to object that could be either global or local");
328 void processAtomicEnterNode(FlatAtomicEnterNode fen, Hashtable<FlatNode, Integer> atomictable) {
329 int atomic=atomictable.get(fen).intValue();
330 atomictable.put(fen, new Integer(atomic+1));
333 void processAtomicExitNode(FlatAtomicExitNode fen, Hashtable<FlatNode, Integer> atomictable) {
334 int atomic=atomictable.get(fen).intValue();
335 atomictable.put(fen, new Integer(atomic-1));