|
|
@ -48,201 +48,64 @@ public abstract class Opcodes implements jode.bytecode.Opcodes { |
|
|
|
}; |
|
|
|
}; |
|
|
|
|
|
|
|
|
|
|
|
private static StructuredBlock createNormal(CodeAnalyzer ca, |
|
|
|
private static StructuredBlock createNormal(CodeAnalyzer ca, |
|
|
|
int addr, int length, |
|
|
|
Instruction instr, |
|
|
|
Expression instr) |
|
|
|
Expression expr) |
|
|
|
{ |
|
|
|
{ |
|
|
|
return new InstructionBlock(instr, new Jump(addr+length)); |
|
|
|
return new InstructionBlock(expr, new Jump(FlowBlock.NEXT_BY_ADDR)); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
private static StructuredBlock createSpecial(CodeAnalyzer ca, |
|
|
|
private static StructuredBlock createSpecial(CodeAnalyzer ca, |
|
|
|
int addr, int length, |
|
|
|
Instruction instr, |
|
|
|
int type, int stackcount, int param) |
|
|
|
int type, |
|
|
|
|
|
|
|
int stackcount, int param) |
|
|
|
{ |
|
|
|
{ |
|
|
|
return new SpecialBlock(type, stackcount, param, |
|
|
|
return new SpecialBlock(type, stackcount, param, |
|
|
|
new Jump(addr+length)); |
|
|
|
new Jump(FlowBlock.NEXT_BY_ADDR)); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
private static StructuredBlock createGoto(CodeAnalyzer ca, |
|
|
|
private static StructuredBlock createGoto(CodeAnalyzer ca, |
|
|
|
int addr, int length, int destAddr) |
|
|
|
Instruction instr) |
|
|
|
{ |
|
|
|
{ |
|
|
|
return new EmptyBlock(new Jump(destAddr)); |
|
|
|
return new EmptyBlock(new Jump((FlowBlock)instr.succs[0].tmpInfo)); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
private static StructuredBlock createJsr(CodeAnalyzer ca, |
|
|
|
private static StructuredBlock createJsr(CodeAnalyzer ca, |
|
|
|
int addr, int length, |
|
|
|
Instruction instr) |
|
|
|
int destAddr) |
|
|
|
|
|
|
|
{ |
|
|
|
{ |
|
|
|
return new JsrBlock(new Jump(addr+length), |
|
|
|
return new JsrBlock(new Jump((FlowBlock)instr.succs[0].tmpInfo), |
|
|
|
new Jump(destAddr)); |
|
|
|
new Jump(FlowBlock.NEXT_BY_ADDR)); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
private static StructuredBlock createIfGoto(CodeAnalyzer ca, |
|
|
|
private static StructuredBlock createIfGoto(CodeAnalyzer ca, |
|
|
|
int addr, int length, |
|
|
|
Instruction instr, |
|
|
|
int destAddr, Expression instr) |
|
|
|
Expression expr) |
|
|
|
{ |
|
|
|
{ |
|
|
|
return new ConditionalBlock(instr, |
|
|
|
return new ConditionalBlock |
|
|
|
new Jump(destAddr), |
|
|
|
(expr, new Jump((FlowBlock)instr.succs[0].tmpInfo), |
|
|
|
new Jump(addr+length)); |
|
|
|
new Jump(FlowBlock.NEXT_BY_ADDR)); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
private static StructuredBlock createSwitch(CodeAnalyzer ca, |
|
|
|
private static StructuredBlock createSwitch(CodeAnalyzer ca, |
|
|
|
int addr, int length, |
|
|
|
Instruction instr, |
|
|
|
int[] cases, int[] dests) |
|
|
|
int[] cases, FlowBlock[] dests) |
|
|
|
{ |
|
|
|
{ |
|
|
|
return new SwitchBlock(new NopOperator(Type.tUInt), cases, dests); |
|
|
|
return new SwitchBlock(new NopOperator(Type.tUInt), cases, dests); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
private static StructuredBlock createBlock(CodeAnalyzer ca, |
|
|
|
private static StructuredBlock createBlock(CodeAnalyzer ca, |
|
|
|
int addr, int length, |
|
|
|
Instruction instr, |
|
|
|
StructuredBlock block) |
|
|
|
StructuredBlock block) |
|
|
|
{ |
|
|
|
{ |
|
|
|
return block; |
|
|
|
return block; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
private static StructuredBlock createRet(CodeAnalyzer ca, |
|
|
|
private static StructuredBlock createRet(CodeAnalyzer ca, |
|
|
|
int addr, int length, |
|
|
|
Instruction instr, |
|
|
|
LocalInfo local) |
|
|
|
LocalInfo local) |
|
|
|
{ |
|
|
|
{ |
|
|
|
return new RetBlock(local); |
|
|
|
return new RetBlock(local); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
|
|
|
* Skips the specified number of bytes in the input stream. This calls |
|
|
|
|
|
|
|
* skip as long until the bytes are all skipped. |
|
|
|
|
|
|
|
* @param is the inputstream to skip. |
|
|
|
|
|
|
|
* @param count the number of bytes to skip. |
|
|
|
|
|
|
|
*/ |
|
|
|
|
|
|
|
private final static void skip(InputStream is, long count) |
|
|
|
|
|
|
|
throws IOException { |
|
|
|
|
|
|
|
while (count > 0) { |
|
|
|
|
|
|
|
long skipped = is.skip(count); |
|
|
|
|
|
|
|
if (skipped == 0) |
|
|
|
|
|
|
|
throw new EOFException("Can't skip"); |
|
|
|
|
|
|
|
count -= skipped; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
|
|
|
* Read an opcode out of a data input stream and determine its size |
|
|
|
|
|
|
|
* and its successors. |
|
|
|
|
|
|
|
* @param addr The current address. |
|
|
|
|
|
|
|
* @param stream The stream containing the java byte code. |
|
|
|
|
|
|
|
* @return An array of ints; the first entry is the size of the |
|
|
|
|
|
|
|
* instruction, the remaining are the successors. |
|
|
|
|
|
|
|
*/ |
|
|
|
|
|
|
|
public static int[] getSizeAndSuccs(int addr, DataInputStream stream) |
|
|
|
|
|
|
|
throws IOException |
|
|
|
|
|
|
|
{ |
|
|
|
|
|
|
|
int opcode = stream.readUnsignedByte(); |
|
|
|
|
|
|
|
switch (opcode) { |
|
|
|
|
|
|
|
case opc_multianewarray: |
|
|
|
|
|
|
|
skip(stream, 3); |
|
|
|
|
|
|
|
return new int[] { 4, addr+4 }; |
|
|
|
|
|
|
|
case opc_invokeinterface: |
|
|
|
|
|
|
|
skip(stream, 4); |
|
|
|
|
|
|
|
return new int[] { 5, addr+5 }; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
case opc_wide: { |
|
|
|
|
|
|
|
switch (opcode = stream.readUnsignedByte()) { |
|
|
|
|
|
|
|
case opc_iload: case opc_lload: |
|
|
|
|
|
|
|
case opc_fload: case opc_dload: case opc_aload: |
|
|
|
|
|
|
|
case opc_istore: case opc_lstore: |
|
|
|
|
|
|
|
case opc_fstore: case opc_dstore: case opc_astore: |
|
|
|
|
|
|
|
skip(stream, 2); |
|
|
|
|
|
|
|
return new int[] { 4, addr+4 }; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
case opc_iinc: |
|
|
|
|
|
|
|
skip(stream, 4); |
|
|
|
|
|
|
|
return new int[] { 6, addr+6 }; |
|
|
|
|
|
|
|
case opc_ret: |
|
|
|
|
|
|
|
skip(stream, 2); |
|
|
|
|
|
|
|
return new int[] { 4 }; |
|
|
|
|
|
|
|
default: |
|
|
|
|
|
|
|
throw new ClassFormatError("Invalid wide opcode "+opcode); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
case opc_ret: |
|
|
|
|
|
|
|
skip(stream, 1); |
|
|
|
|
|
|
|
return new int[] { 2 }; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
case opc_jsr_w: |
|
|
|
|
|
|
|
return new int[] { 5, addr + 5, addr + stream.readInt() }; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
case opc_goto: |
|
|
|
|
|
|
|
return new int[] { 3, addr + stream.readShort() }; |
|
|
|
|
|
|
|
case opc_goto_w: |
|
|
|
|
|
|
|
return new int[] { 5, addr + stream.readInt() }; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
case opc_tableswitch: { |
|
|
|
|
|
|
|
int length = 3-(addr % 4); |
|
|
|
|
|
|
|
skip(stream, length); |
|
|
|
|
|
|
|
int def = addr + stream.readInt(); |
|
|
|
|
|
|
|
int low = stream.readInt(); |
|
|
|
|
|
|
|
int high = stream.readInt(); |
|
|
|
|
|
|
|
int[] dests = new int[high-low+3]; |
|
|
|
|
|
|
|
for (int i=0; i+low <= high; i++) { |
|
|
|
|
|
|
|
dests[i+1] = addr + stream.readInt(); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
dests[dests.length-1] = def; |
|
|
|
|
|
|
|
dests[0] = length + 13 + 4 * (high-low+1); |
|
|
|
|
|
|
|
return dests; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
case opc_lookupswitch: { |
|
|
|
|
|
|
|
int length = 3-(addr % 4); |
|
|
|
|
|
|
|
skip(stream, length); |
|
|
|
|
|
|
|
int def = addr + stream.readInt(); |
|
|
|
|
|
|
|
int npairs = stream.readInt(); |
|
|
|
|
|
|
|
int[] dests = new int[npairs+2]; |
|
|
|
|
|
|
|
for (int i=0; i < npairs; i++) { |
|
|
|
|
|
|
|
int value = stream.readInt(); |
|
|
|
|
|
|
|
dests[i+1] = addr + stream.readInt(); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
dests[npairs+1] = def; |
|
|
|
|
|
|
|
dests[0] = length + 9 + 8 * npairs; |
|
|
|
|
|
|
|
return dests; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
case opc_ifnull: case opc_ifnonnull: |
|
|
|
|
|
|
|
case opc_jsr: |
|
|
|
|
|
|
|
return new int[] { 3, addr + 3, addr + stream.readShort() }; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
case opc_sipush: |
|
|
|
|
|
|
|
case opc_ldc_w: |
|
|
|
|
|
|
|
case opc_ldc2_w: |
|
|
|
|
|
|
|
case opc_iinc: |
|
|
|
|
|
|
|
case opc_getstatic: |
|
|
|
|
|
|
|
case opc_getfield: |
|
|
|
|
|
|
|
case opc_putstatic: |
|
|
|
|
|
|
|
case opc_putfield: |
|
|
|
|
|
|
|
case opc_invokevirtual: |
|
|
|
|
|
|
|
case opc_invokespecial: |
|
|
|
|
|
|
|
case opc_invokestatic: |
|
|
|
|
|
|
|
case opc_new: |
|
|
|
|
|
|
|
case opc_anewarray: |
|
|
|
|
|
|
|
case opc_checkcast: |
|
|
|
|
|
|
|
case opc_instanceof: |
|
|
|
|
|
|
|
skip(stream, 2); |
|
|
|
|
|
|
|
return new int[] { 3, addr+3 }; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (opcode == opc_newarray |
|
|
|
|
|
|
|
|| (opcode >= opc_bipush && opcode <= opc_aload) |
|
|
|
|
|
|
|
|| (opcode >= opc_istore && opcode <= opc_astore)) { |
|
|
|
|
|
|
|
skip(stream, 1); |
|
|
|
|
|
|
|
return new int[] { 2, addr+2 }; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (opcode == opc_athrow |
|
|
|
|
|
|
|
|| opcode >= opc_ireturn && opcode <= opc_return) |
|
|
|
|
|
|
|
return new int[] { 1 }; |
|
|
|
|
|
|
|
if (opcode >= opc_ifeq && opcode <= opc_if_acmpne) |
|
|
|
|
|
|
|
return new int[] { 3, addr + 3, addr + stream.readShort() }; |
|
|
|
|
|
|
|
if (opcode == opc_xxxunusedxxx || opcode > opc_breakpoint) |
|
|
|
|
|
|
|
throw new ClassFormatError("Invalid opcode "+opcode); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
return new int[] { 1, addr+1 }; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/** |
|
|
|
/** |
|
|
|
* Read an opcode out of a data input stream containing the bytecode. |
|
|
|
* Read an opcode out of a data input stream containing the bytecode. |
|
|
|
* @param addr The current address. |
|
|
|
* @param addr The current address. |
|
|
@ -254,163 +117,104 @@ public abstract class Opcodes implements jode.bytecode.Opcodes { |
|
|
|
* @exception IOException if an read error occured. |
|
|
|
* @exception IOException if an read error occured. |
|
|
|
* @exception ClassFormatError if an invalid opcode is detected. |
|
|
|
* @exception ClassFormatError if an invalid opcode is detected. |
|
|
|
*/ |
|
|
|
*/ |
|
|
|
public static StructuredBlock readOpcode(ConstantPool cpool, |
|
|
|
public static StructuredBlock readOpcode(Instruction instr, |
|
|
|
int addr, DataInputStream stream, |
|
|
|
CodeAnalyzer ca) |
|
|
|
CodeAnalyzer ca) |
|
|
|
throws ClassFormatError |
|
|
|
throws IOException, ClassFormatError |
|
|
|
|
|
|
|
{ |
|
|
|
{ |
|
|
|
int opcode = stream.readUnsignedByte(); |
|
|
|
int opcode = instr.opcode; |
|
|
|
switch (opcode) { |
|
|
|
switch (opcode) { |
|
|
|
case opc_nop: |
|
|
|
case opc_nop: |
|
|
|
return createBlock |
|
|
|
return createBlock(ca, instr, new EmptyBlock |
|
|
|
(ca, addr, 1, new EmptyBlock(new Jump(addr+1))); |
|
|
|
(new Jump(FlowBlock.NEXT_BY_ADDR))); |
|
|
|
case opc_aconst_null: |
|
|
|
case opc_aconst_null: |
|
|
|
return createNormal |
|
|
|
|
|
|
|
(ca, addr, 1, new ConstOperator(Type.tUObject, "null")); |
|
|
|
|
|
|
|
case opc_iconst_m1: |
|
|
|
case opc_iconst_m1: |
|
|
|
case opc_iconst_0: case opc_iconst_1: case opc_iconst_2: |
|
|
|
case opc_iconst_0: case opc_iconst_1: case opc_iconst_2: |
|
|
|
case opc_iconst_3: case opc_iconst_4: case opc_iconst_5: |
|
|
|
case opc_iconst_3: case opc_iconst_4: case opc_iconst_5: |
|
|
|
return createNormal |
|
|
|
|
|
|
|
(ca, addr, 1, new ConstOperator(opcode - opc_iconst_0)); |
|
|
|
|
|
|
|
case opc_lconst_0: case opc_lconst_1: |
|
|
|
case opc_lconst_0: case opc_lconst_1: |
|
|
|
return createNormal |
|
|
|
|
|
|
|
(ca, addr, 1, new ConstOperator |
|
|
|
|
|
|
|
(Type.tLong, (char) (opcode + ('0'-opc_lconst_0)) + "")); |
|
|
|
|
|
|
|
case opc_fconst_0: case opc_fconst_1: case opc_fconst_2: |
|
|
|
case opc_fconst_0: case opc_fconst_1: case opc_fconst_2: |
|
|
|
return createNormal |
|
|
|
|
|
|
|
(ca, addr, 1, new ConstOperator |
|
|
|
|
|
|
|
(Type.tFloat, (char) (opcode + ('0'-opc_fconst_0)) + ".0")); |
|
|
|
|
|
|
|
case opc_dconst_0: case opc_dconst_1: |
|
|
|
case opc_dconst_0: case opc_dconst_1: |
|
|
|
return createNormal |
|
|
|
|
|
|
|
(ca, addr, 1, new ConstOperator |
|
|
|
|
|
|
|
(Type.tDouble, (char) (opcode + ('0'-opc_dconst_0)) + ".0")); |
|
|
|
|
|
|
|
case opc_bipush: |
|
|
|
case opc_bipush: |
|
|
|
return createNormal |
|
|
|
|
|
|
|
(ca, addr, 2, new ConstOperator(stream.readByte())); |
|
|
|
|
|
|
|
case opc_sipush: |
|
|
|
case opc_sipush: |
|
|
|
return createNormal |
|
|
|
case opc_ldc: |
|
|
|
(ca, addr, 3, new ConstOperator(stream.readShort())); |
|
|
|
|
|
|
|
case opc_ldc: { |
|
|
|
|
|
|
|
int index = stream.readUnsignedByte(); |
|
|
|
|
|
|
|
ConstOperator op; |
|
|
|
|
|
|
|
if (cpool.getConstantType(index) == Type.tInt) |
|
|
|
|
|
|
|
op = new ConstOperator(cpool.getConstantInt(index)); |
|
|
|
|
|
|
|
else |
|
|
|
|
|
|
|
op = new ConstOperator(cpool.getConstantType(index), |
|
|
|
|
|
|
|
cpool.getConstantString(index)); |
|
|
|
|
|
|
|
return createNormal (ca, addr, 2, op); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
case opc_ldc_w: |
|
|
|
case opc_ldc_w: |
|
|
|
case opc_ldc2_w: { |
|
|
|
case opc_ldc2_w: |
|
|
|
int index = stream.readUnsignedShort(); |
|
|
|
return createNormal (ca, instr, new ConstOperator(instr.objData)); |
|
|
|
ConstOperator op; |
|
|
|
|
|
|
|
if (cpool.getConstantType(index) == Type.tInt) |
|
|
|
|
|
|
|
op = new ConstOperator(cpool.getConstantInt(index)); |
|
|
|
|
|
|
|
else |
|
|
|
|
|
|
|
op = new ConstOperator(cpool.getConstantType(index), |
|
|
|
|
|
|
|
cpool.getConstantString(index)); |
|
|
|
|
|
|
|
return createNormal(ca, addr, 3, op); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
case opc_iload: case opc_lload: |
|
|
|
case opc_iload: case opc_lload: |
|
|
|
case opc_fload: case opc_dload: case opc_aload: |
|
|
|
case opc_fload: case opc_dload: case opc_aload: |
|
|
|
return createNormal |
|
|
|
return createNormal |
|
|
|
(ca, addr, 2, new LocalLoadOperator |
|
|
|
(ca, instr, new LocalLoadOperator |
|
|
|
(types[0][opcode-opc_iload], |
|
|
|
(types[0][opcode-opc_iload], |
|
|
|
ca.getLocalInfo(addr, stream.readUnsignedByte()))); |
|
|
|
ca.getLocalInfo(instr.addr, instr.localSlot))); |
|
|
|
case opc_iload_0: case opc_iload_1: case opc_iload_2: case opc_iload_3: |
|
|
|
|
|
|
|
case opc_lload_0: case opc_lload_1: case opc_lload_2: case opc_lload_3: |
|
|
|
|
|
|
|
case opc_fload_0: case opc_fload_1: case opc_fload_2: case opc_fload_3: |
|
|
|
|
|
|
|
case opc_dload_0: case opc_dload_1: case opc_dload_2: case opc_dload_3: |
|
|
|
|
|
|
|
case opc_aload_0: case opc_aload_1: case opc_aload_2: case opc_aload_3: |
|
|
|
|
|
|
|
return createNormal |
|
|
|
|
|
|
|
(ca, addr, 1, new LocalLoadOperator |
|
|
|
|
|
|
|
(types[0][(opcode-opc_iload_0)/4], |
|
|
|
|
|
|
|
ca.getLocalInfo(addr, (opcode-opc_iload_0) & 3))); |
|
|
|
|
|
|
|
case opc_iaload: case opc_laload: |
|
|
|
case opc_iaload: case opc_laload: |
|
|
|
case opc_faload: case opc_daload: case opc_aaload: |
|
|
|
case opc_faload: case opc_daload: case opc_aaload: |
|
|
|
case opc_baload: case opc_caload: case opc_saload: |
|
|
|
case opc_baload: case opc_caload: case opc_saload: |
|
|
|
return createNormal |
|
|
|
return createNormal |
|
|
|
(ca, addr, 1, new ArrayLoadOperator |
|
|
|
(ca, instr, new ArrayLoadOperator |
|
|
|
(types[1][opcode - opc_iaload])); |
|
|
|
(types[1][opcode - opc_iaload])); |
|
|
|
case opc_istore: case opc_lstore: |
|
|
|
case opc_istore: case opc_lstore: |
|
|
|
case opc_fstore: case opc_dstore: case opc_astore: |
|
|
|
case opc_fstore: case opc_dstore: case opc_astore: |
|
|
|
return createNormal |
|
|
|
return createNormal |
|
|
|
(ca, addr, 2, new LocalStoreOperator |
|
|
|
(ca, instr, new LocalStoreOperator |
|
|
|
(types[0][opcode-opc_istore], |
|
|
|
(types[0][opcode-opc_istore], |
|
|
|
ca.getLocalInfo(addr+2, stream.readUnsignedByte()), |
|
|
|
ca.getLocalInfo(instr.addr+2, instr.localSlot), |
|
|
|
Operator.ASSIGN_OP)); |
|
|
|
|
|
|
|
case opc_istore_0: case opc_istore_1: |
|
|
|
|
|
|
|
case opc_istore_2: case opc_istore_3: |
|
|
|
|
|
|
|
case opc_lstore_0: case opc_lstore_1: |
|
|
|
|
|
|
|
case opc_lstore_2: case opc_lstore_3: |
|
|
|
|
|
|
|
case opc_fstore_0: case opc_fstore_1: |
|
|
|
|
|
|
|
case opc_fstore_2: case opc_fstore_3: |
|
|
|
|
|
|
|
case opc_dstore_0: case opc_dstore_1: |
|
|
|
|
|
|
|
case opc_dstore_2: case opc_dstore_3: |
|
|
|
|
|
|
|
case opc_astore_0: case opc_astore_1: |
|
|
|
|
|
|
|
case opc_astore_2: case opc_astore_3: |
|
|
|
|
|
|
|
return createNormal |
|
|
|
|
|
|
|
(ca, addr, 1, new LocalStoreOperator |
|
|
|
|
|
|
|
(types[0][(opcode-opc_istore_0)/4], |
|
|
|
|
|
|
|
ca.getLocalInfo(addr+1, (opcode-opc_istore_0) & 3), |
|
|
|
|
|
|
|
Operator.ASSIGN_OP)); |
|
|
|
Operator.ASSIGN_OP)); |
|
|
|
case opc_iastore: case opc_lastore: |
|
|
|
case opc_iastore: case opc_lastore: |
|
|
|
case opc_fastore: case opc_dastore: case opc_aastore: |
|
|
|
case opc_fastore: case opc_dastore: case opc_aastore: |
|
|
|
case opc_bastore: case opc_castore: case opc_sastore: |
|
|
|
case opc_bastore: case opc_castore: case opc_sastore: |
|
|
|
return createNormal |
|
|
|
return createNormal |
|
|
|
(ca, addr, 1, new ArrayStoreOperator |
|
|
|
(ca, instr, new ArrayStoreOperator |
|
|
|
(types[1][opcode - opc_iastore])); |
|
|
|
(types[1][opcode - opc_iastore])); |
|
|
|
case opc_pop: case opc_pop2: |
|
|
|
case opc_pop: case opc_pop2: |
|
|
|
return createSpecial |
|
|
|
return createSpecial |
|
|
|
(ca, addr, 1, SpecialBlock.POP, opcode - opc_pop + 1, 0); |
|
|
|
(ca, instr, SpecialBlock.POP, opcode - opc_pop + 1, 0); |
|
|
|
case opc_dup: case opc_dup_x1: case opc_dup_x2: |
|
|
|
case opc_dup: case opc_dup_x1: case opc_dup_x2: |
|
|
|
case opc_dup2: case opc_dup2_x1: case opc_dup2_x2: |
|
|
|
case opc_dup2: case opc_dup2_x1: case opc_dup2_x2: |
|
|
|
return createSpecial |
|
|
|
return createSpecial |
|
|
|
(ca, addr, 1, SpecialBlock.DUP, |
|
|
|
(ca, instr, SpecialBlock.DUP, |
|
|
|
(opcode - opc_dup)/3+1, (opcode - opc_dup)%3); |
|
|
|
(opcode - opc_dup)/3+1, (opcode - opc_dup)%3); |
|
|
|
case opc_swap: |
|
|
|
case opc_swap: |
|
|
|
return createSpecial(ca, addr, 1, SpecialBlock.SWAP, 1, 0); |
|
|
|
return createSpecial(ca, instr, SpecialBlock.SWAP, 1, 0); |
|
|
|
case opc_iadd: case opc_ladd: case opc_fadd: case opc_dadd: |
|
|
|
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_isub: case opc_lsub: case opc_fsub: case opc_dsub: |
|
|
|
case opc_imul: case opc_lmul: case opc_fmul: case opc_dmul: |
|
|
|
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_idiv: case opc_ldiv: case opc_fdiv: case opc_ddiv: |
|
|
|
case opc_irem: case opc_lrem: case opc_frem: case opc_drem: |
|
|
|
case opc_irem: case opc_lrem: case opc_frem: case opc_drem: |
|
|
|
return createNormal |
|
|
|
return createNormal |
|
|
|
(ca, addr, 1, new BinaryOperator |
|
|
|
(ca, instr, new BinaryOperator |
|
|
|
(types[3][(opcode - opc_iadd)%4], |
|
|
|
(types[3][(opcode - opc_iadd)%4], |
|
|
|
(opcode - opc_iadd)/4+Operator.ADD_OP)); |
|
|
|
(opcode - opc_iadd)/4+Operator.ADD_OP)); |
|
|
|
case opc_ineg: case opc_lneg: case opc_fneg: case opc_dneg: |
|
|
|
case opc_ineg: case opc_lneg: case opc_fneg: case opc_dneg: |
|
|
|
return createNormal |
|
|
|
return createNormal |
|
|
|
(ca, addr, 1, new UnaryOperator |
|
|
|
(ca, instr, new UnaryOperator |
|
|
|
(types[3][opcode - opc_ineg], Operator.NEG_OP)); |
|
|
|
(types[3][opcode - opc_ineg], Operator.NEG_OP)); |
|
|
|
case opc_ishl: case opc_lshl: |
|
|
|
case opc_ishl: case opc_lshl: |
|
|
|
case opc_ishr: case opc_lshr: |
|
|
|
case opc_ishr: case opc_lshr: |
|
|
|
case opc_iushr: case opc_lushr: |
|
|
|
case opc_iushr: case opc_lushr: |
|
|
|
return createNormal |
|
|
|
return createNormal |
|
|
|
(ca, addr, 1, new ShiftOperator |
|
|
|
(ca, instr, new ShiftOperator |
|
|
|
(types[3][(opcode - opc_ishl)%2], |
|
|
|
(types[3][(opcode - opc_ishl)%2], |
|
|
|
(opcode - opc_ishl)/2 + Operator.SHIFT_OP)); |
|
|
|
(opcode - opc_ishl)/2 + Operator.SHIFT_OP)); |
|
|
|
case opc_iand: case opc_land: |
|
|
|
case opc_iand: case opc_land: |
|
|
|
case opc_ior : case opc_lor : |
|
|
|
case opc_ior : case opc_lor : |
|
|
|
case opc_ixor: case opc_lxor: |
|
|
|
case opc_ixor: case opc_lxor: |
|
|
|
return createNormal |
|
|
|
return createNormal |
|
|
|
(ca, addr, 1, new BinaryOperator |
|
|
|
(ca, instr, new BinaryOperator |
|
|
|
(types[4][(opcode - opc_iand)%2], |
|
|
|
(types[4][(opcode - opc_iand)%2], |
|
|
|
(opcode - opc_iand)/2 + Operator.AND_OP)); |
|
|
|
(opcode - opc_iand)/2 + Operator.AND_OP)); |
|
|
|
case opc_iinc: { |
|
|
|
case opc_iinc: { |
|
|
|
int local = stream.readUnsignedByte(); |
|
|
|
int value = instr.intData; |
|
|
|
int value = stream.readByte(); |
|
|
|
|
|
|
|
int operation = Operator.ADD_OP; |
|
|
|
int operation = Operator.ADD_OP; |
|
|
|
if (value < 0) { |
|
|
|
if (value < 0) { |
|
|
|
value = -value; |
|
|
|
value = -value; |
|
|
|
operation = Operator.NEG_OP; |
|
|
|
operation = Operator.NEG_OP; |
|
|
|
} |
|
|
|
} |
|
|
|
LocalInfo li = ca.getLocalInfo(addr, local); |
|
|
|
LocalInfo li = ca.getLocalInfo(instr.addr, instr.localSlot); |
|
|
|
li.setType(Type.tUInt); |
|
|
|
li.setType(Type.tUInt); |
|
|
|
return createNormal |
|
|
|
return createNormal |
|
|
|
(ca, addr, 3, new IIncOperator |
|
|
|
(ca, instr, new IIncOperator |
|
|
|
(li, Integer.toString(value), |
|
|
|
(li, Integer.toString(value), |
|
|
|
operation + Operator.OPASSIGN_OP)); |
|
|
|
operation + Operator.OPASSIGN_OP)); |
|
|
|
} |
|
|
|
} |
|
|
|
case opc_i2l: case opc_i2f: case opc_i2d: |
|
|
|
case opc_i2l: case opc_i2f: case opc_i2d: |
|
|
|
case opc_l2i: case opc_l2f: case opc_l2d: |
|
|
|
case opc_l2i: case opc_l2f: case opc_l2d: |
|
|
@ -421,115 +225,97 @@ public abstract class Opcodes implements jode.bytecode.Opcodes { |
|
|
|
if (to >= from) |
|
|
|
if (to >= from) |
|
|
|
to++; |
|
|
|
to++; |
|
|
|
return createNormal |
|
|
|
return createNormal |
|
|
|
(ca, addr, 1, new ConvertOperator(types[3][from], |
|
|
|
(ca, instr, new ConvertOperator(types[3][from], |
|
|
|
types[3][to])); |
|
|
|
types[3][to])); |
|
|
|
} |
|
|
|
} |
|
|
|
case opc_i2b: case opc_i2c: case opc_i2s: |
|
|
|
case opc_i2b: case opc_i2c: case opc_i2s: |
|
|
|
return createNormal |
|
|
|
return createNormal |
|
|
|
(ca, addr, 1, new ConvertOperator |
|
|
|
(ca, instr, new ConvertOperator |
|
|
|
(types[3][0], types[2][opcode-opc_i2b])); |
|
|
|
(types[3][0], types[2][opcode-opc_i2b])); |
|
|
|
case opc_lcmp: |
|
|
|
case opc_lcmp: |
|
|
|
case opc_fcmpl: case opc_fcmpg: |
|
|
|
case opc_fcmpl: case opc_fcmpg: |
|
|
|
case opc_dcmpl: case opc_dcmpg: |
|
|
|
case opc_dcmpl: case opc_dcmpg: |
|
|
|
return createNormal |
|
|
|
return createNormal |
|
|
|
(ca, addr, 1, new CompareToIntOperator |
|
|
|
(ca, instr, new CompareToIntOperator |
|
|
|
(types[3][(opcode-(opc_lcmp-3))/2], |
|
|
|
(types[3][(opcode-(opc_lcmp-3))/2], |
|
|
|
(opcode-(opc_lcmp-3))%2)); |
|
|
|
(opcode-(opc_lcmp-3))%2)); |
|
|
|
case opc_ifeq: case opc_ifne: |
|
|
|
case opc_ifeq: case opc_ifne: |
|
|
|
return createIfGoto |
|
|
|
return createIfGoto |
|
|
|
(ca, addr, 3, addr+stream.readShort(), |
|
|
|
(ca, instr, |
|
|
|
new CompareUnaryOperator |
|
|
|
new CompareUnaryOperator |
|
|
|
(Type.tBoolUInt, opcode - (opc_ifeq-Operator.COMPARE_OP))); |
|
|
|
(Type.tBoolUInt, opcode - (opc_ifeq-Operator.COMPARE_OP))); |
|
|
|
case opc_iflt: case opc_ifge: case opc_ifgt: case opc_ifle: |
|
|
|
case opc_iflt: case opc_ifge: case opc_ifgt: case opc_ifle: |
|
|
|
return createIfGoto |
|
|
|
return createIfGoto |
|
|
|
(ca, addr, 3, addr+stream.readShort(), |
|
|
|
(ca, instr, |
|
|
|
new CompareUnaryOperator |
|
|
|
new CompareUnaryOperator |
|
|
|
(Type.tUInt, opcode - (opc_ifeq-Operator.COMPARE_OP))); |
|
|
|
(Type.tUInt, opcode - (opc_ifeq-Operator.COMPARE_OP))); |
|
|
|
case opc_if_icmpeq: case opc_if_icmpne: |
|
|
|
case opc_if_icmpeq: case opc_if_icmpne: |
|
|
|
return createIfGoto |
|
|
|
return createIfGoto |
|
|
|
(ca, addr, 3, addr+stream.readShort(), |
|
|
|
(ca, instr, |
|
|
|
new CompareBinaryOperator |
|
|
|
new CompareBinaryOperator |
|
|
|
(Type.tBoolInt, |
|
|
|
(Type.tBoolInt, |
|
|
|
opcode - (opc_if_icmpeq-Operator.COMPARE_OP))); |
|
|
|
opcode - (opc_if_icmpeq-Operator.COMPARE_OP))); |
|
|
|
case opc_if_icmplt: case opc_if_icmpge: |
|
|
|
case opc_if_icmplt: case opc_if_icmpge: |
|
|
|
case opc_if_icmpgt: case opc_if_icmple: |
|
|
|
case opc_if_icmpgt: case opc_if_icmple: |
|
|
|
return createIfGoto |
|
|
|
return createIfGoto |
|
|
|
(ca, addr, 3, addr+stream.readShort(), |
|
|
|
(ca, instr, |
|
|
|
new CompareBinaryOperator |
|
|
|
new CompareBinaryOperator |
|
|
|
(Type.tUInt, |
|
|
|
(Type.tUInt, |
|
|
|
opcode - (opc_if_icmpeq-Operator.COMPARE_OP))); |
|
|
|
opcode - (opc_if_icmpeq-Operator.COMPARE_OP))); |
|
|
|
case opc_if_acmpeq: case opc_if_acmpne: |
|
|
|
case opc_if_acmpeq: case opc_if_acmpne: |
|
|
|
return createIfGoto |
|
|
|
return createIfGoto |
|
|
|
(ca, addr, 3, addr+stream.readShort(), |
|
|
|
(ca, instr, |
|
|
|
new CompareBinaryOperator |
|
|
|
new CompareBinaryOperator |
|
|
|
(Type.tUObject, |
|
|
|
(Type.tUObject, |
|
|
|
opcode - (opc_if_acmpeq-Operator.COMPARE_OP))); |
|
|
|
opcode - (opc_if_acmpeq-Operator.COMPARE_OP))); |
|
|
|
case opc_goto: |
|
|
|
case opc_goto: |
|
|
|
return createGoto |
|
|
|
return createGoto(ca, instr); |
|
|
|
(ca, addr, 3, addr+stream.readShort()); |
|
|
|
|
|
|
|
case opc_jsr: |
|
|
|
case opc_jsr: |
|
|
|
return createJsr |
|
|
|
return createJsr(ca, instr); |
|
|
|
(ca, addr, 3, addr+stream.readShort()); |
|
|
|
|
|
|
|
case opc_ret: |
|
|
|
case opc_ret: |
|
|
|
return createRet |
|
|
|
return createRet |
|
|
|
(ca, addr, 2, |
|
|
|
(ca, instr, ca.getLocalInfo(instr.addr, instr.localSlot)); |
|
|
|
ca.getLocalInfo(addr, stream.readUnsignedByte())); |
|
|
|
|
|
|
|
case opc_tableswitch: { |
|
|
|
case opc_tableswitch: { |
|
|
|
int length = 3-(addr % 4); |
|
|
|
int low = instr.intData; |
|
|
|
skip(stream, length); |
|
|
|
int[] cases = new int[instr.succs.length-1]; |
|
|
|
int def = addr + stream.readInt(); |
|
|
|
FlowBlock[] dests = new FlowBlock[instr.succs.length]; |
|
|
|
int low = stream.readInt(); |
|
|
|
for (int i=0; i < cases.length; i++) { |
|
|
|
int high = stream.readInt(); |
|
|
|
|
|
|
|
int[] cases = new int[high-low+1]; |
|
|
|
|
|
|
|
int[] dests = new int[high-low+2]; |
|
|
|
|
|
|
|
for (int i=0; i+low <= high; i++) { |
|
|
|
|
|
|
|
cases[i] = i+low; |
|
|
|
cases[i] = i+low; |
|
|
|
dests[i] = addr + stream.readInt(); |
|
|
|
dests[i] = (FlowBlock) instr.succs[i+1].tmpInfo; |
|
|
|
} |
|
|
|
|
|
|
|
dests[cases.length] = def; |
|
|
|
|
|
|
|
length += 13 + 4 * cases.length; |
|
|
|
|
|
|
|
return createSwitch |
|
|
|
|
|
|
|
(ca, addr, length, cases, dests); |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
dests[cases.length] = (FlowBlock) instr.succs[0].tmpInfo; |
|
|
|
|
|
|
|
return createSwitch(ca, instr, cases, dests); |
|
|
|
|
|
|
|
} |
|
|
|
case opc_lookupswitch: { |
|
|
|
case opc_lookupswitch: { |
|
|
|
int length = 3-(addr % 4); |
|
|
|
int[] cases = (int[]) instr.objData; |
|
|
|
skip(stream, length); |
|
|
|
FlowBlock[] dests = new FlowBlock[instr.succs.length]; |
|
|
|
int def = addr + stream.readInt(); |
|
|
|
for (int i=0; i < dests.length; i++) |
|
|
|
int npairs = stream.readInt(); |
|
|
|
dests[i] = (FlowBlock) instr.succs[i].tmpInfo; |
|
|
|
int[] cases = new int[npairs]; |
|
|
|
dests[cases.length] = (FlowBlock) instr.succs[0].tmpInfo; |
|
|
|
int[] dests = new int[npairs+1]; |
|
|
|
return createSwitch(ca, instr, cases, dests); |
|
|
|
for (int i=0; i < npairs; i++) { |
|
|
|
|
|
|
|
cases[i] = stream.readInt(); |
|
|
|
|
|
|
|
dests[i] = addr + stream.readInt(); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
dests[npairs] = def; |
|
|
|
|
|
|
|
length += 9 + 8 * npairs; |
|
|
|
|
|
|
|
return createSwitch |
|
|
|
|
|
|
|
(ca, addr, length, cases, dests); |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
case opc_ireturn: case opc_lreturn: |
|
|
|
case opc_ireturn: case opc_lreturn: |
|
|
|
case opc_freturn: case opc_dreturn: case opc_areturn: { |
|
|
|
case opc_freturn: case opc_dreturn: case opc_areturn: { |
|
|
|
/* Address -1 is interpreted as end of method */ |
|
|
|
|
|
|
|
Type retType = Type.tSubType(ca.getMethod().getReturnType()); |
|
|
|
Type retType = Type.tSubType(ca.getMethod().getReturnType()); |
|
|
|
return createBlock |
|
|
|
return createBlock |
|
|
|
(ca, addr, 1, new ReturnBlock(new NopOperator(retType))); |
|
|
|
(ca, instr, new ReturnBlock(new NopOperator(retType))); |
|
|
|
} |
|
|
|
} |
|
|
|
case opc_return: |
|
|
|
case opc_return: |
|
|
|
return createBlock |
|
|
|
return createBlock |
|
|
|
(ca, addr, 1, new EmptyBlock(new Jump(-1))); |
|
|
|
(ca, instr, new EmptyBlock(new Jump(FlowBlock.END_OF_METHOD))); |
|
|
|
case opc_getstatic: |
|
|
|
case opc_getstatic: |
|
|
|
case opc_getfield: { |
|
|
|
case opc_getfield: { |
|
|
|
String[] ref = cpool.getRef(stream.readUnsignedShort()); |
|
|
|
String[] ref = (String[]) instr.objData; |
|
|
|
return createNormal |
|
|
|
return createNormal |
|
|
|
(ca, addr, 3, new GetFieldOperator |
|
|
|
(ca, instr, new GetFieldOperator |
|
|
|
(ca, opcode == opc_getstatic, |
|
|
|
(ca, opcode == opc_getstatic, |
|
|
|
Type.tClass(ref[0]), Type.tType(ref[2]), ref[1])); |
|
|
|
Type.tClass(ref[0]), Type.tType(ref[2]), ref[1])); |
|
|
|
} |
|
|
|
} |
|
|
|
case opc_putstatic: |
|
|
|
case opc_putstatic: |
|
|
|
case opc_putfield: { |
|
|
|
case opc_putfield: { |
|
|
|
String[] ref = cpool.getRef(stream.readUnsignedShort()); |
|
|
|
String[] ref = (String[]) instr.objData; |
|
|
|
return createNormal |
|
|
|
return createNormal |
|
|
|
(ca, addr, 3, new PutFieldOperator |
|
|
|
(ca, instr, new PutFieldOperator |
|
|
|
(ca, opcode == opc_putstatic, |
|
|
|
(ca, opcode == opc_putstatic, |
|
|
|
Type.tClass(ref[0]), Type.tType(ref[2]), ref[1])); |
|
|
|
Type.tClass(ref[0]), Type.tType(ref[2]), ref[1])); |
|
|
|
} |
|
|
|
} |
|
|
@ -537,27 +323,21 @@ public abstract class Opcodes implements jode.bytecode.Opcodes { |
|
|
|
case opc_invokespecial: |
|
|
|
case opc_invokespecial: |
|
|
|
case opc_invokestatic : |
|
|
|
case opc_invokestatic : |
|
|
|
case opc_invokeinterface: { |
|
|
|
case opc_invokeinterface: { |
|
|
|
String[] ref = cpool.getRef(stream.readUnsignedShort()); |
|
|
|
String[] ref = (String[]) instr.objData; |
|
|
|
StructuredBlock block = createNormal |
|
|
|
StructuredBlock block = createNormal |
|
|
|
(ca, addr, opcode == opc_invokeinterface ? 5 : 3, |
|
|
|
(ca, instr, new InvokeOperator |
|
|
|
new InvokeOperator |
|
|
|
(ca, opcode == opc_invokespecial, Type.tClass(ref[0]), |
|
|
|
(ca, opcode == opc_invokespecial, |
|
|
|
new MethodType(opcode == opc_invokestatic, ref[2]), ref[1])); |
|
|
|
Type.tClass(ref[0]), |
|
|
|
|
|
|
|
new MethodType(opcode == opc_invokestatic, ref[2]), |
|
|
|
|
|
|
|
ref[1])); |
|
|
|
|
|
|
|
if (opcode == opc_invokeinterface) |
|
|
|
|
|
|
|
stream.readUnsignedShort(); |
|
|
|
|
|
|
|
return block; |
|
|
|
return block; |
|
|
|
} |
|
|
|
} |
|
|
|
case opc_new: { |
|
|
|
case opc_new: { |
|
|
|
Type type = Type.tClassOrArray |
|
|
|
Type type = Type.tClassOrArray((String) instr.objData); |
|
|
|
(cpool.getClassName(stream.readUnsignedShort())); |
|
|
|
|
|
|
|
type.useType(); |
|
|
|
type.useType(); |
|
|
|
return createNormal(ca, addr, 3, new NewOperator(type)); |
|
|
|
return createNormal(ca, instr, new NewOperator(type)); |
|
|
|
} |
|
|
|
} |
|
|
|
case opc_newarray: { |
|
|
|
case opc_newarray: { |
|
|
|
Type type; |
|
|
|
Type type; |
|
|
|
switch (stream.readUnsignedByte()) { |
|
|
|
switch (instr.intData) { |
|
|
|
case 4: type = Type.tBoolean; break; |
|
|
|
case 4: type = Type.tBoolean; break; |
|
|
|
case 5: type = Type.tChar ; break; |
|
|
|
case 5: type = Type.tChar ; break; |
|
|
|
case 6: type = Type.tFloat ; break; |
|
|
|
case 6: type = Type.tFloat ; break; |
|
|
@ -571,103 +351,52 @@ public abstract class Opcodes implements jode.bytecode.Opcodes { |
|
|
|
} |
|
|
|
} |
|
|
|
type.useType(); |
|
|
|
type.useType(); |
|
|
|
return createNormal |
|
|
|
return createNormal |
|
|
|
(ca, addr, 2, new NewArrayOperator(Type.tArray(type), 1)); |
|
|
|
(ca, instr, new NewArrayOperator(Type.tArray(type), 1)); |
|
|
|
} |
|
|
|
} |
|
|
|
case opc_anewarray: { |
|
|
|
case opc_anewarray: { |
|
|
|
Type type = Type.tClassOrArray |
|
|
|
Type type = Type.tClassOrArray((String) instr.objData); |
|
|
|
(cpool.getClassName(stream.readUnsignedShort())); |
|
|
|
|
|
|
|
type.useType(); |
|
|
|
type.useType(); |
|
|
|
return createNormal |
|
|
|
return createNormal |
|
|
|
(ca, addr, 3, new NewArrayOperator(Type.tArray(type), 1)); |
|
|
|
(ca, instr, new NewArrayOperator(Type.tArray(type), 1)); |
|
|
|
} |
|
|
|
} |
|
|
|
case opc_arraylength: |
|
|
|
case opc_arraylength: |
|
|
|
return createNormal |
|
|
|
return createNormal |
|
|
|
(ca, addr, 1, new ArrayLengthOperator()); |
|
|
|
(ca, instr, new ArrayLengthOperator()); |
|
|
|
case opc_athrow: |
|
|
|
case opc_athrow: |
|
|
|
return createBlock |
|
|
|
return createBlock |
|
|
|
(ca, addr, 1, |
|
|
|
(ca, instr, |
|
|
|
new ThrowBlock(new NopOperator(Type.tUObject))); |
|
|
|
new ThrowBlock(new NopOperator(Type.tUObject))); |
|
|
|
case opc_checkcast: { |
|
|
|
case opc_checkcast: { |
|
|
|
Type type = Type.tClassOrArray |
|
|
|
Type type = Type.tClassOrArray((String) instr.objData); |
|
|
|
(cpool.getClassName(stream.readUnsignedShort())); |
|
|
|
|
|
|
|
type.useType(); |
|
|
|
type.useType(); |
|
|
|
return createNormal |
|
|
|
return createNormal |
|
|
|
(ca, addr, 3, new CheckCastOperator(type)); |
|
|
|
(ca, instr, new CheckCastOperator(type)); |
|
|
|
} |
|
|
|
} |
|
|
|
case opc_instanceof: { |
|
|
|
case opc_instanceof: { |
|
|
|
Type type = Type.tClassOrArray |
|
|
|
Type type = Type.tClassOrArray((String) instr.objData); |
|
|
|
(cpool.getClassName(stream.readUnsignedShort())); |
|
|
|
|
|
|
|
type.useType(); |
|
|
|
type.useType(); |
|
|
|
return createNormal |
|
|
|
return createNormal |
|
|
|
(ca, addr, 3, new InstanceOfOperator(type)); |
|
|
|
(ca, instr, new InstanceOfOperator(type)); |
|
|
|
} |
|
|
|
} |
|
|
|
case opc_monitorenter: |
|
|
|
case opc_monitorenter: |
|
|
|
return createNormal(ca, addr, 1, |
|
|
|
return createNormal(ca, instr, |
|
|
|
new MonitorEnterOperator()); |
|
|
|
new MonitorEnterOperator()); |
|
|
|
case opc_monitorexit: |
|
|
|
case opc_monitorexit: |
|
|
|
return createNormal(ca, addr, 1, |
|
|
|
return createNormal(ca, instr, |
|
|
|
new MonitorExitOperator()); |
|
|
|
new MonitorExitOperator()); |
|
|
|
case opc_wide: { |
|
|
|
|
|
|
|
switch (opcode=stream.readUnsignedByte()) { |
|
|
|
|
|
|
|
case opc_iload: case opc_lload: |
|
|
|
|
|
|
|
case opc_fload: case opc_dload: case opc_aload: |
|
|
|
|
|
|
|
return createNormal |
|
|
|
|
|
|
|
(ca, addr, 4, |
|
|
|
|
|
|
|
new LocalLoadOperator |
|
|
|
|
|
|
|
(types[0][opcode-opc_iload], |
|
|
|
|
|
|
|
ca.getLocalInfo(addr, stream.readUnsignedShort()))); |
|
|
|
|
|
|
|
case opc_istore: case opc_lstore: |
|
|
|
|
|
|
|
case opc_fstore: case opc_dstore: case opc_astore: |
|
|
|
|
|
|
|
return createNormal |
|
|
|
|
|
|
|
(ca, addr, 4, |
|
|
|
|
|
|
|
new LocalStoreOperator |
|
|
|
|
|
|
|
(types[0][opcode-opc_istore], |
|
|
|
|
|
|
|
ca.getLocalInfo(addr+4, stream.readUnsignedShort()), |
|
|
|
|
|
|
|
Operator.ASSIGN_OP)); |
|
|
|
|
|
|
|
case opc_iinc: { |
|
|
|
|
|
|
|
int local = stream.readUnsignedShort(); |
|
|
|
|
|
|
|
int value = stream.readShort(); |
|
|
|
|
|
|
|
int operation = Operator.ADD_OP; |
|
|
|
|
|
|
|
if (value < 0) { |
|
|
|
|
|
|
|
value = -value; |
|
|
|
|
|
|
|
operation = Operator.NEG_OP; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
LocalInfo li = ca.getLocalInfo(addr, local); |
|
|
|
|
|
|
|
li.setType(Type.tUInt); |
|
|
|
|
|
|
|
return createNormal |
|
|
|
|
|
|
|
(ca, addr, 6, new IIncOperator |
|
|
|
|
|
|
|
(li, Integer.toString(value), |
|
|
|
|
|
|
|
operation + Operator.OPASSIGN_OP)); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
case opc_ret: |
|
|
|
|
|
|
|
return createRet |
|
|
|
|
|
|
|
(ca, addr, 4, |
|
|
|
|
|
|
|
ca.getLocalInfo(addr, stream.readUnsignedShort())); |
|
|
|
|
|
|
|
default: |
|
|
|
|
|
|
|
throw new ClassFormatError("Invalid wide opcode "+opcode); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
case opc_multianewarray: { |
|
|
|
case opc_multianewarray: { |
|
|
|
Type type = Type.tClassOrArray |
|
|
|
Type type = Type.tClassOrArray((String) instr.objData); |
|
|
|
(cpool.getClassName(stream.readUnsignedShort())); |
|
|
|
type.useType(); |
|
|
|
int dimension = stream.readUnsignedByte(); |
|
|
|
int dimension = instr.intData; |
|
|
|
return createNormal |
|
|
|
return createNormal(ca, instr, |
|
|
|
(ca, addr, 4, |
|
|
|
new NewArrayOperator(type, dimension)); |
|
|
|
new NewArrayOperator(type, dimension)); |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
case opc_ifnull: case opc_ifnonnull: |
|
|
|
case opc_ifnull: case opc_ifnonnull: |
|
|
|
return createIfGoto |
|
|
|
return createIfGoto |
|
|
|
(ca, addr, 3, addr+stream.readShort(), |
|
|
|
(ca, instr, new CompareUnaryOperator |
|
|
|
new CompareUnaryOperator |
|
|
|
|
|
|
|
(Type.tUObject, opcode - (opc_ifnull-Operator.COMPARE_OP))); |
|
|
|
(Type.tUObject, opcode - (opc_ifnull-Operator.COMPARE_OP))); |
|
|
|
case opc_goto_w: |
|
|
|
|
|
|
|
return createGoto |
|
|
|
|
|
|
|
(ca, addr, 5, addr + stream.readInt()); |
|
|
|
|
|
|
|
case opc_jsr_w: |
|
|
|
|
|
|
|
return createJsr |
|
|
|
|
|
|
|
(ca, addr, 5, addr+stream.readInt()); |
|
|
|
|
|
|
|
default: |
|
|
|
default: |
|
|
|
throw new ClassFormatError("Invalid opcode "+opcode); |
|
|
|
throw new jode.AssertError("Invalid opcode "+opcode); |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|