View Javadoc

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 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/*<Register, Object>*/ registers;
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             // special case
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         //bad_methods.add(m2);
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         // initialize parameters
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         // start interpretation
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 }