diff --git a/jode/jode/jvm/Interpreter.java b/jode/jode/jvm/Interpreter.java new file mode 100644 index 0000000..6ef1fcf --- /dev/null +++ b/jode/jode/jvm/Interpreter.java @@ -0,0 +1,812 @@ +/* + * Opcodes (c) 1998 Jochen Hoenicke + * + * You may distribute under the terms of the GNU General Public License. + * + * IN NO EVENT SHALL JOCHEN HOENICKE BE LIABLE TO ANY PARTY FOR DIRECT, + * INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT OF + * THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF JOCHEN HOENICKE + * HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * JOCHEN HOENICKE SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A + * PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS ON AN "AS IS" + * BASIS, AND JOCHEN HOENICKE HAS NO OBLIGATION TO PROVIDE MAINTENANCE, + * SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. + * + * $Id$ + */ +package jode.jvm; +import jode.bytecode.*; +import java.lang.reflect.*; + +/** + * This class is a java virtual machine written in java :-). Well not + * exactly. It does only handle a subset of the opcodes and is mainly + * written do deobfuscate Strings. + * + * @author Jochen Hoenicke + */ +public class Interpreter implements Opcodes { + public static Object interpretMethod + (ClassInfo currentClass, byte[] code, Value[] locals, Value[] stack) + throws InterpreterException, ClassFormatException { + try { + ConstantPool cpool = currentClass.getConstantPool(); + int pc = 0; + int stacktop = 0; + for(;;) { + int opcode = code[pc++] & 0xff; + switch (opcode) { + case opc_nop: + break; + case opc_aconst_null: + stack[stacktop++].setObject(null); + break; + case opc_iconst_m1: + case opc_iconst_0: case opc_iconst_1: case opc_iconst_2: + case opc_iconst_3: case opc_iconst_4: case opc_iconst_5: + stack[stacktop++].setInt(opcode - opc_iconst_0); + break; + case opc_lconst_0: case opc_lconst_1: + stack[stacktop++].setLong(opcode - opc_lconst_0); + break; + case opc_fconst_0: case opc_fconst_1: case opc_fconst_2: + stack[stacktop++].setFloat(opcode - opc_fconst_0); + break; + case opc_dconst_0: case opc_dconst_1: + stack[stacktop++].setDouble(opcode - opc_dconst_0); + break; + case opc_bipush: + stack[stacktop++].setInt(code[pc++]); + break; + case opc_sipush: + stack[stacktop++].setInt((code[pc++] << 8) + | (code[pc++] & 0xff)); + break; + case opc_ldc: + stack[stacktop++].setObject + (cpool.getConstant(code[pc++] & 0xff)); + break; + case opc_ldc_w: + case opc_ldc2_w: { + int index = (code[pc++] << 8) & 0xff00 | code[pc++] & 0xff; + stack[stacktop++].setObject(cpool.getConstant(index)); + break; + } + case opc_iload: case opc_lload: + case opc_fload: case opc_dload: case opc_aload: + stack[stacktop++].setValue(locals[code[pc++]]); + break; + case opc_iload_0: case opc_iload_1: + case opc_iload_2: case opc_iload_3: + case opc_lload_0: case opc_lload_1: + case opc_lload_2: case opc_lload_3: + case opc_fload_0: case opc_fload_1: + case opc_fload_2: case opc_fload_3: + case opc_dload_0: case opc_dload_1: + case opc_dload_2: case opc_dload_3: + case opc_aload_0: case opc_aload_1: + case opc_aload_2: case opc_aload_3: + stack[stacktop++].setValue(locals[(opcode - opc_iload_0) & 3]); + break; + case opc_iaload: case opc_laload: + case opc_faload: case opc_daload: case opc_aaload: + case opc_baload: case opc_caload: case opc_saload: { + int index = stack[--stacktop].intValue(); + Object array = stack[--stacktop].objectValue(); + switch(opcode) { + case opc_baload: + stack[stacktop++].setInt(((byte[])array)[index]); + break; + case opc_caload: + stack[stacktop++].setInt(((char[])array)[index]); + break; + case opc_saload: + stack[stacktop++].setInt(((short[])array)[index]); + break; + case opc_iaload: + stack[stacktop++].setInt(((int[])array)[index]); + break; + case opc_laload: + stack[stacktop++].setLong(((long[])array)[index]); + break; + case opc_faload: + stack[stacktop++].setFloat(((float[])array)[index]); + break; + case opc_daload: + stack[stacktop++].setDouble(((double[])array)[index]); + break; + case opc_aaload: + stack[stacktop++].setObject(((Object[])array)[index]); + break; + } + break; + } + case opc_istore: case opc_lstore: + case opc_fstore: case opc_dstore: case opc_astore: + locals[code[pc++]].setValue(stack[--stacktop]); + break; + case opc_istore_0: case opc_istore_1: + case opc_istore_2: case opc_istore_3: + case opc_lstore_0: case opc_lstore_1: + case opc_lstore_2: case opc_lstore_3: + case opc_fstore_0: case opc_fstore_1: + case opc_fstore_2: case opc_fstore_3: + case opc_dstore_0: case opc_dstore_1: + case opc_dstore_2: case opc_dstore_3: + case opc_astore_0: case opc_astore_1: + case opc_astore_2: case opc_astore_3: + locals[(opcode-opc_istore_0) & 3].setValue(stack[--stacktop]); + break; + case opc_iastore: case opc_lastore: + case opc_fastore: case opc_dastore: case opc_aastore: + case opc_bastore: case opc_castore: case opc_sastore: { + Value value = stack[--stacktop]; + int index = stack[--stacktop].intValue(); + Object array = stack[--stacktop].objectValue(); + switch(opcode) { + case opc_baload: + ((byte[])array)[index] = (byte) value.intValue(); + break; + case opc_caload: + ((char[])array)[index] = (char) value.intValue(); + break; + case opc_saload: + ((short[])array)[index] = (short) value.intValue(); + break; + case opc_iaload: + ((int[])array)[index] = value.intValue(); + break; + case opc_laload: + ((long[])array)[index] = value.longValue(); + break; + case opc_faload: + ((float[])array)[index] = value.floatValue(); + break; + case opc_daload: + ((double[])array)[index] = value.doubleValue(); + break; + case opc_aaload: + ((Object[])array)[index] = value.objectValue(); + break; + } + break; + } + case opc_pop: case opc_pop2: + stacktop -= opcode - (opc_pop-1); + break; + case opc_dup: case opc_dup_x1: case opc_dup_x2: { + int depth = (opcode - opc_dup)%3; + for (int i=0; i < depth+1; i++) + stack[stacktop+1-i].setValue(stack[stacktop-i]); + stack[stacktop-depth].setValue(stack[stacktop]); + stacktop++; + break; + } + case opc_dup2: case opc_dup2_x1: case opc_dup2_x2: { + int depth = (opcode - opc_dup)%3; + for (int i=0; i < depth+2; i++) + stack[stacktop+2-i] = stack[stacktop-i]; + stack[stacktop-depth].setValue(stack[stacktop+1]); + stack[stacktop-depth-1].setValue(stack[stacktop]); + stacktop += 2; + } + case opc_swap: { + Value tmp = stack[stacktop-1]; + stack[stacktop-1] = stack[stacktop-2]; + stack[stacktop-2] = tmp; + } + case opc_iadd: + stack[stacktop-2].setInt(stack[stacktop-2].intValue() + + stack[stacktop-1].intValue()); + stacktop--; + break; + case opc_isub: + stack[stacktop-2].setInt(stack[stacktop-2].intValue() + - stack[stacktop-1].intValue()); + stacktop--; + break; + case opc_imul: + stack[stacktop-2].setInt(stack[stacktop-2].intValue() + * stack[stacktop-1].intValue()); + stacktop--; + break; + case opc_idiv: + stack[stacktop-2].setInt(stack[stacktop-2].intValue() + / stack[stacktop-1].intValue()); + stacktop--; + break; + case opc_irem: + stack[stacktop-2].setInt(stack[stacktop-2].intValue() + % stack[stacktop-1].intValue()); + stacktop--; + break; + + case opc_ladd: + stack[stacktop-2].setLong(stack[stacktop-2].longValue() + + stack[stacktop-1].longValue()); + stacktop--; + break; + case opc_lsub: + stack[stacktop-2].setLong(stack[stacktop-2].longValue() + - stack[stacktop-1].longValue()); + stacktop--; + break; + case opc_lmul: + stack[stacktop-2].setLong(stack[stacktop-2].longValue() + * stack[stacktop-1].longValue()); + stacktop--; + break; + case opc_ldiv: + stack[stacktop-2].setLong(stack[stacktop-2].longValue() + / stack[stacktop-1].longValue()); + stacktop--; + break; + case opc_lrem: + stack[stacktop-2].setLong(stack[stacktop-2].longValue() + % stack[stacktop-1].longValue()); + stacktop--; + break; + + case opc_fadd: + stack[stacktop-2].setFloat(stack[stacktop-2].floatValue() + + stack[stacktop-1].floatValue()); + stacktop--; + break; + case opc_fsub: + stack[stacktop-2].setFloat(stack[stacktop-2].floatValue() + - stack[stacktop-1].floatValue()); + stacktop--; + break; + case opc_fmul: + stack[stacktop-2].setFloat(stack[stacktop-2].floatValue() + * stack[stacktop-1].floatValue()); + stacktop--; + break; + case opc_fdiv: + stack[stacktop-2].setFloat(stack[stacktop-2].floatValue() + / stack[stacktop-1].floatValue()); + stacktop--; + break; + case opc_frem: + stack[stacktop-2].setFloat(stack[stacktop-2].floatValue() + % stack[stacktop-1].floatValue()); + stacktop--; + break; + + case opc_dadd: + stack[stacktop-2].setDouble(stack[stacktop-2].doubleValue() + + stack[stacktop-1].doubleValue()); + stacktop--; + break; + case opc_dsub: + stack[stacktop-2].setDouble(stack[stacktop-2].doubleValue() + - stack[stacktop-1].doubleValue()); + stacktop--; + break; + case opc_dmul: + stack[stacktop-2].setDouble(stack[stacktop-2].doubleValue() + * stack[stacktop-1].doubleValue()); + stacktop--; + break; + case opc_ddiv: + stack[stacktop-2].setDouble(stack[stacktop-2].doubleValue() + / stack[stacktop-1].doubleValue()); + stacktop--; + break; + case opc_drem: + stack[stacktop-2].setDouble(stack[stacktop-2].doubleValue() + % stack[stacktop-1].doubleValue()); + stacktop--; + break; + + case opc_ineg: + stack[stacktop-1].setInt(-stack[stacktop-1].intValue()); + break; + case opc_lneg: + stack[stacktop-1].setLong(-stack[stacktop-1].longValue()); + break; + case opc_fneg: + stack[stacktop-1].setFloat(-stack[stacktop-1].floatValue()); + break; + case opc_dneg: + stack[stacktop-1].setDouble(-stack[stacktop-1].doubleValue()); + break; + + case opc_ishl: + stack[stacktop-2].setInt(stack[stacktop-2].intValue() + << stack[stacktop-1].intValue()); + stacktop--; + break; + case opc_ishr: + stack[stacktop-2].setInt(stack[stacktop-2].intValue() + >> stack[stacktop-1].intValue()); + stacktop--; + break; + case opc_iushr: + stack[stacktop-2].setInt(stack[stacktop-2].intValue() + >>> stack[stacktop-1].intValue()); + stacktop--; + break; + case opc_iand: + stack[stacktop-2].setInt(stack[stacktop-2].intValue() + & stack[stacktop-1].intValue()); + stacktop--; + break; + case opc_ior : + stack[stacktop-2].setInt(stack[stacktop-2].intValue() + | stack[stacktop-1].intValue()); + stacktop--; + break; + case opc_ixor: + stack[stacktop-2].setInt(stack[stacktop-2].intValue() + ^ stack[stacktop-1].intValue()); + stacktop--; + break; + + case opc_lshl: + stack[stacktop-2].setLong(stack[stacktop-2].longValue() + << stack[stacktop-1].longValue()); + stacktop--; + break; + case opc_lshr: + stack[stacktop-2].setLong(stack[stacktop-2].longValue() + >> stack[stacktop-1].longValue()); + stacktop--; + break; + case opc_lushr: + stack[stacktop-2].setLong(stack[stacktop-2].longValue() + >>> stack[stacktop-1].longValue()); + stacktop--; + break; + case opc_land: + stack[stacktop-2].setLong(stack[stacktop-2].longValue() + & stack[stacktop-1].longValue()); + stacktop--; + break; + case opc_lor : + stack[stacktop-2].setLong(stack[stacktop-2].longValue() + | stack[stacktop-1].longValue()); + stacktop--; + break; + case opc_lxor: + stack[stacktop-2].setLong(stack[stacktop-2].longValue() + ^ stack[stacktop-1].longValue()); + stacktop--; + break; + + case opc_iinc: { + int slot = code[pc++] & 0xff; + locals[slot].setInt(locals[slot].intValue() + code[pc++]); + break; + } + case opc_i2l: + stack[stacktop-1] + .setLong((long)stack[stacktop-1].intValue()); + break; + case opc_i2f: + stack[stacktop-1] + .setFloat((float)stack[stacktop-1].intValue()); + break; + case opc_i2d: + stack[stacktop-1] + .setDouble((double)stack[stacktop-1].intValue()); + break; + + case opc_l2i: + stack[stacktop-1] + .setInt((int)stack[stacktop-1].longValue()); + break; + case opc_l2f: + stack[stacktop-1] + .setFloat((float)stack[stacktop-1].longValue()); + break; + case opc_l2d: + stack[stacktop-1] + .setDouble((double)stack[stacktop-1].longValue()); + break; + + case opc_f2i: + stack[stacktop-1] + .setInt((int)stack[stacktop-1].floatValue()); + break; + case opc_f2l: + stack[stacktop-1] + .setLong((long)stack[stacktop-1].floatValue()); + break; + case opc_f2d: + stack[stacktop-1] + .setDouble((double)stack[stacktop-1].floatValue()); + break; + + case opc_d2i: + stack[stacktop-1] + .setInt((int)stack[stacktop-1].doubleValue()); + break; + case opc_d2l: + stack[stacktop-1] + .setLong((long)stack[stacktop-1].doubleValue()); + break; + case opc_d2f: + stack[stacktop-1] + .setFloat((float)stack[stacktop-1].doubleValue()); + break; + + case opc_i2b: + stack[stacktop-1] + .setInt((byte)stack[stacktop-1].intValue()); + break; + case opc_i2c: + stack[stacktop-1] + .setInt((char)stack[stacktop-1].intValue()); + break; + case opc_i2s: + stack[stacktop-1] + .setInt((short)stack[stacktop-1].intValue()); + break; + case opc_lcmp: { + long val1 = stack[stacktop-2].longValue(); + long val2 = stack[--stacktop].longValue(); + stack[stacktop-1].setInt + (val1 == val2 ? 0 : val1 < val2 ? -1 : 1); + break; + } + case opc_fcmpl: case opc_fcmpg: { + float val1 = stack[stacktop-2].floatValue(); + float val2 = stack[--stacktop].floatValue(); + stack[stacktop-1].setInt + (val1 == val2 ? 0 + : ( opcode == opc_fcmpg + ? (val1 < val2 ? -1 : 1) + : (val1 > val2 ? 1 : -1))); + break; + } + case opc_dcmpl: case opc_dcmpg: { + double val1 = stack[stacktop-2].doubleValue(); + double val2 = stack[--stacktop].doubleValue(); + stack[stacktop-1].setInt + (val1 == val2 ? 0 + : ( opcode == opc_dcmpg + ? (val1 < val2 ? -1 : 1) + : (val1 > val2 ? 1 : -1))); + break; + } + case opc_ifeq: case opc_ifne: + case opc_iflt: case opc_ifge: + case opc_ifgt: case opc_ifle: + case opc_if_icmpeq: case opc_if_icmpne: + case opc_if_icmplt: case opc_if_icmpge: + case opc_if_icmpgt: case opc_if_icmple: + case opc_if_acmpeq: case opc_if_acmpne: + case opc_ifnull: case opc_ifnonnull: { + int value; + if (opcode >= opc_if_acmpeq) { + if (opcode >= opc_ifnull) { + value = + stack[--stacktop].objectValue() == null ? 0 : 1; + opcode += opc_ifeq - opc_ifnull; + } else { + value = + stack[--stacktop].objectValue() + == stack[--stacktop].objectValue() ? 0 : 1; + opcode += opc_ifeq - opc_if_acmpeq; + } + } else { + value = stack[--stacktop].intValue(); + if (opcode >= opc_if_icmpeq) { + int val1 = stack[--stacktop].intValue(); + value = (val1 == value ? 0 + : val1 < value ? -1 : 1); + opcode += opc_ifeq - opc_if_icmpeq; + } + } + int offset = ((code[pc++] << 8) | (code[pc++] & 0xff)) - 3; + if (value > 0 && (opcode == opc_ifgt || opcode == opc_ifge) + || value < 0 && (opcode == opc_iflt || opcode == opc_ifle) + || value == 0 && (opcode == opc_ifge || opcode == opc_ifle + || opcode == opc_ifeq)) + pc += opcode; + break; + } + case opc_jsr: + stack[stacktop++].setObject(new ReturnAddress(pc)); + /* fall through */ + case opc_goto: + pc = (pc-1) + ((code[pc] << 8) | (code[pc+1] & 0xff)); + break; + case opc_ret: + pc = ((ReturnAddress) locals[code[pc] & 0xff].objectValue()) + .getPC(); + break; + case opc_tableswitch: { + int value = stack[--stacktop].intValue(); + int start = pc - 1; + pc += 3-(start % 4); + int dest = ((code[pc++] << 8) | (code[pc++] & 0xff)); + int low = ((code[pc++] << 8) | (code[pc++] & 0xff)); + int high = ((code[pc++] << 8) | (code[pc++] & 0xff)); + if (value >= low && value <= high) { + pc += (value - low) << 1; + dest = ((code[pc] << 8) | (code[pc+1] & 0xff)); + } + pc = start + dest; + break; + } + case opc_lookupswitch: { + int value = stack[--stacktop].intValue(); + int start = pc - 1; + pc += 3-(start % 4); + int dest = ((code[pc++] << 8) | (code[pc++] & 0xff)); + int npairs = ((code[pc++] << 8) | (code[pc++] & 0xff)); + for (int i=0; i < npairs; i++) { + if (value == ((code[pc++] << 8) | (code[pc++] & 0xff))) { + dest = ((code[pc++] << 8) | (code[pc++] & 0xff)); + break; + } + pc+=2; + } + pc = start + dest; + break; + } + case opc_ireturn: case opc_lreturn: + case opc_freturn: case opc_dreturn: case opc_areturn: + return stack[--stacktop].objectValue(); + case opc_return: + return Void.TYPE; + case opc_getstatic: + case opc_getfield: + case opc_putstatic: + case opc_putfield: + throw new InterpreterException + ("Implement get/put-static/field?"); + case opc_invokevirtual: + case opc_invokespecial: + case opc_invokestatic : + case opc_invokeinterface: { + String[] ref = cpool.getRef((code[pc++] << 8) & 0xff00 + | code[pc++] & 0xff); + int argcount= (opcode == opc_invokeinterface) + ? (code[pc++] << 8) | (code[pc++] & 0xff) : -1; + +// if (ref[0] == currentClass.getName()) { +// /* invoke interpreter again */ +// } else { + Class clazz; + try { + clazz = Class.forName + (cpool.getClassName((code[pc++] << 8) & 0xff00 + | code[pc++] & 0xff) + .replace('/','.')); + } catch (ClassNotFoundException ex) { + throw new InterpreterException + ("Class "+ref[0]+" not found"); + } + try { + if (ref[1].equals("")) { + Constructor[] cs = clazz.getConstructors(); + Constructor c = null; + for (int i=0; i< cs.length; i++) { + /* check types XXX */ + c = cs[i]; + break; + } + if (c == null) + throw new InterpreterException("Constructor " + +ref[0]+"." + +ref[1]+" not found."); + Object[] args + = new Object[c.getParameterTypes().length]; + for (int i=args.length - 1; i >= 0; i--) + args[i] = stack[--stacktop].objectValue(); + NewObject newObj = + (NewObject) stack[--stacktop].objectValue(); + if (!newObj.getClass().equals(ref[0])) + throw new InterpreterException("constructor not called" + +" on new instance"); + newObj.setObject(c.newInstance(args)); + } else { + Method[] ms = clazz.getMethods(); + Method m = null; + for (int i=0; i< ms.length; i++) { + if (ms[i].getName().equals(ref[1])) { + /* check types XXX */ + m = ms[i]; + break; + } + } + if (m == null) + throw new InterpreterException("Method "+ref[0]+"." + +ref[1]+" not found."); + Object obj = null; + Object[] args + = new Object[m.getParameterTypes().length]; + for (int i=args.length - 1; i >= 0; i--) + args[i] = stack[--stacktop].objectValue(); + if (opcode != opc_invokestatic) + obj = stack[--stacktop].objectValue(); + /* special and constructor? XXX*/ + Object result = m.invoke(obj, args); + if (m.getReturnType() != Void.TYPE) + stack[stacktop++].setObject(result); + } + } catch (IllegalAccessException ex) { + throw new InterpreterException + ("Method "+ref[0]+"."+ref[1]+" not accessible"); + } catch (InstantiationException ex) { + throw new InterpreterException + ("InstantiationException in "+ref[0]+"."+ref[1]+"."); + } catch (InvocationTargetException ex) { + throw new InterpreterException + ("Method "+ref[0]+"."+ref[1]+" throwed an exception"); + /*XXX exception handler?*/ + } + break; + } + case opc_new: { + String clazz = cpool.getClassName((code[pc++] << 8) & 0xff00 + | code[pc++] & 0xff); + stack[stacktop++].setObject(new NewObject(clazz)); + break; + } + case opc_newarray: { + int length = stack[--stacktop].intValue(); + switch (code[pc++]) { + case 4: + stack[stacktop++].setObject(new boolean[length]); + break; + case 5: + stack[stacktop++].setObject(new char[length]); + break; + case 6: + stack[stacktop++].setObject(new float[length]); + break; + case 7: + stack[stacktop++].setObject(new double[length]); + break; + case 8: + stack[stacktop++].setObject(new byte[length]); + break; + case 9: + stack[stacktop++].setObject(new short[length]); + break; + case 10: + stack[stacktop++].setObject(new int[length]); + break; + case 11: + stack[stacktop++].setObject(new long[length]); + break; + default: + throw new ClassFormatException("Invalid newarray operand"); + } + break; + } + case opc_anewarray: { + int length = stack[--stacktop].intValue(); + Class clazz; + try { + clazz = Class.forName + (cpool.getClassName((code[pc++] << 8) & 0xff00 + | code[pc++] & 0xff) + .replace('/','.')); + } catch (ClassNotFoundException ex) { + throw new InterpreterException + ("Class "+ex.getMessage()+" not found"); + } + stack[stacktop++].setObject(Array.newInstance(clazz, length)); + break; + } + case opc_arraylength: { + Object array = stack[--stacktop].objectValue(); + stack[stacktop++].setInt(Array.getLength(array)); + break; + } + case opc_athrow: + /*XXX Throw and catch ?? */ + throw new InterpreterException("Throw not implemented"); + case opc_checkcast: { + Class clazz; + try { + clazz = Class.forName + (cpool.getClassName((code[pc++] << 8) & 0xff00 + | code[pc++] & 0xff) + .replace('/','.')); + } catch (ClassNotFoundException ex) { + throw new InterpreterException + ("Class "+ex.getMessage()+" not found"); + } + Object obj = stack[--stacktop].objectValue(); + if (obj != null && !clazz.isInstance(obj)) { + /*XXX*/ + throw new InterpreterException + ("Throw ClassCastException not implemented"); + } + break; + } + case opc_instanceof: { + Class clazz; + try { + clazz = Class.forName + (cpool.getClassName((code[pc++] << 8) & 0xff00 + | code[pc++] & 0xff) + .replace('/','.')); + } catch (ClassNotFoundException ex) { + throw new InterpreterException + ("Class "+ex.getMessage()+" not found"); + } + Object obj = stack[--stacktop].objectValue(); + if (obj != null && !clazz.isInstance(obj)) { + /*XXX*/ + throw new InterpreterException + ("Throw ClassCastException not implemented"); + } + break; + } + case opc_monitorenter: + case opc_monitorexit: + throw new InterpreterException + ("MonitorEnter/Exit not implemented"); + case opc_wide: { + opcode = code[pc++] & 0xff; + switch (opcode) { + case opc_iload: case opc_lload: + case opc_fload: case opc_dload: case opc_aload: { + int slot = (code[pc++] << 8) | (code[pc++] & 0xff); + stack[stacktop++].setValue(locals[slot & 0xffff]); + break; + } + case opc_istore: case opc_lstore: + case opc_fstore: case opc_dstore: case opc_astore: { + int slot = (code[pc++] << 8) & 0xff00 | code[pc++] & 0xff; + locals[slot & 0xffff].setValue(stack[--stacktop]); + break; + } + case opc_iinc: { + int slot = (code[pc++] << 8) & 0xff00 | code[pc++] & 0xff; + int value = (code[pc++] << 8) | code[pc++] & 0xff; + locals[slot].setInt(locals[slot].intValue() + + value); + } + case opc_ret: { + int slot = (code[pc++] << 8) & 0xff00 | code[pc++] & 0xff; + pc = ((ReturnAddress)locals[slot].objectValue()).getPC(); + } + default: + throw new + ClassFormatException("Invalid wide opcode "+opcode); + } + } + case opc_multianewarray: { + Class clazz; + try { + clazz = Class.forName + (cpool.getClassName((code[pc++] << 8) & 0xff00 + | code[pc++] & 0xff) + .replace('/','.')); + } catch (ClassNotFoundException ex) { + throw new InterpreterException + ("Class "+ex.getMessage()+" not found"); + } + int dimension = code[pc++] & 0xff; + int[] dims = new int[dimension]; + for (int i=dimension-1; i >= 0; i--) + dims[i-1] = stack[--stacktop].intValue(); + stack[stacktop++].setObject(Array.newInstance(clazz, dims)); + break; + } + case opc_jsr_w: + stack[stacktop++].setObject(new ReturnAddress(pc)); + /* fall through */ + case opc_goto_w: + pc = pc-1 + (code[pc] << 24 | ((code[pc+1]&0xff) << 16) + | ((code[pc+2]&0xff) << 8) | code[pc+3]&0xff); + default: + throw new ClassFormatException("Invalid opcode "+opcode); + } + } + } catch(RuntimeException ex) { + throw new InterpreterException("Caught RuntimeException: " + + ex.toString()); + } + } +} diff --git a/jode/jode/jvm/InterpreterException.java b/jode/jode/jvm/InterpreterException.java new file mode 100644 index 0000000..cb7f76f --- /dev/null +++ b/jode/jode/jvm/InterpreterException.java @@ -0,0 +1,35 @@ +/* + * InterpreterException (c) 1998 Jochen Hoenicke + * + * You may distribute under the terms of the GNU General Public License. + * + * IN NO EVENT SHALL JOCHEN HOENICKE BE LIABLE TO ANY PARTY FOR DIRECT, + * INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT OF + * THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF JOCHEN HOENICKE + * HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * JOCHEN HOENICKE SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A + * PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS ON AN "AS IS" + * BASIS, AND JOCHEN HOENICKE HAS NO OBLIGATION TO PROVIDE MAINTENANCE, + * SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. + * + * $Id$ + */ +package jode.jvm; +import jode.bytecode.*; + +/** + * This exception is thrown by the interpreter on various conditions. + * + * @author Jochen Hoenicke + */ +public class InterpreterException extends Exception { + public InterpreterException(String detail) { + super(detail); + } + public InterpreterException() { + super(); + } +} + diff --git a/jode/jode/jvm/NewObject.java b/jode/jode/jvm/NewObject.java new file mode 100644 index 0000000..f569c03 --- /dev/null +++ b/jode/jode/jvm/NewObject.java @@ -0,0 +1,43 @@ +/* + * NewObject (c) 1998 Jochen Hoenicke + * + * You may distribute under the terms of the GNU General Public License. + * + * IN NO EVENT SHALL JOCHEN HOENICKE BE LIABLE TO ANY PARTY FOR DIRECT, + * INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT OF + * THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF JOCHEN HOENICKE + * HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * JOCHEN HOENICKE SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A + * PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS ON AN "AS IS" + * BASIS, AND JOCHEN HOENICKE HAS NO OBLIGATION TO PROVIDE MAINTENANCE, + * SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. + * + * $Id$ + */ +package jode.jvm; +import jode.bytecode.*; + +/** + * This class represents a new object, that may not be initialized yet. + * + * @author Jochen Hoenicke + */ +public class NewObject { + Object instance; + String type; + + public NewObject(String type) { + this.type = type; + } + + public void setObject(Object obj) { + instance = obj; + } + + public Object objectValue() { + return instance; + } +} + diff --git a/jode/jode/jvm/ReturnAddress.java b/jode/jode/jvm/ReturnAddress.java new file mode 100644 index 0000000..862097c --- /dev/null +++ b/jode/jode/jvm/ReturnAddress.java @@ -0,0 +1,30 @@ +/* + * ReturnAddress (c) 1998 Jochen Hoenicke + * + * You may distribute under the terms of the GNU General Public License. + * + * IN NO EVENT SHALL JOCHEN HOENICKE BE LIABLE TO ANY PARTY FOR DIRECT, + * INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT OF + * THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF JOCHEN HOENICKE + * HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * JOCHEN HOENICKE SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A + * PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS ON AN "AS IS" + * BASIS, AND JOCHEN HOENICKE HAS NO OBLIGATION TO PROVIDE MAINTENANCE, + * SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. + * + * $Id$ + */ +package jode.jvm; + +class ReturnAddress { + int pc; + public ReturnAddress(int pc) { + this.pc = pc; + } + + public int getPC() { + return pc; + } +} diff --git a/jode/jode/jvm/Value.java b/jode/jode/jvm/Value.java new file mode 100644 index 0000000..6b13053 --- /dev/null +++ b/jode/jode/jvm/Value.java @@ -0,0 +1,86 @@ +/* + * Value (c) 1998 Jochen Hoenicke + * + * You may distribute under the terms of the GNU General Public License. + * + * IN NO EVENT SHALL JOCHEN HOENICKE BE LIABLE TO ANY PARTY FOR DIRECT, + * INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT OF + * THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF JOCHEN HOENICKE + * HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * JOCHEN HOENICKE SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A + * PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS ON AN "AS IS" + * BASIS, AND JOCHEN HOENICKE HAS NO OBLIGATION TO PROVIDE MAINTENANCE, + * SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. + * + * $Id$ + */ +package jode.jvm; +import jode.bytecode.*; + +/** + * This class represents a stack value. + * + * @author Jochen Hoenicke + */ +public class Value { + Object value; + NewObject newObj; + + public void setObject(Object obj) { + value = obj; + } + + public Object objectValue() { + if (newObj != null) + return newObj.objectValue(); + return value; + } + + public void setInt(int i) { + value = new Integer(i); + } + + public int intValue() { + return ((Integer)value).intValue(); + } + + public void setLong(long i) { + value = new Long(i); + } + + public long longValue() { + return ((Long)value).longValue(); + } + + public void setFloat(float i) { + value = new Float(i); + } + + public float floatValue() { + return ((Float)value).floatValue(); + } + + public void setDouble(double i) { + value = new Double(i); + } + + public double doubleValue() { + return ((Double)value).doubleValue(); + } + + public void setNewObject(NewObject n) { + newObj = n; + } + + public NewObject getNewObject() { + return newObj; + } + + public void setValue(Value val) { + value = val.value; + newObj = val.newObj; + } +} +