1 package Analysis.Locality;
4 import Analysis.CallGraph.CallGraph;
8 import IR.MethodDescriptor;
11 public class LocalityAnalysis {
14 Hashtable<LocalityBinding,LocalityBinding> discovered;
15 Hashtable<LocalityBinding, Set<LocalityBinding>> dependence;
16 Hashtable<LocalityBinding, Hashtable<FlatNode,Hashtable<TempDescriptor, Integer>>> temptab;
17 Hashtable<LocalityBinding, Hashtable<FlatNode, Integer>> atomictab;
18 Hashtable<LocalityBinding, Hashtable<FlatAtomicEnterNode, Set<TempDescriptor>>> tempstosave;
22 public static final Integer LOCAL=new Integer(0);
23 public static final Integer GLOBAL=new Integer(1);
24 public static final Integer EITHER=new Integer(2);
25 public static final Integer CONFLICT=new Integer(3);
27 public LocalityAnalysis(State state, CallGraph callgraph, TypeUtil typeutil) {
28 this.typeutil=typeutil;
30 this.discovered=new Hashtable<LocalityBinding,LocalityBinding>();
31 this.dependence=new Hashtable<LocalityBinding, Set<LocalityBinding>>();
32 this.temptab=new Hashtable<LocalityBinding, Hashtable<FlatNode,Hashtable<TempDescriptor, Integer>>>();
33 this.atomictab=new Hashtable<LocalityBinding, Hashtable<FlatNode, Integer>>();
34 this.lbtovisit=new Stack();
35 this.callgraph=callgraph;
36 this.tempstosave=new Hashtable<LocalityBinding, Hashtable<FlatAtomicEnterNode, Set<TempDescriptor>>>();
41 /** This method returns a set of LocalityBindings. A
42 * LocalityBinding specifies a context a method can be invoked in.
43 * It specifies whether the method is in a transaction and whether
44 * its parameter objects are locals or globals. */
46 public Set<LocalityBinding> getLocalityBindings() {
47 return discovered.keySet();
50 /** This method returns a hashtable for a given LocalityBinding
51 * that tells the current local/global status of temps at the each
52 * node in the flat representation. */
54 public Hashtable<FlatNode, Hashtable<TempDescriptor, Integer>> getNodeTempInfo(LocalityBinding lb) {
55 return temptab.get(lb);
58 /** This method returns an hashtable for a given LocalitBinding
59 * that tells whether a node in the flat represenation is in a
60 * transaction or not. Integer values greater than 0 indicate
61 * that the node is in a transaction and give the nesting depth.
62 * The outermost AtomicEnterNode will have a value of 1 and the
63 * outermost AtomicExitNode will have a value of 0. */
65 public Hashtable<FlatNode, Integer> getAtomic(LocalityBinding lb) {
66 return atomictab.get(lb);
69 /** This methods returns a hashtable for a given LocalityBinding
70 * that tells which temps needs to be saved for each
73 public Hashtable<FlatAtomicEnterNode, Set<TempDescriptor>> getTemps(LocalityBinding lb) {
74 return tempstosave.get(lb);
77 private void doAnalysis() {
78 computeLocalityBindings();
82 private void computeLocalityBindings() {
83 LocalityBinding lbmain=new LocalityBinding(typeutil.getMain(), false);
84 lbmain.setGlobal(0, LOCAL);
85 lbtovisit.add(lbmain);
86 discovered.put(lbmain, lbmain);
88 while(!lbtovisit.empty()) {
89 LocalityBinding lb=(LocalityBinding) lbtovisit.pop();
90 Integer returnglobal=lb.getGlobalReturn();
91 MethodDescriptor md=lb.getMethod();
92 Hashtable<FlatNode,Hashtable<TempDescriptor, Integer>> temptable=new Hashtable<FlatNode,Hashtable<TempDescriptor, Integer>>();
93 Hashtable<FlatNode, Integer> atomictable=new Hashtable<FlatNode, Integer>();
94 computeCallsFlags(md, lb, temptable, atomictable);
95 atomictab.put(lb, atomictable);
96 temptab.put(lb, temptable);
98 if (!md.isStatic()&&!returnglobal.equals(lb.getGlobalReturn())) {
99 //return type is more precise now
100 //rerun everything that call us
101 lbtovisit.addAll(dependence.get(lb));
107 public void computeCallsFlags(MethodDescriptor md, LocalityBinding lb, Hashtable<FlatNode, Hashtable<TempDescriptor, Integer>> temptable, Hashtable<FlatNode, Integer> atomictable) {
108 FlatMethod fm=state.getMethodFlat(md);
109 HashSet<FlatNode> tovisit=new HashSet<FlatNode>();
110 tovisit.add(fm.getNext(0));
112 // Build table for initial node
113 Hashtable<TempDescriptor,Integer> table=new Hashtable<TempDescriptor,Integer>();
114 temptable.put(fm, table);
115 atomictable.put(fm, lb.isAtomic()?1:0);
116 int offset=md.isStatic()?0:1;
117 if (!md.isStatic()) {
118 table.put(fm.getParameter(0), lb.getGlobalThis());
120 for(int i=offset;i<fm.numParameters();i++) {
121 TempDescriptor temp=fm.getParameter(i);
122 Integer b=lb.isGlobal(i-offset);
127 while(!tovisit.isEmpty()) {
128 FlatNode fn=tovisit.iterator().next();
130 Hashtable<TempDescriptor, Integer> currtable=new Hashtable<TempDescriptor, Integer>();
132 for(int i=0;i<fn.numPrev();i++) {
133 FlatNode prevnode=fn.getPrev(i);
134 if (atomictable.containsKey(prevnode)) {
135 atomicstate=atomictable.get(prevnode).intValue();
137 if (!temptable.containsKey(prevnode))
139 Hashtable<TempDescriptor, Integer> prevtable=temptable.get(prevnode);
140 for(Iterator<TempDescriptor> tempit=prevtable.keySet().iterator();tempit.hasNext();) {
141 TempDescriptor temp=tempit.next();
142 Integer tmpint=prevtable.get(temp);
143 Integer oldint=currtable.containsKey(temp)?currtable.get(temp):EITHER;
144 Integer newint=merge(tmpint, oldint);
145 currtable.put(temp, newint);
148 atomictable.put(fn, atomicstate);
151 case FKind.FlatAtomicEnterNode:
152 processAtomicEnterNode((FlatAtomicEnterNode)fn, atomictable);
154 case FKind.FlatAtomicExitNode:
155 processAtomicExitNode((FlatAtomicExitNode)fn, atomictable);
158 processCallNode(lb, (FlatCall)fn, currtable, isAtomic(atomictable, fn));
160 case FKind.FlatFieldNode:
161 processFieldNode(lb, (FlatFieldNode)fn, isAtomic(atomictable, fn), currtable);
163 case FKind.FlatSetFieldNode:
164 processSetFieldNode(lb, (FlatSetFieldNode)fn, isAtomic(atomictable,fn), currtable);
167 processNew(lb, (FlatNew)fn, isAtomic(atomictable, fn), currtable);
169 case FKind.FlatOpNode:
170 processOpNode((FlatOpNode)fn, currtable);
172 case FKind.FlatCastNode:
173 processCastNode((FlatCastNode)fn, currtable);
175 case FKind.FlatLiteralNode:
176 processLiteralNode((FlatLiteralNode)fn, currtable);
178 case FKind.FlatReturnNode:
179 processReturnNode(lb, (FlatReturnNode)fn, currtable);
181 case FKind.FlatSetElementNode:
182 processSetElementNode(lb, (FlatSetElementNode)fn, currtable, isAtomic(atomictable, fn));
184 case FKind.FlatElementNode:
185 processElementNode(lb, (FlatElementNode)fn, currtable, isAtomic(atomictable, fn));
187 case FKind.FlatCondBranch:
188 case FKind.FlatBackEdge:
190 //No action needed for these
192 case FKind.FlatFlagActionNode:
193 case FKind.FlatCheckNode:
194 case FKind.FlatTagDeclaration:
195 throw new Error("Incompatible with tasks!");
196 case FKind.FlatMethod:
200 Hashtable<TempDescriptor,Integer> oldtable=temptable.get(fn);
201 if (oldtable==null||!oldtable.equals(currtable)) {
202 // Update table for this node
203 temptable.put(fn, currtable);
204 for(int i=0;i<fn.numNext();i++) {
205 tovisit.add(fn.getNext(i));
211 private static boolean isAtomic(Hashtable<FlatNode, Integer> atomictable, FlatNode fn) {
212 return atomictable.get(fn).intValue()>0;
215 private static Integer merge(Integer a, Integer b) {
216 if (a==null||a.equals(EITHER))
218 if (b==null||b.equals(EITHER))
225 void processCallNode(LocalityBinding currlb, FlatCall fc, Hashtable<TempDescriptor, Integer> currtable, boolean isatomic) {
226 MethodDescriptor nodemd=fc.getMethod();
227 Set methodset=fc.getThis()==null?callgraph.getMethods(nodemd):
228 callgraph.getMethods(nodemd, fc.getThis().getType());
229 Integer currreturnval=EITHER; //Start off with the either value
230 for(Iterator methodit=methodset.iterator();methodit.hasNext();) {
231 MethodDescriptor md=(MethodDescriptor) methodit.next();
232 LocalityBinding lb=new LocalityBinding(md, isatomic);
233 for(int i=0;i<fc.numArgs();i++) {
234 TempDescriptor arg=fc.getArg(i);
235 lb.setGlobal(i,currtable.get(arg));
237 if (fc.getThis()!=null) {
238 Integer thistype=currtable.get(fc.getThis());
241 if(thistype.equals(CONFLICT))
242 throw new Error("Using type that can be either local or global in context:\n"+currlb.getExplanation());
243 if(thistype.equals(GLOBAL)&&!isatomic)
244 throw new Error("Using global object outside of transaction in context:\n"+currlb.getExplanation());
245 lb.setGlobalThis(thistype);
247 lb.setGlobalThis(EITHER);//default value
249 if (!discovered.containsKey(lb)) {
250 lb.setGlobalReturn(EITHER);
251 lb.setParent(currlb);
253 discovered.put(lb, lb);
255 lb=discovered.get(lb);
256 Integer returnval=lb.getGlobalReturn();
257 currreturnval=merge(returnval, currreturnval);
258 if (!dependence.containsKey(lb))
259 dependence.put(lb, new HashSet<LocalityBinding>());
260 dependence.get(lb).add(currlb);
262 if (fc.getReturnTemp()!=null) {
263 currtable.put(fc.getReturnTemp(), currreturnval);
267 void processFieldNode(LocalityBinding lb, FlatFieldNode ffn, boolean transaction, Hashtable<TempDescriptor, Integer> currtable) {
268 Integer type=currtable.get(ffn.getSrc());
269 TempDescriptor dst=ffn.getDst();
270 if (type.equals(LOCAL)) {
271 if (ffn.getField().isGlobal())
272 currtable.put(dst,GLOBAL);
274 currtable.put(dst,LOCAL);
275 } else if (type.equals(GLOBAL)) {
277 throw new Error("Global access outside of a transaction in context:\n"+lb.getExplanation());
278 if (ffn.getField().getType().isPrimitive())
279 currtable.put(dst, LOCAL); // primitives are local
281 currtable.put(dst, GLOBAL);
282 } else if (type.equals(EITHER)) {
283 if (ffn.getField().getType().isPrimitive())
284 currtable.put(dst, LOCAL); // primitives are local
286 currtable.put(dst, EITHER);
287 } else if (type.equals(CONFLICT)) {
288 throw new Error("Access to object that could be either global or local in context:\n"+lb.getExplanation());
292 //need to handle primitives
293 void processSetFieldNode(LocalityBinding lb, FlatSetFieldNode fsfn, boolean transaction, Hashtable<TempDescriptor, Integer> currtable) {
294 Integer srctype=currtable.get(fsfn.getSrc());
295 Integer dsttype=currtable.get(fsfn.getDst());
297 if (dsttype.equals(LOCAL)) {
298 if (fsfn.getField().isGlobal()) {
299 if (!(srctype.equals(GLOBAL)||srctype.equals(EITHER)))
300 throw new Error("Writing possible local reference to global field in context: \n"+lb.getExplanation());
302 if (!(srctype.equals(LOCAL)||srctype.equals(EITHER)))
303 throw new Error("Writing possible global reference to local object in context: \n"+lb.getExplanation());
305 } else if (dsttype.equals(GLOBAL)) {
307 throw new Error("Global access outside of a transaction in context:\n"+lb.getExplanation());
308 //okay to store primitives in global object
309 if (srctype.equals(LOCAL) && fsfn.getField().getType().isPrimitive())
311 if (!(srctype.equals(GLOBAL)||srctype.equals(EITHER)))
312 throw new Error("Writing possible local reference to global object in context:\n"+lb.getExplanation());
313 } else if (dsttype.equals(EITHER)) {
314 if (srctype.equals(CONFLICT))
315 throw new Error("Using reference that could be local or global in context:\n"+lb.getExplanation());
316 } else if (dsttype.equals(CONFLICT)) {
317 throw new Error("Access to object that could be either global or local in context:\n"+lb.getExplanation());
321 void processNew(LocalityBinding lb, FlatNew fn, boolean transaction, Hashtable<TempDescriptor, Integer> currtable) {
322 if (fn.isGlobal()&&!transaction) {
323 throw new Error("Allocating global object outside of transaction in context:"+lb.getExplanation());
326 currtable.put(fn.getDst(), GLOBAL);
328 currtable.put(fn.getDst(), LOCAL);
331 void processOpNode(FlatOpNode fon, Hashtable<TempDescriptor, Integer> currtable) {
332 /* Just propagate value */
333 currtable.put(fon.getDest(), currtable.get(fon.getLeft()));
336 void processCastNode(FlatCastNode fcn, Hashtable<TempDescriptor, Integer> currtable) {
337 currtable.put(fcn.getDst(), currtable.get(fcn.getSrc()));
340 void processLiteralNode(FlatLiteralNode fln, Hashtable<TempDescriptor, Integer> currtable) {
342 if (fln.getValue()==null)
343 currtable.put(fln.getDst(), EITHER);
345 currtable.put(fln.getDst(), LOCAL);
348 void processReturnNode(LocalityBinding lb, FlatReturnNode frn, Hashtable<TempDescriptor, Integer> currtable) {
349 if(frn.getReturnTemp()!=null) {
350 Integer returntype=currtable.get(frn.getReturnTemp());
351 lb.setGlobalReturn(merge(returntype, lb.getGlobalReturn()));
355 void processSetElementNode(LocalityBinding lb, FlatSetElementNode fsen, Hashtable<TempDescriptor, Integer> currtable, boolean isatomic) {
356 Integer srctype=currtable.get(fsen.getSrc());
357 Integer dsttype=currtable.get(fsen.getDst());
359 if (dsttype.equals(LOCAL)) {
360 if (!(srctype.equals(LOCAL)||srctype.equals(EITHER)))
361 throw new Error("Writing possible global reference to local object in context:\n"+lb.getExplanation());
362 } else if (dsttype.equals(GLOBAL)) {
363 if (!(srctype.equals(GLOBAL)||srctype.equals(EITHER)))
364 throw new Error("Writing possible local reference to global object in context:\n"+lb.getExplanation());
366 throw new Error("Global access outside of a transaction in context:\n"+lb.getExplanation());
367 } else if (dsttype.equals(EITHER)) {
368 if (srctype.equals(CONFLICT))
369 throw new Error("Using reference that could be local or global in context:\n"+lb.getExplanation());
370 } else if (dsttype.equals(CONFLICT)) {
371 throw new Error("Access to object that could be either global or local in context:\n"+lb.getExplanation());
375 void processElementNode(LocalityBinding lb, FlatElementNode fen, Hashtable<TempDescriptor, Integer> currtable, boolean isatomic) {
376 Integer type=currtable.get(fen.getSrc());
377 TempDescriptor dst=fen.getDst();
378 if (type.equals(LOCAL)) {
379 currtable.put(dst,LOCAL);
380 } else if (type.equals(GLOBAL)) {
382 throw new Error("Global access outside of a transaction in context:\n"+lb.getExplanation());
383 currtable.put(dst, GLOBAL);
384 } else if (type.equals(EITHER)) {
385 currtable.put(dst, EITHER);
386 } else if (type.equals(CONFLICT)) {
387 throw new Error("Access to object that could be either global or local in context:\n"+lb.getExplanation());
391 void processAtomicEnterNode(FlatAtomicEnterNode fen, Hashtable<FlatNode, Integer> atomictable) {
392 int atomic=atomictable.get(fen).intValue();
393 atomictable.put(fen, new Integer(atomic+1));
396 void processAtomicExitNode(FlatAtomicExitNode fen, Hashtable<FlatNode, Integer> atomictable) {
397 int atomic=atomictable.get(fen).intValue();
398 atomictable.put(fen, new Integer(atomic-1));
401 private Hashtable<FlatNode, Set<TempDescriptor>> computeLiveTemps(FlatMethod fm) {
402 Hashtable<FlatNode, Set<TempDescriptor>> nodetotemps=new Hashtable<FlatNode, Set<TempDescriptor>>();
404 Set<FlatNode> toprocess=fm.getNodeSet();
406 while(!toprocess.isEmpty()) {
407 FlatNode fn=toprocess.iterator().next();
408 toprocess.remove(fn);
410 List<TempDescriptor> reads=Arrays.asList(fn.readsTemps());
411 List<TempDescriptor> writes=Arrays.asList(fn.readsTemps());
413 HashSet<TempDescriptor> tempset=new HashSet<TempDescriptor>();
414 for(int i=0;i<fn.numNext();i++) {
415 FlatNode fnnext=fn.getNext(i);
416 if (nodetotemps.containsKey(fnnext))
417 tempset.addAll(nodetotemps.get(fnnext));
419 tempset.removeAll(writes);
420 tempset.addAll(reads);
421 if (!nodetotemps.containsKey(fn)||
422 nodetotemps.get(fn).equals(tempset)) {
423 nodetotemps.put(fn, tempset);
424 for(int i=0;i<fn.numPrev();i++)
425 toprocess.add(fn.getPrev(i));
431 private void computeTempstoSave() {
432 for(Iterator<LocalityBinding> lbit=getLocalityBindings().iterator();lbit.hasNext();) {
433 LocalityBinding lb=lbit.next();
434 computeTempstoSave(lb);
438 /* Need to checkpoint all temps that could be read from along any
439 * path that are either:
440 1) Written to by any assignment inside the transaction
441 2) Read from a global temp.
443 Generate tempstosave map from
444 localitybinding->flatatomicenternode->Set<TempDescriptors>
447 private void computeTempstoSave(LocalityBinding lb) {
450 Hashtable<FlatNode, Integer> atomictab=getAtomic(lb);
451 Hashtable<FlatNode, Hashtable<TempDescriptor, Integer>> temptab=getNodeTempInfo(lb);
452 MethodDescriptor md=lb.getMethod();
453 FlatMethod fm=state.getMethodFlat(md);
455 Hashtable<FlatNode, Set<TempDescriptor>> nodetotemps=computeLiveTemps(fm);
456 Hashtable<FlatAtomicEnterNode, Set<TempDescriptor>> nodetosavetemps=new Hashtable<FlatAtomicEnterNode, Set<TempDescriptor>>();
457 tempstosave.put(lb, nodetosavetemps);
459 Hashtable<FlatNode, FlatAtomicEnterNode> nodemap=new Hashtable<FlatNode, FlatAtomicEnterNode>();
461 HashSet<FlatNode> toprocess=new HashSet<FlatNode>();
462 HashSet<FlatNode> discovered=new HashSet<FlatNode>();
465 while(!toprocess.isEmpty()) {
466 FlatNode fn=toprocess.iterator().next();
467 toprocess.remove(fn);
468 boolean isatomic=atomictab.get(fn).intValue()>0;
470 atomictab.get(fn.getPrev(0)).intValue()==0) {
471 assert(fn.getPrev(0).kind()==FKind.FlatAtomicEnterNode);
472 nodemap.put(fn, (FlatAtomicEnterNode)fn);
473 nodetosavetemps.put((FlatAtomicEnterNode)fn, new HashSet<TempDescriptor>());
474 } else if (isatomic) {
475 FlatAtomicEnterNode atomicnode=nodemap.get(fn);
476 Set<TempDescriptor> livetemps=nodetotemps.get(fn);
477 List<TempDescriptor> reads=Arrays.asList(fn.readsTemps());
478 List<TempDescriptor> writes=Arrays.asList(fn.readsTemps());
480 for(Iterator<TempDescriptor> tempit=livetemps.iterator();tempit.hasNext();) {
481 TempDescriptor tmp=tempit.next();
482 if (writes.contains(tmp)) {
483 nodetosavetemps.get(fn).add(tmp);
484 } else if (reads.contains(tmp)&&temptab.get(fn).get(tmp)==GLOBAL) {
485 nodetosavetemps.get(fn).add(tmp);
489 for(int i=0;i<fn.numNext();i++) {
490 FlatNode fnnext=fn.getNext(i);
491 if (!discovered.contains(fnnext)) {
492 discovered.add(fnnext);
493 toprocess.add(fnnext);
495 nodemap.put(fnnext, nodemap.get(fn));