Many clean ups, use RuntimeException

note that there is also a jasmin implementation


git-svn-id: https://svn.code.sf.net/p/jode/code/trunk@538 379699f6-c40d-0410-875b-85095c16579e
stable
jochen 26 years ago
parent 2b71a4d303
commit 5c02a91a35
  1. 445
      jode/jode/jvm/Interpreter.java

@ -21,7 +21,8 @@ package jode.jvm;
import jode.*; import jode.*;
import jode.bytecode.*; import jode.bytecode.*;
import jode.decompiler.ClassAnalyzer; import jode.decompiler.ClassAnalyzer;
import java.lang.reflect.*; import java.lang.reflect.Array;
import java.lang.reflect.InvocationTargetException;
/** /**
* This class is a java virtual machine written in java :-). Well not * This class is a java virtual machine written in java :-). Well not
@ -32,80 +33,46 @@ import java.lang.reflect.*;
*/ */
public class Interpreter implements Opcodes { public class Interpreter implements Opcodes {
static boolean checkType(Type type1, Class type2) {
if (type1 == Type.tBoolean) {
return type2 == Boolean.TYPE;
} else if (type1 == Type.tByte) {
return type2 == Byte.TYPE;
} else if (type1 == Type.tChar) {
return type2 == Character.TYPE;
} else if (type1 == Type.tShort) {
return type2 == Short.TYPE;
} else if (type1 == Type.tInt) {
return type2 == Integer.TYPE;
} else if (type1 == Type.tLong) {
return type2 == Long.TYPE;
} else if (type1 == Type.tFloat) {
return type2 == Float.TYPE;
} else if (type1 == Type.tDouble) {
return type2 == Double.TYPE;
} else if (type1 == Type.tVoid) {
return type2 == Void.TYPE;
} else if (type1 instanceof ArrayType) {
if (!type2.isArray())
return false;
return checkType(((ArrayType)type1).getElementType(),
type2.getComponentType());
} else if (type1 instanceof ClassInterfacesType) {
return type1.equals(Type.tClass(type2.getName()));
} else
return false;
}
static boolean checkMethod(MethodType methodType,
Class[] paramTypes, Class retType) {
Type[] params = methodType.getParameterTypes();
if (params.length != paramTypes.length)
return false;
for (int i=0; i < params.length; i++) {
if (!checkType(params[i], paramTypes[i]))
return false;
}
return checkType(methodType.getReturnType(), retType);
}
public static Object interpretMethod public static Object interpretMethod
(ClassAnalyzer ca, BytecodeInfo code, Value[] locals, Value[] stack) (RuntimeEnvironment env, BytecodeInfo code, Value[] locals)
throws InterpreterException, ClassFormatException { throws InterpreterException, InvocationTargetException {
try { Value[] stack = new Value[code.getMaxStack()];
for (int i=0; i< stack.length; i++)
stack[i] = new Value();
Instruction pc = code.getFirstInstr(); Instruction pc = code.getFirstInstr();
int stacktop = 0; int stacktop = 0;
big_loop:
for(;;) { for(;;) {
try {
Instruction instr = pc; Instruction instr = pc;
// System.err.print(instr.addr+": ["); System.err.print(instr.addr+": [");
// for (int i=0; i<stacktop; i++) { for (int i=0; i<stacktop; i++) {
// if (i>0) if (i>0)
// System.err.print(","); System.err.print(",");
// System.err.print(stack[i]); System.err.print(stack[i]);
// if (stack[i].objectValue() instanceof char[]) { if (stack[i].objectValue() instanceof char[]) {
// System.err.print(new String((char[])stack[i].objectValue())); System.err.print(new String((char[])stack[i].objectValue()));
// } }
// } }
// System.err.println("]"); System.err.println("]");
// System.err.print("local: ["); System.err.print("local: [");
// for (int i=0; i<locals.length; i++) for (int i=0; i<locals.length; i++)
// System.err.print(locals[i]+","); System.err.print(locals[i]+",");
// System.err.println("]"); System.err.println("]");
pc = instr.nextByAddr; pc = instr.nextByAddr;
int opcode = instr.opcode; int opcode = instr.opcode;
switch (opcode) { switch (opcode) {
case opc_nop: case opc_nop:
break; break;
case opc_ldc: case opc_ldc:
case opc_ldc2_w: {
stack[stacktop++].setObject(instr.objData); stack[stacktop++].setObject(instr.objData);
break; break;
} case opc_ldc2_w:
stack[stacktop].setObject(instr.objData);
stacktop += 2;
break;
case opc_iload: case opc_lload: case opc_iload: case opc_lload:
case opc_fload: case opc_dload: case opc_aload: case opc_fload: case opc_dload: case opc_aload:
stack[stacktop++].setValue(locals[instr.localSlot]); stack[stacktop++].setValue(locals[instr.localSlot]);
@ -115,26 +82,31 @@ public class Interpreter implements Opcodes {
case opc_baload: case opc_caload: case opc_saload: { case opc_baload: case opc_caload: case opc_saload: {
int index = stack[--stacktop].intValue(); int index = stack[--stacktop].intValue();
Object array = stack[--stacktop].objectValue(); Object array = stack[--stacktop].objectValue();
Object result;
try {
switch(opcode) { switch(opcode) {
case opc_baload: case opc_baload:
stack[stacktop++].setInt result = new Integer
(array instanceof byte[] (array instanceof byte[]
? ((byte[])array)[index] ? ((byte[])array)[index]
: ((boolean[])array)[index] ? 1 : 0); : ((boolean[])array)[index] ? 1 : 0);
break;
case opc_caload: case opc_caload:
stack[stacktop++].setInt(((char[])array)[index]); result = new Integer(((char[])array)[index]);
break; break;
case opc_saload: case opc_saload:
stack[stacktop++].setInt(((short[])array)[index]); result = new Integer(((short[])array)[index]);
break; break;
case opc_iaload: default:
case opc_laload: result = Array.get(array, index);
case opc_faload:
case opc_daload:
case opc_aaload:
stack[stacktop++].setObject(Array.get(array, index));
break; break;
} }
} catch (NullPointerException ex) {
throw new InvocationTargetException(ex);
} catch (ArrayIndexOutOfBoundsException ex) {
throw new InvocationTargetException(ex);
}
stack[stacktop++].setObject(result);
break; break;
} }
case opc_istore: case opc_lstore: case opc_istore: case opc_lstore:
@ -147,12 +119,15 @@ public class Interpreter implements Opcodes {
Value value = stack[--stacktop]; Value value = stack[--stacktop];
int index = stack[--stacktop].intValue(); int index = stack[--stacktop].intValue();
Object array = stack[--stacktop].objectValue(); Object array = stack[--stacktop].objectValue();
try {
switch(opcode) { switch(opcode) {
case opc_bastore: case opc_bastore:
if (array instanceof byte[]) if (array instanceof byte[])
((byte[])array)[index] = (byte) value.intValue(); ((byte[])array)[index]
= (byte) value.intValue();
else else
((boolean[])array)[index] = value.intValue() != 0; ((boolean[])array)[index]
= value.intValue() != 0;
break; break;
case opc_castore: case opc_castore:
((char[])array)[index] = (char) value.intValue(); ((char[])array)[index] = (char) value.intValue();
@ -160,13 +135,16 @@ public class Interpreter implements Opcodes {
case opc_sastore: case opc_sastore:
((short[])array)[index] = (short) value.intValue(); ((short[])array)[index] = (short) value.intValue();
break; break;
case opc_iastore: default:
case opc_lastore:
case opc_fastore:
case opc_dastore:
case opc_aastore:
Array.set(array, index, value.objectValue()); Array.set(array, index, value.objectValue());
} }
} catch (NullPointerException ex) {
throw new InvocationTargetException(ex);
} catch (ArrayIndexOutOfBoundsException ex) {
throw new InvocationTargetException(ex);
} catch (ArrayStoreException ex) {
throw new InvocationTargetException(ex);
}
break; break;
} }
case opc_pop: case opc_pop2: case opc_pop: case opc_pop2:
@ -211,40 +189,60 @@ public class Interpreter implements Opcodes {
stacktop--; stacktop--;
break; break;
case opc_idiv: case opc_idiv:
stack[stacktop-2].setInt(stack[stacktop-2].intValue() try {
stack[stacktop-2].setInt
(stack[stacktop-2].intValue()
/ stack[stacktop-1].intValue()); / stack[stacktop-1].intValue());
} catch (ArithmeticException ex) {
throw new InvocationTargetException(ex);
}
stacktop--; stacktop--;
break; break;
case opc_irem: case opc_irem:
stack[stacktop-2].setInt(stack[stacktop-2].intValue() try {
stack[stacktop-2].setInt
(stack[stacktop-2].intValue()
% stack[stacktop-1].intValue()); % stack[stacktop-1].intValue());
} catch (ArithmeticException ex) {
throw new InvocationTargetException(ex);
}
stacktop--; stacktop--;
break; break;
case opc_ladd: case opc_ladd:
stacktop-=2;
stack[stacktop-2].setLong(stack[stacktop-2].longValue() stack[stacktop-2].setLong(stack[stacktop-2].longValue()
+ stack[stacktop-1].longValue()); + stack[stacktop].longValue());
stacktop--;
break; break;
case opc_lsub: case opc_lsub:
stacktop-=2;
stack[stacktop-2].setLong(stack[stacktop-2].longValue() stack[stacktop-2].setLong(stack[stacktop-2].longValue()
- stack[stacktop-1].longValue()); - stack[stacktop].longValue());
stacktop--;
break; break;
case opc_lmul: case opc_lmul:
stacktop-=2;
stack[stacktop-2].setLong(stack[stacktop-2].longValue() stack[stacktop-2].setLong(stack[stacktop-2].longValue()
* stack[stacktop-1].longValue()); * stack[stacktop].longValue());
stacktop--;
break; break;
case opc_ldiv: case opc_ldiv:
stack[stacktop-2].setLong(stack[stacktop-2].longValue() stacktop-=2;
/ stack[stacktop-1].longValue()); try {
stacktop--; stack[stacktop-2].setLong
(stack[stacktop-2].longValue()
/ stack[stacktop].longValue());
} catch (ArithmeticException ex) {
throw new InvocationTargetException(ex);
}
break; break;
case opc_lrem: case opc_lrem:
stack[stacktop-2].setLong(stack[stacktop-2].longValue() stacktop-=2;
% stack[stacktop-1].longValue()); try {
stacktop--; stack[stacktop-2].setLong
(stack[stacktop-2].longValue()
% stack[stacktop].longValue());
} catch (ArithmeticException ex) {
throw new InvocationTargetException(ex);
}
break; break;
case opc_fadd: case opc_fadd:
@ -274,42 +272,42 @@ public class Interpreter implements Opcodes {
break; break;
case opc_dadd: case opc_dadd:
stacktop-=2;
stack[stacktop-2].setDouble(stack[stacktop-2].doubleValue() stack[stacktop-2].setDouble(stack[stacktop-2].doubleValue()
+ stack[stacktop-1].doubleValue()); + stack[stacktop].doubleValue());
stacktop--;
break; break;
case opc_dsub: case opc_dsub:
stacktop-=2;
stack[stacktop-2].setDouble(stack[stacktop-2].doubleValue() stack[stacktop-2].setDouble(stack[stacktop-2].doubleValue()
- stack[stacktop-1].doubleValue()); - stack[stacktop].doubleValue());
stacktop--;
break; break;
case opc_dmul: case opc_dmul:
stacktop-=2;
stack[stacktop-2].setDouble(stack[stacktop-2].doubleValue() stack[stacktop-2].setDouble(stack[stacktop-2].doubleValue()
* stack[stacktop-1].doubleValue()); * stack[stacktop].doubleValue());
stacktop--;
break; break;
case opc_ddiv: case opc_ddiv:
stacktop-=2;
stack[stacktop-2].setDouble(stack[stacktop-2].doubleValue() stack[stacktop-2].setDouble(stack[stacktop-2].doubleValue()
/ stack[stacktop-1].doubleValue()); / stack[stacktop].doubleValue());
stacktop--;
break; break;
case opc_drem: case opc_drem:
stacktop-=2;
stack[stacktop-2].setDouble(stack[stacktop-2].doubleValue() stack[stacktop-2].setDouble(stack[stacktop-2].doubleValue()
% stack[stacktop-1].doubleValue()); % stack[stacktop].doubleValue());
stacktop--;
break; break;
case opc_ineg: case opc_ineg:
stack[stacktop-1].setInt(-stack[stacktop-1].intValue()); stack[stacktop-1].setInt(-stack[stacktop-1].intValue());
break; break;
case opc_lneg: case opc_lneg:
stack[stacktop-1].setLong(-stack[stacktop-1].longValue()); stack[stacktop-2].setLong(-stack[stacktop-2].longValue());
break; break;
case opc_fneg: case opc_fneg:
stack[stacktop-1].setFloat(-stack[stacktop-1].floatValue()); stack[stacktop-1].setFloat(-stack[stacktop-1].floatValue());
break; break;
case opc_dneg: case opc_dneg:
stack[stacktop-1].setDouble(-stack[stacktop-1].doubleValue()); stack[stacktop-2].setDouble(-stack[stacktop-2].doubleValue());
break; break;
case opc_ishl: case opc_ishl:
@ -543,112 +541,64 @@ public class Interpreter implements Opcodes {
case opc_return: case opc_return:
return Void.TYPE; return Void.TYPE;
case opc_getstatic: case opc_getstatic:
case opc_getfield: stack[stacktop++].setObject
case opc_putstatic: (env.getField((Reference) instr.objData, null));
case opc_putfield: break;
throw new InterpreterException case opc_getfield: {
("Implement get/put-static/field?"); Object cls = stack[--stacktop];
if (cls == null)
throw new InvocationTargetException
(new NullPointerException());
stack[stacktop++].setObject
(env.getField((Reference) instr.objData, cls));
break;
}
case opc_putstatic: {
Object value = stack[--stacktop];
env.putField((Reference) instr.objData, null, value);
break;
}
case opc_putfield: {
Object value = stack[--stacktop];
Object cls = stack[--stacktop];
if (cls == null)
throw new InvocationTargetException
(new NullPointerException());
env.putField((Reference) instr.objData, cls, value);
break;
}
case opc_invokevirtual: case opc_invokevirtual:
case opc_invokespecial: case opc_invokespecial:
case opc_invokestatic : case opc_invokestatic :
case opc_invokeinterface: { case opc_invokeinterface: {
Reference ref = (Reference) instr.objData; Reference ref = (Reference) instr.objData;
if (ref.getClazz().equals(ca.getClazz().getName())) {
MethodType mt = (MethodType) Type.tType(ref.getType()); MethodType mt = (MethodType) Type.tType(ref.getType());
BytecodeInfo info = ca.getMethod(ref.getName(), mt) Object[] args = new Object[mt.getParameterTypes().length];
.getCode().getBytecodeInfo(); for (int i=args.length - 1; i >= 0; i--) {
Value[] newLocals = new Value[info.getMaxLocals()]; stacktop -= mt.getParameterTypes()[i].stackSize();
for (int i=0; i< newLocals.length; i++) args[i] = stack[stacktop].objectValue();
newLocals[i] = new Value();
Value[] newStack = new Value[info.getMaxStack()];
for (int i=0; i< newStack.length; i++)
newStack[i] = new Value();
int param = mt.getParameterTypes().length;
int slot = 0;
if (opcode != opc_invokestatic)
newLocals[slot++].setValue(stack[stacktop-param-1]);
for (int i = 0; i < param; i++) {
newLocals[slot].setValue(stack[stacktop-param+i]);
slot += mt.getParameterTypes()[i].stackSize();
}
Object result = interpretMethod(ca, info,
newLocals, newStack);
if (mt.getReturnType() != Type.tVoid)
stack[stacktop++].setObject(result);
} else {
Class clazz;
try {
clazz = Class.forName(ref.getClazz());
} catch (ClassNotFoundException ex) {
throw new InterpreterException
("Class "+ref.getClazz()+" not found");
} }
try {
Object result = null;
if (ref.getName().equals("<init>")) { if (ref.getName().equals("<init>")) {
Constructor[] cs = clazz.getConstructors();
Constructor c = null;
for (int i=0; i< cs.length; i++) {
if (checkMethod((MethodType)
Type.tType(ref.getType()),
cs[i].getParameterTypes(),
Void.TYPE)) {
c = cs[i];
break;
}
}
if (c == null)
throw new InterpreterException
("Constructor " + ref + " 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 = stack[--stacktop].getNewObject(); NewObject newObj = stack[--stacktop].getNewObject();
if (!newObj.getType().equals(ref.getClazz())) // if (!newObj.getType().equals(ref.getClazz()))
throw new InterpreterException // throw new InterpreterException
("constructor called on wrong type"); // ("constructor called on wrong type");
newObj.setObject(c.newInstance(args)); newObj.setObject(env.invokeConstructor(ref, args));
} else if (opcode == opc_invokestatic) {
result = env.invokeMethod(ref, false, null, args);
} else { } else {
Method[] ms = clazz.getMethods(); Object cls = stack[--stacktop].objectValue();
Method m = null; if (cls == null)
for (int i=0; i< ms.length; i++) { throw new InvocationTargetException
if (ms[i].getName().equals(ref.getName())) { (new NullPointerException());
if (checkMethod((MethodType) result = env.invokeMethod
Type.tType(ref.getType()), (ref, opcode != opc_invokespecial, cls, args);
ms[i].getParameterTypes(),
ms[i].getReturnType())) {
m = ms[i];
break;
}
}
}
if (m == null)
throw new InterpreterException
("Method " + ref + " 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 + " not accessible");
} catch (InstantiationException ex) {
throw new InterpreterException
("InstantiationException in " + ref + ".");
} catch (InvocationTargetException ex) {
throw new InterpreterException
("Method " + ref + " throwed an exception");
/*XXX exception handler?*/
} }
if (mt.getReturnType() != Type.tVoid) {
stack[stacktop].setObject(result);
stacktop += mt.getReturnType().stackSize();
} }
break; break;
} }
@ -659,6 +609,7 @@ public class Interpreter implements Opcodes {
} }
case opc_newarray: { case opc_newarray: {
int length = stack[--stacktop].intValue(); int length = stack[--stacktop].intValue();
try {
switch (instr.intData) { switch (instr.intData) {
case 4: case 4:
stack[stacktop++].setObject(new boolean[length]); stack[stacktop++].setObject(new boolean[length]);
@ -685,20 +636,22 @@ public class Interpreter implements Opcodes {
stack[stacktop++].setObject(new long[length]); stack[stacktop++].setObject(new long[length]);
break; break;
default: default:
throw new ClassFormatException("Invalid newarray operand"); throw new AssertError("Invalid newarray operand");
}
} catch (NegativeArraySizeException ex) {
throw new InvocationTargetException(ex);
} }
break; break;
} }
case opc_anewarray: { case opc_anewarray: {
int length = stack[--stacktop].intValue(); int length = stack[--stacktop].intValue();
Class clazz;
try { try {
clazz = Class.forName((String) instr.objData); stack[stacktop++].setObject
} catch (ClassNotFoundException ex) { (env.newArray((String) instr.objData,
throw new InterpreterException new int[] { length }));
("Class "+ex.getMessage()+" not found"); } catch (NegativeArraySizeException ex) {
throw new InvocationTargetException(ex);
} }
stack[stacktop++].setObject(Array.newInstance(clazz, length));
break; break;
} }
case opc_arraylength: { case opc_arraylength: {
@ -706,68 +659,64 @@ public class Interpreter implements Opcodes {
stack[stacktop++].setInt(Array.getLength(array)); stack[stacktop++].setInt(Array.getLength(array));
break; break;
} }
case opc_athrow: case opc_athrow: {
/*XXX Throw and catch ?? */ Throwable exc =
throw new InterpreterException("Throw not implemented"); (Throwable) stack[--stacktop].objectValue();
case opc_checkcast: { throw new InvocationTargetException
Class clazz; (exc == null ? new NullPointerException() : exc);
try {
clazz = Class.forName((String) instr.objData);
} catch (ClassNotFoundException ex) {
throw new InterpreterException
("Class "+ex.getMessage()+" not found");
} }
case opc_checkcast: {
Object obj = stack[stacktop-1].objectValue(); Object obj = stack[stacktop-1].objectValue();
if (obj != null && !clazz.isInstance(obj)) { if (obj != null
/*XXX*/ && !env.instanceOf(obj, (String) instr.objData))
throw new InterpreterException throw new InvocationTargetException
("Throw ClassCastException not implemented"); (new ClassCastException(obj.getClass().getName()));
}
break; break;
} }
case opc_instanceof: { case opc_instanceof: {
Class clazz;
try {
clazz = Class.forName((String) instr.objData);
} catch (ClassNotFoundException ex) {
throw new InterpreterException
("Class "+ex.getMessage()+" not found");
}
Object obj = stack[--stacktop].objectValue(); Object obj = stack[--stacktop].objectValue();
if (obj != null && !clazz.isInstance(obj)) { stack[stacktop++].setInt
/*XXX*/ (env.instanceOf(obj, (String) instr.objData) ? 1 : 0);
throw new InterpreterException
("Throw ClassCastException not implemented");
}
break; break;
} }
case opc_monitorenter: case opc_monitorenter:
env.enterMonitor(stack[--stacktop].objectValue());
break;
case opc_monitorexit: case opc_monitorexit:
throw new InterpreterException env.exitMonitor(stack[--stacktop].objectValue());
("MonitorEnter/Exit not implemented"); break;
case opc_multianewarray: { case opc_multianewarray: {
Class clazz;
try {
clazz = Class.forName((String) instr.objData);
} catch (ClassNotFoundException ex) {
throw new InterpreterException
("Class "+ex.getMessage()+" not found");
}
int dimension = instr.intData; int dimension = instr.intData;
int[] dims = new int[dimension]; int[] dims = new int[dimension];
for (int i=dimension - 1; i >= 0; i--) for (int i=dimension - 1; i >= 0; i--)
dims[i-1] = stack[--stacktop].intValue(); dims[i-1] = stack[--stacktop].intValue();
stack[stacktop++].setObject(Array.newInstance(clazz, dims)); try {
stack[stacktop++].setObject
(env.newArray((String) instr.objData, dims));
} catch (NegativeArraySizeException ex) {
throw new InvocationTargetException(ex);
}
break; break;
} }
default: default:
throw new ClassFormatException("Invalid opcode "+opcode); throw new AssertError("Invalid opcode "+opcode);
}
} catch (InvocationTargetException ex) {
Handler[] handlers = code.getExceptionHandlers();
Throwable obj = ex.getTargetException();
for (int i=0; i< handlers.length; i++) {
if (handlers[i].start.addr <= pc.addr
&& handlers[i].end.addr >= pc.addr
&& (handlers[i].type == null
|| env.instanceOf(obj, handlers[i].type))) {
stacktop = 0;
stack[stacktop++].setObject(obj);
pc = handlers[i].catcher;
continue big_loop;
}
} }
throw ex;
} }
} catch(RuntimeException ex) {
ex.printStackTrace();
throw new InterpreterException("Caught RuntimeException: "
+ ex.toString());
} }
} }
} }

Loading…
Cancel
Save