|
|
@ -63,6 +63,7 @@ public class BytecodeInfo extends BinaryInfo implements Opcodes { |
|
|
|
codeLength = input.readInt(); |
|
|
|
codeLength = input.readInt(); |
|
|
|
Instruction[] instrs = new Instruction[codeLength]; |
|
|
|
Instruction[] instrs = new Instruction[codeLength]; |
|
|
|
int[][] succAddrs = new int[codeLength][]; |
|
|
|
int[][] succAddrs = new int[codeLength][]; |
|
|
|
|
|
|
|
int[] predcounts = new int[codeLength]; |
|
|
|
{ |
|
|
|
{ |
|
|
|
int addr = 0; |
|
|
|
int addr = 0; |
|
|
|
Instruction lastInstr = null; |
|
|
|
Instruction lastInstr = null; |
|
|
@ -86,11 +87,23 @@ public class BytecodeInfo extends BinaryInfo implements Opcodes { |
|
|
|
int wideopcode = input.readUnsignedByte(); |
|
|
|
int wideopcode = input.readUnsignedByte(); |
|
|
|
instr.opcode = wideopcode; |
|
|
|
instr.opcode = wideopcode; |
|
|
|
switch (wideopcode) { |
|
|
|
switch (wideopcode) { |
|
|
|
case opc_iload: case opc_lload: |
|
|
|
case opc_iload: case opc_fload: case opc_aload: |
|
|
|
case opc_fload: case opc_dload: case opc_aload: |
|
|
|
case opc_istore: case opc_fstore: case opc_astore: |
|
|
|
case opc_istore: case opc_lstore: |
|
|
|
|
|
|
|
case opc_fstore: case opc_dstore: case opc_astore: |
|
|
|
|
|
|
|
instr.localSlot = input.readUnsignedShort(); |
|
|
|
instr.localSlot = input.readUnsignedShort(); |
|
|
|
|
|
|
|
if (instr.localSlot >= maxLocals) |
|
|
|
|
|
|
|
throw new ClassFormatError |
|
|
|
|
|
|
|
("Invalid local slot "+instr.localSlot); |
|
|
|
|
|
|
|
instr.length = 4; |
|
|
|
|
|
|
|
if (Decompiler.isDebugging)/*XXX*/ |
|
|
|
|
|
|
|
Decompiler.err.print(" "+opcodeString[wideopcode] |
|
|
|
|
|
|
|
+" "+instr.localSlot); |
|
|
|
|
|
|
|
break; |
|
|
|
|
|
|
|
case opc_lload: case opc_dload: |
|
|
|
|
|
|
|
case opc_lstore: case opc_dstore: |
|
|
|
|
|
|
|
instr.localSlot = input.readUnsignedShort(); |
|
|
|
|
|
|
|
if (instr.localSlot >= maxLocals-1) |
|
|
|
|
|
|
|
throw new ClassFormatError |
|
|
|
|
|
|
|
("Invalid local slot "+instr.localSlot); |
|
|
|
instr.length = 4; |
|
|
|
instr.length = 4; |
|
|
|
if (Decompiler.isDebugging)/*XXX*/ |
|
|
|
if (Decompiler.isDebugging)/*XXX*/ |
|
|
|
Decompiler.err.print(" "+opcodeString[wideopcode] |
|
|
|
Decompiler.err.print(" "+opcodeString[wideopcode] |
|
|
@ -98,6 +111,9 @@ public class BytecodeInfo extends BinaryInfo implements Opcodes { |
|
|
|
break; |
|
|
|
break; |
|
|
|
case opc_ret: |
|
|
|
case opc_ret: |
|
|
|
instr.localSlot = input.readUnsignedShort(); |
|
|
|
instr.localSlot = input.readUnsignedShort(); |
|
|
|
|
|
|
|
if (instr.localSlot >= maxLocals) |
|
|
|
|
|
|
|
throw new ClassFormatError |
|
|
|
|
|
|
|
("Invalid local slot "+instr.localSlot); |
|
|
|
instr.length = 4; |
|
|
|
instr.length = 4; |
|
|
|
instr.alwaysJumps = true; |
|
|
|
instr.alwaysJumps = true; |
|
|
|
if (Decompiler.isDebugging)/*XXX*/ |
|
|
|
if (Decompiler.isDebugging)/*XXX*/ |
|
|
@ -106,6 +122,9 @@ public class BytecodeInfo extends BinaryInfo implements Opcodes { |
|
|
|
|
|
|
|
|
|
|
|
case opc_iinc: |
|
|
|
case opc_iinc: |
|
|
|
instr.localSlot = input.readUnsignedShort(); |
|
|
|
instr.localSlot = input.readUnsignedShort(); |
|
|
|
|
|
|
|
if (instr.localSlot >= maxLocals) |
|
|
|
|
|
|
|
throw new ClassFormatError |
|
|
|
|
|
|
|
("Invalid local slot "+instr.localSlot); |
|
|
|
instr.intData = input.readShort(); |
|
|
|
instr.intData = input.readShort(); |
|
|
|
instr.length = 6; |
|
|
|
instr.length = 6; |
|
|
|
if (Decompiler.isDebugging)/*XXX*/ |
|
|
|
if (Decompiler.isDebugging)/*XXX*/ |
|
|
@ -130,27 +149,51 @@ public class BytecodeInfo extends BinaryInfo implements Opcodes { |
|
|
|
case opc_aload_2: case opc_aload_3: |
|
|
|
case opc_aload_2: case opc_aload_3: |
|
|
|
instr.opcode = opc_iload + (opcode-opc_iload_0)/4; |
|
|
|
instr.opcode = opc_iload + (opcode-opc_iload_0)/4; |
|
|
|
instr.localSlot = (opcode-opc_iload_0) & 3; |
|
|
|
instr.localSlot = (opcode-opc_iload_0) & 3; |
|
|
|
|
|
|
|
if (instr.localSlot >= maxLocals) |
|
|
|
|
|
|
|
throw new ClassFormatError |
|
|
|
|
|
|
|
("Invalid local slot "+instr.localSlot); |
|
|
|
instr.length = 1; |
|
|
|
instr.length = 1; |
|
|
|
break; |
|
|
|
break; |
|
|
|
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: |
|
|
|
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_0: case opc_fstore_1: |
|
|
|
case opc_fstore_2: case opc_fstore_3: |
|
|
|
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_0: case opc_astore_1: |
|
|
|
case opc_astore_2: case opc_astore_3: |
|
|
|
case opc_astore_2: case opc_astore_3: |
|
|
|
instr.opcode = opc_istore + (opcode-opc_istore_0)/4; |
|
|
|
instr.opcode = opc_istore + (opcode-opc_istore_0)/4; |
|
|
|
instr.localSlot = (opcode-opc_istore_0) & 3; |
|
|
|
instr.localSlot = (opcode-opc_istore_0) & 3; |
|
|
|
|
|
|
|
if (instr.localSlot >= maxLocals) |
|
|
|
|
|
|
|
throw new ClassFormatError |
|
|
|
|
|
|
|
("Invalid local slot "+instr.localSlot); |
|
|
|
instr.length = 1; |
|
|
|
instr.length = 1; |
|
|
|
break; |
|
|
|
break; |
|
|
|
case opc_iload: case opc_lload: |
|
|
|
case opc_lstore_0: case opc_lstore_1: |
|
|
|
case opc_fload: case opc_dload: case opc_aload: |
|
|
|
case opc_lstore_2: case opc_lstore_3: |
|
|
|
case opc_istore: case opc_lstore: |
|
|
|
case opc_dstore_0: case opc_dstore_1: |
|
|
|
case opc_fstore: case opc_dstore: case opc_astore: |
|
|
|
case opc_dstore_2: case opc_dstore_3: |
|
|
|
|
|
|
|
instr.opcode = opc_istore + (opcode-opc_istore_0)/4; |
|
|
|
|
|
|
|
instr.localSlot = (opcode-opc_istore_0) & 3; |
|
|
|
|
|
|
|
if (instr.localSlot >= maxLocals-1) |
|
|
|
|
|
|
|
throw new ClassFormatError |
|
|
|
|
|
|
|
("Invalid local slot "+instr.localSlot); |
|
|
|
|
|
|
|
instr.length = 1; |
|
|
|
|
|
|
|
break; |
|
|
|
|
|
|
|
case opc_iload: case opc_fload: case opc_aload: |
|
|
|
|
|
|
|
case opc_istore: case opc_fstore: case opc_astore: |
|
|
|
|
|
|
|
instr.localSlot = input.readUnsignedByte(); |
|
|
|
|
|
|
|
if (instr.localSlot >= maxLocals) |
|
|
|
|
|
|
|
throw new ClassFormatError |
|
|
|
|
|
|
|
("Invalid local slot "+instr.localSlot); |
|
|
|
|
|
|
|
instr.length = 2; |
|
|
|
|
|
|
|
if (Decompiler.isDebugging)/*XXX*/ |
|
|
|
|
|
|
|
Decompiler.err.print(" "+instr.localSlot); |
|
|
|
|
|
|
|
break; |
|
|
|
|
|
|
|
case opc_lstore: case opc_dstore: |
|
|
|
|
|
|
|
case opc_lload: case opc_dload: |
|
|
|
instr.localSlot = input.readUnsignedByte(); |
|
|
|
instr.localSlot = input.readUnsignedByte(); |
|
|
|
|
|
|
|
if (instr.localSlot >= maxLocals - 1) |
|
|
|
|
|
|
|
throw new ClassFormatError |
|
|
|
|
|
|
|
("Invalid local slot "+instr.localSlot); |
|
|
|
instr.length = 2; |
|
|
|
instr.length = 2; |
|
|
|
if (Decompiler.isDebugging)/*XXX*/ |
|
|
|
if (Decompiler.isDebugging)/*XXX*/ |
|
|
|
Decompiler.err.print(" "+instr.localSlot); |
|
|
|
Decompiler.err.print(" "+instr.localSlot); |
|
|
@ -158,6 +201,9 @@ public class BytecodeInfo extends BinaryInfo implements Opcodes { |
|
|
|
|
|
|
|
|
|
|
|
case opc_ret: |
|
|
|
case opc_ret: |
|
|
|
instr.localSlot = input.readUnsignedByte(); |
|
|
|
instr.localSlot = input.readUnsignedByte(); |
|
|
|
|
|
|
|
if (instr.localSlot >= maxLocals) |
|
|
|
|
|
|
|
throw new ClassFormatError |
|
|
|
|
|
|
|
("Invalid local slot "+instr.localSlot); |
|
|
|
instr.alwaysJumps = true; |
|
|
|
instr.alwaysJumps = true; |
|
|
|
instr.length = 2; |
|
|
|
instr.length = 2; |
|
|
|
if (Decompiler.isDebugging)/*XXX*/ |
|
|
|
if (Decompiler.isDebugging)/*XXX*/ |
|
|
@ -189,20 +235,44 @@ public class BytecodeInfo extends BinaryInfo implements Opcodes { |
|
|
|
instr.objData = new Integer(input.readShort()); |
|
|
|
instr.objData = new Integer(input.readShort()); |
|
|
|
instr.length = 3; |
|
|
|
instr.length = 3; |
|
|
|
break; |
|
|
|
break; |
|
|
|
case opc_ldc: |
|
|
|
case opc_ldc: { |
|
|
|
instr.objData = cp.getConstant(input.readUnsignedByte()); |
|
|
|
int index = input.readUnsignedByte(); |
|
|
|
|
|
|
|
int tag = cp.getTag(index); |
|
|
|
|
|
|
|
if (tag != cp.STRING |
|
|
|
|
|
|
|
&& tag != cp.INTEGER && tag != cp.FLOAT) |
|
|
|
|
|
|
|
throw new ClassFormatException |
|
|
|
|
|
|
|
("wrong constant tag: "+tag); |
|
|
|
|
|
|
|
instr.objData = cp.getConstant(index); |
|
|
|
instr.length = 2; |
|
|
|
instr.length = 2; |
|
|
|
break; |
|
|
|
break; |
|
|
|
case opc_ldc_w: |
|
|
|
} |
|
|
|
|
|
|
|
case opc_ldc_w: { |
|
|
|
|
|
|
|
int index = input.readUnsignedShort(); |
|
|
|
|
|
|
|
int tag = cp.getTag(index); |
|
|
|
|
|
|
|
if (tag != cp.STRING |
|
|
|
|
|
|
|
&& tag != cp.INTEGER && tag != cp.FLOAT) |
|
|
|
|
|
|
|
throw new ClassFormatException |
|
|
|
|
|
|
|
("wrong constant tag: "+tag); |
|
|
|
instr.opcode = opc_ldc; |
|
|
|
instr.opcode = opc_ldc; |
|
|
|
/* fall through */ |
|
|
|
instr.objData = cp.getConstant(index); |
|
|
|
case opc_ldc2_w: |
|
|
|
|
|
|
|
instr.objData = cp.getConstant(input.readUnsignedShort()); |
|
|
|
|
|
|
|
instr.length = 3; |
|
|
|
instr.length = 3; |
|
|
|
break; |
|
|
|
break; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
case opc_ldc2_w: { |
|
|
|
|
|
|
|
int index = input.readUnsignedShort(); |
|
|
|
|
|
|
|
int tag = cp.getTag(index); |
|
|
|
|
|
|
|
if (tag != cp.LONG && tag != cp.DOUBLE) |
|
|
|
|
|
|
|
throw new ClassFormatException |
|
|
|
|
|
|
|
("wrong constant tag: "+tag); |
|
|
|
|
|
|
|
instr.objData = cp.getConstant(index); |
|
|
|
|
|
|
|
instr.length = 3; |
|
|
|
|
|
|
|
break; |
|
|
|
|
|
|
|
} |
|
|
|
case opc_iinc: |
|
|
|
case opc_iinc: |
|
|
|
instr.localSlot = input.readUnsignedByte(); |
|
|
|
instr.localSlot = input.readUnsignedByte(); |
|
|
|
|
|
|
|
if (instr.localSlot >= maxLocals) |
|
|
|
|
|
|
|
throw new ClassFormatError |
|
|
|
|
|
|
|
("Invalid local slot "+instr.localSlot); |
|
|
|
instr.intData = input.readByte(); |
|
|
|
instr.intData = input.readByte(); |
|
|
|
instr.length = 3; |
|
|
|
instr.length = 3; |
|
|
|
if (Decompiler.isDebugging)/*XXX*/ |
|
|
|
if (Decompiler.isDebugging)/*XXX*/ |
|
|
@ -211,6 +281,7 @@ public class BytecodeInfo extends BinaryInfo implements Opcodes { |
|
|
|
break; |
|
|
|
break; |
|
|
|
|
|
|
|
|
|
|
|
case opc_goto: |
|
|
|
case opc_goto: |
|
|
|
|
|
|
|
case opc_jsr: |
|
|
|
instr.alwaysJumps = true; |
|
|
|
instr.alwaysJumps = true; |
|
|
|
/* fall through */ |
|
|
|
/* fall through */ |
|
|
|
case opc_ifeq: case opc_ifne: |
|
|
|
case opc_ifeq: case opc_ifne: |
|
|
@ -221,21 +292,21 @@ public class BytecodeInfo extends BinaryInfo implements Opcodes { |
|
|
|
case opc_if_icmpgt: case opc_if_icmple: |
|
|
|
case opc_if_icmpgt: case opc_if_icmple: |
|
|
|
case opc_if_acmpeq: case opc_if_acmpne: |
|
|
|
case opc_if_acmpeq: case opc_if_acmpne: |
|
|
|
case opc_ifnull: case opc_ifnonnull: |
|
|
|
case opc_ifnull: case opc_ifnonnull: |
|
|
|
case opc_jsr: |
|
|
|
|
|
|
|
succAddrs[addr] = new int[1]; |
|
|
|
succAddrs[addr] = new int[1]; |
|
|
|
succAddrs[addr][0] = addr+input.readShort(); |
|
|
|
succAddrs[addr][0] = addr+input.readShort(); |
|
|
|
|
|
|
|
predcounts[succAddrs[addr][0]]++; |
|
|
|
instr.length = 3; |
|
|
|
instr.length = 3; |
|
|
|
if (Decompiler.isDebugging)/*XXX*/ |
|
|
|
if (Decompiler.isDebugging)/*XXX*/ |
|
|
|
Decompiler.err.print(" "+succAddrs[addr][0]); |
|
|
|
Decompiler.err.print(" "+succAddrs[addr][0]); |
|
|
|
break; |
|
|
|
break; |
|
|
|
|
|
|
|
|
|
|
|
case opc_goto_w: |
|
|
|
case opc_goto_w: |
|
|
|
instr.alwaysJumps = true; |
|
|
|
|
|
|
|
/* fall through */ |
|
|
|
|
|
|
|
case opc_jsr_w: |
|
|
|
case opc_jsr_w: |
|
|
|
|
|
|
|
instr.alwaysJumps = true; |
|
|
|
instr.opcode -= opc_goto_w - opc_goto; |
|
|
|
instr.opcode -= opc_goto_w - opc_goto; |
|
|
|
succAddrs[addr] = new int[1]; |
|
|
|
succAddrs[addr] = new int[1]; |
|
|
|
succAddrs[addr][0] = addr+input.readInt(); |
|
|
|
succAddrs[addr][0] = addr+input.readInt(); |
|
|
|
|
|
|
|
predcounts[succAddrs[addr][0]]++; |
|
|
|
instr.length = 5; |
|
|
|
instr.length = 5; |
|
|
|
if (Decompiler.isDebugging)/*XXX*/ |
|
|
|
if (Decompiler.isDebugging)/*XXX*/ |
|
|
|
Decompiler.err.print(" "+succAddrs[addr][0]); |
|
|
|
Decompiler.err.print(" "+succAddrs[addr][0]); |
|
|
@ -251,8 +322,10 @@ public class BytecodeInfo extends BinaryInfo implements Opcodes { |
|
|
|
succAddrs[addr] = new int[high-low+2]; |
|
|
|
succAddrs[addr] = new int[high-low+2]; |
|
|
|
for (int i=0; i+low <= high; i++) { |
|
|
|
for (int i=0; i+low <= high; i++) { |
|
|
|
succAddrs[addr][i] = addr + input.readInt(); |
|
|
|
succAddrs[addr][i] = addr + input.readInt(); |
|
|
|
|
|
|
|
predcounts[succAddrs[addr][i]]++; |
|
|
|
} |
|
|
|
} |
|
|
|
succAddrs[addr][high-low+1] = addr + def; |
|
|
|
succAddrs[addr][high-low+1] = addr + def; |
|
|
|
|
|
|
|
predcounts[addr + def]++; |
|
|
|
instr.alwaysJumps = true; |
|
|
|
instr.alwaysJumps = true; |
|
|
|
instr.length = length + 13 + 4 * (high-low+1); |
|
|
|
instr.length = length + 13 + 4 * (high-low+1); |
|
|
|
break; |
|
|
|
break; |
|
|
@ -267,8 +340,10 @@ public class BytecodeInfo extends BinaryInfo implements Opcodes { |
|
|
|
for (int i=0; i < npairs; i++) { |
|
|
|
for (int i=0; i < npairs; i++) { |
|
|
|
values[i] = input.readInt(); |
|
|
|
values[i] = input.readInt(); |
|
|
|
succAddrs[addr][i] = addr + input.readInt(); |
|
|
|
succAddrs[addr][i] = addr + input.readInt(); |
|
|
|
|
|
|
|
predcounts[succAddrs[addr][i]]++; |
|
|
|
} |
|
|
|
} |
|
|
|
succAddrs[addr][npairs] = addr + def; |
|
|
|
succAddrs[addr][npairs] = addr + def; |
|
|
|
|
|
|
|
predcounts[addr + def]++; |
|
|
|
instr.objData = values; |
|
|
|
instr.objData = values; |
|
|
|
instr.alwaysJumps = true; |
|
|
|
instr.alwaysJumps = true; |
|
|
|
instr.length = length + 9 + 8 * npairs; |
|
|
|
instr.length = length + 9 + 8 * npairs; |
|
|
@ -290,7 +365,23 @@ public class BytecodeInfo extends BinaryInfo implements Opcodes { |
|
|
|
case opc_invokespecial: |
|
|
|
case opc_invokespecial: |
|
|
|
case opc_invokestatic: |
|
|
|
case opc_invokestatic: |
|
|
|
case opc_invokevirtual: { |
|
|
|
case opc_invokevirtual: { |
|
|
|
Reference ref = cp.getRef(input.readUnsignedShort()); |
|
|
|
int index = input.readUnsignedShort(); |
|
|
|
|
|
|
|
int tag = cp.getTag(index); |
|
|
|
|
|
|
|
if (instr.opcode < opc_invokevirtual) { |
|
|
|
|
|
|
|
if (tag != cp.FIELDREF) |
|
|
|
|
|
|
|
throw new ClassFormatException |
|
|
|
|
|
|
|
("field tag mismatch: "+tag); |
|
|
|
|
|
|
|
} else { |
|
|
|
|
|
|
|
if (tag != cp.METHODREF) |
|
|
|
|
|
|
|
throw new ClassFormatException |
|
|
|
|
|
|
|
("method tag mismatch: "+tag); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
Reference ref = cp.getRef(index); |
|
|
|
|
|
|
|
if (ref.getName().charAt(0) == '<' |
|
|
|
|
|
|
|
&& (!ref.getName().equals("<init>") |
|
|
|
|
|
|
|
|| opcode != opc_invokespecial)) |
|
|
|
|
|
|
|
throw new ClassFormatException |
|
|
|
|
|
|
|
("Illegal call of special method/field "+ref); |
|
|
|
if (Decompiler.isDebugging)/*XXX*/ |
|
|
|
if (Decompiler.isDebugging)/*XXX*/ |
|
|
|
Decompiler.err.print(" "+ref); |
|
|
|
Decompiler.err.print(" "+ref); |
|
|
|
instr.objData = ref; |
|
|
|
instr.objData = ref; |
|
|
@ -298,33 +389,73 @@ public class BytecodeInfo extends BinaryInfo implements Opcodes { |
|
|
|
break; |
|
|
|
break; |
|
|
|
} |
|
|
|
} |
|
|
|
case opc_invokeinterface: { |
|
|
|
case opc_invokeinterface: { |
|
|
|
Reference ref = cp.getRef(input.readUnsignedShort()); |
|
|
|
int index = input.readUnsignedShort(); |
|
|
|
|
|
|
|
int tag = cp.getTag(index); |
|
|
|
|
|
|
|
if (tag != cp.INTERFACEMETHODREF) |
|
|
|
|
|
|
|
throw new ClassFormatException |
|
|
|
|
|
|
|
("interface tag mismatch: "+tag); |
|
|
|
|
|
|
|
Reference ref = cp.getRef(index); |
|
|
|
|
|
|
|
if (ref.getName().charAt(0) == '<') |
|
|
|
|
|
|
|
throw new ClassFormatException |
|
|
|
|
|
|
|
("Illegal call of special method "+ref); |
|
|
|
if (Decompiler.isDebugging)/*XXX*/ |
|
|
|
if (Decompiler.isDebugging)/*XXX*/ |
|
|
|
Decompiler.err.print(" "+ref); |
|
|
|
Decompiler.err.print(" "+ref); |
|
|
|
instr.objData = ref; |
|
|
|
instr.objData = ref; |
|
|
|
instr.intData = input.readUnsignedShort(); |
|
|
|
instr.intData = input.readUnsignedByte(); |
|
|
|
|
|
|
|
if (input.readUnsignedByte() != 0) |
|
|
|
|
|
|
|
throw new ClassFormatException |
|
|
|
|
|
|
|
("Illegal call of special method "+ref); |
|
|
|
|
|
|
|
|
|
|
|
instr.length = 5; |
|
|
|
instr.length = 5; |
|
|
|
break; |
|
|
|
break; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
case opc_new: |
|
|
|
case opc_new: |
|
|
|
case opc_anewarray: |
|
|
|
|
|
|
|
case opc_checkcast: |
|
|
|
case opc_checkcast: |
|
|
|
case opc_instanceof: |
|
|
|
case opc_instanceof: |
|
|
|
instr.objData = cp.getClassName(input.readUnsignedShort()) |
|
|
|
instr.objData = cp.getClassName(input.readUnsignedShort()) |
|
|
|
.replace('/','.'); |
|
|
|
.replace('/','.'); |
|
|
|
|
|
|
|
if (Decompiler.isDebugging)/*XXX*/ |
|
|
|
|
|
|
|
Decompiler.err.print(" "+instr.objData); |
|
|
|
instr.length = 3; |
|
|
|
instr.length = 3; |
|
|
|
break; |
|
|
|
break; |
|
|
|
case opc_multianewarray: |
|
|
|
case opc_multianewarray: |
|
|
|
instr.objData = cp.getClassName(input.readUnsignedShort()) |
|
|
|
instr.objData = cp.getClassName(input.readUnsignedShort()); |
|
|
|
.replace('/','.'); |
|
|
|
|
|
|
|
instr.intData = input.readUnsignedByte(); |
|
|
|
instr.intData = input.readUnsignedByte(); |
|
|
|
|
|
|
|
for (int i=0; i<instr.intData; i++) |
|
|
|
|
|
|
|
if (((String)instr.objData).charAt(i) != '[') |
|
|
|
|
|
|
|
throw new ClassFormatException |
|
|
|
|
|
|
|
("multianewarray called for non array:" |
|
|
|
|
|
|
|
+ instr.getDescription()); |
|
|
|
|
|
|
|
if (Decompiler.isDebugging)/*XXX*/ |
|
|
|
|
|
|
|
Decompiler.err.print(" "+instr.objData |
|
|
|
|
|
|
|
+" "+instr.intData); |
|
|
|
instr.length = 4; |
|
|
|
instr.length = 4; |
|
|
|
break; |
|
|
|
break; |
|
|
|
case opc_newarray: |
|
|
|
case opc_anewarray: { |
|
|
|
instr.intData = input.readUnsignedByte(); |
|
|
|
String type = cp.getClassName(input.readUnsignedShort()); |
|
|
|
|
|
|
|
instr.opcode = opc_multianewarray; |
|
|
|
|
|
|
|
if (type.charAt(0) == '[') |
|
|
|
|
|
|
|
instr.objData = "["+type; |
|
|
|
|
|
|
|
else |
|
|
|
|
|
|
|
instr.objData = "[L" + type + ';'; |
|
|
|
|
|
|
|
if (Decompiler.isDebugging)/*XXX*/ |
|
|
|
|
|
|
|
Decompiler.err.print(" "+instr.objData); |
|
|
|
|
|
|
|
instr.intData = 1; |
|
|
|
|
|
|
|
instr.length = 3; |
|
|
|
|
|
|
|
break; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
case opc_newarray: { |
|
|
|
|
|
|
|
char sig = newArrayTypes.charAt |
|
|
|
|
|
|
|
(input.readUnsignedByte()-4); |
|
|
|
|
|
|
|
instr.opcode = opc_multianewarray; |
|
|
|
|
|
|
|
instr.objData = new String (new char[] { '[', sig }); |
|
|
|
|
|
|
|
if (Decompiler.isDebugging)/*XXX*/ |
|
|
|
|
|
|
|
Decompiler.err.print(" "+instr.objData); |
|
|
|
|
|
|
|
instr.intData = 1; |
|
|
|
instr.length = 2; |
|
|
|
instr.length = 2; |
|
|
|
break; |
|
|
|
break; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
default: |
|
|
|
default: |
|
|
|
if (opcode == opc_xxxunusedxxx |
|
|
|
if (opcode == opc_xxxunusedxxx |
|
|
@ -346,15 +477,14 @@ public class BytecodeInfo extends BinaryInfo implements Opcodes { |
|
|
|
int length = succAddrs[addr].length; |
|
|
|
int length = succAddrs[addr].length; |
|
|
|
instr.succs = new Instruction[length]; |
|
|
|
instr.succs = new Instruction[length]; |
|
|
|
for (int i=0; i < length; i++) { |
|
|
|
for (int i=0; i < length; i++) { |
|
|
|
instr.succs[i] = instrs[succAddrs[addr][i]]; |
|
|
|
int succAddr = succAddrs[addr][i]; |
|
|
|
instr.succs[i].preds.addElement(instr); |
|
|
|
instr.succs[i] = instrs[succAddr]; |
|
|
|
|
|
|
|
if (instr.succs[i].preds == null) |
|
|
|
|
|
|
|
instr.succs[i].preds |
|
|
|
|
|
|
|
= new Instruction[predcounts[succAddr]]; |
|
|
|
|
|
|
|
instr.succs[i].preds[--predcounts[succAddr]] = instr; |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
/* YES, if the last instruction is not reachable it may |
|
|
|
|
|
|
|
* not alwaysJump. This happens under jikes |
|
|
|
|
|
|
|
*/ |
|
|
|
|
|
|
|
if (!instr.alwaysJumps && instr.nextByAddr != null) |
|
|
|
|
|
|
|
instr.nextByAddr.preds.addElement(instr); |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
succAddrs = null; |
|
|
|
succAddrs = null; |
|
|
|
|
|
|
|
|
|
|
@ -380,21 +510,27 @@ public class BytecodeInfo extends BinaryInfo implements Opcodes { |
|
|
|
public void dumpCode(java.io.PrintStream output) { |
|
|
|
public void dumpCode(java.io.PrintStream output) { |
|
|
|
for (Instruction instr = firstInstr; |
|
|
|
for (Instruction instr = firstInstr; |
|
|
|
instr != null; instr = instr.nextByAddr) { |
|
|
|
instr != null; instr = instr.nextByAddr) { |
|
|
|
output.println(instr+ ": " + opcodeString[instr.opcode]); |
|
|
|
output.println(instr.getDescription() + " " |
|
|
|
|
|
|
|
+ Integer.toHexString(hashCode())); |
|
|
|
if (instr.succs != null) { |
|
|
|
if (instr.succs != null) { |
|
|
|
output.print("\tsuccs: "+instr.succs[0]); |
|
|
|
output.print("\tsuccs: "+instr.succs[0]); |
|
|
|
for (int i = 1; i < instr.succs.length; i++) |
|
|
|
for (int i = 1; i < instr.succs.length; i++) |
|
|
|
output.print(", "+instr.succs[i]); |
|
|
|
output.print(", "+instr.succs[i]); |
|
|
|
output.println(); |
|
|
|
output.println(); |
|
|
|
} |
|
|
|
} |
|
|
|
if (instr.preds.size() > 0) { |
|
|
|
if (instr.preds != null) { |
|
|
|
Enumeration enum = instr.preds.elements(); |
|
|
|
output.print("\tpreds: " + instr.preds[0]); |
|
|
|
output.print("\tpreds: " + enum.nextElement()); |
|
|
|
for (int i=1; i < instr.preds.length; i++) |
|
|
|
while (enum.hasMoreElements()) |
|
|
|
output.print(", " + instr.preds[i]); |
|
|
|
output.print(", " + enum.nextElement()); |
|
|
|
|
|
|
|
output.println(); |
|
|
|
output.println(); |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
for (int i=0; i< exceptionHandlers.length; i++) { |
|
|
|
|
|
|
|
output.println("catch " + exceptionHandlers[i].type |
|
|
|
|
|
|
|
+ " from " + exceptionHandlers[i].start |
|
|
|
|
|
|
|
+ " to " + exceptionHandlers[i].end |
|
|
|
|
|
|
|
+ " catcher " + exceptionHandlers[i].catcher); |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
public void prepareWriting(GrowableConstantPool gcp) { |
|
|
|
public void prepareWriting(GrowableConstantPool gcp) { |
|
|
@ -407,13 +543,11 @@ public class BytecodeInfo extends BinaryInfo implements Opcodes { |
|
|
|
if (instr.opcode == opc_ldc |
|
|
|
if (instr.opcode == opc_ldc |
|
|
|
|| instr.opcode == opc_ldc2_w) { |
|
|
|
|| instr.opcode == opc_ldc2_w) { |
|
|
|
if (instr.objData == null) { |
|
|
|
if (instr.objData == null) { |
|
|
|
instr.opcode = opc_aconst_null; |
|
|
|
|
|
|
|
instr.length = 1; |
|
|
|
instr.length = 1; |
|
|
|
continue next_instr; |
|
|
|
continue next_instr; |
|
|
|
} |
|
|
|
} |
|
|
|
for (int i=1; i < constants.length; i++) { |
|
|
|
for (int i=1; i < constants.length; i++) { |
|
|
|
if (instr.objData.equals(constants[i])) { |
|
|
|
if (instr.objData.equals(constants[i])) { |
|
|
|
instr.opcode = opc_aconst_null+i; |
|
|
|
|
|
|
|
instr.length = 1; |
|
|
|
instr.length = 1; |
|
|
|
continue next_instr; |
|
|
|
continue next_instr; |
|
|
|
} |
|
|
|
} |
|
|
@ -426,21 +560,17 @@ public class BytecodeInfo extends BinaryInfo implements Opcodes { |
|
|
|
int value = ((Integer) instr.objData).intValue(); |
|
|
|
int value = ((Integer) instr.objData).intValue(); |
|
|
|
if (value >= -Byte.MIN_VALUE |
|
|
|
if (value >= -Byte.MIN_VALUE |
|
|
|
&& value <= Byte.MAX_VALUE) { |
|
|
|
&& value <= Byte.MAX_VALUE) { |
|
|
|
instr.opcode = opc_bipush; |
|
|
|
|
|
|
|
instr.length = 2; |
|
|
|
instr.length = 2; |
|
|
|
continue; |
|
|
|
continue; |
|
|
|
} else if (value >= -Short.MIN_VALUE |
|
|
|
} else if (value >= -Short.MIN_VALUE |
|
|
|
&& value <= Short.MAX_VALUE) { |
|
|
|
&& value <= Short.MAX_VALUE) { |
|
|
|
instr.opcode = opc_bipush; |
|
|
|
|
|
|
|
instr.length = 2; |
|
|
|
instr.length = 2; |
|
|
|
continue; |
|
|
|
continue; |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
if (gcp.reserveConstant(instr.objData) < 256) { |
|
|
|
if (gcp.reserveConstant(instr.objData) < 256) { |
|
|
|
instr.opcode = opc_ldc; |
|
|
|
|
|
|
|
instr.length = 2; |
|
|
|
instr.length = 2; |
|
|
|
} else { |
|
|
|
} else { |
|
|
|
instr.opcode = opc_ldc_w; |
|
|
|
|
|
|
|
instr.length = 3; |
|
|
|
instr.length = 3; |
|
|
|
} |
|
|
|
} |
|
|
|
} else if (instr.localSlot != -1) { |
|
|
|
} else if (instr.localSlot != -1) { |
|
|
@ -472,6 +602,15 @@ public class BytecodeInfo extends BinaryInfo implements Opcodes { |
|
|
|
instr.length = 5; |
|
|
|
instr.length = 5; |
|
|
|
} else |
|
|
|
} else |
|
|
|
instr.length = 3; |
|
|
|
instr.length = 3; |
|
|
|
|
|
|
|
} else if (instr.opcode == opc_multianewarray |
|
|
|
|
|
|
|
&& instr.intData == 1) { |
|
|
|
|
|
|
|
String clazz = ((String) instr.objData).substring(1); |
|
|
|
|
|
|
|
if (newArrayTypes.indexOf(clazz.charAt(0)) |
|
|
|
|
|
|
|
!= -1) { |
|
|
|
|
|
|
|
instr.length = 2; |
|
|
|
|
|
|
|
} else { |
|
|
|
|
|
|
|
instr.length = 3; |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
codeLength = addr; |
|
|
|
codeLength = addr; |
|
|
@ -485,6 +624,7 @@ public class BytecodeInfo extends BinaryInfo implements Opcodes { |
|
|
|
output.writeInt(codeLength); |
|
|
|
output.writeInt(codeLength); |
|
|
|
for (Instruction instr = firstInstr; |
|
|
|
for (Instruction instr = firstInstr; |
|
|
|
instr != null; instr = instr.nextByAddr) { |
|
|
|
instr != null; instr = instr.nextByAddr) { |
|
|
|
|
|
|
|
switch_opc: |
|
|
|
switch (instr.opcode) { |
|
|
|
switch (instr.opcode) { |
|
|
|
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: |
|
|
@ -521,26 +661,46 @@ public class BytecodeInfo extends BinaryInfo implements Opcodes { |
|
|
|
break; |
|
|
|
break; |
|
|
|
|
|
|
|
|
|
|
|
case opc_ldc: |
|
|
|
case opc_ldc: |
|
|
|
output.writeByte(opc_ldc); |
|
|
|
|
|
|
|
output.writeByte(gcp.putConstant(instr.objData)); |
|
|
|
|
|
|
|
break; |
|
|
|
|
|
|
|
case opc_ldc_w: |
|
|
|
|
|
|
|
output.writeByte(opc_ldc_w); |
|
|
|
|
|
|
|
output.writeShort(gcp.putConstant(instr.objData)); |
|
|
|
|
|
|
|
break; |
|
|
|
|
|
|
|
case opc_ldc2_w: |
|
|
|
case opc_ldc2_w: |
|
|
|
output.writeByte(instr.opcode); |
|
|
|
if (instr.objData == null) { |
|
|
|
output.writeShort(gcp.putConstant(instr.objData)); |
|
|
|
output.writeByte(opc_aconst_null); |
|
|
|
break; |
|
|
|
instr.length = 1; |
|
|
|
case opc_bipush: |
|
|
|
break switch_opc; |
|
|
|
output.writeByte(instr.opcode); |
|
|
|
} |
|
|
|
output.writeByte(((Integer)instr.objData).intValue()); |
|
|
|
for (int i=1; i < constants.length; i++) { |
|
|
|
break; |
|
|
|
if (instr.objData.equals(constants[i])) { |
|
|
|
case opc_sipush: |
|
|
|
output.writeByte(opc_aconst_null + i); |
|
|
|
output.writeByte(instr.opcode); |
|
|
|
break switch_opc; |
|
|
|
output.writeShort(((Integer)instr.objData).intValue()); |
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
if (instr.opcode == opc_ldc2_w) { |
|
|
|
|
|
|
|
output.writeByte(instr.opcode); |
|
|
|
|
|
|
|
output.writeShort(gcp.putLongConstant(instr.objData)); |
|
|
|
|
|
|
|
} else { |
|
|
|
|
|
|
|
if (instr.objData instanceof Integer) { |
|
|
|
|
|
|
|
int value = ((Integer) instr.objData).intValue(); |
|
|
|
|
|
|
|
if (value >= -Byte.MIN_VALUE |
|
|
|
|
|
|
|
&& value <= Byte.MAX_VALUE) { |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
output.writeByte(instr.opcode); |
|
|
|
|
|
|
|
output.writeByte(((Integer)instr.objData) |
|
|
|
|
|
|
|
.intValue()); |
|
|
|
|
|
|
|
} else if (value >= -Short.MIN_VALUE |
|
|
|
|
|
|
|
&& value <= Short.MAX_VALUE) { |
|
|
|
|
|
|
|
output.writeByte(instr.opcode); |
|
|
|
|
|
|
|
output.writeShort(((Integer)instr.objData) |
|
|
|
|
|
|
|
.intValue()); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
if (instr.length == 2) { |
|
|
|
|
|
|
|
output.writeByte(opc_ldc); |
|
|
|
|
|
|
|
output.writeByte(gcp.putConstant(instr.objData)); |
|
|
|
|
|
|
|
} else { |
|
|
|
|
|
|
|
output.writeByte(opc_ldc_w); |
|
|
|
|
|
|
|
output.writeShort(gcp.putConstant(instr.objData)); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
break; |
|
|
|
break; |
|
|
|
|
|
|
|
|
|
|
|
case opc_iinc: |
|
|
|
case opc_iinc: |
|
|
|
if (instr.length == 3) { |
|
|
|
if (instr.length == 3) { |
|
|
|
output.writeByte(instr.opcode); |
|
|
|
output.writeByte(instr.opcode); |
|
|
@ -622,25 +782,36 @@ public class BytecodeInfo extends BinaryInfo implements Opcodes { |
|
|
|
if (instr.opcode == opc_invokeinterface) { |
|
|
|
if (instr.opcode == opc_invokeinterface) { |
|
|
|
output.writeShort(gcp.putRef(gcp.INTERFACEMETHODREF, |
|
|
|
output.writeShort(gcp.putRef(gcp.INTERFACEMETHODREF, |
|
|
|
(Reference) instr.objData)); |
|
|
|
(Reference) instr.objData)); |
|
|
|
output.writeShort(instr.intData); |
|
|
|
output.writeByte(instr.intData); |
|
|
|
|
|
|
|
output.writeByte(0); |
|
|
|
} else |
|
|
|
} else |
|
|
|
output.writeShort(gcp.putRef(gcp.METHODREF, |
|
|
|
output.writeShort(gcp.putRef(gcp.METHODREF, |
|
|
|
(Reference) instr.objData)); |
|
|
|
(Reference) instr.objData)); |
|
|
|
break; |
|
|
|
break; |
|
|
|
case opc_new: |
|
|
|
case opc_new: |
|
|
|
case opc_anewarray: |
|
|
|
|
|
|
|
case opc_checkcast: |
|
|
|
case opc_checkcast: |
|
|
|
case opc_instanceof: |
|
|
|
case opc_instanceof: |
|
|
|
case opc_multianewarray: |
|
|
|
|
|
|
|
output.writeByte(instr.opcode); |
|
|
|
output.writeByte(instr.opcode); |
|
|
|
output.writeShort(gcp.putClassRef((String) instr.objData)); |
|
|
|
output.writeShort(gcp.putClassRef((String) instr.objData)); |
|
|
|
if (instr.opcode == opc_multianewarray) |
|
|
|
|
|
|
|
output.writeByte(instr.intData); |
|
|
|
|
|
|
|
break; |
|
|
|
break; |
|
|
|
|
|
|
|
case opc_multianewarray: |
|
|
|
case opc_newarray: |
|
|
|
if (instr.intData == 1) { |
|
|
|
output.writeByte(instr.opcode); |
|
|
|
String clazz = ((String) instr.objData).substring(1); |
|
|
|
output.writeByte(instr.intData); |
|
|
|
int index = newArrayTypes.indexOf(clazz.charAt(0)); |
|
|
|
|
|
|
|
if (index != -1) { |
|
|
|
|
|
|
|
output.writeByte(opc_newarray); |
|
|
|
|
|
|
|
output.writeByte(index + 4); |
|
|
|
|
|
|
|
} else { |
|
|
|
|
|
|
|
output.writeByte(opc_anewarray); |
|
|
|
|
|
|
|
if (clazz.charAt(0) == 'L') |
|
|
|
|
|
|
|
clazz = clazz.substring(1, clazz.indexOf(';')); |
|
|
|
|
|
|
|
output.writeShort(gcp.putClassRef(clazz)); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} else { |
|
|
|
|
|
|
|
output.writeByte(instr.opcode); |
|
|
|
|
|
|
|
output.writeShort(gcp.putClassRef((String) instr.objData)); |
|
|
|
|
|
|
|
output.writeByte(instr.intData); |
|
|
|
|
|
|
|
} |
|
|
|
break; |
|
|
|
break; |
|
|
|
|
|
|
|
|
|
|
|
default: |
|
|
|
default: |
|
|
|