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=state.DSM?getNodePreTempInfo(currlb,fc):null;
59 MethodDescriptor md=fc.getMethod();
61 boolean isnative=md.getModifiers().isNative();
63 LocalityBinding lb=new LocalityBinding(md, isatomic);
66 for(int i=0; i<fc.numArgs(); i++) {
67 TempDescriptor arg=fc.getArg(i);
68 lb.setGlobal(i,currtable.get(arg));
71 if (state.DSM&&fc.getThis()!=null) {
72 Integer thistype=currtable.get(fc.getThis());
75 lb.setGlobalThis(thistype);
77 // lb.setGlobalThis(EITHER);//default value
78 if (discovered.containsKey(lb))
79 lb=discovered.get(lb);
80 else throw new Error();
85 /** This method returns a set of LocalityBindings for the parameter class. */
86 public Set<LocalityBinding> getClassBindings(ClassDescriptor cd) {
87 return classtolb.get(cd);
90 /** This method returns a set of LocalityBindings for the parameter method. */
92 public Set<LocalityBinding> getMethodBindings(MethodDescriptor md) {
93 return methodtolb.get(md);
96 public Set<MethodDescriptor> getMethods() {
97 return methodtolb.keySet();
100 /** This method returns a set of LocalityBindings. A
101 * LocalityBinding specifies a context a method can be invoked in.
102 * It specifies whether the method is in a transaction and whether
103 * its parameter objects are locals or globals. */
105 public Set<LocalityBinding> getLocalityBindings() {
106 return discovered.keySet();
109 /** This method returns a hashtable for a given LocalityBinding
110 * that tells the current local/global status of temps at the each
111 * node in the flat representation. */
113 public Hashtable<FlatNode, Hashtable<TempDescriptor, Integer>> getNodeTempInfo(LocalityBinding lb) {
114 return temptab.get(lb);
117 /** This method returns a hashtable for a given LocalityBinding
118 * that tells the current local/global status of temps at the
119 * beginning of each node in the flat representation. */
121 public Hashtable<TempDescriptor, Integer> getNodePreTempInfo(LocalityBinding lb, FlatNode fn) {
122 Hashtable<TempDescriptor, Integer> currtable=new Hashtable<TempDescriptor, Integer>();
123 Hashtable<FlatNode, Hashtable<TempDescriptor, Integer>> temptable=getNodeTempInfo(lb);
125 for(int i=0; i<fn.numPrev(); i++) {
126 FlatNode prevnode=fn.getPrev(i);
127 Hashtable<TempDescriptor, Integer> prevtable=temptable.get(prevnode);
128 for(Iterator<TempDescriptor> tempit=prevtable.keySet().iterator(); tempit.hasNext();) {
129 TempDescriptor temp=tempit.next();
130 Integer tmpint=prevtable.get(temp);
131 Integer oldint=currtable.containsKey(temp) ? currtable.get(temp) : EITHER;
132 Integer newint=merge(tmpint, oldint);
133 currtable.put(temp, newint);
139 /** This method returns an hashtable for a given LocalitBinding
140 * that tells whether a node in the flat represenation is in a
141 * transaction or not. Integer values greater than 0 indicate
142 * that the node is in a transaction and give the nesting depth.
143 * The outermost AtomicEnterNode will have a value of 1 and the
144 * outermost AtomicExitNode will have a value of 0. */
146 public Hashtable<FlatNode, Integer> getAtomic(LocalityBinding lb) {
147 return atomictab.get(lb);
150 /** This methods returns a hashtable for a given LocalityBinding
151 * that tells which temps needs to be saved for each
152 * AtomicEnterNode. */
154 public Hashtable<FlatAtomicEnterNode, Set<TempDescriptor>> getTemps(LocalityBinding lb) {
155 return tempstosave.get(lb);
158 public Set<TempDescriptor> getTempSet(LocalityBinding lb) {
159 HashSet<TempDescriptor> set=new HashSet<TempDescriptor>();
160 Hashtable<FlatAtomicEnterNode, Set<TempDescriptor>> table=getTemps(lb);
162 for(Iterator<FlatAtomicEnterNode> faenit=table.keySet().iterator(); faenit.hasNext();) {
163 FlatAtomicEnterNode faen=faenit.next();
164 set.addAll(table.get(faen));
169 private void doAnalysis() {
171 computeLocalityBindingsSTM();
173 computeLocalityBindings();
174 computeTempstoSave();
178 private void cleanSets() {
179 HashSet<LocalityBinding> lbset=new HashSet<LocalityBinding>();
180 Stack<LocalityBinding> lbstack=new Stack<LocalityBinding>();
185 while(!lbstack.isEmpty()) {
186 LocalityBinding lb=lbstack.pop();
187 if (calldep.containsKey(lb)) {
188 Set<LocalityBinding> set=new HashSet<LocalityBinding>();
189 set.addAll(calldep.get(lb));
190 set.removeAll(lbset);
195 for(Iterator<LocalityBinding> lbit=discovered.keySet().iterator(); lbit.hasNext();) {
196 LocalityBinding lb=lbit.next();
197 if (!lbset.contains(lb)) {
199 classtolb.get(lb.getMethod().getClassDesc()).remove(lb);
200 methodtolb.get(lb.getMethod()).remove(lb);
205 private void computeLocalityBindingsSTM() {
206 lbmain=new LocalityBinding(typeutil.getMain(), false);
207 lbtovisit.add(lbmain);
208 discovered.put(lbmain, lbmain);
209 if (!classtolb.containsKey(lbmain.getMethod().getClassDesc()))
210 classtolb.put(lbmain.getMethod().getClassDesc(), new HashSet<LocalityBinding>());
211 classtolb.get(lbmain.getMethod().getClassDesc()).add(lbmain);
213 if (!methodtolb.containsKey(lbmain.getMethod()))
214 methodtolb.put(lbmain.getMethod(), new HashSet<LocalityBinding>());
215 methodtolb.get(lbmain.getMethod()).add(lbmain);
217 //Do this to force a virtual table number for the run method
218 lbrun=new LocalityBinding(typeutil.getRun(), false);
219 lbtovisit.add(lbrun);
221 discovered.put(lbrun, lbrun);
222 if (!classtolb.containsKey(lbrun.getMethod().getClassDesc()))
223 classtolb.put(lbrun.getMethod().getClassDesc(), new HashSet<LocalityBinding>());
224 classtolb.get(lbrun.getMethod().getClassDesc()).add(lbrun);
226 if (!methodtolb.containsKey(lbrun.getMethod()))
227 methodtolb.put(lbrun.getMethod(), new HashSet<LocalityBinding>());
228 methodtolb.get(lbrun.getMethod()).add(lbrun);
230 while(!lbtovisit.empty()) {
231 LocalityBinding lb=(LocalityBinding) lbtovisit.pop();
232 Integer returnglobal=lb.getGlobalReturn();
233 MethodDescriptor md=lb.getMethod();
234 Hashtable<FlatNode, Integer> atomictable=new Hashtable<FlatNode, Integer>();
237 computeCallsFlagsSTM(md, lb, atomictable);
239 System.out.println("Error in "+md+" context "+lb);
243 atomictab.put(lb, atomictable);
247 public void computeCallsFlagsSTM(MethodDescriptor md, LocalityBinding lb, Hashtable<FlatNode, Integer> atomictable) {
248 FlatMethod fm=state.getMethodFlat(md);
249 HashSet<FlatNode> tovisit=new HashSet<FlatNode>();
250 tovisit.add(fm.getNext(0));
251 atomictable.put(fm, lb.isAtomic() ? 1 : 0);
253 while(!tovisit.isEmpty()) {
254 FlatNode fn=tovisit.iterator().next();
257 for(int i=0; i<fn.numPrev(); i++) {
258 FlatNode prevnode=fn.getPrev(i);
259 if (atomictable.containsKey(prevnode)) {
260 atomicstate=atomictable.get(prevnode).intValue();
263 Integer oldatomic=atomictable.get(fn);
264 if (oldatomic==null||!oldatomic.equals(atomicstate)) {
265 //add in the next node
266 for(int i=0;i<fn.numNext();i++) {
267 tovisit.add(fn.getNext(i));
269 atomictable.put(fn, atomicstate);
273 case FKind.FlatAtomicEnterNode:
274 processAtomicEnterNode((FlatAtomicEnterNode)fn, atomictable);
279 case FKind.FlatAtomicExitNode:
280 processAtomicExitNode((FlatAtomicExitNode)fn, atomictable);
284 processCallNodeSTM(lb, (FlatCall)fn, isAtomic(atomictable, fn));
287 case FKind.FlatMethod:
288 case FKind.FlatOffsetNode:
289 case FKind.FlatFieldNode:
290 case FKind.FlatSetFieldNode:
292 case FKind.FlatOpNode:
293 case FKind.FlatCastNode:
294 case FKind.FlatLiteralNode:
295 case FKind.FlatReturnNode:
296 case FKind.FlatSetElementNode:
297 case FKind.FlatElementNode:
298 case FKind.FlatInstanceOfNode:
299 case FKind.FlatCondBranch:
300 case FKind.FlatBackEdge:
302 case FKind.FlatPrefetchNode:
304 //No action needed for these
307 case FKind.FlatFlagActionNode:
308 case FKind.FlatCheckNode:
309 case FKind.FlatTagDeclaration:
310 throw new Error("Incompatible with tasks!");
313 throw new Error("In finding fn.kind()= " + fn.kind());
318 void processCallNodeSTM(LocalityBinding currlb, FlatCall fc, boolean isatomic) {
319 MethodDescriptor nodemd=fc.getMethod();
321 Set runmethodset=null;
323 if (nodemd.isStatic()||nodemd.getReturnType()==null) {
324 methodset=new HashSet();
325 methodset.add(nodemd);
327 methodset=callgraph.getMethods(nodemd, fc.getThis().getType());
328 // Build start -> run link
329 if (nodemd.getClassDesc().getSymbol().equals(TypeUtil.ThreadClass)&&
330 nodemd.getSymbol().equals("start")&&!nodemd.getModifiers().isStatic()&&
331 nodemd.numParameters()==0) {
332 assert(nodemd.getModifiers().isNative());
334 MethodDescriptor runmd=null;
335 for(Iterator methodit=nodemd.getClassDesc().getMethodTable().getSet("run").iterator(); methodit.hasNext();) {
336 MethodDescriptor md=(MethodDescriptor) methodit.next();
337 if (md.numParameters()!=0||md.getModifiers().isStatic())
343 runmethodset=callgraph.getMethods(runmd,fc.getThis().getType());
344 methodset.addAll(runmethodset);
345 } else throw new Error("Can't find run method");
349 for(Iterator methodit=methodset.iterator(); methodit.hasNext();) {
350 MethodDescriptor md=(MethodDescriptor) methodit.next();
352 boolean isnative=md.getModifiers().isNative();
353 boolean isjoin = md.getClassDesc().getSymbol().equals(TypeUtil.ThreadClass)&&!nodemd.getModifiers().isStatic()&&nodemd.numParameters()==0&&md.getSymbol().equals("join");
354 boolean isObjectgetType = md.getClassDesc().getSymbol().equals("Object") && md.getSymbol().equals("getType");
355 boolean isObjecthashCode = md.getClassDesc().getSymbol().equals("Object") && md.getSymbol().equals("nativehashCode");
357 LocalityBinding lb=new LocalityBinding(md, isatomic);
358 if (isnative&&isatomic) {
359 System.out.println("Don't call native methods in atomic blocks!"+currlb.getMethod());
363 if (!discovered.containsKey(lb)) {
364 lb.setParent(currlb);
366 discovered.put(lb, lb);
367 if (!classtolb.containsKey(lb.getMethod().getClassDesc()))
368 classtolb.put(lb.getMethod().getClassDesc(), new HashSet<LocalityBinding>());
369 classtolb.get(lb.getMethod().getClassDesc()).add(lb);
370 if (!methodtolb.containsKey(lb.getMethod()))
371 methodtolb.put(lb.getMethod(), new HashSet<LocalityBinding>());
372 methodtolb.get(lb.getMethod()).add(lb);
374 lb=discovered.get(lb);
376 if (!dependence.containsKey(lb))
377 dependence.put(lb, new HashSet<LocalityBinding>());
378 dependence.get(lb).add(currlb);
380 if (!calldep.containsKey(currlb))
381 calldep.put(currlb, new HashSet<LocalityBinding>());
382 calldep.get(currlb).add(lb);
386 private void computeLocalityBindings() {
387 lbmain=new LocalityBinding(typeutil.getMain(), false);
388 lbmain.setGlobalReturn(EITHER);
389 lbmain.setGlobal(0, LOCAL);
390 lbtovisit.add(lbmain);
391 discovered.put(lbmain, lbmain);
392 if (!classtolb.containsKey(lbmain.getMethod().getClassDesc()))
393 classtolb.put(lbmain.getMethod().getClassDesc(), new HashSet<LocalityBinding>());
394 classtolb.get(lbmain.getMethod().getClassDesc()).add(lbmain);
396 if (!methodtolb.containsKey(lbmain.getMethod()))
397 methodtolb.put(lbmain.getMethod(), new HashSet<LocalityBinding>());
398 methodtolb.get(lbmain.getMethod()).add(lbmain);
400 //Do this to force a virtual table number for the run method
401 lbrun=new LocalityBinding(typeutil.getRun(), false);
402 lbrun.setGlobalReturn(EITHER);
403 lbrun.setGlobalThis(GLOBAL);
404 lbtovisit.add(lbrun);
405 discovered.put(lbrun, lbrun);
406 if (!classtolb.containsKey(lbrun.getMethod().getClassDesc()))
407 classtolb.put(lbrun.getMethod().getClassDesc(), new HashSet<LocalityBinding>());
408 classtolb.get(lbrun.getMethod().getClassDesc()).add(lbrun);
410 if (!methodtolb.containsKey(lbrun.getMethod()))
411 methodtolb.put(lbrun.getMethod(), new HashSet<LocalityBinding>());
412 methodtolb.get(lbrun.getMethod()).add(lbrun);
414 while(!lbtovisit.empty()) {
415 LocalityBinding lb=(LocalityBinding) lbtovisit.pop();
416 Integer returnglobal=lb.getGlobalReturn();
417 MethodDescriptor md=lb.getMethod();
418 Hashtable<FlatNode,Hashtable<TempDescriptor, Integer>> temptable=new Hashtable<FlatNode,Hashtable<TempDescriptor, Integer>>();
419 Hashtable<FlatNode, Integer> atomictable=new Hashtable<FlatNode, Integer>();
422 computeCallsFlags(md, lb, temptable, atomictable);
424 System.out.println("Error in "+md+" context "+lb);
428 atomictab.put(lb, atomictable);
429 temptab.put(lb, temptable);
431 if (md.getReturnType()!=null&&!returnglobal.equals(lb.getGlobalReturn())) {
432 //return type is more precise now
433 //rerun everything that call us
434 lbtovisit.addAll(dependence.get(lb));
442 public void computeCallsFlags(MethodDescriptor md, LocalityBinding lb, Hashtable<FlatNode, Hashtable<TempDescriptor, Integer>> temptable, Hashtable<FlatNode, Integer> atomictable) {
443 FlatMethod fm=state.getMethodFlat(md);
444 HashSet<FlatNode> tovisit=new HashSet<FlatNode>();
445 tovisit.add(fm.getNext(0));
447 // Build table for initial node
448 Hashtable<TempDescriptor,Integer> table=new Hashtable<TempDescriptor,Integer>();
449 temptable.put(fm, table);
450 atomictable.put(fm, lb.isAtomic() ? 1 : 0);
451 int offset=md.isStatic() ? 0 : 1;
452 if (!md.isStatic()) {
453 table.put(fm.getParameter(0), lb.getGlobalThis());
455 for(int i=offset; i<fm.numParameters(); i++) {
456 TempDescriptor temp=fm.getParameter(i);
457 Integer b=lb.isGlobal(i-offset);
462 while(!tovisit.isEmpty()) {
463 FlatNode fn=tovisit.iterator().next();
465 Hashtable<TempDescriptor, Integer> currtable=new Hashtable<TempDescriptor, Integer>();
467 for(int i=0; i<fn.numPrev(); i++) {
468 FlatNode prevnode=fn.getPrev(i);
469 if (atomictable.containsKey(prevnode)) {
470 atomicstate=atomictable.get(prevnode).intValue();
472 if (!temptable.containsKey(prevnode))
474 Hashtable<TempDescriptor, Integer> prevtable=temptable.get(prevnode);
475 for(Iterator<TempDescriptor> tempit=prevtable.keySet().iterator(); tempit.hasNext();) {
476 TempDescriptor temp=tempit.next();
477 Integer tmpint=prevtable.get(temp);
478 Integer oldint=currtable.containsKey(temp) ? currtable.get(temp) : EITHER;
479 Integer newint=merge(tmpint, oldint);
480 currtable.put(temp, newint);
483 atomictable.put(fn, atomicstate);
486 case FKind.FlatAtomicEnterNode:
487 processAtomicEnterNode((FlatAtomicEnterNode)fn, atomictable);
492 case FKind.FlatAtomicExitNode:
493 processAtomicExitNode((FlatAtomicExitNode)fn, atomictable);
497 processCallNode(lb, (FlatCall)fn, currtable, isAtomic(atomictable, fn));
500 case FKind.FlatFieldNode:
501 processFieldNode(lb, (FlatFieldNode)fn, isAtomic(atomictable, fn), currtable);
504 case FKind.FlatSetFieldNode:
505 processSetFieldNode(lb, (FlatSetFieldNode)fn, isAtomic(atomictable,fn), currtable);
509 processNew(lb, (FlatNew)fn, isAtomic(atomictable, fn), currtable);
512 case FKind.FlatOpNode:
513 processOpNode((FlatOpNode)fn, currtable);
516 case FKind.FlatCastNode:
517 processCastNode((FlatCastNode)fn, currtable);
520 case FKind.FlatLiteralNode:
521 processLiteralNode((FlatLiteralNode)fn, currtable);
524 case FKind.FlatReturnNode:
525 processReturnNode(lb, (FlatReturnNode)fn, currtable);
528 case FKind.FlatSetElementNode:
529 processSetElementNode(lb, (FlatSetElementNode)fn, currtable, isAtomic(atomictable, fn));
532 case FKind.FlatElementNode:
533 processElementNode(lb, (FlatElementNode)fn, currtable, isAtomic(atomictable, fn));
536 case FKind.FlatInstanceOfNode:
537 case FKind.FlatCondBranch:
538 case FKind.FlatBackEdge:
541 case FKind.FlatPrefetchNode:
542 //No action needed for these
545 case FKind.FlatFlagActionNode:
546 case FKind.FlatCheckNode:
547 case FKind.FlatTagDeclaration:
548 throw new Error("Incompatible with tasks!");
550 case FKind.FlatMethod:
553 case FKind.FlatOffsetNode:
554 processOffsetNode((FlatOffsetNode)fn, currtable);
558 throw new Error("In finding fn.kind()= " + fn.kind());
560 Hashtable<TempDescriptor,Integer> oldtable=temptable.get(fn);
561 if (oldtable==null||!oldtable.equals(currtable)) {
562 // Update table for this node
563 temptable.put(fn, currtable);
564 for(int i=0; i<fn.numNext(); i++) {
565 tovisit.add(fn.getNext(i));
571 private static boolean isAtomic(Hashtable<FlatNode, Integer> atomictable, FlatNode fn) {
572 return atomictable.get(fn).intValue()>0;
575 private static Integer merge(Integer a, Integer b) {
576 if (a==null||a.equals(EITHER))
578 if (b==null||b.equals(EITHER))
585 void processCallNode(LocalityBinding currlb, FlatCall fc, Hashtable<TempDescriptor, Integer> currtable, boolean isatomic) {
586 MethodDescriptor nodemd=fc.getMethod();
588 Set runmethodset=null;
590 if (nodemd.isStatic()||nodemd.getReturnType()==null) {
591 methodset=new HashSet();
592 methodset.add(nodemd);
594 methodset=callgraph.getMethods(nodemd, fc.getThis().getType());
595 // Build start -> run link
596 if (nodemd.getClassDesc().getSymbol().equals(TypeUtil.ThreadClass)&&
597 nodemd.getSymbol().equals("start")&&!nodemd.getModifiers().isStatic()&&
598 nodemd.numParameters()==1&&nodemd.getParamType(0).isInt()) {
599 assert(nodemd.getModifiers().isNative());
601 MethodDescriptor runmd=null;
602 for(Iterator methodit=nodemd.getClassDesc().getMethodTable().getSet("run").iterator(); methodit.hasNext();) {
603 MethodDescriptor md=(MethodDescriptor) methodit.next();
604 if (md.numParameters()!=0||md.getModifiers().isStatic())
610 runmethodset=callgraph.getMethods(runmd,fc.getThis().getType());
611 methodset.addAll(runmethodset);
612 } else throw new Error("Can't find run method");
616 Integer currreturnval=EITHER; //Start off with the either value
617 for(Iterator methodit=methodset.iterator(); methodit.hasNext();) {
618 MethodDescriptor md=(MethodDescriptor) methodit.next();
620 boolean isnative=md.getModifiers().isNative();
621 boolean isjoin = md.getClassDesc().getSymbol().equals(TypeUtil.ThreadClass)&&!nodemd.getModifiers().isStatic()&&nodemd.numParameters()==0&&md.getSymbol().equals("join");
622 boolean isObjectgetType = md.getClassDesc().getSymbol().equals("Object") && md.getSymbol().equals("getType");
623 boolean isObjecthashCode = md.getClassDesc().getSymbol().equals("Object") && md.getSymbol().equals("nativehashCode");
625 LocalityBinding lb=new LocalityBinding(md, isatomic);
626 if (isnative&&isatomic) {
627 System.out.println("Don't call native methods in atomic blocks!"+currlb.getMethod());
629 if (runmethodset==null||!runmethodset.contains(md)) {
630 //Skip this part if it is a run method
631 for(int i=0; i<fc.numArgs(); i++) {
632 TempDescriptor arg=fc.getArg(i);
633 if(isnative&&(currtable.get(arg).equals(GLOBAL)||
634 currtable.get(arg).equals(CONFLICT))&& !(nodemd.getSymbol().equals("rangePrefetch"))) {
635 throw new Error("Potential call to native method "+md+" with global parameter:\n"+currlb.getExplanation());
637 lb.setGlobal(i,currtable.get(arg));
641 if (fc.getThis()!=null) {
642 Integer thistype=currtable.get(fc.getThis());
646 if(runmethodset!=null&&runmethodset.contains(md)&&thistype.equals(LOCAL))
647 throw new Error("Starting thread on local object not allowed in context:\n"+currlb.getExplanation());
648 if(isjoin&&thistype.equals(LOCAL))
649 throw new Error("Joining thread on local object not allowed in context:\n"+currlb.getExplanation());
650 if(thistype.equals(CONFLICT))
651 throw new Error("Using type that can be either local or global in context:\n"+currlb.getExplanation());
652 if(runmethodset==null&&thistype.equals(GLOBAL)&&!isatomic && !isjoin)
653 throw new Error("Using global object outside of transaction in context:\n"+currlb.getExplanation());
654 if (runmethodset==null&&isnative&&thistype.equals(GLOBAL) && !isjoin && !isObjectgetType && !isObjecthashCode)
655 throw new Error("Potential call to native method "+md+" on global objects:\n"+currlb.getExplanation());
656 lb.setGlobalThis(thistype);
659 if (!discovered.containsKey(lb)) {
661 lb.setGlobalReturn(LOCAL);
663 lb.setGlobalReturn(EITHER);
664 lb.setParent(currlb);
666 discovered.put(lb, lb);
667 if (!classtolb.containsKey(lb.getMethod().getClassDesc()))
668 classtolb.put(lb.getMethod().getClassDesc(), new HashSet<LocalityBinding>());
669 classtolb.get(lb.getMethod().getClassDesc()).add(lb);
670 if (!methodtolb.containsKey(lb.getMethod()))
671 methodtolb.put(lb.getMethod(), new HashSet<LocalityBinding>());
672 methodtolb.get(lb.getMethod()).add(lb);
674 lb=discovered.get(lb);
675 Integer returnval=lb.getGlobalReturn();
676 currreturnval=merge(returnval, currreturnval);
677 if (!dependence.containsKey(lb))
678 dependence.put(lb, new HashSet<LocalityBinding>());
679 dependence.get(lb).add(currlb);
681 if (!calldep.containsKey(currlb))
682 calldep.put(currlb, new HashSet<LocalityBinding>());
683 calldep.get(currlb).add(lb);
685 if (fc.getReturnTemp()!=null) {
686 currtable.put(fc.getReturnTemp(), currreturnval);
690 void processFieldNode(LocalityBinding lb, FlatFieldNode ffn, boolean transaction, Hashtable<TempDescriptor, Integer> currtable) {
691 Integer type=currtable.get(ffn.getSrc());
692 TempDescriptor dst=ffn.getDst();
693 if (type.equals(LOCAL)) {
694 if (ffn.getField().isGlobal())
695 currtable.put(dst,GLOBAL);
697 currtable.put(dst,LOCAL);
698 } else if (type.equals(GLOBAL)) {
700 throw new Error("Global access outside of a transaction in context:\n"+lb.getExplanation());
701 if (ffn.getField().getType().isPrimitive()&&!ffn.getField().getType().isArray())
702 currtable.put(dst, LOCAL); // primitives are local
704 currtable.put(dst, GLOBAL);
705 } else if (type.equals(EITHER)) {
706 if (ffn.getField().getType().isPrimitive()&&!ffn.getField().getType().isArray())
707 currtable.put(dst, LOCAL); // primitives are local
708 else if (ffn.getField().isGlobal())
709 currtable.put(dst, GLOBAL);
711 currtable.put(dst, EITHER);
712 } else if (type.equals(CONFLICT)) {
713 throw new Error("Access to object that could be either global or local in context:\n"+lb.getExplanation());
717 //need to handle primitives
718 void processSetFieldNode(LocalityBinding lb, FlatSetFieldNode fsfn, boolean transaction, Hashtable<TempDescriptor, Integer> currtable) {
719 Integer srctype=currtable.get(fsfn.getSrc());
720 Integer dsttype=currtable.get(fsfn.getDst());
722 if (dsttype.equals(LOCAL)) {
723 if (fsfn.getField().isGlobal()) {
724 if (!(srctype.equals(GLOBAL)||srctype.equals(EITHER)))
725 throw new Error("Writing possible local reference to global field in context: \n"+lb.getExplanation());
727 if (!(srctype.equals(LOCAL)||srctype.equals(EITHER)))
728 throw new Error("Writing possible global reference to local object in context: \n"+lb.getExplanation());
730 } else if (dsttype.equals(GLOBAL)) {
732 throw new Error("Global access outside of a transaction in context:\n"+lb.getExplanation());
733 //okay to store primitives in global object
734 if (srctype.equals(LOCAL) && fsfn.getField().getType().isPrimitive() && !fsfn.getField().getType().isArray())
736 if (!(srctype.equals(GLOBAL)||srctype.equals(EITHER)))
737 throw new Error("Writing possible local reference to global object in context:\n"+lb.getExplanation()+" for FlatFieldNode "+fsfn);
738 } else if (dsttype.equals(EITHER)) {
739 if (srctype.equals(CONFLICT))
740 throw new Error("Using reference that could be local or global in context:\n"+lb.getExplanation());
741 } else if (dsttype.equals(CONFLICT)) {
742 throw new Error("Access to object that could be either global or local in context:\n"+lb.getExplanation());
746 void processNew(LocalityBinding lb, FlatNew fn, boolean transaction, Hashtable<TempDescriptor, Integer> currtable) {
747 if (fn.isGlobal()&&!transaction) {
748 throw new Error("Allocating global object outside of transaction in context:"+lb.getExplanation());
751 currtable.put(fn.getDst(), GLOBAL);
753 currtable.put(fn.getDst(), LOCAL);
756 void processOpNode(FlatOpNode fon, Hashtable<TempDescriptor, Integer> currtable) {
757 /* Just propagate value */
758 Integer srcvalue=currtable.get(fon.getLeft());
760 if (srcvalue==null) {
761 if (!fon.getLeft().getType().isPtr()) {
764 throw new Error(fon.getLeft()+" is undefined!");
766 currtable.put(fon.getDest(), srcvalue);
769 void processCastNode(FlatCastNode fcn, Hashtable<TempDescriptor, Integer> currtable) {
770 currtable.put(fcn.getDst(), currtable.get(fcn.getSrc()));
773 void processLiteralNode(FlatLiteralNode fln, Hashtable<TempDescriptor, Integer> currtable) {
775 if (fln.getValue()==null)
776 currtable.put(fln.getDst(), EITHER);
778 currtable.put(fln.getDst(), LOCAL);
781 void processOffsetNode(FlatOffsetNode fln, Hashtable<TempDescriptor, Integer> currtable) {
782 currtable.put(fln.getDst(), LOCAL);
785 void processReturnNode(LocalityBinding lb, FlatReturnNode frn, Hashtable<TempDescriptor, Integer> currtable) {
786 if(frn.getReturnTemp()!=null) {
787 Integer returntype=currtable.get(frn.getReturnTemp());
788 lb.setGlobalReturn(merge(returntype, lb.getGlobalReturn()));
792 void processSetElementNode(LocalityBinding lb, FlatSetElementNode fsen, Hashtable<TempDescriptor, Integer> currtable, boolean isatomic) {
793 Integer srctype=currtable.get(fsen.getSrc());
794 Integer dsttype=currtable.get(fsen.getDst());
796 if (dsttype.equals(LOCAL)) {
797 if (!(srctype.equals(LOCAL)||srctype.equals(EITHER)))
798 throw new Error("Writing possible global reference to local object in context:\n"+lb.getExplanation()+fsen);
799 } else if (dsttype.equals(GLOBAL)) {
800 if (srctype.equals(LOCAL) && fsen.getDst().getType().dereference().isPrimitive() && !fsen.getDst().getType().dereference().isArray())
802 if (!(srctype.equals(GLOBAL)||srctype.equals(EITHER)))
803 throw new Error("Writing possible local reference to global object in context:\n"+lb.getExplanation());
805 throw new Error("Global access outside of a transaction in context:\n"+lb.getExplanation());
806 } else if (dsttype.equals(EITHER)) {
807 if (srctype.equals(CONFLICT))
808 throw new Error("Using reference that could be local or global in context:\n"+lb.getExplanation());
809 } else if (dsttype.equals(CONFLICT)) {
810 throw new Error("Access to object that could be either global or local in context:\n"+lb.getExplanation());
814 void processElementNode(LocalityBinding lb, FlatElementNode fen, Hashtable<TempDescriptor, Integer> currtable, boolean isatomic) {
815 Integer type=currtable.get(fen.getSrc());
816 TempDescriptor dst=fen.getDst();
817 if (type.equals(LOCAL)) {
818 currtable.put(dst,LOCAL);
819 } else if (type.equals(GLOBAL)) {
821 throw new Error("Global access outside of a transaction in context:\n"+lb.getExplanation());
822 if(fen.getSrc().getType().dereference().isPrimitive()&&
823 !fen.getSrc().getType().dereference().isArray())
824 currtable.put(dst, LOCAL);
826 currtable.put(dst, GLOBAL);
827 } else if (type.equals(EITHER)) {
828 if(fen.getSrc().getType().dereference().isPrimitive()&&
829 !fen.getSrc().getType().dereference().isArray())
830 currtable.put(dst, LOCAL);
832 currtable.put(dst, EITHER);
833 } else if (type.equals(CONFLICT)) {
834 throw new Error("Access to object that could be either global or local in context:\n"+lb.getExplanation());
838 void processAtomicEnterNode(FlatAtomicEnterNode fen, Hashtable<FlatNode, Integer> atomictable) {
839 int atomic=atomictable.get(fen).intValue();
840 atomictable.put(fen, new Integer(atomic+1));
843 void processAtomicExitNode(FlatAtomicExitNode fen, Hashtable<FlatNode, Integer> atomictable) {
844 int atomic=atomictable.get(fen).intValue();
845 atomictable.put(fen, new Integer(atomic-1));
848 private Hashtable<FlatNode, Set<TempDescriptor>> computeLiveTemps(FlatMethod fm) {
849 Hashtable<FlatNode, Set<TempDescriptor>> nodetotemps=new Hashtable<FlatNode, Set<TempDescriptor>>();
851 Set<FlatNode> toprocess=fm.getNodeSet();
853 while(!toprocess.isEmpty()) {
854 FlatNode fn=toprocess.iterator().next();
855 toprocess.remove(fn);
857 List<TempDescriptor> reads=Arrays.asList(fn.readsTemps());
858 List<TempDescriptor> writes=Arrays.asList(fn.writesTemps());
860 HashSet<TempDescriptor> tempset=new HashSet<TempDescriptor>();
861 for(int i=0; i<fn.numNext(); i++) {
862 FlatNode fnnext=fn.getNext(i);
863 if (nodetotemps.containsKey(fnnext))
864 tempset.addAll(nodetotemps.get(fnnext));
866 tempset.removeAll(writes);
867 tempset.addAll(reads);
868 if (!nodetotemps.containsKey(fn)||
869 !nodetotemps.get(fn).equals(tempset)) {
870 nodetotemps.put(fn, tempset);
871 for(int i=0; i<fn.numPrev(); i++)
872 toprocess.add(fn.getPrev(i));
878 private void computeTempstoSave() {
879 for(Iterator<LocalityBinding> lbit=getLocalityBindings().iterator(); lbit.hasNext();) {
880 LocalityBinding lb=lbit.next();
881 computeTempstoSave(lb);
885 /* Need to checkpoint all temps that could be read from along any
886 * path that are either:
887 1) Written to by any assignment inside the transaction
888 2) Read from a global temp.
890 Generate tempstosave map from
891 localitybinding->flatatomicenternode->Set<TempDescriptors>
894 private void computeTempstoSave(LocalityBinding lb) {
897 Hashtable<FlatNode, Integer> atomictab=getAtomic(lb);
898 Hashtable<FlatNode, Hashtable<TempDescriptor, Integer>> temptab=getNodeTempInfo(lb);
899 MethodDescriptor md=lb.getMethod();
900 FlatMethod fm=state.getMethodFlat(md);
901 Hashtable<FlatNode, Set<TempDescriptor>> nodetotemps=computeLiveTemps(fm);
902 Hashtable<FlatAtomicEnterNode, Set<TempDescriptor>> nodetosavetemps=new Hashtable<FlatAtomicEnterNode, Set<TempDescriptor>>();
903 tempstosave.put(lb, nodetosavetemps);
904 Hashtable<FlatNode, FlatAtomicEnterNode> nodemap=new Hashtable<FlatNode, FlatAtomicEnterNode>();
905 HashSet<FlatNode> toprocess=new HashSet<FlatNode>();
906 HashSet<FlatNode> discovered=new HashSet<FlatNode>();
909 while(!toprocess.isEmpty()) {
910 FlatNode fn=toprocess.iterator().next();
911 toprocess.remove(fn);
912 boolean isatomic=atomictab.get(fn).intValue()>0;
914 atomictab.get(fn.getPrev(0)).intValue()==0) {
915 assert(fn.getPrev(0).kind()==FKind.FlatAtomicEnterNode);
916 nodemap.put(fn, (FlatAtomicEnterNode)fn);
917 nodetosavetemps.put((FlatAtomicEnterNode)fn, new HashSet<TempDescriptor>());
918 } else if (isatomic) {
919 FlatAtomicEnterNode atomicnode=nodemap.get(fn);
920 Set<TempDescriptor> livetemps=nodetotemps.get(fn);
921 List<TempDescriptor> reads=Arrays.asList(fn.readsTemps());
922 List<TempDescriptor> writes=Arrays.asList(fn.readsTemps());
924 for(Iterator<TempDescriptor> tempit=livetemps.iterator(); tempit.hasNext();) {
925 TempDescriptor tmp=tempit.next();
926 if (writes.contains(tmp)) {
927 nodetosavetemps.get(atomicnode).add(tmp);
928 } else if (state.DSM) {
929 if (reads.contains(tmp)&&temptab.get(fn).get(tmp)==GLOBAL) {
930 nodetosavetemps.get(atomicnode).add(tmp);
933 if (reads.contains(tmp)&&tmp.getType().isPtr()) {
934 nodetosavetemps.get(atomicnode).add(tmp);
939 for(int i=0; i<fn.numNext(); i++) {
940 FlatNode fnnext=fn.getNext(i);
941 if (!discovered.contains(fnnext)) {
942 discovered.add(fnnext);
943 toprocess.add(fnnext);
945 nodemap.put(fnnext, nodemap.get(fn));