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<LocalityBinding, Set<LocalityBinding>> dependence;
21 Hashtable<LocalityBinding, Hashtable<FlatNode,Hashtable<TempDescriptor, Integer>>> temptab;
22 Hashtable<LocalityBinding, Hashtable<FlatNode, Integer>> atomictab;
27 public static final Integer LOCAL=new Integer(0);
28 public static final Integer GLOBAL=new Integer(1);
29 public static final Integer EITHER=new Integer(2);
30 public static final Integer CONFLICT=new Integer(3);
32 public LocalityAnalysis(State state, CallGraph callgraph, TypeUtil typeutil) {
33 this.typeutil=typeutil;
35 this.discovered=new Hashtable<LocalityBinding,LocalityBinding>();
36 this.dependence=new Hashtable<LocalityBinding, Set<LocalityBinding>>();
37 this.temptab=new Hashtable<LocalityBinding, Hashtable<FlatNode,Hashtable<TempDescriptor, Integer>>>();
38 this.atomictab=new Hashtable<LocalityBinding, Hashtable<FlatNode, Integer>>();
39 this.lbtovisit=new Stack();
40 this.callgraph=callgraph;
44 private void doAnalysis() {
45 computeLocalityBindings();
48 private void computeLocalityBindings() {
49 LocalityBinding lbmain=new LocalityBinding(typeutil.getMain(), false);
50 lbmain.setGlobal(0, LOCAL);
51 lbtovisit.add(lbmain);
52 discovered.put(lbmain, lbmain);
54 while(!lbtovisit.empty()) {
55 LocalityBinding lb=(LocalityBinding) lbtovisit.pop();
56 Integer returnglobal=lb.getGlobalReturn();
57 MethodDescriptor md=lb.getMethod();
58 Hashtable<FlatNode,Hashtable<TempDescriptor, Integer>> temptable=new Hashtable<FlatNode,Hashtable<TempDescriptor, Integer>>();
59 Hashtable<FlatNode, Integer> atomictable=new Hashtable<FlatNode, Integer>();
60 computeCallsFlags(md, lb, temptable, atomictable);
61 atomictab.put(lb, atomictable);
62 temptab.put(lb, temptable);
64 if (!md.isStatic()&&!returnglobal.equals(lb.getGlobalReturn())) {
65 //return type is more precise now
66 //rerun everything that call us
67 lbtovisit.addAll(dependence.get(lb));
73 public void computeCallsFlags(MethodDescriptor md, LocalityBinding lb, Hashtable<FlatNode, Hashtable<TempDescriptor, Integer>> temptable, Hashtable<FlatNode, Integer> atomictable) {
74 FlatMethod fm=state.getMethodFlat(md);
75 HashSet<FlatNode> tovisit=new HashSet<FlatNode>();
76 tovisit.add(fm.getNext(0));
78 // Build table for initial node
79 Hashtable<TempDescriptor,Integer> table=new Hashtable<TempDescriptor,Integer>();
80 temptable.put(fm, table);
81 atomictable.put(fm, lb.isAtomic()?1:0);
82 int offset=md.isStatic()?0:1;
84 table.put(fm.getParameter(0), lb.getGlobalThis());
86 for(int i=offset;i<fm.numParameters();i++) {
87 TempDescriptor temp=fm.getParameter(i);
88 Integer b=lb.isGlobal(i-offset);
93 while(!tovisit.isEmpty()) {
94 FlatNode fn=tovisit.iterator().next();
96 Hashtable<TempDescriptor, Integer> currtable=new Hashtable<TempDescriptor, Integer>();
98 for(int i=0;i<fn.numPrev();i++) {
99 FlatNode prevnode=fn.getPrev(i);
100 if (atomictable.containsKey(prevnode)) {
101 atomicstate=atomictable.get(prevnode).intValue();
103 if (!temptable.containsKey(prevnode))
105 Hashtable<TempDescriptor, Integer> prevtable=temptable.get(prevnode);
106 for(Iterator<TempDescriptor> tempit=prevtable.keySet().iterator();tempit.hasNext();) {
107 TempDescriptor temp=tempit.next();
108 Integer tmpint=prevtable.get(temp);
109 Integer oldint=currtable.containsKey(temp)?currtable.get(temp):EITHER;
110 Integer newint=merge(tmpint, oldint);
111 currtable.put(temp, newint);
114 atomictable.put(fn, atomicstate);
117 case FKind.FlatAtomicEnterNode:
118 processAtomicEnterNode((FlatAtomicEnterNode)fn, atomictable);
120 case FKind.FlatAtomicExitNode:
121 processAtomicExitNode((FlatAtomicExitNode)fn, atomictable);
124 processCallNode(lb, (FlatCall)fn, currtable, isAtomic(atomictable, fn));
126 case FKind.FlatFieldNode:
127 processFieldNode(lb, (FlatFieldNode)fn, isAtomic(atomictable, fn), currtable);
129 case FKind.FlatSetFieldNode:
130 processSetFieldNode(lb, (FlatSetFieldNode)fn, isAtomic(atomictable,fn), currtable);
133 processNew(lb, (FlatNew)fn, isAtomic(atomictable, fn), currtable);
135 case FKind.FlatOpNode:
136 processOpNode((FlatOpNode)fn, currtable);
138 case FKind.FlatCastNode:
139 processCastNode((FlatCastNode)fn, currtable);
141 case FKind.FlatLiteralNode:
142 processLiteralNode((FlatLiteralNode)fn, currtable);
144 case FKind.FlatReturnNode:
145 processReturnNode(lb, (FlatReturnNode)fn, currtable);
147 case FKind.FlatSetElementNode:
148 processSetElementNode(lb, (FlatSetElementNode)fn, currtable, isAtomic(atomictable, fn));
150 case FKind.FlatElementNode:
151 processElementNode(lb, (FlatElementNode)fn, currtable, isAtomic(atomictable, fn));
153 case FKind.FlatCondBranch:
154 case FKind.FlatBackEdge:
156 //No action needed for these
158 case FKind.FlatFlagActionNode:
159 case FKind.FlatCheckNode:
160 case FKind.FlatTagDeclaration:
161 throw new Error("Incompatible with tasks!");
162 case FKind.FlatMethod:
166 Hashtable<TempDescriptor,Integer> oldtable=temptable.get(fn);
167 if (oldtable==null||!oldtable.equals(currtable)) {
168 // Update table for this node
169 temptable.put(fn, currtable);
170 for(int i=0;i<fn.numNext();i++) {
171 tovisit.add(fn.getNext(i));
177 private static boolean isAtomic(Hashtable<FlatNode, Integer> atomictable, FlatNode fn) {
178 return atomictable.get(fn).intValue()>0;
181 private static Integer merge(Integer a, Integer b) {
182 if (a==null||a.equals(EITHER))
184 if (b==null||b.equals(EITHER))
191 void processCallNode(LocalityBinding currlb, FlatCall fc, Hashtable<TempDescriptor, Integer> currtable, boolean isatomic) {
192 MethodDescriptor nodemd=fc.getMethod();
193 Set methodset=fc.getThis()==null?callgraph.getMethods(nodemd):
194 callgraph.getMethods(nodemd, fc.getThis().getType());
195 Integer currreturnval=EITHER; //Start off with the either value
196 for(Iterator methodit=methodset.iterator();methodit.hasNext();) {
197 MethodDescriptor md=(MethodDescriptor) methodit.next();
198 LocalityBinding lb=new LocalityBinding(md, isatomic);
199 for(int i=0;i<fc.numArgs();i++) {
200 TempDescriptor arg=fc.getArg(i);
201 lb.setGlobal(i,currtable.get(arg));
203 if (fc.getThis()!=null) {
204 Integer thistype=currtable.get(fc.getThis());
207 if(thistype.equals(CONFLICT))
208 throw new Error("Using type that can be either local or global in context:\n"+currlb.getExplanation());
209 if(thistype.equals(GLOBAL)&&!isatomic)
210 throw new Error("Using global object outside of transaction in context:\n"+currlb.getExplanation());
211 lb.setGlobalThis(thistype);
213 lb.setGlobalThis(EITHER);//default value
215 if (!discovered.containsKey(lb)) {
216 lb.setGlobalReturn(EITHER);
217 lb.setParent(currlb);
219 discovered.put(lb, lb);
221 lb=discovered.get(lb);
222 Integer returnval=lb.getGlobalReturn();
223 currreturnval=merge(returnval, currreturnval);
224 if (!dependence.containsKey(lb))
225 dependence.put(lb, new HashSet<LocalityBinding>());
226 dependence.get(lb).add(currlb);
228 if (fc.getReturnTemp()!=null) {
229 currtable.put(fc.getReturnTemp(), currreturnval);
233 void processFieldNode(LocalityBinding lb, FlatFieldNode ffn, boolean transaction, Hashtable<TempDescriptor, Integer> currtable) {
234 Integer type=currtable.get(ffn.getSrc());
235 TempDescriptor dst=ffn.getDst();
236 if (type.equals(LOCAL)) {
237 if (ffn.getField().isGlobal())
238 currtable.put(dst,GLOBAL);
240 currtable.put(dst,LOCAL);
241 } else if (type.equals(GLOBAL)) {
243 throw new Error("Global access outside of a transaction in context:\n"+lb.getExplanation());
244 if (ffn.getField().getType().isPrimitive())
245 currtable.put(dst, LOCAL); // primitives are local
247 currtable.put(dst, GLOBAL);
248 } else if (type.equals(EITHER)) {
249 if (ffn.getField().getType().isPrimitive())
250 currtable.put(dst, LOCAL); // primitives are local
252 currtable.put(dst, EITHER);
253 } else if (type.equals(CONFLICT)) {
254 throw new Error("Access to object that could be either global or local in context:\n"+lb.getExplanation());
258 //need to handle primitives
259 void processSetFieldNode(LocalityBinding lb, FlatSetFieldNode fsfn, boolean transaction, Hashtable<TempDescriptor, Integer> currtable) {
260 Integer srctype=currtable.get(fsfn.getSrc());
261 Integer dsttype=currtable.get(fsfn.getDst());
263 if (dsttype.equals(LOCAL)) {
264 if (fsfn.getField().isGlobal()) {
265 if (!(srctype.equals(GLOBAL)||srctype.equals(EITHER)))
266 throw new Error("Writing possible local reference to global field in context: \n"+lb.getExplanation());
268 if (!(srctype.equals(LOCAL)||srctype.equals(EITHER)))
269 throw new Error("Writing possible global reference to local object in context: \n"+lb.getExplanation());
271 } else if (dsttype.equals(GLOBAL)) {
273 throw new Error("Global access outside of a transaction in context:\n"+lb.getExplanation());
274 //okay to store primitives in global object
275 if (srctype.equals(LOCAL) && fsfn.getField().getType().isPrimitive())
277 if (!(srctype.equals(GLOBAL)||srctype.equals(EITHER)))
278 throw new Error("Writing possible local reference to global object in context:\n"+lb.getExplanation());
279 } else if (dsttype.equals(EITHER)) {
280 if (srctype.equals(CONFLICT))
281 throw new Error("Using reference that could be local or global in context:\n"+lb.getExplanation());
282 } else if (dsttype.equals(CONFLICT)) {
283 throw new Error("Access to object that could be either global or local in context:\n"+lb.getExplanation());
287 void processNew(LocalityBinding lb, FlatNew fn, boolean transaction, Hashtable<TempDescriptor, Integer> currtable) {
288 if (fn.isGlobal()&&!transaction) {
289 throw new Error("Allocating global object outside of transaction in context:"+lb.getExplanation());
292 currtable.put(fn.getDst(), GLOBAL);
294 currtable.put(fn.getDst(), LOCAL);
297 void processOpNode(FlatOpNode fon, Hashtable<TempDescriptor, Integer> currtable) {
298 /* Just propagate value */
299 currtable.put(fon.getDest(), currtable.get(fon.getLeft()));
302 void processCastNode(FlatCastNode fcn, Hashtable<TempDescriptor, Integer> currtable) {
303 currtable.put(fcn.getDst(), currtable.get(fcn.getSrc()));
306 void processLiteralNode(FlatLiteralNode fln, Hashtable<TempDescriptor, Integer> currtable) {
308 if (fln.getValue()==null)
309 currtable.put(fln.getDst(), EITHER);
311 currtable.put(fln.getDst(), LOCAL);
314 void processReturnNode(LocalityBinding lb, FlatReturnNode frn, Hashtable<TempDescriptor, Integer> currtable) {
315 if(frn.getReturnTemp()!=null) {
316 Integer returntype=currtable.get(frn.getReturnTemp());
317 lb.setGlobalReturn(merge(returntype, lb.getGlobalReturn()));
321 void processSetElementNode(LocalityBinding lb, FlatSetElementNode fsen, Hashtable<TempDescriptor, Integer> currtable, boolean isatomic) {
322 Integer srctype=currtable.get(fsen.getSrc());
323 Integer dsttype=currtable.get(fsen.getDst());
325 if (dsttype.equals(LOCAL)) {
326 if (!(srctype.equals(LOCAL)||srctype.equals(EITHER)))
327 throw new Error("Writing possible global reference to local object in context:\n"+lb.getExplanation());
328 } else if (dsttype.equals(GLOBAL)) {
329 if (!(srctype.equals(GLOBAL)||srctype.equals(EITHER)))
330 throw new Error("Writing possible local reference to global object in context:\n"+lb.getExplanation());
332 throw new Error("Global access outside of a transaction in context:\n"+lb.getExplanation());
333 } else if (dsttype.equals(EITHER)) {
334 if (srctype.equals(CONFLICT))
335 throw new Error("Using reference that could be local or global in context:\n"+lb.getExplanation());
336 } else if (dsttype.equals(CONFLICT)) {
337 throw new Error("Access to object that could be either global or local in context:\n"+lb.getExplanation());
341 void processElementNode(LocalityBinding lb, FlatElementNode fen, Hashtable<TempDescriptor, Integer> currtable, boolean isatomic) {
342 Integer type=currtable.get(fen.getSrc());
343 TempDescriptor dst=fen.getDst();
344 if (type.equals(LOCAL)) {
345 currtable.put(dst,LOCAL);
346 } else if (type.equals(GLOBAL)) {
348 throw new Error("Global access outside of a transaction in context:\n"+lb.getExplanation());
349 currtable.put(dst, GLOBAL);
350 } else if (type.equals(EITHER)) {
351 currtable.put(dst, EITHER);
352 } else if (type.equals(CONFLICT)) {
353 throw new Error("Access to object that could be either global or local in context:\n"+lb.getExplanation());
357 void processAtomicEnterNode(FlatAtomicEnterNode fen, Hashtable<FlatNode, Integer> atomictable) {
358 int atomic=atomictable.get(fen).intValue();
359 atomictable.put(fen, new Integer(atomic+1));
362 void processAtomicExitNode(FlatAtomicExitNode fen, Hashtable<FlatNode, Integer> atomictable) {
363 int atomic=atomictable.get(fen).intValue();
364 atomictable.put(fen, new Integer(atomic-1));