Interpreter reworked and simplified

git-svn-id: https://svn.code.sf.net/p/jode/code/trunk@1112 379699f6-c40d-0410-875b-85095c16579e
branch_1_1
jochen 25 years ago
parent b15a674928
commit f504348712
  1. 47
      jode/jode/expr/InvokeOperator.java.in
  2. 227
      jode/jode/jvm/Interpreter.java.in
  3. 47
      jode/jode/jvm/RuntimeEnvironment.java
  4. 18
      jode/jode/jvm/SimpleRuntimeEnvironment.java
  5. 25
      jode/jode/obfuscator/ConstantRuntimeEnvironment.java

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

@ -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: {

@ -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. <br>
*
* 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). <br>
*
* @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;
}

@ -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

@ -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 + ".");
}

Loading…
Cancel
Save