diff --git a/jbmc/src/java_bytecode/bytecode_info.cpp b/jbmc/src/java_bytecode/bytecode_info.cpp index 10473ae8fe0..11405ecb089 100644 --- a/jbmc/src/java_bytecode/bytecode_info.cpp +++ b/jbmc/src/java_bytecode/bytecode_info.cpp @@ -15,86 +15,139 @@ Author: Daniel Kroening, kroening@kroening.com // clang-format off struct bytecode_infot const bytecode_info[]= { -{ "aaload", 0x32, ' ', 2, 1, 'a' }, // arrayref, index → value; load onto the stack a reference from an array NOLINT(*) -{ "aastore", 0x53, ' ', 3, 0, ' ' }, // arrayref, index, value →; store into a reference in an array NOLINT(*) +{ "nop", 0x00, ' ', 0, 0, ' ' }, // [No change]; perform no operation NOLINT(*) { "aconst_null", 0x01, ' ', 0, 1, 'a' }, // → null; push a null reference onto the stack NOLINT(*) -{ "aload", 0x19, 'v', 0, 1, 'a' }, // → objectref; load a reference onto the stack from a local variable #index NOLINT(*) -{ "aload_0", 0x2a, ' ', 0, 1, 'a' }, // → objectref; load a reference onto the stack from local variable 0 NOLINT(*) -{ "aload_1", 0x2b, ' ', 0, 1, 'a' }, // → objectref; load a reference onto the stack from local variable 1 NOLINT(*) -{ "aload_2", 0x2c, ' ', 0, 1, 'a' }, // → objectref; load a reference onto the stack from local variable 2 NOLINT(*) -{ "aload_3", 0x2d, ' ', 0, 1, 'a' }, // → objectref; load a reference onto the stack from local variable 3 NOLINT(*) -{ "anewarray", 0xbd, 'C', 1, 1, 'a' }, // count → arrayref; create a new array of references of length count and component type identified by the class reference index (indexbyte1 << 8 + indexbyte2) in the constant pool NOLINT(*) -{ "areturn", 0xb0, ' ', 1, 0, ' ' }, // objectref → [empty]; return a reference from a method NOLINT(*) -{ "arraylength", 0xbe, ' ', 1, 1, 'i' }, // arrayref → length; get the length of an array NOLINT(*) -{ "astore", 0x3a, 'v', 1, 0, ' ' }, // objectref →; store a reference into a local variable #index NOLINT(*) -{ "astore_0", 0x4b, ' ', 1, 0, ' ' }, // objectref →; store a reference into local variable 0 NOLINT(*) -{ "astore_1", 0x4c, ' ', 1, 0, ' ' }, // objectref →; store a reference into local variable 1 NOLINT(*) -{ "astore_2", 0x4d, ' ', 1, 0, ' ' }, // objectref →; store a reference into local variable 2 NOLINT(*) -{ "astore_3", 0x4e, ' ', 1, 0, ' ' }, // objectref →; store a reference into local variable 3 NOLINT(*) -{ "athrow", 0xbf, ' ', 1, 1, ' ' }, // objectref → [empty], objectref; throws an error or exception (notice that the rest of the stack is cleared, leaving only a reference to the Throwable) NOLINT(*) -{ "baload", 0x33, ' ', 2, 1, 'b' }, // arrayref, index → value; load a byte or Boolean value from an array NOLINT(*) -{ "bastore", 0x54, ' ', 3, 0, ' ' }, // arrayref, index, value →; store a byte or Boolean value into an array NOLINT(*) -{ "bipush", 0x10, 'b', 0, 1, 'i' }, // → value; push a byte onto the stack as an integer value NOLINT(*) -{ "caload", 0x34, ' ', 2, 1, 'c' }, // arrayref, index → value; load a char from an array NOLINT(*) -{ "castore", 0x55, ' ', 3, 0, ' ' }, // arrayref, index, value →; store a char into an array NOLINT(*) -{ "checkcast", 0xc0, 'C', 1, 1, 'a' }, // objectref → objectref; checks whether an objectref is of a certain type, the class reference of which is in the constant pool at index (indexbyte1 << 8 + indexbyte2) NOLINT(*) -{ "dadd", 0x63, ' ', 2, 1, 'd' }, // value1, value2 → result; add two doubles NOLINT(*) -{ "daload", 0x31, ' ', 2, 1, 'd' }, // arrayref, index → value; load a double from an array NOLINT(*) -{ "dastore", 0x52, ' ', 3, 0, ' ' }, // arrayref, index, value →; store a double into an array NOLINT(*) -{ "dcmpg", 0x98, ' ', 2, 1, 'i' }, // value1, value2 → result; compare two doubles NOLINT(*) -{ "dcmpl", 0x97, ' ', 2, 1, 'i' }, // value1, value2 → result; compare two doubles NOLINT(*) +{ "iconst_m1", 0x02, ' ', 0, 1, 'i' }, // → -1; load the int value -1 onto the stack NOLINT(*) +{ "iconst_0", 0x03, ' ', 0, 1, 'i' }, // → 0; load the int value 0 onto the stack NOLINT(*) +{ "iconst_1", 0x04, ' ', 0, 1, 'i' }, // → 1; load the int value 1 onto the stack NOLINT(*) +{ "iconst_2", 0x05, ' ', 0, 1, 'i' }, // → 2; load the int value 2 onto the stack NOLINT(*) +{ "iconst_3", 0x06, ' ', 0, 1, 'i' }, // → 3; load the int value 3 onto the stack NOLINT(*) +{ "iconst_4", 0x07, ' ', 0, 1, 'i' }, // → 4; load the int value 4 onto the stack NOLINT(*) +{ "iconst_5", 0x08, ' ', 0, 1, 'i' }, // → 5; load the int value 5 onto the stack NOLINT(*) +{ "lconst_0", 0x09, ' ', 0, 1, 'l' }, // → 0L; push the long 0 onto the stack NOLINT(*) +{ "lconst_1", 0x0a, ' ', 0, 1, 'l' }, // → 1L; push the long 1 onto the stack NOLINT(*) +{ "fconst_0", 0x0b, ' ', 0, 1, 'f' }, // → 0.0f; push 0.0f on the stack NOLINT(*) +{ "fconst_1", 0x0c, ' ', 0, 1, 'f' }, // → 1.0f; push 1.0f on the stack NOLINT(*) +{ "fconst_2", 0x0d, ' ', 0, 1, 'f' }, // → 2.0f; push 2.0f on the stack NOLINT(*) { "dconst_0", 0x0e, ' ', 0, 1, 'd' }, // → 0.0; push the constant 0.0 onto the stack NOLINT(*) { "dconst_1", 0x0f, ' ', 0, 1, 'd' }, // → 1.0; push the constant 1.0 onto the stack NOLINT(*) -{ "ddiv", 0x6f, ' ', 2, 1, 'd' }, // value1, value2 → result; divide two doubles NOLINT(*) +{ "bipush", 0x10, 'b', 0, 1, 'i' }, // → value; push a byte onto the stack as an integer value NOLINT(*) +{ "sipush", 0x11, 's', 0, 1, 'i' }, // → value; push a short onto the stack as an integer value NOLINT(*) +{ "ldc", 0x12, 'c', 0, 1, ' ' }, // → value; push a constant #index from a constant pool (String, int or float) onto the stack NOLINT(*) +{ "ldc_w", 0x13, 'C', 0, 1, ' ' }, // → value; push a constant #index from a constant pool (String, int or float) onto the stack (wide index is constructed as indexbyte1 << 8 + indexbyte2) NOLINT(*) +{ "ldc2_w", 0x14, 'C', 0, 1, ' ' }, // → value; push a constant #index from a constant pool (double or long) onto the stack (wide index is constructed as indexbyte1 << 8 + indexbyte2) NOLINT(*) +{ "iload", 0x15, 'v', 0, 1, 'i' }, // → value; load an int value from a local variable #index NOLINT(*) +{ "lload", 0x16, 'v', 0, 1, 'l' }, // → value; load a long value from a local variable #index NOLINT(*) +{ "fload", 0x17, 'v', 0, 1, 'f' }, // → value; load a float value from a local variable #index NOLINT(*) { "dload", 0x18, 'v', 0, 1, 'd' }, // → value; load a double value from a local variable #index NOLINT(*) +{ "aload", 0x19, 'v', 0, 1, 'a' }, // → objectref; load a reference onto the stack from a local variable #index NOLINT(*) +{ "iload_0", 0x1a, ' ', 0, 1, 'i' }, // → value; load an int value from local variable 0 NOLINT(*) +{ "iload_1", 0x1b, ' ', 0, 1, 'i' }, // → value; load an int value from local variable 1 NOLINT(*) +{ "iload_2", 0x1c, ' ', 0, 1, 'i' }, // → value; load an int value from local variable 2 NOLINT(*) +{ "iload_3", 0x1d, ' ', 0, 1, 'i' }, // → value; load an int value from local variable 3 NOLINT(*) +{ "lload_0", 0x1e, ' ', 0, 1, 'l' }, // → value; load a long value from a local variable 0 NOLINT(*) +{ "lload_1", 0x1f, ' ', 0, 1, 'l' }, // → value; load a long value from a local variable 1 NOLINT(*) +{ "lload_2", 0x20, ' ', 0, 1, 'l' }, // → value; load a long value from a local variable 2 NOLINT(*) +{ "lload_3", 0x21, ' ', 0, 1, 'l' }, // → value; load a long value from a local variable 3 NOLINT(*) +{ "fload_0", 0x22, ' ', 0, 1, 'f' }, // → value; load a float value from local variable 0 NOLINT(*) +{ "fload_1", 0x23, ' ', 0, 1, 'f' }, // → value; load a float value from local variable 1 NOLINT(*) +{ "fload_2", 0x24, ' ', 0, 1, 'f' }, // → value; load a float value from local variable 2 NOLINT(*) +{ "fload_3", 0x25, ' ', 0, 1, 'f' }, // → value; load a float value from local variable 3 NOLINT(*) { "dload_0", 0x26, ' ', 0, 1, 'd' }, // → value; load a double from local variable 0 NOLINT(*) { "dload_1", 0x27, ' ', 0, 1, 'd' }, // → value; load a double from local variable 1 NOLINT(*) { "dload_2", 0x28, ' ', 0, 1, 'd' }, // → value; load a double from local variable 2 NOLINT(*) { "dload_3", 0x29, ' ', 0, 1, 'd' }, // → value; load a double from local variable 3 NOLINT(*) -{ "dmul", 0x6b, ' ', 2, 1, 'd' }, // value1, value2 → result; multiply two doubles NOLINT(*) -{ "dneg", 0x77, ' ', 1, 1, 'd' }, // value → result; negate a double NOLINT(*) -{ "drem", 0x73, ' ', 2, 1, 'd' }, // value1, value2 → result; get the remainder from a division between two doubles NOLINT(*) -{ "dreturn", 0xaf, ' ', 1, 0, ' ' }, // value → [empty]; return a double from a method NOLINT(*) +{ "aload_0", 0x2a, ' ', 0, 1, 'a' }, // → objectref; load a reference onto the stack from local variable 0 NOLINT(*) +{ "aload_1", 0x2b, ' ', 0, 1, 'a' }, // → objectref; load a reference onto the stack from local variable 1 NOLINT(*) +{ "aload_2", 0x2c, ' ', 0, 1, 'a' }, // → objectref; load a reference onto the stack from local variable 2 NOLINT(*) +{ "aload_3", 0x2d, ' ', 0, 1, 'a' }, // → objectref; load a reference onto the stack from local variable 3 NOLINT(*) +{ "iaload", 0x2e, ' ', 2, 1, 'i' }, // arrayref, index → value; load an int from an array NOLINT(*) +{ "laload", 0x2f, ' ', 2, 1, 'l' }, // arrayref, index → value; load a long from an array NOLINT(*) +{ "faload", 0x30, ' ', 2, 1, 'f' }, // arrayref, index → value; load a float from an array NOLINT(*) +{ "daload", 0x31, ' ', 2, 1, 'd' }, // arrayref, index → value; load a double from an array NOLINT(*) +{ "aaload", 0x32, ' ', 2, 1, 'a' }, // arrayref, index → value; load onto the stack a reference from an array NOLINT(*) +{ "baload", 0x33, ' ', 2, 1, 'b' }, // arrayref, index → value; load a byte or Boolean value from an array NOLINT(*) +{ "caload", 0x34, ' ', 2, 1, 'c' }, // arrayref, index → value; load a char from an array NOLINT(*) +{ "saload", 0x35, ' ', 2, 1, 's' }, // arrayref, index → value; load short from array NOLINT(*) +{ "istore", 0x36, 'v', 1, 0, ' ' }, // value →; store int value into variable #index NOLINT(*) +{ "lstore", 0x37, 'v', 1, 0, ' ' }, // value →; store a long value in a local variable #index NOLINT(*) +{ "fstore", 0x38, 'v', 1, 0, ' ' }, // value →; store a float value into a local variable #index NOLINT(*) { "dstore", 0x39, 'v', 1, 0, ' ' }, // value →; store a double value into a local variable #index NOLINT(*) +{ "astore", 0x3a, 'v', 1, 0, ' ' }, // objectref →; store a reference into a local variable #index NOLINT(*) +{ "istore_0", 0x3b, ' ', 1, 0, ' ' }, // value →; store int value into variable 0 NOLINT(*) +{ "istore_1", 0x3c, ' ', 1, 0, ' ' }, // value →; store int value into variable 1 NOLINT(*) +{ "istore_2", 0x3d, ' ', 1, 0, ' ' }, // value →; store int value into variable 2 NOLINT(*) +{ "istore_3", 0x3e, ' ', 1, 0, ' ' }, // value →; store int value into variable 3 NOLINT(*) +{ "lstore_0", 0x3f, ' ', 1, 0, ' ' }, // value →; store a long value in a local variable 0 NOLINT(*) +{ "lstore_1", 0x40, ' ', 1, 0, ' ' }, // value →; store a long value in a local variable 1 NOLINT(*) +{ "lstore_2", 0x41, ' ', 1, 0, ' ' }, // value →; store a long value in a local variable 2 NOLINT(*) +{ "lstore_3", 0x42, ' ', 1, 0, ' ' }, // value →; store a long value in a local variable 3 NOLINT(*) +{ "fstore_0", 0x43, ' ', 1, 0, ' ' }, // value →; store a float value into local variable 0 NOLINT(*) +{ "fstore_1", 0x44, ' ', 1, 0, ' ' }, // value →; store a float value into local variable 1 NOLINT(*) +{ "fstore_2", 0x45, ' ', 1, 0, ' ' }, // value →; store a float value into local variable 2 NOLINT(*) +{ "fstore_3", 0x46, ' ', 1, 0, ' ' }, // value →; store a float value into local variable 3 NOLINT(*) { "dstore_0", 0x47, ' ', 1, 0, ' ' }, // value →; store a double into local variable 0 NOLINT(*) { "dstore_1", 0x48, ' ', 1, 0, ' ' }, // value →; store a double into local variable 1 NOLINT(*) { "dstore_2", 0x49, ' ', 1, 0, ' ' }, // value →; store a double into local variable 2 NOLINT(*) { "dstore_3", 0x4a, ' ', 1, 0, ' ' }, // value →; store a double into local variable 3 NOLINT(*) -{ "dsub", 0x67, ' ', 2, 1, 'd' }, // value1, value2 → result; subtract a double from another NOLINT(*) +{ "astore_0", 0x4b, ' ', 1, 0, ' ' }, // objectref →; store a reference into local variable 0 NOLINT(*) +{ "astore_1", 0x4c, ' ', 1, 0, ' ' }, // objectref →; store a reference into local variable 1 NOLINT(*) +{ "astore_2", 0x4d, ' ', 1, 0, ' ' }, // objectref →; store a reference into local variable 2 NOLINT(*) +{ "astore_3", 0x4e, ' ', 1, 0, ' ' }, // objectref →; store a reference into local variable 3 NOLINT(*) +{ "iastore", 0x4f, ' ', 3, 0, ' ' }, // arrayref, index, value →; store an int into an array NOLINT(*) +{ "lastore", 0x50, ' ', 3, 0, ' ' }, // arrayref, index, value →; store a long to an array NOLINT(*) +{ "fastore", 0x51, ' ', 3, 0, ' ' }, // arrayref, index, value →; store a float in an array NOLINT(*) +{ "dastore", 0x52, ' ', 3, 0, ' ' }, // arrayref, index, value →; store a double into an array NOLINT(*) +{ "aastore", 0x53, ' ', 3, 0, ' ' }, // arrayref, index, value →; store into a reference in an array NOLINT(*) +{ "bastore", 0x54, ' ', 3, 0, ' ' }, // arrayref, index, value →; store a byte or Boolean value into an array NOLINT(*) +{ "castore", 0x55, ' ', 3, 0, ' ' }, // arrayref, index, value →; store a char into an array NOLINT(*) +{ "sastore", 0x56, ' ', 3, 0, 's' }, // arrayref, index, value →; store short to array NOLINT(*) +{ "pop", 0x57, ' ', 1, 0, ' ' }, // value →; discard the top value on the stack NOLINT(*) +{ "pop2", 0x58, ' ', 1, 0, ' ' }, // {value2, value1} →; discard the top two values on the stack (or one value, if it is a double or long) NOLINT(*) { "dup", 0x59, ' ', 1, 2, ' ' }, // value → value, value; duplicate the value on top of the stack NOLINT(*) { "dup_x1", 0x5a, ' ', 2, 3, ' ' }, // value2, value1 → value1, value2, value1; insert a copy of the top value into the stack two values from the top. value1 and value2 must not be of the type double or long. NOLINT(*) { "dup_x2", 0x5b, ' ', 3, 4, ' ' }, // value3, value2, value1 → value1, value3, value2, value1; insert a copy of the top value into the stack two (if value2 is double or long it takes up the entry of value3, too) or three values (if value2 is neither double nor long) from the top NOLINT(*) { "dup2", 0x5c, ' ', 0, 0, ' ' }, // {value2, value1} → {value2, value; value2, value1} }, // duplicate top two stack words NOLINT(*) { "dup2_x1", 0x5d, ' ', 0, 0, ' ' }, // value3, {value2, value1} → {value2, value; value3, {value2, value1} }, // duplicate two words and insert beneath third word (see explanation above) NOLINT(*) { "dup2_x2", 0x5e, ' ', 0, 0, ' ' }, // {value4, value; value2, value1} → {value2, value1}, {value4, value3}, {value2, value1} }, // duplicate two words and insert beneath fourth word NOLINT(*) +{ "swap", 0x5f, ' ', 2, 2, ' ' }, // value2, value1 → value1, value2; swaps two top words on the stack (note that value1 and value2 must not be double or long) NOLINT(*) +{ "iadd", 0x60, ' ', 2, 1, 'i' }, // value1, value2 → result; add two ints NOLINT(*) +{ "ladd", 0x61, ' ', 2, 1, 'l' }, // value1, value2 → result; add two longs NOLINT(*) { "fadd", 0x62, ' ', 2, 1, 'f' }, // value1, value2 → result; add two floats NOLINT(*) -{ "faload", 0x30, ' ', 2, 1, 'f' }, // arrayref, index → value; load a float from an array NOLINT(*) -{ "fastore", 0x51, ' ', 3, 0, ' ' }, // arrayref, index, value →; store a float in an array NOLINT(*) -{ "fcmpg", 0x96, ' ', 2, 1, 'i' }, // value1, value2 → result; compare two floats NOLINT(*) -{ "fcmpl", 0x95, ' ', 2, 1, 'i' }, // value1, value2 → result; compare two floats NOLINT(*) -{ "fconst_0", 0x0b, ' ', 0, 1, 'f' }, // → 0.0f; push 0.0f on the stack NOLINT(*) -{ "fconst_1", 0x0c, ' ', 0, 1, 'f' }, // → 1.0f; push 1.0f on the stack NOLINT(*) -{ "fconst_2", 0x0d, ' ', 0, 1, 'f' }, // → 2.0f; push 2.0f on the stack NOLINT(*) -{ "fdiv", 0x6e, ' ', 2, 1, 'f' }, // value1, value2 → result; divide two floats NOLINT(*) -{ "fload", 0x17, 'v', 0, 1, 'f' }, // → value; load a float value from a local variable #index NOLINT(*) -{ "fload_0", 0x22, ' ', 0, 1, 'f' }, // → value; load a float value from local variable 0 NOLINT(*) -{ "fload_1", 0x23, ' ', 0, 1, 'f' }, // → value; load a float value from local variable 1 NOLINT(*) -{ "fload_2", 0x24, ' ', 0, 1, 'f' }, // → value; load a float value from local variable 2 NOLINT(*) -{ "fload_3", 0x25, ' ', 0, 1, 'f' }, // → value; load a float value from local variable 3 NOLINT(*) +{ "dadd", 0x63, ' ', 2, 1, 'd' }, // value1, value2 → result; add two doubles NOLINT(*) +{ "isub", 0x64, ' ', 2, 1, 'i' }, // value1, value2 → result; int subtract NOLINT(*) +{ "lsub", 0x65, ' ', 2, 1, 'l' }, // value1, value2 → result; subtract two longs NOLINT(*) +{ "fsub", 0x66, ' ', 2, 1, 'f' }, // value1, value2 → result; subtract two floats NOLINT(*) +{ "dsub", 0x67, ' ', 2, 1, 'd' }, // value1, value2 → result; subtract a double from another NOLINT(*) +{ "imul", 0x68, ' ', 2, 1, 'i' }, // value1, value2 → result; multiply two integers NOLINT(*) +{ "lmul", 0x69, ' ', 2, 1, 'l' }, // value1, value2 → result; multiply two longs NOLINT(*) { "fmul", 0x6a, ' ', 2, 1, 'f' }, // value1, value2 → result; multiply two floats NOLINT(*) -{ "fneg", 0x76, ' ', 1, 1, 'f' }, // value → result; negate a float NOLINT(*) +{ "dmul", 0x6b, ' ', 2, 1, 'd' }, // value1, value2 → result; multiply two doubles NOLINT(*) +{ "idiv", 0x6c, ' ', 2, 1, 'i' }, // value1, value2 → result; divide two integers NOLINT(*) +{ "ldiv", 0x6d, ' ', 2, 1, 'l' }, // value1, value2 → result; divide two longs NOLINT(*) +{ "fdiv", 0x6e, ' ', 2, 1, 'f' }, // value1, value2 → result; divide two floats NOLINT(*) +{ "ddiv", 0x6f, ' ', 2, 1, 'd' }, // value1, value2 → result; divide two doubles NOLINT(*) +{ "irem", 0x70, ' ', 2, 1, 'i' }, // value1, value2 → result; logical int remainder NOLINT(*) +{ "lrem", 0x71, ' ', 2, 1, 'l' }, // value1, value2 → result; remainder of division of two longs NOLINT(*) { "frem", 0x72, ' ', 2, 1, 'f' }, // value1, value2 → result; get the remainder from a division between two floats NOLINT(*) -{ "freturn", 0xae, ' ', 1, 0, ' ' }, // value → [empty]; return a float NOLINT(*) -{ "fstore", 0x38, 'v', 1, 0, ' ' }, // value →; store a float value into a local variable #index NOLINT(*) -{ "fstore_0", 0x43, ' ', 1, 0, ' ' }, // value →; store a float value into local variable 0 NOLINT(*) -{ "fstore_1", 0x44, ' ', 1, 0, ' ' }, // value →; store a float value into local variable 1 NOLINT(*) -{ "fstore_2", 0x45, ' ', 1, 0, ' ' }, // value →; store a float value into local variable 2 NOLINT(*) -{ "fstore_3", 0x46, ' ', 1, 0, ' ' }, // value →; store a float value into local variable 3 NOLINT(*) -{ "fsub", 0x66, ' ', 2, 1, 'f' }, // value1, value2 → result; subtract two floats NOLINT(*) -{ "getfield", 0xb4, 'C', 1, 1, ' ' }, // objectref → value; get a field value of an object objectref, where the field is identified by field reference in the constant pool index (index1 << 8 + index2) NOLINT(*) -{ "getstatic", 0xb2, 'C', 0, 1, ' ' }, // → value; get a static field value of a class, where the field is identified by field reference in the constant pool index (index1 << 8 + index2) NOLINT(*) -{ "goto", 0xa7, 'o', 0, 0, ' ' }, // [no change]; goes to another instruction at branchoffset (signed short constructed from unsigned bytes branchbyte1 << 8 + branchbyte2) NOLINT(*) -{ "goto_w", 0xc8, 'O', 0, 0, ' ' }, // [no change]; goes to another instruction at branchoffset (signed int constructed from unsigned bytes branchbyte1 << 24 + branchbyte2 << 16 + branchbyte3 << 8 + branchbyte4) NOLINT(*) +{ "drem", 0x73, ' ', 2, 1, 'd' }, // value1, value2 → result; get the remainder from a division between two doubles NOLINT(*) +{ "ineg", 0x74, ' ', 1, 1, 'i' }, // value → result; negate int NOLINT(*) +{ "lneg", 0x75, ' ', 1, 1, 'l' }, // value → result; negate a long NOLINT(*) +{ "fneg", 0x76, ' ', 1, 1, 'f' }, // value → result; negate a float NOLINT(*) +{ "dneg", 0x77, ' ', 1, 1, 'd' }, // value → result; negate a double NOLINT(*) +{ "ishl", 0x78, ' ', 2, 1, 'i' }, // value1, value2 → result; int shift left NOLINT(*) +{ "lshl", 0x79, ' ', 2, 1, 'l' }, // value1, value2 → result; bitwise shift left of a long value1 by value2 positions NOLINT(*) +{ "ishr", 0x7a, ' ', 2, 1, 'i' }, // value1, value2 → result; int arithmetic shift right NOLINT(*) +{ "lshr", 0x7b, ' ', 2, 1, 'l' }, // value1, value2 → result; bitwise shift right of a long value1 by value2 positions NOLINT(*) +{ "iushr", 0x7c, ' ', 2, 1, 'i' }, // value1, value2 → result; int logical shift right NOLINT(*) +{ "lushr", 0x7d, ' ', 2, 1, 'l' }, // value1, value2 → result; bitwise shift right of a long value1 by value2 positions, unsigned NOLINT(*) +{ "iand", 0x7e, ' ', 2, 1, 'i' }, // value1, value2 → result; perform a bitwise and on two integers NOLINT(*) +{ "land", 0x7f, ' ', 2, 1, 'l' }, // value1, value2 → result; bitwise and of two longs NOLINT(*) +{ "ior", 0x80, ' ', 2, 1, 'i' }, // value1, value2 → result; bitwise int or NOLINT(*) +{ "lor", 0x81, ' ', 2, 1, 'l' }, // value1, value2 → result; bitwise or of two longs NOLINT(*) +{ "ixor", 0x82, ' ', 2, 1, 'i' }, // value1, value2 → result; int xor NOLINT(*) +{ "lxor", 0x83, ' ', 2, 1, 'l' }, // value1, value2 → result; bitwise exclusive or of two longs NOLINT(*) +{ "iinc", 0x84, 'V', 0, 0, ' ' }, // [No change]; increment local variable #index by signed byte const NOLINT(*) { "i2l", 0x85, ' ', 1, 1, 'l' }, // value → result; convert an int into a long NOLINT(*) { "i2f", 0x86, ' ', 1, 1, 'f' }, // value → result; convert an int into a float NOLINT(*) { "i2d", 0x87, ' ', 1, 1, 'd' }, // value → result; convert an int into a double NOLINT(*) @@ -110,116 +163,117 @@ struct bytecode_infot const bytecode_info[]= { "i2b", 0x91, ' ', 1, 1, 'b' }, // value → result; convert an int into a byte NOLINT(*) { "i2c", 0x92, ' ', 1, 1, 'c' }, // value → result; convert an int into a character NOLINT(*) { "i2s", 0x93, ' ', 1, 1, 's' }, // value → result; convert an int into a short NOLINT(*) -{ "iadd", 0x60, ' ', 2, 1, 'i' }, // value1, value2 → result; add two ints NOLINT(*) -{ "iaload", 0x2e, ' ', 2, 1, 'i' }, // arrayref, index → value; load an int from an array NOLINT(*) -{ "iand", 0x7e, ' ', 2, 1, 'i' }, // value1, value2 → result; perform a bitwise and on two integers NOLINT(*) -{ "iastore", 0x4f, ' ', 3, 0, ' ' }, // arrayref, index, value →; store an int into an array NOLINT(*) -{ "iconst_m1", 0x02, ' ', 0, 1, 'i' }, // → -1; load the int value -1 onto the stack NOLINT(*) -{ "iconst_0", 0x03, ' ', 0, 1, 'i' }, // → 0; load the int value 0 onto the stack NOLINT(*) -{ "iconst_1", 0x04, ' ', 0, 1, 'i' }, // → 1; load the int value 1 onto the stack NOLINT(*) -{ "iconst_2", 0x05, ' ', 0, 1, 'i' }, // → 2; load the int value 2 onto the stack NOLINT(*) -{ "iconst_3", 0x06, ' ', 0, 1, 'i' }, // → 3; load the int value 3 onto the stack NOLINT(*) -{ "iconst_4", 0x07, ' ', 0, 1, 'i' }, // → 4; load the int value 4 onto the stack NOLINT(*) -{ "iconst_5", 0x08, ' ', 0, 1, 'i' }, // → 5; load the int value 5 onto the stack NOLINT(*) -{ "idiv", 0x6c, ' ', 2, 1, 'i' }, // value1, value2 → result; divide two integers NOLINT(*) -{ "if_acmpeq", 0xa5, 'o', 2, 0, ' ' }, // value1, value2 →; if references are equal, branch to instruction at branchoffset (signed short constructed from unsigned bytes branchbyte1 << 8 + branchbyte2) NOLINT(*) -{ "if_acmpne", 0xa6, 'o', 2, 0, ' ' }, // value1, value2 →; if references are not equal, branch to instruction at branchoffset (signed short constructed from unsigned bytes branchbyte1 << 8 + branchbyte2) NOLINT(*) -{ "if_icmpeq", 0x9f, 'o', 2, 0, ' ' }, // value1, value2 →; if ints are equal, branch to instruction at branchoffset (signed short constructed from unsigned bytes branchbyte1 << 8 + branchbyte2) NOLINT(*) -{ "if_icmpne", 0xa0, 'o', 2, 0, ' ' }, // value1, value2 →; if ints are not equal, branch to instruction at branchoffset (signed short constructed from unsigned bytes branchbyte1 << 8 + branchbyte2) NOLINT(*) -{ "if_icmplt", 0xa1, 'o', 2, 0, ' ' }, // value1, value2 →; if value1 is less than value2, branch to instruction at branchoffset (signed short constructed from unsigned bytes branchbyte1 << 8 + branchbyte2) NOLINT(*) -{ "if_icmpge", 0xa2, 'o', 2, 0, ' ' }, // value1, value2 →; if value1 is greater than or equal to value2, branch to instruction at branchoffset (signed short constructed from unsigned bytes branchbyte1 << 8 + branchbyte2) NOLINT(*) -{ "if_icmpgt", 0xa3, 'o', 2, 0, ' ' }, // value1, value2 →; if value1 is greater than value2, branch to instruction at branchoffset (signed short constructed from unsigned bytes branchbyte1 << 8 + branchbyte2) NOLINT(*) -{ "if_icmple", 0xa4, 'o', 2, 0, ' ' }, // value1, value2 →; if value1 is less than or equal to value2, branch to instruction at branchoffset (signed short constructed from unsigned bytes branchbyte1 << 8 + branchbyte2) NOLINT(*) +{ "lcmp", 0x94, ' ', 2, 1, 'i' }, // value1, value2 → result; compare two long values NOLINT(*) +{ "fcmpl", 0x95, ' ', 2, 1, 'i' }, // value1, value2 → result; compare two floats NOLINT(*) +{ "fcmpg", 0x96, ' ', 2, 1, 'i' }, // value1, value2 → result; compare two floats NOLINT(*) +{ "dcmpl", 0x97, ' ', 2, 1, 'i' }, // value1, value2 → result; compare two doubles NOLINT(*) +{ "dcmpg", 0x98, ' ', 2, 1, 'i' }, // value1, value2 → result; compare two doubles NOLINT(*) { "ifeq", 0x99, 'o', 1, 0, ' ' }, // value →; if value is 0, branch to instruction at branchoffset (signed short constructed from unsigned bytes branchbyte1 << 8 + branchbyte2) NOLINT(*) { "ifne", 0x9a, 'o', 1, 0, ' ' }, // value →; if value is not 0, branch to instruction at branchoffset (signed short constructed from unsigned bytes branchbyte1 << 8 + branchbyte2) NOLINT(*) { "iflt", 0x9b, 'o', 1, 0, ' ' }, // value →; if value is less than 0, branch to instruction at branchoffset (signed short constructed from unsigned bytes branchbyte1 << 8 + branchbyte2) NOLINT(*) { "ifge", 0x9c, 'o', 1, 0, ' ' }, // value →; if value is greater than or equal to 0, branch to instruction at branchoffset (signed short constructed from unsigned bytes branchbyte1 << 8 + branchbyte2) NOLINT(*) { "ifgt", 0x9d, 'o', 1, 0, ' ' }, // value →; if value is greater than 0, branch to instruction at branchoffset (signed short constructed from unsigned bytes branchbyte1 << 8 + branchbyte2) NOLINT(*) { "ifle", 0x9e, 'o', 1, 0, ' ' }, // value →; if value is less than or equal to 0, branch to instruction at branchoffset (signed short constructed from unsigned bytes branchbyte1 << 8 + branchbyte2) NOLINT(*) -{ "ifnonnull", 0xc7, 'o', 1, 0, ' ' }, // value →; if value is not null, branch to instruction at branchoffset (signed short constructed from unsigned bytes branchbyte1 << 8 + branchbyte2) NOLINT(*) -{ "ifnull", 0xc6, 'o', 1, 0, ' ' }, // value →; if value is null, branch to instruction at branchoffset (signed short constructed from unsigned bytes branchbyte1 << 8 + branchbyte2) NOLINT(*) -{ "iinc", 0x84, 'V', 0, 0, ' ' }, // [No change]; increment local variable #index by signed byte const NOLINT(*) -{ "iload", 0x15, 'v', 0, 1, 'i' }, // → value; load an int value from a local variable #index NOLINT(*) -{ "iload_0", 0x1a, ' ', 0, 1, 'i' }, // → value; load an int value from local variable 0 NOLINT(*) -{ "iload_1", 0x1b, ' ', 0, 1, 'i' }, // → value; load an int value from local variable 1 NOLINT(*) -{ "iload_2", 0x1c, ' ', 0, 1, 'i' }, // → value; load an int value from local variable 2 NOLINT(*) -{ "iload_3", 0x1d, ' ', 0, 1, 'i' }, // → value; load an int value from local variable 3 NOLINT(*) -{ "imul", 0x68, ' ', 2, 1, 'i' }, // value1, value2 → result; multiply two integers NOLINT(*) -{ "ineg", 0x74, ' ', 1, 1, 'i' }, // value → result; negate int NOLINT(*) -{ "instanceof", 0xc1, 'C', 1, 1, ' ' }, // objectref → result; determines if an object objectref is of a given type, identified by class reference index in constant pool (indexbyte1 << 8 + indexbyte2) NOLINT(*) -{ "invokedynamic", 0xba, 'I', 0, 0, ' ' }, // [arg1, [arg2 ...]] →; invokes a dynamic method identified by method reference index in constant pool (indexbyte1 << 8 + indexbyte2) NOLINT(*) -{ "invokeinterface", 0xb9, 'I', 0, 0, ' ' }, // objectref, [arg1, arg2, ...] →; invokes an interface method on object objectref, where the interface method is identified by method reference index in constant pool (indexbyte1 << 8 + indexbyte2) NOLINT(*) -{ "invokespecial", 0xb7, 'C', 0, 0, ' ' }, // objectref, [arg1, arg2, ...] →; invoke instance method on object objectref, where the method is identified by method reference index in constant pool (indexbyte1 << 8 + indexbyte2) NOLINT(*) -{ "invokestatic", 0xb8, 'C', 0, 0, ' ' }, // [arg1, arg2, ...] →; invoke a static method, where the method is identified by method reference index in constant pool (indexbyte1 << 8 + indexbyte2) NOLINT(*) -{ "invokevirtual", 0xb6, 'C', 0, 0, ' ' }, // objectref, [arg1, arg2, ...] →; invoke virtual method on object objectref, where the method is identified by method reference index in constant pool (indexbyte1 << 8 + indexbyte2) NOLINT(*) -{ "ior", 0x80, ' ', 2, 1, 'i' }, // value1, value2 → result; bitwise int or NOLINT(*) -{ "irem", 0x70, ' ', 2, 1, 'i' }, // value1, value2 → result; logical int remainder NOLINT(*) -{ "ireturn", 0xac, ' ', 1, 0, ' ' }, // value → [empty]; return an integer from a method NOLINT(*) -{ "ishl", 0x78, ' ', 2, 1, 'i' }, // value1, value2 → result; int shift left NOLINT(*) -{ "ishr", 0x7a, ' ', 2, 1, 'i' }, // value1, value2 → result; int arithmetic shift right NOLINT(*) -{ "istore", 0x36, 'v', 1, 0, ' ' }, // value →; store int value into variable #index NOLINT(*) -{ "istore_0", 0x3b, ' ', 1, 0, ' ' }, // value →; store int value into variable 0 NOLINT(*) -{ "istore_1", 0x3c, ' ', 1, 0, ' ' }, // value →; store int value into variable 1 NOLINT(*) -{ "istore_2", 0x3d, ' ', 1, 0, ' ' }, // value →; store int value into variable 2 NOLINT(*) -{ "istore_3", 0x3e, ' ', 1, 0, ' ' }, // value →; store int value into variable 3 NOLINT(*) -{ "isub", 0x64, ' ', 2, 1, 'i' }, // value1, value2 → result; int subtract NOLINT(*) -{ "iushr", 0x7c, ' ', 2, 1, 'i' }, // value1, value2 → result; int logical shift right NOLINT(*) -{ "ixor", 0x82, ' ', 2, 1, 'i' }, // value1, value2 → result; int xor NOLINT(*) +{ "if_icmpeq", 0x9f, 'o', 2, 0, ' ' }, // value1, value2 →; if ints are equal, branch to instruction at branchoffset (signed short constructed from unsigned bytes branchbyte1 << 8 + branchbyte2) NOLINT(*) +{ "if_icmpne", 0xa0, 'o', 2, 0, ' ' }, // value1, value2 →; if ints are not equal, branch to instruction at branchoffset (signed short constructed from unsigned bytes branchbyte1 << 8 + branchbyte2) NOLINT(*) +{ "if_icmplt", 0xa1, 'o', 2, 0, ' ' }, // value1, value2 →; if value1 is less than value2, branch to instruction at branchoffset (signed short constructed from unsigned bytes branchbyte1 << 8 + branchbyte2) NOLINT(*) +{ "if_icmpge", 0xa2, 'o', 2, 0, ' ' }, // value1, value2 →; if value1 is greater than or equal to value2, branch to instruction at branchoffset (signed short constructed from unsigned bytes branchbyte1 << 8 + branchbyte2) NOLINT(*) +{ "if_icmpgt", 0xa3, 'o', 2, 0, ' ' }, // value1, value2 →; if value1 is greater than value2, branch to instruction at branchoffset (signed short constructed from unsigned bytes branchbyte1 << 8 + branchbyte2) NOLINT(*) +{ "if_icmple", 0xa4, 'o', 2, 0, ' ' }, // value1, value2 →; if value1 is less than or equal to value2, branch to instruction at branchoffset (signed short constructed from unsigned bytes branchbyte1 << 8 + branchbyte2) NOLINT(*) +{ "if_acmpeq", 0xa5, 'o', 2, 0, ' ' }, // value1, value2 →; if references are equal, branch to instruction at branchoffset (signed short constructed from unsigned bytes branchbyte1 << 8 + branchbyte2) NOLINT(*) +{ "if_acmpne", 0xa6, 'o', 2, 0, ' ' }, // value1, value2 →; if references are not equal, branch to instruction at branchoffset (signed short constructed from unsigned bytes branchbyte1 << 8 + branchbyte2) NOLINT(*) +{ "goto", 0xa7, 'o', 0, 0, ' ' }, // [no change]; goes to another instruction at branchoffset (signed short constructed from unsigned bytes branchbyte1 << 8 + branchbyte2) NOLINT(*) { "jsr", 0xa8, 'o', 0, 1, 'a' }, // → address; jump to subroutine at branchoffset (signed short constructed from unsigned bytes branchbyte1 << 8 + branchbyte2) and place the return address on the stack NOLINT(*) -{ "jsr_w", 0xc9, 'O', 0, 1, 'a' }, // → address; jump to subroutine at branchoffset (signed int constructed from unsigned bytes branchbyte1 << 24 + branchbyte2 << 16 + branchbyte3 << 8 + branchbyte4) and place the return address on the stack NOLINT(*) -{ "ladd", 0x61, ' ', 2, 1, 'l' }, // value1, value2 → result; add two longs NOLINT(*) -{ "laload", 0x2f, ' ', 2, 1, 'l' }, // arrayref, index → value; load a long from an array NOLINT(*) -{ "land", 0x7f, ' ', 2, 1, 'l' }, // value1, value2 → result; bitwise and of two longs NOLINT(*) -{ "lastore", 0x50, ' ', 3, 0, ' ' }, // arrayref, index, value →; store a long to an array NOLINT(*) -{ "lcmp", 0x94, ' ', 2, 1, 'i' }, // value1, value2 → result; compare two long values NOLINT(*) -{ "lconst_0", 0x09, ' ', 0, 1, 'l' }, // → 0L; push the long 0 onto the stack NOLINT(*) -{ "lconst_1", 0x0a, ' ', 0, 1, 'l' }, // → 1L; push the long 1 onto the stack NOLINT(*) -{ "ldc", 0x12, 'c', 0, 1, ' ' }, // → value; push a constant #index from a constant pool (String, int or float) onto the stack NOLINT(*) -{ "ldc_w", 0x13, 'C', 0, 1, ' ' }, // → value; push a constant #index from a constant pool (String, int or float) onto the stack (wide index is constructed as indexbyte1 << 8 + indexbyte2) NOLINT(*) -{ "ldc2_w", 0x14, 'C', 0, 1, ' ' }, // → value; push a constant #index from a constant pool (double or long) onto the stack (wide index is constructed as indexbyte1 << 8 + indexbyte2) NOLINT(*) -{ "ldiv", 0x6d, ' ', 2, 1, 'l' }, // value1, value2 → result; divide two longs NOLINT(*) -{ "lload", 0x16, 'v', 0, 1, 'l' }, // → value; load a long value from a local variable #index NOLINT(*) -{ "lload_0", 0x1e, ' ', 0, 1, 'l' }, // → value; load a long value from a local variable 0 NOLINT(*) -{ "lload_1", 0x1f, ' ', 0, 1, 'l' }, // → value; load a long value from a local variable 1 NOLINT(*) -{ "lload_2", 0x20, ' ', 0, 1, 'l' }, // → value; load a long value from a local variable 2 NOLINT(*) -{ "lload_3", 0x21, ' ', 0, 1, 'l' }, // → value; load a long value from a local variable 3 NOLINT(*) -{ "lmul", 0x69, ' ', 2, 1, 'l' }, // value1, value2 → result; multiply two longs NOLINT(*) -{ "lneg", 0x75, ' ', 1, 1, 'l' }, // value → result; negate a long NOLINT(*) +{ "ret", 0xa9, 'v', 0, 0, ' ' }, // [No change]; continue execution from address taken from a local variable #index (the asymmetry with jsr is intentional) NOLINT(*) +{ "tableswitch", 0xaa, 'T', 1, 0, ' ' }, // index →; continue execution from an address in the table at offset index NOLINT(*) { "lookupswitch", 0xab, 'L', 1, 0, ' ' }, // key →; a target address is looked up from a table using a key and execution continues from the instruction at that address NOLINT(*) -{ "lor", 0x81, ' ', 2, 1, 'l' }, // value1, value2 → result; bitwise or of two longs NOLINT(*) -{ "lrem", 0x71, ' ', 2, 1, 'l' }, // value1, value2 → result; remainder of division of two longs NOLINT(*) +{ "ireturn", 0xac, ' ', 1, 0, ' ' }, // value → [empty]; return an integer from a method NOLINT(*) { "lreturn", 0xad, ' ', 1, 0, ' ' }, // value → [empty]; return a long value NOLINT(*) -{ "lshl", 0x79, ' ', 2, 1, 'l' }, // value1, value2 → result; bitwise shift left of a long value1 by value2 positions NOLINT(*) -{ "lshr", 0x7b, ' ', 2, 1, 'l' }, // value1, value2 → result; bitwise shift right of a long value1 by value2 positions NOLINT(*) -{ "lstore", 0x37, 'v', 1, 0, ' ' }, // value →; store a long value in a local variable #index NOLINT(*) -{ "lstore_0", 0x3f, ' ', 1, 0, ' ' }, // value →; store a long value in a local variable 0 NOLINT(*) -{ "lstore_1", 0x40, ' ', 1, 0, ' ' }, // value →; store a long value in a local variable 1 NOLINT(*) -{ "lstore_2", 0x41, ' ', 1, 0, ' ' }, // value →; store a long value in a local variable 2 NOLINT(*) -{ "lstore_3", 0x42, ' ', 1, 0, ' ' }, // value →; store a long value in a local variable 3 NOLINT(*) -{ "lsub", 0x65, ' ', 2, 1, 'l' }, // value1, value2 → result; subtract two longs NOLINT(*) -{ "lushr", 0x7d, ' ', 2, 1, 'l' }, // value1, value2 → result; bitwise shift right of a long value1 by value2 positions, unsigned NOLINT(*) -{ "lxor", 0x83, ' ', 2, 1, 'l' }, // value1, value2 → result; bitwise exclusive or of two longs NOLINT(*) +{ "freturn", 0xae, ' ', 1, 0, ' ' }, // value → [empty]; return a float NOLINT(*) +{ "dreturn", 0xaf, ' ', 1, 0, ' ' }, // value → [empty]; return a double from a method NOLINT(*) +{ "areturn", 0xb0, ' ', 1, 0, ' ' }, // objectref → [empty]; return a reference from a method NOLINT(*) +{ "return", 0xb1, ' ', 0, 0, ' ' }, // → [empty]; return void from method NOLINT(*) +{ "getstatic", 0xb2, 'C', 0, 1, ' ' }, // → value; get a static field value of a class, where the field is identified by field reference in the constant pool index (index1 << 8 + index2) NOLINT(*) +{ "putstatic", 0xb3, 'C', 1, 0, ' ' }, // value →; set static field to value in a class, where the field is identified by a field reference index in constant pool (indexbyte1 << 8 + indexbyte2) NOLINT(*) +{ "getfield", 0xb4, 'C', 1, 1, ' ' }, // objectref → value; get a field value of an object objectref, where the field is identified by field reference in the constant pool index (index1 << 8 + index2) NOLINT(*) +{ "putfield", 0xb5, 'C', 2, 0, ' ' }, // objectref, value →; set field to value in an object objectref, where the field is identified by a field reference index in constant pool (indexbyte1 << 8 + indexbyte2) NOLINT(*) +{ "invokevirtual", 0xb6, 'C', 0, 0, ' ' }, // objectref, [arg1, arg2, ...] →; invoke virtual method on object objectref, where the method is identified by method reference index in constant pool (indexbyte1 << 8 + indexbyte2) NOLINT(*) +{ "invokespecial", 0xb7, 'C', 0, 0, ' ' }, // objectref, [arg1, arg2, ...] →; invoke instance method on object objectref, where the method is identified by method reference index in constant pool (indexbyte1 << 8 + indexbyte2) NOLINT(*) +{ "invokestatic", 0xb8, 'C', 0, 0, ' ' }, // [arg1, arg2, ...] →; invoke a static method, where the method is identified by method reference index in constant pool (indexbyte1 << 8 + indexbyte2) NOLINT(*) +{ "invokeinterface", 0xb9, 'I', 0, 0, ' ' }, // objectref, [arg1, arg2, ...] →; invokes an interface method on object objectref, where the interface method is identified by method reference index in constant pool (indexbyte1 << 8 + indexbyte2) NOLINT(*) +{ "invokedynamic", 0xba, 'I', 0, 0, ' ' }, // [arg1, [arg2 ...]] →; invokes a dynamic method identified by method reference index in constant pool (indexbyte1 << 8 + indexbyte2) NOLINT(*) +{ "new", 0xbb, 'C', 0, 1, 'a' }, // → objectref; create new object of type identified by class reference in constant pool index (indexbyte1 << 8 + indexbyte2) NOLINT(*) +{ "newarray", 0xbc, 't', 1, 1, 'a' }, // count → arrayref; create new array with count elements of primitive type identified by atype NOLINT(*) +{ "anewarray", 0xbd, 'C', 1, 1, 'a' }, // count → arrayref; create a new array of references of length count and component type identified by the class reference index (indexbyte1 << 8 + indexbyte2) in the constant pool NOLINT(*) +{ "arraylength", 0xbe, ' ', 1, 1, 'i' }, // arrayref → length; get the length of an array NOLINT(*) +{ "athrow", 0xbf, ' ', 1, 1, ' ' }, // objectref → [empty], objectref; throws an error or exception (notice that the rest of the stack is cleared, leaving only a reference to the Throwable) NOLINT(*) +{ "checkcast", 0xc0, 'C', 1, 1, 'a' }, // objectref → objectref; checks whether an objectref is of a certain type, the class reference of which is in the constant pool at index (indexbyte1 << 8 + indexbyte2) NOLINT(*) +{ "instanceof", 0xc1, 'C', 1, 1, ' ' }, // objectref → result; determines if an object objectref is of a given type, identified by class reference index in constant pool (indexbyte1 << 8 + indexbyte2) NOLINT(*) { "monitorenter", 0xc2, ' ', 1, 0, ' ' }, // objectref →; enter monitor for object ("grab the lock" - start of synchronized() section) NOLINT(*) { "monitorexit", 0xc3, ' ', 1, 0, ' ' }, // objectref →; exit monitor for object ("release the lock" - end of synchronized() section) NOLINT(*) +{ "wide", 0xc4, ' ', 0, 0, ' ' }, // modifier for others NOLINT(*) { "multianewarray", 0xc5, 'm', 0, 1, 'a' }, // count1, [count2,...] → arrayref; create a new array of dimensions dimensions with elements of type identified by class reference in constant pool index (indexbyte1 << 8 + indexbyte2); the sizes of each dimension is identified by count1, [count2, etc.] NOLINT(*) -{ "new", 0xbb, 'C', 0, 1, 'a' }, // → objectref; create new object of type identified by class reference in constant pool index (indexbyte1 << 8 + indexbyte2) NOLINT(*) -{ "newarray", 0xbc, 't', 1, 1, 'a' }, // count → arrayref; create new array with count elements of primitive type identified by atype NOLINT(*) -{ "nop", 0x00, ' ', 0, 0, ' ' }, // [No change]; perform no operation NOLINT(*) -{ "pop", 0x57, ' ', 1, 0, ' ' }, // value →; discard the top value on the stack NOLINT(*) -{ "pop2", 0x58, ' ', 1, 0, ' ' }, // {value2, value1} →; discard the top two values on the stack (or one value, if it is a double or long) NOLINT(*) -{ "putfield", 0xb5, 'C', 2, 0, ' ' }, // objectref, value →; set field to value in an object objectref, where the field is identified by a field reference index in constant pool (indexbyte1 << 8 + indexbyte2) NOLINT(*) -{ "putstatic", 0xb3, 'C', 1, 0, ' ' }, // value →; set static field to value in a class, where the field is identified by a field reference index in constant pool (indexbyte1 << 8 + indexbyte2) NOLINT(*) -{ "ret", 0xa9, 'v', 0, 0, ' ' }, // [No change]; continue execution from address taken from a local variable #index (the asymmetry with jsr is intentional) NOLINT(*) -{ "return", 0xb1, ' ', 0, 0, ' ' }, // → [empty]; return void from method NOLINT(*) -{ "saload", 0x35, ' ', 2, 1, 's' }, // arrayref, index → value; load short from array NOLINT(*) -{ "sastore", 0x56, ' ', 3, 0, 's' }, // arrayref, index, value →; store short to array NOLINT(*) -{ "sipush", 0x11, 's', 0, 1, 'i' }, // → value; push a short onto the stack as an integer value NOLINT(*) -{ "swap", 0x5f, ' ', 2, 2, ' ' }, // value2, value1 → value1, value2; swaps two top words on the stack (note that value1 and value2 must not be double or long) NOLINT(*) -{ "tableswitch", 0xaa, 'T', 1, 0, ' ' }, // index →; continue execution from an address in the table at offset index NOLINT(*) +{ "ifnull", 0xc6, 'o', 1, 0, ' ' }, // value →; if value is null, branch to instruction at branchoffset (signed short constructed from unsigned bytes branchbyte1 << 8 + branchbyte2) NOLINT(*) +{ "ifnonnull", 0xc7, 'o', 1, 0, ' ' }, // value →; if value is not null, branch to instruction at branchoffset (signed short constructed from unsigned bytes branchbyte1 << 8 + branchbyte2) NOLINT(*) +{ "goto_w", 0xc8, 'O', 0, 0, ' ' }, // [no change]; goes to another instruction at branchoffset (signed int constructed from unsigned bytes branchbyte1 << 24 + branchbyte2 << 16 + branchbyte3 << 8 + branchbyte4) NOLINT(*) +{ "jsr_w", 0xc9, 'O', 0, 1, 'a' }, // → address; jump to subroutine at branchoffset (signed int constructed from unsigned bytes branchbyte1 << 24 + branchbyte2 << 16 + branchbyte3 << 8 + branchbyte4) and place the return address on the stack NOLINT(*) { "breakpoint", 0xca, ' ', 0, 0, ' ' }, // ; reserved for breakpoints in Java debuggers; should not appear in any class file NOLINT(*) +{ nullptr, 0xcb, '\0',0, 0, '\0'}, // zero-initialized NOLINT (*) +{ nullptr, 0xcc, '\0',0, 0, '\0'}, // zero-initialized NOLINT (*) +{ nullptr, 0xcd, '\0',0, 0, '\0'}, // zero-initialized NOLINT (*) +{ nullptr, 0xce, '\0',0, 0, '\0'}, // zero-initialized NOLINT (*) +{ nullptr, 0xcf, '\0',0, 0, '\0'}, // zero-initialized NOLINT (*) +{ nullptr, 0xd0, '\0',0, 0, '\0'}, // zero-initialized NOLINT (*) +{ nullptr, 0xd1, '\0',0, 0, '\0'}, // zero-initialized NOLINT (*) +{ nullptr, 0xd2, '\0',0, 0, '\0'}, // zero-initialized NOLINT (*) +{ nullptr, 0xd3, '\0',0, 0, '\0'}, // zero-initialized NOLINT (*) +{ nullptr, 0xd4, '\0',0, 0, '\0'}, // zero-initialized NOLINT (*) +{ nullptr, 0xd5, '\0',0, 0, '\0'}, // zero-initialized NOLINT (*) +{ nullptr, 0xd6, '\0',0, 0, '\0'}, // zero-initialized NOLINT (*) +{ nullptr, 0xd7, '\0',0, 0, '\0'}, // zero-initialized NOLINT (*) +{ nullptr, 0xd8, '\0',0, 0, '\0'}, // zero-initialized NOLINT (*) +{ nullptr, 0xd9, '\0',0, 0, '\0'}, // zero-initialized NOLINT (*) +{ nullptr, 0xda, '\0',0, 0, '\0'}, // zero-initialized NOLINT (*) +{ nullptr, 0xdb, '\0',0, 0, '\0'}, // zero-initialized NOLINT (*) +{ nullptr, 0xdc, '\0',0, 0, '\0'}, // zero-initialized NOLINT (*) +{ nullptr, 0xdd, '\0',0, 0, '\0'}, // zero-initialized NOLINT (*) +{ nullptr, 0xde, '\0',0, 0, '\0'}, // zero-initialized NOLINT (*) +{ nullptr, 0xdf, '\0',0, 0, '\0'}, // zero-initialized NOLINT (*) +{ nullptr, 0xe0, '\0',0, 0, '\0'}, // zero-initialized NOLINT (*) +{ nullptr, 0xe1, '\0',0, 0, '\0'}, // zero-initialized NOLINT (*) +{ nullptr, 0xe2, '\0',0, 0, '\0'}, // zero-initialized NOLINT (*) +{ nullptr, 0xe3, '\0',0, 0, '\0'}, // zero-initialized NOLINT (*) +{ nullptr, 0xe4, '\0',0, 0, '\0'}, // zero-initialized NOLINT (*) +{ nullptr, 0xe5, '\0',0, 0, '\0'}, // zero-initialized NOLINT (*) +{ nullptr, 0xe6, '\0',0, 0, '\0'}, // zero-initialized NOLINT (*) +{ nullptr, 0xe7, '\0',0, 0, '\0'}, // zero-initialized NOLINT (*) +{ nullptr, 0xe8, '\0',0, 0, '\0'}, // zero-initialized NOLINT (*) +{ nullptr, 0xe9, '\0',0, 0, '\0'}, // zero-initialized NOLINT (*) +{ nullptr, 0xea, '\0',0, 0, '\0'}, // zero-initialized NOLINT (*) +{ nullptr, 0xeb, '\0',0, 0, '\0'}, // zero-initialized NOLINT (*) +{ nullptr, 0xec, '\0',0, 0, '\0'}, // zero-initialized NOLINT (*) +{ nullptr, 0xed, '\0',0, 0, '\0'}, // zero-initialized NOLINT (*) +{ nullptr, 0xee, '\0',0, 0, '\0'}, // zero-initialized NOLINT (*) +{ nullptr, 0xef, '\0',0, 0, '\0'}, // zero-initialized NOLINT (*) +{ nullptr, 0xf0, '\0',0, 0, '\0'}, // zero-initialized NOLINT (*) +{ nullptr, 0xf1, '\0',0, 0, '\0'}, // zero-initialized NOLINT (*) +{ nullptr, 0xf2, '\0',0, 0, '\0'}, // zero-initialized NOLINT (*) +{ nullptr, 0xf3, '\0',0, 0, '\0'}, // zero-initialized NOLINT (*) +{ nullptr, 0xf4, '\0',0, 0, '\0'}, // zero-initialized NOLINT (*) +{ nullptr, 0xf5, '\0',0, 0, '\0'}, // zero-initialized NOLINT (*) +{ nullptr, 0xf6, '\0',0, 0, '\0'}, // zero-initialized NOLINT (*) +{ nullptr, 0xf7, '\0',0, 0, '\0'}, // zero-initialized NOLINT (*) +{ nullptr, 0xf8, '\0',0, 0, '\0'}, // zero-initialized NOLINT (*) +{ nullptr, 0xf9, '\0',0, 0, '\0'}, // zero-initialized NOLINT (*) +{ nullptr, 0xfa, '\0',0, 0, '\0'}, // zero-initialized NOLINT (*) +{ nullptr, 0xfb, '\0',0, 0, '\0'}, // zero-initialized NOLINT (*) +{ nullptr, 0xfc, '\0',0, 0, '\0'}, // zero-initialized NOLINT (*) +{ nullptr, 0xfd, '\0',0, 0, '\0'}, // zero-initialized NOLINT (*) { "impdep1", 0xfe, ' ', 0, 0, ' ' }, // ; reserved for implementation-dependent operations within debuggers; should not appear in any class file NOLINT(*) { "impdep2", 0xff, ' ', 0, 0, ' ' }, // ; reserved for implementation-dependent operations within debuggers; should not appear in any class file NOLINT(*) -{ "wide", 0xc4, ' ', 0, 0, ' ' }, // modifier for others NOLINT(*) -{ nullptr, 0x00, '\0',0, 0, '\0'}, // zero-initialized NOLINT (*) }; // clang-format on + +static_assert( + sizeof(bytecode_info) == sizeof(bytecode_infot) * 256, + "bytecode table has right size"); diff --git a/jbmc/src/java_bytecode/java_bytecode_convert_method.cpp b/jbmc/src/java_bytecode/java_bytecode_convert_method.cpp index d6af61dfbd4..8274e3f2227 100644 --- a/jbmc/src/java_bytecode/java_bytecode_convert_method.cpp +++ b/jbmc/src/java_bytecode/java_bytecode_convert_method.cpp @@ -590,18 +590,6 @@ void java_bytecode_convert_methodt::convert( to_java_class_type(class_symbol.type).lambda_method_handles()); } -const bytecode_infot &java_bytecode_convert_methodt::get_bytecode_info( - const irep_idt &statement) -{ - for(const bytecode_infot *p=bytecode_info; p->mnemonic!=nullptr; p++) - if(statement==p->mnemonic) - return *p; - - error() << "failed to find bytecode mnemonic `" - << statement << '\'' << eom; - throw 0; -} - static irep_idt get_if_cmp_operator(const irep_idt &stmt) { if(stmt==patternt("if_?cmplt")) @@ -1007,14 +995,16 @@ code_blockt java_bytecode_convert_methodt::convert_instructions( // a new maximal key assert(a_entry.first==--address_map.end()); + const std::string statement = bytecode_info[i_it->bytecode].mnemonic; + // clang-format off - if(i_it->statement != "goto" && - i_it->statement != "return" && - i_it->statement != patternt("?return") && - i_it->statement != "athrow" && - i_it->statement != "jsr" && - i_it->statement != "jsr_w" && - i_it->statement != "ret") + if(statement != "goto" && + statement != "return" && + statement != patternt("?return") && + statement != "athrow" && + statement != "jsr" && + statement != "jsr_w" && + statement != "ret") { // clang-format on instructionst::const_iterator next=i_it; @@ -1022,25 +1012,27 @@ code_blockt java_bytecode_convert_methodt::convert_instructions( a_entry.first->second.successors.push_back(next->address); } - if(i_it->statement=="athrow" || - i_it->statement=="putfield" || - i_it->statement=="getfield" || - i_it->statement=="checkcast" || - i_it->statement=="newarray" || - i_it->statement=="anewarray" || - i_it->statement=="idiv" || - i_it->statement=="ldiv" || - i_it->statement=="irem" || - i_it->statement=="lrem" || - i_it->statement==patternt("?astore") || - i_it->statement==patternt("?aload") || - i_it->statement=="invokestatic" || - i_it->statement=="invokevirtual" || - i_it->statement=="invokespecial" || - i_it->statement=="invokeinterface" || - (threading_support && (i_it->statement=="monitorenter" || - i_it->statement=="monitorexit"))) + // clang-format off + if(statement == "athrow" || + statement == "putfield" || + statement == "getfield" || + statement == "checkcast" || + statement == "newarray" || + statement == "anewarray" || + statement == "idiv" || + statement == "ldiv" || + statement == "irem" || + statement == "lrem" || + statement == patternt("?astore") || + statement == patternt("?aload") || + statement == "invokestatic" || + statement == "invokevirtual" || + statement == "invokespecial" || + statement == "invokeinterface" || + (threading_support && + (statement == "monitorenter" || statement == "monitorexit"))) { + // clang-format on const std::vector handler = try_catch_handler(i_it->address, method.exception_table); std::list &successors = a_entry.first->second.successors; @@ -1048,14 +1040,16 @@ code_blockt java_bytecode_convert_methodt::convert_instructions( targets.insert(handler.begin(), handler.end()); } - if(i_it->statement=="goto" || - i_it->statement==patternt("if_?cmp??") || - i_it->statement==patternt("if??") || - i_it->statement=="ifnonnull" || - i_it->statement=="ifnull" || - i_it->statement=="jsr" || - i_it->statement=="jsr_w") + // clang-format off + if(statement == "goto" || + statement == patternt("if_?cmp??") || + statement == patternt("if??") || + statement == "ifnonnull" || + statement == "ifnull" || + statement == "jsr" || + statement == "jsr_w") { + // clang-format on PRECONDITION(!i_it->args.empty()); auto target = numeric_cast_v(to_constant_expr(i_it->args[0])); @@ -1063,8 +1057,7 @@ code_blockt java_bytecode_convert_methodt::convert_instructions( a_entry.first->second.successors.push_back(target); - if(i_it->statement=="jsr" || - i_it->statement=="jsr_w") + if(statement == "jsr" || statement == "jsr_w") { auto next = std::next(i_it); DATA_INVARIANT( @@ -1073,8 +1066,7 @@ code_blockt java_bytecode_convert_methodt::convert_instructions( jsr_ret_targets.push_back(next->address); } } - else if(i_it->statement=="tableswitch" || - i_it->statement=="lookupswitch") + else if(statement == "tableswitch" || statement == "lookupswitch") { bool is_label=true; for(const auto &arg : i_it->args) @@ -1088,7 +1080,7 @@ code_blockt java_bytecode_convert_methodt::convert_instructions( is_label=!is_label; } } - else if(i_it->statement=="ret") + else if(statement == "ret") { // Finish these later, once we've seen all jsr instructions. ret_instructions.push_back(i_it); @@ -1144,11 +1136,11 @@ code_blockt java_bytecode_convert_methodt::convert_instructions( stack.empty() || instruction.predecessors.size() <= 1 || has_prefix(stack.front().get_string(ID_C_base_name), "$stack")); - irep_idt statement=i_it->statement; exprt arg0=i_it->args.size()>=1?i_it->args[0]:nil_exprt(); exprt arg1=i_it->args.size()>=2?i_it->args[1]:nil_exprt(); - const bytecode_infot &stmt_bytecode_info = get_bytecode_info(statement); + const bytecode_infot &stmt_bytecode_info = bytecode_info[i_it->bytecode]; + std::string statement = stmt_bytecode_info.mnemonic; // deal with _idx suffixes if(statement.size()>=2 && diff --git a/jbmc/src/java_bytecode/java_bytecode_convert_method_class.h b/jbmc/src/java_bytecode/java_bytecode_convert_method_class.h index fab0ff46b42..8df90a98e22 100644 --- a/jbmc/src/java_bytecode/java_bytecode_convert_method_class.h +++ b/jbmc/src/java_bytecode/java_bytecode_convert_method_class.h @@ -304,8 +304,6 @@ class java_bytecode_convert_methodt:public messaget const methodt &, const java_class_typet::java_lambda_method_handlest &); - const bytecode_infot &get_bytecode_info(const irep_idt &statement); - codet get_clinit_call(const irep_idt &classname); bool is_method_inherited( diff --git a/jbmc/src/java_bytecode/java_bytecode_language.cpp b/jbmc/src/java_bytecode/java_bytecode_language.cpp index 2506bc3cb8c..0abc95283d2 100644 --- a/jbmc/src/java_bytecode/java_bytecode_language.cpp +++ b/jbmc/src/java_bytecode/java_bytecode_language.cpp @@ -316,8 +316,9 @@ static void infer_opaque_type_fields( for(const java_bytecode_parse_treet::instructiont &instruction : method.instructions) { - if(instruction.statement == "getfield" || - instruction.statement == "putfield") + const std::string statement = + bytecode_info[instruction.bytecode].mnemonic; + if(statement == "getfield" || statement == "putfield") { const fieldref_exprt &fieldref = expr_dynamic_cast(instruction.args[0]); @@ -461,11 +462,15 @@ static void generate_constant_global_variables( { // ldc* instructions are Java bytecode "load constant" ops, which can // retrieve a numeric constant, String literal, or Class literal. - if(instruction.statement == "ldc" || - instruction.statement == "ldc2" || - instruction.statement == "ldc_w" || - instruction.statement == "ldc2_w") + const std::string statement = + bytecode_info[instruction.bytecode].mnemonic; + // clang-format off + if(statement == "ldc" || + statement == "ldc2" || + statement == "ldc_w" || + statement == "ldc2_w") { + // clang-format on INVARIANT( instruction.args.size() != 0, "ldc instructions should have an argument"); @@ -589,8 +594,9 @@ static void create_stub_global_symbols( for(const java_bytecode_parse_treet::instructiont &instruction : method.instructions) { - if(instruction.statement == "getstatic" || - instruction.statement == "putstatic") + const std::string statement = + bytecode_info[instruction.bytecode].mnemonic; + if(statement == "getstatic" || statement == "putstatic") { INVARIANT( instruction.args.size() > 0, diff --git a/jbmc/src/java_bytecode/java_bytecode_parse_tree.cpp b/jbmc/src/java_bytecode/java_bytecode_parse_tree.cpp index 208ad718329..351fe2112ac 100644 --- a/jbmc/src/java_bytecode/java_bytecode_parse_tree.cpp +++ b/jbmc/src/java_bytecode/java_bytecode_parse_tree.cpp @@ -161,7 +161,7 @@ void java_bytecode_parse_treet::methodt::output(std::ostream &out) const out << " // " << i.source_location << '\n'; out << " " << i.address << ": "; - out << i.statement; + out << bytecode_info[i.bytecode].mnemonic; bool first = true; for(const auto &arg : i.args) diff --git a/jbmc/src/java_bytecode/java_bytecode_parse_tree.h b/jbmc/src/java_bytecode/java_bytecode_parse_tree.h index c682576fb0a..e16eabc79fd 100644 --- a/jbmc/src/java_bytecode/java_bytecode_parse_tree.h +++ b/jbmc/src/java_bytecode/java_bytecode_parse_tree.h @@ -56,7 +56,7 @@ struct java_bytecode_parse_treet { source_locationt source_location; unsigned address; - irep_idt statement; + u8 bytecode; typedef std::vector argst; argst args; }; diff --git a/jbmc/src/java_bytecode/java_bytecode_parser.cpp b/jbmc/src/java_bytecode/java_bytecode_parser.cpp index 7ba8adaa84a..dc648237b47 100644 --- a/jbmc/src/java_bytecode/java_bytecode_parser.cpp +++ b/jbmc/src/java_bytecode/java_bytecode_parser.cpp @@ -36,7 +36,6 @@ class java_bytecode_parsert:public parsert explicit java_bytecode_parsert(bool skip_instructions) : skip_instructions(skip_instructions) { - populate_bytecode_mnemonics_table(); } virtual bool parse(); @@ -72,14 +71,6 @@ class java_bytecode_parsert:public parsert constant_poolt constant_pool; protected: - class bytecodet - { - public: - irep_idt mnemonic; - char format; - }; - - std::vector bytecodes; const bool skip_instructions = false; pool_entryt &pool_entry(u2 index) @@ -104,23 +95,6 @@ class java_bytecode_parsert:public parsert return *java_type_from_string(id2string(pool_entry(index).s)); } - void populate_bytecode_mnemonics_table() - { - // This is only useful for rbytecodes, which in turn is only useful to - // parse method instructions. - if(skip_instructions) - return; - - // pre-hash the mnemonics, so we do this only once - bytecodes.resize(256); - for(const bytecode_infot *p=bytecode_info; p->mnemonic!=nullptr; p++) - { - assert(p->opcodeopcode].mnemonic=p->mnemonic; - bytecodes[p->opcode].format=p->format; - } - } - void rClassFile(); void rconstant_pool(); void rinterfaces(classt &parsed_class); @@ -954,9 +928,6 @@ void java_bytecode_parsert::rfields(classt &parsed_class) void java_bytecode_parsert::rbytecode( methodt::instructionst &instructions) { - INVARIANT( - bytecodes.size() == 256, "bytecode mnemonics should have been populated"); - u4 code_length=read_u4(); u4 address; @@ -978,19 +949,20 @@ void java_bytecode_parsert::rbytecode( // [ifald]load, [ifald]store, ret and iinc // All of these have either format of v, or V INVARIANT( - bytecodes[bytecode].format == 'v' || bytecodes[bytecode].format == 'V', - "Unexpected wide instruction: " + - id2string(bytecodes[bytecode].mnemonic)); + bytecode_info[bytecode].format == 'v' || + bytecode_info[bytecode].format == 'V', + std::string("Unexpected wide instruction: ") + + bytecode_info[bytecode].mnemonic); } instructions.push_back(instructiont()); instructiont &instruction=instructions.back(); - instruction.statement=bytecodes[bytecode].mnemonic; + instruction.bytecode = bytecode; instruction.address=start_of_instruction; instruction.source_location .set_java_bytecode_index(std::to_string(bytecode_index)); - switch(bytecodes[bytecode].format) + switch(bytecode_info[bytecode].format) { case ' ': // no further bytes break; diff --git a/jbmc/src/java_bytecode/java_local_variable_table.cpp b/jbmc/src/java_bytecode/java_local_variable_table.cpp index 7049c711e25..00b9608a425 100644 --- a/jbmc/src/java_bytecode/java_local_variable_table.cpp +++ b/jbmc/src/java_bytecode/java_local_variable_table.cpp @@ -184,7 +184,8 @@ static bool is_store_to_slot( const java_bytecode_convert_methodt::instructiont &inst, unsigned slotidx) { - const std::string prevstatement=id2string(inst.statement); + const std::string prevstatement = bytecode_info[inst.bytecode].mnemonic; + if(!(prevstatement.size()>=1 && prevstatement.substr(1, 5)=="store")) return false; diff --git a/jbmc/unit/java-testing-utils/require_parse_tree.cpp b/jbmc/unit/java-testing-utils/require_parse_tree.cpp index 2054c13c1bf..8466cca2278 100644 --- a/jbmc/unit/java-testing-utils/require_parse_tree.cpp +++ b/jbmc/unit/java-testing-utils/require_parse_tree.cpp @@ -95,8 +95,9 @@ void require_parse_tree::require_instructions_match_expectation( void require_parse_tree::expected_instructiont::require_instructions_equal( java_bytecode_parse_treet::instructiont actual_instruction) const { - REQUIRE(actual_instruction.statement == instruction_mnemoic); - REQUIRE(actual_instruction.args.size() == instruction_arguments.size()); + REQUIRE( + instruction_mnemoic == bytecode_info[actual_instruction.bytecode].mnemonic); + REQUIRE(instruction_arguments.size() == actual_instruction.args.size()); auto actual_arg_it = actual_instruction.args.begin(); for(const exprt &expected_arg : actual_instruction.args) {