1. Overview
The commands of a Java Virtual Machine consist of a number with a byte length that represents the meaning of a specific operation (as an operation code, opcde) and 0 to multiple parameters required for this operation (operands, operands ). Because the length of the operation code is one byte, the total number of operands of the instruction set cannot exceed 256; and because the class file does not give up the operand alignment of the compiled code, therefore, when a virtual machine processes more than one byte of data, It reconstructs a specific data format from the byte, for example, a 16-length unsigned integer is stored in two unsigned bytes (byte1 and byte2), and their values are byte1 <8 | byte2. For most bytecode commands related to data types, their operation codes have special characters to indicate the specific data type service: I represents the operation of int type data, l represents the operation of long data, s represents short, B Represents byte, c Represents char, f Represents float, D represents double, a represents reference.
2. bytecode type 2.1, loading and storage commands
The load and storage commands are used to transmit data back and forth between the local variable table in the stack frame and the operand stack. These Commands include the following:
- Load a local variable to the operation Stack: iload, iload <n>, lLoad, lLoad <n>, fload, fload <n>, dload, dload <n>, aload, aload <n>
- Store a value from the operand stack to the local variable table: istore, istore <n>, lstore, lstore <n>, fstore, fstore <n>, dstore, dstore <n>, astore, and astore <n>
- Load a constant to the operand Stack: bipush, sipush, LDC, ldc_w, ldc2_w, aconst_null, aconst_m1, aconst _ <I>, lfonst <L>, fconst _ <F>, dconst _ <D>
- Command for expanding the access index of the local variable table: wide
The Data Storage Operations stack and local variable tables are mainly operated by the loading and storage commands. In addition, there are a few commands, for example, fields or array elements accessing objects will also transmit data to the operand stack.
2.2 operation commands
An operation or arithmetic execution is used to perform a specific operation on the values on the two operand stacks, and store the results to the top of the Operation stack. Generally, arithmetic commands can be divided into two types: commands for integer data operations and instructions for floating-point data operations. No matter which arithmetic commands are used, Java virtual data types are used, because no arithmetic commands of the byte, short, Char, and Boolean types are directly supported, Int-type commands should be used for such data operations. All arithmetic commands are as follows:
- Addition commands: iadd, Ladd, FADD, and dadd
- Subtraction commands: isub, LSUB, fsub, and dsub
- Multiplication command: imul, lmul, fmul, dmul
- Division command: idiv, ldiv, fdiv, ddiv
- Remainder instruction: irem, lrem, frem, drem
- Reverse command: INEG, lneg, fneg, dneg
- Displacement command: ishl, ISHR, iushr, lshl, lshr, lushr
- Bitwise OR command: IOR, Lor
- Bitwise AND command: iand, land
- By-bit XOR or command: ixor, lxor
- Local variable auto-increment command: iinc
- Comparison commands: dcmpg, dcmpl, fcmpg, fcmpl, and lcmp
2.3 type conversion commands
The type conversion command can convert two different numeric types. These grasping and changing operations are generally used to implement explicit type conversion operations in user code, it can also be used to handle the issue that the data type-related commands in the bytecode instruction set cannot match the data type one by one.
2.3.1 wide type conversion
Java Virtual Machine support (that is, explicit conversion commands are not required during conversion), including the following three types:
- Int to long, float, or double
- Long to float or double type
- Float to double type
2.3.2 narrow type conversion
Narrow type conversion must be performed explicitly using conversion commands. Narrow type changes may lead to different positive and negative numbers and different orders of magnitude in the results, and may lead to loss of numerical precision. The narrow type command is as follows:
- Int to byte: i2b
- Int to Char: I2C
- Int to short: I2S
- Long to int: l2i
- Float to int: f2i
- Float to long: f2l
- Double to int: d2i
- Double to long: d2l
- Double to float: D2F
2.4 object creation and access commands
Classes and arrays are all objects, but Java virtual machines use different bytecode for the creation and operation of classes and arrays (because ). After an object is created, you can use the object access command to obtain fields or array elements in the object instance or array instance. These commands are as follows:
- Command for creating a class instance: New
- Instructions for creating Arrays: newarray, anewarray, and multianewarray
- Variables (static modifier) and instance variables (non-static modifier) commands: getstatic, putstatic, getfield, putfield
- Commands for loading an array to the operand Stack: baload, caload, saload, iaload, laload, faload, daload, aload
- Commands that store the value of an operand stack to an array: bastore, Castore, sastore, iastore, lastore, fastore, dastore, and aastore
- Command for getting the array length: arraylength
- Check instance type commands: instanceof, checkcase
2.5 operations stack management commands
The Java virtual machine provides a series of commands for direct operations on the operand stack, including:
- Stack one or two elements at the top of the stack: Pop and pop2.
- Copy one or two values at the top of the stack and re-Press the copy value or duplicate values to the top of the stack: dup, dup2, dup_x1, dup_x2, dup2_x1, dup2_x2
- Swap two elements at the top of the stack: swap
2.6 transfer control instructions
The Control Transfer Instruction allows the Java Virtual Machine to execute commands from the instruction location conditional or unconditional instead of the next instruction to control the transfer instruction, the control command is to modify the PC register value conditional or unconditional. Comparison of conditional branches of the Boolean, byte, Char, and short types is performed using int-type comparison commands; for comparison operations on conditional branches of the long, float, and double types, corresponding comparison commands (dcmpg, dcmpl, fcpmg, fcpml, and ICMP) are executed first ), the operation command returns an integer data to the operand stack, and then performs the INT-type conditional branch comparison operation to complete the entire branch jump. The transfer control command is as follows:
- Condition branches: ifeq, iflt, ifle, ifne, ifgt, ifge, ifnull, ifnnonull, if_icmpeq, if_icmpne, if_icmplt, if_icmpgt, if_icmple, if_icmpge, limit, and limit
- Qualified branches: tableswitch and lookupswitch
- Unconditional branches: Goto, goto_w, JSR, jsr_w, RET
2.7 method call and return command
Common method call commands are as follows:
- Invokevirtual: Call the instance method of an object and assign Objects Based on their actual types (virtual method assignment)
- Invokeinterface: Call an interface method. It searches for an object that implements this interface method at runtime and finds a suitable method for calling.
- Invokespecial: Call some instance methods that require special processing, including the instance initialization method, private method, and parent class method.
- Invokestatic: Used to call class methods (static modification)
- Invokedynamic: it is used to dynamically parse the method referenced by the call point qualifier at runtime and execute this method
Common methods to return commands:
- Ireturn: The returned values are Boolean, byte, Char, short, and INT types.
- Lreturn: the return value is of the long type.
- Freturn: The returned value is of the float type.
- Dreturn: the return value is of the double type.
- Return: the return value is void.
2.8 exception handling commands
All the operations (throw statements) that explicitly throw exceptions in Java programs areAthrowIn addition to throwing exceptions explicitly using the throw statement, the Java Virtual Machine specification also specifies that many runtime exceptions will be automatically thrown when other Java Virtual Machine commands detect exceptions. In the Java virtual machine, the exception handling (try... catch) is not implemented by bytecode, but by using an exception table.
2.9 synchronous commands
Java Virtual Machine supports method-level synchronization and synchronization of a command sequence within the method. Both synchronization structures are supported by the monitor.
Method-level synchronization is implicit and does not need to be controlled by bytecode commands. It is implemented in method calls and return operations. The VM can know whether a method is declared as a synchronous method from the acc_synchronized access mark in the method table structure of the method constant pool. When a method is called, the call command checks whether the acc_synchronized access flag of the method is set. If it is set, the execution thread must first successfully hold the management thread before executing the method, finally, release the manager after the method is executed. During method execution, the execution thread holds a pipe, and no other thread can obtain the same pipe. If an exception occurs during the execution of a synchronous method, and the method cannot handle this exception internally, the pipe held by this thread will be automatically released when the exception is thrown out of the method.
A sequence of synchronous instruction sets is usually represented by synchronized statement blocks in Java. The instruction sets of Java virtual machines include monitorrenter and monitorexit to support synchronized keywords. Correctly implementing synchronized requires the support of the javac compiler and Java virtual machine.
Introduction to JVM bytecode