|
|
@ -18,12 +18,13 @@ |
|
|
|
*/ |
|
|
|
*/ |
|
|
|
|
|
|
|
|
|
|
|
package jode; |
|
|
|
package jode; |
|
|
|
|
|
|
|
import jode.flow.*; |
|
|
|
import java.io.*; |
|
|
|
import java.io.*; |
|
|
|
import sun.tools.java.*; |
|
|
|
import sun.tools.java.*; |
|
|
|
|
|
|
|
|
|
|
|
/** |
|
|
|
/** |
|
|
|
* This is an abstract class which creates InstructionHeader for the |
|
|
|
* This is an abstract class which creates flow blocks for the |
|
|
|
* opcodes in an byte stream. |
|
|
|
* opcodes in a byte stream. |
|
|
|
*/ |
|
|
|
*/ |
|
|
|
public abstract class Opcodes implements RuntimeConstants { |
|
|
|
public abstract class Opcodes implements RuntimeConstants { |
|
|
|
|
|
|
|
|
|
|
@ -47,19 +48,54 @@ public abstract class Opcodes implements RuntimeConstants{ |
|
|
|
}; |
|
|
|
}; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
public static FlowBlock createNormal(int addr, int length, |
|
|
|
|
|
|
|
Instruction instr) |
|
|
|
|
|
|
|
{ |
|
|
|
|
|
|
|
return new FlowBlock(addr, length, |
|
|
|
|
|
|
|
new InstructionBlock(instr, |
|
|
|
|
|
|
|
new Jump(addr+length))); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
public static FlowBlock createGoto(int addr, int length, |
|
|
|
|
|
|
|
int destAddr) |
|
|
|
|
|
|
|
{ |
|
|
|
|
|
|
|
return new FlowBlock(addr, length, new EmptyBlock(new Jump(destAddr))); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
public static FlowBlock createIfGoto(int addr, int length, |
|
|
|
|
|
|
|
int destAddr, Instruction instr) |
|
|
|
|
|
|
|
{ |
|
|
|
|
|
|
|
ConditionalBlock ifBlock = |
|
|
|
|
|
|
|
new ConditionalBlock(instr, |
|
|
|
|
|
|
|
new Jump(destAddr), |
|
|
|
|
|
|
|
new Jump(addr+length)); |
|
|
|
|
|
|
|
return new FlowBlock(addr, length, ifBlock); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
public static FlowBlock createSwitch(int addr, int length, |
|
|
|
|
|
|
|
int[] cases, int[] dests) |
|
|
|
|
|
|
|
{ |
|
|
|
|
|
|
|
return new FlowBlock(addr, length, new SwitchBlock(cases, dests)); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
public static FlowBlock createBlock(int addr, int length, |
|
|
|
|
|
|
|
StructuredBlock block) |
|
|
|
|
|
|
|
{ |
|
|
|
|
|
|
|
return new FlowBlock(addr, length, block); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
/** |
|
|
|
/** |
|
|
|
* 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. |
|
|
|
* @param stream The stream containing the java byte code. |
|
|
|
* @param stream The stream containing the java byte code. |
|
|
|
* @param ca The Code Analyzer |
|
|
|
* @param ca The Code Analyzer |
|
|
|
* (where further information can be get from). |
|
|
|
* (where further information can be get from). |
|
|
|
* @return The InstructionHeader representing this opcode |
|
|
|
* @return The FlowBlock representing this opcode |
|
|
|
* or null if the stream is empty. |
|
|
|
* or null if the stream is empty. |
|
|
|
* @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 |
|
|
|
public static FlowBlock readOpcode(int addr, DataInputStream stream, |
|
|
|
InstructionHeader readOpcode(int addr, DataInputStream stream, |
|
|
|
|
|
|
|
CodeAnalyzer ca) |
|
|
|
CodeAnalyzer ca) |
|
|
|
throws IOException, ClassFormatError |
|
|
|
throws IOException, ClassFormatError |
|
|
|
{ |
|
|
|
{ |
|
|
@ -67,42 +103,42 @@ public abstract class Opcodes implements RuntimeConstants{ |
|
|
|
int opcode = stream.readUnsignedByte(); |
|
|
|
int opcode = stream.readUnsignedByte(); |
|
|
|
switch (opcode) { |
|
|
|
switch (opcode) { |
|
|
|
case opc_nop: |
|
|
|
case opc_nop: |
|
|
|
return InstructionHeader.createNormal(addr, 1, new NopOperator()); |
|
|
|
return createNormal(addr, 1, new NopOperator()); |
|
|
|
case opc_aconst_null: |
|
|
|
case opc_aconst_null: |
|
|
|
return InstructionHeader.createNormal |
|
|
|
return createNormal |
|
|
|
(addr, 1, new ConstOperator(OBJECT_TYPE, "null")); |
|
|
|
(addr, 1, new ConstOperator(OBJECT_TYPE, "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 InstructionHeader.createNormal |
|
|
|
return createNormal |
|
|
|
(addr, 1, new ConstOperator |
|
|
|
(addr, 1, new ConstOperator |
|
|
|
(ALL_INT_TYPE, Integer.toString(opcode - opc_iconst_0))); |
|
|
|
(ALL_INT_TYPE, Integer.toString(opcode - opc_iconst_0))); |
|
|
|
case opc_lconst_0: case opc_lconst_1: |
|
|
|
case opc_lconst_0: case opc_lconst_1: |
|
|
|
return InstructionHeader.createNormal |
|
|
|
return createNormal |
|
|
|
(addr, 1, new ConstOperator |
|
|
|
(addr, 1, new ConstOperator |
|
|
|
(LONG_TYPE, |
|
|
|
(LONG_TYPE, |
|
|
|
Integer.toString(opcode - opc_lconst_0) + "L")); |
|
|
|
Integer.toString(opcode - opc_lconst_0) + "L")); |
|
|
|
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 InstructionHeader.createNormal |
|
|
|
return createNormal |
|
|
|
(addr, 1, new ConstOperator |
|
|
|
(addr, 1, new ConstOperator |
|
|
|
(FLOAT_TYPE, |
|
|
|
(FLOAT_TYPE, |
|
|
|
Integer.toString(opcode - opc_fconst_0) + ".0F")); |
|
|
|
Integer.toString(opcode - opc_fconst_0) + ".0F")); |
|
|
|
case opc_dconst_0: case opc_dconst_1: |
|
|
|
case opc_dconst_0: case opc_dconst_1: |
|
|
|
return InstructionHeader.createNormal |
|
|
|
return createNormal |
|
|
|
(addr, 1, new ConstOperator |
|
|
|
(addr, 1, new ConstOperator |
|
|
|
(DOUBLE_TYPE, |
|
|
|
(DOUBLE_TYPE, |
|
|
|
Integer.toString(opcode - opc_dconst_0) + ".0")); |
|
|
|
Integer.toString(opcode - opc_dconst_0) + ".0")); |
|
|
|
case opc_bipush: |
|
|
|
case opc_bipush: |
|
|
|
return InstructionHeader.createNormal |
|
|
|
return createNormal |
|
|
|
(addr, 2, new ConstOperator |
|
|
|
(addr, 2, new ConstOperator |
|
|
|
(ALL_INT_TYPE, Integer.toString(stream.readByte()))); |
|
|
|
(ALL_INT_TYPE, Integer.toString(stream.readByte()))); |
|
|
|
case opc_sipush: |
|
|
|
case opc_sipush: |
|
|
|
return InstructionHeader.createNormal |
|
|
|
return createNormal |
|
|
|
(addr, 3, new ConstOperator |
|
|
|
(addr, 3, new ConstOperator |
|
|
|
(ALL_INT_TYPE, Integer.toString(stream.readShort()))); |
|
|
|
(ALL_INT_TYPE, Integer.toString(stream.readShort()))); |
|
|
|
case opc_ldc: { |
|
|
|
case opc_ldc: { |
|
|
|
int index = stream.readUnsignedByte(); |
|
|
|
int index = stream.readUnsignedByte(); |
|
|
|
return InstructionHeader.createNormal |
|
|
|
return createNormal |
|
|
|
(addr, 2, new ConstOperator |
|
|
|
(addr, 2, new ConstOperator |
|
|
|
(ca.env.getConstantType(index), |
|
|
|
(ca.env.getConstantType(index), |
|
|
|
ca.env.getConstant(index).toString())); |
|
|
|
ca.env.getConstant(index).toString())); |
|
|
@ -110,38 +146,38 @@ public abstract class Opcodes implements RuntimeConstants{ |
|
|
|
case opc_ldc_w: |
|
|
|
case opc_ldc_w: |
|
|
|
case opc_ldc2_w: { |
|
|
|
case opc_ldc2_w: { |
|
|
|
int index = stream.readUnsignedShort(); |
|
|
|
int index = stream.readUnsignedShort(); |
|
|
|
return InstructionHeader.createNormal |
|
|
|
return createNormal |
|
|
|
(addr, 3, new ConstOperator |
|
|
|
(addr, 3, new ConstOperator |
|
|
|
(ca.env.getConstantType(index), |
|
|
|
(ca.env.getConstantType(index), |
|
|
|
ca.env.getConstant(index).toString())); |
|
|
|
ca.env.getConstant(index).toString())); |
|
|
|
} |
|
|
|
} |
|
|
|
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 InstructionHeader.createNormal |
|
|
|
return createNormal |
|
|
|
(addr, 2, new LocalLoadOperator |
|
|
|
(addr, 2, new LocalLoadOperator |
|
|
|
(types[0][opcode-opc_iload], |
|
|
|
(types[0][opcode-opc_iload], |
|
|
|
stream.readUnsignedByte())); |
|
|
|
new LocalInfo(stream.readUnsignedByte()))); |
|
|
|
case opc_iload_0: case opc_iload_1: case opc_iload_2: case opc_iload_3: |
|
|
|
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_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_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_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: |
|
|
|
case opc_aload_0: case opc_aload_1: case opc_aload_2: case opc_aload_3: |
|
|
|
return InstructionHeader.createNormal |
|
|
|
return createNormal |
|
|
|
(addr, 1, new LocalLoadOperator |
|
|
|
(addr, 1, new LocalLoadOperator |
|
|
|
(types[0][(opcode-opc_iload_0)/4], |
|
|
|
(types[0][(opcode-opc_iload_0)/4], |
|
|
|
(opcode-opc_iload_0) & 3)); |
|
|
|
new LocalInfo((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 InstructionHeader.createNormal |
|
|
|
return createNormal |
|
|
|
(addr, 1, new ArrayLoadOperator |
|
|
|
(addr, 1, 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 InstructionHeader.createNormal |
|
|
|
return createNormal |
|
|
|
(addr, 2, new LocalStoreOperator |
|
|
|
(addr, 2, new LocalStoreOperator |
|
|
|
(types[0][opcode-opc_istore], |
|
|
|
(types[0][opcode-opc_istore], |
|
|
|
stream.readUnsignedByte(), |
|
|
|
new LocalInfo(stream.readUnsignedByte()), |
|
|
|
Operator.ASSIGN_OP)); |
|
|
|
Operator.ASSIGN_OP)); |
|
|
|
case opc_istore_0: case opc_istore_1: |
|
|
|
case opc_istore_0: case opc_istore_1: |
|
|
|
case opc_istore_2: case opc_istore_3: |
|
|
|
case opc_istore_2: case opc_istore_3: |
|
|
@ -153,51 +189,51 @@ public abstract class Opcodes implements RuntimeConstants{ |
|
|
|
case opc_dstore_2: case opc_dstore_3: |
|
|
|
case opc_dstore_2: case opc_dstore_3: |
|
|
|
case opc_astore_0: case opc_astore_1: |
|
|
|
case opc_astore_0: case opc_astore_1: |
|
|
|
case opc_astore_2: case opc_astore_3: |
|
|
|
case opc_astore_2: case opc_astore_3: |
|
|
|
return InstructionHeader.createNormal |
|
|
|
return createNormal |
|
|
|
(addr, 1, new LocalStoreOperator |
|
|
|
(addr, 1, new LocalStoreOperator |
|
|
|
(types[0][(opcode-opc_istore_0)/4], |
|
|
|
(types[0][(opcode-opc_istore_0)/4], |
|
|
|
(opcode-opc_istore_0) & 3, |
|
|
|
new LocalInfo((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 InstructionHeader.createNormal |
|
|
|
return createNormal |
|
|
|
(addr, 1, new ArrayStoreOperator |
|
|
|
(addr, 1, 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 InstructionHeader.createNormal |
|
|
|
return createNormal |
|
|
|
(addr, 1, new PopOperator(opcode - opc_pop + 1)); |
|
|
|
(addr, 1, new PopOperator(opcode - opc_pop + 1)); |
|
|
|
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 InstructionHeader.createNormal |
|
|
|
return createNormal |
|
|
|
(addr, 1, new DupOperator |
|
|
|
(addr, 1, new DupOperator |
|
|
|
((opcode - opc_dup)%3, (opcode - opc_dup)/3+1)); |
|
|
|
((opcode - opc_dup)%3, (opcode - opc_dup)/3+1)); |
|
|
|
case opc_swap: |
|
|
|
case opc_swap: |
|
|
|
return InstructionHeader.createNormal(addr, 1, new SwapOperator()); |
|
|
|
return createNormal(addr, 1, new SwapOperator()); |
|
|
|
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 InstructionHeader.createNormal |
|
|
|
return createNormal |
|
|
|
(addr, 1, new BinaryOperator |
|
|
|
(addr, 1, new BinaryOperator |
|
|
|
(types[0][(opcode - opc_iadd)%4], |
|
|
|
(types[0][(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 InstructionHeader.createNormal |
|
|
|
return createNormal |
|
|
|
(addr, 1, new UnaryOperator |
|
|
|
(addr, 1, new UnaryOperator |
|
|
|
(types[0][opcode - opc_ineg], Operator.NEG_OP)); |
|
|
|
(types[0][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 InstructionHeader.createNormal |
|
|
|
return createNormal |
|
|
|
(addr, 1, new ShiftOperator |
|
|
|
(addr, 1, new ShiftOperator |
|
|
|
(types[0][(opcode - opc_ishl)%2], |
|
|
|
(types[0][(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 InstructionHeader.createNormal |
|
|
|
return createNormal |
|
|
|
(addr, 1, new BinaryOperator |
|
|
|
(addr, 1, new BinaryOperator |
|
|
|
(types[0][(opcode - opc_iand)%2], |
|
|
|
(types[0][(opcode - opc_iand)%2], |
|
|
|
(opcode - opc_iand)/2 + Operator.AND_OP)); |
|
|
|
(opcode - opc_iand)/2 + Operator.AND_OP)); |
|
|
@ -209,9 +245,10 @@ public abstract class Opcodes implements RuntimeConstants{ |
|
|
|
value = -value; |
|
|
|
value = -value; |
|
|
|
operation = Operator.NEG_OP; |
|
|
|
operation = Operator.NEG_OP; |
|
|
|
} |
|
|
|
} |
|
|
|
return InstructionHeader.createNormal |
|
|
|
LocalInfo li = new LocalInfo(local); |
|
|
|
|
|
|
|
return createNormal |
|
|
|
(addr, 3, new IIncOperator |
|
|
|
(addr, 3, new IIncOperator |
|
|
|
(local, 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: |
|
|
@ -222,48 +259,48 @@ public abstract class Opcodes implements RuntimeConstants{ |
|
|
|
int to = (opcode-opc_i2l)%3; |
|
|
|
int to = (opcode-opc_i2l)%3; |
|
|
|
if (to >= from) |
|
|
|
if (to >= from) |
|
|
|
to++; |
|
|
|
to++; |
|
|
|
return InstructionHeader.createNormal |
|
|
|
return createNormal |
|
|
|
(addr, 1, new ConvertOperator(types[0][from], |
|
|
|
(addr, 1, new ConvertOperator(types[0][from], |
|
|
|
types[0][to])); |
|
|
|
types[0][to])); |
|
|
|
} |
|
|
|
} |
|
|
|
case opc_i2b: case opc_i2c: case opc_i2s: |
|
|
|
case opc_i2b: case opc_i2c: case opc_i2s: |
|
|
|
return InstructionHeader.createNormal |
|
|
|
return createNormal |
|
|
|
(addr, 1, new ConvertOperator |
|
|
|
(addr, 1, new ConvertOperator |
|
|
|
(ALL_INT_TYPE, types[1][(opcode-opc_i2b)+5])); |
|
|
|
(ALL_INT_TYPE, types[1][(opcode-opc_i2b)+5])); |
|
|
|
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 InstructionHeader.createNormal |
|
|
|
return createNormal |
|
|
|
(addr, 1, new CompareToIntOperator |
|
|
|
(addr, 1, new CompareToIntOperator |
|
|
|
(types[0][(opcode-opc_lcmp+3)/2], (opcode-opc_lcmp+3)%2)); |
|
|
|
(types[0][(opcode-opc_lcmp+3)/2], (opcode-opc_lcmp+3)%2)); |
|
|
|
case opc_ifeq: case opc_ifne: |
|
|
|
case opc_ifeq: case opc_ifne: |
|
|
|
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 InstructionHeader.createIfGoto |
|
|
|
return createIfGoto |
|
|
|
(addr, 3, addr+stream.readShort(), |
|
|
|
(addr, 3, addr+stream.readShort(), |
|
|
|
new CompareUnaryOperator |
|
|
|
new CompareUnaryOperator |
|
|
|
(ALL_INT_TYPE, opcode - opc_ifeq+Operator.COMPARE_OP)); |
|
|
|
(ALL_INT_TYPE, opcode - opc_ifeq+Operator.COMPARE_OP)); |
|
|
|
case opc_if_icmpeq: case opc_if_icmpne: case opc_if_icmplt: |
|
|
|
case opc_if_icmpeq: case opc_if_icmpne: case opc_if_icmplt: |
|
|
|
case opc_if_icmpge: case opc_if_icmpgt: case opc_if_icmple: |
|
|
|
case opc_if_icmpge: case opc_if_icmpgt: case opc_if_icmple: |
|
|
|
return InstructionHeader.createIfGoto |
|
|
|
return createIfGoto |
|
|
|
(addr, 3, addr+stream.readShort(), |
|
|
|
(addr, 3, addr+stream.readShort(), |
|
|
|
new CompareBinaryOperator |
|
|
|
new CompareBinaryOperator |
|
|
|
(ALL_INT_TYPE, opcode - opc_if_icmpeq+Operator.COMPARE_OP)); |
|
|
|
(ALL_INT_TYPE, opcode - opc_if_icmpeq+Operator.COMPARE_OP)); |
|
|
|
case opc_if_acmpeq: case opc_if_acmpne: |
|
|
|
case opc_if_acmpeq: case opc_if_acmpne: |
|
|
|
return InstructionHeader.createIfGoto |
|
|
|
return createIfGoto |
|
|
|
(addr, 3, addr+stream.readShort(), |
|
|
|
(addr, 3, addr+stream.readShort(), |
|
|
|
new CompareBinaryOperator |
|
|
|
new CompareBinaryOperator |
|
|
|
(OBJECT_TYPE, opcode - opc_if_acmpeq+Operator.COMPARE_OP)); |
|
|
|
(OBJECT_TYPE, opcode - opc_if_acmpeq+Operator.COMPARE_OP)); |
|
|
|
case opc_goto: |
|
|
|
case opc_goto: |
|
|
|
return InstructionHeader.createGoto |
|
|
|
return createGoto |
|
|
|
(addr, 3, addr+stream.readShort()); |
|
|
|
|
|
|
|
case opc_jsr: |
|
|
|
|
|
|
|
return InstructionHeader.createGoto //XXX
|
|
|
|
|
|
|
|
(addr, 3, addr+stream.readShort()); |
|
|
|
(addr, 3, addr+stream.readShort()); |
|
|
|
case opc_ret: |
|
|
|
// case opc_jsr:
|
|
|
|
return InstructionHeader.createReturn //XXX
|
|
|
|
// return createGoto //XXX
|
|
|
|
(addr, 2, |
|
|
|
// (addr, 3, addr+stream.readShort());
|
|
|
|
new LocalLoadOperator |
|
|
|
// case opc_ret:
|
|
|
|
(OBJECT_TYPE, stream.readUnsignedByte())); |
|
|
|
// return createReturn //XXX
|
|
|
|
|
|
|
|
// (addr, 2,
|
|
|
|
|
|
|
|
// new LocalLoadOperator
|
|
|
|
|
|
|
|
// (OBJECT_TYPE, new LocalInfo(stream.readUnsignedByte())));
|
|
|
|
case opc_tableswitch: { |
|
|
|
case opc_tableswitch: { |
|
|
|
int length = 3-(addr % 4); |
|
|
|
int length = 3-(addr % 4); |
|
|
|
stream.skip(length); |
|
|
|
stream.skip(length); |
|
|
@ -278,8 +315,8 @@ public abstract class Opcodes implements RuntimeConstants{ |
|
|
|
} |
|
|
|
} |
|
|
|
dests[cases.length] = def; |
|
|
|
dests[cases.length] = def; |
|
|
|
length += 13 + 4 * cases.length; |
|
|
|
length += 13 + 4 * cases.length; |
|
|
|
return InstructionHeader.createSwitch |
|
|
|
return createSwitch |
|
|
|
(addr, length, new NopOperator(), cases, dests); |
|
|
|
(addr, length, cases, dests); |
|
|
|
} |
|
|
|
} |
|
|
|
case opc_lookupswitch: { |
|
|
|
case opc_lookupswitch: { |
|
|
|
int length = 3-(addr % 4); |
|
|
|
int length = 3-(addr % 4); |
|
|
@ -294,31 +331,31 @@ public abstract class Opcodes implements RuntimeConstants{ |
|
|
|
} |
|
|
|
} |
|
|
|
dests[npairs] = def; |
|
|
|
dests[npairs] = def; |
|
|
|
length += 9 + 8 * npairs; |
|
|
|
length += 9 + 8 * npairs; |
|
|
|
return InstructionHeader.createSwitch |
|
|
|
return createSwitch |
|
|
|
(addr, length, new NopOperator(), cases, dests); |
|
|
|
(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: { |
|
|
|
Type retType = MyType.intersection |
|
|
|
Type retType = MyType.intersection |
|
|
|
(ca.getMethod().mdef.getType().getReturnType(), |
|
|
|
(ca.getMethod().mdef.getType().getReturnType(), |
|
|
|
types[0][opcode-opc_ireturn]); |
|
|
|
types[0][opcode-opc_ireturn]); |
|
|
|
return InstructionHeader.createReturn |
|
|
|
return createBlock |
|
|
|
(addr, 1, new ReturnOperator(retType)); |
|
|
|
(addr, 1, new ReturnBlock(new NopOperator(retType))); |
|
|
|
} |
|
|
|
|
|
|
|
case opc_return: { |
|
|
|
|
|
|
|
return InstructionHeader.createReturn |
|
|
|
|
|
|
|
(addr, 1, null); |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
case opc_return: |
|
|
|
|
|
|
|
/* Address -1 is interpreted as end of method */ |
|
|
|
|
|
|
|
return createBlock |
|
|
|
|
|
|
|
(addr, 1, new EmptyBlock(new Jump(-1))); |
|
|
|
case opc_getstatic: |
|
|
|
case opc_getstatic: |
|
|
|
case opc_getfield: |
|
|
|
case opc_getfield: |
|
|
|
return InstructionHeader.createNormal |
|
|
|
return createNormal |
|
|
|
(addr, 3, new GetFieldOperator |
|
|
|
(addr, 3, new GetFieldOperator |
|
|
|
(ca, opcode == opc_getstatic, |
|
|
|
(ca, opcode == opc_getstatic, |
|
|
|
(FieldDefinition)ca.env.getConstant |
|
|
|
(FieldDefinition)ca.env.getConstant |
|
|
|
(stream.readUnsignedShort()))); |
|
|
|
(stream.readUnsignedShort()))); |
|
|
|
case opc_putstatic: |
|
|
|
case opc_putstatic: |
|
|
|
case opc_putfield: |
|
|
|
case opc_putfield: |
|
|
|
return InstructionHeader.createNormal |
|
|
|
return createNormal |
|
|
|
(addr, 3, new PutFieldOperator |
|
|
|
(addr, 3, new PutFieldOperator |
|
|
|
(ca, opcode == opc_putstatic, |
|
|
|
(ca, opcode == opc_putstatic, |
|
|
|
(FieldDefinition)ca.env.getConstant |
|
|
|
(FieldDefinition)ca.env.getConstant |
|
|
@ -326,26 +363,26 @@ public abstract class Opcodes implements RuntimeConstants{ |
|
|
|
case opc_invokevirtual: |
|
|
|
case opc_invokevirtual: |
|
|
|
case opc_invokespecial: |
|
|
|
case opc_invokespecial: |
|
|
|
case opc_invokestatic : |
|
|
|
case opc_invokestatic : |
|
|
|
return InstructionHeader.createNormal |
|
|
|
return createNormal |
|
|
|
(addr, 3, new InvokeOperator |
|
|
|
(addr, 3, new InvokeOperator |
|
|
|
(ca, |
|
|
|
(ca, |
|
|
|
opcode == opc_invokestatic, opcode == opc_invokespecial, |
|
|
|
opcode == opc_invokestatic, opcode == opc_invokespecial, |
|
|
|
(FieldDefinition)ca.env.getConstant |
|
|
|
(FieldDefinition)ca.env.getConstant |
|
|
|
(stream.readUnsignedShort()))); |
|
|
|
(stream.readUnsignedShort()))); |
|
|
|
case opc_invokeinterface: { |
|
|
|
case opc_invokeinterface: { |
|
|
|
InstructionHeader ih = InstructionHeader.createNormal |
|
|
|
FlowBlock fb = createNormal |
|
|
|
(addr, 5, new InvokeOperator |
|
|
|
(addr, 5, new InvokeOperator |
|
|
|
(ca, false, false, |
|
|
|
(ca, false, false, |
|
|
|
(FieldDefinition)ca.env.getConstant |
|
|
|
(FieldDefinition)ca.env.getConstant |
|
|
|
(stream.readUnsignedShort()))); |
|
|
|
(stream.readUnsignedShort()))); |
|
|
|
int reserved = stream.readUnsignedShort(); |
|
|
|
int reserved = stream.readUnsignedShort(); |
|
|
|
return ih; |
|
|
|
return fb; |
|
|
|
} |
|
|
|
} |
|
|
|
case opc_new: { |
|
|
|
case opc_new: { |
|
|
|
ClassDeclaration cldec = (ClassDeclaration) |
|
|
|
ClassDeclaration cldec = (ClassDeclaration) |
|
|
|
ca.env.getConstant(stream.readUnsignedShort()); |
|
|
|
ca.env.getConstant(stream.readUnsignedShort()); |
|
|
|
Type type = MyType.tClassOrArray(cldec.getName()); |
|
|
|
Type type = MyType.tClassOrArray(cldec.getName()); |
|
|
|
return InstructionHeader.createNormal |
|
|
|
return createNormal |
|
|
|
(addr, 3, new NewOperator(type, ca.env.getTypeString(type))); |
|
|
|
(addr, 3, new NewOperator(type, ca.env.getTypeString(type))); |
|
|
|
} |
|
|
|
} |
|
|
|
case opc_newarray: { |
|
|
|
case opc_newarray: { |
|
|
@ -362,7 +399,7 @@ public abstract class Opcodes implements RuntimeConstants{ |
|
|
|
default: |
|
|
|
default: |
|
|
|
throw new ClassFormatError("Invalid newarray operand"); |
|
|
|
throw new ClassFormatError("Invalid newarray operand"); |
|
|
|
} |
|
|
|
} |
|
|
|
return InstructionHeader.createNormal |
|
|
|
return createNormal |
|
|
|
(addr, 2, |
|
|
|
(addr, 2, |
|
|
|
new NewArrayOperator(MyType.tArray(type), |
|
|
|
new NewArrayOperator(MyType.tArray(type), |
|
|
|
type.toString(), 1)); |
|
|
|
type.toString(), 1)); |
|
|
@ -372,21 +409,22 @@ public abstract class Opcodes implements RuntimeConstants{ |
|
|
|
(stream.readUnsignedShort()); |
|
|
|
(stream.readUnsignedShort()); |
|
|
|
Identifier ident = cldec.getName(); |
|
|
|
Identifier ident = cldec.getName(); |
|
|
|
Type type = MyType.tClassOrArray(cldec.getName()); |
|
|
|
Type type = MyType.tClassOrArray(cldec.getName()); |
|
|
|
return InstructionHeader.createNormal |
|
|
|
return createNormal |
|
|
|
(addr, 3, new NewArrayOperator |
|
|
|
(addr, 3, new NewArrayOperator |
|
|
|
(MyType.tArray(type), ca.env.getTypeString(type),1)); |
|
|
|
(MyType.tArray(type), ca.env.getTypeString(type),1)); |
|
|
|
} |
|
|
|
} |
|
|
|
case opc_arraylength: |
|
|
|
case opc_arraylength: |
|
|
|
return InstructionHeader.createNormal |
|
|
|
return createNormal |
|
|
|
(addr, 1, new ArrayLengthOperator()); |
|
|
|
(addr, 1, new ArrayLengthOperator()); |
|
|
|
case opc_athrow: |
|
|
|
case opc_athrow: |
|
|
|
return InstructionHeader.createReturn |
|
|
|
return createBlock |
|
|
|
(addr, 1, new ThrowOperator()); |
|
|
|
(addr, 1, |
|
|
|
|
|
|
|
new ThrowBlock(new NopOperator(MyType.tUObject))); |
|
|
|
case opc_checkcast: { |
|
|
|
case opc_checkcast: { |
|
|
|
ClassDeclaration cldec = (ClassDeclaration) ca.env.getConstant |
|
|
|
ClassDeclaration cldec = (ClassDeclaration) ca.env.getConstant |
|
|
|
(stream.readUnsignedShort()); |
|
|
|
(stream.readUnsignedShort()); |
|
|
|
Type type = MyType.tClassOrArray(cldec.getName()); |
|
|
|
Type type = MyType.tClassOrArray(cldec.getName()); |
|
|
|
return InstructionHeader.createNormal |
|
|
|
return createNormal |
|
|
|
(addr, 3, new CheckCastOperator |
|
|
|
(addr, 3, new CheckCastOperator |
|
|
|
(type, ca.env.getTypeString(type))); |
|
|
|
(type, ca.env.getTypeString(type))); |
|
|
|
} |
|
|
|
} |
|
|
@ -394,30 +432,32 @@ public abstract class Opcodes implements RuntimeConstants{ |
|
|
|
ClassDeclaration cldec = (ClassDeclaration) ca.env.getConstant |
|
|
|
ClassDeclaration cldec = (ClassDeclaration) ca.env.getConstant |
|
|
|
(stream.readUnsignedShort()); |
|
|
|
(stream.readUnsignedShort()); |
|
|
|
Type type = MyType.tClassOrArray(cldec.getName()); |
|
|
|
Type type = MyType.tClassOrArray(cldec.getName()); |
|
|
|
return InstructionHeader.createNormal |
|
|
|
return createNormal |
|
|
|
(addr, 3, |
|
|
|
(addr, 3, |
|
|
|
new InstanceOfOperator(type, ca.env.getTypeString(type))); |
|
|
|
new InstanceOfOperator(type, ca.env.getTypeString(type))); |
|
|
|
} |
|
|
|
} |
|
|
|
case opc_monitorenter: |
|
|
|
case opc_monitorenter: |
|
|
|
return InstructionHeader.createNormal(addr, 1, |
|
|
|
return createNormal(addr, 1, |
|
|
|
new MonitorEnterOperator()); |
|
|
|
new MonitorEnterOperator()); |
|
|
|
case opc_monitorexit: |
|
|
|
case opc_monitorexit: |
|
|
|
return InstructionHeader.createNormal(addr, 1, |
|
|
|
return createNormal(addr, 1, |
|
|
|
new MonitorExitOperator()); |
|
|
|
new MonitorExitOperator()); |
|
|
|
case opc_wide: { |
|
|
|
case opc_wide: { |
|
|
|
switch (opcode=stream.readUnsignedByte()) { |
|
|
|
switch (opcode=stream.readUnsignedByte()) { |
|
|
|
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 InstructionHeader.createNormal |
|
|
|
return createNormal |
|
|
|
(addr, 4, |
|
|
|
(addr, 4, |
|
|
|
new LocalLoadOperator(types[0][opcode-opc_iload], |
|
|
|
new LocalLoadOperator(types[0][opcode-opc_iload], |
|
|
|
stream.readUnsignedShort())); |
|
|
|
new LocalInfo |
|
|
|
|
|
|
|
(stream.readUnsignedShort()))); |
|
|
|
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 InstructionHeader.createNormal |
|
|
|
return createNormal |
|
|
|
(addr, 4, |
|
|
|
(addr, 4, |
|
|
|
new LocalStoreOperator(types[0][opcode-opc_istore], |
|
|
|
new LocalStoreOperator |
|
|
|
stream.readUnsignedShort(), |
|
|
|
(types[0][opcode-opc_istore], |
|
|
|
|
|
|
|
new LocalInfo(stream.readUnsignedShort()), |
|
|
|
Operator.ASSIGN_OP)); |
|
|
|
Operator.ASSIGN_OP)); |
|
|
|
case opc_iinc: { |
|
|
|
case opc_iinc: { |
|
|
|
int local = stream.readUnsignedShort(); |
|
|
|
int local = stream.readUnsignedShort(); |
|
|
@ -427,16 +467,18 @@ public abstract class Opcodes implements RuntimeConstants{ |
|
|
|
value = -value; |
|
|
|
value = -value; |
|
|
|
operation = Operator.NEG_OP; |
|
|
|
operation = Operator.NEG_OP; |
|
|
|
} |
|
|
|
} |
|
|
|
return InstructionHeader.createNormal |
|
|
|
LocalInfo li = new LocalInfo(local); |
|
|
|
|
|
|
|
return createNormal |
|
|
|
(addr, 6, new IIncOperator |
|
|
|
(addr, 6, new IIncOperator |
|
|
|
(local, Integer.toString(value), |
|
|
|
(li, Integer.toString(value), |
|
|
|
operation + Operator.OPASSIGN_OP)); |
|
|
|
operation + Operator.OPASSIGN_OP)); |
|
|
|
} |
|
|
|
} |
|
|
|
case opc_ret: |
|
|
|
// case opc_ret:
|
|
|
|
return new RetInstructionHeader |
|
|
|
// return new RetInstructionHeader
|
|
|
|
(addr, 4, |
|
|
|
// (addr, 4,
|
|
|
|
new LocalLoadOperator |
|
|
|
// new LocalLoadOperator
|
|
|
|
(INT_TYPE, stream.readUnsignedShort())); |
|
|
|
// (INT_TYPE,
|
|
|
|
|
|
|
|
// new LocalInfo(stream.readUnsignedShort())));
|
|
|
|
default: |
|
|
|
default: |
|
|
|
throw new ClassFormatError("Invalid wide opcode "+opcode); |
|
|
|
throw new ClassFormatError("Invalid wide opcode "+opcode); |
|
|
|
} |
|
|
|
} |
|
|
@ -449,22 +491,22 @@ public abstract class Opcodes implements RuntimeConstants{ |
|
|
|
Type baseType = type; |
|
|
|
Type baseType = type; |
|
|
|
for (int i=0; i<dimension; i++) |
|
|
|
for (int i=0; i<dimension; i++) |
|
|
|
baseType = baseType.getElementType(); |
|
|
|
baseType = baseType.getElementType(); |
|
|
|
return InstructionHeader.createNormal |
|
|
|
return createNormal |
|
|
|
(addr, 4, |
|
|
|
(addr, 4, |
|
|
|
new NewArrayOperator |
|
|
|
new NewArrayOperator |
|
|
|
(type, ca.env.getTypeString(baseType), dimension)); |
|
|
|
(type, ca.env.getTypeString(baseType), dimension)); |
|
|
|
} |
|
|
|
} |
|
|
|
case opc_ifnull: case opc_ifnonnull: |
|
|
|
case opc_ifnull: case opc_ifnonnull: |
|
|
|
return InstructionHeader.createIfGoto |
|
|
|
return createIfGoto |
|
|
|
(addr, 3, addr+stream.readShort(), |
|
|
|
(addr, 3, addr+stream.readShort(), |
|
|
|
new CompareUnaryOperator |
|
|
|
new CompareUnaryOperator |
|
|
|
(OBJECT_TYPE, opcode - opc_ifnull+Operator.COMPARE_OP)); |
|
|
|
(OBJECT_TYPE, opcode - opc_ifnull+Operator.COMPARE_OP)); |
|
|
|
case opc_goto_w: |
|
|
|
case opc_goto_w: |
|
|
|
return InstructionHeader.createGoto |
|
|
|
return createGoto |
|
|
|
(addr, 5, addr + stream.readInt()); |
|
|
|
(addr, 5, addr + stream.readInt()); |
|
|
|
case opc_jsr_w: |
|
|
|
// case opc_jsr_w:
|
|
|
|
return InstructionHeader.createGoto |
|
|
|
// return createGoto
|
|
|
|
(addr, 5, addr+stream.readInt()); // XXX
|
|
|
|
// (addr, 5, addr+stream.readInt()); // XXX
|
|
|
|
default: |
|
|
|
default: |
|
|
|
throw new ClassFormatError("Invalid opcode "+opcode); |
|
|
|
throw new ClassFormatError("Invalid opcode "+opcode); |
|
|
|
} |
|
|
|
} |
|
|
|