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;
24 public static final Integer LOCAL=new Integer(0);
25 public static final Integer GLOBAL=new Integer(1);
26 public static final Integer EITHER=new Integer(2);
27 public static final Integer CONFLICT=new Integer(3);
29 public LocalityAnalysis(State state, CallGraph callgraph, TypeUtil typeutil) {
30 this.typeutil=typeutil;
32 this.discovered=new Hashtable<LocalityBinding,LocalityBinding>();
33 this.dependence=new Hashtable<LocalityBinding, Set<LocalityBinding>>();
34 this.lbtovisit=new Stack();
35 this.callgraph=callgraph;
39 private void doAnalysis() {
40 computeLocalityBindings();
43 private void computeLocalityBindings() {
44 LocalityBinding lbmain=new LocalityBinding(typeutil.getMain(), false);
45 lbmain.setGlobal(0, LOCAL);
46 lbtovisit.add(lbmain);
47 discovered.put(lbmain, lbmain);
49 while(!lbtovisit.empty()) {
50 LocalityBinding lb=(LocalityBinding) lbtovisit.pop();
51 Integer returnglobal=lb.getGlobalReturn();
52 MethodDescriptor md=lb.getMethod();
53 Hashtable<FlatNode,Hashtable<TempDescriptor, Integer>> temptable=new Hashtable<FlatNode,Hashtable<TempDescriptor, Integer>>();
54 Hashtable<FlatNode, Integer> atomictable=new Hashtable<FlatNode, Integer>();
55 computeCallsFlags(md, lb, temptable, atomictable);
56 if (!md.isStatic()&&!returnglobal.equals(lb.getGlobalReturn())) {
57 //return type is more precise now
58 //rerun everything that call us
59 lbtovisit.addAll(dependence.get(lb));
65 public void computeCallsFlags(MethodDescriptor md, LocalityBinding lb, Hashtable<FlatNode, Hashtable<TempDescriptor, Integer>> temptable, Hashtable<FlatNode, Integer> atomictable) {
66 FlatMethod fm=state.getMethodFlat(md);
67 HashSet<FlatNode> tovisit=new HashSet<FlatNode>();
68 tovisit.add(fm.getNext(0));
70 // Build table for initial node
71 Hashtable<TempDescriptor,Integer> table=new Hashtable<TempDescriptor,Integer>();
72 temptable.put(fm, table);
73 atomictable.put(fm, lb.isAtomic()?1:0);
74 int offset=md.isStatic()?0:1;
76 table.put(fm.getParameter(0), lb.getGlobalThis());
78 for(int i=offset;i<fm.numParameters();i++) {
79 TempDescriptor temp=fm.getParameter(i);
80 Integer b=lb.isGlobal(i-offset);
85 while(!tovisit.isEmpty()) {
86 FlatNode fn=tovisit.iterator().next();
88 Hashtable<TempDescriptor, Integer> currtable=new Hashtable<TempDescriptor, Integer>();
90 for(int i=0;i<fn.numPrev();i++) {
91 FlatNode prevnode=fn.getPrev(i);
92 if (atomictable.containsKey(prevnode)) {
93 atomicstate=atomictable.get(prevnode).intValue();
95 if (!temptable.containsKey(prevnode))
97 Hashtable<TempDescriptor, Integer> prevtable=temptable.get(prevnode);
98 for(Iterator<TempDescriptor> tempit=prevtable.keySet().iterator();tempit.hasNext();) {
99 TempDescriptor temp=tempit.next();
100 Integer tmpint=prevtable.get(temp);
101 Integer oldint=currtable.containsKey(temp)?currtable.get(temp):EITHER;
102 Integer newint=merge(tmpint, oldint);
103 currtable.put(temp, newint);
106 atomictable.put(fn, atomicstate);
109 case FKind.FlatAtomicEnterNode:
110 processAtomicEnterNode((FlatAtomicEnterNode)fn, atomictable);
112 case FKind.FlatAtomicExitNode:
113 processAtomicExitNode((FlatAtomicExitNode)fn, atomictable);
116 processCallNode(lb, (FlatCall)fn, currtable, isAtomic(atomictable, fn));
118 case FKind.FlatFieldNode:
119 processFieldNode(lb, (FlatFieldNode)fn, isAtomic(atomictable, fn), currtable);
121 case FKind.FlatSetFieldNode:
122 processSetFieldNode(lb, (FlatSetFieldNode)fn, isAtomic(atomictable,fn), currtable);
125 processNew(lb, (FlatNew)fn, isAtomic(atomictable, fn), currtable);
127 case FKind.FlatOpNode:
128 processOpNode((FlatOpNode)fn, currtable);
130 case FKind.FlatCastNode:
131 processCastNode((FlatCastNode)fn, currtable);
133 case FKind.FlatLiteralNode:
134 processLiteralNode((FlatLiteralNode)fn, currtable);
136 case FKind.FlatReturnNode:
137 processReturnNode(lb, (FlatReturnNode)fn, currtable);
139 case FKind.FlatSetElementNode:
140 processSetElementNode(lb, (FlatSetElementNode)fn, currtable, isAtomic(atomictable, fn));
142 case FKind.FlatElementNode:
143 processElementNode(lb, (FlatElementNode)fn, currtable, isAtomic(atomictable, fn));
145 case FKind.FlatCondBranch:
146 case FKind.FlatBackEdge:
148 //No action needed for these
150 case FKind.FlatFlagActionNode:
151 case FKind.FlatCheckNode:
152 case FKind.FlatTagDeclaration:
153 throw new Error("Incompatible with tasks!");
154 case FKind.FlatMethod:
158 Hashtable<TempDescriptor,Integer> oldtable=temptable.get(fn);
159 if (oldtable==null||!oldtable.equals(currtable)) {
160 // Update table for this node
161 temptable.put(fn, currtable);
162 for(int i=0;i<fn.numNext();i++) {
163 tovisit.add(fn.getNext(i));
169 private static boolean isAtomic(Hashtable<FlatNode, Integer> atomictable, FlatNode fn) {
170 return atomictable.get(fn).intValue()>0;
173 private static Integer merge(Integer a, Integer b) {
174 if (a==null||a.equals(EITHER))
176 if (b==null||b.equals(EITHER))
183 void processCallNode(LocalityBinding currlb, FlatCall fc, Hashtable<TempDescriptor, Integer> currtable, boolean isatomic) {
184 MethodDescriptor nodemd=fc.getMethod();
185 Set methodset=fc.getThis()==null?callgraph.getMethods(nodemd):
186 callgraph.getMethods(nodemd, fc.getThis().getType());
187 Integer currreturnval=EITHER; //Start off with the either value
188 for(Iterator methodit=methodset.iterator();methodit.hasNext();) {
189 MethodDescriptor md=(MethodDescriptor) methodit.next();
190 LocalityBinding lb=new LocalityBinding(md, isatomic);
191 for(int i=0;i<fc.numArgs();i++) {
192 TempDescriptor arg=fc.getArg(i);
193 lb.setGlobal(i,currtable.get(arg));
195 if (fc.getThis()!=null) {
196 Integer thistype=currtable.get(fc.getThis());
199 if(thistype.equals(CONFLICT))
200 throw new Error("Using type that can be either local or global in context:\n"+currlb.getExplanation());
201 if(thistype.equals(GLOBAL)&&!isatomic)
202 throw new Error("Using global object outside of transaction in context:\n"+currlb.getExplanation());
203 lb.setGlobalThis(thistype);
205 lb.setGlobalThis(EITHER);//default value
207 if (!discovered.containsKey(lb)) {
208 lb.setGlobalReturn(EITHER);
209 lb.setParent(currlb);
211 discovered.put(lb, lb);
213 lb=discovered.get(lb);
214 Integer returnval=lb.getGlobalReturn();
215 currreturnval=merge(returnval, currreturnval);
216 if (!dependence.containsKey(lb))
217 dependence.put(lb, new HashSet<LocalityBinding>());
218 dependence.get(lb).add(currlb);
220 if (fc.getReturnTemp()!=null) {
221 currtable.put(fc.getReturnTemp(), currreturnval);
225 void processFieldNode(LocalityBinding lb, FlatFieldNode ffn, boolean transaction, Hashtable<TempDescriptor, Integer> currtable) {
226 Integer type=currtable.get(ffn.getSrc());
227 TempDescriptor dst=ffn.getDst();
228 if (type.equals(LOCAL)) {
229 if (ffn.getField().isGlobal())
230 currtable.put(dst,GLOBAL);
232 currtable.put(dst,LOCAL);
233 } else if (type.equals(GLOBAL)) {
235 throw new Error("Global access outside of a transaction in context:\n"+lb.getExplanation());
236 if (ffn.getField().getType().isPrimitive())
237 currtable.put(dst, LOCAL); // primitives are local
239 currtable.put(dst, GLOBAL);
240 } else if (type.equals(EITHER)) {
241 if (ffn.getField().getType().isPrimitive())
242 currtable.put(dst, LOCAL); // primitives are local
244 currtable.put(dst, EITHER);
245 } else if (type.equals(CONFLICT)) {
246 throw new Error("Access to object that could be either global or local in context:\n"+lb.getExplanation());
250 //need to handle primitives
251 void processSetFieldNode(LocalityBinding lb, FlatSetFieldNode fsfn, boolean transaction, Hashtable<TempDescriptor, Integer> currtable) {
252 Integer srctype=currtable.get(fsfn.getSrc());
253 Integer dsttype=currtable.get(fsfn.getDst());
255 if (dsttype.equals(LOCAL)) {
256 if (fsfn.getField().isGlobal()) {
257 if (!(srctype.equals(GLOBAL)||srctype.equals(EITHER)))
258 throw new Error("Writing possible local reference to global field in context: \n"+lb.getExplanation());
260 if (!(srctype.equals(LOCAL)||srctype.equals(EITHER)))
261 throw new Error("Writing possible global reference to local object in context: \n"+lb.getExplanation());
263 } else if (dsttype.equals(GLOBAL)) {
265 throw new Error("Global access outside of a transaction in context:\n"+lb.getExplanation());
266 //okay to store primitives in global object
267 if (srctype.equals(LOCAL) && fsfn.getField().getType().isPrimitive())
269 if (!(srctype.equals(GLOBAL)||srctype.equals(EITHER)))
270 throw new Error("Writing possible local reference to global object in context:\n"+lb.getExplanation());
271 } else if (dsttype.equals(EITHER)) {
272 if (srctype.equals(CONFLICT))
273 throw new Error("Using reference that could be local or global in context:\n"+lb.getExplanation());
274 } else if (dsttype.equals(CONFLICT)) {
275 throw new Error("Access to object that could be either global or local in context:\n"+lb.getExplanation());
279 void processNew(LocalityBinding lb, FlatNew fn, boolean transaction, Hashtable<TempDescriptor, Integer> currtable) {
280 if (fn.isGlobal()&&!transaction) {
281 throw new Error("Allocating global object outside of transaction in context:"+lb.getExplanation());
284 currtable.put(fn.getDst(), GLOBAL);
286 currtable.put(fn.getDst(), LOCAL);
289 void processOpNode(FlatOpNode fon, Hashtable<TempDescriptor, Integer> currtable) {
290 /* Just propagate value */
291 currtable.put(fon.getDest(), currtable.get(fon.getLeft()));
294 void processCastNode(FlatCastNode fcn, Hashtable<TempDescriptor, Integer> currtable) {
295 currtable.put(fcn.getDst(), currtable.get(fcn.getSrc()));
298 void processLiteralNode(FlatLiteralNode fln, Hashtable<TempDescriptor, Integer> currtable) {
300 if (fln.getValue()==null)
301 currtable.put(fln.getDst(), EITHER);
303 currtable.put(fln.getDst(), LOCAL);
306 void processReturnNode(LocalityBinding lb, FlatReturnNode frn, Hashtable<TempDescriptor, Integer> currtable) {
307 if(frn.getReturnTemp()!=null) {
308 Integer returntype=currtable.get(frn.getReturnTemp());
309 lb.setGlobalReturn(merge(returntype, lb.getGlobalReturn()));
313 void processSetElementNode(LocalityBinding lb, FlatSetElementNode fsen, Hashtable<TempDescriptor, Integer> currtable, boolean isatomic) {
314 Integer srctype=currtable.get(fsen.getSrc());
315 Integer dsttype=currtable.get(fsen.getDst());
317 if (dsttype.equals(LOCAL)) {
318 if (!(srctype.equals(LOCAL)||srctype.equals(EITHER)))
319 throw new Error("Writing possible global reference to local object in context:\n"+lb.getExplanation());
320 } else if (dsttype.equals(GLOBAL)) {
321 if (!(srctype.equals(GLOBAL)||srctype.equals(EITHER)))
322 throw new Error("Writing possible local reference to global object in context:\n"+lb.getExplanation());
324 throw new Error("Global access outside of a transaction in context:\n"+lb.getExplanation());
325 } else if (dsttype.equals(EITHER)) {
326 if (srctype.equals(CONFLICT))
327 throw new Error("Using reference that could be local or global in context:\n"+lb.getExplanation());
328 } else if (dsttype.equals(CONFLICT)) {
329 throw new Error("Access to object that could be either global or local in context:\n"+lb.getExplanation());
333 void processElementNode(LocalityBinding lb, FlatElementNode fen, Hashtable<TempDescriptor, Integer> currtable, boolean isatomic) {
334 Integer type=currtable.get(fen.getSrc());
335 TempDescriptor dst=fen.getDst();
336 if (type.equals(LOCAL)) {
337 currtable.put(dst,LOCAL);
338 } else if (type.equals(GLOBAL)) {
340 throw new Error("Global access outside of a transaction in context:\n"+lb.getExplanation());
341 currtable.put(dst, GLOBAL);
342 } else if (type.equals(EITHER)) {
343 currtable.put(dst, EITHER);
344 } else if (type.equals(CONFLICT)) {
345 throw new Error("Access to object that could be either global or local in context:\n"+lb.getExplanation());
349 void processAtomicEnterNode(FlatAtomicEnterNode fen, Hashtable<FlatNode, Integer> atomictable) {
350 int atomic=atomictable.get(fen).intValue();
351 atomictable.put(fen, new Integer(atomic+1));
354 void processAtomicExitNode(FlatAtomicExitNode fen, Hashtable<FlatNode, Integer> atomictable) {
355 int atomic=atomictable.get(fen).intValue();
356 atomictable.put(fen, new Integer(atomic-1));