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;
23 Hashtable<LocalityBinding, Hashtable<FlatAtomicEnterNode, Set<TempDescriptor>>> tempstosave;
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;
41 this.tempstosave=new Hashtable<LocalityBinding, Hashtable<FlatAtomicEnterNode, Set<TempDescriptor>>>();
46 public Set<LocalityBinding> getLocalityBindings() {
47 return discovered.keySet();
50 public Hashtable<FlatNode, Hashtable<TempDescriptor, Integer>> getNodeTempInfo(LocalityBinding lb) {
51 return temptab.get(lb);
54 public Hashtable<FlatNode, Integer> getAtomic(LocalityBinding lb) {
55 return atomictab.get(lb);
58 private void doAnalysis() {
59 computeLocalityBindings();
62 private void computeLocalityBindings() {
63 LocalityBinding lbmain=new LocalityBinding(typeutil.getMain(), false);
64 lbmain.setGlobal(0, LOCAL);
65 lbtovisit.add(lbmain);
66 discovered.put(lbmain, lbmain);
68 while(!lbtovisit.empty()) {
69 LocalityBinding lb=(LocalityBinding) lbtovisit.pop();
70 Integer returnglobal=lb.getGlobalReturn();
71 MethodDescriptor md=lb.getMethod();
72 Hashtable<FlatNode,Hashtable<TempDescriptor, Integer>> temptable=new Hashtable<FlatNode,Hashtable<TempDescriptor, Integer>>();
73 Hashtable<FlatNode, Integer> atomictable=new Hashtable<FlatNode, Integer>();
74 computeCallsFlags(md, lb, temptable, atomictable);
75 atomictab.put(lb, atomictable);
76 temptab.put(lb, temptable);
78 if (!md.isStatic()&&!returnglobal.equals(lb.getGlobalReturn())) {
79 //return type is more precise now
80 //rerun everything that call us
81 lbtovisit.addAll(dependence.get(lb));
87 public void computeCallsFlags(MethodDescriptor md, LocalityBinding lb, Hashtable<FlatNode, Hashtable<TempDescriptor, Integer>> temptable, Hashtable<FlatNode, Integer> atomictable) {
88 FlatMethod fm=state.getMethodFlat(md);
89 HashSet<FlatNode> tovisit=new HashSet<FlatNode>();
90 tovisit.add(fm.getNext(0));
92 // Build table for initial node
93 Hashtable<TempDescriptor,Integer> table=new Hashtable<TempDescriptor,Integer>();
94 temptable.put(fm, table);
95 atomictable.put(fm, lb.isAtomic()?1:0);
96 int offset=md.isStatic()?0:1;
98 table.put(fm.getParameter(0), lb.getGlobalThis());
100 for(int i=offset;i<fm.numParameters();i++) {
101 TempDescriptor temp=fm.getParameter(i);
102 Integer b=lb.isGlobal(i-offset);
107 while(!tovisit.isEmpty()) {
108 FlatNode fn=tovisit.iterator().next();
110 Hashtable<TempDescriptor, Integer> currtable=new Hashtable<TempDescriptor, Integer>();
112 for(int i=0;i<fn.numPrev();i++) {
113 FlatNode prevnode=fn.getPrev(i);
114 if (atomictable.containsKey(prevnode)) {
115 atomicstate=atomictable.get(prevnode).intValue();
117 if (!temptable.containsKey(prevnode))
119 Hashtable<TempDescriptor, Integer> prevtable=temptable.get(prevnode);
120 for(Iterator<TempDescriptor> tempit=prevtable.keySet().iterator();tempit.hasNext();) {
121 TempDescriptor temp=tempit.next();
122 Integer tmpint=prevtable.get(temp);
123 Integer oldint=currtable.containsKey(temp)?currtable.get(temp):EITHER;
124 Integer newint=merge(tmpint, oldint);
125 currtable.put(temp, newint);
128 atomictable.put(fn, atomicstate);
131 case FKind.FlatAtomicEnterNode:
132 processAtomicEnterNode((FlatAtomicEnterNode)fn, atomictable);
134 case FKind.FlatAtomicExitNode:
135 processAtomicExitNode((FlatAtomicExitNode)fn, atomictable);
138 processCallNode(lb, (FlatCall)fn, currtable, isAtomic(atomictable, fn));
140 case FKind.FlatFieldNode:
141 processFieldNode(lb, (FlatFieldNode)fn, isAtomic(atomictable, fn), currtable);
143 case FKind.FlatSetFieldNode:
144 processSetFieldNode(lb, (FlatSetFieldNode)fn, isAtomic(atomictable,fn), currtable);
147 processNew(lb, (FlatNew)fn, isAtomic(atomictable, fn), currtable);
149 case FKind.FlatOpNode:
150 processOpNode((FlatOpNode)fn, currtable);
152 case FKind.FlatCastNode:
153 processCastNode((FlatCastNode)fn, currtable);
155 case FKind.FlatLiteralNode:
156 processLiteralNode((FlatLiteralNode)fn, currtable);
158 case FKind.FlatReturnNode:
159 processReturnNode(lb, (FlatReturnNode)fn, currtable);
161 case FKind.FlatSetElementNode:
162 processSetElementNode(lb, (FlatSetElementNode)fn, currtable, isAtomic(atomictable, fn));
164 case FKind.FlatElementNode:
165 processElementNode(lb, (FlatElementNode)fn, currtable, isAtomic(atomictable, fn));
167 case FKind.FlatCondBranch:
168 case FKind.FlatBackEdge:
170 //No action needed for these
172 case FKind.FlatFlagActionNode:
173 case FKind.FlatCheckNode:
174 case FKind.FlatTagDeclaration:
175 throw new Error("Incompatible with tasks!");
176 case FKind.FlatMethod:
180 Hashtable<TempDescriptor,Integer> oldtable=temptable.get(fn);
181 if (oldtable==null||!oldtable.equals(currtable)) {
182 // Update table for this node
183 temptable.put(fn, currtable);
184 for(int i=0;i<fn.numNext();i++) {
185 tovisit.add(fn.getNext(i));
191 private static boolean isAtomic(Hashtable<FlatNode, Integer> atomictable, FlatNode fn) {
192 return atomictable.get(fn).intValue()>0;
195 private static Integer merge(Integer a, Integer b) {
196 if (a==null||a.equals(EITHER))
198 if (b==null||b.equals(EITHER))
205 void processCallNode(LocalityBinding currlb, FlatCall fc, Hashtable<TempDescriptor, Integer> currtable, boolean isatomic) {
206 MethodDescriptor nodemd=fc.getMethod();
207 Set methodset=fc.getThis()==null?callgraph.getMethods(nodemd):
208 callgraph.getMethods(nodemd, fc.getThis().getType());
209 Integer currreturnval=EITHER; //Start off with the either value
210 for(Iterator methodit=methodset.iterator();methodit.hasNext();) {
211 MethodDescriptor md=(MethodDescriptor) methodit.next();
212 LocalityBinding lb=new LocalityBinding(md, isatomic);
213 for(int i=0;i<fc.numArgs();i++) {
214 TempDescriptor arg=fc.getArg(i);
215 lb.setGlobal(i,currtable.get(arg));
217 if (fc.getThis()!=null) {
218 Integer thistype=currtable.get(fc.getThis());
221 if(thistype.equals(CONFLICT))
222 throw new Error("Using type that can be either local or global in context:\n"+currlb.getExplanation());
223 if(thistype.equals(GLOBAL)&&!isatomic)
224 throw new Error("Using global object outside of transaction in context:\n"+currlb.getExplanation());
225 lb.setGlobalThis(thistype);
227 lb.setGlobalThis(EITHER);//default value
229 if (!discovered.containsKey(lb)) {
230 lb.setGlobalReturn(EITHER);
231 lb.setParent(currlb);
233 discovered.put(lb, lb);
235 lb=discovered.get(lb);
236 Integer returnval=lb.getGlobalReturn();
237 currreturnval=merge(returnval, currreturnval);
238 if (!dependence.containsKey(lb))
239 dependence.put(lb, new HashSet<LocalityBinding>());
240 dependence.get(lb).add(currlb);
242 if (fc.getReturnTemp()!=null) {
243 currtable.put(fc.getReturnTemp(), currreturnval);
247 void processFieldNode(LocalityBinding lb, FlatFieldNode ffn, boolean transaction, Hashtable<TempDescriptor, Integer> currtable) {
248 Integer type=currtable.get(ffn.getSrc());
249 TempDescriptor dst=ffn.getDst();
250 if (type.equals(LOCAL)) {
251 if (ffn.getField().isGlobal())
252 currtable.put(dst,GLOBAL);
254 currtable.put(dst,LOCAL);
255 } else if (type.equals(GLOBAL)) {
257 throw new Error("Global access outside of a transaction in context:\n"+lb.getExplanation());
258 if (ffn.getField().getType().isPrimitive())
259 currtable.put(dst, LOCAL); // primitives are local
261 currtable.put(dst, GLOBAL);
262 } else if (type.equals(EITHER)) {
263 if (ffn.getField().getType().isPrimitive())
264 currtable.put(dst, LOCAL); // primitives are local
266 currtable.put(dst, EITHER);
267 } else if (type.equals(CONFLICT)) {
268 throw new Error("Access to object that could be either global or local in context:\n"+lb.getExplanation());
272 //need to handle primitives
273 void processSetFieldNode(LocalityBinding lb, FlatSetFieldNode fsfn, boolean transaction, Hashtable<TempDescriptor, Integer> currtable) {
274 Integer srctype=currtable.get(fsfn.getSrc());
275 Integer dsttype=currtable.get(fsfn.getDst());
277 if (dsttype.equals(LOCAL)) {
278 if (fsfn.getField().isGlobal()) {
279 if (!(srctype.equals(GLOBAL)||srctype.equals(EITHER)))
280 throw new Error("Writing possible local reference to global field in context: \n"+lb.getExplanation());
282 if (!(srctype.equals(LOCAL)||srctype.equals(EITHER)))
283 throw new Error("Writing possible global reference to local object in context: \n"+lb.getExplanation());
285 } else if (dsttype.equals(GLOBAL)) {
287 throw new Error("Global access outside of a transaction in context:\n"+lb.getExplanation());
288 //okay to store primitives in global object
289 if (srctype.equals(LOCAL) && fsfn.getField().getType().isPrimitive())
291 if (!(srctype.equals(GLOBAL)||srctype.equals(EITHER)))
292 throw new Error("Writing possible local reference to global object in context:\n"+lb.getExplanation());
293 } else if (dsttype.equals(EITHER)) {
294 if (srctype.equals(CONFLICT))
295 throw new Error("Using reference that could be local or global in context:\n"+lb.getExplanation());
296 } else if (dsttype.equals(CONFLICT)) {
297 throw new Error("Access to object that could be either global or local in context:\n"+lb.getExplanation());
301 void processNew(LocalityBinding lb, FlatNew fn, boolean transaction, Hashtable<TempDescriptor, Integer> currtable) {
302 if (fn.isGlobal()&&!transaction) {
303 throw new Error("Allocating global object outside of transaction in context:"+lb.getExplanation());
306 currtable.put(fn.getDst(), GLOBAL);
308 currtable.put(fn.getDst(), LOCAL);
311 void processOpNode(FlatOpNode fon, Hashtable<TempDescriptor, Integer> currtable) {
312 /* Just propagate value */
313 currtable.put(fon.getDest(), currtable.get(fon.getLeft()));
316 void processCastNode(FlatCastNode fcn, Hashtable<TempDescriptor, Integer> currtable) {
317 currtable.put(fcn.getDst(), currtable.get(fcn.getSrc()));
320 void processLiteralNode(FlatLiteralNode fln, Hashtable<TempDescriptor, Integer> currtable) {
322 if (fln.getValue()==null)
323 currtable.put(fln.getDst(), EITHER);
325 currtable.put(fln.getDst(), LOCAL);
328 void processReturnNode(LocalityBinding lb, FlatReturnNode frn, Hashtable<TempDescriptor, Integer> currtable) {
329 if(frn.getReturnTemp()!=null) {
330 Integer returntype=currtable.get(frn.getReturnTemp());
331 lb.setGlobalReturn(merge(returntype, lb.getGlobalReturn()));
335 void processSetElementNode(LocalityBinding lb, FlatSetElementNode fsen, Hashtable<TempDescriptor, Integer> currtable, boolean isatomic) {
336 Integer srctype=currtable.get(fsen.getSrc());
337 Integer dsttype=currtable.get(fsen.getDst());
339 if (dsttype.equals(LOCAL)) {
340 if (!(srctype.equals(LOCAL)||srctype.equals(EITHER)))
341 throw new Error("Writing possible global reference to local object in context:\n"+lb.getExplanation());
342 } else if (dsttype.equals(GLOBAL)) {
343 if (!(srctype.equals(GLOBAL)||srctype.equals(EITHER)))
344 throw new Error("Writing possible local reference to global object in context:\n"+lb.getExplanation());
346 throw new Error("Global access outside of a transaction in context:\n"+lb.getExplanation());
347 } else if (dsttype.equals(EITHER)) {
348 if (srctype.equals(CONFLICT))
349 throw new Error("Using reference that could be local or global in context:\n"+lb.getExplanation());
350 } else if (dsttype.equals(CONFLICT)) {
351 throw new Error("Access to object that could be either global or local in context:\n"+lb.getExplanation());
355 void processElementNode(LocalityBinding lb, FlatElementNode fen, Hashtable<TempDescriptor, Integer> currtable, boolean isatomic) {
356 Integer type=currtable.get(fen.getSrc());
357 TempDescriptor dst=fen.getDst();
358 if (type.equals(LOCAL)) {
359 currtable.put(dst,LOCAL);
360 } else if (type.equals(GLOBAL)) {
362 throw new Error("Global access outside of a transaction in context:\n"+lb.getExplanation());
363 currtable.put(dst, GLOBAL);
364 } else if (type.equals(EITHER)) {
365 currtable.put(dst, EITHER);
366 } else if (type.equals(CONFLICT)) {
367 throw new Error("Access to object that could be either global or local in context:\n"+lb.getExplanation());
371 void processAtomicEnterNode(FlatAtomicEnterNode fen, Hashtable<FlatNode, Integer> atomictable) {
372 int atomic=atomictable.get(fen).intValue();
373 atomictable.put(fen, new Integer(atomic+1));
376 void processAtomicExitNode(FlatAtomicExitNode fen, Hashtable<FlatNode, Integer> atomictable) {
377 int atomic=atomictable.get(fen).intValue();
378 atomictable.put(fen, new Integer(atomic-1));
381 private Hashtable<FlatNode, Set<TempDescriptor>> computeLiveTemps(FlatMethod fm) {
382 Hashtable<FlatNode, Set<TempDescriptor>> nodetotemps=new Hashtable<FlatNode, Set<TempDescriptor>>();
384 Set<FlatNode> toprocess=fm.getNodeSet();
386 while(!toprocess.isEmpty()) {
387 FlatNode fn=toprocess.iterator().next();
388 toprocess.remove(fn);
389 boolean isatomic=atomictab.get(fn).intValue()>0;
391 List<TempDescriptor> reads=Arrays.asList(fn.readsTemps());
392 List<TempDescriptor> writes=Arrays.asList(fn.readsTemps());
394 HashSet<TempDescriptor> tempset=new HashSet<TempDescriptor>();
395 for(int i=0;i<fn.numNext();i++) {
396 FlatNode fnnext=fn.getNext(i);
397 if (nodetotemps.containsKey(fnnext))
398 tempset.addAll(nodetotemps.get(fnnext));
400 tempset.removeAll(writes);
401 tempset.addAll(reads);
402 if (!nodetotemps.containsKey(fn)||
403 nodetotemps.get(fn).equals(tempset)) {
404 nodetotemps.put(fn, tempset);
405 for(int i=0;i<fn.numPrev(i);i++)
406 toprocess.add(fn.getPrev(i));
412 /* Need to checkpoint all temps that could be read from along any
413 * path that are either:
414 1) Written to by any assignment inside the transaction
415 2) Read from a global temp.
417 Generate tempstosave map from
418 localitybinding->flatatomicenternode->Set<TempDescriptors>
421 private void computeTempstoCheckpoint(LocalityBinding lb) {
422 Hashtable<FlatNode, Integer> atomictab=getAtomic(lb);
423 Hashtable<FlatNode, Hashtable<TempDescriptor, Integer>> temptab=getNodeTempInfo(lb);
424 MethodDescriptor md=lb.getMethod();
425 FlatMethod fm=state.getMethodFlat(md);
427 Hashtable<FlatNode, Set<TempDescriptor>> nodetotemps=computeLiveTemps(md);