You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
883 lines
26 KiB
883 lines
26 KiB
/* Interpreter Copyright (C) 1999 Jochen Hoenicke.
|
|
*
|
|
* This program is free software; you can redistribute it and/or modify
|
|
* it under the terms of the GNU General Public License as published by
|
|
* the Free Software Foundation; either version 2, or (at your option)
|
|
* any later version.
|
|
*
|
|
* This program is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with this program; see the file COPYING. If not, write to
|
|
* the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
|
|
*
|
|
* $Id$
|
|
*/
|
|
|
|
package jode.jvm;
|
|
import jode.AssertError;
|
|
import jode.GlobalOptions;
|
|
import jode.bytecode.BytecodeInfo;
|
|
import jode.bytecode.Handler;
|
|
import jode.bytecode.Instruction;
|
|
import jode.bytecode.Opcodes;
|
|
import jode.bytecode.Reference;
|
|
import jode.bytecode.TypeSignature;
|
|
|
|
import java.lang.reflect.Array;
|
|
import java.lang.reflect.InvocationTargetException;
|
|
import @COLLECTIONS@.Arrays;
|
|
|
|
/**
|
|
* 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 {
|
|
|
|
private final static int CMP_EQ = 0;
|
|
private final static int CMP_NE = 1;
|
|
private final static int CMP_LT = 2;
|
|
private final static int CMP_GE = 3;
|
|
private final static int CMP_GT = 4;
|
|
private final static int CMP_LE = 5;
|
|
private final static int CMP_GREATER_MASK
|
|
= (1 << CMP_GT)|(1 << CMP_GE)|(1 << CMP_NE);
|
|
private final static int CMP_LESS_MASK
|
|
= (1 << CMP_LT)|(1 << CMP_LE)|(1 << CMP_NE);
|
|
private final static int CMP_EQUAL_MASK
|
|
= (1 << CMP_GE)|(1 << CMP_LE)|(1 << CMP_EQ);
|
|
|
|
private RuntimeEnvironment env;
|
|
|
|
public Interpreter(RuntimeEnvironment env) {
|
|
this.env = env;
|
|
}
|
|
|
|
private Value[] fillParameters(BytecodeInfo code,
|
|
Object cls, Object[] params) {
|
|
Value[] locals = new Value[code.getMaxLocals()];
|
|
for (int i=0; i< locals.length; i++)
|
|
locals[i] = new Value();
|
|
|
|
String myType = code.getMethodInfo().getType();
|
|
String[] myParamTypes = TypeSignature.getParameterTypes(myType);
|
|
int slot = 0;
|
|
if (!code.getMethodInfo().isStatic())
|
|
locals[slot++].setObject(cls);
|
|
for (int i=0; i< myParamTypes.length; i++) {
|
|
char type = myParamTypes[i].charAt(0);
|
|
switch ("ZBSC".indexOf(type)) {
|
|
case 0:
|
|
locals[slot].setInt(((Boolean) params[i])
|
|
.booleanValue() ? 1 : 0);
|
|
break;
|
|
case 1: case 2:
|
|
locals[slot].setInt(((Number) params[i]).intValue());
|
|
break;
|
|
case 3:
|
|
locals[slot].setInt(((Character) params[i]).charValue());
|
|
break;
|
|
default:
|
|
locals[slot].setObject(params[i]);
|
|
break;
|
|
}
|
|
slot += TypeSignature.getTypeSize(myParamTypes[i]);
|
|
}
|
|
return locals;
|
|
}
|
|
|
|
public Object interpretMethod(BytecodeInfo code,
|
|
Object instance, Object[] myParams)
|
|
throws InterpreterException, InvocationTargetException {
|
|
if ((GlobalOptions.debuggingFlags
|
|
& GlobalOptions.DEBUG_INTERPRT) != 0)
|
|
GlobalOptions.err.println("Interpreting "+code);
|
|
|
|
Value[] locals = fillParameters(code, instance, myParams);
|
|
Value[] stack = new Value[code.getMaxStack()];
|
|
for (int i=0; i < stack.length; i++)
|
|
stack[i] = new Value();
|
|
|
|
Instruction pc = (Instruction) code.getInstructions().get(0);
|
|
int stacktop = 0;
|
|
big_loop:
|
|
for(;;) {
|
|
try {
|
|
Instruction instr = pc;
|
|
if ((GlobalOptions.debuggingFlags
|
|
& GlobalOptions.DEBUG_INTERPRT) != 0) {
|
|
GlobalOptions.err.println(instr.getDescription());
|
|
GlobalOptions.err.print("stack: [");
|
|
for (int i=0; i<stacktop; i++) {
|
|
if (i>0)
|
|
GlobalOptions.err.print(",");
|
|
GlobalOptions.err.print(stack[i]);
|
|
if (stack[i].objectValue() instanceof char[]) {
|
|
GlobalOptions.err.print
|
|
(new String((char[])stack[i].objectValue()));
|
|
}
|
|
}
|
|
GlobalOptions.err.println("]");
|
|
GlobalOptions.err.print("local: [");
|
|
for (int i=0; i<locals.length; i++)
|
|
GlobalOptions.err.print(locals[i]+",");
|
|
GlobalOptions.err.println("]");
|
|
}
|
|
pc = instr.getNextByAddr();
|
|
int opcode = instr.getOpcode();
|
|
switch (opcode) {
|
|
case opc_nop:
|
|
break;
|
|
case opc_ldc:
|
|
stack[stacktop++].setObject(instr.getConstant());
|
|
break;
|
|
case opc_ldc2_w:
|
|
stack[stacktop].setObject(instr.getConstant());
|
|
stacktop += 2;
|
|
break;
|
|
case opc_iload: case opc_fload: case opc_aload:
|
|
stack[stacktop++].setValue(locals[instr.getLocalSlot()]);
|
|
break;
|
|
case opc_lload: case opc_dload:
|
|
stack[stacktop].setValue(locals[instr.getLocalSlot()]);
|
|
stacktop += 2;
|
|
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();
|
|
Object result;
|
|
try {
|
|
switch(opcode) {
|
|
case opc_baload:
|
|
result = new Integer
|
|
(array instanceof byte[]
|
|
? ((byte[])array)[index]
|
|
: ((boolean[])array)[index] ? 1 : 0);
|
|
break;
|
|
case opc_caload:
|
|
result = new Integer(((char[])array)[index]);
|
|
break;
|
|
case opc_saload:
|
|
result = new Integer(((short[])array)[index]);
|
|
break;
|
|
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);
|
|
if (opcode == opc_laload || opcode == opc_daload)
|
|
stacktop++;
|
|
break;
|
|
}
|
|
case opc_istore: case opc_fstore: case opc_astore:
|
|
locals[instr.getLocalSlot()].setValue(stack[--stacktop]);
|
|
break;
|
|
case opc_lstore: case opc_dstore:
|
|
locals[instr.getLocalSlot()].setValue(stack[stacktop -= 2]);
|
|
break;
|
|
|
|
case opc_lastore: case opc_dastore:
|
|
stacktop--;
|
|
/* fall through */
|
|
case opc_iastore: case opc_fastore: 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();
|
|
try {
|
|
switch(opcode) {
|
|
case opc_bastore:
|
|
if (array instanceof byte[])
|
|
((byte[])array)[index]
|
|
= (byte) value.intValue();
|
|
else
|
|
((boolean[])array)[index]
|
|
= value.intValue() != 0;
|
|
break;
|
|
case opc_castore:
|
|
((char[])array)[index] = (char) value.intValue();
|
|
break;
|
|
case opc_sastore:
|
|
((short[])array)[index] = (short) value.intValue();
|
|
break;
|
|
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:
|
|
stacktop -= opcode - (opc_pop-1);
|
|
break;
|
|
case opc_dup: case opc_dup_x1: case opc_dup_x2: {
|
|
int depth = opcode - opc_dup;
|
|
for (int i=0; i < depth+1; i++)
|
|
stack[stacktop-i].setValue(stack[stacktop-i-1]);
|
|
stack[stacktop-depth-1].setValue(stack[stacktop]);
|
|
stacktop++;
|
|
break;
|
|
}
|
|
case opc_dup2: case opc_dup2_x1: case opc_dup2_x2: {
|
|
int depth = opcode - opc_dup2;
|
|
for (int i=0; i < depth+2; i++)
|
|
stack[stacktop+1-i].setValue(stack[stacktop-1-i]);
|
|
stack[stacktop-depth-1].setValue(stack[stacktop+1]);
|
|
stack[stacktop-depth-2].setValue(stack[stacktop]);
|
|
stacktop += 2;
|
|
break;
|
|
}
|
|
case opc_swap: {
|
|
Value tmp = stack[stacktop-1];
|
|
stack[stacktop-1] = stack[stacktop-2];
|
|
stack[stacktop-2] = tmp;
|
|
break;
|
|
}
|
|
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:
|
|
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:
|
|
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].longValue());
|
|
break;
|
|
case opc_lsub:
|
|
stacktop-=2;
|
|
stack[stacktop-2].setLong(stack[stacktop-2].longValue()
|
|
- stack[stacktop].longValue());
|
|
break;
|
|
case opc_lmul:
|
|
stacktop-=2;
|
|
stack[stacktop-2].setLong(stack[stacktop-2].longValue()
|
|
* stack[stacktop].longValue());
|
|
break;
|
|
case opc_ldiv:
|
|
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:
|
|
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:
|
|
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:
|
|
stacktop-=2;
|
|
stack[stacktop-2].setDouble(stack[stacktop-2].doubleValue()
|
|
+ stack[stacktop].doubleValue());
|
|
break;
|
|
case opc_dsub:
|
|
stacktop-=2;
|
|
stack[stacktop-2].setDouble(stack[stacktop-2].doubleValue()
|
|
- stack[stacktop].doubleValue());
|
|
break;
|
|
case opc_dmul:
|
|
stacktop-=2;
|
|
stack[stacktop-2].setDouble(stack[stacktop-2].doubleValue()
|
|
* stack[stacktop].doubleValue());
|
|
break;
|
|
case opc_ddiv:
|
|
stacktop-=2;
|
|
stack[stacktop-2].setDouble(stack[stacktop-2].doubleValue()
|
|
/ stack[stacktop].doubleValue());
|
|
break;
|
|
case opc_drem:
|
|
stacktop-=2;
|
|
stack[stacktop-2].setDouble(stack[stacktop-2].doubleValue()
|
|
% stack[stacktop].doubleValue());
|
|
break;
|
|
|
|
case opc_ineg:
|
|
stack[stacktop-1].setInt(-stack[stacktop-1].intValue());
|
|
break;
|
|
case opc_lneg:
|
|
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-2].setDouble(-stack[stacktop-2].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-3].setLong(stack[stacktop-3].longValue()
|
|
<< stack[stacktop-1].intValue());
|
|
stacktop--;
|
|
break;
|
|
case opc_lshr:
|
|
stack[stacktop-3].setLong(stack[stacktop-3].longValue()
|
|
>> stack[stacktop-1].intValue());
|
|
stacktop--;
|
|
break;
|
|
case opc_lushr:
|
|
stack[stacktop-3].setLong(stack[stacktop-3].longValue()
|
|
>>> stack[stacktop-1].intValue());
|
|
stacktop--;
|
|
break;
|
|
case opc_land:
|
|
stacktop-=2;
|
|
stack[stacktop-2].setLong(stack[stacktop-2].longValue()
|
|
& stack[stacktop].longValue());
|
|
break;
|
|
case opc_lor :
|
|
stacktop-=2;
|
|
stack[stacktop-2].setLong(stack[stacktop-2].longValue()
|
|
| stack[stacktop].longValue());
|
|
break;
|
|
case opc_lxor:
|
|
stacktop-=2;
|
|
stack[stacktop-2].setLong(stack[stacktop-2].longValue()
|
|
^ stack[stacktop].longValue());
|
|
break;
|
|
|
|
case opc_iinc:
|
|
locals[instr.getLocalSlot()].setInt
|
|
(locals[instr.getLocalSlot()].intValue() + instr.getIncrement());
|
|
break;
|
|
case opc_i2l:
|
|
stack[stacktop-1]
|
|
.setLong((long)stack[stacktop-1].intValue());
|
|
stacktop++;
|
|
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());
|
|
stacktop++;
|
|
break;
|
|
|
|
case opc_l2i:
|
|
stacktop--;
|
|
stack[stacktop-1]
|
|
.setInt((int)stack[stacktop-1].longValue());
|
|
break;
|
|
case opc_l2f:
|
|
stacktop--;
|
|
stack[stacktop-1]
|
|
.setFloat((float)stack[stacktop-1].longValue());
|
|
break;
|
|
case opc_l2d:
|
|
stack[stacktop-2]
|
|
.setDouble((double)stack[stacktop-2].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());
|
|
stacktop++;
|
|
break;
|
|
case opc_f2d:
|
|
stack[stacktop-1]
|
|
.setDouble((double)stack[stacktop-1].floatValue());
|
|
stacktop++;
|
|
break;
|
|
|
|
case opc_d2i:
|
|
stacktop--;
|
|
stack[stacktop-1]
|
|
.setInt((int)stack[stacktop-1].doubleValue());
|
|
break;
|
|
case opc_d2l:
|
|
stack[stacktop-2]
|
|
.setLong((long)stack[stacktop-2].doubleValue());
|
|
break;
|
|
case opc_d2f:
|
|
stacktop--;
|
|
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: {
|
|
stacktop -= 3;
|
|
long val1 = stack[stacktop-1].longValue();
|
|
long val2 = stack[stacktop+1].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: {
|
|
stacktop -= 3;
|
|
double val1 = stack[stacktop-1].doubleValue();
|
|
double val2 = stack[stacktop+1].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) {
|
|
Object objValue = stack[--stacktop].objectValue();
|
|
if (opcode >= opc_ifnull) {
|
|
value = objValue == null ? 0 : 1;
|
|
opcode -= opc_ifnull;
|
|
} else {
|
|
value = objValue
|
|
== stack[--stacktop].objectValue() ? 0 : 1;
|
|
opcode -= 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_if_icmpeq;
|
|
} else
|
|
opcode -= opc_ifeq;
|
|
}
|
|
int opc_mask = 1 << opcode;
|
|
if (value > 0 && (opc_mask & CMP_GREATER_MASK) != 0
|
|
|| value < 0 && (opc_mask & CMP_LESS_MASK) != 0
|
|
|| value == 0 && (opc_mask & CMP_EQUAL_MASK) != 0)
|
|
pc = instr.getSingleSucc();
|
|
break;
|
|
}
|
|
case opc_jsr:
|
|
case opc_jsr_w:
|
|
stack[stacktop++].setObject(instr);
|
|
/* fall through */
|
|
case opc_goto:
|
|
case opc_goto_w:
|
|
pc = instr.getSingleSucc();
|
|
break;
|
|
case opc_ret:
|
|
pc = (Instruction)locals[instr.getLocalSlot()].objectValue();
|
|
break;
|
|
case opc_lookupswitch: {
|
|
int value = stack[--stacktop].intValue();
|
|
int[] values = instr.getValues();
|
|
int pos = Arrays.binarySearch(values, value);
|
|
pc = pos < 0
|
|
? instr.getSuccs()[values.length]
|
|
: instr.getSuccs()[pos];
|
|
break;
|
|
}
|
|
case opc_ireturn: {
|
|
Object result = stack[--stacktop].objectValue();
|
|
String retType = TypeSignature
|
|
.getReturnType(code.getMethodInfo().getType());
|
|
switch ("ZBSC".indexOf(retType.charAt(0))) {
|
|
case 0: // boolean
|
|
return new Boolean(((Integer)result).intValue() != 0);
|
|
case 1: // byte
|
|
return new Byte(((Integer)result).byteValue());
|
|
case 2: // short
|
|
return new Short(((Integer)result).shortValue());
|
|
case 3: // char
|
|
return new Character((char)
|
|
((Integer)result).intValue());
|
|
default: // integer
|
|
return result;
|
|
}
|
|
}
|
|
case opc_freturn: case opc_areturn:
|
|
return stack[--stacktop].objectValue();
|
|
case opc_lreturn: case opc_dreturn:
|
|
return stack[stacktop -= 2].objectValue();
|
|
case opc_return:
|
|
return Void.TYPE;
|
|
case opc_getstatic: {
|
|
Reference ref = instr.getReference();
|
|
Object result = env.getField(instr.getReference(), null);
|
|
char type = ref.getType().charAt(0);
|
|
switch ("ZBSC".indexOf(type)) {
|
|
case 0:
|
|
stack[stacktop].setInt(((Boolean) result)
|
|
.booleanValue() ? 1 : 0);
|
|
break;
|
|
case 1: case 2:
|
|
stack[stacktop].setInt(((Number) result)
|
|
.intValue());
|
|
break;
|
|
case 3:
|
|
stack[stacktop].setInt(((Character) result)
|
|
.charValue());
|
|
break;
|
|
default:
|
|
stack[stacktop].setObject(result);
|
|
break;
|
|
}
|
|
stacktop += TypeSignature.getTypeSize(ref.getType());
|
|
break;
|
|
}
|
|
case opc_getfield: {
|
|
Reference ref = instr.getReference();
|
|
Object cls = stack[--stacktop].objectValue();
|
|
if (cls == null)
|
|
throw new InvocationTargetException
|
|
(new NullPointerException());
|
|
Object result = env.getField(instr.getReference(), cls);
|
|
char type = ref.getType().charAt(0);
|
|
switch ("ZBSC".indexOf(type)) {
|
|
case 0:
|
|
stack[stacktop].setInt(((Boolean) result)
|
|
.booleanValue() ? 1 : 0);
|
|
break;
|
|
case 1: case 2:
|
|
stack[stacktop].setInt(((Number) result)
|
|
.intValue());
|
|
break;
|
|
case 3:
|
|
stack[stacktop].setInt(((Character) result)
|
|
.charValue());
|
|
break;
|
|
default:
|
|
stack[stacktop].setObject(result);
|
|
break;
|
|
}
|
|
stacktop += TypeSignature.getTypeSize(ref.getType());
|
|
break;
|
|
}
|
|
case opc_putstatic: {
|
|
Reference ref = instr.getReference();
|
|
stacktop -= TypeSignature.getTypeSize(ref.getType());
|
|
Object value = stack[stacktop].objectValue();
|
|
int type = "ZBSC".indexOf(ref.getType().charAt(0));
|
|
switch(type) {
|
|
case 0: // boolean
|
|
value = new Boolean(((Integer)value).intValue() != 0);
|
|
break;
|
|
case 1: // byte
|
|
value = new Byte(((Integer)value).byteValue());
|
|
break;
|
|
case 2: // short
|
|
value = new Short(((Integer)value).shortValue());
|
|
break;
|
|
case 3: // char
|
|
value = new Character((char)
|
|
((Integer)value).intValue());
|
|
break;
|
|
}
|
|
env.putField(instr.getReference(), null, value);
|
|
break;
|
|
}
|
|
case opc_putfield: {
|
|
Reference ref = instr.getReference();
|
|
stacktop -= TypeSignature.getTypeSize(ref.getType());
|
|
Object value = stack[stacktop].objectValue();
|
|
int type = "ZBSC".indexOf(ref.getType().charAt(0));
|
|
switch(type) {
|
|
case 0: // boolean
|
|
value = new Boolean(((Integer)value).intValue() != 0);
|
|
break;
|
|
case 1: // byte
|
|
value = new Byte(((Integer)value).byteValue());
|
|
break;
|
|
case 2: // short
|
|
value = new Short(((Integer)value).shortValue());
|
|
break;
|
|
case 3: // char
|
|
value = new Character((char)
|
|
((Integer)value).intValue());
|
|
break;
|
|
}
|
|
Object cls = stack[--stacktop].objectValue();
|
|
if (cls == null)
|
|
throw new InvocationTargetException
|
|
(new NullPointerException());
|
|
env.putField(instr.getReference(), cls, value);
|
|
break;
|
|
}
|
|
case opc_invokevirtual:
|
|
case opc_invokespecial:
|
|
case opc_invokestatic :
|
|
case opc_invokeinterface: {
|
|
Reference ref = instr.getReference();
|
|
String[] paramTypes
|
|
= TypeSignature.getParameterTypes(ref.getType());
|
|
Object[] args = new Object[paramTypes.length];
|
|
for (int i = paramTypes.length - 1; i >= 0; i--) {
|
|
stacktop -= TypeSignature.getTypeSize(paramTypes[i]);
|
|
Object value = stack[stacktop].objectValue();
|
|
int type = "ZBSC".indexOf(paramTypes[i].charAt(0));
|
|
switch(type) {
|
|
case 0: // boolean
|
|
value = new Boolean(((Integer)value)
|
|
.intValue() != 0);
|
|
break;
|
|
case 1: // byte
|
|
value = new Byte(((Integer)value).byteValue());
|
|
break;
|
|
case 2: // short
|
|
value = new Short(((Integer)value).shortValue());
|
|
break;
|
|
case 3: // char
|
|
value = new Character((char)
|
|
((Integer)value).intValue());
|
|
break;
|
|
}
|
|
args[i] = value;
|
|
}
|
|
|
|
Object result = null;
|
|
if (ref.getName().equals("<init>")) {
|
|
NewObject newObj = stack[--stacktop].getNewObject();
|
|
// 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 {
|
|
Object cls = stack[--stacktop].objectValue();
|
|
if (cls == null)
|
|
throw new InvocationTargetException
|
|
(new NullPointerException());
|
|
result = env.invokeMethod
|
|
(ref, opcode != opc_invokespecial, cls, args);
|
|
}
|
|
String retType
|
|
= TypeSignature.getReturnType(ref.getType());
|
|
char type = retType.charAt(0);
|
|
switch ("ZBSCV".indexOf(type)) {
|
|
case 0:
|
|
stack[stacktop].setInt(((Boolean) result)
|
|
.booleanValue() ? 1 : 0);
|
|
break;
|
|
case 1: case 2:
|
|
stack[stacktop].setInt(((Number) result)
|
|
.intValue());
|
|
break;
|
|
case 3:
|
|
stack[stacktop].setInt(((Character) result)
|
|
.charValue());
|
|
break;
|
|
case 4: // Void
|
|
break;
|
|
default:
|
|
stack[stacktop].setObject(result);
|
|
break;
|
|
}
|
|
stacktop += TypeSignature.getTypeSize(retType);
|
|
break;
|
|
}
|
|
case opc_new: {
|
|
String clazz = instr.getClazzType();
|
|
stack[stacktop++].setNewObject(new NewObject(clazz));
|
|
break;
|
|
}
|
|
case opc_arraylength: {
|
|
Object array = stack[--stacktop].objectValue();
|
|
stack[stacktop++].setInt(Array.getLength(array));
|
|
break;
|
|
}
|
|
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
|
|
&& !env.instanceOf(obj, instr.getClazzType()))
|
|
throw new InvocationTargetException
|
|
(new ClassCastException(obj.getClass().getName()));
|
|
break;
|
|
}
|
|
case opc_instanceof: {
|
|
Object obj = stack[--stacktop].objectValue();
|
|
stack[stacktop++].setInt
|
|
(env.instanceOf(obj, instr.getClazzType()) ? 1 : 0);
|
|
break;
|
|
}
|
|
case opc_monitorenter:
|
|
env.enterMonitor(stack[--stacktop].objectValue());
|
|
break;
|
|
case opc_monitorexit:
|
|
env.exitMonitor(stack[--stacktop].objectValue());
|
|
break;
|
|
case opc_multianewarray: {
|
|
int dimension = instr.getDimensions();
|
|
int[] dims = new int[dimension];
|
|
for (int i=dimension - 1; i >= 0; i--)
|
|
dims[i] = stack[--stacktop].intValue();
|
|
try {
|
|
stack[stacktop++].setObject
|
|
(env.newArray(instr.getClazzType(), dims));
|
|
} catch (NegativeArraySizeException ex) {
|
|
throw new InvocationTargetException(ex);
|
|
}
|
|
break;
|
|
}
|
|
default:
|
|
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.compareTo(pc) <= 0
|
|
&& handlers[i].end.compareTo(pc) >= 0
|
|
&& (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;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|