1
2
3
4
5
6
7
8
9
10 package nl.tudelft.simulation.dsol.interpreter;
11
12 import java.io.IOException;
13 import java.io.InputStream;
14 import java.lang.reflect.AccessibleObject;
15 import java.lang.reflect.Constructor;
16 import java.lang.reflect.Method;
17 import java.lang.reflect.Modifier;
18 import java.util.Properties;
19 import java.util.Stack;
20 import java.util.logging.Level;
21
22 import nl.tudelft.simulation.dsol.interpreter.classfile.ClassDescriptor;
23 import nl.tudelft.simulation.dsol.interpreter.classfile.Constant;
24 import nl.tudelft.simulation.dsol.interpreter.classfile.MethodDescriptor;
25 import nl.tudelft.simulation.dsol.interpreter.operations.InvokeOperation;
26 import nl.tudelft.simulation.dsol.interpreter.operations.JumpOperation;
27 import nl.tudelft.simulation.dsol.interpreter.operations.RET;
28 import nl.tudelft.simulation.dsol.interpreter.operations.RETURN;
29 import nl.tudelft.simulation.dsol.interpreter.operations.ReturnOperation;
30 import nl.tudelft.simulation.dsol.interpreter.operations.VoidOperation;
31 import nl.tudelft.simulation.dsol.interpreter.operations.WIDE;
32 import nl.tudelft.simulation.language.io.URLResource;
33 import nl.tudelft.simulation.language.reflection.ClassUtil;
34 import nl.tudelft.simulation.logger.Logger;
35
36 /***
37 * A Interpreter <br>
38 * (c) copyright 2003 <a href="http://www.simulation.tudelft.nl">Delft
39 * University of Technology </a>, the Netherlands. <br>
40 * See for project information <a
41 * href="http://www.simulation.tudelft.nl">www.simulation.tudelft.nl </a> <br>
42 * License of use: <a href="http://www.gnu.org/copyleft/gpl.html">General Public
43 * License (GPL) </a>, no warranty <br>
44 *
45 * @version 1.0 Jan 13, 2004 <br>
46 * @author <a href="http://www.simulation.tudelft.nl/people/jacobs.html">Peter
47 * Jacobs </a>
48 */
49 public class Interpreter
50 {
51
52 /*** Let's resolve the logLevel to use. */
53 static
54 {
55 try
56 {
57 InputStream stream = URLResource
58 .getResourceAsStream("/interpreter.properties");
59 if (stream != null)
60 {
61 Properties properties = new Properties();
62 properties.load(stream);
63 Logger.setLogLevel(Level.parse(properties
64 .getProperty("interpreter.logLevel")));
65 }
66 } catch (Exception exception)
67 {
68 Logger.warning(MethodDescriptor.class, "<clinit>", exception);
69 }
70 }
71
72 /***
73 * constructs a new Interpreter
74 */
75 protected Interpreter()
76 {
77 super();
78 }
79
80 /***
81 * creates a frame for a method
82 *
83 * @param object the object on which the method must be invoked
84 * @param method the method or constructor
85 * @param arguments the arguments
86 * @return Frame the result
87 * @throws ClassNotFoundException whenever the classpath is incomplete
88 * @throws IOException on IOException
89 */
90 public static Frame createFrame(final Object object,
91 final AccessibleObject method, final Object[] arguments)
92 throws ClassNotFoundException, IOException
93 {
94 Object[] args = new Object[0];
95 if (arguments != null)
96 {
97 args = arguments;
98 }
99 ClassDescriptor classDescriptor = null;
100 int modifiers = -1;
101 Class[] parameterTypes = null;
102 if (method instanceof Method)
103 {
104 parameterTypes = ((Method) method).getParameterTypes();
105 classDescriptor = ClassDescriptor.get(((Method) method)
106 .getDeclaringClass());
107 modifiers = ((Method) method).getModifiers();
108 } else
109 {
110 parameterTypes = ((Constructor) method).getParameterTypes();
111 classDescriptor = ClassDescriptor.get(((Constructor) method)
112 .getDeclaringClass());
113 modifiers = ((Constructor) method).getModifiers();
114 }
115 MethodDescriptor methodDescriptor = classDescriptor.getMethod(method);
116 OperandStack operandStack = new OperandStack(methodDescriptor
117 .getMaxStack());
118 LocalVariable[] localVariables = LocalVariable
119 .newInstance(methodDescriptor.getLocalVariableTable());
120 int counter = 0;
121
122
123 if (!Modifier.isStatic(modifiers))
124 {
125 localVariables[counter++].setValue(object);
126 }
127
128
129 for (int i = 0; i < args.length; i++)
130 {
131 localVariables[counter++].setValue(arguments[i]);
132 if ((parameterTypes[i].equals(double.class))
133 || (parameterTypes[i].equals(long.class)))
134 {
135 counter++;
136 }
137 }
138
139 if (Logger.getLogLevel().intValue() <= Level.FINER.intValue())
140 {
141 String logMessage = methodDescriptor.getMethod().toString()
142 + "\n"
143 + Operation.toString(methodDescriptor, methodDescriptor
144 .getOperations());
145 Logger.finer(Interpreter.class, "createFrame", logMessage);
146 }
147
148 return new Frame(classDescriptor.getConstantPool(), localVariables,
149 methodDescriptor.getOperations(), operandStack,
150 methodDescriptor);
151 }
152
153 /***
154 * interprets the frameStack
155 *
156 * @param frameStack the frameStack of the interpreter
157 * @return Object the return value of the invoked method
158 * @throws InterpreterException on failure
159 */
160 public static Object interpret(final Stack frameStack)
161 throws InterpreterException
162 {
163 Frame frame = (Frame) frameStack.peek();
164 OperandStack operandStack = frame.getOperandStack();
165 Constant[] constantPool = frame.getConstantPool();
166 LocalVariable[] localVariables = frame.getLocalVariables();
167 MethodDescriptor methodDescriptor = frame.getMethodDescriptor();
168 int operationIndex = frame.getReturnPosition();
169 boolean log = Logger.getLogLevel().intValue() <= Level.FINEST
170 .intValue();
171
172 while (true)
173 {
174 Operation operation = frame.getOperations()[operationIndex];
175
176
177 if (log)
178 {
179 Logger
180 .finest(Interpreter.class, "interpret", ""
181 + operandStack);
182 Logger.finest(Interpreter.class, "interpret", ""
183 + frameStack.size() + " " + operation);
184 }
185
186
187 if (operation instanceof WIDE)
188 {
189 operation = ((WIDE) operation).getTarget();
190 }
191
192
193 if (operation instanceof VoidOperation)
194 {
195 ((VoidOperation) operation).execute(operandStack, constantPool,
196 localVariables);
197 operationIndex++;
198 continue;
199 }
200
201
202 if (operation instanceof InvokeOperation)
203 {
204 Frame childFrame = ((InvokeOperation) operation).execute(frame);
205 operationIndex++;
206 if (childFrame != null)
207 {
208 frame.setReturnPosition(operationIndex);
209 if (frame.isPaused())
210 {
211 return frame;
212 }
213 frame = childFrame;
214 frameStack.push(frame);
215 operandStack = frame.getOperandStack();
216 constantPool = frame.getConstantPool();
217 localVariables = frame.getLocalVariables();
218 methodDescriptor = frame.getMethodDescriptor();
219 operationIndex = 0;
220 }
221 continue;
222 }
223
224
225 if (operation instanceof JumpOperation)
226 {
227 int offset = ((JumpOperation) operation).execute(operandStack,
228 constantPool, localVariables);
229 int bytePosition = offset;
230 if (!(operation instanceof RET))
231 {
232 bytePosition = bytePosition
233 + methodDescriptor.getBytePosition(operationIndex);
234 }
235 operationIndex = methodDescriptor
236 .getOperationIndex(bytePosition);
237 continue;
238 }
239
240
241 if (operation instanceof ReturnOperation)
242 {
243 Object result = ((ReturnOperation) operation).execute(frame);
244
245
246 frameStack.pop();
247
248
249 if (frameStack.isEmpty())
250 {
251 return result;
252 }
253 frame = (Frame) frameStack.peek();
254 operandStack = frame.getOperandStack();
255 constantPool = frame.getConstantPool();
256 localVariables = frame.getLocalVariables();
257 methodDescriptor = frame.getMethodDescriptor();
258 operationIndex = frame.getReturnPosition();
259
260 if (!(operation instanceof RETURN))
261 {
262 operandStack.push(result);
263 }
264 }
265 }
266 }
267
268 /***
269 * interpretes the invocation of a method on an object
270 *
271 * @param object the object on which the method must be invoked
272 * @param methodName the methodName
273 * @param arguments the arguments
274 * @param argumentTypes the classes of the arguments
275 * @return Object the result
276 */
277 public static Object invoke(final Object object, final String methodName,
278 final Object[] arguments, final Class[] argumentTypes)
279 {
280 try
281 {
282 AccessibleObject method = null;
283 if (!methodName.equals("<init>"))
284 {
285 if (object instanceof Class)
286 {
287 method = ClassUtil.resolveMethod((Class) object,
288 methodName, argumentTypes);
289 } else
290 {
291 method = ClassUtil.resolveMethod(object.getClass(),
292 methodName, argumentTypes);
293 }
294 } else
295 {
296 method = object.getClass()
297 .getDeclaredConstructor(argumentTypes);
298 }
299 return Interpreter.invoke(object, method, arguments);
300 } catch (Exception exception)
301 {
302 throw new InterpreterException(exception);
303 }
304 }
305
306 /***
307 * interpretes the invocation of a method on an object
308 *
309 * @param object the object on which the method must be invoked
310 * @param method the method
311 * @param arguments the arguments
312 * @return Object the result
313 * @throws InterpreterException on failure
314 */
315 public static Object invoke(final Object object,
316 final AccessibleObject method, final Object[] arguments)
317 throws InterpreterException
318 {
319 if (Logger.getLogLevel().intValue() <= Level.FINE.intValue())
320 {
321 Logger.fine(Interpreter.class, "invoke", method.toString());
322 }
323 try
324 {
325 if (method instanceof Constructor
326 && Modifier.isNative(((Constructor) method).getModifiers()))
327 {
328 return ((Constructor) method).newInstance(arguments);
329 }
330 if (method instanceof Method
331 && Modifier.isNative(((Method) method).getModifiers()))
332 {
333 return ((Method) method).invoke(object, arguments);
334 }
335 Stack frameStack = new Stack();
336 frameStack.push(Interpreter.createFrame(object, method, arguments));
337
338 return Interpreter.interpret(frameStack);
339 } catch (Exception exception)
340 {
341 throw new InterpreterException(exception);
342 }
343 }
344 }