|
|
@ -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()); |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|