1 package Analysis.Locality;
4 import Analysis.CallGraph.CallGraph;
8 import IR.MethodDescriptor;
10 import IR.ClassDescriptor;
12 public class LocalityAnalysis {
15 Hashtable<LocalityBinding,LocalityBinding> discovered;
16 Hashtable<LocalityBinding, Set<LocalityBinding>> dependence;
17 Hashtable<LocalityBinding, Set<LocalityBinding>> calldep;
18 Hashtable<LocalityBinding, Hashtable<FlatNode,Hashtable<TempDescriptor, Integer>>> temptab;
19 Hashtable<LocalityBinding, Hashtable<FlatNode, Integer>> atomictab;
20 Hashtable<LocalityBinding, Hashtable<FlatAtomicEnterNode, Set<TempDescriptor>>> tempstosave;
21 Hashtable<ClassDescriptor, Set<LocalityBinding>> classtolb;
22 Hashtable<MethodDescriptor, Set<LocalityBinding>> methodtolb;
23 private LocalityBinding lbmain;
24 private LocalityBinding lbrun;
28 public static final Integer LOCAL=new Integer(0);
29 public static final Integer GLOBAL=new Integer(1);
30 public static final Integer EITHER=new Integer(2);
31 public static final Integer CONFLICT=new Integer(3);
33 public LocalityAnalysis(State state, CallGraph callgraph, TypeUtil typeutil) {
34 this.typeutil=typeutil;
36 this.discovered=new Hashtable<LocalityBinding,LocalityBinding>();
37 this.dependence=new Hashtable<LocalityBinding, Set<LocalityBinding>>();
38 this.calldep=new Hashtable<LocalityBinding, Set<LocalityBinding>>();
39 this.temptab=new Hashtable<LocalityBinding, Hashtable<FlatNode,Hashtable<TempDescriptor, Integer>>>();
40 this.atomictab=new Hashtable<LocalityBinding, Hashtable<FlatNode, Integer>>();
41 this.lbtovisit=new Stack();
42 this.callgraph=callgraph;
43 this.tempstosave=new Hashtable<LocalityBinding, Hashtable<FlatAtomicEnterNode, Set<TempDescriptor>>>();
44 this.classtolb=new Hashtable<ClassDescriptor, Set<LocalityBinding>>();
45 this.methodtolb=new Hashtable<MethodDescriptor, Set<LocalityBinding>>();
49 public LocalityBinding getMain() {
53 /** This method returns the set of LocalityBindings that a given
54 * flatcall could invoke */
56 public LocalityBinding getBinding(LocalityBinding currlb, FlatCall fc) {
57 boolean isatomic=getAtomic(currlb).get(fc).intValue()>0;
58 Hashtable<TempDescriptor, Integer> currtable=getNodePreTempInfo(currlb,fc);
59 MethodDescriptor md=fc.getMethod();
61 boolean isnative=md.getModifiers().isNative();
63 LocalityBinding lb=new LocalityBinding(md, isatomic);
65 for(int i=0; i<fc.numArgs(); i++) {
66 TempDescriptor arg=fc.getArg(i);
67 lb.setGlobal(i,currtable.get(arg));
69 if (fc.getThis()!=null) {
70 Integer thistype=currtable.get(fc.getThis());
73 lb.setGlobalThis(thistype);
75 // lb.setGlobalThis(EITHER);//default value
76 if (discovered.containsKey(lb))
77 lb=discovered.get(lb);
78 else throw new Error();
83 /** This method returns a set of LocalityBindings for the parameter class. */
84 public Set<LocalityBinding> getClassBindings(ClassDescriptor cd) {
85 return classtolb.get(cd);
88 /** This method returns a set of LocalityBindings for the parameter method. */
90 public Set<LocalityBinding> getMethodBindings(MethodDescriptor md) {
91 return methodtolb.get(md);
94 public Set<MethodDescriptor> getMethods() {
95 return methodtolb.keySet();
98 /** This method returns a set of LocalityBindings. A
99 * LocalityBinding specifies a context a method can be invoked in.
100 * It specifies whether the method is in a transaction and whether
101 * its parameter objects are locals or globals. */
103 public Set<LocalityBinding> getLocalityBindings() {
104 return discovered.keySet();
107 /** This method returns a hashtable for a given LocalityBinding
108 * that tells the current local/global status of temps at the each
109 * node in the flat representation. */
111 public Hashtable<FlatNode, Hashtable<TempDescriptor, Integer>> getNodeTempInfo(LocalityBinding lb) {
112 return temptab.get(lb);
115 /** This method returns a hashtable for a given LocalityBinding
116 * that tells the current local/global status of temps at the
117 * beginning of each node in the flat representation. */
119 public Hashtable<TempDescriptor, Integer> getNodePreTempInfo(LocalityBinding lb, FlatNode fn) {
120 Hashtable<TempDescriptor, Integer> currtable=new Hashtable<TempDescriptor, Integer>();
121 Hashtable<FlatNode, Hashtable<TempDescriptor, Integer>> temptable=getNodeTempInfo(lb);
123 for(int i=0; i<fn.numPrev(); i++) {
124 FlatNode prevnode=fn.getPrev(i);
125 Hashtable<TempDescriptor, Integer> prevtable=temptable.get(prevnode);
126 for(Iterator<TempDescriptor> tempit=prevtable.keySet().iterator(); tempit.hasNext();) {
127 TempDescriptor temp=tempit.next();
128 Integer tmpint=prevtable.get(temp);
129 Integer oldint=currtable.containsKey(temp) ? currtable.get(temp) : EITHER;
130 Integer newint=merge(tmpint, oldint);
131 currtable.put(temp, newint);
137 /** This method returns an hashtable for a given LocalitBinding
138 * that tells whether a node in the flat represenation is in a
139 * transaction or not. Integer values greater than 0 indicate
140 * that the node is in a transaction and give the nesting depth.
141 * The outermost AtomicEnterNode will have a value of 1 and the
142 * outermost AtomicExitNode will have a value of 0. */
144 public Hashtable<FlatNode, Integer> getAtomic(LocalityBinding lb) {
145 return atomictab.get(lb);
148 /** This methods returns a hashtable for a given LocalityBinding
149 * that tells which temps needs to be saved for each
150 * AtomicEnterNode. */
152 public Hashtable<FlatAtomicEnterNode, Set<TempDescriptor>> getTemps(LocalityBinding lb) {
153 return tempstosave.get(lb);
156 public Set<TempDescriptor> getTempSet(LocalityBinding lb) {
157 HashSet<TempDescriptor> set=new HashSet<TempDescriptor>();
158 Hashtable<FlatAtomicEnterNode, Set<TempDescriptor>> table=getTemps(lb);
160 for(Iterator<FlatAtomicEnterNode> faenit=table.keySet().iterator(); faenit.hasNext();) {
161 FlatAtomicEnterNode faen=faenit.next();
162 set.addAll(table.get(faen));
167 private void doAnalysis() {
168 computeLocalityBindings();
169 computeTempstoSave();
173 private void cleanSets() {
174 HashSet<LocalityBinding> lbset=new HashSet<LocalityBinding>();
175 Stack<LocalityBinding> lbstack=new Stack<LocalityBinding>();
180 while(!lbstack.isEmpty()) {
181 LocalityBinding lb=lbstack.pop();
182 if (calldep.containsKey(lb)) {
183 Set<LocalityBinding> set=new HashSet<LocalityBinding>();
184 set.addAll(calldep.get(lb));
185 set.removeAll(lbset);
190 for(Iterator<LocalityBinding> lbit=discovered.keySet().iterator(); lbit.hasNext();) {
191 LocalityBinding lb=lbit.next();
192 if (!lbset.contains(lb)) {
194 classtolb.get(lb.getMethod().getClassDesc()).remove(lb);
195 methodtolb.get(lb.getMethod()).remove(lb);
200 private void computeLocalityBindings() {
201 lbmain=new LocalityBinding(typeutil.getMain(), false);
202 lbmain.setGlobalReturn(EITHER);
203 lbmain.setGlobal(0, LOCAL);
204 lbtovisit.add(lbmain);
205 discovered.put(lbmain, lbmain);
206 if (!classtolb.containsKey(lbmain.getMethod().getClassDesc()))
207 classtolb.put(lbmain.getMethod().getClassDesc(), new HashSet<LocalityBinding>());
208 classtolb.get(lbmain.getMethod().getClassDesc()).add(lbmain);
210 if (!methodtolb.containsKey(lbmain.getMethod()))
211 methodtolb.put(lbmain.getMethod(), new HashSet<LocalityBinding>());
212 methodtolb.get(lbmain.getMethod()).add(lbmain);
214 //Do this to force a virtual table number for the run method
215 lbrun=new LocalityBinding(typeutil.getRun(), false);
216 lbrun.setGlobalReturn(EITHER);
217 lbrun.setGlobalThis(GLOBAL);
218 lbtovisit.add(lbrun);
219 discovered.put(lbrun, lbrun);
220 if (!classtolb.containsKey(lbrun.getMethod().getClassDesc()))
221 classtolb.put(lbrun.getMethod().getClassDesc(), new HashSet<LocalityBinding>());
222 classtolb.get(lbrun.getMethod().getClassDesc()).add(lbrun);
224 if (!methodtolb.containsKey(lbrun.getMethod()))
225 methodtolb.put(lbrun.getMethod(), new HashSet<LocalityBinding>());
226 methodtolb.get(lbrun.getMethod()).add(lbrun);
228 while(!lbtovisit.empty()) {
229 LocalityBinding lb=(LocalityBinding) lbtovisit.pop();
230 Integer returnglobal=lb.getGlobalReturn();
231 MethodDescriptor md=lb.getMethod();
232 Hashtable<FlatNode,Hashtable<TempDescriptor, Integer>> temptable=new Hashtable<FlatNode,Hashtable<TempDescriptor, Integer>>();
233 Hashtable<FlatNode, Integer> atomictable=new Hashtable<FlatNode, Integer>();
236 computeCallsFlags(md, lb, temptable, atomictable);
238 System.out.println("Error in "+md+" context "+lb);
242 atomictab.put(lb, atomictable);
243 temptab.put(lb, temptable);
245 if (md.getReturnType()!=null&&!returnglobal.equals(lb.getGlobalReturn())) {
246 //return type is more precise now
247 //rerun everything that call us
248 lbtovisit.addAll(dependence.get(lb));
253 public void computeCallsFlags(MethodDescriptor md, LocalityBinding lb, Hashtable<FlatNode, Hashtable<TempDescriptor, Integer>> temptable, Hashtable<FlatNode, Integer> atomictable) {
254 FlatMethod fm=state.getMethodFlat(md);
255 HashSet<FlatNode> tovisit=new HashSet<FlatNode>();
256 tovisit.add(fm.getNext(0));
258 // Build table for initial node
259 Hashtable<TempDescriptor,Integer> table=new Hashtable<TempDescriptor,Integer>();
260 temptable.put(fm, table);
261 atomictable.put(fm, lb.isAtomic() ? 1 : 0);
262 int offset=md.isStatic() ? 0 : 1;
263 if (!md.isStatic()) {
264 table.put(fm.getParameter(0), lb.getGlobalThis());
266 for(int i=offset; i<fm.numParameters(); i++) {
267 TempDescriptor temp=fm.getParameter(i);
268 Integer b=lb.isGlobal(i-offset);
273 while(!tovisit.isEmpty()) {
274 FlatNode fn=tovisit.iterator().next();
276 Hashtable<TempDescriptor, Integer> currtable=new Hashtable<TempDescriptor, Integer>();
278 for(int i=0; i<fn.numPrev(); i++) {
279 FlatNode prevnode=fn.getPrev(i);
280 if (atomictable.containsKey(prevnode)) {
281 atomicstate=atomictable.get(prevnode).intValue();
283 if (!temptable.containsKey(prevnode))
285 Hashtable<TempDescriptor, Integer> prevtable=temptable.get(prevnode);
286 for(Iterator<TempDescriptor> tempit=prevtable.keySet().iterator(); tempit.hasNext();) {
287 TempDescriptor temp=tempit.next();
288 Integer tmpint=prevtable.get(temp);
289 Integer oldint=currtable.containsKey(temp) ? currtable.get(temp) : EITHER;
290 Integer newint=merge(tmpint, oldint);
291 currtable.put(temp, newint);
294 atomictable.put(fn, atomicstate);
297 case FKind.FlatAtomicEnterNode:
298 processAtomicEnterNode((FlatAtomicEnterNode)fn, atomictable);
303 case FKind.FlatAtomicExitNode:
304 processAtomicExitNode((FlatAtomicExitNode)fn, atomictable);
308 processCallNode(lb, (FlatCall)fn, currtable, isAtomic(atomictable, fn));
311 case FKind.FlatFieldNode:
312 processFieldNode(lb, (FlatFieldNode)fn, isAtomic(atomictable, fn), currtable);
315 case FKind.FlatSetFieldNode:
316 processSetFieldNode(lb, (FlatSetFieldNode)fn, isAtomic(atomictable,fn), currtable);
320 processNew(lb, (FlatNew)fn, isAtomic(atomictable, fn), currtable);
323 case FKind.FlatOpNode:
324 processOpNode((FlatOpNode)fn, currtable);
327 case FKind.FlatCastNode:
328 processCastNode((FlatCastNode)fn, currtable);
331 case FKind.FlatLiteralNode:
332 processLiteralNode((FlatLiteralNode)fn, currtable);
335 case FKind.FlatReturnNode:
336 processReturnNode(lb, (FlatReturnNode)fn, currtable);
339 case FKind.FlatSetElementNode:
340 processSetElementNode(lb, (FlatSetElementNode)fn, currtable, isAtomic(atomictable, fn));
343 case FKind.FlatElementNode:
344 processElementNode(lb, (FlatElementNode)fn, currtable, isAtomic(atomictable, fn));
347 case FKind.FlatCondBranch:
348 case FKind.FlatBackEdge:
350 case FKind.FlatPrefetchNode:
351 //No action needed for these
354 case FKind.FlatFlagActionNode:
355 case FKind.FlatCheckNode:
356 case FKind.FlatTagDeclaration:
357 throw new Error("Incompatible with tasks!");
359 case FKind.FlatMethod:
361 case FKind.FlatInstanceOfNode:
363 case FKind.FlatOffsetNode:
364 processOffsetNode((FlatOffsetNode)fn, currtable);
368 throw new Error("In finding fn.kind()= " + fn.kind());
370 Hashtable<TempDescriptor,Integer> oldtable=temptable.get(fn);
371 if (oldtable==null||!oldtable.equals(currtable)) {
372 // Update table for this node
373 temptable.put(fn, currtable);
374 for(int i=0; i<fn.numNext(); i++) {
375 tovisit.add(fn.getNext(i));
381 private static boolean isAtomic(Hashtable<FlatNode, Integer> atomictable, FlatNode fn) {
382 return atomictable.get(fn).intValue()>0;
385 private static Integer merge(Integer a, Integer b) {
386 if (a==null||a.equals(EITHER))
388 if (b==null||b.equals(EITHER))
395 void processCallNode(LocalityBinding currlb, FlatCall fc, Hashtable<TempDescriptor, Integer> currtable, boolean isatomic) {
396 MethodDescriptor nodemd=fc.getMethod();
398 Set runmethodset=null;
400 if (nodemd.isStatic()||nodemd.getReturnType()==null) {
401 methodset=new HashSet();
402 methodset.add(nodemd);
404 methodset=callgraph.getMethods(nodemd, fc.getThis().getType());
405 // Build start -> run link
406 if (nodemd.getClassDesc().getSymbol().equals(TypeUtil.ThreadClass)&&
407 nodemd.getSymbol().equals("start")&&!nodemd.getModifiers().isStatic()&&
408 nodemd.numParameters()==1&&nodemd.getParamType(0).isInt()) {
409 assert(nodemd.getModifiers().isNative());
411 MethodDescriptor runmd=null;
412 for(Iterator methodit=nodemd.getClassDesc().getMethodTable().getSet("run").iterator(); methodit.hasNext();) {
413 MethodDescriptor md=(MethodDescriptor) methodit.next();
414 if (md.numParameters()!=0||md.getModifiers().isStatic())
420 runmethodset=callgraph.getMethods(runmd,fc.getThis().getType());
421 methodset.addAll(runmethodset);
422 } else throw new Error("Can't find run method");
426 Integer currreturnval=EITHER; //Start off with the either value
427 for(Iterator methodit=methodset.iterator(); methodit.hasNext();) {
428 MethodDescriptor md=(MethodDescriptor) methodit.next();
430 boolean isnative=md.getModifiers().isNative();
431 boolean isjoin = md.getClassDesc().getSymbol().equals(TypeUtil.ThreadClass)&&!nodemd.getModifiers().isStatic()&&nodemd.numParameters()==0&&md.getSymbol().equals("join");
432 boolean isObjectgetType = md.getClassDesc().getSymbol().equals("Object") && md.getSymbol().equals("getType");
433 boolean isObjecthashCode = md.getClassDesc().getSymbol().equals("Object") && md.getSymbol().equals("nativehashCode");
435 LocalityBinding lb=new LocalityBinding(md, isatomic);
436 if (isnative&&isatomic) {
437 System.out.println("Don't call native methods in atomic blocks!"+currlb.getMethod());
439 if (runmethodset==null||!runmethodset.contains(md)) {
440 //Skip this part if it is a run method
441 for(int i=0; i<fc.numArgs(); i++) {
442 TempDescriptor arg=fc.getArg(i);
443 if(isnative&&(currtable.get(arg).equals(GLOBAL)||
444 currtable.get(arg).equals(CONFLICT))&& !(nodemd.getSymbol().equals("rangePrefetch"))) {
445 throw new Error("Potential call to native method "+md+" with global parameter:\n"+currlb.getExplanation());
447 lb.setGlobal(i,currtable.get(arg));
451 if (fc.getThis()!=null) {
452 Integer thistype=currtable.get(fc.getThis());
456 if(runmethodset!=null&&runmethodset.contains(md)&&thistype.equals(LOCAL))
457 throw new Error("Starting thread on local object not allowed in context:\n"+currlb.getExplanation());
458 if(isjoin&&thistype.equals(LOCAL))
459 throw new Error("Joining thread on local object not allowed in context:\n"+currlb.getExplanation());
460 if(thistype.equals(CONFLICT))
461 throw new Error("Using type that can be either local or global in context:\n"+currlb.getExplanation());
462 if(runmethodset==null&&thistype.equals(GLOBAL)&&!isatomic && !isjoin)
463 throw new Error("Using global object outside of transaction in context:\n"+currlb.getExplanation());
464 if (runmethodset==null&&isnative&&thistype.equals(GLOBAL) && !isjoin && !isObjectgetType && !isObjecthashCode)
465 throw new Error("Potential call to native method "+md+" on global objects:\n"+currlb.getExplanation());
466 lb.setGlobalThis(thistype);
469 if (!discovered.containsKey(lb)) {
471 lb.setGlobalReturn(LOCAL);
473 lb.setGlobalReturn(EITHER);
474 lb.setParent(currlb);
476 discovered.put(lb, lb);
477 if (!classtolb.containsKey(lb.getMethod().getClassDesc()))
478 classtolb.put(lb.getMethod().getClassDesc(), new HashSet<LocalityBinding>());
479 classtolb.get(lb.getMethod().getClassDesc()).add(lb);
480 if (!methodtolb.containsKey(lb.getMethod()))
481 methodtolb.put(lb.getMethod(), new HashSet<LocalityBinding>());
482 methodtolb.get(lb.getMethod()).add(lb);
484 lb=discovered.get(lb);
485 Integer returnval=lb.getGlobalReturn();
486 currreturnval=merge(returnval, currreturnval);
487 if (!dependence.containsKey(lb))
488 dependence.put(lb, new HashSet<LocalityBinding>());
489 dependence.get(lb).add(currlb);
491 if (!calldep.containsKey(currlb))
492 calldep.put(currlb, new HashSet<LocalityBinding>());
493 calldep.get(currlb).add(lb);
495 if (fc.getReturnTemp()!=null) {
496 currtable.put(fc.getReturnTemp(), currreturnval);
500 void processFieldNode(LocalityBinding lb, FlatFieldNode ffn, boolean transaction, Hashtable<TempDescriptor, Integer> currtable) {
501 Integer type=currtable.get(ffn.getSrc());
502 TempDescriptor dst=ffn.getDst();
503 if (type.equals(LOCAL)) {
504 if (ffn.getField().isGlobal())
505 currtable.put(dst,GLOBAL);
507 currtable.put(dst,LOCAL);
508 } else if (type.equals(GLOBAL)) {
510 throw new Error("Global access outside of a transaction in context:\n"+lb.getExplanation());
511 if (ffn.getField().getType().isPrimitive()&&!ffn.getField().getType().isArray())
512 currtable.put(dst, LOCAL); // primitives are local
514 currtable.put(dst, GLOBAL);
515 } else if (type.equals(EITHER)) {
516 if (ffn.getField().getType().isPrimitive()&&!ffn.getField().getType().isArray())
517 currtable.put(dst, LOCAL); // primitives are local
518 else if (ffn.getField().isGlobal())
519 currtable.put(dst, GLOBAL);
521 currtable.put(dst, EITHER);
522 } else if (type.equals(CONFLICT)) {
523 throw new Error("Access to object that could be either global or local in context:\n"+lb.getExplanation());
527 //need to handle primitives
528 void processSetFieldNode(LocalityBinding lb, FlatSetFieldNode fsfn, boolean transaction, Hashtable<TempDescriptor, Integer> currtable) {
529 Integer srctype=currtable.get(fsfn.getSrc());
530 Integer dsttype=currtable.get(fsfn.getDst());
532 if (dsttype.equals(LOCAL)) {
533 if (fsfn.getField().isGlobal()) {
534 if (!(srctype.equals(GLOBAL)||srctype.equals(EITHER)))
535 throw new Error("Writing possible local reference to global field in context: \n"+lb.getExplanation());
537 if (!(srctype.equals(LOCAL)||srctype.equals(EITHER)))
538 throw new Error("Writing possible global reference to local object in context: \n"+lb.getExplanation());
540 } else if (dsttype.equals(GLOBAL)) {
542 throw new Error("Global access outside of a transaction in context:\n"+lb.getExplanation());
543 //okay to store primitives in global object
544 if (srctype.equals(LOCAL) && fsfn.getField().getType().isPrimitive() && !fsfn.getField().getType().isArray())
546 if (!(srctype.equals(GLOBAL)||srctype.equals(EITHER)))
547 throw new Error("Writing possible local reference to global object in context:\n"+lb.getExplanation()+" for FlatFieldNode "+fsfn);
548 } else if (dsttype.equals(EITHER)) {
549 if (srctype.equals(CONFLICT))
550 throw new Error("Using reference that could be local or global in context:\n"+lb.getExplanation());
551 } else if (dsttype.equals(CONFLICT)) {
552 throw new Error("Access to object that could be either global or local in context:\n"+lb.getExplanation());
556 void processNew(LocalityBinding lb, FlatNew fn, boolean transaction, Hashtable<TempDescriptor, Integer> currtable) {
557 if (fn.isGlobal()&&!transaction) {
558 throw new Error("Allocating global object outside of transaction in context:"+lb.getExplanation());
561 currtable.put(fn.getDst(), GLOBAL);
563 currtable.put(fn.getDst(), LOCAL);
566 void processOpNode(FlatOpNode fon, Hashtable<TempDescriptor, Integer> currtable) {
567 /* Just propagate value */
568 Integer srcvalue=currtable.get(fon.getLeft());
570 if (srcvalue==null) {
571 if (!fon.getLeft().getType().isPtr()) {
574 throw new Error(fon.getLeft()+" is undefined!");
576 currtable.put(fon.getDest(), srcvalue);
579 void processOffsetNode(FlatOffsetNode fon, Hashtable<TempDescriptor, Integer> currtable) {
580 /* Just propagate value */
581 currtable.put(fon.getDst(), LOCAL);
584 void processCastNode(FlatCastNode fcn, Hashtable<TempDescriptor, Integer> currtable) {
585 currtable.put(fcn.getDst(), currtable.get(fcn.getSrc()));
588 void processLiteralNode(FlatLiteralNode fln, Hashtable<TempDescriptor, Integer> currtable) {
590 if (fln.getValue()==null)
591 currtable.put(fln.getDst(), EITHER);
593 currtable.put(fln.getDst(), LOCAL);
596 void processReturnNode(LocalityBinding lb, FlatReturnNode frn, Hashtable<TempDescriptor, Integer> currtable) {
597 if(frn.getReturnTemp()!=null) {
598 Integer returntype=currtable.get(frn.getReturnTemp());
599 lb.setGlobalReturn(merge(returntype, lb.getGlobalReturn()));
603 void processSetElementNode(LocalityBinding lb, FlatSetElementNode fsen, Hashtable<TempDescriptor, Integer> currtable, boolean isatomic) {
604 Integer srctype=currtable.get(fsen.getSrc());
605 Integer dsttype=currtable.get(fsen.getDst());
607 if (dsttype.equals(LOCAL)) {
608 if (!(srctype.equals(LOCAL)||srctype.equals(EITHER)))
609 throw new Error("Writing possible global reference to local object in context:\n"+lb.getExplanation()+fsen);
610 } else if (dsttype.equals(GLOBAL)) {
611 if (srctype.equals(LOCAL) && fsen.getDst().getType().dereference().isPrimitive() && !fsen.getDst().getType().dereference().isArray())
613 if (!(srctype.equals(GLOBAL)||srctype.equals(EITHER)))
614 throw new Error("Writing possible local reference to global object in context:\n"+lb.getExplanation());
616 throw new Error("Global access outside of a transaction in context:\n"+lb.getExplanation());
617 } else if (dsttype.equals(EITHER)) {
618 if (srctype.equals(CONFLICT))
619 throw new Error("Using reference that could be local or global in context:\n"+lb.getExplanation());
620 } else if (dsttype.equals(CONFLICT)) {
621 throw new Error("Access to object that could be either global or local in context:\n"+lb.getExplanation());
625 void processElementNode(LocalityBinding lb, FlatElementNode fen, Hashtable<TempDescriptor, Integer> currtable, boolean isatomic) {
626 Integer type=currtable.get(fen.getSrc());
627 TempDescriptor dst=fen.getDst();
628 if (type.equals(LOCAL)) {
629 currtable.put(dst,LOCAL);
630 } else if (type.equals(GLOBAL)) {
632 throw new Error("Global access outside of a transaction in context:\n"+lb.getExplanation());
633 if(fen.getSrc().getType().dereference().isPrimitive()&&
634 !fen.getSrc().getType().dereference().isArray())
635 currtable.put(dst, LOCAL);
637 currtable.put(dst, GLOBAL);
638 } else if (type.equals(EITHER)) {
639 if(fen.getSrc().getType().dereference().isPrimitive()&&
640 !fen.getSrc().getType().dereference().isArray())
641 currtable.put(dst, LOCAL);
643 currtable.put(dst, EITHER);
644 } else if (type.equals(CONFLICT)) {
645 throw new Error("Access to object that could be either global or local in context:\n"+lb.getExplanation());
649 void processAtomicEnterNode(FlatAtomicEnterNode fen, Hashtable<FlatNode, Integer> atomictable) {
650 int atomic=atomictable.get(fen).intValue();
651 atomictable.put(fen, new Integer(atomic+1));
654 void processAtomicExitNode(FlatAtomicExitNode fen, Hashtable<FlatNode, Integer> atomictable) {
655 int atomic=atomictable.get(fen).intValue();
656 atomictable.put(fen, new Integer(atomic-1));
659 private Hashtable<FlatNode, Set<TempDescriptor>> computeLiveTemps(FlatMethod fm) {
660 Hashtable<FlatNode, Set<TempDescriptor>> nodetotemps=new Hashtable<FlatNode, Set<TempDescriptor>>();
662 Set<FlatNode> toprocess=fm.getNodeSet();
664 while(!toprocess.isEmpty()) {
665 FlatNode fn=toprocess.iterator().next();
666 toprocess.remove(fn);
668 List<TempDescriptor> reads=Arrays.asList(fn.readsTemps());
669 List<TempDescriptor> writes=Arrays.asList(fn.writesTemps());
671 HashSet<TempDescriptor> tempset=new HashSet<TempDescriptor>();
672 for(int i=0; i<fn.numNext(); i++) {
673 FlatNode fnnext=fn.getNext(i);
674 if (nodetotemps.containsKey(fnnext))
675 tempset.addAll(nodetotemps.get(fnnext));
677 tempset.removeAll(writes);
678 tempset.addAll(reads);
679 if (!nodetotemps.containsKey(fn)||
680 !nodetotemps.get(fn).equals(tempset)) {
681 nodetotemps.put(fn, tempset);
682 for(int i=0; i<fn.numPrev(); i++)
683 toprocess.add(fn.getPrev(i));
689 private void computeTempstoSave() {
690 for(Iterator<LocalityBinding> lbit=getLocalityBindings().iterator(); lbit.hasNext();) {
691 LocalityBinding lb=lbit.next();
692 computeTempstoSave(lb);
696 /* Need to checkpoint all temps that could be read from along any
697 * path that are either:
698 1) Written to by any assignment inside the transaction
699 2) Read from a global temp.
701 Generate tempstosave map from
702 localitybinding->flatatomicenternode->Set<TempDescriptors>
705 private void computeTempstoSave(LocalityBinding lb) {
708 Hashtable<FlatNode, Integer> atomictab=getAtomic(lb);
709 Hashtable<FlatNode, Hashtable<TempDescriptor, Integer>> temptab=getNodeTempInfo(lb);
710 MethodDescriptor md=lb.getMethod();
711 FlatMethod fm=state.getMethodFlat(md);
712 Hashtable<FlatNode, Set<TempDescriptor>> nodetotemps=computeLiveTemps(fm);
713 Hashtable<FlatAtomicEnterNode, Set<TempDescriptor>> nodetosavetemps=new Hashtable<FlatAtomicEnterNode, Set<TempDescriptor>>();
714 tempstosave.put(lb, nodetosavetemps);
715 Hashtable<FlatNode, FlatAtomicEnterNode> nodemap=new Hashtable<FlatNode, FlatAtomicEnterNode>();
716 HashSet<FlatNode> toprocess=new HashSet<FlatNode>();
717 HashSet<FlatNode> discovered=new HashSet<FlatNode>();
720 while(!toprocess.isEmpty()) {
721 FlatNode fn=toprocess.iterator().next();
722 toprocess.remove(fn);
723 boolean isatomic=atomictab.get(fn).intValue()>0;
725 atomictab.get(fn.getPrev(0)).intValue()==0) {
726 assert(fn.getPrev(0).kind()==FKind.FlatAtomicEnterNode);
727 nodemap.put(fn, (FlatAtomicEnterNode)fn);
728 nodetosavetemps.put((FlatAtomicEnterNode)fn, new HashSet<TempDescriptor>());
729 } else if (isatomic) {
730 FlatAtomicEnterNode atomicnode=nodemap.get(fn);
731 Set<TempDescriptor> livetemps=nodetotemps.get(fn);
732 List<TempDescriptor> reads=Arrays.asList(fn.readsTemps());
733 List<TempDescriptor> writes=Arrays.asList(fn.readsTemps());
735 for(Iterator<TempDescriptor> tempit=livetemps.iterator(); tempit.hasNext();) {
736 TempDescriptor tmp=tempit.next();
737 if (writes.contains(tmp)) {
738 nodetosavetemps.get(atomicnode).add(tmp);
739 } else if (reads.contains(tmp)&&temptab.get(fn).get(tmp)==GLOBAL) {
740 nodetosavetemps.get(atomicnode).add(tmp);
744 for(int i=0; i<fn.numNext(); i++) {
745 FlatNode fnnext=fn.getNext(i);
746 if (!discovered.contains(fnnext)) {
747 discovered.add(fnnext);
748 toprocess.add(fnnext);
750 nodemap.put(fnnext, nodemap.get(fn));