Detailed use of the Java bytecode instruction set

  • 2020-04-01 01:46:32
  • OfStack

      The Java virtual machine instruction consists of an Opcode of one byte length representing a particular meaning, followed by zero or more operands representing the operation parameter. Many instructions in a virtual machine do not contain operands, but only one opcode. If exceptions are ignored, the JVM interpreter can be used to make the code work.

do{
     Automatic calculation PC Register and from PC Register location fetch opcode 
    if( Existential operand )  Take out operand ;
     Perform the operations defined by the opcode ;
}while( Handle the next loop )

The number and length of operands depends on the opcode. If an operand is longer than one byte, it will be stored in big-endian order (with the highest byte in front of the bytecode). The value should be (byte1< < 8) | byte2.

      Bytecode instruction streams are single-byte aligned, with the exception of the "tableswitch" and "lookupswitch" instructions, which have special operands and are bounded by 4 bytes and need to be reserved to achieve alignment.

    Limiting the length of the Java virtual machine opcodes to one byte and dropping the parameter length alignment of compiled code is a way to get short and crisp compiled code, even if it may cost the JVM implementation some performance cost. Because opcodes can only be one byte long, limiting the number of instruction sets and not assuming that the data is aligned means that when the data exceeds one byte, you have to reconstruct the specific data structure from the bytes, which costs you some performance.

Data types and Java virtual machines

    In the instruction set in the JVM, most instructions contain information about the data type corresponding to their operations. For example, the iload instruction loads int data from the local variables into the operand stack, while fload loads float data.

    For most data type-related bytecode instructions, their opcode mnemonics have special characters to indicate: I for int, l for long, s for short, b for byte, c for char, f for float, d for double, and a for reference. There are separate instructions that can be used to convert unsupported types into supported types if necessary.

Load and store instructions

    Load and store instructions are used to transfer data back and forth between the local variables and operand stacks of the stack frame.
    1) instructions to load a local variable onto the operand stack include: iload,iload_< N> Lload, lload_ < N> , float, fload_ < N> , dload, dload_ < N> , aload, aload_ < N> .
    2) store a value from the operand stack to the local variable object instruction: istore,istore_< N> , lstore lstore_ < N> , fstore fstore_ < N> , dstore dstore_ < N> Astore, astore_ < N>
    3) instructions for loading constants onto the operand stack: bipush,sipush, LDC,ldc_w,ldc2_w,aconst_null,iconst_ml,iconst_< I> , lconst_ < L> , fconst_ < F> , dconst_ < D>
    4) access index instruction of local variable scale :wide
    Some of the instructions ending in Angle brackets represent a set of instructions, such as iload_< I> , represents iload_0,iload_1, and so on. These sets of instructions are all general instructions with one operand.

Operation instruction

    The arithmetic instruction is used to perform a specific operation on the value of two operand stacks and to store the result back at the top of the operation stack.
    1) add instruction :iadd,ladd,fadd,dadd
    2) subtraction instruction :isub,lsub,fsub,dsub
    3) multiplication instruction :imul,lmul,fmul,dmul
    4) division instruction :idiv,ldiv,fdiv,ddiv
    5) complementary instructions :irem,lrem,frem,drem
    6) reverse instruction :ineg,leng,fneg,dneg
    7) displacement command: ishl, ishr iushr, LSHL, LSHR, lushr
    8) by bit or instruction :ior,lor
    9) bits and instructions :iand,land
    10) instructions by bit :ixor,lxor
    11) local variable self-increment instruction :iinc
    12) compare instructions: DCMPG DCMPL, FCMPG, FCMPL, LCMP

    The Java virtual machine does not specify integer data overflow, but it does specify that when dealing with integer data, only the division and remainder instructions with a divisor of 0 cause the virtual machine to throw an exception.

Load and store instructions

    The load and store instructions are used to transfer data back and forth between the local variables and operand stacks that you use to frame the stack.

    1) instructions to load a local variable onto the operand stack include: iload,iload_< N> Lload, lload_ < N> , float, fload_ < N> , dload, dload_ < N> , aload, aload_ < N> .
    2) store a value from the operand stack to the local variable object instruction: istore,istore_< N> , lstore lstore_ < N> , fstore fstore_ < N> , dstore dstore_ < N> Astore, astore_ < N>
    3) instructions for loading constants onto the operand stack: bipush,sipush, LDC,ldc_w,ldc2_w,aconst_null,iconst_ml,iconst_< I> , lconst_ < L> , fconst_ < F> , dconst_ < D>
    4) access index instruction of local variable scale :wide
    Some of the instructions ending in Angle brackets represent a set of instructions, such as iload_< I> , represents iload_0,iload_1, and so on. These sets of instructions are all general instructions with one operand.

