git-svn-id: https://svn.code.sf.net/p/jode/code/trunk@543 379699f6-c40d-0410-875b-85095c16579estable
parent
c8b176e899
commit
544e5ff99e
@ -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<locals.length; i++) { |
||||||
|
result.append(comma).append(i).append(':'); |
||||||
|
if (locals[i] == Type.tError) |
||||||
|
result.append("-"); |
||||||
|
else |
||||||
|
result.append(locals[i]); |
||||||
|
comma = ","; |
||||||
|
} |
||||||
|
result.append("], stack:["); |
||||||
|
comma = ""; |
||||||
|
for (int i=0; i<stackHeight; i++) { |
||||||
|
result.append(comma).append(stack[i]); |
||||||
|
comma = ","; |
||||||
|
} |
||||||
|
if (jsrTargets != null) { |
||||||
|
result.append("], jsrs:["); |
||||||
|
comma = ""; |
||||||
|
for (int i=0; i<jsrTargets.length; i++) { |
||||||
|
result.append(comma).append(jsrTargets[i]) |
||||||
|
.append(jsrLocals[i]); |
||||||
|
comma = ","; |
||||||
|
} |
||||||
|
} |
||||||
|
return result.append("]").toString(); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
public CodeVerifier(ClassInfo ci, MethodInfo mi, BytecodeInfo bi) { |
||||||
|
this.ci = ci; |
||||||
|
this.mi = mi; |
||||||
|
this.bi = bi; |
||||||
|
} |
||||||
|
|
||||||
|
public VerifyInfo initInfo() { |
||||||
|
VerifyInfo info = new VerifyInfo(); |
||||||
|
Type[] paramTypes = mi.getType().getParameterTypes(); |
||||||
|
int slot = 0; |
||||||
|
if (!mi.isStatic()) { |
||||||
|
if (mi.getName().equals("<init>")) |
||||||
|
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("<init>")) { |
||||||
|
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<handlers.length; i++) { |
||||||
|
if (handlers[i].start.addr <= instr.addr |
||||||
|
&& handlers[i].end.addr >= 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; |
||||||
|
} |
||||||
|
} |
||||||
|
} |
@ -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; |
||||||
|
} |
@ -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"); |
||||||
|
} |
||||||
|
} |
@ -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(); |
||||||
|
} |
||||||
|
} |
||||||
|
|
@ -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", "<init>", |
||||||
|
"(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", "<init>", "()V")); |
||||||
|
addWhite(new Reference("java.lang.String", "<init>", "([C)V")); |
||||||
|
addWhite(new Reference("java.lang.String", "<init>", "([CII)V")); |
||||||
|
addWhite(new Reference("java.lang.String", "<init>", |
||||||
|
"(Ljava/lang/String;)V")); |
||||||
|
addWhite(new Reference("java.lang.String", "<init>", |
||||||
|
"(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"); |
||||||
|
} |
||||||
|
} |
Loading…
Reference in new issue