Docjar: A Java Source and Docuemnt Enginecom.*    java.*    javax.*    org.*    all    new    plug-in

Quick Search    Search Deep

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 }