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.bytecode.*;
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
@ -32,80 +33,46 @@ import java.lang.reflect.*;
*/
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
(ClassAnalyzer ca, BytecodeInfo code, Value[] locals, Value[] stack)
throws InterpreterException, ClassFormatException {
try {
(RuntimeEnvironment env, BytecodeInfo code, Value[] locals)
throws InterpreterException, InvocationTargetException {
Value[] stack = new Value[code.getMaxStack()];
for (int i=0; i< stack.length; i++)
stack[i] = new Value();
Instruction pc = code.getFirstInstr();
int stacktop = 0;
big_loop:
for(;;) {
try {
Instruction instr = pc;
// System.err.print(instr.addr+": [");
// for (int i=0; i<stacktop; i++) {
// if (i>0)
// 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<locals.length; i++)
// System.err.print(locals[i]+",");
// System.err.println("]");
System.err.print(instr.addr+": [");
for (int i=0; i<stacktop; i++) {
if (i>0)
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<locals.length; i++)
System.err.print(locals[i]+",");
System.err.println("]");
pc = instr.nextByAddr;
int opcode = instr.opcode;
switch (opcode) {
case opc_nop:
break;
case opc_ldc:
case opc_ldc2_w: {
stack[stacktop++].setObject(instr.objData);
break;
}
case opc_ldc2_w:
stack[stacktop].setObject(instr.objData);
stacktop += 2;
break;
case opc_iload: case opc_lload:
case opc_fload: case opc_dload: case opc_aload:
stack[stacktop++].setValue(locals[instr.localSlot]);
@ -115,26 +82,31 @@ public class Interpreter implements Opcodes {
case opc_baload: case opc_caload: case opc_saload: {
int index = stack[--stacktop].intValue();
Object array = stack[--stacktop].objectValue();
Object result;
try {
switch(opcode) {
case opc_baload:
stack[stacktop++].setInt
result = new Integer
(array instanceof byte[]
? ((byte[])array)[index]
: ((boolean[])array)[index] ? 1 : 0);
break;
case opc_caload:
stack[stacktop++].setInt(((char[])array)[index]);
result = new Integer(((char[])array)[index]);
break;
case opc_saload:
stack[stacktop++].setInt(((short[])array)[index]);
result = new Integer(((short[])array)[index]);
break;
case opc_iaload:
case opc_laload:
case opc_faload:
case opc_daload:
case opc_aaload:
stack[stacktop++].setObject(Array.get(array, index));
default:
result = Array.get(array, index);
break;
}
} catch (NullPointerException ex) {
throw new InvocationTargetException(ex);
} catch (ArrayIndexOutOfBoundsException ex) {
throw new InvocationTargetException(ex);
}
stack[stacktop++].setObject(result);
break;
}
case opc_istore: case opc_lstore:
@ -147,12 +119,15 @@ public class Interpreter implements Opcodes {
Value value = stack[--stacktop];
int index = stack[--stacktop].intValue();
Object array = stack[--stacktop].objectValue();
try {
switch(opcode) {
case opc_bastore:
if (array instanceof byte[])
((byte[])array)[index] = (byte) value.intValue();
((byte[])array)[index]
= (byte) value.intValue();
else
((boolean[])array)[index] = value.intValue() != 0;
((boolean[])array)[index]
= value.intValue() != 0;
break;
case opc_castore:
((char[])array)[index] = (char) value.intValue();
@ -160,13 +135,16 @@ public class Interpreter implements Opcodes {
case opc_sastore:
((short[])array)[index] = (short) value.intValue();
break;
case opc_iastore:
case opc_lastore:
case opc_fastore:
case opc_dastore:
case opc_aastore:
default:
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;
}
case opc_pop: case opc_pop2:
@ -211,40 +189,60 @@ public class Interpreter implements Opcodes {
stacktop--;
break;
case opc_idiv:
stack[stacktop-2].setInt(stack[stacktop-2].intValue()
try {
stack[stacktop-2].setInt
(stack[stacktop-2].intValue()
/ stack[stacktop-1].intValue());
} catch (ArithmeticException ex) {
throw new InvocationTargetException(ex);
}
stacktop--;
break;
case opc_irem:
stack[stacktop-2].setInt(stack[stacktop-2].intValue()
try {
stack[stacktop-2].setInt
(stack[stacktop-2].intValue()
% stack[stacktop-1].intValue());
} catch (ArithmeticException ex) {
throw new InvocationTargetException(ex);
}
stacktop--;
break;
case opc_ladd:
stacktop-=2;
stack[stacktop-2].setLong(stack[stacktop-2].longValue()
+ stack[stacktop-1].longValue());
stacktop--;
+ stack[stacktop].longValue());
break;
case opc_lsub:
stacktop-=2;
stack[stacktop-2].setLong(stack[stacktop-2].longValue()
- stack[stacktop-1].longValue());
stacktop--;
- stack[stacktop].longValue());
break;
case opc_lmul:
stacktop-=2;
stack[stacktop-2].setLong(stack[stacktop-2].longValue()
* stack[stacktop-1].longValue());
stacktop--;
* stack[stacktop].longValue());
break;
case opc_ldiv:
stack[stacktop-2].setLong(stack[stacktop-2].longValue()
/ stack[stacktop-1].longValue());
stacktop--;
stacktop-=2;
try {
stack[stacktop-2].setLong
(stack[stacktop-2].longValue()
/ stack[stacktop].longValue());
} catch (ArithmeticException ex) {
throw new InvocationTargetException(ex);
}
break;
case opc_lrem:
stack[stacktop-2].setLong(stack[stacktop-2].longValue()
% stack[stacktop-1].longValue());
stacktop--;
stacktop-=2;
try {
stack[stacktop-2].setLong
(stack[stacktop-2].longValue()
% stack[stacktop].longValue());
} catch (ArithmeticException ex) {
throw new InvocationTargetException(ex);
}
break;
case opc_fadd:
@ -274,42 +272,42 @@ public class Interpreter implements Opcodes {
break;
case opc_dadd:
stacktop-=2;
stack[stacktop-2].setDouble(stack[stacktop-2].doubleValue()
+ stack[stacktop-1].doubleValue());
stacktop--;
+ stack[stacktop].doubleValue());
break;
case opc_dsub:
stacktop-=2;
stack[stacktop-2].setDouble(stack[stacktop-2].doubleValue()
- stack[stacktop-1].doubleValue());
stacktop--;
- stack[stacktop].doubleValue());
break;
case opc_dmul:
stacktop-=2;
stack[stacktop-2].setDouble(stack[stacktop-2].doubleValue()
* stack[stacktop-1].doubleValue());
stacktop--;
* stack[stacktop].doubleValue());
break;
case opc_ddiv:
stacktop-=2;
stack[stacktop-2].setDouble(stack[stacktop-2].doubleValue()
/ stack[stacktop-1].doubleValue());
stacktop--;
/ stack[stacktop].doubleValue());
break;
case opc_drem:
stacktop-=2;
stack[stacktop-2].setDouble(stack[stacktop-2].doubleValue()
% stack[stacktop-1].doubleValue());
stacktop--;
% stack[stacktop].doubleValue());
break;
case opc_ineg:
stack[stacktop-1].setInt(-stack[stacktop-1].intValue());
break;
case opc_lneg:
stack[stacktop-1].setLong(-stack[stacktop-1].longValue());
stack[stacktop-2].setLong(-stack[stacktop-2].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());
stack[stacktop-2].setDouble(-stack[stacktop-2].doubleValue());
break;
case opc_ishl:
@ -543,112 +541,64 @@ public class Interpreter implements Opcodes {
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?");
stack[stacktop++].setObject
(env.getField((Reference) instr.objData, null));
break;
case opc_getfield: {
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_invokespecial:
case opc_invokestatic :
case opc_invokeinterface: {
Reference ref = (Reference) instr.objData;
if (ref.getClazz().equals(ca.getClazz().getName())) {
MethodType mt = (MethodType) Type.tType(ref.getType());
BytecodeInfo info = ca.getMethod(ref.getName(), mt)
.getCode().getBytecodeInfo();
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();
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");
Object[] args = new Object[mt.getParameterTypes().length];
for (int i=args.length - 1; i >= 0; i--) {
stacktop -= mt.getParameterTypes()[i].stackSize();
args[i] = stack[stacktop].objectValue();
}
try {
Object result = null;
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();
if (!newObj.getType().equals(ref.getClazz()))
throw new InterpreterException
("constructor called on wrong type");
newObj.setObject(c.newInstance(args));
// if (!newObj.getType().equals(ref.getClazz()))
// throw new InterpreterException
// ("constructor called on wrong type");
newObj.setObject(env.invokeConstructor(ref, args));
} else if (opcode == opc_invokestatic) {
result = env.invokeMethod(ref, false, null, args);
} else {
Method[] ms = clazz.getMethods();
Method m = null;
for (int i=0; i< ms.length; i++) {
if (ms[i].getName().equals(ref.getName())) {
if (checkMethod((MethodType)
Type.tType(ref.getType()),
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?*/
Object cls = stack[--stacktop].objectValue();
if (cls == null)
throw new InvocationTargetException
(new NullPointerException());
result = env.invokeMethod
(ref, opcode != opc_invokespecial, cls, args);
}
if (mt.getReturnType() != Type.tVoid) {
stack[stacktop].setObject(result);
stacktop += mt.getReturnType().stackSize();
}
break;
}
@ -659,6 +609,7 @@ public class Interpreter implements Opcodes {
}
case opc_newarray: {
int length = stack[--stacktop].intValue();
try {
switch (instr.intData) {
case 4:
stack[stacktop++].setObject(new boolean[length]);
@ -685,20 +636,22 @@ public class Interpreter implements Opcodes {
stack[stacktop++].setObject(new long[length]);
break;
default:
throw new ClassFormatException("Invalid newarray operand");
throw new AssertError("Invalid newarray operand");
}
} catch (NegativeArraySizeException ex) {
throw new InvocationTargetException(ex);
}
break;
}
case opc_anewarray: {
int length = stack[--stacktop].intValue();
Class clazz;
try {
clazz = Class.forName((String) instr.objData);
} catch (ClassNotFoundException ex) {
throw new InterpreterException
("Class "+ex.getMessage()+" not found");
stack[stacktop++].setObject
(env.newArray((String) instr.objData,
new int[] { length }));
} catch (NegativeArraySizeException ex) {
throw new InvocationTargetException(ex);
}
stack[stacktop++].setObject(Array.newInstance(clazz, length));
break;
}
case opc_arraylength: {
@ -706,68 +659,64 @@ public class Interpreter implements Opcodes {
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((String) instr.objData);
} catch (ClassNotFoundException ex) {
throw new InterpreterException
("Class "+ex.getMessage()+" not found");
case opc_athrow: {
Throwable exc =
(Throwable) stack[--stacktop].objectValue();
throw new InvocationTargetException
(exc == null ? new NullPointerException() : exc);
}
case opc_checkcast: {
Object obj = stack[stacktop-1].objectValue();
if (obj != null && !clazz.isInstance(obj)) {
/*XXX*/
throw new InterpreterException
("Throw ClassCastException not implemented");
}
if (obj != null
&& !env.instanceOf(obj, (String) instr.objData))
throw new InvocationTargetException
(new ClassCastException(obj.getClass().getName()));
break;
}
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();
if (obj != null && !clazz.isInstance(obj)) {
/*XXX*/
throw new InterpreterException
("Throw ClassCastException not implemented");
}
stack[stacktop++].setInt
(env.instanceOf(obj, (String) instr.objData) ? 1 : 0);
break;
}
case opc_monitorenter:
env.enterMonitor(stack[--stacktop].objectValue());
break;
case opc_monitorexit:
throw new InterpreterException
("MonitorEnter/Exit not implemented");
env.exitMonitor(stack[--stacktop].objectValue());
break;
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[] 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));
try {
stack[stacktop++].setObject
(env.newArray((String) instr.objData, dims));
} catch (NegativeArraySizeException ex) {
throw new InvocationTargetException(ex);
}
break;
}
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