diff --git a/FormatCLASS/src/main/java/org/freeinternals/format/classfile/Opcode.java b/FormatCLASS/src/main/java/org/freeinternals/format/classfile/Opcode.java index b023280..43ab09c 100755 --- a/FormatCLASS/src/main/java/org/freeinternals/format/classfile/Opcode.java +++ b/FormatCLASS/src/main/java/org/freeinternals/format/classfile/Opcode.java @@ -20,9 +20,8 @@ * * @author Amos Shi * @see - * - * VM Spec: The Java Virtual Machine Instruction Set - * + * VM + * Spec: The Java Virtual Machine Instruction Set */ public final class Opcode { @@ -37,6 +36,8 @@ public final class Opcode { private static final String FORMAT_OPCODE_LOCAL_IINC = "%s index = %d const = %d"; /** + * The Java Virtual Machine Instruction Set. + * * @see * * VM Spec: Instructions @@ -44,144 +45,1170 @@ public final class Opcode { */ public static enum Instruction { + /** + * Do nothing. + */ nop(0), + /** + * Push null. Push the null object reference onto the operand stack. + */ aconst_null(1), + /** + * Push int constant -1. + * + * An iconst_m1 instruction is type safe if one can validly push the + * type int onto the incoming operand stack yielding the outgoing type + * state. + * + * Push the int constant i (-1, 0, 1, 2, 3, 4 or 5) onto + * the operand stack. + */ iconst_m1(2), + /** + * Push int constant 0. + */ iconst_0(3), + /** + * Push int constant 1. + */ iconst_1(4), + /** + * Push int constant 2. + */ iconst_2(5), + /** + * Push int constant 3. + */ iconst_3(6), + /** + * Push int constant 4. + */ iconst_4(7), + /** + * Push int constant 5. + */ iconst_5(8), + /** + * Push long constant 0. + * + * Push the long constant l (0 or 1) onto the operand + * stack. + */ lconst_0(9), + /** + * Push long constant 1. + */ lconst_1(10), + /** + * Push float 0.0. + * + * Push the float constant f (0.0, 1.0, or 2.0) onto the + * operand stack. + */ fconst_0(11), + /** + * Push float 1.0. + */ fconst_1(12), + /** + * Push float 2.0. + */ fconst_2(13), + /** + * Push double 0.0. + * + * Push the double constant d (0.0 or 1.0) onto the operand + * stack. + */ dconst_0(14), + /** + * Push double 1.0. + */ dconst_1(15), - bipush(16), - sipush(17), - ldc(18), - ldc_w(19), - ldc2_w(20), - iload(21), - lload(22), - fload(23), - dload(24), - aload(25), + /** + * Push the immediate byte value. + * + * The immediate byte is sign-extended to an int value. That value is + * pushed onto the operand stack. + */ + bipush(16) { + @Override + protected InstructionParsed parse(final int curPos, final PosDataInputStream pdis) throws IOException { + int intermediateByteValue = pdis.readUnsignedByte(); + + InstructionParsed parsed = new InstructionParsed(curPos, this.code); + parsed.opCodeText = String.format(FORMAT_OPCODE_LOCAL, this.name(), intermediateByteValue); + return parsed; + } + }, + /** + * Push the immediate short value. + * + * The immediate unsigned byte1 and byte2 values are assembled into an + * intermediate short. + * + * The intermediate value is then sign-extended to an int value. That + * value is pushed onto the operand stack. + */ + sipush(17) { + @Override + protected InstructionParsed parse(final int curPos, final PosDataInputStream pdis) throws IOException { + int intermediateShortValue = pdis.readUnsignedShort(); + + InstructionParsed parsed = new InstructionParsed(curPos, this.code); + parsed.opCodeText = String.format(FORMAT_OPCODE_LOCAL, this.name(), intermediateShortValue); + return parsed; + } + }, + /** + * Push item from runtime constant pool. + * + * The index is an unsigned byte that must be a valid index into the + * runtime constant pool of the current class. + */ + ldc(18) { + @Override + protected InstructionParsed parse(final int curPos, final PosDataInputStream pdis) throws IOException { + InstructionParsed parsed = new InstructionParsed(curPos, this.code); + parsed.cpIndex = pdis.readUnsignedByte(); + parsed.opCodeText = this.name(); + return parsed; + } + }, + /** + * Push item from run-time constant pool (wide index). + * + * The unsigned indexbyte1 and indexbyte2 are assembled into an unsigned + * 16-bit index into the run-time constant pool of the current class. + * The index must be a valid index into the run-time constant pool of + * the current class. + */ + ldc_w(19) { + @Override + protected InstructionParsed parse(final int curPos, final PosDataInputStream pdis) throws IOException { + InstructionParsed parsed = new InstructionParsed(curPos, this.code); + parsed.cpIndex = pdis.readUnsignedShort(); + parsed.opCodeText = this.name(); + return parsed; + } + }, + /** + * Push long or double from runtime constant pool (wide index). + * + * The unsigned indexbyte1 and indexbyte2 are assembled into an unsigned + * 16-bit index into the run-time constant pool of the current class. + */ + ldc2_w(20) { + @Override + protected InstructionParsed parse(final int curPos, final PosDataInputStream pdis) throws IOException { + InstructionParsed parsed = new InstructionParsed(curPos, this.code); + parsed.cpIndex = pdis.readUnsignedShort(); + parsed.opCodeText = this.name(); + return parsed; + } + }, + /** + * Load int from local variable at index. + * + * The index is an unsigned byte that must be an index into + * the local variable array of the current frame. The local variable at + * index must contain an int. The value of the local variable at index + * is pushed onto the operand stack. + */ + iload(21) { + @Override + protected InstructionParsed parse(final int curPos, final PosDataInputStream pdis) throws IOException { + return super.parse_Lvindex_UnsignedByte(curPos, pdis); + } + }, + /** + * Load long from local variable at index. + * + * The index is an unsigned byte. Both index and index+1 + * must be indices into the local variable array of the current frame. + * The local variable at index must contain a long. The value of the + * local variable at index is pushed onto the operand stack. + */ + lload(22) { + @Override + protected InstructionParsed parse(final int curPos, final PosDataInputStream pdis) throws IOException { + return super.parse_Lvindex_UnsignedByte(curPos, pdis); + } + }, + /** + * Load float from local variable at index. + * + * The index is an unsigned byte that must be an index into + * the local variable array of the current frame. The local variable at + * index must contain a float. The value of the local variable at index + * is pushed onto the operand stack. + */ + fload(23) { + @Override + protected InstructionParsed parse(final int curPos, final PosDataInputStream pdis) throws IOException { + return super.parse_Lvindex_UnsignedByte(curPos, pdis); + } + }, + /** + * Load double from local variable at index. + * + * The index is an unsigned byte. Both index and index+1 + * must be indices into the local variable array of the current frame. + * The local variable at index must contain a double. The value of the + * local variable at index is pushed onto the operand stack. + */ + dload(24) { + @Override + protected InstructionParsed parse(final int curPos, final PosDataInputStream pdis) throws IOException { + return super.parse_Lvindex_UnsignedByte(curPos, pdis); + } + }, + /** + * Load reference from local variable at index. + * + * The index is an unsigned byte that must be an index into + * the local variable array of the current frame. The local variable at + * index must contain a reference. The objectref in the local variable + * at index is pushed onto the operand stack. + */ + aload(25) { + @Override + protected InstructionParsed parse(final int curPos, final PosDataInputStream pdis) throws IOException { + return super.parse_Lvindex_UnsignedByte(curPos, pdis); + } + }, + /** + * Load int from local variable at index 0. + * + * The n must be an index into the local variable array of + * the current frame. The local variable at n must contain + * an int. The value of the local variable at n is pushed + * onto the operand stack. + * + * @see #iload_1 + * @see #iload_2 + * @see #iload_3 + */ iload_0(26), + /** + * Load int from local variable at index 1. + * + * @see #iload_0 + */ iload_1(27), + /** + * Load int from local variable at index 2. + * + * @see #iload_0 + */ iload_2(28), + /** + * Load int from local variable at index 3. + * + * @see #iload_0 + */ iload_3(29), + /** + * Load long from local variable at index 0. + * + * Both n and n+1 must be indices into the + * local variable array of the current frame. The local variable at + * n must contain a long. The value of the local variable + * at n is pushed onto the operand stack. + * + * @see #lload_1 + * @see #lload_2 + * @see #lload_3 + */ lload_0(30), + /** + * Load long from local variable at index 1. + * + * @see #lload_0 + */ lload_1(31), + /** + * Load long from local variable at index 2. + * + * @see #lload_0 + */ lload_2(32), + /** + * Load long from local variable at index 3. + * + * @see #lload_0 + */ lload_3(33), + /** + * Load float from local variable at index 0. + * + * The n must be an index into the local variable array of + * the current frame. The local variable at n must contain + * a float. The value of the local variable at n is pushed + * onto the operand stack. + * + * @see #fload_1 + * @see #fload_2 + * @see #fload_3 + */ fload_0(34), + /** + * Load float from local variable at index 1. + * + * @see #fload_0 + */ fload_1(35), + /** + * Load float from local variable at index 2. + * + * @see #fload_0 + */ fload_2(36), + /** + * Load float from local variable at index 3. + * + * @see #fload_0 + */ fload_3(37), + /** + * Load double from local variable at index 0. + * + * Both n and n+1 must be indices into the + * local variable array of the current frame. The local variable at + * n must contain a double. The value of the local variable + * at n is pushed onto the operand stack. + * + * @see #dload_1 + * @see #dload_2 + * @see #dload_3 + */ dload_0(38), + /** + * Load double from local variable at index 1. + * + * @see #dload_0 + */ dload_1(39), + /** + * Load double from local variable at index 2. + * + * @see #dload_0 + */ dload_2(40), + /** + * Load double from local variable at index 3. + * + * @see #dload_0 + */ dload_3(41), + /** + * Load reference from local variable at index 0. + * + * The n must be an index into the local variable array of + * the current frame. The local variable at n must contain + * a reference. The objectref in the local variable at n is + * pushed onto the operand stack. + * + * @see #aload_1 + * @see #aload_2 + * @see #aload_3 + */ aload_0(42), + /** + * Load reference from local variable at index 1. + * + * @see #aload_0 + */ aload_1(43), + /** + * Load reference from local variable at index 2. + * + * @see #aload_0 + */ aload_2(44), + /** + * Load reference from local variable at index 3. + * + * @see #aload_0 + */ aload_3(45), + /** + * Load int from array. + * + * The arrayref must be of type reference and must refer to an array + * whose components are of type int. The index must be of type int. Both + * arrayref and index are popped from the operand stack. The int value + * in the component of the array at index is retrieved and pushed onto + * the operand stack. + */ iaload(46), + /** + * Load long from array. + * + * The arrayref must be of type reference and must refer to an array + * whose components are of type long. The index must be of type int. + * Both arrayref and index are popped from the operand stack. The long + * value in the component of the array at index is retrieved and pushed + * onto the operand stack. + */ laload(47), + /** + * Load float from array. + * + * The arrayref must be of type reference and must refer to an array + * whose components are of type float. The index must be of type int. + * Both arrayref and index are popped from the operand stack. The float + * value in the component of the array at index is retrieved and pushed + * onto the operand stack. + */ faload(48), + /** + * Load double from array. + * + * The arrayref must be of type reference and must refer to an array + * whose components are of type double. The index must be of type int. + * Both arrayref and index are popped from the operand stack. The double + * value in the component of the array at index is retrieved and pushed + * onto the operand stack. + */ daload(49), + /** + * Load reference from array. + * + * The arrayref must be of type reference and must refer to an array + * whose components are of type reference. The index must be of type + * int. Both arrayref and index are popped from the operand stack. The + * reference value in the component of the array at index is retrieved + * and pushed onto the operand stack. + */ aaload(50), + /** + * Load byte or boolean from array. + * + * The arrayref must be of type reference and must refer to an array + * whose components are of type reference. The index must be of type + * int. Both arrayref and index are popped from the operand stack. The + * reference value in the component of the array at index is retrieved + * and pushed onto the operand stack. + */ baload(51), + /** + * Load char from array. + * + * The arrayref must be of type reference and must refer to an array + * whose components are of type byte or of type boolean. The index must + * be of type int. Both arrayref and index are popped from the operand + * stack. The byte value in the component of the array at index is + * retrieved, sign-extended to an int value, and pushed onto the top of + * the operand stack. + */ caload(52), + /** + * Load short from array. + * + * The arrayref must be of type reference and must refer to an array + * whose components are of type short. The index must be of type int. + * Both arrayref and index are popped from the operand stack. The + * component of the array at index is retrieved and sign-extended to an + * int value. That value is pushed onto the operand stack. + */ saload(53), - istore(54), - lstore(55), - fstore(56), - dstore(57), - astore(58), + /** + * Store int into local variable at index. + * + * The index is an unsigned byte that must be an index into + * the local variable array of the current frame. The value on the top + * of the operand stack must be of type int. It is popped from the + * operand stack, and the value of the local variable at index is set to + * value. + */ + istore(54) { + @Override + protected InstructionParsed parse(final int curPos, final PosDataInputStream pdis) throws IOException { + return super.parse_Lvindex_UnsignedByte(curPos, pdis); + } + }, + /** + * Store long into local variable at index. + * + * The index is an unsigned byte. Both index + * and index+1 must be indices into the local variable + * array of the current frame. The value on the top of the operand stack + * must be of type long. It is popped from the operand stack, and the + * local variables at index and index+1 are + * set to value. + */ + lstore(55) { + @Override + protected InstructionParsed parse(final int curPos, final PosDataInputStream pdis) throws IOException { + return super.parse_Lvindex_UnsignedByte(curPos, pdis); + } + }, + /** + * Store float into local variable at index. + * + * The index is an unsigned byte that must be an index into + * the local variable array of the current frame. The value on the top + * of the operand stack must be of type float. It is popped from the + * operand stack and undergoes value set conversion, resulting in value. + * The value of the local variable at index is set to value. + */ + fstore(56) { + @Override + protected InstructionParsed parse(final int curPos, final PosDataInputStream pdis) throws IOException { + return super.parse_Lvindex_UnsignedByte(curPos, pdis); + } + }, + /** + * Store double into local variable at index. + * + * The index is an unsigned byte. Both index + * and index+1 must be indices into the local variable + * array of the current frame. The value on the top of the operand stack + * must be of type double. It is popped from the operand stack and + * undergoes value set conversion, resulting in value. The local + * variables at index and index+1 are set to + * value. + */ + dstore(57) { + @Override + protected InstructionParsed parse(final int curPos, final PosDataInputStream pdis) throws IOException { + return super.parse_Lvindex_UnsignedByte(curPos, pdis); + } + }, + /** + * Store reference into local variable at index. + * + * The index is an unsigned byte that must be an index into + * the local variable array of the current frame. The objectref on the + * top of the operand stack must be of type returnAddress or of type + * reference. It is popped from the operand stack, and the value of the + * local variable at index is set to objectref. + */ + astore(58) { + @Override + protected InstructionParsed parse(final int curPos, final PosDataInputStream pdis) throws IOException { + return super.parse_Lvindex_UnsignedByte(curPos, pdis); + } + }, + /** + * Store int into local variable at index 0. + * + * The n must be an index into the local variable array of + * the current frame. The value on the top of the operand stack must be + * of type int. It is popped from the operand stack, and the value of + * the local variable at n is set to value. + * + * @see #istore_1 + * @see #istore_2 + * @see #istore_3 + */ istore_0(59), + /** + * Store int into local variable at index 1. + * + * @see #istore_0 + */ istore_1(60), + /** + * Store int into local variable at index 2. + * + * @see #istore_0 + */ istore_2(61), + /** + * Store int into local variable at index 3. + * + * @see #istore_0 + */ istore_3(62), + /** + * Store long into local variable at index 0. + * + * Both n and n+1 must be indices into the + * local variable array of the current frame. The value on the top of + * the operand stack must be of type long. It is popped from the operand + * stack, and the local variables at n and n+1 + * are set to value. + * + * @see #lstore_1 + * @see #lstore_2 + * @see #lstore_3 + */ lstore_0(63), + /** + * Store long into local variable at index 1. + * + * @see #lstore_0 + */ lstore_1(64), + /** + * Store long into local variable at index 2. + * + * @see #lstore_0 + */ lstore_2(65), + /** + * Store long into local variable at index 3. + * + * @see #lstore_0 + */ lstore_3(66), + /** + * Store float into local variable at index 0. + * + * The n must be an index into the local variable array of + * the current frame. The value on the top of the operand stack must be + * of type float. It is popped from the operand stack and undergoes + * value set conversion, resulting in value. The value of the local + * variable at n is set to value. + * + * @see #fstore_1 + * @see #fstore_2 + * @see #fstore_3 + */ fstore_0(67), + /** + * Store float into local variable at index 1. + * + * @see #fstore_0 + */ fstore_1(68), + /** + * Store float into local variable at index 2. + * + * @see #fstore_0 + */ fstore_2(69), + /** + * Store float into local variable at index 3. + * + * @see #fstore_0 + */ fstore_3(70), + /** + * Store double into local variable at index 0. + * + * Both n and n+1 must be indices into the + * local variable array of the current frame. The value on the top of + * the operand stack must be of type double. It is popped from the + * operand stack and undergoes value set conversion, resulting in value. + * The local variables at n and n+1are set to + * value. + * + * @see #dstore_1 + * @see #dstore_2 + * @see #dstore_3 + */ dstore_0(71), + /** + * Store double into local variable at index 1. + * + * @see #dstore_0 + */ dstore_1(72), + /** + * Store double into local variable at index 2. + * + * @see #dstore_0 + */ dstore_2(73), + /** + * Store double into local variable at index 3. + * + * @see #dstore_0 + */ dstore_3(74), + /** + * Store reference into local variable at index 0. + * + * The n must be an index into the local variable array of + * the current frame. The objectref on the top of the operand stack must + * be of type returnAddress or of type reference. It is popped from the + * operand stack, and the value of the local variable at n + * is set to objectref. + * + * @see #astore_1 + * @see #astore_2 + * @see #astore_3 + */ astore_0(75), + /** + * Store reference into local variable at index 1. + * + * @see #astore_0 + */ astore_1(76), + /** + * Store reference into local variable at index 2. + * + * @see #astore_0 + */ astore_2(77), + /** + * Store reference into local variable at index 3. + * + * @see #astore_0 + */ astore_3(78), + /** + * Store into int array in current Operand Stack + * ..., arrayref, index, value. + * + * The arrayref must be of type reference and must refer to + * an array whose components are of type int. Both index and value must + * be of type int. The arrayref, index, and + * value are popped from the operand stack. The int value + * is stored as the component of the array indexed by index. + */ iastore(79), + /** + * Store into long array in current Operand Stack + * ..., arrayref, index, value. + */ lastore(80), + /** + * Store into float array in current Operand Stack + * ..., arrayref, index, value. + */ fastore(81), + /** + * Store into double array in current Operand Stack + * ..., arrayref, index, value. + */ dastore(82), + /** + * Store into reference array in current Operand Stack + * ..., arrayref, index, value. + */ aastore(83), + /** + * Store into byte or boolean array in current Operand Stack + * ..., arrayref, index, value. + */ bastore(84), + /** + * Store into char array in current Operand Stack + * ..., arrayref, index, value. + */ castore(85), + /** + * Store into short array in current Operand Stack + * ..., arrayref, index, value. + */ sastore(86), + /** + * Pop the top value from the operand stack. + */ pop(87), + /** + * Pop the top one or two values from the operand stack. + */ pop2(88), + /** + * Duplicate the top value on the operand stack and push the duplicated + * value onto the operand stack. + */ dup(89), + /** + * Duplicate the top value on the operand stack and insert the + * duplicated value two values down in the operand stack. + */ dup_x1(90), + /** + * Duplicate the top value on the operand stack and insert the + * duplicated value two or three values down in the operand stack. + */ dup_x2(91), + /** + * Duplicate the top one or two values on the operand stack and push the + * duplicated value or values back onto the operand stack in the + * original order. + */ dup2(92), + /** + * Duplicate the top one or two values on the operand stack and insert + * the duplicated values, in the original order, one value beneath the + * original value or values in the operand stack. + */ dup2_x1(93), + /** + * Duplicate the top one or two values on the operand stack and insert + * the duplicated values, in the original order, into the operand stack. + */ dup2_x2(94), + /** + * Swap the top two values on the operand stack. + */ swap(95), + /** + * Add int in current Operand Stack ..., value1, value2. + * + * Both value1 and value2 must be of type int. The values are popped + * from the operand stack. The int result is value1 + value2. The result + * is pushed onto the operand stack. + * + * @see #ladd + * @see #fadd + * @see #dadd + */ iadd(96), + /** + * Add long in current Operand Stack ..., value1, value2. + * + * @see #iadd + */ ladd(97), + /** + * Add float in current Operand Stack ..., value1, value2. + * + * @see #iadd + */ fadd(98), + /** + * Add double in current Operand Stack ..., value1, value2. + * + * @see #iadd + */ dadd(99), + /** + * Subtract int in current Operand Stack + * ..., value1, value2. + * + * Both value1 and value2 must be of type int. The values are popped + * from the operand stack. The int result is value1 - value2. The result + * is pushed onto the operand stack. + * + * @see #lsub + * @see #fsub + * @see #dsub + */ isub(100), + /** + * Subtract long in current Operand Stack + * ..., value1, value2. + * + * Both value1 and value2 must be of type long. The values are popped + * from the operand stack. The long result is value1 - value2. The + * result is pushed onto the operand stack. + * + * @see #isub + */ lsub(101), + /** + * Subtract float. + * + * @see #isub + */ fsub(102), + /** + * Subtract double. + * + * @see #isub + */ dsub(103), + /** + * Multiply int in current Operand Stack + * ..., value1, value2. + * + * Both value1 and value2 must be of type int. The values are popped + * from the operand stack. The int result is value1 * value2. The result + * is pushed onto the operand stack. + * + * @see #lmul + * @see #fmul + * @see #dmul + */ imul(104), + /** + * Multiply long. + * + * @see #imul + */ lmul(105), + /** + * Multiply float. + * + * @see #imul + */ fmul(106), + /** + * Multiply double. + * + * @see #imul + */ dmul(107), + /** + * Divide int in current Operand Stack ..., value1, value2. + * + * Both value1 and value2 must be of type int. The values are popped + * from the operand stack. The int result is the value of the Java + * programming language expression value1 / value2. The result is pushed + * onto the operand stack. + * + * @see #ldiv + * @see #fdiv + * @see #ddiv + */ idiv(108), + /** + * Divide long. + * + * @see #idiv + */ ldiv(109), + /** + * Divide float. + * + * @see #idiv + */ fdiv(110), + /** + * Divide double. + * + * @see #idiv + */ ddiv(111), + /** + * Remainder int in current Operand Stack + * ..., value1, value2. + * + * Both value1 and value2 must be of type int. The values are popped + * from the operand stack. The int result is + * value1 - (value1 / value2) * value2. The result is + * pushed onto the operand stack. + * + * @see #lrem + * @see #frem + * @see #drem + */ irem(112), + /** + * Remainder long. + * + * @see #irem + */ lrem(113), + /** + * Remainder float. + * + * @see #irem + */ frem(114), + /** + * Remainder double. + * + * @see #irem + */ drem(115), + /** + * Negate int in current Operand Stack ..., value. + * + * The value must be of type int. It is popped from the operand stack. + * The int result is the arithmetic negation of value, + * -value. The result is pushed onto the operand stack. + * + * @see #lneg + * @see #fneg + * @see #dneg + */ ineg(116), + /** + * Negate long. + * + * @see #ineg + */ lneg(117), + /** + * Negate float. + * + * @see #ineg + */ fneg(118), + /** + * Negate double. + * + * @see #ineg + */ dneg(119), + /** + * Shift left int in current Operand Stack + * ..., value1, value2. + * + * Both value1 and value2 must be of type int. The values are popped + * from the operand stack. An int result is calculated by shifting + * value1 left by s bit positions, where s is the value of the low 5 + * bits of value2. The result is pushed onto the operand stack. + * + * @see #lshl + */ ishl(120), + /** + * Shift left long. + * + * @see #ishl + */ lshl(121), + /** + * Arithmetic shift right int, in current Operand Stack + * ..., value1, value2. + * + * Both value1 and value2 must be of type int. The values are popped + * from the operand stack. An int result is calculated by shifting + * value1 right by s bit positions, with sign extension, where s is the + * value of the low 5 bits of value2. The result is pushed onto the + * operand stack. + * + * @see #lshr + */ ishr(122), + /** + * Arithmetic shift right long. + * + * @see #ishr + */ lshr(123), + /** + * Logical shift right int, in current Operand Stack + * ..., value1, value2. + * + * Both value1 and value2 must be of type int. The values are popped + * from the operand stack. An int result is calculated by shifting + * value1 right by s bit positions, with zero extension, where s is the + * value of the low 5 bits of value2. The result is pushed onto the + * operand stack. + * + * @see #lushr + */ iushr(124), + /** + * Logical shift right long. + * + * @see #iushr + */ lushr(125), + /** + * Boolean AND int, in current Operand Stack + * ..., value1, value2. + * + * Both value1 and value2 must be of type int. They are popped from the + * operand stack. An int result is calculated by taking the bitwise AND + * (conjunction) of value1 and value2. The result is pushed onto the + * operand stack. + * + * @see #land + */ iand(126), + /** + * Boolean AND long. + * + * @see #iand + */ land(127), + /** + * Boolean OR int, in current Operand Stack + * ..., value1, value2. + * + * Both value1 and value2 must be of type int. They are popped from the + * operand stack. An int result is calculated by taking the bitwise + * inclusive OR of value1 and value2. The result is pushed onto the + * operand stack. + * + * @see #lor + */ ior(128), + /** + * Boolean OR long. + * + * @see #ior + */ lor(129), + /** + * Boolean XOR int, in current Operand Stack + * ..., value1, value2. + * + * Both value1 and value2 must be of type int. They are popped from the + * operand stack. An int result is calculated by taking the bitwise + * exclusive OR of value1 and value2. The result is pushed onto the + * operand stack. + * + * @see #lxor + */ ixor(130), + /** + * Boolean XOR long. + * + * @see #ixor + */ lxor(131), - iinc(132), + /** + * Increment local variable by constant. + * + * The index is an unsigned byte that must be an index into the local + * variable array of the current frame. The const is an immediate signed + * byte. The local variable at index must contain an int. The value + * const is first sign-extended to an int, and then the local variable + * at index is incremented by that amount. + */ + iinc(132) { + @Override + protected InstructionParsed parse(final int curPos, final PosDataInputStream pdis) throws IOException { + InstructionParsed parsed = new InstructionParsed(curPos, this.code); + parsed.lvIndex = pdis.readUnsignedByte(); + int immediateSignedByteValue = pdis.readByte(); + parsed.opCodeText = String.format(FORMAT_OPCODE_LOCAL_IINC, this.name(), parsed.lvIndex, immediateSignedByteValue); + return parsed; + } + }, + /** + * Convert int to long, in current Operand Stack + * ..., value. + * + * The value on the top of the operand stack must be of type int. It is + * popped from the operand stack and sign-extended to a long result. + * That result is pushed onto the operand stack. + */ i2l(133), + /** + * Convert int to float. + * + * @see #i2l + */ i2f(134), + /** + * Convert int to double. + * + * @see #i2l + */ i2d(135), + /** + * Convert long to int, in current Operand Stack + * ..., value. + * + * The value on the top of the operand stack must be of type long. It is + * popped from the operand stack and converted to an int result by + * taking the low-order 32 bits of the long value and discarding the + * high-order 32 bits. The result is pushed onto the operand stack. + */ l2i(136), + /** + * Convert long to float, in current Operand Stack + * ..., value. + * + * The l2f instruction performs a widening primitive conversion that may + * lose precision because values of type float have only 24 significand + * bits. + */ l2f(137), + /** + * Convert long to double, in current Operand Stack + * ..., value. + * + * The value on the top of the operand stack must be of type long. It is + * popped from the operand stack and converted to a double result using + * IEEE 754 round to nearest mode. The result is pushed onto the operand + * stack. + */ l2d(138), f2i(139), f2l(140), @@ -197,23 +1224,121 @@ public static enum Instruction { fcmpg(150), dcmpl(151), dcmpg(152), - ifeq(153), - ifne(154), - iflt(155), - ifge(156), - ifgt(157), - ifle(158), - if_icmpeq(159), - if_icmpne(160), - if_icmplt(161), - if_icmpge(162), - if_icmpgt(163), - if_icmple(164), - if_acmpeq(165), - if_acmpne(166), - /** Note: Add '_' suffix to avoid compile error since 'goto' is a Java keyword, remove the '_' from the name when showing. */ - goto_(167), - jsr(168), + /** + * Branch if int comparison with zero succeeds. + * + * ifeq succeeds if and only if value = 0. + */ + ifeq(153) { + @Override + protected InstructionParsed parse(final int curPos, final PosDataInputStream pdis) throws IOException { + return super.parse_Branchbyte_Short(curPos, pdis); + } + }, + ifne(154) { + @Override + protected InstructionParsed parse(final int curPos, final PosDataInputStream pdis) throws IOException { + return super.parse_Branchbyte_Short(curPos, pdis); + } + }, + iflt(155) { + @Override + protected InstructionParsed parse(final int curPos, final PosDataInputStream pdis) throws IOException { + return super.parse_Branchbyte_Short(curPos, pdis); + } + }, + ifge(156) { + @Override + protected InstructionParsed parse(final int curPos, final PosDataInputStream pdis) throws IOException { + return super.parse_Branchbyte_Short(curPos, pdis); + } + }, + ifgt(157) { + @Override + protected InstructionParsed parse(final int curPos, final PosDataInputStream pdis) throws IOException { + return super.parse_Branchbyte_Short(curPos, pdis); + } + }, + ifle(158) { + @Override + protected InstructionParsed parse(final int curPos, final PosDataInputStream pdis) throws IOException { + return super.parse_Branchbyte_Short(curPos, pdis); + } + }, + if_icmpeq(159) { + @Override + protected InstructionParsed parse(final int curPos, final PosDataInputStream pdis) throws IOException { + return super.parse_Branchbyte_Short(curPos, pdis); + } + }, + if_icmpne(160) { + @Override + protected InstructionParsed parse(final int curPos, final PosDataInputStream pdis) throws IOException { + return super.parse_Branchbyte_Short(curPos, pdis); + } + }, + if_icmplt(161) { + @Override + protected InstructionParsed parse(final int curPos, final PosDataInputStream pdis) throws IOException { + return super.parse_Branchbyte_Short(curPos, pdis); + } + }, + if_icmpge(162) { + @Override + protected InstructionParsed parse(final int curPos, final PosDataInputStream pdis) throws IOException { + return super.parse_Branchbyte_Short(curPos, pdis); + } + }, + if_icmpgt(163) { + @Override + protected InstructionParsed parse(final int curPos, final PosDataInputStream pdis) throws IOException { + return super.parse_Branchbyte_Short(curPos, pdis); + } + }, + if_icmple(164) { + @Override + protected InstructionParsed parse(final int curPos, final PosDataInputStream pdis) throws IOException { + return super.parse_Branchbyte_Short(curPos, pdis); + } + }, + if_acmpeq(165) { + @Override + protected InstructionParsed parse(final int curPos, final PosDataInputStream pdis) throws IOException { + return super.parse_Branchbyte_Short(curPos, pdis); + } + }, + if_acmpne(166) { + @Override + protected InstructionParsed parse(final int curPos, final PosDataInputStream pdis) throws IOException { + return super.parse_Branchbyte_Short(curPos, pdis); + } + }, + /** + * Branch always. + * + * Note: Add '_' suffix to avoid compile error since 'goto' is a Java + * keyword, remove the '_' from the name when showing. + * + * @see #getName() + */ + goto_(167) { + @Override + protected InstructionParsed parse(final int curPos, final PosDataInputStream pdis) throws IOException { + InstructionParsed parsed = new InstructionParsed(curPos, this.code); + parsed.branchbyte = Integer.valueOf(pdis.readShort()); + parsed.opCodeText = this.getName(); + return parsed; + } + }, + /** + * Jump subroutine. + */ + jsr(168){ + @Override + protected InstructionParsed parse(final int curPos, final PosDataInputStream pdis) throws IOException { + return super.parse_Branchbyte_Short(curPos, pdis); + } + }, ret(169), tableswitch(170), lookupswitch(171), @@ -222,7 +1347,10 @@ public static enum Instruction { freturn(174), dreturn(175), areturn(176), - /** Note: Add '_' suffix to avoid compile error since 'goto' is a Java keyword, remove the '_' from the name when showing. */ + /** + * Note: Add '_' suffix to avoid compile error since 'goto' is a Java + * keyword, remove the '_' from the name when showing. + */ return_(177), getstatic(178), putstatic(179), @@ -233,14 +1361,20 @@ public static enum Instruction { invokestatic(184), invokeinterface(185), invokedynamic(186), - /** Note: Add '_' suffix to avoid compile error since 'goto' is a Java keyword, remove the '_' from the name when showing. */ + /** + * Note: Add '_' suffix to avoid compile error since 'goto' is a Java + * keyword, remove the '_' from the name when showing. + */ new_(187), newarray(188), anewarray(189), arraylength(190), athrow(191), checkcast(192), - /** Note: Add '_' suffix to avoid compile error since 'goto' is a Java keyword, remove the '_' from the name when showing. */ + /** + * Note: Add '_' suffix to avoid compile error since 'goto' is a Java + * keyword, remove the '_' from the name when showing. + */ instanceof_(193), monitorenter(194), monitorexit(195), @@ -280,11 +1414,12 @@ public static enum Instruction { * {@link #instanceof_}. * * @return The postfix "_" from the name - * + * * @see #goto_ * @see #return_ * @see #new_ * @see #instanceof_ + * @see #reserved */ String getName() { String name = super.name(); @@ -325,6 +1460,28 @@ public static String getOpcodeName(int opcode) { return name; } + + protected InstructionParsed parse(final int curPos, final PosDataInputStream pdis) throws IOException { + InstructionParsed parsed = new InstructionParsed(curPos, this.code); + parsed.opCodeText = this.name(); + return parsed; + + } + + private InstructionParsed parse_Lvindex_UnsignedByte(final int curPos, final PosDataInputStream pdis) throws IOException { + InstructionParsed parsed = new InstructionParsed(curPos, this.code); + parsed.lvIndex = pdis.readUnsignedByte(); + parsed.opCodeText = String.format(FORMAT_OPCODE_LOCAL, this.name(), parsed.lvIndex); + return parsed; + } + + private InstructionParsed parse_Branchbyte_Short(final int curPos, final PosDataInputStream pdis) throws IOException { + InstructionParsed parsed = new InstructionParsed(curPos, this.code); + parsed.branchbyte = Integer.valueOf(pdis.readShort()); + parsed.opCodeText = this.name(); + return parsed; + } + } /** @@ -404,614 +1561,8 @@ private static InstructionParsed parseInstruction(final PosDataInputStream pdis) int byteValue; int immediateSignedByteValue; - int intermediateShortValue; if (Opcode.Instruction.nop.code == opcode) { - // Do nothing - result.opCodeText = Opcode.Instruction.nop.name(); - } else if (Opcode.Instruction.aconst_null.code == opcode) { - // Push null - // Push the null object reference onto the operand stack. - result.opCodeText = Opcode.Instruction.aconst_null.name(); - } else if (Opcode.Instruction.iconst_m1.code == opcode) { - // An iconst_m1 instruction is type safe if one can validly push the type int onto the incoming operand stack yielding the outgoing type state. - // Push int constant -1 - result.opCodeText = Opcode.Instruction.iconst_m1.name(); - } else if (Opcode.Instruction.iconst_0.code == opcode) { - // Push int constant - // Push the int constant (-1, 0, 1, 2, 3, 4 or 5) onto the operand stack. - result.opCodeText = Opcode.Instruction.iconst_0.name(); - } else if (Opcode.Instruction.iconst_1.code == opcode) { - result.opCodeText = Opcode.Instruction.iconst_1.name(); - } else if (Opcode.Instruction.iconst_2.code == opcode) { - result.opCodeText = Opcode.Instruction.iconst_2.name(); - } else if (Opcode.Instruction.iconst_3.code == opcode) { - result.opCodeText = Opcode.Instruction.iconst_3.name(); - } else if (Opcode.Instruction.iconst_4.code == opcode) { - result.opCodeText = Opcode.Instruction.iconst_4.name(); - } else if (Opcode.Instruction.iconst_5.code == opcode) { - result.opCodeText = Opcode.Instruction.iconst_5.name(); - } else if (Opcode.Instruction.lconst_0.code == opcode) { - // Push long constant - // Push the long constant (0 or 1) onto the operand stack. - result.opCodeText = Opcode.Instruction.lconst_0.name(); - } else if (Opcode.Instruction.lconst_1.code == opcode) { - result.opCodeText = Opcode.Instruction.lconst_1.name(); - } else if (Opcode.Instruction.fconst_0.code == opcode) { - // Push float - // Push the float constant (0.0, 1.0, or 2.0) onto the operand stack. - result.opCodeText = Opcode.Instruction.fconst_0.name(); - } else if (Opcode.Instruction.fconst_1.code == opcode) { - result.opCodeText = Opcode.Instruction.fconst_1.name(); - } else if (Opcode.Instruction.fconst_2.code == opcode) { - result.opCodeText = Opcode.Instruction.fconst_2.name(); - } else if (Opcode.Instruction.dconst_0.code == opcode) { - // Push double - // Push the double constant (0.0 or 1.0) onto the operand stack. - result.opCodeText = Opcode.Instruction.dconst_0.name(); - } else if (Opcode.Instruction.bipush.code == opcode) { - // Push the immediate byte value - // -- - // The immediate byte is sign-extended to an int value. - // That value is pushed onto the operand stack. - byteValue = pdis.readUnsignedByte(); - result.opCodeText = String.format(FORMAT_OPCODE_LOCAL, Opcode.Instruction.bipush.name(), byteValue); - } else if (Opcode.Instruction.sipush.code == opcode) { - // Push the immediate short value - // -- - // The immediate unsigned byte1 and byte2 values are assembled into an intermediate short - // where the value of the short is (byte1 << 8) | byte2. - // The intermediate value is then sign-extended to an int value. - // That value is pushed onto the operand stack. - intermediateShortValue = pdis.readUnsignedShort(); - result.opCodeText = String.format(FORMAT_OPCODE_LOCAL, Opcode.Instruction.sipush.name(), intermediateShortValue); - } else if (Opcode.Instruction.ldc.code == opcode) { - // Push item from runtime constant pool - // -- - // The index is an unsigned byte that must be a valid index into the runtime constant pool of the current class. - // The runtime constant pool entry at index - // either must be a runtime constant of type int or float, - // or must be a symbolic reference to a string literal (?.1). - result.cpIndex = pdis.readUnsignedByte(); - result.opCodeText = Opcode.Instruction.ldc.name(); - } else if (Opcode.Instruction.ldc_w.code == opcode) { - // Push item from runtime constant pool (wide index) - // -- - // The unsigned indexbyte1 and indexbyte2 are assembled into an unsigned 16-bit index - // into the runtime constant pool of the current class (?.6), - // where the value of the index is calculated as (indexbyte1 << 8) | indexbyte2. - // The index must be a valid index into the runtime constant pool of the current class. - // The runtime constant pool entry at the index - // either must be a runtime constant of type int or float, - // or must be a symbolic reference to a string literal (?.1). - - result.cpIndex = pdis.readUnsignedShort(); - result.opCodeText = Opcode.Instruction.ldc_w.name(); - - } else if (Opcode.Instruction.ldc2_w.code == opcode) { - // Push long or double from runtime constant pool (wide index) - // -- - // The unsigned indexbyte1 and indexbyte2 are assembled into an unsigned 16-bit index - // into the runtime constant pool of the current class (?.6), - // where the value of the index is calculated as (indexbyte1 << 8) | indexbyte2. - // The index must be a valid index into the runtime constant pool of the current class. - // The runtime constant pool entry at the index must be a runtime constant of type long or double (?.1). - // The numeric value of that runtime constant is pushed onto the operand stack as a long or double, respectively. - result.cpIndex = pdis.readUnsignedShort(); - result.opCodeText = Opcode.Instruction.ldc2_w.name(); - } else if (Opcode.Instruction.iload.code == opcode) { - // Load int from local variable - // -- - // The index is an unsigned byte that must be an index into the local variable array of the current frame. - // The local variable at index must contain an int. - // The value of the local variable at index is pushed onto the operand stack. - byteValue = pdis.readUnsignedByte(); - result.opCodeText = String.format(FORMAT_OPCODE_LOCAL, Opcode.Instruction.iload.name(), byteValue); - } else if (Opcode.Instruction.lload.code == opcode) { - // Load long from local variable - // -- - // The index is an unsigned byte. - // Both index and index + 1 must be indices into the local variable array of the current frame (2.6). - // The local variable at index must contain a long. - // The value of the local variable at index is pushed onto the operand stack. - byteValue = pdis.readUnsignedByte(); - result.opCodeText = String.format(FORMAT_OPCODE_LOCAL, Opcode.Instruction.lload.name(), byteValue); - } else if (Opcode.Instruction.fload.code == opcode) { - // Load float from local variable - // - - // The index is an unsigned byte that must be an index into the local variable array of the current frame (2.6). - // The local variable at index must contain a float. - // The value of the local variable at index is pushed onto the operand stack. - byteValue = pdis.readUnsignedByte(); - result.opCodeText = String.format(FORMAT_OPCODE_LOCAL, Opcode.Instruction.fload.name(), byteValue); - } else if (Opcode.Instruction.dload.code == opcode) { - // Load double from local variable - // - - // The index is an unsigned byte. - // Both index and index + 1 must be indices into the local variable array of the current frame (2.6). - // The local variable at index must contain a double. - // The value of the local variable at index is pushed onto the operand stack. - byteValue = pdis.readUnsignedByte(); - result.opCodeText = String.format(FORMAT_OPCODE_LOCAL, Opcode.Instruction.dload.name(), byteValue); - } else if (Opcode.Instruction.aload.code == opcode) { - // Load reference from local variable - // -- - // The index is an unsigned byte that must be an index into the local variable array of the current frame (2.6). - // The local variable at index must contain a reference. - // The objectref in the local variable at index is pushed onto the operand stack. - byteValue = pdis.readUnsignedByte(); - result.opCodeText = String.format(FORMAT_OPCODE_LOCAL, Opcode.Instruction.aload.name(), byteValue); - } else if (Opcode.Instruction.iload_0.code == opcode) { - // Load int from local variable - // The must be an index into the local variable array of the current frame (2.6). - // The local variable at must contain an int. - // The value of the local variable at is pushed onto the operand stack. - result.opCodeText = Opcode.Instruction.iload_0.name(); - } else if (Opcode.Instruction.iload_1.code == opcode) { - result.opCodeText = Opcode.Instruction.iload_1.name(); - } else if (Opcode.Instruction.iload_2.code == opcode) { - result.opCodeText = Opcode.Instruction.iload_2.name(); - } else if (Opcode.Instruction.iload_3.code == opcode) { - result.opCodeText = Opcode.Instruction.iload_3.name(); - } else if (Opcode.Instruction.lload_0.code == opcode) { - // Load long from local variable - // Both and + 1 must be indices into the local variable array of the current frame (2.6). - // The local variable at must contain a long. - // The value of the local variable at is pushed onto the operand stack. - result.opCodeText = Opcode.Instruction.lload_0.name(); - } else if (Opcode.Instruction.lload_1.code == opcode) { - result.opCodeText = Opcode.Instruction.lload_1.name(); - } else if (Opcode.Instruction.lload_2.code == opcode) { - result.opCodeText = Opcode.Instruction.lload_2.name(); - } else if (Opcode.Instruction.lload_3.code == opcode) { - result.opCodeText = Opcode.Instruction.lload_3.name(); - } else if (Opcode.Instruction.fload_0.code == opcode) { - // Load float from local variable - // The must be an index into the local variable array of the current frame (2.6). - // The local variable at must contain a float. - // The value of the local variable at is pushed onto the operand stack. - result.opCodeText = Opcode.Instruction.fload_0.name(); - } else if (Opcode.Instruction.fload_1.code == opcode) { - result.opCodeText = Opcode.Instruction.fload_1.name(); - } else if (Opcode.Instruction.fload_2.code == opcode) { - result.opCodeText = Opcode.Instruction.fload_2.name(); - } else if (Opcode.Instruction.fload_3.code == opcode) { - result.opCodeText = Opcode.Instruction.fload_3.name(); - } else if (Opcode.Instruction.dload_0.code == opcode) { - // Load double from local variable - // Both and + 1 must be indices into the local variable array of the current frame (2.6). - // The local variable at must contain a double. - // The value of the local variable at is pushed onto the operand stack. - result.opCodeText = Opcode.Instruction.dload_0.name(); - } else if (Opcode.Instruction.dload_1.code == opcode) { - result.opCodeText = Opcode.Instruction.dload_1.name(); - } else if (Opcode.Instruction.dload_2.code == opcode) { - result.opCodeText = Opcode.Instruction.dload_2.name(); - } else if (Opcode.Instruction.dload_3.code == opcode) { - result.opCodeText = Opcode.Instruction.dload_3.name(); - } else if (Opcode.Instruction.aload_0.code == opcode) { - // Load reference from local variable - // The must be an index into the local variable array of the current frame (2.6). - // The local variable at must contain a reference. - // The objectref in the local variable at index is pushed onto the operand stack. - result.opCodeText = Opcode.Instruction.aload_0.name(); - } else if (Opcode.Instruction.aload_1.code == opcode) { - result.opCodeText = Opcode.Instruction.aload_1.name(); - } else if (Opcode.Instruction.aload_2.code == opcode) { - result.opCodeText = Opcode.Instruction.aload_2.name(); - } else if (Opcode.Instruction.aload_3.code == opcode) { - result.opCodeText = Opcode.Instruction.aload_3.name(); - } else if (Opcode.Instruction.iaload.code == opcode) { - // Load int from array - // The arrayref must be of type reference and must refer to an array - // whose components are of type int. - // The index must be of type int. - // Both arrayref and index are popped from the operand stack. - // The int value in the component of the array at index is retrieved and pushed onto the operand stack. - result.opCodeText = Opcode.Instruction.iaload.name(); - } else if (Opcode.Instruction.laload.code == opcode) { - // Load long from array - result.opCodeText = Opcode.Instruction.laload.name(); - } else if (Opcode.Instruction.faload.code == opcode) { - // Load float from array - result.opCodeText = Opcode.Instruction.faload.name(); - } else if (Opcode.Instruction.daload.code == opcode) { - // Load double from array - result.opCodeText = Opcode.Instruction.daload.name(); - } else if (Opcode.Instruction.aaload.code == opcode) { - // Load reference from array - result.opCodeText = Opcode.Instruction.aaload.name(); - } else if (Opcode.Instruction.baload.code == opcode) { - // Load byte or boolean from array - result.opCodeText = Opcode.Instruction.baload.name(); - } else if (Opcode.Instruction.caload.code == opcode) { - // Load char from array - result.opCodeText = Opcode.Instruction.caload.name(); - } else if (Opcode.Instruction.saload.code == opcode) { - // Load short from array - result.opCodeText = Opcode.Instruction.saload.name(); - } else if (Opcode.Instruction.istore.code == opcode) { - // Store int into local variable - // -- - // The index is an unsigned byte that must be an index into the local variable array of the current frame (2.6). - // The value on the top of the operand stack must be of type int. - // It is popped from the operand stack, and the value of the local variable at index is set to value. - byteValue = pdis.readUnsignedByte(); - result.opCodeText = String.format(FORMAT_OPCODE_LOCAL, Opcode.Instruction.istore.name(), byteValue); - } else if (Opcode.Instruction.lstore.code == opcode) { - // Store long into local variable - // -- - // The index is an unsigned byte. - // Both index and index + 1 must be indices into the local variable array of the current frame (2.6). - // The value on the top of the operand stack must be of type long. - // It is popped from the operand stack, and the local variables at index and index + 1 are set to value. - byteValue = pdis.readUnsignedByte(); - result.opCodeText = String.format(FORMAT_OPCODE_LOCAL, Opcode.Instruction.lstore.name(), byteValue); - } else if (Opcode.Instruction.fstore.code == opcode) { - // Store float into local variable - // The index is an unsigned byte that must be an index into the local variable array of the current frame (2.6). - // The value on the top of the operand stack must be of type float. - // It is popped from the operand stack and undergoes value set conversion (?.8.3), resulting in value'. - // The value of the local variable at index is set to value'. - byteValue = pdis.readUnsignedByte(); - result.opCodeText = String.format(FORMAT_OPCODE_LOCAL, Opcode.Instruction.fstore.name(), byteValue); - } else if (Opcode.Instruction.dstore.code == opcode) { - // Store double into local variable - // The index is an unsigned byte. Both index and index + 1 must be indices into the local variable array of the current frame (2.6). - // The value on the top of the operand stack must be of type double. - // It is popped from the operand stack and undergoes value set conversion (?.8.3), resulting in value'. - // The local variables at index and index + 1 are set to value'. - byteValue = pdis.readUnsignedByte(); - result.opCodeText = String.format(FORMAT_OPCODE_LOCAL, Opcode.Instruction.dstore.name(), byteValue); - } else if (Opcode.Instruction.astore.code == opcode) { - // Store reference into local variable - // The index is an unsigned byte that must be an index into the local variable array of the current frame (2.6). - // The objectref on the top of the operand stack must be of type returnAddress or of type reference. - // It is popped from the operand stack, and the value of the local variable at index is set to objectref. - byteValue = pdis.readUnsignedByte(); - result.opCodeText = String.format(FORMAT_OPCODE_LOCAL, Opcode.Instruction.astore.name(), byteValue); - } else if (Opcode.Instruction.istore_0.code == opcode) { - // Store int into local variable - // The must be an index into the local variable array of the current frame (?.6). - // The value on the top of the operand stack must be of type int. - // It is popped from the operand stack, and the value of the local variable at is set to value. - result.opCodeText = Opcode.Instruction.istore_0.name(); - } else if (Opcode.Instruction.istore_1.code == opcode) { - result.opCodeText = Opcode.Instruction.istore_1.name(); - } else if (Opcode.Instruction.istore_2.code == opcode) { - result.opCodeText = Opcode.Instruction.istore_2.name(); - } else if (Opcode.Instruction.istore_3.code == opcode) { - result.opCodeText = Opcode.Instruction.istore_3.name(); - } else if (Opcode.Instruction.lstore_0.code == opcode) { - // Store long into local variable - // Both and + 1 must be indices into the local variable array of the current frame (?.6). - // The value on the top of the operand stack must be of type long. - // It is popped from the operand stack, and the local variables at and + 1 are set to value. - result.opCodeText = Opcode.Instruction.lstore_0.name(); - } else if (Opcode.Instruction.lstore_1.code == opcode) { - result.opCodeText = Opcode.Instruction.lstore_1.name(); - } else if (Opcode.Instruction.lstore_2.code == opcode) { - result.opCodeText = Opcode.Instruction.lstore_2.name(); - } else if (Opcode.Instruction.lstore_3.code == opcode) { - result.opCodeText = Opcode.Instruction.lstore_3.name(); - } else if (Opcode.Instruction.fstore_0.code == opcode) { - // Store float into local variable - // The must be an index into the local variable array of the current frame (?.6). - // The value on the top of the operand stack must be of type float. - // It is popped from the operand stack and undergoes value set conversion (?.8.3), resulting in value'. - // The value of the local variable at is set to value'. - result.opCodeText = Opcode.Instruction.fstore_0.name(); - } else if (Opcode.Instruction.fstore_1.code == opcode) { - result.opCodeText = Opcode.Instruction.fstore_1.name(); - } else if (Opcode.Instruction.fstore_2.code == opcode) { - result.opCodeText = Opcode.Instruction.fstore_2.name(); - } else if (Opcode.Instruction.fstore_3.code == opcode) { - result.opCodeText = Opcode.Instruction.fstore_3.name(); - } else if (Opcode.Instruction.dstore_0.code == opcode) { - // Store double into local variable - // Both and + 1 must be indices into the local variable array of the current frame (?.6). - // The value on the top of the operand stack must be of type double. - // It is popped from the operand stack and undergoes value set conversion (?.8.3), resulting in value'. - // The local variables at and + 1 are set to value'. - result.opCodeText = Opcode.Instruction.dstore_0.name(); - } else if (Opcode.Instruction.dstore_1.code == opcode) { - result.opCodeText = Opcode.Instruction.dstore_1.name(); - } else if (Opcode.Instruction.dstore_2.code == opcode) { - result.opCodeText = Opcode.Instruction.dstore_2.name(); - } else if (Opcode.Instruction.dstore_3.code == opcode) { - result.opCodeText = Opcode.Instruction.dstore_3.name(); - } else if (Opcode.Instruction.astore_0.code == opcode) { - // Store reference into local variable - // The must be an index into the local variable array of the current frame (?.6). - // The objectref on the top of the operand stack must be of type returnAddress or of type reference. - // It is popped from the operand stack, and the value of the local variable at is set to objectref. - result.opCodeText = Opcode.Instruction.astore_0.name(); - } else if (Opcode.Instruction.astore_1.code == opcode) { - result.opCodeText = Opcode.Instruction.astore_1.name(); - } else if (Opcode.Instruction.astore_2.code == opcode) { - result.opCodeText = Opcode.Instruction.astore_2.name(); - } else if (Opcode.Instruction.astore_3.code == opcode) { - result.opCodeText = Opcode.Instruction.astore_3.name(); - } else if (Opcode.Instruction.iastore.code == opcode) { - // Store into int array - // ..., arrayref, index, value - // The arrayref must be of type reference and must refer to an array whose components are of type int. - // Both index and value must be of type int. - // The arrayref, index, and value are popped from the operand stack. - // The int value is stored as the component of the array indexed by index. - result.opCodeText = Opcode.Instruction.iastore.name(); - } else if (Opcode.Instruction.lastore.code == opcode) { - // Store into long array - // ..., arrayref, index, value - result.opCodeText = Opcode.Instruction.lastore.name(); - } else if (Opcode.Instruction.fastore.code == opcode) { - // Store into float array - // ..., arrayref, index, value - result.opCodeText = Opcode.Instruction.fastore.name(); - } else if (Opcode.Instruction.dastore.code == opcode) { - // Store into double array - // ..., arrayref, index, value - result.opCodeText = Opcode.Instruction.dastore.name(); - } else if (Opcode.Instruction.aastore.code == opcode) { - // Store into reference array - // ..., arrayref, index, value - // ** Very complex, see the for detail - result.opCodeText = Opcode.Instruction.aastore.name(); - } else if (Opcode.Instruction.bastore.code == opcode) { - // Store into byte or boolean array - // ..., arrayref, index, value - result.opCodeText = Opcode.Instruction.bastore.name(); - } else if (Opcode.Instruction.castore.code == opcode) { - // Store into char array - // ..., arrayref, index, value - result.opCodeText = Opcode.Instruction.castore.name(); - } else if (Opcode.Instruction.sastore.code == opcode) { - // Store into short array - // ..., arrayref, index, value - result.opCodeText = Opcode.Instruction.sastore.name(); - } else if (Opcode.Instruction.pop.code == opcode) { - // Pop the top operand stack value - // The pop instruction must not be used unless value is a value of a category 1 computational type (?.11.1). - result.opCodeText = Opcode.Instruction.pop.name(); - } else if (Opcode.Instruction.pop2.code == opcode) { - // Pop the top one or two operand stack values - // Form 1: ..., value2, value1 - // where each of value1 and value2 is a value of a category 1 computational type (?.11.1). - // Form 2: ..., value - // where value is a value of a category 2 computational type (?.11.1). - result.opCodeText = Opcode.Instruction.pop2.name(); - } else if (Opcode.Instruction.dup.code == opcode) { - // Duplicate the top operand stack value - // ..., value --> ..., value, value - result.opCodeText = Opcode.Instruction.dup.name(); - } else if (Opcode.Instruction.dup_x1.code == opcode) { - // Duplicate the top operand stack value and insert two values down - // ..., value2, value1 --> ..., value1, value2, value1 - // ** Very complex, see the for detail - result.opCodeText = Opcode.Instruction.dup_x1.name(); - } else if (Opcode.Instruction.dup_x2.code == opcode) { - // Duplicate the top operand stack value and insert two or three values down - // Form 1: ..., value3, value2, value1 --> ..., value1, value3, value2, value1 - // Form 2: ..., value2, value1 --> ..., value1, value2, value1 - // ** Very complex, see the for detail - result.opCodeText = Opcode.Instruction.dup_x2.name(); - } else if (Opcode.Instruction.dup2.code == opcode) { - // Duplicate the top one or two operand stack values - // ** Very complex, see the for detail - result.opCodeText = Opcode.Instruction.dup2.name(); - } else if (Opcode.Instruction.dup2_x1.code == opcode) { - // Duplicate the top one or two operand stack values and insert two or three values down - // ** Very complex, see the for detail - result.opCodeText = Opcode.Instruction.dup2_x1.name(); - } else if (Opcode.Instruction.dup2_x2.code == opcode) { - // Duplicate the top one or two operand stack values and insert two, three, or four values down - // ** Very complex, see the for detail - result.opCodeText = Opcode.Instruction.dup2_x2.name(); - } else if (Opcode.Instruction.swap.code == opcode) { - // Swap the top two operand stack values - // ..., value2, value1 --> ..., value1, value2 - // The swap instruction must not be used unless value1 and value2 are both values of a category 1 computational type (?.11.1). - result.opCodeText = Opcode.Instruction.swap.name(); - } else if (Opcode.Instruction.iadd.code == opcode) { - result.opCodeText = Opcode.Instruction.iadd.name(); - } else if (Opcode.Instruction.ladd.code == opcode) { - result.opCodeText = Opcode.Instruction.ladd.name(); - } else if (Opcode.Instruction.fadd.code == opcode) { - result.opCodeText = Opcode.Instruction.fadd.name(); - } else if (Opcode.Instruction.dadd.code == opcode) { - result.opCodeText = Opcode.Instruction.dadd.name(); - } else if (Opcode.Instruction.isub.code == opcode) { - result.opCodeText = Opcode.Instruction.isub.name(); - } else if (Opcode.Instruction.lsub.code == opcode) { - result.opCodeText = Opcode.Instruction.lsub.name(); - } else if (Opcode.Instruction.fsub.code == opcode) { - result.opCodeText = Opcode.Instruction.fsub.name(); - } else if (Opcode.Instruction.dsub.code == opcode) { - result.opCodeText = Opcode.Instruction.dsub.name(); - } else if (Opcode.Instruction.imul.code == opcode) { - result.opCodeText = Opcode.Instruction.imul.name(); - } else if (Opcode.Instruction.lmul.code == opcode) { - result.opCodeText = Opcode.Instruction.lmul.name(); - } else if (Opcode.Instruction.fmul.code == opcode) { - result.opCodeText = Opcode.Instruction.fmul.name(); - } else if (Opcode.Instruction.dmul.code == opcode) { - result.opCodeText = Opcode.Instruction.dmul.name(); - } else if (Opcode.Instruction.idiv.code == opcode) { - result.opCodeText = Opcode.Instruction.idiv.name(); - } else if (Opcode.Instruction.ldiv.code == opcode) { - result.opCodeText = Opcode.Instruction.ldiv.name(); - } else if (Opcode.Instruction.fdiv.code == opcode) { - result.opCodeText = Opcode.Instruction.fdiv.name(); - } else if (Opcode.Instruction.ddiv.code == opcode) { - result.opCodeText = Opcode.Instruction.ddiv.name(); - } else if (Opcode.Instruction.irem.code == opcode) { - result.opCodeText = Opcode.Instruction.irem.name(); - } else if (Opcode.Instruction.lrem.code == opcode) { - result.opCodeText = Opcode.Instruction.lrem.name(); - } else if (Opcode.Instruction.frem.code == opcode) { - result.opCodeText = Opcode.Instruction.frem.name(); - } else if (Opcode.Instruction.drem.code == opcode) { - result.opCodeText = Opcode.Instruction.drem.name(); - } else if (Opcode.Instruction.ineg.code == opcode) { - result.opCodeText = Opcode.Instruction.ineg.name(); - } else if (Opcode.Instruction.lneg.code == opcode) { - result.opCodeText = Opcode.Instruction.lneg.name(); - } else if (Opcode.Instruction.fneg.code == opcode) { - result.opCodeText = Opcode.Instruction.fneg.name(); - } else if (Opcode.Instruction.dneg.code == opcode) { - result.opCodeText = Opcode.Instruction.dneg.name(); - } else if (Opcode.Instruction.ishl.code == opcode) { - result.opCodeText = Opcode.Instruction.ishl.name(); - } else if (Opcode.Instruction.lshl.code == opcode) { - result.opCodeText = Opcode.Instruction.lshl.name(); - } else if (Opcode.Instruction.ishr.code == opcode) { - result.opCodeText = Opcode.Instruction.ishr.name(); - } else if (Opcode.Instruction.lshr.code == opcode) { - result.opCodeText = Opcode.Instruction.lshr.name(); - } else if (Opcode.Instruction.iushr.code == opcode) { - result.opCodeText = Opcode.Instruction.iushr.name(); - } else if (Opcode.Instruction.lushr.code == opcode) { - result.opCodeText = Opcode.Instruction.lushr.name(); - } else if (Opcode.Instruction.iand.code == opcode) { - result.opCodeText = Opcode.Instruction.iand.name(); - } else if (Opcode.Instruction.land.code == opcode) { - result.opCodeText = Opcode.Instruction.land.name(); - } else if (Opcode.Instruction.ior.code == opcode) { - result.opCodeText = Opcode.Instruction.ior.name(); - } else if (Opcode.Instruction.lor.code == opcode) { - result.opCodeText = Opcode.Instruction.lor.name(); - } else if (Opcode.Instruction.ixor.code == opcode) { - result.opCodeText = Opcode.Instruction.ixor.name(); - } else if (Opcode.Instruction.lxor.code == opcode) { - result.opCodeText = Opcode.Instruction.lxor.name(); - } else if (Opcode.Instruction.iinc.code == opcode) { - // Increment local variable by constant - // -- - // The index is an unsigned byte that must be an index into the local variable array of the current frame (?.6). - // The local variable at index must contain an int. - byteValue = pdis.readUnsignedByte(); - // The const is an immediate signed byte. - // The value const is first sign-extended to an int, and then the local variable at index is incremented by that amount. - immediateSignedByteValue = pdis.readByte(); - result.opCodeText = String.format(FORMAT_OPCODE_LOCAL_IINC, Opcode.Instruction.iinc.name(), byteValue, immediateSignedByteValue); - } else if (Opcode.Instruction.i2l.code == opcode) { - result.opCodeText = Opcode.Instruction.i2l.name(); - } else if (Opcode.Instruction.i2f.code == opcode) { - result.opCodeText = Opcode.Instruction.i2f.name(); - } else if (Opcode.Instruction.i2d.code == opcode) { - result.opCodeText = Opcode.Instruction.i2d.name(); - } else if (Opcode.Instruction.l2i.code == opcode) { - result.opCodeText = Opcode.Instruction.l2i.name(); - } else if (Opcode.Instruction.l2f.code == opcode) { - result.opCodeText = Opcode.Instruction.l2f.name(); - } else if (Opcode.Instruction.l2d.code == opcode) { - result.opCodeText = Opcode.Instruction.l2d.name(); - } else if (Opcode.Instruction.f2i.code == opcode) { - result.opCodeText = Opcode.Instruction.f2i.name(); - } else if (Opcode.Instruction.f2l.code == opcode) { - result.opCodeText = Opcode.Instruction.f2l.name(); - } else if (Opcode.Instruction.f2d.code == opcode) { - result.opCodeText = Opcode.Instruction.f2d.name(); - } else if (Opcode.Instruction.d2i.code == opcode) { - result.opCodeText = Opcode.Instruction.d2i.name(); - } else if (Opcode.Instruction.d2l.code == opcode) { - result.opCodeText = Opcode.Instruction.d2l.name(); - } else if (Opcode.Instruction.d2f.code == opcode) { - result.opCodeText = Opcode.Instruction.d2f.name(); - } else if (Opcode.Instruction.i2b.code == opcode) { - result.opCodeText = Opcode.Instruction.i2b.name(); - } else if (Opcode.Instruction.i2c.code == opcode) { - result.opCodeText = Opcode.Instruction.i2c.name(); - } else if (Opcode.Instruction.i2s.code == opcode) { - result.opCodeText = Opcode.Instruction.i2s.name(); - } else if (Opcode.Instruction.lcmp.code == opcode) { - result.opCodeText = Opcode.Instruction.lcmp.name(); - } else if (Opcode.Instruction.fcmpl.code == opcode) { - result.opCodeText = Opcode.Instruction.fcmpl.name(); - } else if (Opcode.Instruction.fcmpg.code == opcode) { - result.opCodeText = Opcode.Instruction.fcmpg.name(); - } else if (Opcode.Instruction.dcmpl.code == opcode) { - result.opCodeText = Opcode.Instruction.dcmpl.name(); - } else if (Opcode.Instruction.dcmpg.code == opcode) { - result.opCodeText = Opcode.Instruction.dcmpg.name(); - } else if (Opcode.Instruction.ifeq.code == opcode) { - // if: ifeq = 153 (0x99) ifne = 154 (0x9a) iflt = 155 (0x9b) ifge = 156 (0x9c) ifgt = 157 (0x9d) ifle = 158 (0x9e) - // Branch if int comparison with zero succeeds - // - // If the comparison succeeds, the unsigned branchbyte1 and branchbyte2 are used to construct a signed 16-bit offset, - // where the offset is calculated to be (branchbyte1 << 8) | branchbyte2. - // Execution then proceeds at that offset from the address of the opCode of this if instruction. - // The target address must be that of an opCode of an instruction within the method that contains this if instruction. - result.branchbyte = Integer.valueOf(pdis.readShort()); - result.opCodeText = Opcode.Instruction.ifeq.name(); - } else if (Opcode.Instruction.ifne.code == opcode) { - result.branchbyte = Integer.valueOf(pdis.readShort()); - result.opCodeText = Opcode.Instruction.ifne.name(); - } else if (Opcode.Instruction.iflt.code == opcode) { - result.branchbyte = Integer.valueOf(pdis.readShort()); - result.opCodeText = Opcode.Instruction.iflt.name(); - } else if (Opcode.Instruction.ifge.code == opcode) { - result.branchbyte = Integer.valueOf(pdis.readShort()); - result.opCodeText = Opcode.Instruction.ifge.name(); - } else if (Opcode.Instruction.ifgt.code == opcode) { - result.branchbyte = Integer.valueOf(pdis.readShort()); - result.opCodeText = Opcode.Instruction.ifgt.name(); - } else if (Opcode.Instruction.ifle.code == opcode) { - result.branchbyte = Integer.valueOf(pdis.readShort()); - result.opCodeText = Opcode.Instruction.ifle.name(); - } else if (Opcode.Instruction.if_icmpeq.code == opcode) { - // if_icmp: if_icmpeq = 159 (0x9f) if_icmpne = 160 (0xa0) if_icmplt = 161 (0xa1) if_icmpge = 162 (0xa2) if_icmpgt = 163 (0xa3) if_icmple = 164 (0xa4) - // Branch if int comparison succeeds - result.branchbyte = Integer.valueOf(pdis.readShort()); - result.opCodeText = Opcode.Instruction.if_icmpeq.name(); - } else if (Opcode.Instruction.if_icmpne.code == opcode) { - result.branchbyte = Integer.valueOf(pdis.readShort()); - result.opCodeText = Opcode.Instruction.if_icmpne.name(); - } else if (Opcode.Instruction.if_icmplt.code == opcode) { - result.branchbyte = Integer.valueOf(pdis.readShort()); - result.opCodeText = Opcode.Instruction.if_icmplt.name(); - } else if (Opcode.Instruction.if_icmpge.code == opcode) { - result.branchbyte = Integer.valueOf(pdis.readShort()); - result.opCodeText = Opcode.Instruction.if_icmpge.name(); - } else if (Opcode.Instruction.if_icmpgt.code == opcode) { - result.branchbyte = Integer.valueOf(pdis.readShort()); - result.opCodeText = Opcode.Instruction.if_icmpgt.name(); - } else if (Opcode.Instruction.if_icmple.code == opcode) { - result.branchbyte = Integer.valueOf(pdis.readShort()); - result.opCodeText = Opcode.Instruction.if_icmple.name(); - } else if (Opcode.Instruction.if_acmpeq.code == opcode) { - // if_acmp: if_acmpeq = 165 (0xa5) if_acmpne = 166 (0xa6) - // Branch if reference comparison succeeds - // ..., value1, value2 - // Both value1 and value2 must be of type reference. They are both popped from the operand stack and compared. - // - // If the comparison succeeds, the unsigned branchbyte1 and branchbyte2 are used to construct a signed 16-bit offset, - // where the offset is calculated to be (branchbyte1 << 8) | branchbyte2. - // Execution then proceeds at that offset from the address of the opCode of this if_acmp instruction. - // The target address must be that of an opCode of an instruction within the method that contains this if_acmp instruction. - result.branchbyte = Integer.valueOf(pdis.readShort()); - result.opCodeText = Opcode.Instruction.if_acmpeq.name(); - } else if (Opcode.Instruction.if_acmpne.code == opcode) { - result.branchbyte = Integer.valueOf(pdis.readShort()); - result.opCodeText = Opcode.Instruction.if_acmpne.name(); - } else if (Opcode.Instruction.goto_.code == opcode) { - // Branch always - // The unsigned bytes branchbyte1 and branchbyte2 are used to construct a signed 16-bit branchoffset, - // where branchoffset is (branchbyte1 << 8) | branchbyte2. - // Execution proceeds at that offset from the address of the opCode of this goto instruction. - // The target address must be that of an opCode of an instruction within the method that contains this goto instruction. - result.branchbyte = Integer.valueOf(pdis.readShort()); - result.opCodeText = Opcode.Instruction.goto_.getName(); - } else if (Opcode.Instruction.jsr.code == opcode) { - // Jump subroutine - // The address of the opCode of the instruction immediately following this jsr instruction - // is pushed onto the operand stack as a value of type returnAddress. - // The unsigned branchbyte1 and branchbyte2 are used to construct a signed 16-bit offset, - // where the offset is (branchbyte1 << 8) | branchbyte2. - // Execution proceeds at that offset from the address of this jsr instruction. - // The target address must be that of an opCode of an instruction within the method that contains this jsr instruction. - result.branchbyte = Integer.valueOf(pdis.readShort()); - result.opCodeText = Opcode.Instruction.jsr.name(); } else if (Opcode.Instruction.ret.code == opcode) { // Return from subroutine // The index is an unsigned byte between 0 and 255, inclusive. @@ -1224,6 +1775,13 @@ private static String getText_lookupswitch(final PosDataInputStream pdis) return sb.toString(); } + /** + * tableswitch instruction. + * + * @see + * VM + * Spec: The Java Virtual Machine Instruction Set + */ private static String getText_tableswitch(final PosDataInputStream pdis) throws IOException { String space = " "; @@ -1247,7 +1805,7 @@ private static String getText_tableswitch(final PosDataInputStream pdis) private static String getText_wide(final PosDataInputStream pdis) throws IOException { final int opcode = pdis.readUnsignedByte(); - String opCodeText = null; + String opCodeText; int shortValue; int shortValue2; @@ -1309,7 +1867,7 @@ public static class InstructionParsed { /** * JVM Opcode value. - * + * * @see Instruction#code */ public final int opCode; @@ -1323,9 +1881,9 @@ public static class InstructionParsed { /** * Referenced {@link ClassFile#constant_pool} object index if exist. It - * will be null if the {@link Instruction} did not reference - * to any {@link ClassFile#constant_pool} object. - * + * will be null if the {@link Instruction} did not + * reference to any {@link ClassFile#constant_pool} object. + * * @see Instruction#ldc * @see Instruction#ldc_w * @see Instruction#ldc2_w @@ -1347,8 +1905,17 @@ public static class InstructionParsed { protected Integer cpIndex = null; /** - * Execution proceeds at that offset from the address of the opcode of current instruction. - * + * Index into the Local Variable array of the current frame. + * + * @see Instruction#iload + * @see Instruction#lload + */ + protected Integer lvIndex = null; + + /** + * Execution proceeds at that offset from the address of the opcode of + * current instruction. + * * @see Instruction#goto_ * @see Instruction#goto_w * @see Instruction#if_acmpeq @@ -1378,18 +1945,20 @@ public static class InstructionParsed { } /** - * Get the absolute value of the branch byte, if {@link #branchbyte} is not null. - * - * @return Absolute value of the {@link #branchbyte}; return null in case {@link #branchbyte} is null + * Get the absolute value of the branch byte, if {@link #branchbyte} is + * not null. + * + * @return Absolute value of the {@link #branchbyte}; return + * null in case {@link #branchbyte} is null * @see #branchbyte */ - public Integer getAbsoluteBranchByte(){ + public Integer getAbsoluteBranchByte() { return (this.branchbyte != null) ? this.offset + this.branchbyte : null; } /** * Getter for {@link #opCodeText}. - * + * * @return {@link #opCodeText} value */ public String getOpcodeText() { @@ -1398,8 +1967,9 @@ public String getOpcodeText() { /** * Getter for {@link #cpIndex}. - * - * @return {@link #cpIndex} value. null if no constant pool index. + * + * @return {@link #cpIndex} value. null if no constant pool + * index. */ public Integer getCpindex() { return this.cpIndex; @@ -1426,7 +1996,7 @@ public String toString() { */ public String toString(ClassFile cf) { String s = this.toString(); - + if (this.cpIndex != null) { String cpDesc = cf.getCPDescription(this.cpIndex); // Avoid too long description