From 544e5ff99e0644a7f799e0db899e3ca999c64f98 Mon Sep 17 00:00:00 2001 From: jochen Date: Fri, 9 Apr 1999 08:10:40 +0000 Subject: [PATCH] Initial revision git-svn-id: https://svn.code.sf.net/p/jode/code/trunk@543 379699f6-c40d-0410-875b-85095c16579e --- jode/jode/jvm/CodeVerifier.java | 952 ++++++++++++++++++ jode/jode/jvm/RuntimeEnvironment.java | 45 + jode/jode/jvm/SimpleRuntimeEnvironment.java | 200 ++++ jode/jode/jvm/VerifyException.java | 36 + .../ConstantRuntimeEnvironment.java | 251 +++++ 5 files changed, 1484 insertions(+) create mode 100644 jode/jode/jvm/CodeVerifier.java create mode 100644 jode/jode/jvm/RuntimeEnvironment.java create mode 100644 jode/jode/jvm/SimpleRuntimeEnvironment.java create mode 100644 jode/jode/jvm/VerifyException.java create mode 100644 jode/jode/obfuscator/ConstantRuntimeEnvironment.java diff --git a/jode/jode/jvm/CodeVerifier.java b/jode/jode/jvm/CodeVerifier.java new file mode 100644 index 0000000..66b5765 --- /dev/null +++ b/jode/jode/jvm/CodeVerifier.java @@ -0,0 +1,952 @@ +package jode.jvm; +import jode.bytecode.*; +import jode.Type; +import jode.MethodType; +import jode.ArrayType; +import jode.ClassInterfacesType; +import jode.AssertError; +import jode.Decompiler; +import java.util.BitSet; +import java.util.Stack; + +public class CodeVerifier implements Opcodes { + ClassInfo ci; + MethodInfo mi; + BytecodeInfo bi; + + class UninitializedClassType extends Type { + ClassInfo classType; + boolean maySuper; + public UninitializedClassType(ClassInfo clazz, boolean maySuper) { + super(-TC_CLASS); + this.classType = clazz; + this.maySuper = maySuper; + } + public boolean equals(Object o) { + return o instanceof UninitializedClassType + && ((UninitializedClassType) o).classType.equals(classType); + } + public String toString() { + StringBuffer result = new StringBuffer("new ").append(classType); + if (maySuper) + result.append("(maySuper)"); + return result.toString(); + } + } + + class ReturnAddressType extends Type { + Instruction jsrTarget; + + public ReturnAddressType(Instruction instr) { + super(-TC_METHOD); + jsrTarget = instr; + } + public boolean equals(Object o) { + return o instanceof ReturnAddressType + && ((ReturnAddressType) o).jsrTarget == jsrTarget; + } + public String toString() { + return "returnAddress "+jsrTarget; + } + } + + + /** + * JLS 4.9.6: Verifying code that contains a finally clause: + * - Each instruction keeps track of the list of jsr targets. + * - For each instruction and each jsr needed to reach that instruction + * a bit vector is maintained of all local vars accessed or modified. + */ + + class VerifyInfo implements Cloneable { + Type[] stack = new Type[bi.getMaxStack()]; + Type[] locals = new Type[bi.getMaxLocals()]; + Instruction[] jsrTargets = null; + BitSet[] jsrLocals = null; + int stackHeight = 0; + int maxHeight = 0; + /* If this is a jsr target, this field contains the single + * allowed ret instruction. + */ + Instruction retInstr = null; + + public Object clone() { + try { + VerifyInfo result = (VerifyInfo) super.clone(); + result.stack = (Type[]) stack.clone(); + result.locals = (Type[]) locals.clone(); + return result; + } catch(CloneNotSupportedException ex) { + throw new AssertError("Clone not supported?"); + } + } + + public final void reserve(int count) throws VerifyException { + if (stackHeight + count > maxHeight) { + maxHeight = stackHeight + count; + if (maxHeight > stack.length) + throw new VerifyException("stack overflow"); + } + } + + public final void need(int count) throws VerifyException { + if (stackHeight < count) + throw new VerifyException("stack overflow"); + } + + public final void push(Type type) throws VerifyException { + reserve(1); + stack[stackHeight++] = type; + } + + public final Type pop() throws VerifyException { + need(1); + return stack[--stackHeight]; + } + + public String toString() { + StringBuffer result = new StringBuffer("locals:["); + String comma = ""; + for (int i=0; i")) + info.locals[slot++] = + new UninitializedClassType(ci, true); + else + info.locals[slot++] = Type.tClass(ci); + } + for (int i=0; i< paramTypes.length; i++) { + info.locals[slot++] = paramTypes[i]; + if (paramTypes[i].stackSize() == 2) + info.locals[slot++] = Type.tVoid; + } + while (slot < bi.getMaxLocals()) + info.locals[slot++] = Type.tError; + return info; + } + + public boolean isOfType(Type t1, Type t2) { + if (t1.equals(t2)) + return true; + if (t1.getTypeCode() == Type.TC_INTEGER + && t2.getTypeCode() == Type.TC_INTEGER) + return true; + if (t1 == Type.tUObject) + return (t2.getTypeCode() == Type.TC_CLASS + || t2.getTypeCode() == Type.TC_ARRAY + || t2.getTypeCode() == -Type.TC_CLASS); + if (t2 == Type.tUObject) + return (t1.getTypeCode() == Type.TC_CLASS + || t1.getTypeCode() == Type.TC_ARRAY + || t1.getTypeCode() == -Type.TC_CLASS); + if ((t1.getTypeCode() == Type.TC_CLASS + || t1.getTypeCode() == Type.TC_ARRAY) + && (t2.getTypeCode() == Type.TC_CLASS + || t2.getTypeCode() == Type.TC_ARRAY)) { + if (t1.getTypeCode() == Type.TC_ARRAY) { + if (t2.getTypeCode() == Type.TC_CLASS) + return (t2 == Type.tObject); + Type e1 = ((ArrayType)t1).getElementType(); + Type e2 = ((ArrayType)t2).getElementType(); + if ((e1.getTypeCode() == Type.TC_CLASS + || e1.getTypeCode() == Type.TC_ARRAY + || e1 == Type.tUObject) + && (e2.getTypeCode() == Type.TC_CLASS + || e2.getTypeCode() == Type.TC_ARRAY + || e2 == Type.tUObject)) + return isOfType(e1, e2); + return false; + } else { + if (t2.getTypeCode() == Type.TC_ARRAY) + return false; + ClassInfo c1 = ((ClassInterfacesType) t1).getClazz(); + ClassInfo c2 = ((ClassInterfacesType) t2).getClazz(); + return c2.superClassOf(c1); + } + } + return false; + } + + public Type mergeType(Type t1, Type t2) { + if (t1.equals(t2)) + return t1; + if (t1.getTypeCode() == Type.TC_INTEGER + && t2.getTypeCode() == Type.TC_INTEGER) + return t1; + if (t1 == Type.tUObject) + return (t2.getTypeCode() == Type.TC_CLASS + || t2.getTypeCode() == Type.TC_ARRAY + || t2.getTypeCode() == -Type.TC_CLASS) ? t2 : Type.tError; + if (t2 == Type.tUObject) + return (t1.getTypeCode() == Type.TC_CLASS + || t1.getTypeCode() == Type.TC_ARRAY + || t1.getTypeCode() == -Type.TC_CLASS) ? t1 : Type.tError; + if ((t1.getTypeCode() == Type.TC_CLASS + || t1.getTypeCode() == Type.TC_ARRAY) + && (t2.getTypeCode() == Type.TC_CLASS + || t2.getTypeCode() == Type.TC_ARRAY)) { + if (t1.getTypeCode() == Type.TC_ARRAY) { + if (t2.getTypeCode() == Type.TC_CLASS) + return Type.tObject; + Type e1 = ((ArrayType)t1).getElementType(); + Type e2 = ((ArrayType)t2).getElementType(); + if ((e1.getTypeCode() == Type.TC_CLASS + || e1.getTypeCode() == Type.TC_ARRAY + || e1 == Type.tUObject) + && (e2.getTypeCode() == Type.TC_CLASS + || e2.getTypeCode() == Type.TC_ARRAY + || e2 == Type.tUObject)) + return Type.tArray(mergeType(e1, e2)); + return Type.tObject; + } else { + if (t2.getTypeCode() == Type.TC_ARRAY) + return Type.tObject; + ClassInfo c1 = ((ClassInterfacesType) t1).getClazz(); + ClassInfo c2 = ((ClassInterfacesType) t2).getClazz(); + if (c1.superClassOf(c2)) + return t1; + if (c2.superClassOf(c1)) + return t2; + do { + c1 = c1.getSuperclass(); + } while (!c1.superClassOf(c2)); + return Type.tClass(c1); + } + } + return Type.tError; + } + + public boolean mergeInfo(Instruction instr, VerifyInfo info) + throws VerifyException { + if (instr.tmpInfo == null) { + instr.tmpInfo = info; + return true; + } + boolean changed = false; + VerifyInfo oldInfo = (VerifyInfo) instr.tmpInfo; + if (oldInfo.stackHeight != info.stackHeight) + throw new VerifyException("Stack height differ at: " + + instr.getDescription()); + for (int i=0; i < oldInfo.stackHeight; i++) { + Type newType = mergeType(oldInfo.stack[i], info.stack[i]); + if (!newType.equals(oldInfo.stack[i])) { + if (newType == Type.tError) + throw new VerifyException("Type error while merging: " + + oldInfo.stack[i] + + " and " + info.stack[i]); + changed = true; + oldInfo.stack[i] = newType; + } + } + for (int i=0; i < bi.getMaxLocals(); i++) { + Type newType = mergeType(oldInfo.locals[i], info.locals[i]); + if (!newType.equals(oldInfo.locals[i])) { + changed = true; + oldInfo.locals[i] = newType; + } + } + return changed; + } + + + Type[] types = { Type.tInt, Type.tLong, Type.tFloat, Type.tDouble, + Type.tUObject, Type.tByte, Type.tChar, Type.tShort }; + + public VerifyInfo modelEffect(Instruction instr, VerifyInfo prevInfo) + throws VerifyException { + int jsrLength = + prevInfo.jsrTargets != null ? prevInfo.jsrTargets.length : 0; + VerifyInfo result = (VerifyInfo) prevInfo.clone(); + switch (instr.opcode) { + case opc_nop: + case opc_goto: + break; + case opc_ldc: { + Type type; + if (instr.objData == null) + type = Type.tUObject; + else if (instr.objData instanceof Integer) + type = Type.tInt; + else if (instr.objData instanceof Float) + type = Type.tFloat; + else + type = Type.tString; + result.push(type); + break; + } + case opc_ldc2_w: { + Type type; + if (instr.objData instanceof Long) + type = Type.tLong; + else + type = Type.tDouble; + result.push(type); + result.push(Type.tVoid); + break; + } + case opc_iload: + case opc_lload: + case opc_fload: + case opc_dload: + case opc_aload: { + if (jsrLength > 0 + && (!result.jsrLocals[jsrLength-1].get(instr.localSlot) + || ((instr.opcode & 0x1) == 0 + && !result.jsrLocals[jsrLength-1] + .get(instr.localSlot+1)))) { + result.jsrLocals = (BitSet[]) result.jsrLocals.clone(); + result.jsrLocals[jsrLength-1] + = (BitSet) result.jsrLocals[jsrLength-1].clone(); + result.jsrLocals[jsrLength-1].set(instr.localSlot); + if ((instr.opcode & 0x1) == 0) + result.jsrLocals[jsrLength-1].set(instr.localSlot + 1); + } + if ((instr.opcode & 0x1) == 0 + && result.locals[instr.localSlot+1] != Type.tVoid) + throw new VerifyException(instr.getDescription()); + Type type = result.locals[instr.localSlot]; + if (!isOfType(type, types[instr.opcode - opc_iload])) + throw new VerifyException(instr.getDescription()); + result.push(type); + if ((instr.opcode & 0x1) == 0) + result.push(Type.tVoid); + 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: { + if (!isOfType(result.pop(), Type.tInt)) + throw new VerifyException(instr.getDescription()); + Type arrType = result.pop(); + if (!isOfType(arrType, + Type.tArray(types[instr.opcode - opc_iaload])) + && (instr.opcode != opc_baload + || !isOfType(arrType, Type.tArray(Type.tBoolean)))) + throw new VerifyException(instr.getDescription()); + + result.push(((ArrayType)arrType).getElementType()); + if (((1 << instr.opcode - opc_iaload) & 0xa) != 0) + result.push(Type.tVoid); + break; + } + case opc_istore: case opc_lstore: + case opc_fstore: case opc_dstore: case opc_astore: { + if (jsrLength > 0 + && (!result.jsrLocals[jsrLength-1].get(instr.localSlot) + || ((instr.opcode & 0x1) != 0 + && !result.jsrLocals[jsrLength-1] + .get(instr.localSlot+1)))) { + result.jsrLocals = (BitSet[]) result.jsrLocals.clone(); + result.jsrLocals[jsrLength-1] + = (BitSet) result.jsrLocals[jsrLength-1].clone(); + result.jsrLocals[jsrLength-1].set(instr.localSlot); + if ((instr.opcode & 0x1) != 0) + result.jsrLocals[jsrLength-1].set(instr.localSlot + 1); + } + if ((instr.opcode & 0x1) != 0 + && result.pop() != Type.tVoid) + throw new VerifyException(instr.getDescription()); + Type type = result.pop(); + if (instr.opcode != opc_astore + || !(type instanceof ReturnAddressType)) + if (!isOfType(type, types[instr.opcode - opc_istore])) + throw new VerifyException(instr.getDescription()); + result.locals[instr.localSlot] = type; + if ((instr.opcode & 0x1) != 0) + result.locals[instr.localSlot+1] = Type.tVoid; + break; + } + case opc_iastore: case opc_lastore: + case opc_fastore: case opc_dastore: case opc_aastore: + case opc_bastore: case opc_castore: case opc_sastore: { + if (((1 << instr.opcode - opc_iastore) & 0xa) != 0 + && result.pop() != Type.tVoid) + throw new VerifyException(instr.getDescription()); + Type type = result.pop(); + if (!isOfType(result.pop(), Type.tInt)) + throw new VerifyException(instr.getDescription()); + Type arrType = result.pop(); + if (!isOfType(arrType, + Type.tArray(types[instr.opcode - opc_iastore])) + && (instr.opcode != opc_bastore + || !isOfType(arrType, Type.tArray(Type.tBoolean)))) + throw new VerifyException(instr.getDescription()); + if (!isOfType(type, ((ArrayType)arrType).getElementType())) + throw new VerifyException(instr.getDescription()); + break; + } + case opc_pop: case opc_pop2: + result.stackHeight -= instr.opcode - (opc_pop-1); + break; + case opc_dup: case opc_dup_x1: case opc_dup_x2: { + int depth = instr.opcode - opc_dup; + result.reserve(1); + result.need(depth+1); + if (result.stack[result.stackHeight-1] == Type.tVoid) + throw new VerifyException(instr.getDescription()); + + int stackdepth = result.stackHeight - (depth + 1); + if (result.stack[stackdepth] == Type.tVoid) + throw new VerifyException(instr.getDescription() + + " on long or double"); + for (int i=result.stackHeight; i > stackdepth; i--) + result.stack[i] = result.stack[i-1]; + result.stack[stackdepth] = result.stack[result.stackHeight++]; + break; + } + case opc_dup2: case opc_dup2_x1: case opc_dup2_x2: { + int depth = instr.opcode - opc_dup2; + result.reserve(2); + result.need(depth+2); + if (result.stack[result.stackHeight-2] == Type.tVoid) + throw new VerifyException(instr.getDescription() + + " on misaligned long or double"); + int stacktop = result.stackHeight; + int stackdepth = stacktop - (depth + 2); + if (result.stack[stackdepth] == Type.tVoid) + throw new VerifyException(instr.getDescription() + + " on long or double"); + for (int i=stacktop; i > stackdepth; i--) + result.stack[i+1] = result.stack[i-1]; + result.stack[stackdepth+1] = result.stack[stacktop+1]; + result.stack[stackdepth] = result.stack[stacktop]; + result.stackHeight+=2; + break; + } + case opc_swap: { + result.need(2); + if (result.stack[result.stackHeight-2] == Type.tVoid + || result.stack[result.stackHeight-1] == Type.tVoid) + throw new VerifyException(instr.getDescription() + + " on misaligned long or double"); + Type tmp = result.stack[result.stackHeight-1]; + result.stack[result.stackHeight-1] = + result.stack[result.stackHeight-2]; + result.stack[result.stackHeight-2] = tmp; + break; + } + case opc_iadd: case opc_ladd: case opc_fadd: case opc_dadd: + case opc_isub: case opc_lsub: case opc_fsub: case opc_dsub: + case opc_imul: case opc_lmul: case opc_fmul: case opc_dmul: + case opc_idiv: case opc_ldiv: case opc_fdiv: case opc_ddiv: + case opc_irem: case opc_lrem: case opc_frem: case opc_drem: { + Type type = types[(instr.opcode - opc_iadd) & 3]; + if ((instr.opcode & 1) != 0 + && result.pop() != Type.tVoid) + throw new VerifyException(instr.getDescription()); + if (!isOfType(result.pop(), type)) + throw new VerifyException(instr.getDescription()); + if ((instr.opcode & 1) != 0) { + result.need(2); + if (result.stack[result.stackHeight-1] != Type.tVoid + || !isOfType(result.stack[result.stackHeight-2], type)) + throw new VerifyException(instr.getDescription()); + } else { + result.need(1); + if (!isOfType(result.stack[result.stackHeight-1], type)) + throw new VerifyException(instr.getDescription()); + } + break; + } + case opc_ineg: case opc_lneg: case opc_fneg: case opc_dneg: { + Type type = types[(instr.opcode - opc_ineg) & 3]; + if ((instr.opcode & 1) != 0) { + result.need(2); + if (result.stack[result.stackHeight-1] != Type.tVoid + || !isOfType(result.stack[result.stackHeight-2], type)) + throw new VerifyException(instr.getDescription()); + } else { + result.need(1); + if (!isOfType(result.stack[result.stackHeight-1], type)) + throw new VerifyException(instr.getDescription()); + } + break; + } + case opc_ishl: case opc_lshl: + case opc_ishr: case opc_lshr: + case opc_iushr: case opc_lushr: + if (!isOfType(result.pop(), Type.tInt)) + throw new VerifyException(instr.getDescription()); + + if ((instr.opcode & 1) != 0) { + result.need(2); + if (result.stack[result.stackHeight-1] != Type.tVoid || + !isOfType(result.stack[result.stackHeight-2],Type.tLong)) + throw new VerifyException(instr.getDescription()); + } else { + result.need(1); + if (!isOfType(result.stack[result.stackHeight-1],Type.tInt)) + throw new VerifyException(instr.getDescription()); + } + break; + + case opc_iand: case opc_land: + case opc_ior : case opc_lor : + case opc_ixor: case opc_lxor: + if ((instr.opcode & 1) != 0 + && result.pop() != Type.tVoid) + throw new VerifyException(instr.getDescription()); + if (!isOfType(result.pop(), + types[instr.opcode & 1])) + throw new VerifyException(instr.getDescription()); + if ((instr.opcode & 1) != 0) { + result.need(2); + if (result.stack[result.stackHeight-1] != Type.tVoid + || !isOfType(result.stack[result.stackHeight-2], + Type.tLong)) + throw new VerifyException(instr.getDescription()); + } else { + result.need(1); + if (!isOfType(result.stack[result.stackHeight-1], + Type.tInt)) + throw new VerifyException(instr.getDescription()); + } + break; + + case opc_iinc: + if (!isOfType(result.locals[instr.localSlot], Type.tInt)) + throw new VerifyException(instr.getDescription()); + break; + case opc_i2l: case opc_i2f: case opc_i2d: + case opc_l2i: case opc_l2f: case opc_l2d: + case opc_f2i: case opc_f2l: case opc_f2d: + case opc_d2i: case opc_d2l: case opc_d2f: { + int from = (instr.opcode-opc_i2l)/3; + int to = (instr.opcode-opc_i2l)%3; + if (to >= from) + to++; + if ((from & 1) != 0 + && result.pop() != Type.tVoid) + throw new VerifyException(instr.getDescription()); + if (!isOfType(result.pop(), types[from])) + throw new VerifyException(instr.getDescription()); + + result.push(types[to]); + if ((to & 1) != 0) + result.push(Type.tVoid); + break; + } + case opc_i2b: case opc_i2c: case opc_i2s: + result.need(1); + if (!isOfType(result.stack[result.stackHeight-1], Type.tInt)) + throw new VerifyException(instr.getDescription()); + break; + + case opc_lcmp: + if (result.pop() != Type.tVoid) + throw new VerifyException(instr.getDescription()); + if (result.pop() != Type.tLong) + throw new VerifyException(instr.getDescription()); + if (result.pop() != Type.tVoid) + throw new VerifyException(instr.getDescription()); + if (result.pop() != Type.tLong) + throw new VerifyException(instr.getDescription()); + result.push(Type.tInt); + break; + case opc_dcmpl: case opc_dcmpg: + if (result.pop() != Type.tVoid) + throw new VerifyException(instr.getDescription()); + if (result.pop() != Type.tDouble) + throw new VerifyException(instr.getDescription()); + if (result.pop() != Type.tVoid) + throw new VerifyException(instr.getDescription()); + if (result.pop() != Type.tDouble) + throw new VerifyException(instr.getDescription()); + result.push(Type.tInt); + break; + case opc_fcmpl: case opc_fcmpg: + if (result.pop() != Type.tFloat) + throw new VerifyException(instr.getDescription()); + if (result.pop() != Type.tFloat) + throw new VerifyException(instr.getDescription()); + result.push(Type.tInt); + break; + + case opc_ifeq: case opc_ifne: + case opc_iflt: case opc_ifge: + case opc_ifgt: case opc_ifle: + case opc_tableswitch: + case opc_lookupswitch: + if (!isOfType(result.pop(), Type.tInt)) + throw new VerifyException(instr.getDescription()); + break; + + case opc_if_icmpeq: case opc_if_icmpne: + case opc_if_icmplt: case opc_if_icmpge: + case opc_if_icmpgt: case opc_if_icmple: + if (!isOfType(result.pop(), Type.tInt)) + throw new VerifyException(instr.getDescription()); + if (!isOfType(result.pop(), Type.tInt)) + throw new VerifyException(instr.getDescription()); + break; + case opc_if_acmpeq: case opc_if_acmpne: + if (!isOfType(result.pop(), Type.tUObject)) + throw new VerifyException(instr.getDescription()); + if (!isOfType(result.pop(), Type.tUObject)) + throw new VerifyException(instr.getDescription()); + break; + case opc_ifnull: case opc_ifnonnull: + if (!isOfType(result.pop(), Type.tUObject)) + throw new VerifyException(instr.getDescription()); + break; + + case opc_ireturn: case opc_lreturn: + case opc_freturn: case opc_dreturn: case opc_areturn: { + if (((1 << instr.opcode - opc_ireturn) & 0xa) != 0 + && result.pop() != Type.tVoid) + throw new VerifyException(instr.getDescription()); + Type type = result.pop(); + if (!isOfType(type, types[instr.opcode - opc_ireturn]) + || !isOfType(type, mi.getType().getReturnType())) + throw new VerifyException(instr.getDescription()); + break; + } + case opc_jsr: { + result.stack[result.stackHeight++] + = new ReturnAddressType(instr.succs[0]); + result.jsrTargets = new Instruction[jsrLength+1]; + result.jsrLocals = new BitSet[jsrLength+1]; + if (jsrLength > 0) { + for (int i=0; i< prevInfo.jsrTargets.length; i++) + if (prevInfo.jsrTargets[i] == instr.succs[0]) + throw new VerifyException(instr.getDescription()+ + " is recursive"); + System.arraycopy(prevInfo.jsrTargets, 0, + result.jsrTargets, 0, jsrLength); + System.arraycopy(prevInfo.jsrLocals, 0, + result.jsrLocals, 0, jsrLength); + } + result.jsrTargets[jsrLength] = instr.succs[0]; + result.jsrLocals[jsrLength] = new BitSet(); + break; + } + case opc_return: + if (mi.getType().getReturnType() != Type.tVoid) + throw new VerifyException(instr.getDescription()); + break; + + case opc_getstatic: { + Reference ref = (Reference) instr.objData; + Type type = Type.tType(ref.getType()); + result.push(type); + if (type.stackSize() == 2) + result.push(Type.tVoid); + break; + } + case opc_getfield: { + Reference ref = (Reference) instr.objData; + Type classType = Type.tClass(ref.getClazz()); + if (!isOfType(result.pop(), classType)) + throw new VerifyException(instr.getDescription()); + Type type = Type.tType(ref.getType()); + result.push(type); + if (type.stackSize() == 2) + result.push(Type.tVoid); + break; + } + case opc_putstatic: { + Reference ref = (Reference) instr.objData; + Type type = Type.tType(ref.getType()); + if (type.stackSize() == 2 + && result.pop() != Type.tVoid) + throw new VerifyException(instr.getDescription()); + if (!isOfType(result.pop(), type)) + throw new VerifyException(instr.getDescription()); + break; + } + case opc_putfield: { + Reference ref = (Reference) instr.objData; + Type type = Type.tType(ref.getType()); + if (type.stackSize() == 2 + && result.pop() != Type.tVoid) + throw new VerifyException(instr.getDescription()); + if (!isOfType(result.pop(), type)) + throw new VerifyException(instr.getDescription()); + Type classType = Type.tClass(ref.getClazz()); + if (!isOfType(result.pop(), classType)) + throw new VerifyException(instr.getDescription()); + break; + } + case opc_invokevirtual: + case opc_invokespecial: + case opc_invokestatic : + case opc_invokeinterface: { + Reference ref = (Reference) instr.objData; + MethodType mt = (MethodType) Type.tType(ref.getType()); + Type[] paramTypes = mt.getParameterTypes(); + for (int i=paramTypes.length - 1; i >= 0; i--) { + if (paramTypes[i].stackSize() == 2 + && result.pop() != Type.tVoid) + throw new VerifyException(instr.getDescription()); + if (!isOfType(result.pop(), + paramTypes[i])) + throw new VerifyException(instr.getDescription()); + } + if (ref.getName().equals("")) { + Type clazz = result.pop(); + if (!(clazz instanceof UninitializedClassType)) + throw new VerifyException(instr.getDescription()); + UninitializedClassType uct = (UninitializedClassType) clazz; + ClassInfo refCi = ClassInfo.forName(ref.getClazz()); + if (refCi != uct.classType + && (!uct.maySuper + || refCi != uct.classType.getSuperclass())) + throw new VerifyException(instr.getDescription()); + Type newType = Type.tClass(uct.classType); + for (int i=0; i< result.stackHeight; i++) + if (result.stack[i] == clazz) + result.stack[i] = newType; + for (int i=0; i< result.locals.length; i++) + if (result.locals[i] == clazz) + result.locals[i] = newType; + } else if (instr.opcode != opc_invokestatic) { + Type classType = Type.tClass(ref.getClazz()); + if (!isOfType(result.pop(), classType)) + throw new VerifyException(instr.getDescription()); + } + Type type = mt.getReturnType(); + if (type != Type.tVoid) { + result.push(type); + if (type.stackSize() == 2) + result.push(Type.tVoid); + } + break; + } + case opc_new: { + ClassInfo ci = ClassInfo.forName((String) instr.objData); + result.stack[result.stackHeight++] = + new UninitializedClassType(ci, false); + break; + } + case opc_arraylength: { + if (result.pop().getTypeCode() + != Type.TC_ARRAY) + throw new VerifyException(instr.getDescription()); + result.push(Type.tInt); + break; + } + case opc_athrow: { + if (!isOfType(result.pop(), + Type.tClass("java.lang.Throwable"))) + throw new VerifyException(instr.getDescription()); + break; + } + case opc_checkcast: { + Type classType = Type.tClassOrArray((String) instr.objData); + if (!isOfType(result.pop(), Type.tUObject)) + throw new VerifyException(instr.getDescription()); + result.push(classType); + break; + } + case opc_instanceof: { + if (!isOfType(result.pop(), Type.tObject)) + throw new VerifyException(instr.getDescription()); + result.push(Type.tInt); + break; + } + case opc_monitorenter: + case opc_monitorexit: + if (!isOfType(result.pop(), Type.tObject)) + throw new VerifyException(instr.getDescription()); + break; + case opc_multianewarray: { + int dimension = instr.intData; + for (int i=dimension - 1; i >= 0; i--) + if (!isOfType(result.pop(), Type.tInt)) + throw new VerifyException(instr.getDescription()); + Type classType = Type.tType((String) instr.objData); + result.push(classType); + break; + } + default: + throw new AssertError("Invalid opcode "+instr.opcode); + } + return result; + } + + public void doVerify() throws VerifyException { + Stack instrStack = new Stack(); + + bi.getFirstInstr().tmpInfo = initInfo(); + instrStack.push(bi.getFirstInstr()); + Handler[] handlers = bi.getExceptionHandlers(); + while (!instrStack.isEmpty()) { + Instruction instr = (Instruction) instrStack.pop(); + if (!instr.alwaysJumps && instr.nextByAddr == null) + throw new VerifyException("Flow can fall off end of method"); + + VerifyInfo prevInfo = (VerifyInfo) instr.tmpInfo; + if (instr.opcode == opc_ret) { + if (prevInfo.jsrTargets == null + || !(prevInfo.locals[instr.localSlot] + instanceof ReturnAddressType)) + throw new VerifyException(instr.getDescription()); + int jsrLength = prevInfo.jsrTargets.length - 1; + Instruction jsrTarget = + ((ReturnAddressType) + prevInfo.locals[instr.localSlot]).jsrTarget; + if (jsrTarget != prevInfo.jsrTargets[jsrLength]) + throw new VerifyException(instr.getDescription()); + VerifyInfo jsrTargetInfo = (VerifyInfo) jsrTarget.tmpInfo; + if (jsrTargetInfo.retInstr == null) + jsrTargetInfo.retInstr = instr; + else if (jsrTargetInfo.retInstr != instr) + throw new VerifyException + ("JsrTarget has more than one ret: " + + jsrTarget.getDescription()); + Instruction[] nextTargets; + BitSet[] nextLocals; + if (jsrLength > 0) { + nextTargets = new Instruction[jsrLength]; + nextLocals = new BitSet[jsrLength]; + System.arraycopy(prevInfo.jsrTargets, 0, + nextTargets, 0, jsrLength); + System.arraycopy(prevInfo.jsrLocals, 0, + nextLocals, 0, jsrLength); + } else { + nextTargets = null; + nextLocals = null; + } + BitSet usedLocals = prevInfo.jsrLocals[jsrLength]; + for (int i=0; i < jsrTarget.preds.length; i++) { + Instruction jsrInstr = jsrTarget.preds[i]; + VerifyInfo jsrInfo = (VerifyInfo) jsrInstr.tmpInfo; + if (jsrInfo == null) + continue; + VerifyInfo afterJsrInfo = (VerifyInfo) jsrInfo.clone(); + for (int j = 0; j < bi.getMaxLocals(); j++) { + if (usedLocals.get(j)) + afterJsrInfo.locals[j] = prevInfo.locals[j]; + } + if (mergeInfo(jsrInstr.nextByAddr, afterJsrInfo)) + instrStack.push(jsrInstr.nextByAddr); + } + } else { + VerifyInfo info = modelEffect(instr, prevInfo); + if (!instr.alwaysJumps) + if (mergeInfo(instr.nextByAddr, info)) + instrStack.push(instr.nextByAddr); + if (instr.opcode == opc_jsr) { + VerifyInfo targetInfo = + (VerifyInfo) instr.succs[0].tmpInfo; + if (targetInfo != null && targetInfo.retInstr != null) { + VerifyInfo afterJsrInfo + = (VerifyInfo) prevInfo.clone(); + VerifyInfo retInfo + = (VerifyInfo) targetInfo.retInstr.tmpInfo; + BitSet usedLocals + = retInfo.jsrLocals[retInfo.jsrLocals.length-1]; + for (int j = 0; j < bi.getMaxLocals(); j++) { + if (usedLocals.get(j)) + afterJsrInfo.locals[j] = retInfo.locals[j]; + } + if (mergeInfo(instr.nextByAddr, afterJsrInfo)) + instrStack.push(instr.nextByAddr); + } + } + if (instr.succs != null) { + for (int i=0; i< instr.succs.length; i++) { + if (instr.succs[i].addr < instr.addr) { + /* This is a backwards branch */ + for (int j = 0; j < prevInfo.locals.length; j++) { + if (prevInfo.locals[j] + instanceof UninitializedClassType) + throw new VerifyException + ("Uninitialized local in back-branch"); + } + for (int j = 0; j < prevInfo.stackHeight; j++) { + if (prevInfo.stack[j] + instanceof UninitializedClassType) + throw new VerifyException + ("Uninitialized stack in back-branch"); + } + } + if (mergeInfo(instr.succs[i], + (VerifyInfo) info.clone())) + instrStack.push(instr.succs[i]); + } + } + for (int i=0; i= instr.addr) { + for (int j = 0; j < prevInfo.locals.length; j++) { + if (prevInfo.locals[j] + instanceof UninitializedClassType) + throw new VerifyException + ("Uninitialized local in try block"); + } + VerifyInfo excInfo = (VerifyInfo) prevInfo.clone(); + excInfo.stackHeight = 1; + if (handlers[i].type != null) + excInfo.stack[0] = Type.tClass(handlers[i].type); + else + excInfo.stack[0] = + Type.tClass("java.lang.Throwable"); + if (mergeInfo(handlers[i].catcher, excInfo)) + instrStack.push(handlers[i].catcher); + } + } + } + } + + for (Instruction instr = bi.getFirstInstr(); instr != null; + instr = instr.nextByAddr) + instr.tmpInfo = null; + } + + + public void verify() throws VerifyException { + try { + doVerify(); + } catch (VerifyException ex) { + for (Instruction instr = bi.getFirstInstr(); instr != null; + instr = instr.nextByAddr) { + + VerifyInfo info = (VerifyInfo) instr.tmpInfo; + if (info != null) + System.err.println(info.toString()); + System.err.println(instr.getDescription()); + + instr.tmpInfo = null; + } + throw ex; + } + } +} diff --git a/jode/jode/jvm/RuntimeEnvironment.java b/jode/jode/jvm/RuntimeEnvironment.java new file mode 100644 index 0000000..97292af --- /dev/null +++ b/jode/jode/jvm/RuntimeEnvironment.java @@ -0,0 +1,45 @@ +/* RuntimeEnvironment 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.bytecode.Reference; +import java.lang.reflect.InvocationTargetException; + +public interface RuntimeEnvironment { + public Object getField(Reference fieldref, Object obj) + throws InterpreterException; + public void putField(Reference fieldref, Object obj, Object value) + throws InterpreterException; + public Object invokeMethod(Reference methodRef, boolean isVirtual, + Object cls, Object[] params) + throws InterpreterException, InvocationTargetException; + public Object invokeConstructor(Reference methodRef, Object[] params) + throws InterpreterException, InvocationTargetException; + + public boolean instanceOf(Object obj, String className) + throws InterpreterException; + + public Object newArray(String type, int[] dimensions) + throws InterpreterException; + + public void enterMonitor(Object obj) + throws InterpreterException; + public void exitMonitor(Object obj) + throws InterpreterException; +} diff --git a/jode/jode/jvm/SimpleRuntimeEnvironment.java b/jode/jode/jvm/SimpleRuntimeEnvironment.java new file mode 100644 index 0000000..040af04 --- /dev/null +++ b/jode/jode/jvm/SimpleRuntimeEnvironment.java @@ -0,0 +1,200 @@ +/* RuntimeEnvironment 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.bytecode.Reference; +import jode.*; +import java.lang.reflect.*; + +public class SimpleRuntimeEnvironment implements RuntimeEnvironment { + + public Object getField(Reference ref, Object obj) + throws InterpreterException { + Field f; + try { + Class clazz = Class.forName(ref.getClazz()); + try { + f = clazz.getField(ref.getName()); + } catch (NoSuchFieldException ex) { + f = clazz.getDeclaredField(ref.getName()); + } + } catch (ClassNotFoundException ex) { + throw new InterpreterException + (ref+": Class not found"); + } catch (NoSuchFieldException ex) { + throw new InterpreterException + ("Constructor "+ref+" not found"); + } catch (SecurityException ex) { + throw new InterpreterException + (ref+": Security exception"); + } + try { + return f.get(obj); + } catch (IllegalAccessException ex) { + throw new InterpreterException + ("Field " + ref + " not accessible"); + } + } + public void putField(Reference ref, Object obj, Object value) + throws InterpreterException { + Field f; + try { + Class clazz = Class.forName(ref.getClazz()); + try { + f = clazz.getField(ref.getName()); + } catch (NoSuchFieldException ex) { + f = clazz.getDeclaredField(ref.getName()); + } + } catch (ClassNotFoundException ex) { + throw new InterpreterException + (ref+": Class not found"); + } catch (NoSuchFieldException ex) { + throw new InterpreterException + ("Constructor "+ref+" not found"); + } catch (SecurityException ex) { + throw new InterpreterException + (ref+": Security exception"); + } + try { + f.set(obj, value); + } catch (IllegalAccessException ex) { + throw new InterpreterException + ("Field " + ref + " not accessible"); + } + } + + public Object invokeConstructor(Reference ref, Object[] params) + throws InterpreterException, InvocationTargetException { + Constructor c; + try { + Class clazz = Class.forName(ref.getClazz()); + MethodType mt = (MethodType) Type.tType(ref.getType()); + Class[] paramTypes = mt.getParameterClasses(); + try { + c = clazz.getConstructor(paramTypes); + } catch (NoSuchMethodException ex) { + c = clazz.getDeclaredConstructor(paramTypes); + } + } catch (ClassNotFoundException ex) { + throw new InterpreterException + (ref+": Class not found"); + } catch (NoSuchMethodException ex) { + throw new InterpreterException + ("Constructor "+ref+" not found"); + } catch (SecurityException ex) { + throw new InterpreterException + (ref+": Security exception"); + } + + try { + return c.newInstance(params); + } catch (IllegalAccessException ex) { + throw new InterpreterException + ("Constructor " + ref + " not accessible"); + } catch (InstantiationException ex) { + throw new InterpreterException + ("InstantiationException in " + ref + "."); + } + } + + public Object invokeMethod(Reference ref, boolean isVirtual, + Object cls, Object[] params) + throws InterpreterException, InvocationTargetException { + Method m; + if (!isVirtual && cls != null) /*XXX*/ + throw new InterpreterException + ("Can't invoke nonvirtual Method " + ref + "."); + MethodType mt = (MethodType) Type.tType(ref.getType()); + try { + Class clazz = Class.forName(ref.getClazz()); + Class[] paramTypes = mt.getParameterClasses(); + try { + m = clazz.getMethod(ref.getName(), paramTypes); + } catch (NoSuchMethodException ex) { + m = clazz.getDeclaredMethod(ref.getName(), paramTypes); + } + } catch (ClassNotFoundException ex) { + throw new InterpreterException + (ref+": Class not found"); + } catch (NoSuchMethodException ex) { + throw new InterpreterException + ("Method "+ref+" not found"); + } catch (SecurityException ex) { + throw new InterpreterException + (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 + ("Method " + ref + " not accessible"); + } + } + + public boolean instanceOf(Object obj, String className) + throws InterpreterException { + Class clazz; + try { + clazz = Class.forName(className); + } catch (ClassNotFoundException ex) { + throw new InterpreterException + ("Class "+ex.getMessage()+" not found"); + } + return obj != null && !clazz.isInstance(obj); + } + + public Object newArray(String type, int[] dimensions) + throws InterpreterException, NegativeArraySizeException { + Class clazz; + try { + clazz = Class.forName(type); + } catch (ClassNotFoundException ex) { + throw new InterpreterException + ("Class "+ex.getMessage()+" not found"); + } + return Array.newInstance(clazz, dimensions); + } + + public void enterMonitor(Object obj) + throws InterpreterException { + throw new InterpreterException("monitorenter not implemented"); + } + public void exitMonitor(Object obj) + throws InterpreterException { + throw new InterpreterException("monitorenter not implemented"); + } +} diff --git a/jode/jode/jvm/VerifyException.java b/jode/jode/jvm/VerifyException.java new file mode 100644 index 0000000..e769ea7 --- /dev/null +++ b/jode/jode/jvm/VerifyException.java @@ -0,0 +1,36 @@ +/* VerifyException 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.bytecode.*; + +/** + * This exception is thrown by the CodeVerifier on various conditions. + * + * @author Jochen Hoenicke + */ +public class VerifyException extends Exception { + public VerifyException(String detail) { + super(detail); + } + public VerifyException() { + super(); + } +} + diff --git a/jode/jode/obfuscator/ConstantRuntimeEnvironment.java b/jode/jode/obfuscator/ConstantRuntimeEnvironment.java new file mode 100644 index 0000000..90fbcd4 --- /dev/null +++ b/jode/jode/obfuscator/ConstantRuntimeEnvironment.java @@ -0,0 +1,251 @@ +/* ConstantRuntimeEnvironment 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.obfuscator; +import jode.jvm.*; +import jode.bytecode.Reference; +import jode.bytecode.BytecodeInfo; +import jode.*; +import java.lang.reflect.Array; +import java.lang.reflect.InvocationTargetException; +import java.util.*; + +public class ConstantRuntimeEnvironment extends SimpleRuntimeEnvironment { + + /** + * The references that may be used in constant methods. + */ +///#ifdef JDK12 +/// static Set whiteList = new HashSet(); +/// +/// static void addWhite(Reference ref) { +/// /* note that this gets inlined */ +/// whiteList.add(ref); +/// } +/// +/// public static boolean isWhite(Reference ref) { +/// return whiteList.contains(ref); +/// } +///#else + static Hashtable whiteList = new Hashtable(); + + static void addWhite(Reference ref) { + /* note that this gets inlined */ + whiteList.put(ref, ref); + } + + public static boolean isWhite(Reference ref) { + return whiteList.containsKey(ref); + } +///#endif + + static { + addWhite(new Reference("java.lang.String", "toCharArray", "()[C")); + addWhite(new Reference("java.lang.StringBuffer", "", + "(Ljava/lang/String;)V")); + addWhite(new Reference("java.lang.StringBuffer", "append", + "(Ljava/lang/String;)Ljava/lang/StringBuffer;")); + addWhite(new Reference("java.lang.StringBuffer", "append", + "(C)Ljava/lang/StringBuffer;")); + addWhite(new Reference("java.lang.StringBuffer", "append", + "(B)Ljava/lang/StringBuffer;")); + addWhite(new Reference("java.lang.StringBuffer", "append", + "(S)Ljava/lang/StringBuffer;")); + addWhite(new Reference("java.lang.StringBuffer", "append", + "(Z)Ljava/lang/StringBuffer;")); + addWhite(new Reference("java.lang.StringBuffer", "append", + "(F)Ljava/lang/StringBuffer;")); + addWhite(new Reference("java.lang.StringBuffer", "append", + "(I)Ljava/lang/StringBuffer;")); + addWhite(new Reference("java.lang.StringBuffer", "append", + "(J)Ljava/lang/StringBuffer;")); + addWhite(new Reference("java.lang.StringBuffer", "append", + "(D)Ljava/lang/StringBuffer;")); + addWhite(new Reference("java.lang.StringBuffer", "toString", + "()Ljava/lang/String;")); + addWhite(new Reference("java.lang.String", "", "()V")); + addWhite(new Reference("java.lang.String", "", "([C)V")); + addWhite(new Reference("java.lang.String", "", "([CII)V")); + addWhite(new Reference("java.lang.String", "", + "(Ljava/lang/String;)V")); + addWhite(new Reference("java.lang.String", "", + "(Ljava/lang/StringBuffer;)V")); + addWhite(new Reference("java.lang.String", "length", "()I")); + addWhite(new Reference("java.lang.String", "valueOf", + "(Z)Ljava/lang/String;")); + addWhite(new Reference("java.lang.String", "valueOf", + "(B)Ljava/lang/String;")); + addWhite(new Reference("java.lang.String", "valueOf", + "(S)Ljava/lang/String;")); + addWhite(new Reference("java.lang.String", "valueOf", + "(C)Ljava/lang/String;")); + addWhite(new Reference("java.lang.String", "valueOf", + "(D)Ljava/lang/String;")); + addWhite(new Reference("java.lang.String", "valueOf", + "(F)Ljava/lang/String;")); + addWhite(new Reference("java.lang.String", "valueOf", + "(I)Ljava/lang/String;")); + addWhite(new Reference("java.lang.String", "valueOf", + "(J)Ljava/lang/String;")); + addWhite(new Reference("java.lang.String", "valueOf", + "(Ljava/lang/Object;)Ljava/lang/String;")); + addWhite(new Reference("java.lang.String", "substring", + "(I)Ljava/lang/String;")); + addWhite(new Reference("java.lang.String", "substring", + "(II)Ljava/lang/String;")); + addWhite(new Reference("java.lang.Math", "abs", "(D)D")); + addWhite(new Reference("java.lang.Math", "abs", "(F)F")); + addWhite(new Reference("java.lang.Math", "abs", "(I)I")); + addWhite(new Reference("java.lang.Math", "abs", "(J)J")); + addWhite(new Reference("java.lang.Math", "acos", "(D)D")); + addWhite(new Reference("java.lang.Math", "asin", "(D)D")); + addWhite(new Reference("java.lang.Math", "atan", "(D)D")); + addWhite(new Reference("java.lang.Math", "atan2", "(D)D")); + addWhite(new Reference("java.lang.Math", "ceil", "(D)D")); + addWhite(new Reference("java.lang.Math", "cos", "(D)D")); + addWhite(new Reference("java.lang.Math", "exp", "(D)D")); + addWhite(new Reference("java.lang.Math", "floor", "(D)D")); + addWhite(new Reference("java.lang.Math", "IEEEremainder", "(DD)D")); + addWhite(new Reference("java.lang.Math", "log", "(D)D")); + addWhite(new Reference("java.lang.Math", "max", "(DD)D")); + addWhite(new Reference("java.lang.Math", "max", "(FF)F")); + addWhite(new Reference("java.lang.Math", "max", "(II)I")); + addWhite(new Reference("java.lang.Math", "max", "(JJ)J")); + addWhite(new Reference("java.lang.Math", "min", "(DD)D")); + addWhite(new Reference("java.lang.Math", "min", "(FF)F")); + addWhite(new Reference("java.lang.Math", "min", "(II)I")); + addWhite(new Reference("java.lang.Math", "min", "(JJ)J")); + addWhite(new Reference("java.lang.Math", "pow", "(DD)D")); + addWhite(new Reference("java.lang.Math", "rint", "(D)D")); + addWhite(new Reference("java.lang.Math", "round", "(D)J")); + addWhite(new Reference("java.lang.Math", "round", "(F)I")); + addWhite(new Reference("java.lang.Math", "sin", "(D)D")); + addWhite(new Reference("java.lang.Math", "sqrt", "(D)D")); + addWhite(new Reference("java.lang.Math", "tan", "(D)D")); + addWhite(new Reference("java.lang.Math", "toDegrees", "(D)D")); + addWhite(new Reference("java.lang.Math", "toRadians", "(D)D")); + addWhite(new Reference("java.lang.Math", "E", "D")); + addWhite(new Reference("java.lang.Math", "PI", "D")); + } + + MethodIdentifier m; + public ConstantRuntimeEnvironment(MethodIdentifier method) { + m = method; + } + + public Object getField(Reference ref, Object obj) + throws InterpreterException { + if (isWhite(ref)) + return super.getField(ref, obj); + Type type = Type.tType(ref.getType()); + ClassIdentifier ci = (ClassIdentifier) + m.clazz.bundle.getIdentifier(ref.getClazz()); + if (ci != null) { + FieldIdentifier fi = (FieldIdentifier) + ci.getIdentifier(ref.getName(), ref.getType()); + if (fi != null && !fi.isNotConstant()) { + Object result = fi.getConstant(); + if (result == null) + result = type.getDefaultValue(); + return result; + } + } + throw new InterpreterException("Field " + ref + " not constant"); + } + + public void putField(Reference ref, Object obj, Object value) + throws InterpreterException { + throw new InterpreterException("Modifiing Field " + ref + "."); + } + + public Object invokeConstructor(Reference ref, Object[] params) + throws InterpreterException, InvocationTargetException { + if (isWhite(ref)) + return super.invokeConstructor(ref, params); + throw new InterpreterException("Creating new Object " + ref + "."); + } + + public Object invokeMethod(Reference ref, boolean isVirtual, + Object cls, Object[] params) + throws InterpreterException, InvocationTargetException { + if (isWhite(ref)) + return super.invokeMethod(ref, isVirtual, cls, params); + Type type = Type.tType(ref.getType()); + ClassIdentifier ci = (ClassIdentifier) + m.clazz.bundle.getIdentifier(ref.getClazz()); + if (ci != null) { + MethodIdentifier mi = (MethodIdentifier) + ci.getIdentifier(ref.getName(), ref.getType()); + if (mi != null) { + BytecodeInfo code = mi.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); + } + } + } + throw new InterpreterException("Invoking library method " + ref + "."); + } + + public boolean instanceOf(Object obj, String className) + throws InterpreterException { + Class clazz; + try { + clazz = Class.forName(className); + } catch (ClassNotFoundException ex) { + throw new InterpreterException + ("Class "+ex.getMessage()+" not found"); + } + return obj != null && !clazz.isInstance(obj); + } + + public Object newArray(String type, int[] dimensions) + throws InterpreterException, NegativeArraySizeException { + if (type.length() == 1) { + Class clazz; + try { + clazz = Class.forName(type); + } catch (ClassNotFoundException ex) { + throw new InterpreterException + ("Class "+ex.getMessage()+" not found"); + } + return Array.newInstance(clazz, dimensions); + } + throw new InterpreterException("Creating object array."); + } + + public void enterMonitor(Object obj) + throws InterpreterException { + throw new InterpreterException("monitorenter not implemented"); + } + public void exitMonitor(Object obj) + throws InterpreterException { + throw new InterpreterException("monitorenter not implemented"); + } +}