diff --git a/jode/jode/expr/InvokeOperator.java.in b/jode/jode/expr/InvokeOperator.java.in
index ec316c4..b5c1e9d 100644
--- a/jode/jode/expr/InvokeOperator.java.in
+++ b/jode/jode/expr/InvokeOperator.java.in
@@ -342,26 +342,25 @@ public final class InvokeOperator extends Operator
class Environment extends SimpleRuntimeEnvironment {
+ Interpreter interpreter;
+ String classSig;
+
+ public Environment(String interpretedClassSig) {
+ classSig = interpretedClassSig.intern();
+ }
+
public Object invokeMethod(Reference ref, boolean isVirtual,
Object cls, Object[] params)
throws InterpreterException, InvocationTargetException {
- if (ref.getClazz().equals
- ("L"+methodAnalyzer.getClazz().getName().replace('.','/')+";")) {
- MethodType mt = (MethodType) Type.tType(ref.getType());
- BytecodeInfo info = methodAnalyzer.getClassAnalyzer()
- .getMethod(ref.getName(), mt).getBytecodeInfo();
- Value[] locals = new Value[info.getMaxLocals()];
- for (int i=0; i< locals.length; i++)
- locals[i] = new Value();
- int param = params.length;
- int slot = 0;
- if (cls != null)
- locals[slot++].setObject(cls);
- for (int i = 0; i < param; i++) {
- locals[slot].setObject(params[i]);
- slot += mt.getParameterTypes()[i].stackSize();
- }
- return Interpreter.interpretMethod(this, info, locals);
+ if (cls == null && ref.getClazz().equals(classSig)) {
+ BytecodeInfo info =
+ ClassInfo.forName(ref.getClazz())
+ .findMethod(ref.getName(), ref.getType())
+ .getBytecode();
+ if (info != null)
+ return interpreter.interpretMethod(info, null, params);
+ throw new InterpreterException
+ ("Can't interpret static native method: "+ref);
} else
return super.invokeMethod(ref, isVirtual, cls, params);
}
@@ -372,15 +371,15 @@ public final class InvokeOperator extends Operator
MethodAnalyzer ma = clazz.getMethod(methodName, methodType);
if (ma == null)
return null;
- Environment env = new Environment();
- BytecodeInfo info = ma.getBytecodeInfo();
- Value[] locals = new Value[info.getMaxLocals()];
- for (int i=0; i< locals.length; i++)
- locals[i] = new Value();
- locals[0].setObject(op.getValue());
+ Environment env = new Environment("L"+methodAnalyzer.getClazz()
+ .getName().replace('.','/')+";");
+ Interpreter interpreter = new Interpreter(env);
+ env.interpreter = interpreter;
+
String result;
try {
- result = (String) Interpreter.interpretMethod(env, info, locals);
+ result = (String) interpreter.interpretMethod
+ (ma.getBytecodeInfo(), null, new String[] { op.getValue() });
} catch (InterpreterException ex) {
GlobalOptions.err.println("Warning: Can't interpret method "
+methodName);
diff --git a/jode/jode/jvm/Interpreter.java.in b/jode/jode/jvm/Interpreter.java.in
index 825c050..011b5f3 100644
--- a/jode/jode/jvm/Interpreter.java.in
+++ b/jode/jode/jvm/Interpreter.java.in
@@ -25,11 +25,11 @@ import jode.bytecode.Handler;
import jode.bytecode.Instruction;
import jode.bytecode.Opcodes;
import jode.bytecode.Reference;
-import jode.type.MethodType;
-import jode.type.Type;
+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
@@ -53,14 +53,55 @@ public class Interpreter implements Opcodes {
private final static int CMP_EQUAL_MASK
= (1 << CMP_GE)|(1 << CMP_LE)|(1 << CMP_EQ);
- public static Object interpretMethod
- (RuntimeEnvironment env, BytecodeInfo code, Value[] locals)
+ 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++)
+ for (int i=0; i < stack.length; i++)
stack[i] = new Value();
Instruction pc = (Instruction) code.getInstructions().get(0);
@@ -78,7 +119,8 @@ public class Interpreter implements Opcodes {
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.print
+ (new String((char[])stack[i].objectValue()));
}
}
GlobalOptions.err.println("]");
@@ -563,16 +605,31 @@ public class Interpreter implements Opcodes {
case opc_lookupswitch: {
int value = stack[--stacktop].intValue();
int[] values = instr.getValues();
- pc = instr.getSuccs()[values.length];
- for (int i=0; i< values.length; i++) {
- if (values[i] == value) {
- pc = instr.getSuccs()[i];
- break;
- }
- }
+ int pos = Arrays.binarySearch(values, value);
+ pc = pos < 0
+ ? instr.getSuccs()[values.length]
+ : instr.getSuccs()[pos];
break;
}
- case opc_ireturn: case opc_freturn: case opc_areturn:
+ 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();
@@ -580,34 +637,100 @@ public class Interpreter implements Opcodes {
return Void.TYPE;
case opc_getstatic: {
Reference ref = instr.getReference();
- stack[stacktop].setObject
- (env.getField(instr.getReference(), null));
- stacktop += Type.tType(ref.getType()).stackSize();
+ 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];
+ Object cls = stack[--stacktop].objectValue();
if (cls == null)
throw new InvocationTargetException
(new NullPointerException());
- stack[stacktop].setObject
- (env.getField(instr.getReference(), cls));
- stacktop += Type.tType(ref.getType()).stackSize();
+ 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 -= Type.tType(ref.getType()).stackSize();
- Object value = stack[stacktop];
+ 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 -= Type.tType(ref.getType()).stackSize();
- Object value = stack[stacktop];
- Object cls = stack[--stacktop];
+ 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());
@@ -619,11 +742,30 @@ public class Interpreter implements Opcodes {
case opc_invokestatic :
case opc_invokeinterface: {
Reference ref = instr.getReference();
- MethodType mt = (MethodType) Type.tType(ref.getType());
- 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();
+ 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;
@@ -643,10 +785,29 @@ public class Interpreter implements Opcodes {
result = env.invokeMethod
(ref, opcode != opc_invokespecial, cls, args);
}
- if (mt.getReturnType() != Type.tVoid) {
+ 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);
- stacktop += mt.getReturnType().stackSize();
+ break;
}
+ stacktop += TypeSignature.getTypeSize(retType);
break;
}
case opc_new: {
diff --git a/jode/jode/jvm/RuntimeEnvironment.java b/jode/jode/jvm/RuntimeEnvironment.java
index 97292af..d6d08c9 100644
--- a/jode/jode/jvm/RuntimeEnvironment.java
+++ b/jode/jode/jvm/RuntimeEnvironment.java
@@ -21,11 +21,56 @@ package jode.jvm;
import jode.bytecode.Reference;
import java.lang.reflect.InvocationTargetException;
+/**
+ * This interface is used by the Interpreter to actually modify objects,
+ * invoke methods, etc.
+ *
+ * The objects used in this runtime environment need not to be of the
+ * real class, but could also be of some wrapper class. The only
+ * exception are arrays, which must be arrays (but not necessarily of
+ * the real element type).
+ *
+ * @author Jochen Hoenicke */
public interface RuntimeEnvironment {
+ /**
+ * Get the value of a field member.
+ * @param fieldref the Reference of the field.
+ * @param obj the object of which the field should be taken, null
+ * if the field is static.
+ * @return the field value. Primitive types are wrapped to
+ * Object.
+ * @exception InterpreterException if the field does not exists, the
+ * object is not supported etc.
+ */
public Object getField(Reference fieldref, Object obj)
throws InterpreterException;
+
+ /**
+ * Set the value of a field member.
+ * @param fieldref the Reference of the field.
+ * @param obj the object of which the field should be taken, null
+ * if the field is static.
+ * @param value the field value. Primitive types are wrapped to
+ * Object.
+ * @exception InterpreterException if the field does not exists, the
+ * object is not supported etc.
+ */
public void putField(Reference fieldref, Object obj, Object value)
throws InterpreterException;
+
+
+ /**
+ * Invoke a method.
+ * @param methodRef the reference to the method.
+ * @param isVirtual true, iff the call is virtual
+ * @param cls the object on which the method should be called, null
+ * if the method is static.
+ * @param params the params of the method. Primitive types are
+ * wrapped to Object.
+ * @return the return value of the method. Primitive types are
+ * wrapped to Object, void type is ignored, may be null.
+ * @exception InterpreterException if the field does not exists, the
+ * object is not supported etc. */
public Object invokeMethod(Reference methodRef, boolean isVirtual,
Object cls, Object[] params)
throws InterpreterException, InvocationTargetException;
@@ -43,3 +88,5 @@ public interface RuntimeEnvironment {
public void exitMonitor(Object obj)
throws InterpreterException;
}
+
+
diff --git a/jode/jode/jvm/SimpleRuntimeEnvironment.java b/jode/jode/jvm/SimpleRuntimeEnvironment.java
index 201ca89..900ad26 100644
--- a/jode/jode/jvm/SimpleRuntimeEnvironment.java
+++ b/jode/jode/jvm/SimpleRuntimeEnvironment.java
@@ -154,24 +154,6 @@ public class SimpleRuntimeEnvironment implements RuntimeEnvironment {
(ref+": Security exception");
}
try {
- Type[] paramTypes = mt.getParameterTypes();
- for (int i = 0; i< paramTypes.length; i++) {
- if (paramTypes[i] instanceof IntegerType
- && paramTypes[i] != Type.tInt) {
- int value = ((Integer) params[i]).intValue();
- if (paramTypes[i] == Type.tBoolean) {
- params[i] = value != 0 ? Boolean.TRUE : Boolean.FALSE;
- } else if (paramTypes[i] == Type.tChar) {
- params[i] = new Character((char) value);
- } else if (paramTypes[i] == Type.tByte) {
- params[i] = new Byte((byte) value);
- } else if (paramTypes[i] == Type.tShort) {
- params[i] = new Short((short) value);
- } else
- throw new AssertError("Unknown integer type: "
- +paramTypes[i]);
- }
- }
return m.invoke(cls, params);
} catch (IllegalAccessException ex) {
throw new InterpreterException
diff --git a/jode/jode/obfuscator/ConstantRuntimeEnvironment.java b/jode/jode/obfuscator/ConstantRuntimeEnvironment.java
index c2a99f5..d882507 100644
--- a/jode/jode/obfuscator/ConstantRuntimeEnvironment.java
+++ b/jode/jode/obfuscator/ConstantRuntimeEnvironment.java
@@ -18,7 +18,9 @@
*/
package jode.obfuscator;
-import jode.jvm.*;
+import jode.jvm.Interpreter;
+import jode.jvm.SimpleRuntimeEnvironment;
+import jode.jvm.InterpreterException;
import jode.bytecode.Reference;
import jode.bytecode.BytecodeInfo;
import jode.type.*;
@@ -213,8 +215,11 @@ public class ConstantRuntimeEnvironment extends SimpleRuntimeEnvironment {
addWhite(Reference.getReference
("Ljava/lang/Math;", "PI", "D"));
}
+
+ private Interpreter interpreter;
public ConstantRuntimeEnvironment() {
+ interpreter = new Interpreter(this);
}
public Object getField(Reference ref, Object obj)
@@ -235,7 +240,7 @@ public class ConstantRuntimeEnvironment extends SimpleRuntimeEnvironment {
public void putField(Reference ref, Object obj, Object value)
throws InterpreterException {
- throw new InterpreterException("Modifiing Field " + ref + ".");
+ throw new InterpreterException("Modifying Field " + ref + ".");
}
public Object invokeConstructor(Reference ref, Object[] params)
@@ -255,20 +260,8 @@ public class ConstantRuntimeEnvironment extends SimpleRuntimeEnvironment {
= (MethodIdentifier) Main.getClassBundle().getIdentifier(ref);
if (mi != null) {
BytecodeInfo code = mi.info.getBytecode();
- if (code != null) {
- MethodType mt = (MethodType) Type.tType(ref.getType());
- Value[] locals = new Value[code.getMaxLocals()];
- for (int i=0; i< locals.length; i++)
- locals[i] = new Value();
- int slot = 0;
- if (cls != null)
- locals[slot++].setObject(cls);
- for (int i = 0; i < params.length; i++) {
- locals[slot].setObject(params[i]);
- slot += mt.getParameterTypes()[i].stackSize();
- }
- return Interpreter.interpretMethod(this, code, locals);
- }
+ if (code != null)
+ return interpreter.interpretMethod(code, cls, params);
}
throw new InterpreterException("Invoking library method " + ref + ".");
}