diff --git a/jode/jode/jvm/Interpreter.java b/jode/jode/jvm/Interpreter.java index 6ef1fcf..d44e189 100644 --- a/jode/jode/jvm/Interpreter.java +++ b/jode/jode/jvm/Interpreter.java @@ -18,6 +18,9 @@ */ package jode.jvm; import jode.bytecode.*; +import jode.decompiler.ClassAnalyzer; +import jode.MethodType; +import jode.Type; import java.lang.reflect.*; /** @@ -28,14 +31,109 @@ import java.lang.reflect.*; * @author Jochen Hoenicke */ public class Interpreter implements Opcodes { + + static int checkType(String typesig, int pos, Class type) { + switch (typesig.charAt(pos++)) { + case 'Z': + if (type != Boolean.TYPE) + return -1; + break; + case 'B': + if (type != Byte.TYPE) + return -1; + break; + case 'C': + if (type != Character.TYPE) + return -1; + break; + case 'S': + if (type != Short.TYPE) + return -1; + break; + case 'I': + if (type != Integer.TYPE) + return -1; + break; + case 'J': + if (type != Long.TYPE) + return -1; + break; + case 'F': + if (type != Float.TYPE) + return -1; + break; + case 'D': + if (type != Double.TYPE) + return -1; + break; + case 'V': + if (type != Void.TYPE) + return -1; + break; + case '[': + if (!type.isArray()) + return -1; + pos = checkType(typesig, pos, type.getComponentType()); + break; + case 'L': { + int index = typesig.indexOf(';', pos); + if (index == -1) + return -1; + if (!type.getName().replace('.','/') + .equals(typesig.substring(pos, index))) + return -1; + pos = index+1; + break; + } + default: + return -1; + } + return pos; + } + + static boolean checkMethod(String typesig, + Class[] paramTypes, Class retType) { + if (typesig.charAt(0) != '(') + return false; + int pos = 1; + int i = 0; + while (typesig.charAt(pos) != ')') { + if (i >= paramTypes.length) + return false; + pos = checkType(typesig, pos, paramTypes[i++]); + if (pos == -1) { + return false; + } + } + if (i != paramTypes.length) + return false; + pos++; + pos = checkType(typesig, pos, retType); + return pos == typesig.length(); + } + public static Object interpretMethod - (ClassInfo currentClass, byte[] code, Value[] locals, Value[] stack) + (ClassAnalyzer ca, byte[] code, Value[] locals, Value[] stack) throws InterpreterException, ClassFormatException { try { - ConstantPool cpool = currentClass.getConstantPool(); + ConstantPool cpool = ca.getClazz().getConstantPool(); int pc = 0; int stacktop = 0; for(;;) { +// System.err.print(pc+": ["); +// for (int i=0; i0) +// System.err.print(","); +// System.err.print(stack[i]); +// if (stack[i].objectValue() instanceof char[]) { +// System.err.print(new String((char[])stack[i].objectValue())); +// } +// } +// System.err.println("]"); +// System.err.print("local: ["); +// for (int i=0; i= low && value <= high) { - pc += (value - low) << 1; - dest = ((code[pc] << 8) | (code[pc+1] & 0xff)); + pc += (value - low) << 2; + dest = (code[pc++] << 24 | (code[pc++] & 0xff) << 16 + | (code[pc++] & 0xff) << 8 | (code[pc++] & 0xff)); } pc = start + dest; break; @@ -537,11 +629,23 @@ public class Interpreter implements Opcodes { 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)); + int dest = (code[pc++] << 24 + | (code[pc++] & 0xff) << 16 + | (code[pc++] & 0xff) << 8 + | (code[pc++] & 0xff)); + int npairs = (code[pc++] << 24 + | (code[pc++] & 0xff) << 16 + | (code[pc++] & 0xff) << 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)); + if (value == (code[pc++] << 24 + | (code[pc++] & 0xff) << 16 + | (code[pc++] & 0xff) << 8 + | (code[pc++] & 0xff))) { + dest = (code[pc++] << 24 + | (code[pc++] & 0xff) << 16 + | (code[pc++] & 0xff) << 8 + | (code[pc++] & 0xff)); break; } pc+=2; @@ -569,84 +673,102 @@ public class Interpreter implements Opcodes { 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 (ref[0].equals(ca.getClazz().getName().replace('.','/'))) { + boolean isStatic = opcode == opc_invokestatic; + MethodType mt = new MethodType(isStatic, ref[2]); + CodeInfo info = ca.getMethod(ref[1], mt) + .getCode().getCodeInfo(); + Value[] newLocals = new Value[info.getMaxLocals()]; + for (int i=0; i< newLocals.length; i++) + newLocals[i] = new Value(); + Value[] newStack = new Value[info.getMaxStack()]; + for (int i=0; i< newStack.length; i++) + newStack[i] = new Value(); + for (int i=mt.getParameterTypes().length - 1; i >= 0; i--) + newLocals[i].setValue(stack[--stacktop]); + Object result = interpretMethod(ca, info.getCode(), + newLocals, newStack); + if (mt.getReturnType() != Type.tVoid) { + stack[stacktop++].setObject(result); + } + } else { + Class clazz; + try { + clazz = Class.forName(ref[0].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++) { + if (checkMethod(ref[2], cs[i].getParameterTypes(), + Void.TYPE)) { + c = cs[i]; + break; + } + } if (c == null) throw new InterpreterException("Constructor " - +ref[0]+"." - +ref[1]+" not found."); + +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])) + NewObject newObj = stack[--stacktop].getNewObject(); + if (!newObj.getType().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; + } else { + Method[] ms = clazz.getMethods(); + Method m = null; + for (int i=0; i< ms.length; i++) { + if (ms[i].getName().equals(ref[1])) { + if (checkMethod(ref[2], + ms[i].getParameterTypes(), + ms[i].getReturnType())) { + 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*/ + 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?*/ } - } 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)); + stack[stacktop++].setNewObject(new NewObject(clazz)); break; } case opc_newarray: { @@ -805,6 +927,7 @@ public class Interpreter implements Opcodes { } } } catch(RuntimeException ex) { + ex.printStackTrace(); throw new InterpreterException("Caught RuntimeException: " + ex.toString()); }