Operation instruction

    The arithmetic instruction is used to perform a specific operation on the value of two operand stacks and to store the result back at the top of the operation stack.
    1) add instruction :iadd,ladd,fadd,dadd
    2) subtraction instruction :isub,lsub,fsub,dsub
    3) multiplication instruction :imul,lmul,fmul,dmul
    4) division instruction :idiv,ldiv,fdiv,ddiv
    5) complementary instructions :irem,lrem,frem,drem
    6) reverse instruction :ineg,leng,fneg,dneg
    7) displacement command: ishl, ishr iushr, LSHL, LSHR, lushr
    8) by bit or instruction :ior,lor
    9) bits and instructions :iand,land
    10) instructions by bit :ixor,lxor
    11) local variable self-increment instruction :iinc
    12) compare instructions: DCMPG DCMPL, FCMPG, FCMPL, LCMP

    The Java virtual machine does not specify integer data overflow, but it does specify that when dealing with integer data, only the division and remainder instructions with a divisor of 0 cause the virtual machine to throw an exception.

Type conversion instruction

    The type conversion directive converts two Java virtual machine numeric types to each other, and these operations are generally used to implement explicit type conversion operations for user code.
    The JVM supports wide type conversions (conversions from small range types to large range types) :
    1)int to long,float,double
    2)long to float,double
    3)float to double

    Narrow flower type conversion instructions: i2b, i2c, i2s, l2i, f2i, f2l, d2l and d2f, narrow type conversion may cause transformation can result different plus or minus, different orders of magnitude, the conversion process may cause numerical accuracy loss. For example, when an int or long converts to an integer type T, the conversion process simply discards the least significant N bytes (N is the length of the data type of type T)

Object creation and manipulation

    Although class instances and arrays are objects, the Java virtual machine USES different bytecode instructions for creating and manipulating class instances and arrays.
    1) instruction to create an instance :new
    2) create an array of instruction: newarray, anewarray, multianewarray
    3) access field instruction, getfield, putfield, getstatic, putstatic
    4) the elements of an array is loaded into the operand stack command: baload, caload, saload, iaload, laload, faload, daload, aaload
    5) to the operand stack values stored in the array elements in the execution: bastore, castore, castore, sastore, iastore, fastore, dastore, aastore
    6) take arraylength instruction :arraylength
    7) check instance type directives :instanceof,checkcast

Operand stack management instructions

    Instructions that directly manipulate the operand stack: pop,pop2,dup,dup2,dup_x1,dup2_x1,dup_x2,dup2_x2, and swap
Control transfer instruction

    Allow the JVM to continue executing the program conditionally or unconditionally from the specified instruction rather than the next instruction that controls the transition instruction. Control transfer instructions include:
    1) conditional branches: ifeq iflt, ifle, ifne, ifgt, ifge, ifnull, ifnotnull, if_cmpeq, if_icmpne, if_icmlt, if_icmpgt, etc

        2) composite condition branch: tableswitch lookupswitch

      3) unconditional branch :goto,goto_w, JSR,jsr_w,ret

    There is a special instruction set in the JVM to handle conditional branch comparison operations of int and reference types. In order to not explicitly indicate whether an entity value is null, there is a special instruction to detect null values. Boolean type and type byte, char type and short types of conditional branch comparison operation, USES the comparison of type int instruction to complete, and long, float, double conditional branch comparison, by comparing different types of corresponding operation instructions, operation command will return an integer value to the operand stack, then perform the condition of type int operation to complete the whole branches. All types of comparison end up being converted to int comparison operations.

Method calls and return instructions

    The invokevirtual directive: invokes the instance method of the object, dispatching according to the actual type of the object (virtual machine dispatching).
    Invokeinterface directive: invokes an interface method, searches an object that implements the interface method at runtime, and finds the appropriate method to invoke.
    Invokespecial: invokes instance methods that require special handling, including instance initialization methods, private methods, and parent methods
    Invokestatic: call class method (static)
    Method return instructions are distinguished by the type of return value, including ireturn(return values are Boolean,byte,char,short, and int),lreturn,freturn,drturn, and areturn, and another return for class initialization I methods for void methods, instance initializers, classes, and interfaces.

synchronous

    The JVM supports method-level synchronization and a sequence of instructions within a method, both of which are implemented through moniter.

    Method-level synchronization is implicit and does not need to be controlled by bytecode instructions, which are implemented in method invocation and return operations. The virtual machine distinguishes whether a method is synchronized from the ACC_SYNCHRONIZED flag in the method signature structure in the method constant pool. When a method is called, the calling instruction checks to see if the flag is set. If so, the executing thread holds the moniter, then executes the method, and releases the moniter when the method completes.

    Synchronizing a sequence of instruction sets, usually marked by synchronized blocks, with JVM instruction sets such as monitorenter and monitorexit to support synchronized semantics.

    Structured locking is a situation where each monitor exit during a method call matches the previous monitor entry. The JVM guarantees the existence of a structured lock (T for a thread and M for a monitor) by following two rules:

    1) the number of times that T holds M when the method is executed must be equal to the number of times that T releases M when the method is completed

    2) at no time will T release M more times than T holds M

Related articles: