Mercurial > hg > truffle
view graal/com.oracle.graal.interpreter/src/com/oracle/graal/interpreter/BytecodeInterpreter.java @ 7530:5e3d1a68664e
applied mx eclipseformat to all Java files
author | Doug Simon <doug.simon@oracle.com> |
---|---|
date | Wed, 23 Jan 2013 16:34:57 +0100 |
parents | 1baf7f1e3f23 |
children |
line wrap: on
line source
/* * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 only, as * published by the Free Software Foundation. * * This code is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * version 2 for more details (a copy is included in the LICENSE file that * accompanied this code). * * You should have received a copy of the GNU General Public License version * 2 along with this work; if not, write to the Free Software Foundation, * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA * or visit www.oracle.com if you need additional information or have any * questions. */ package com.oracle.graal.interpreter; import java.lang.reflect.*; import java.util.*; import com.oracle.graal.api.interpreter.*; import com.oracle.graal.api.meta.*; import com.oracle.graal.api.runtime.*; import com.oracle.graal.bytecode.*; /** * High-level bytecode interpreter that executes on top of Java. Java native methods are executed * using the {@link com.oracle.graal.api.interpreter.RuntimeInterpreterInterface}. */ @SuppressWarnings("static-method") public final class BytecodeInterpreter implements Interpreter { private static final String OPTION_MAX_STACK_SIZE = "maxStackSize"; private static final boolean TRACE = false; private static final boolean TRACE_BYTE_CODE = false; private static final int DEFAULT_MAX_STACK_SIZE = 1500; private static final int NEXT = -1; private static final int BRANCH = -2; private static final int RETURN = -3; private static final int CALL = -4; private InterpreterFrame callFrame; private Map<ResolvedJavaMethod, MethodRedirectionInfo> methodDelegates; private int maxStackFrames; private ResolvedJavaMethod rootMethod; private RuntimeInterpreterInterface runtimeInterface; private MetaAccessProvider metaAccessProvider; public boolean initialize(String args) { methodDelegates = new HashMap<>(); maxStackFrames = DEFAULT_MAX_STACK_SIZE; GraalRuntime runtime = Graal.getRuntime(); this.runtimeInterface = runtime.getCapability(RuntimeInterpreterInterface.class); if (this.runtimeInterface == null) { throw new UnsupportedOperationException("The provided Graal runtime does not support the required capability " + RuntimeInterpreterInterface.class.getName() + "."); } this.metaAccessProvider = runtime.getCapability(MetaAccessProvider.class); if (this.metaAccessProvider == null) { throw new UnsupportedOperationException("The provided Graal runtime does not support the required capability " + MetaAccessProvider.class.getName() + "."); } this.rootMethod = resolveRootMethod(); registerDelegates(); return parseArguments(args); } @Override public void setOption(String name, String value) { if (name != null && name.equals(OPTION_MAX_STACK_SIZE)) { this.maxStackFrames = Integer.parseInt(value); } } private void registerDelegates() { addDelegate(findMethod(Throwable.class, "fillInStackTrace"), new InterpreterCallable() { @Override public Object invoke(InterpreterFrame caller, ResolvedJavaMethod method, Object[] arguments) throws Throwable { setBackTrace(caller, (Throwable) arguments[0], createStackTraceElements(caller, runtimeInterface)); return null; } }); addDelegate(findMethod(Throwable.class, "getStackTraceDepth"), new InterpreterCallable() { @Override public Object invoke(InterpreterFrame caller, ResolvedJavaMethod method, Object[] arguments) throws Throwable { StackTraceElement[] elements = getBackTrace(caller, (Throwable) arguments[0]); if (elements != null) { return elements.length; } return 0; } }); addDelegate(findMethod(Throwable.class, "getStackTraceElement", int.class), new InterpreterCallable() { @Override public Object invoke(InterpreterFrame caller, ResolvedJavaMethod method, Object[] arguments) throws Throwable { StackTraceElement[] elements = getBackTrace(caller, (Throwable) arguments[0]); if (elements != null) { Integer index = (Integer) arguments[0]; if (index != null) { return elements[index]; } } return null; } }); } @SuppressWarnings("unused") private boolean parseArguments(String stringArgs) { // TODO: parse the arguments return true; } public void setMaxStackFrames(int maxStackSize) { this.maxStackFrames = maxStackSize; } public int getMaxStackFrames() { return maxStackFrames; } public void addDelegate(Method method, InterpreterCallable callable) { ResolvedJavaMethod resolvedMethod = metaAccessProvider.lookupJavaMethod(method); if (methodDelegates.containsKey(resolvedMethod)) { throw new IllegalArgumentException("Delegate for method " + method + " already added."); } methodDelegates.put(resolvedMethod, new MethodRedirectionInfo(callable)); } public void removeDelegate(Method method) { methodDelegates.remove(metaAccessProvider.lookupJavaMethod(method)); } @Override public Object execute(ResolvedJavaMethod method, Object... boxedArguments) throws Throwable { try { boolean receiver = hasReceiver(method); Signature signature = method.getSignature(); assert boxedArguments != null; assert signature.getParameterCount(receiver) == boxedArguments.length; if (TRACE) { trace(0, "Executing root method " + method); } InterpreterFrame rootFrame = new InterpreterFrame(rootMethod, signature.getParameterSlots(true)); rootFrame.pushObject(this); rootFrame.pushObject(method); rootFrame.pushObject(boxedArguments); int index = 0; if (receiver) { pushAsObject(rootFrame, Kind.Object, boxedArguments[index]); index++; } for (int i = 0; index < boxedArguments.length; i++, index++) { pushAsObject(rootFrame, signature.getParameterKind(i), boxedArguments[index]); } InterpreterFrame frame = rootFrame.create(method, receiver); executeRoot(rootFrame, frame); return popAsObject(rootFrame, signature.getReturnKind()); } catch (Exception e) { // TODO (chaeubl): remove this exception handler (only used for debugging) throw e; } } public Object execute(Method javaMethod, Object... boxedArguments) throws Throwable { return execute(metaAccessProvider.lookupJavaMethod(javaMethod), boxedArguments); } private boolean hasReceiver(ResolvedJavaMethod method) { return !Modifier.isStatic(method.getModifiers()); } private void executeRoot(InterpreterFrame root, InterpreterFrame frame) throws Throwable { // TODO reflection redirection InterpreterFrame prevFrame = frame; InterpreterFrame currentFrame = frame; BytecodeStream bs = new BytecodeStream(currentFrame.getMethod().getCode()); if (TRACE) { traceCall(frame, "Call"); } while (currentFrame != root) { if (prevFrame != currentFrame) { bs = new BytecodeStream(currentFrame.getMethod().getCode()); } bs.setBCI(currentFrame.getBCI()); prevFrame = currentFrame; currentFrame = loop(root, prevFrame, bs); } assert callFrame == null; } private InterpreterFrame loop(InterpreterFrame root, final InterpreterFrame frame, final BytecodeStream bs) throws Throwable { try { while (true) { int result = executeInstruction(frame, bs); switch (result) { case NEXT: bs.next(); break; case RETURN: return popFrame(frame); case CALL: return allocateFrame(frame, bs); case BRANCH: bs.setBCI(bs.readBranchDest()); break; default: // the outcome depends on stack values assert result >= 0 : "negative branch target"; bs.setBCI(result); break; } } } catch (Throwable t) { if (TRACE) { traceOp(frame, "Exception " + t.toString()); } updateStackTrace(frame, t); // frame bci needs to be in sync when handling exceptions frame.setBCI(bs.currentBCI()); InterpreterFrame handlerFrame = handleThrowable(root, frame, t); if (handlerFrame == null) { // matched root we just throw it again. throw t; } else { if (TRACE) { traceOp(frame, "Handler found " + handlerFrame.getMethod() + ":" + handlerFrame.getBCI()); } // update bci from frame bs.setBCI(handlerFrame.getBCI()); // continue execution on the found frame return handlerFrame; } } finally { // TODO may be not necessary. frame.setBCI(bs.currentBCI()); } } private int executeInstruction(InterpreterFrame frame, BytecodeStream bs) throws Throwable { if (TRACE_BYTE_CODE) { traceOp(frame, bs.currentBCI() + ": " + Bytecodes.baseNameOf(bs.currentBC())); } switch (bs.currentBC()) { case Bytecodes.NOP: break; case Bytecodes.ACONST_NULL: frame.pushObject(null); break; case Bytecodes.ICONST_M1: frame.pushInt(-1); break; case Bytecodes.ICONST_0: frame.pushInt(0); break; case Bytecodes.ICONST_1: frame.pushInt(1); break; case Bytecodes.ICONST_2: frame.pushInt(2); break; case Bytecodes.ICONST_3: frame.pushInt(3); break; case Bytecodes.ICONST_4: frame.pushInt(4); break; case Bytecodes.ICONST_5: frame.pushInt(5); break; case Bytecodes.LCONST_0: frame.pushLong(0L); break; case Bytecodes.LCONST_1: frame.pushLong(1L); break; case Bytecodes.FCONST_0: frame.pushFloat(0.0F); break; case Bytecodes.FCONST_1: frame.pushFloat(1.0F); break; case Bytecodes.FCONST_2: frame.pushFloat(2.0F); break; case Bytecodes.DCONST_0: frame.pushDouble(0.0D); break; case Bytecodes.DCONST_1: frame.pushDouble(1.0D); break; case Bytecodes.BIPUSH: frame.pushInt(bs.readByte()); break; case Bytecodes.SIPUSH: frame.pushInt(bs.readShort()); break; case Bytecodes.LDC: case Bytecodes.LDC_W: case Bytecodes.LDC2_W: pushCPConstant(frame, bs.readCPI()); break; case Bytecodes.ILOAD: frame.pushInt(frame.getInt(frame.resolveLocalIndex(bs.readLocalIndex()))); break; case Bytecodes.LLOAD: frame.pushLong(frame.getLong(frame.resolveLocalIndex(bs.readLocalIndex()))); break; case Bytecodes.FLOAD: frame.pushFloat(frame.getFloat(frame.resolveLocalIndex(bs.readLocalIndex()))); break; case Bytecodes.DLOAD: frame.pushDouble(frame.getDouble(frame.resolveLocalIndex(bs.readLocalIndex()))); break; case Bytecodes.ALOAD: frame.pushObject(frame.getObject(frame.resolveLocalIndex(bs.readLocalIndex()))); break; case Bytecodes.ILOAD_0: frame.pushInt(frame.getInt(frame.resolveLocalIndex(0))); break; case Bytecodes.ILOAD_1: frame.pushInt(frame.getInt(frame.resolveLocalIndex(1))); break; case Bytecodes.ILOAD_2: frame.pushInt(frame.getInt(frame.resolveLocalIndex(2))); break; case Bytecodes.ILOAD_3: frame.pushInt(frame.getInt(frame.resolveLocalIndex(3))); break; case Bytecodes.LLOAD_0: frame.pushLong(frame.getLong(frame.resolveLocalIndex(0))); break; case Bytecodes.LLOAD_1: frame.pushLong(frame.getLong(frame.resolveLocalIndex(1))); break; case Bytecodes.LLOAD_2: frame.pushLong(frame.getLong(frame.resolveLocalIndex(2))); break; case Bytecodes.LLOAD_3: frame.pushLong(frame.getLong(frame.resolveLocalIndex(3))); break; case Bytecodes.FLOAD_0: frame.pushFloat(frame.getFloat(frame.resolveLocalIndex(0))); break; case Bytecodes.FLOAD_1: frame.pushFloat(frame.getFloat(frame.resolveLocalIndex(1))); break; case Bytecodes.FLOAD_2: frame.pushFloat(frame.getFloat(frame.resolveLocalIndex(2))); break; case Bytecodes.FLOAD_3: frame.pushFloat(frame.getFloat(frame.resolveLocalIndex(3))); break; case Bytecodes.DLOAD_0: frame.pushDouble(frame.getDouble(frame.resolveLocalIndex(0))); break; case Bytecodes.DLOAD_1: frame.pushDouble(frame.getDouble(frame.resolveLocalIndex(1))); break; case Bytecodes.DLOAD_2: frame.pushDouble(frame.getDouble(frame.resolveLocalIndex(2))); break; case Bytecodes.DLOAD_3: frame.pushDouble(frame.getDouble(frame.resolveLocalIndex(3))); break; case Bytecodes.ALOAD_0: frame.pushObject(frame.getObject(frame.resolveLocalIndex(0))); break; case Bytecodes.ALOAD_1: frame.pushObject(frame.getObject(frame.resolveLocalIndex(1))); break; case Bytecodes.ALOAD_2: frame.pushObject(frame.getObject(frame.resolveLocalIndex(2))); break; case Bytecodes.ALOAD_3: frame.pushObject(frame.getObject(frame.resolveLocalIndex(3))); break; case Bytecodes.IALOAD: frame.pushInt(runtimeInterface.getArrayInt(frame.popInt(), frame.popObject())); break; case Bytecodes.LALOAD: frame.pushLong(runtimeInterface.getArrayLong(frame.popInt(), frame.popObject())); break; case Bytecodes.FALOAD: frame.pushFloat(runtimeInterface.getArrayFloat(frame.popInt(), frame.popObject())); break; case Bytecodes.DALOAD: frame.pushDouble(runtimeInterface.getArrayDouble(frame.popInt(), frame.popObject())); break; case Bytecodes.AALOAD: frame.pushObject(runtimeInterface.getArrayObject(frame.popInt(), frame.popObject())); break; case Bytecodes.BALOAD: frame.pushInt(runtimeInterface.getArrayByte(frame.popInt(), frame.popObject())); break; case Bytecodes.CALOAD: frame.pushInt(runtimeInterface.getArrayChar(frame.popInt(), frame.popObject())); break; case Bytecodes.SALOAD: frame.pushInt(runtimeInterface.getArrayShort(frame.popInt(), frame.popObject())); break; case Bytecodes.ISTORE: frame.setInt(frame.resolveLocalIndex(bs.readLocalIndex()), frame.popInt()); break; case Bytecodes.LSTORE: frame.setLong(frame.resolveLocalIndex(bs.readLocalIndex()), frame.popLong()); break; case Bytecodes.FSTORE: frame.setFloat(frame.resolveLocalIndex(bs.readLocalIndex()), frame.popFloat()); break; case Bytecodes.DSTORE: frame.setDouble(frame.resolveLocalIndex(bs.readLocalIndex()), frame.popDouble()); break; case Bytecodes.ASTORE: frame.setObject(frame.resolveLocalIndex(bs.readLocalIndex()), frame.popObject()); break; case Bytecodes.ISTORE_0: frame.setInt(frame.resolveLocalIndex(0), frame.popInt()); break; case Bytecodes.ISTORE_1: frame.setInt(frame.resolveLocalIndex(1), frame.popInt()); break; case Bytecodes.ISTORE_2: frame.setInt(frame.resolveLocalIndex(2), frame.popInt()); break; case Bytecodes.ISTORE_3: frame.setInt(frame.resolveLocalIndex(3), frame.popInt()); break; case Bytecodes.LSTORE_0: frame.setLong(frame.resolveLocalIndex(0), frame.popLong()); break; case Bytecodes.LSTORE_1: frame.setLong(frame.resolveLocalIndex(1), frame.popLong()); break; case Bytecodes.LSTORE_2: frame.setLong(frame.resolveLocalIndex(2), frame.popLong()); break; case Bytecodes.LSTORE_3: frame.setLong(frame.resolveLocalIndex(3), frame.popLong()); break; case Bytecodes.FSTORE_0: frame.setFloat(frame.resolveLocalIndex(0), frame.popFloat()); break; case Bytecodes.FSTORE_1: frame.setFloat(frame.resolveLocalIndex(1), frame.popFloat()); break; case Bytecodes.FSTORE_2: frame.setFloat(frame.resolveLocalIndex(2), frame.popFloat()); break; case Bytecodes.FSTORE_3: frame.setFloat(frame.resolveLocalIndex(3), frame.popFloat()); break; case Bytecodes.DSTORE_0: frame.setDouble(frame.resolveLocalIndex(0), frame.popDouble()); break; case Bytecodes.DSTORE_1: frame.setDouble(frame.resolveLocalIndex(1), frame.popDouble()); break; case Bytecodes.DSTORE_2: frame.setDouble(frame.resolveLocalIndex(2), frame.popDouble()); break; case Bytecodes.DSTORE_3: frame.setDouble(frame.resolveLocalIndex(3), frame.popDouble()); break; case Bytecodes.ASTORE_0: frame.setObject(frame.resolveLocalIndex(0), frame.popObject()); break; case Bytecodes.ASTORE_1: frame.setObject(frame.resolveLocalIndex(1), frame.popObject()); break; case Bytecodes.ASTORE_2: frame.setObject(frame.resolveLocalIndex(2), frame.popObject()); break; case Bytecodes.ASTORE_3: frame.setObject(frame.resolveLocalIndex(3), frame.popObject()); break; case Bytecodes.IASTORE: runtimeInterface.setArrayInt(frame.popInt(), frame.popInt(), frame.popObject()); break; case Bytecodes.LASTORE: runtimeInterface.setArrayLong(frame.popLong(), frame.popInt(), frame.popObject()); break; case Bytecodes.FASTORE: runtimeInterface.setArrayFloat(frame.popFloat(), frame.popInt(), frame.popObject()); break; case Bytecodes.DASTORE: runtimeInterface.setArrayDouble(frame.popDouble(), frame.popInt(), frame.popObject()); break; case Bytecodes.AASTORE: runtimeInterface.setArrayObject(frame.popObject(), frame.popInt(), frame.popObject()); break; case Bytecodes.BASTORE: runtimeInterface.setArrayByte((byte) frame.popInt(), frame.popInt(), frame.popObject()); break; case Bytecodes.CASTORE: runtimeInterface.setArrayChar((char) frame.popInt(), frame.popInt(), frame.popObject()); break; case Bytecodes.SASTORE: runtimeInterface.setArrayShort((short) frame.popInt(), frame.popInt(), frame.popObject()); break; case Bytecodes.POP: frame.popVoid(1); break; case Bytecodes.POP2: frame.popVoid(2); break; case Bytecodes.DUP: frame.dup(1); break; case Bytecodes.DUP_X1: frame.dupx1(); break; case Bytecodes.DUP_X2: frame.dupx2(); break; case Bytecodes.DUP2: frame.dup(2); break; case Bytecodes.DUP2_X1: frame.dup2x1(); break; case Bytecodes.DUP2_X2: frame.dup2x2(); break; case Bytecodes.SWAP: frame.swapSingle(); break; case Bytecodes.IADD: frame.pushInt(frame.popInt() + frame.popInt()); break; case Bytecodes.LADD: frame.pushLong(frame.popLong() + frame.popLong()); break; case Bytecodes.FADD: frame.pushFloat(frame.popFloat() + frame.popFloat()); break; case Bytecodes.DADD: frame.pushDouble(frame.popDouble() + frame.popDouble()); break; case Bytecodes.ISUB: frame.pushInt(-frame.popInt() + frame.popInt()); break; case Bytecodes.LSUB: frame.pushLong(-frame.popLong() + frame.popLong()); break; case Bytecodes.FSUB: frame.pushFloat(-frame.popFloat() + frame.popFloat()); break; case Bytecodes.DSUB: frame.pushDouble(-frame.popDouble() + frame.popDouble()); break; case Bytecodes.IMUL: frame.pushInt(frame.popInt() * frame.popInt()); break; case Bytecodes.LMUL: frame.pushLong(frame.popLong() * frame.popLong()); break; case Bytecodes.FMUL: frame.pushFloat(frame.popFloat() * frame.popFloat()); break; case Bytecodes.DMUL: frame.pushDouble(frame.popDouble() * frame.popDouble()); break; case Bytecodes.IDIV: divInt(frame); break; case Bytecodes.LDIV: divLong(frame); break; case Bytecodes.FDIV: divFloat(frame); break; case Bytecodes.DDIV: divDouble(frame); break; case Bytecodes.IREM: remInt(frame); break; case Bytecodes.LREM: remLong(frame); break; case Bytecodes.FREM: remFloat(frame); break; case Bytecodes.DREM: remDouble(frame); break; case Bytecodes.INEG: frame.pushInt(-frame.popInt()); break; case Bytecodes.LNEG: frame.pushLong(-frame.popLong()); break; case Bytecodes.FNEG: frame.pushFloat(-frame.popFloat()); break; case Bytecodes.DNEG: frame.pushDouble(-frame.popDouble()); break; case Bytecodes.ISHL: shiftLeftInt(frame); break; case Bytecodes.LSHL: shiftLeftLong(frame); break; case Bytecodes.ISHR: shiftRightSignedInt(frame); break; case Bytecodes.LSHR: shiftRightSignedLong(frame); break; case Bytecodes.IUSHR: shiftRightUnsignedInt(frame); break; case Bytecodes.LUSHR: shiftRightUnsignedLong(frame); break; case Bytecodes.IAND: frame.pushInt(frame.popInt() & frame.popInt()); break; case Bytecodes.LAND: frame.pushLong(frame.popLong() & frame.popLong()); break; case Bytecodes.IOR: frame.pushInt(frame.popInt() | frame.popInt()); break; case Bytecodes.LOR: frame.pushLong(frame.popLong() | frame.popLong()); break; case Bytecodes.IXOR: frame.pushInt(frame.popInt() ^ frame.popInt()); break; case Bytecodes.LXOR: frame.pushLong(frame.popLong() ^ frame.popLong()); break; case Bytecodes.IINC: iinc(frame, bs); break; case Bytecodes.I2L: frame.pushLong(frame.popInt()); break; case Bytecodes.I2F: frame.pushFloat(frame.popInt()); break; case Bytecodes.I2D: frame.pushDouble(frame.popInt()); break; case Bytecodes.L2I: frame.pushInt((int) frame.popLong()); break; case Bytecodes.L2F: frame.pushFloat(frame.popLong()); break; case Bytecodes.L2D: frame.pushDouble(frame.popLong()); break; case Bytecodes.F2I: frame.pushInt((int) frame.popFloat()); break; case Bytecodes.F2L: frame.pushLong((long) frame.popFloat()); break; case Bytecodes.F2D: frame.pushDouble(frame.popFloat()); break; case Bytecodes.D2I: frame.pushInt((int) frame.popDouble()); break; case Bytecodes.D2L: frame.pushLong((long) frame.popDouble()); break; case Bytecodes.D2F: frame.pushFloat((float) frame.popDouble()); break; case Bytecodes.I2B: frame.pushInt((byte) frame.popInt()); break; case Bytecodes.I2C: frame.pushInt((char) frame.popInt()); break; case Bytecodes.I2S: frame.pushInt((short) frame.popInt()); break; case Bytecodes.LCMP: compareLong(frame); break; case Bytecodes.FCMPL: compareFloatLess(frame); break; case Bytecodes.FCMPG: compareFloatGreater(frame); break; case Bytecodes.DCMPL: compareDoubleLess(frame); break; case Bytecodes.DCMPG: compareDoubleGreater(frame); break; case Bytecodes.IFEQ: if (frame.popInt() == 0) { return BRANCH; } break; case Bytecodes.IFNE: if (frame.popInt() != 0) { return BRANCH; } break; case Bytecodes.IFLT: if (frame.popInt() < 0) { return BRANCH; } break; case Bytecodes.IFGE: if (frame.popInt() >= 0) { return BRANCH; } break; case Bytecodes.IFGT: if (frame.popInt() > 0) { return BRANCH; } break; case Bytecodes.IFLE: if (frame.popInt() <= 0) { return BRANCH; } break; case Bytecodes.IF_ICMPEQ: if (frame.popInt() == frame.popInt()) { return BRANCH; } break; case Bytecodes.IF_ICMPNE: if (frame.popInt() != frame.popInt()) { return BRANCH; } break; case Bytecodes.IF_ICMPLT: if (frame.popInt() > frame.popInt()) { return BRANCH; } break; case Bytecodes.IF_ICMPGE: if (frame.popInt() <= frame.popInt()) { return BRANCH; } break; case Bytecodes.IF_ICMPGT: if (frame.popInt() < frame.popInt()) { return BRANCH; } break; case Bytecodes.IF_ICMPLE: if (frame.popInt() >= frame.popInt()) { return BRANCH; } break; case Bytecodes.IF_ACMPEQ: if (frame.popObject() == frame.popObject()) { return BRANCH; } break; case Bytecodes.IF_ACMPNE: if (frame.popObject() != frame.popObject()) { return BRANCH; } break; case Bytecodes.GOTO: case Bytecodes.GOTO_W: return BRANCH; case Bytecodes.JSR: case Bytecodes.JSR_W: frame.pushInt(bs.currentBCI()); return BRANCH; case Bytecodes.RET: return frame.getInt(frame.resolveLocalIndex(bs.readLocalIndex())); case Bytecodes.TABLESWITCH: return tableSwitch(frame, bs); case Bytecodes.LOOKUPSWITCH: return lookupSwitch(frame, bs); case Bytecodes.IRETURN: frame.getParentFrame().pushInt(frame.popInt()); return RETURN; case Bytecodes.LRETURN: frame.getParentFrame().pushLong(frame.popLong()); return RETURN; case Bytecodes.FRETURN: frame.getParentFrame().pushFloat(frame.popFloat()); return RETURN; case Bytecodes.DRETURN: frame.getParentFrame().pushDouble(frame.popDouble()); return RETURN; case Bytecodes.ARETURN: frame.getParentFrame().pushObject(frame.popObject()); return RETURN; case Bytecodes.RETURN: return RETURN; case Bytecodes.GETSTATIC: getField(frame, null, bs.currentBC(), bs.readCPI()); break; case Bytecodes.PUTSTATIC: putStatic(frame, bs.readCPI()); break; case Bytecodes.GETFIELD: getField(frame, nullCheck(frame.popObject()), bs.currentBC(), bs.readCPI()); break; case Bytecodes.PUTFIELD: putField(frame, bs.readCPI()); break; case Bytecodes.INVOKEVIRTUAL: callFrame = invokeVirtual(frame, bs.readCPI()); if (callFrame == null) { break; } return CALL; case Bytecodes.INVOKESPECIAL: callFrame = invokeSpecial(frame, bs.readCPI()); if (callFrame == null) { break; } return CALL; case Bytecodes.INVOKESTATIC: callFrame = invokeStatic(frame, bs.readCPI()); if (callFrame == null) { break; } return CALL; case Bytecodes.INVOKEINTERFACE: callFrame = invokeInterface(frame, bs.readCPI()); if (callFrame == null) { break; } return CALL; case Bytecodes.XXXUNUSEDXXX: assert false : "unused bytecode used. behaviour unspecified."; // nop break; case Bytecodes.NEW: frame.pushObject(allocateInstance(frame, bs.readCPI())); break; case Bytecodes.NEWARRAY: frame.pushObject(allocateNativeArray(frame, bs.readByte())); break; case Bytecodes.ANEWARRAY: frame.pushObject(allocateArray(frame, bs.readCPI())); break; case Bytecodes.ARRAYLENGTH: frame.pushInt(Array.getLength(nullCheck(frame.popObject()))); break; case Bytecodes.ATHROW: Throwable t = (Throwable) frame.popObject(); if ("break".equals(t.getMessage())) { t.printStackTrace(); } throw t; case Bytecodes.CHECKCAST: checkCast(frame, bs.readCPI()); break; case Bytecodes.INSTANCEOF: instanceOf(frame, bs.readCPI()); break; case Bytecodes.MONITORENTER: runtimeInterface.monitorEnter(frame.popObject()); break; case Bytecodes.MONITOREXIT: runtimeInterface.monitorExit(frame.popObject()); break; case Bytecodes.WIDE: assert false; break; case Bytecodes.MULTIANEWARRAY: frame.pushObject(allocateMultiArray(frame, bs.readCPI(), bs.readUByte(bs.currentBCI() + 3))); break; case Bytecodes.IFNULL: if (frame.popObject() == null) { return BRANCH; } break; case Bytecodes.IFNONNULL: if (frame.popObject() != null) { return BRANCH; } break; case Bytecodes.BREAKPOINT: assert false : "no breakpoints supported at this time."; break; // nop } return NEXT; } private InterpreterFrame handleThrowable(InterpreterFrame root, InterpreterFrame frame, Throwable t) { ExceptionHandler handler; InterpreterFrame currentFrame = frame; do { handler = resolveExceptionHandlers(currentFrame, currentFrame.getBCI(), t); if (handler == null) { // no handler found pop frame // and continue searching currentFrame = popFrame(currentFrame); } else { // found a handler -> execute it currentFrame.setBCI(handler.getHandlerBCI()); currentFrame.popStack(); currentFrame.pushObject(t); return currentFrame; } } while (handler == null && currentFrame != root); // will throw exception up the interpreter return null; } private void updateStackTrace(InterpreterFrame frame, Throwable t) { StackTraceElement[] elements = getBackTrace(frame, t); if (elements != null) { setStackTrace(frame, t, elements); setBackTrace(frame, t, null); } else { setBackTrace(frame, t, createStackTraceElements(frame, runtimeInterface)); } } private void setStackTrace(InterpreterFrame frame, Throwable t, StackTraceElement[] stackTrace) { runtimeInterface.setFieldObject(stackTrace, t, findThrowableField(frame, "stackTrace")); } private StackTraceElement[] getBackTrace(InterpreterFrame frame, Throwable t) { Object value = runtimeInterface.getFieldObject(t, findThrowableField(frame, "backtrace")); if (value instanceof StackTraceElement[]) { return (StackTraceElement[]) value; } return null; } private void setBackTrace(InterpreterFrame frame, Throwable t, StackTraceElement[] backtrace) { runtimeInterface.setFieldObject(backtrace, t, findThrowableField(frame, "backtrace")); } private ExceptionHandler resolveExceptionHandlers(InterpreterFrame frame, int bci, Throwable t) { ExceptionHandler[] handlers = frame.getMethod().getExceptionHandlers(); for (int i = 0; i < handlers.length; i++) { ExceptionHandler handler = handlers[i]; if (bci >= handler.getStartBCI() && bci <= handler.getEndBCI()) { ResolvedJavaType catchType = null; if (!handler.isCatchAll()) { // exception handlers are similar to instanceof bytecodes, so we pass instanceof catchType = resolveType(frame, Bytecodes.INSTANCEOF, (char) handler.catchTypeCPI()); } if (catchType == null || catchType.isInstance(Constant.forObject(t))) { // the first found exception handler is our exception handler return handler; } } } return null; } private Class<?> mirror(ResolvedJavaType type) { return runtimeInterface.getMirror(type); } private InterpreterFrame allocateFrame(InterpreterFrame frame, BytecodeStream bs) { try { InterpreterFrame nextFrame = this.callFrame; assert nextFrame != null; assert nextFrame.getParentFrame() == frame; // store bci when leaving method frame.setBCI(bs.currentBCI()); if (TRACE) { traceCall(nextFrame, "Call"); } if (Modifier.isSynchronized(nextFrame.getMethod().getModifiers())) { if (TRACE) { traceOp(frame, "Method monitor enter"); } if (Modifier.isStatic(nextFrame.getMethod().getModifiers())) { runtimeInterface.monitorEnter(mirror(nextFrame.getMethod().getDeclaringClass())); } else { Object enterObject = nextFrame.getObject(frame.resolveLocalIndex(0)); assert enterObject != null; runtimeInterface.monitorEnter(enterObject); } } return nextFrame; } finally { callFrame = null; bs.next(); } } private InterpreterFrame popFrame(InterpreterFrame frame) { InterpreterFrame parent = frame.getParentFrame(); if (Modifier.isSynchronized(frame.getMethod().getModifiers())) { if (TRACE) { traceOp(frame, "Method monitor exit"); } if (Modifier.isStatic(frame.getMethod().getModifiers())) { runtimeInterface.monitorExit(mirror(frame.getMethod().getDeclaringClass())); } else { Object exitObject = frame.getObject(frame.resolveLocalIndex(0)); if (exitObject != null) { runtimeInterface.monitorExit(exitObject); } } } if (TRACE) { traceCall(frame, "Ret"); } frame.dispose(); return parent; } private void traceOp(InterpreterFrame frame, String opName) { trace(frame.depth(), opName); } private void traceCall(InterpreterFrame frame, String type) { trace(frame.depth(), type + " " + frame.getMethod() + " - " + frame.getMethod().getSignature()); } private void trace(int level, String message) { StringBuilder builder = new StringBuilder(); for (int i = 0; i < level; i++) { builder.append(" "); } builder.append(message); System.out.println(builder); } private void divInt(InterpreterFrame frame) { int dividend = frame.popInt(); int divisor = frame.popInt(); frame.pushInt(divisor / dividend); } private void divLong(InterpreterFrame frame) { long dividend = frame.popLong(); long divisor = frame.popLong(); frame.pushLong(divisor / dividend); } private void divFloat(InterpreterFrame frame) { float dividend = frame.popFloat(); float divisor = frame.popFloat(); frame.pushFloat(divisor / dividend); } private void divDouble(InterpreterFrame frame) { double dividend = frame.popDouble(); double divisor = frame.popDouble(); frame.pushDouble(divisor / dividend); } private void remInt(InterpreterFrame frame) { int dividend = frame.popInt(); int divisor = frame.popInt(); frame.pushInt(divisor % dividend); } private void remLong(InterpreterFrame frame) { long dividend = frame.popLong(); long divisor = frame.popLong(); frame.pushLong(divisor % dividend); } private void remFloat(InterpreterFrame frame) { float dividend = frame.popFloat(); float divisor = frame.popFloat(); frame.pushFloat(divisor % dividend); } private void remDouble(InterpreterFrame frame) { double dividend = frame.popDouble(); double divisor = frame.popDouble(); frame.pushDouble(divisor % dividend); } private void shiftLeftInt(InterpreterFrame frame) { int bits = frame.popInt(); int value = frame.popInt(); frame.pushInt(value << bits); } private void shiftLeftLong(InterpreterFrame frame) { int bits = frame.popInt(); long value = frame.popLong(); frame.pushLong(value << bits); } private void shiftRightSignedInt(InterpreterFrame frame) { int bits = frame.popInt(); int value = frame.popInt(); frame.pushInt(value >> bits); } private void shiftRightSignedLong(InterpreterFrame frame) { int bits = frame.popInt(); long value = frame.popLong(); frame.pushLong(value >> bits); } private void shiftRightUnsignedInt(InterpreterFrame frame) { int bits = frame.popInt(); int value = frame.popInt(); frame.pushInt(value >>> bits); } private void shiftRightUnsignedLong(InterpreterFrame frame) { int bits = frame.popInt(); long value = frame.popLong(); frame.pushLong(value >>> bits); } private int lookupSwitch(InterpreterFrame frame, BytecodeStream bs) { return lookupSearch(new BytecodeLookupSwitch(bs, bs.currentBCI()), frame.popInt()); } /** * Binary search implementation for the lookup switch. */ private int lookupSearch(BytecodeLookupSwitch switchHelper, int key) { int low = 0; int high = switchHelper.numberOfCases() - 1; while (low <= high) { int mid = (low + high) >>> 1; int midVal = switchHelper.keyAt(mid); if (midVal < key) { low = mid + 1; } else if (midVal > key) { high = mid - 1; } else { return switchHelper.bci() + switchHelper.offsetAt(mid); // key found } } return switchHelper.defaultTarget(); // key not found. } private int tableSwitch(InterpreterFrame frame, BytecodeStream bs) { BytecodeTableSwitch switchHelper = new BytecodeTableSwitch(bs, bs.currentBCI()); int low = switchHelper.lowKey(); int high = switchHelper.highKey(); assert low <= high; int index = frame.popInt(); if (index < low || index > high) { return switchHelper.defaultTarget(); } else { return switchHelper.targetAt(index - low); } } private void checkCast(InterpreterFrame frame, char cpi) { frame.pushObject(mirror(resolveType(frame, Bytecodes.CHECKCAST, cpi)).cast(frame.popObject())); } private ResolvedJavaType resolveType(InterpreterFrame frame, int opcode, char cpi) { ConstantPool constantPool = frame.getConstantPool(); constantPool.loadReferencedType(cpi, opcode); return constantPool.lookupType(cpi, opcode).resolve(frame.getMethod().getDeclaringClass()); } private ResolvedJavaType resolveType(InterpreterFrame frame, Class<?> javaClass) { return metaAccessProvider.lookupJavaType(javaClass).resolve(frame.getMethod().getDeclaringClass()); } private ResolvedJavaMethod resolveMethod(InterpreterFrame frame, int opcode, char cpi) { ConstantPool constantPool = frame.getConstantPool(); constantPool.loadReferencedType(cpi, opcode); return (ResolvedJavaMethod) constantPool.lookupMethod(cpi, opcode); } private ResolvedJavaField resolveField(InterpreterFrame frame, int opcode, char cpi) { ConstantPool constantPool = frame.getConstantPool(); constantPool.loadReferencedType(cpi, opcode); return (ResolvedJavaField) constantPool.lookupField(cpi, opcode); } private void instanceOf(InterpreterFrame frame, char cpi) { frame.pushInt(resolveType(frame, Bytecodes.INSTANCEOF, cpi).isInstance(Constant.forObject(frame.popObject())) ? 1 : 0); } private void pushCPConstant(InterpreterFrame frame, char cpi) { ResolvedJavaMethod method = frame.getMethod(); Object constant = method.getConstantPool().lookupConstant(cpi); if (constant instanceof Constant) { Constant c = ((Constant) constant); switch (c.getKind()) { case Int: frame.pushInt(c.asInt()); break; case Float: frame.pushFloat(c.asFloat()); break; case Object: frame.pushObject(c.asObject()); break; case Double: frame.pushDouble(c.asDouble()); break; case Long: frame.pushLong(c.asLong()); break; default: assert false : "unspecified case"; } } else if (constant instanceof JavaType) { frame.pushObject(mirror(((JavaType) constant).resolve(method.getDeclaringClass()))); } else { assert false : "unexpected case"; } } private void compareLong(InterpreterFrame frame) { long y = frame.popLong(); long x = frame.popLong(); frame.pushInt((x < y) ? -1 : ((x == y) ? 0 : 1)); } private void compareDoubleGreater(InterpreterFrame frame) { double y = frame.popDouble(); double x = frame.popDouble(); frame.pushInt(x < y ? -1 : ((x == y) ? 0 : 1)); } private void compareDoubleLess(InterpreterFrame frame) { double y = frame.popDouble(); double x = frame.popDouble(); frame.pushInt(x > y ? 1 : ((x == y) ? 0 : -1)); } private void compareFloatGreater(InterpreterFrame frame) { float y = frame.popFloat(); float x = frame.popFloat(); frame.pushInt(x < y ? -1 : ((x == y) ? 0 : 1)); } private void compareFloatLess(InterpreterFrame frame) { float y = frame.popFloat(); float x = frame.popFloat(); frame.pushInt(x > y ? 1 : ((x == y) ? 0 : -1)); } private Object nullCheck(Object value) { if (value == null) { throw new NullPointerException(); } return value; } private InterpreterFrame invokeStatic(InterpreterFrame frame, char cpi) throws Throwable { return invoke(frame, resolveMethod(frame, Bytecodes.INVOKESTATIC, cpi), null); } private InterpreterFrame invokeInterface(InterpreterFrame frame, char cpi) throws Throwable { return resolveAndInvoke(frame, resolveMethod(frame, Bytecodes.INVOKEINTERFACE, cpi)); } private InterpreterFrame resolveAndInvoke(InterpreterFrame parent, ResolvedJavaMethod m) throws Throwable { Object receiver = nullCheck(parent.peekReceiver(m)); ResolvedJavaMethod method = resolveType(parent, receiver.getClass()).resolveMethod(m); if (method == null) { throw new AbstractMethodError(); } return invoke(parent, method, receiver); } private InterpreterFrame invokeVirtual(InterpreterFrame frame, char cpi) throws Throwable { ResolvedJavaMethod m = resolveMethod(frame, Bytecodes.INVOKEVIRTUAL, cpi); if (Modifier.isFinal(m.getModifiers())) { return invoke(frame, m, nullCheck(frame.peekReceiver(m))); } else { return resolveAndInvoke(frame, m); } } private InterpreterFrame invokeSpecial(InterpreterFrame frame, char cpi) throws Throwable { ResolvedJavaMethod m = resolveMethod(frame, Bytecodes.INVOKESPECIAL, cpi); return invoke(frame, m, nullCheck(frame.peekReceiver(m))); } private Object[] popArgumentsAsObject(InterpreterFrame frame, ResolvedJavaMethod method, boolean hasReceiver) { Signature signature = method.getSignature(); int argumentCount = method.getSignature().getParameterCount(hasReceiver); Object[] parameters = new Object[argumentCount]; int lastSignatureIndex = hasReceiver ? 1 : 0; for (int i = argumentCount - 1; i >= lastSignatureIndex; i--) { ResolvedJavaType type = signature.getParameterType(i - lastSignatureIndex, method.getDeclaringClass()).resolve(method.getDeclaringClass()); parameters[i] = popAsObject(frame, type.getKind()); } if (hasReceiver) { parameters[0] = frame.popObject(); } return parameters; } private InterpreterFrame invoke(InterpreterFrame caller, ResolvedJavaMethod method, Object receiver) throws Throwable { if (caller.depth() >= maxStackFrames) { throw new StackOverflowError("Maximum callstack of " + maxStackFrames + " exceeded."); } if (Modifier.isNative(method.getModifiers())) { return invokeNativeMethodViaVM(caller, method, receiver != null); } else { MethodRedirectionInfo redirectedMethod = methodDelegates.get(method); if (redirectedMethod != null) { return invokeRedirectedMethodViaVM(caller, method, redirectedMethod, receiver != null); } else { return invokeOptimized(caller, method, receiver != null); } } } private InterpreterFrame invokeNativeMethodViaVM(InterpreterFrame caller, ResolvedJavaMethod method, boolean hasReceiver) throws Throwable { assert !methodDelegates.containsKey(method) : "must not be redirected"; if (TRACE) { traceCall(caller, "Native " + method); } // mark the current thread as high level and execute the native method Object[] parameters = popArgumentsAsObject(caller, method, hasReceiver); Object returnValue = runtimeInterface.invoke(method, parameters); pushAsObject(caller, method.getSignature().getReturnKind(), returnValue); return null; } private InterpreterFrame invokeRedirectedMethodViaVM(InterpreterFrame caller, ResolvedJavaMethod originalMethod, MethodRedirectionInfo redirectionInfo, boolean hasReceiver) throws Throwable { assert methodDelegates.containsKey(originalMethod) : "must be redirected"; if (TRACE) { traceCall(caller, "Delegate " + originalMethod); } // current thread is low level and we also execute the target method in the low-level // interpreter Object[] originalCalleeParameters = popArgumentsAsObject(caller, originalMethod, hasReceiver); Object[] parameters = new Object[]{caller, originalMethod, originalCalleeParameters}; Object returnValue = redirectionInfo.getTargetMethod().invoke(redirectionInfo.getReceiver(), parameters); pushAsObject(caller, originalMethod.getSignature().getReturnKind(), returnValue); return null; } private InterpreterFrame invokeOptimized(InterpreterFrame parent, ResolvedJavaMethod method, boolean hasReceiver) throws Throwable { return parent.create(method, hasReceiver); } private Object allocateMultiArray(InterpreterFrame frame, char cpi, int dimension) { ResolvedJavaType type = getLastDimensionType(resolveType(frame, Bytecodes.MULTIANEWARRAY, cpi)); int[] dimensions = new int[dimension]; for (int i = dimension - 1; i >= 0; i--) { dimensions[i] = frame.popInt(); } return Array.newInstance(mirror(type), dimensions); } private ResolvedJavaType getLastDimensionType(ResolvedJavaType type) { ResolvedJavaType result = type; while (result.isArray()) { result = result.getComponentType(); } return result; } private Object allocateArray(InterpreterFrame frame, char cpi) { ResolvedJavaType type = resolveType(frame, Bytecodes.ANEWARRAY, cpi); return Array.newInstance(runtimeInterface.getMirror(type), frame.popInt()); } private Object allocateNativeArray(InterpreterFrame frame, byte cpi) { // the constants for the cpi are loosely defined and no real cpi indices. switch (cpi) { case 4: return new byte[frame.popInt()]; case 8: return new byte[frame.popInt()]; case 5: return new char[frame.popInt()]; case 7: return new double[frame.popInt()]; case 6: return new float[frame.popInt()]; case 10: return new int[frame.popInt()]; case 11: return new long[frame.popInt()]; case 9: return new short[frame.popInt()]; default: assert false : "unexpected case"; return null; } } private Object allocateInstance(InterpreterFrame frame, char cpi) throws InstantiationException { return runtimeInterface.newObject(resolveType(frame, Bytecodes.NEW, cpi)); } private void iinc(InterpreterFrame frame, BytecodeStream bs) { int index = frame.resolveLocalIndex(bs.readLocalIndex()); frame.setInt(index, frame.getInt(index) + bs.readIncrement()); } private void putStatic(InterpreterFrame frame, char cpi) { putFieldStatic(frame, resolveField(frame, Bytecodes.PUTSTATIC, cpi)); } private void putField(InterpreterFrame frame, char cpi) { putFieldVirtual(frame, resolveField(frame, Bytecodes.PUTFIELD, cpi)); } private void putFieldStatic(InterpreterFrame frame, ResolvedJavaField field) { switch (field.getKind()) { case Boolean: case Byte: case Char: case Short: case Int: runtimeInterface.setFieldInt(frame.popInt(), null, field); break; case Double: runtimeInterface.setFieldDouble(frame.popDouble(), null, field); break; case Float: runtimeInterface.setFieldFloat(frame.popFloat(), null, field); break; case Long: runtimeInterface.setFieldLong(frame.popLong(), null, field); break; case Object: runtimeInterface.setFieldObject(frame.popObject(), null, field); break; default: assert false : "unexpected case"; } } private void putFieldVirtual(InterpreterFrame frame, ResolvedJavaField field) { switch (field.getKind()) { case Boolean: case Byte: case Char: case Short: case Int: runtimeInterface.setFieldInt(frame.popInt(), nullCheck(frame.popObject()), field); break; case Double: runtimeInterface.setFieldDouble(frame.popDouble(), nullCheck(frame.popObject()), field); break; case Float: runtimeInterface.setFieldFloat(frame.popFloat(), nullCheck(frame.popObject()), field); break; case Long: runtimeInterface.setFieldLong(frame.popLong(), nullCheck(frame.popObject()), field); break; case Object: runtimeInterface.setFieldObject(frame.popObject(), nullCheck(frame.popObject()), field); break; default: assert false : "unexpected case"; } } private void getField(InterpreterFrame frame, Object base, int opcode, char cpi) { ResolvedJavaField field = resolveField(frame, opcode, cpi); switch (field.getKind()) { case Boolean: frame.pushInt(runtimeInterface.getFieldBoolean(base, field) ? 1 : 0); break; case Byte: frame.pushInt(runtimeInterface.getFieldByte(base, field)); break; case Char: frame.pushInt(runtimeInterface.getFieldChar(base, field)); break; case Short: frame.pushInt(runtimeInterface.getFieldShort(base, field)); break; case Int: frame.pushInt(runtimeInterface.getFieldInt(base, field)); break; case Double: frame.pushDouble(runtimeInterface.getFieldDouble(base, field)); break; case Float: frame.pushFloat(runtimeInterface.getFieldFloat(base, field)); break; case Long: frame.pushLong(runtimeInterface.getFieldLong(base, field)); break; case Object: frame.pushObject(runtimeInterface.getFieldObject(base, field)); break; default: assert false : "unexpected case"; } } private int pushAsObject(InterpreterFrame frame, Kind typeKind, Object value) { switch (typeKind) { case Int: frame.pushInt((int) value); break; case Long: frame.pushLong((long) value); return 2; case Boolean: frame.pushInt(((boolean) value) ? 1 : 0); break; case Byte: frame.pushInt((byte) value); break; case Char: frame.pushInt((char) value); break; case Double: frame.pushDouble((double) value); return 2; case Float: frame.pushFloat((float) value); break; case Short: frame.pushInt((short) value); break; case Object: frame.pushObject(value); break; case Void: return 0; default: assert false : "case not specified"; } return 1; } private Object popAsObject(InterpreterFrame frame, Kind typeKind) { switch (typeKind) { case Boolean: return frame.popInt() == 1 ? true : false; case Byte: return (byte) frame.popInt(); case Char: return (char) frame.popInt(); case Double: return frame.popDouble(); case Int: return frame.popInt(); case Float: return frame.popFloat(); case Long: return frame.popLong(); case Short: return (short) frame.popInt(); case Object: return frame.popObject(); case Void: return null; default: assert false : "unexpected case"; } return null; } private ResolvedJavaMethod resolveRootMethod() { try { return metaAccessProvider.lookupJavaMethod(BytecodeInterpreter.class.getDeclaredMethod("execute", Method.class, Object[].class)); } catch (Exception e) { throw new RuntimeException(e); } } private static Method findMethod(Class<?> clazz, String name, Class<?>... parameters) { try { return clazz.getDeclaredMethod(name, parameters); } catch (Exception e) { throw new RuntimeException(e); } } private static StackTraceElement[] createStackTraceElements(InterpreterFrame frame, RuntimeInterpreterInterface runtimeInterface) { InterpreterFrame tmp = frame; List<StackTraceElement> elements = new ArrayList<>(); boolean first = false; // filter only first stack elements while (tmp != null) { if (first || !filterStackElement(tmp, runtimeInterface)) { first = true; elements.add(tmp.getMethod().asStackTraceElement(tmp.getBCI())); } tmp = tmp.getParentFrame(); } return elements.toArray(new StackTraceElement[elements.size()]); } private static boolean filterStackElement(InterpreterFrame frame, RuntimeInterpreterInterface runtimeInterface) { return Throwable.class.isAssignableFrom(runtimeInterface.getMirror(frame.getMethod().getDeclaringClass())); } private ResolvedJavaField findThrowableField(InterpreterFrame frame, String name) { ResolvedJavaType throwableType = resolveType(frame, Throwable.class); ResolvedJavaField[] fields = throwableType.getInstanceFields(false); for (int i = 0; i < fields.length; i++) { if (fields[i].getName().equals(name)) { return fields[i]; } } assert false; return null; } private class MethodRedirectionInfo { private InterpreterCallable receiver; private Method method; public MethodRedirectionInfo(InterpreterCallable instance) { this.receiver = instance; this.method = resolveMethod(instance); } public InterpreterCallable getReceiver() { return receiver; } public Method getTargetMethod() { return method; } private Method resolveMethod(InterpreterCallable instance) { try { return instance.getClass().getMethod(InterpreterCallable.INTERPRETER_CALLABLE_INVOKE_NAME, InterpreterCallable.INTERPRETER_CALLABLE_INVOKE_SIGNATURE); } catch (NoSuchMethodException e) { throw new InterpreterException(e); } catch (SecurityException e) { throw new InterpreterException(e); } } } }