1
2
3
4 package joeq.Interpreter;
5
6 import java.util.Arrays;
7 import java.util.HashMap;
8 import java.util.HashSet;
9 import java.util.Iterator;
10 import java.util.Map;
11 import java.util.Set;
12 import java.lang.reflect.Constructor;
13 import java.lang.reflect.InvocationTargetException;
14 import java.lang.reflect.Method;
15 import joeq.Class.PrimordialClassLoader;
16 import joeq.Class.jq_Array;
17 import joeq.Class.jq_Class;
18 import joeq.Class.jq_Initializer;
19 import joeq.Class.jq_InstanceMethod;
20 import joeq.Class.jq_Method;
21 import joeq.Class.jq_Primitive;
22 import joeq.Class.jq_Reference;
23 import joeq.Class.jq_StaticMethod;
24 import joeq.Class.jq_Type;
25 import joeq.Compiler.Quad.BasicBlock;
26 import joeq.Compiler.Quad.CodeCache;
27 import joeq.Compiler.Quad.ControlFlowGraph;
28 import joeq.Compiler.Quad.ExceptionHandler;
29 import joeq.Compiler.Quad.Quad;
30 import joeq.Compiler.Quad.RegisterFactory;
31 import joeq.Compiler.Quad.Operand.ParamListOperand;
32 import joeq.Compiler.Quad.RegisterFactory.Register;
33 import joeq.Main.HostedVM;
34 import joeq.Memory.Address;
35 import joeq.Runtime.Reflection;
36 import joeq.UTF.Utf8;
37 import joeq.Util.Templates.ListIterator;
38 import jwutil.collections.Filter;
39 import jwutil.util.Assert;
40 import jwutil.util.Convert;
41
42 /***
43 *
44 * @author John Whaley <jwhaley@alum.mit.edu>
45 * @version $Id: QuadInterpreter.java 2476 2007-02-28 19:14:41Z joewhaley $
46 */
47 public class QuadInterpreter extends joeq.Compiler.Quad.QuadVisitor.EmptyVisitor {
48
49 jq_Method method;
50 Map
51 ControlFlowGraph cfg;
52 RegisterFactory rf;
53 BasicBlock current_bb;
54 ListIterator.Quad current_iterator;
55 Quad current_quad;
56 Object return_value;
57 Throwable thrown, caught;
58
59 public QuadInterpreter(jq_Method m) {
60 registers = new HashMap();
61 method = m;
62 }
63
64 public static boolean TRACE = false;
65
66 public static long num_quads = 0;
67 public static long num_nullchecks = 0;
68
69 public void visitNullCheck(Quad q) { ++num_nullchecks; }
70
71 public void visitQuad(Quad q) {
72 if (TRACE) System.out.println("Registers: "+registers);
73 if (TRACE) System.out.println("Interpreting: "+q);
74 ++num_quads;
75 current_quad = q;
76 q.interpret(this);
77 }
78
79 public void setReturnValue(Object o) { return_value = o; }
80 public Object getReturnValue() { return return_value; }
81 public Throwable getThrown() { return thrown; }
82 public void setThrown(Throwable t) { thrown = t; }
83 public Throwable getCaught() { return caught; }
84
85 public Register getExceptionRegister() { return rf.getOrCreateStack(0, PrimordialClassLoader.getJavaLangObject()); }
86
87 public QuadInterpreter invokeReflective(jq_Method f, ParamListOperand plo) {
88 if (f instanceof jq_StaticMethod)
89 return invokeStaticReflective((jq_StaticMethod)f, plo);
90 else
91 return invokeInstanceReflective((jq_InstanceMethod)f, plo);
92 }
93 public Object[] generateParamArray(jq_Method f, ParamListOperand plo) {
94 int offset = f.isStatic()?0:1;
95 jq_Type[] paramTypes = f.getParamTypes();
96 Object[] param = new Object[plo.length()-offset];
97 for (int i=offset; i<plo.length(); ++i) {
98 if (paramTypes[i] == jq_Primitive.BYTE) {
99 param[i-offset] = new Byte((byte)getReg_I(plo.get(i).getRegister()));
100 } else if (paramTypes[i] == jq_Primitive.CHAR) {
101 param[i-offset] = new Character((char)getReg_I(plo.get(i).getRegister()));
102 } else if (paramTypes[i] == jq_Primitive.SHORT) {
103 param[i-offset] = new Short((short)getReg_I(plo.get(i).getRegister()));
104 } else if (paramTypes[i] == jq_Primitive.BOOLEAN) {
105 param[i-offset] = Convert.getBoolean(getReg_I(plo.get(i).getRegister()) != 0);
106 } else {
107 param[i-offset] = getReg(plo.get(i).getRegister());
108 }
109 }
110 return param;
111 }
112 public QuadInterpreter invokeInstanceReflective(jq_InstanceMethod f, ParamListOperand plo) {
113 QuadInterpreter s = new QuadInterpreter(f);
114 try {
115 Object[] param = generateParamArray(f, plo);
116 if (f instanceof jq_Initializer) {
117 try {
118 Constructor co = (Constructor)Reflection.getJDKMember(f);
119 co.setAccessible(true);
120 UninitializedReference u = (UninitializedReference)getReg_A(plo.get(0).getRegister());
121 Assert._assert(u.k == f.getDeclaringClass(), u.k+" != "+f.getDeclaringClass());
122 Object inited = co.newInstance(param);
123 replaceUninitializedReferences(inited, u);
124 } catch (InstantiationException x) {
125 Assert.UNREACHABLE();
126 } catch (IllegalAccessException x) {
127 Assert.UNREACHABLE();
128 } catch (IllegalArgumentException x) {
129 Assert.UNREACHABLE();
130 } catch (InvocationTargetException x) {
131 handleException(x.getTargetException());
132 }
133 return s;
134 }
135
136 Method m = (Method)Reflection.getJDKMember(f);
137 m.setAccessible(true);
138 Object result = m.invoke(getReg(plo.get(0).getRegister()), param);
139 s.setReturnValue(result);
140 } catch (IllegalAccessException x) {
141 Assert.UNREACHABLE();
142 } catch (IllegalArgumentException x) {
143 Assert.UNREACHABLE();
144 } catch (InvocationTargetException x) {
145 s.setThrown(x.getTargetException());
146 }
147 return s;
148 }
149 public QuadInterpreter invokeStaticReflective(jq_StaticMethod f, ParamListOperand plo) {
150 QuadInterpreter s = new QuadInterpreter(f);
151 if (f == joeq.Runtime.Arrays._multinewarray) {
152
153 int dim = getReg_I(plo.get(0).getRegister());
154 jq_Type t = (jq_Type)getReg_A(plo.get(1).getRegister());
155 int[] dims = new int[dim];
156 for (int i=0; i<dim; ++i)
157 dims[dim-i-1] = getReg_I(plo.get(i+2).getRegister());
158 for (int i=0; i<dims.length; ++i) {
159 t.cls_initialize();
160 t = ((jq_Array)t).getElementType();
161 }
162 try {
163 s.return_value = java.lang.reflect.Array.newInstance(Reflection.getJDKType(t), dims);
164 } catch (Throwable x) {
165 s.setThrown(x);
166 }
167 return s;
168 }
169 Object[] param = generateParamArray(f, plo);
170 try {
171 Method m = (Method)Reflection.getJDKMember(f);
172 m.setAccessible(true);
173 Object result = m.invoke(null, param);
174 s.setReturnValue(result);
175 } catch (IllegalAccessException x) {
176 Assert.UNREACHABLE();
177 } catch (IllegalArgumentException x) {
178 Assert.UNREACHABLE();
179 } catch (InvocationTargetException x) {
180 s.setThrown(x.getTargetException());
181 }
182 return s;
183 }
184
185 static Set bad_methods;
186 static Set bad_classes;
187 public static Filter interpret_filter;
188 static {
189 bad_classes = new HashSet();
190 bad_classes.add(Reflection._class);
191 bad_methods = new HashSet();
192 jq_Class k2 = (jq_Class)PrimordialClassLoader.loader.getOrCreateBSType("Ljava/io/PrintStream;");
193 jq_Method m2 = k2.getOrCreateInstanceMethod("write", "(Ljava/lang/String;)V");
194
195 k2 = (jq_Class)PrimordialClassLoader.loader.getOrCreateBSType("Ljava/io/OutputStreamWriter;");
196 m2 = k2.getOrCreateInstanceMethod("write", "([CII)V");
197 bad_methods.add(m2);
198 bad_methods.add(joeq.Runtime.Arrays._multinewarray);
199 interpret_filter = new Filter() {
200 public boolean isElement(Object o) {
201 jq_Method m = (jq_Method)o;
202 if (m.isNative()) return false;
203 if (m.getBytecode() == null) return false;
204 if (m instanceof jq_Initializer) return false;
205 if (bad_classes.contains(m.getDeclaringClass())) return false;
206 if (bad_methods.contains(m)) return false;
207 return true;
208 }
209 };
210 }
211
212 public QuadInterpreter invokeMethod(jq_Method f, ParamListOperand plo) {
213 if (TRACE) System.out.println("Invoking "+f);
214 jq_Class c = f.getDeclaringClass();
215 c.cls_initialize();
216 if (!interpret_filter.isElement(f))
217 return invokeReflective(f, plo);
218 ControlFlowGraph cfg = CodeCache.getCode(f);
219 QuadInterpreter s = new QuadInterpreter(f);
220 Object[] param = new Object[plo.length()];
221 for (int i=0; i<plo.length(); ++i) {
222 param[i] = getReg(plo.get(i).getRegister());
223 }
224 s.interpretMethod(f, param, cfg.getRegisterFactory(), cfg);
225 if (TRACE) System.out.println("Finished interpreting "+f);
226 return s;
227 }
228
229 public void output() {
230 System.out.println("Quad count: "+num_quads);
231 }
232
233 public void trapOnSystemExit() {
234 SecurityManager sm = new SecurityManager() {
235 public void checkAccept(String host, int port) {}
236 public void checkAccess(Thread t) {}
237 public void checkAccess(ThreadGroup t) {}
238 public void checkAwtEventQueueAccess() {}
239 public void checkConnect(String host, int port) {}
240 public void checkConnect(String host, int port, Object context) {}
241 public void checkCreateClassLoader() {}
242 public void checkDelete(String file) {}
243 public void checkExec(String file) {}
244 public void checkExit(int status) { output(); }
245 public void checkLink(String lib) {}
246 public void checkListen(int port) {}
247 public void checkMemberAccess(Class clazzz, int which) {}
248 public void checkMulticast(java.net.InetAddress maddr) {}
249 public void checkPackageAccess(String pkg) {}
250 public void checkPackageDefinition(String pkg) {}
251 public void checkPermission(java.security.Permission perm) {}
252 public void checkPermission(java.security.Permission perm, Object context) {}
253 public void checkPrintJobAccess() {}
254 public void checkPropertiesAccess() {}
255 public void checkPropertyAccess(String key) {}
256 public void checkRead(java.io.FileDescriptor fd) {}
257 public void checkRead(String file) {}
258 public void checkRead(String file, Object context) {}
259 public void checkSecurityAccess(String target) {}
260 public void checkSetFactory() {}
261 public void checkSystemClipboardAccess() {}
262 public boolean checkTopLevelWindow(Object window) { return true; }
263 public void checkWrite(java.io.FileDescriptor fd) {}
264 public void checkWrite(String file) {}
265 };
266 System.setSecurityManager(sm);
267 }
268
269 public static void main(String[] s_args) throws Throwable {
270 String s = s_args[0];
271 int dotloc = s.lastIndexOf('.');
272 String rootMethodClassName = s.substring(0, dotloc);
273 String rootMethodName = s.substring(dotloc+1);
274
275 HostedVM.initialize();
276
277 jq_Class c = (jq_Class)PrimordialClassLoader.loader.getOrCreateBSType("L"+rootMethodClassName.replace('.','/')+";");
278 c.cls_initialize();
279
280 jq_StaticMethod rootm = null;
281 Utf8 rootm_name = Utf8.get(rootMethodName);
282 for(Iterator it = Arrays.asList(c.getDeclaredStaticMethods()).iterator();
283 it.hasNext(); ) {
284 jq_StaticMethod m = (jq_StaticMethod)it.next();
285 if (m.getName() == rootm_name) {
286 rootm = m;
287 break;
288 }
289 }
290 if (rootm == null)
291 Assert.UNREACHABLE("root method not found: "+rootMethodClassName+"."+rootMethodName);
292 Object[] args = ReflectiveInterpreter.parseMethodArgs(rootm.getParamWords(), rootm.getParamTypes(), s_args, 0);
293
294 QuadInterpreter q = interpretMethod(rootm, args);
295
296 System.out.println(q);
297 }
298
299 public static QuadInterpreter interpretMethod(jq_Method f, Object[] params) {
300 QuadInterpreter s = new QuadInterpreter(f);
301 s.trapOnSystemExit();
302 ControlFlowGraph cfg = CodeCache.getCode(f);
303 try {
304 s.interpretMethod(f, params, cfg.getRegisterFactory(), cfg);
305 } catch (SecurityException x) {}
306 return s;
307 }
308
309 public void interpretMethod(jq_Method m, Object[] params, RegisterFactory rf, ControlFlowGraph cfg) {
310 this.cfg = cfg; this.rf = rf;
311
312 jq_Type[] paramTypes = m.getParamTypes();
313 for (int i=0, j=0; i<paramTypes.length; ++i, ++j) {
314 Register r = rf.getOrCreateLocal(j, paramTypes[i]);
315 registers.put(r, params[i]);
316 if (paramTypes[i].getReferenceSize() == 8) ++j;
317 }
318
319 current_bb = cfg.entry();
320 for (;;) {
321 current_iterator = current_bb.iterator();
322 while (current_iterator.hasNext()) {
323 Quad q = current_iterator.nextQuad();
324 q.accept(this);
325 }
326 if (current_bb.isExit()) break;
327 current_bb = current_bb.getFallthroughSuccessor();
328 }
329 }
330
331 public void branchTo(BasicBlock bb) {
332 if (TRACE) System.out.println("Branching to: "+bb);
333 current_bb = bb;
334 current_iterator = bb.iterator();
335 }
336
337 public void handleException(Throwable x) {
338 jq_Class t = (jq_Class)jq_Reference.getTypeOf(x);
339 t.prepare();
340 ExceptionHandler eh = current_bb.getExceptionHandlers().mustCatch(t);
341 if (eh != null) {
342 caught = x;
343 branchTo(eh.getEntry());
344 if (TRACE) System.out.println("Method "+method+" handler "+eh+" catches "+x);
345 } else {
346 thrown = x;
347 branchTo(cfg.exit());
348 if (TRACE)
349 System.out.println("Method "+method+" does not catch "+x);
350 }
351 }
352
353 public int getReg_I(Register r) { return ((Integer)registers.get(r)).intValue(); }
354 public float getReg_F(Register r) { return ((Float)registers.get(r)).floatValue(); }
355 public long getReg_L(Register r) { return ((Long)registers.get(r)).longValue(); }
356 public double getReg_D(Register r) { return ((Double)registers.get(r)).doubleValue(); }
357 public Object getReg_A(Register r) { return registers.get(r); }
358 public Address getReg_P(Register r) { Assert.TODO(); return null; }
359 public Object getReg(Register r) { return registers.get(r); }
360
361 public void putReg_I(Register r, int i) { registers.put(r, new Integer(i)); }
362 public void putReg_F(Register r, float i) { registers.put(r, new Float(i)); }
363 public void putReg_L(Register r, long i) { registers.put(r, new Long(i)); }
364 public void putReg_D(Register r, double i) { registers.put(r, new Double(i)); }
365 public void putReg_A(Register r, Object i) { registers.put(r, i); }
366 public void putReg_P(Register r, Address i) { Assert.TODO(); }
367 public void putReg(Register r, Object i) { registers.put(r, i); }
368
369 public void replaceUninitializedReferences(Object o, UninitializedReference u) {
370 Iterator i = registers.entrySet().iterator();
371 while (i.hasNext()) {
372 Map.Entry e = (Map.Entry)i.next();
373 if (e.getValue() == u) e.setValue(o);
374 }
375 }
376
377 public String currentLocation() { return method+" "+current_bb+" quad#"+current_quad.getID(); }
378
379 public String toString() {
380 if (thrown != null)
381 return "Thrown exception: "+thrown+" (null checks: "+num_nullchecks+" quad count: "+num_quads+")";
382 return "Returned: "+return_value+" (null checks: "+num_nullchecks+" quad count: "+num_quads+")";
383 }
384
385 public static class UninitializedReference {
386 public jq_Class k;
387 public UninitializedReference(jq_Class k) { this.k = k; }
388 public String toString() { return k+" <uninit>"; }
389 }
390 }