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