1. Bytecode instructions

1. Bytecode overview

  • Bytecode format
  • Byte instruction
  • Class loading mechanism
  • Bytecode execution engine

1.2 Introduction to bytecode instructions

  • The method table in the bytecode. The method table stores the summary information of the method. The method body is stored in code in the property table (arrtibute_info).

  • Java virtual machine instructions consist of a byte number representing the meaning of a particular operation (Opcode), followed by zero or more parameters representing the parameters required for that operation (Operands). (P196)

  • The length of the opcode (occupying the size of the class file) is 1 byte (2^8), so it has a maximum of 256 bytes

  • The JVM is built for operand stacks rather than cotton thread registers.

1.2 Differences between Stacks and register-based VMS

Stack based virtual machine versus register based virtual machine

Stack based virtual machine VS register based virtual machine

1.2.1 overview

Any VM needs to provide the following functions:

  • Fetch instruction, where the instruction comes from memory
  • Decode and determine the instruction type (which operation to perform). The decoding process also involves fetching operands from memory
  • The execution. The instructions are decoded and executed by the virtual machine (in fact, they eventually use physical machine resources).
  • Storing results

1.2.2 Stack-based VMS

  • An overview of the

Stack-based virtual machines have a concept of the operand stack. When performing real operations, virtual machines directly interact with the operand stack and cannot directly manipulate data in memory (actually this sentence is not strict, the operand stack of virtual machines is also laid out in memory). That is, whatever operation is done is done through the operand stack, even something as simple as passing data.

  • Advantages: The VIRTUAL machine can ignore the specific physical architecture, especially registers.
  • Cons: Slow, because everything goes through the operand stack.

Since the default execution is to fetch data from the operand stack, there is no need to specify operands.

For example, the x86 assembly “ADD EAX, EBX” needs to specify where to take the operands from and where to store the results. For example, a simple “Add” is ok because the default operand is stored on the operand stack. Pop two operands from the operand stack to perform the addition operation, and the result of the operation is stored at the top of the stack by default.

The depth of the operand stack is statically determined by the compiler, which is convenient to preallocate space to the stack frame. The stack and can’t be defined on the similar variable-length array (actually this sentence is not rigorous, variable-length arrays allocated on the stack, need the support of the compiler, distribution at the top of the stack), due to the address of the local variable can only be at compile time (compile time) to determine the offset for the current stack frame, if there is a variable is a variable length arrays, The offset of the following variable is undetermined (vector data is allocated on the heap and controlled by itself).

For example, run a = b + C.

  • The bytecode instructions on the stack-based virtual machine look like this:

Since operands are implicit, instructions can be very short, usually one or two bytes. But it is obvious that the number of instructions will increase significantly.

I1: LOAD C
I2: LOAD B
I3: ADD 
I4: STORE A
Copy the code
  • Register-based virtual machines perform this operation with only one instruction:

Where A, B, and C are virtual registers.

I1: add a, b, c
Copy the code
  • The sample

The change on the operand stack is shown as follows: first, data is read from the symbol table (JVM local variator table) and pushed onto the operand stack:

Then bounce the operation from the stack to perform the addition operation, which is performed by the physical machine, as shown in the figure below:

As can be seen from the diagram, the data from the local variable table has to go through an operand stack operation. Note that both the operand stack and the local variable table are stored in memory. The memory-to-memory data transfer on x86 machines has to go through a data bus transfer. It turns out that a simple addition basically takes nine data transfers, which is pretty slow if you think about it.

But stack-based virtual machines have the advantage of being portable, with registers supplied directly by the hardware. With stacked instruction sets, user programs (compiled bytecode) do not directly use registers in the hardware, and in order to improve runtime speed, some frequently accessed data can be stored in registers for maximum performance. In addition, stack-based virtual machine instructions are more compact, can be stored in one or two bytes, and the compiler implementation is relatively simple, no register allocation. Register allocation is a science.

1.2.3 Register-based VMS

In registri-based virtual machines, there is no concept of operand stack, but there are many virtual registers. In general, these registers (operands) are aliases. The execution engine needs to parse these registers (operands), find the specific location of the operands, and then extract the operands for operation.

Since they are virtual registers, which are certainly not in the CPU (and certainly not in the CPU, since the virtual machine is all about cross-platform and compatibility), these registers are actually stored in the runtime stack, essentially an array.

The following describes the registers of a Lua VM:

The new virtual machine also uses the stack to assign active records, and the registers are in that active record. When entering the function body of a Lua program, the function allocates an active record from the stack large enough to hold all the registers of the function. All local variables of a function occupy one register each. Therefore, accessing local variables is quite efficient.

From the figure above, we can see that the concept of a “register” is just a contiguous memory area in the current stack frame. The data is fed directly to the physical CPU for calculation, instead of being sent to the Operand stack for calculation.

For example, “ADD R3, R2, R1” is shown as follows:

In fact, “ADD R3, R2, R1” has to go through a decoding process, of course, the current type of instruction and operands are explained by the virtual machine. As we will see later, some implementations have a large switch-case for instruction dispatch and the actual computation.

Using register-based virtual machines does not have the large number of push/pop instructions that stack based virtual machines use to copy data. At the same time, the instructions are more compact and concise. But because the display specifies operands, register-based code is larger than stack-based code, but not much larger because of the reduction in the number of instructions.

1. To summarize

The difference between the two VMS mainly lies in the storage and retrieval mechanisms for operands and results.

  • Stack-based VMS use interrupt processing to retrieve operands, which are stored in the Stack data structure. The data is fetched from the stack, calculated, and then put onto the stack (LIFO, Last in first out).

    • 1. Code must use these instructions to move variables (push and POP)
    • 2, small code size and decoding efficiency will be higher
    • Stack virtual machine instructions have implicit operands.
  • A register-based VM whose operands are stored in CPU registers. There are no operations on and off the stack, but the instructions executed therefore need to contain the address of the operand and cannot be manipulated with the stack pointer as with the stack.

    • 1. Use a stack to assign activation loggers
    • Register-based code eliminates push and POP commands and reduces the total number of instructions per function.
    • 3. The code size and decoding efficiency are not as good as stack-based virtual machines because they contain operands, so the instructions are larger than stack-based instructions. But register-based code generates less code, so the total code count does not increase.
    • 4. The register virtual machine must decode operands from operation instructions, requiring additional decoding operations.

The summary is as follows:

  1. Number of instructions: Stacks of VMS
  2. Code size: stack virtual machine
  3. Portability: Stack VMS have better portability
  4. Instruction optimization: Register virtual machines can be optimized better
Stack VS register contrast
Article order number Stack > register
The code size Stack type < register type
portability Stack is better than register
Order to optimize The stack is more difficult to optimize
Interpreter execution speed The stack interpreter is slightly slower
Code generation difficulty Stacked simple
Number of data moves in a simple implementation Stack moves a lot

2. Bytecode and data types

  • In the virtual machine instruction set, most instructions contain the data type information corresponding to their operations.

Iload: int fload: float type

  • Most directives contain type information
  • There are also ones that don’t contain type information
    • Goto has nothing to do with type
    • Arraylength operates on an array type
  • 8 data types + reference types. If each instruction contains type information, then 256 instructions are not enough. Some instructions convert unsupported instructions to supported ones.

Java bytecode instruction set assembly

3 Loading Instruction

3.1 an overview of the

  • Load and store instructions are used to transfer data back and forth between the local variable table and operand stack in a stack frame.

    Local variables are added to the operand stack, and then added to the local variables table when the operand stack is finished.

  • Load the local variable table onto the operand stack: iload lload fload dload ALOad

  • Store a value from the operand stack to the local variable table: ISTore LFDA

  • Load a constant onto the operand stack: bipush sipush LDC ldc_w LDC2_w aconST_NULL ICONST_M1 iconst

  • Instruction that extends the access index of a local variable table: wide

  • Load the constant onto the operand stack

— When int is -1 5 Iconst is used — 128 127 Bipush is used — 32768 32767 SIPUSH is used — 2147483648 2147483647 LDC is used

3.2 interpretation

/ / the source code

package classstruct; public class HelloWorldMethod { public int add(int a,int b){ return a+b; } private String conact(String str1,Object objStr){ return str1+objStr; }}Copy the code

// Further understand the contents of 2.6.2 javap in the jVM2-class file structure

#40 = Utf8 ()Ljava/lang/String; { public classstruct.HelloWorldMethod(); descriptor: ()V flags: ACC_PUBLIC Code: stack=1, locals=1, args_size=1 0: aload_0 1: invokespecial #1 // Method java/lang/Object."<init> ":()V 4: return LineNumberTable: line 3: 0 LocalVariableTable: Start Length Slot Name Signature 0 5 0 this Lclassstruct/HelloWorldMethod; public int add(int, int); descriptor: (II)I flags: ACC_PUBLIC Code: stack=2, locals=3, args_size=3 0: iload_1 1: iload_2 2: iadd 3: ireturn LineNumberTable: line 5: 0 LocalVariableTable: Start Length Slot Name Signature 0 4 0 this Lclassstruct/HelloWorldMethod; 0 4 1 a I 0 4 2 b} I interpret lassstruct. HelloWorldMethod () constructor. Args_size = 1, because there is a default with this a parameter. The stack = 2, locals = 3, The locals of args_size = 3 = 3, Public int add(int, int); args_size=3 number of arguments, one more argument is the default parameter this so it is 3 arguments, so iloAD_1 and iload_2(load_0 is this) public int add(int, int); Args_size =3 because there is this in addition to arguments a and b.Copy the code

3.3 read 2

Public class HelloWorldMethod2 {public int add(int a,int b){int c = a + b; return 1+1; Public int add(int, int); public int add(int, int); descriptor: (II)I flags: ACC_PUBLIC Code: stack=2, locals=4, args_size=3 0: iload_1 1: iload_2 2: iadd 3: istore_3 4: iconst_2 5: ireturn LineNumberTable: line 5: 0 line 6: 4 LocalVariableTable: Start Length Slot Name Signature 0 6 0 this Lcourse/jvmstu/opcode/HelloWorldMethod2; 0 6 1 a I 0 6 2 b I 4 2 3 c I // read istore_3 Store operand stack in local variable table iconst_2 is constant value 2, iReturn returns constant value. Instead of storing the result of a+b and then returning the result of 1+1, we return the result of constant 1+1 directly, because the compiler is optimized.Copy the code

Note: The main function is static and does not have a default this parameter.

The compiler evaluates constants to class.

4 Operation instruction

4.1 an overview of the

An operation or arithmetic instruction is used to perform a specific operation on a value on two operand stacks and store the result at the top of the operand stack.

  • Add instruction: add I L F D
  • Subtraction instruction: sub
  • Multiplication instruction: MUL
  • Division instruction: div
  • Mod instruction: REM
  • Take the reverse instruction: neg

Operate on two variables at the top of the stack.

4.2 interpretation

package classstruct; public class HelloOperation { public int add(int a,int b){ int c = a + b; int d = a - b; int e = a * b; int f = a / b; int g = a % b; int h = c + d + e + f + g; return 1 + 1; }}Copy the code
Public int add(int, int); descriptor: (II)I flags: ACC_PUBLIC Code: stack=2, locals=9, args_size=3 0: iload_1 1: iload_2 2: iadd 3: istore_3 4: iload_1 5: iload_2 6: isub 7: istore 4 9: iload_1 10: iload_2 11: imul 12: istore 5 14: iload_1 15: iload_2 16: idiv 17: istore 6 19: iload_1 20: iload_2 21: irem 22: istore 7 24: iload_3 25: iload 4 27: iadd 28: iload 5 30: iadd 31: iload 6 33: iadd 34: iload 7 36: iadd 37: istore 8 39: iconst_2 40: ireturn LineNumberTable: line 5: 0 line 6: 4 line 7: 9 line 8: 14 line 9: 19 line 10: 24 line 11: 39 LocalVariableTable: Start Length Slot Name Signature 0 41 0 this Lclassstruct/HelloOperation; 0 41 1 a I 0 41 2 b I 4 37 3 c I 9 32 4 d I 14 27 5 e I 19 22 6 f I 24 17 7 g I 39 2 8 h I Iload_1 = iload_2 = iload_2; Load1,laod2, store //istore 4, sotre to 4, iload 4,Copy the code

The depth of the stack is 2(i.e. the length of a and B), and the result is c, D.. It was transferred to the local variable scale by istore_3.

5 Type conversion instruction

5.1 an overview of the

  • A conversion instruction can convert two different numeric types to each other,
    • These conversions are typically used to implement display type conversions in user code and to deal with the fact that the data type related instructions in the bytecode instruction set do not correspond to the data type one by one. (There are only 256 bytecode instructions in the stack, and if there is one bytecode instruction for each type, it is not enough. Use the cast instruction to do so.
  • Broad type processing (upcast int->long,UserVO->Object) and narrow type processing (downcast Long ->int,Object->UserVO)
int i = 10; //4 bytes Long a = 10; User User =getUser(); //8 bytes int I will be converted to Long a. Ojbect obj = user; Ojbect obj = getUser(); User user =(User)obj; // This is a narrow type (of course, this type can be wrong if it is not correct)Copy the code
  • I2b i2c I2s L2i…
    • i2b int to byte
    • i2c int to char
    • i2s int to string
    • l2i long to int

5.2 interpretation

// source code package classstruct; Public class HelloInstruction {public int add(int a,int b){long c = a; Int d = (int)c; // narrow type return 1 + 1; }}Copy the code

HelloInstruction.class

Public int add(int, int); descriptor: (II)I flags: ACC_PUBLIC Code: stack=2, locals=6, args_size=3 0: iload_1 1: i2l 2: lstore_3 3: lload_3 4: l2i 5: istore 5 7: iconst_2 8: ireturn LineNumberTable: line 5: 0 line 6: 3 line 7: 7 LocalVariableTable: Start Length Slot Name Signature 0 9 0 this Lclassstruct/HelloInstruction; 0 9 1 a I 0 9 2 b I 3 6 3 c J 7 2 5 d I } SourceFile: "HelloInstruction.java"Copy the code
package classstruct; Public class HelloInstruction2 {public static int add(int a,int b){long hour = 24; long m = hour * 60 * 60 * 1000; long mic = hour * 60 * 60 * 1000 * 1000; System.out.println(mic/m); return 1 + 1; } public static void main(String[] args) {add(1,2); }}Copy the code

HelloInstruction2.class

  public static int add(int, int);
    descriptor: (II)I
    flags: ACC_PUBLIC, ACC_STATIC
    Code:
      stack=5, locals=8, args_size=2
         0: ldc2_w        #2                  // long 24l
         3: lstore_2
         4: lload_2
         5: ldc2_w        #4                  // long 60l
         8: lmul
         9: ldc2_w        #4                  // long 60l
        12: lmul
        13: ldc2_w        #6                  // long 1000l
        16: lmul
        17: lstore        4
        19: lload_2
        20: ldc2_w        #4                  // long 60l
        23: lmul
        24: ldc2_w        #4                  // long 60l
        27: lmul
        28: ldc2_w        #6                  // long 1000l
        31: lmul
        32: ldc2_w        #6                  // long 1000l
        35: lmul
        36: lstore        6
        38: getstatic     #8                  // Field java/lang/System.out:Ljav
a/io/PrintStream;
        41: lload         6
        43: lload         4
        45: ldiv
        46: invokevirtual #9                  // Method java/io/PrintStream.prin
tln:(J)V
        49: iconst_2
        50: ireturn
      LineNumberTable:
        line 5: 0
        line 6: 4
        line 7: 19
        line 8: 38
        line 9: 49
      LocalVariableTable:
        Start  Length  Slot  Name   Signature
            0      51     0     a   I
            0      51     1     b   I
            4      47     2  hour   J
           19      32     4     m   J
           38      13     6   mic   J

  public static void main(java.lang.String[]);
    descriptor: ([Ljava/lang/String;)V
    flags: ACC_PUBLIC, ACC_STATIC
    Code:
      stack=2, locals=1, args_size=1
         0: iconst_1
         1: iconst_2
         2: invokestatic  #10                 // Method add:(II)I
         5: pop
         6: return
      LineNumberTable:
        line 13: 0
Copy the code

HelloInstruction2 is the result of executing on JDK8. If executed in JDK, the result will be equal to “HelloInstruction2” because int is computed first and then converted to “long”, as shown in the following figure:

Object creation and access instructions

6.1 an overview of the

  • Directive to create class instances: new
  • Newarray anewarray multianewarray creates an array
  • Access the class field getField getStatic putStatic
  • The instruction to load array elements onto the operand stack: baload c s I l f d a
  • Stores the values of the operand stack into the array element: astore
  • The instruction to take the length of an array: arrayLength
  • The command to check instance types: instanceof checkcast

6.2 interpretation

/ / the source code

package classstruct; Public class HelloUser {public static void main(String[] args) {User User = new User(); User[] us = new User[10]; int[] as = new int[10]; user.name = "username"; String name2 = user.name; } } class User { String name; static int age; }Copy the code

/ / javap verbose results

{ public classstruct.HelloUser(); descriptor: ()V flags: ACC_PUBLIC Code: stack=1, locals=1, args_size=1 0: aload_0 1: invokespecial #1 // Method java/lang/Object."<init> ":()V 4: return LineNumberTable: line 4: 0 LocalVariableTable: Start Length Slot Name Signature 0 5 0 this Lclassstruct/HelloUser; public static void main(java.lang.String[]); descriptor: ([Ljava/lang/String;)V flags: ACC_PUBLIC, ACC_STATIC Code: stack=2, locals=5, args_size=1 0: new #2 // class classstruct/User 3: dup 4: invokespecial #3 // Method classstruct/User."<init> ":()V 7: astore_1 8: bipush 10 10: anewarray #2 // class classstruct/User 13: astore_2 14: bipush 10 16: newarray int 18: astore_3 19: aload_1 20: ldc #4 // String username 22: putfield #5 // Field classstruct/User.name:Lja va/lang/String; 25: aload_1 26: getfield #5 // Field classstruct/User.name:Lja va/lang/String; 29: astore 4 31: return LineNumberTable: line 6: 0 line 7: 8 line 8: 14 line 10: 19 line 11: 25 line 13: 31 LocalVariableTable: Start Length Slot Name Signature 0 32 0 args [Ljava/lang/String; 8 24 1 user Lclassstruct/User; 14 18 2 us [Lclassstruct/User; 19 13 3 as [I 31 1 4 name2 Ljava/lang/String;} SourceFile: "hellouser. Java" Stack =2, locals=5, args_size=1, args_size=1, args_size=1, args_size=1 New #2 // class classstruct/User Invokespecial #3 // Method classstruct/User."<init>":()V // new array object 10: Anewarray #2 // classstruct/User // Putfield # 5 / / Field classstruct/User. The name: Ljava/lang/String; / / the following is a value from the object of 26: getfield #5 // Field classstruct/User.name:Ljava/lang/String;Copy the code

Operand stack management instructions

  • Operand stack instructions are used to manipulate operand stacks directly.
  • Unstack one or two elements of the operand stack: pop pop2
  • Duplicates one or two values from the top of the stack and pushes the duplicates or duplicates back to the top: dUP dup2 dup_X1 dup_x2
  • Replace the top two values of the stack: swap

8 control transfer instruction

8.1 an overview of the

  • A control transfer instruction enables the Java virtual machine to conditionally or unconditionally proceed from a specified location to the next instruction in the control transfer instruction. You can think of the transfer instruction as modifying the value of a PC register.
  • Conditional branch: ifeq iflt ifle ifne ifgt ifNULL ifCMple…
  • Compound condition branch: tablesWitch Lookupswitch
  • Unconditional branch: goto goto_w JSR jSR_w ret

8.2 interpretation

package classstruct; public class HelloCondition { public static void main(String[] args) { int a = 10; if(a>10){ System.out.println("a>10"); }else{ System.out.println("a<=10"); } int b = 12; if(b>10){ System.out.println("b>10"); }else{ System.out.println("b<=10"); }}}Copy the code

HelloCondition.class

public static void main(java.lang.String[]); descriptor: ([Ljava/lang/String;)V flags: ACC_PUBLIC, ACC_STATIC Code: stack=2, locals=3, args_size=1 0: bipush 10 2: Istore_1 ////istore,a add to operand stack 3: iloAD_1 ////10 add to operand stack 4: bipush 10 //// Compare the top two digits of the stack, if successful, continue, if not jump to line 20 6: if_icmple 20 9: getstatic #2 // Field java/lang/System.out:Ljav a/io/PrintStream; 12: ldc #3 // String a>10 14: invokevirtual #4 // Method java/io/PrintStream.prin tln:(Ljava/lang/String;)V 17: goto 28 20: getstatic #2 // Field java/lang/System.out:Ljav a/io/PrintStream; 23: ldc #5 // String a<=10 25: invokevirtual #4 // Method java/io/PrintStream.prin tln:(Ljava/lang/String;)V 28: bipush 12 30: istore_2 31: iload_2 32: bipush 10 34: if_icmple 48 37: getstatic #2 // Field java/lang/System.out:Ljav a/io/PrintStream; 40: ldc #6 // String b>10 42: invokevirtual #4 // Method java/io/PrintStream.prin tln:(Ljava/lang/String;)V 45: goto 56 48: getstatic #2 // Field java/lang/System.out:Ljav a/io/PrintStream; 51: ldc #7 // String b<=10 53: invokevirtual #4 // Method java/io/PrintStream.prin tln:(Ljava/lang/String;)V 56: return LineNumberTable: line 5: 0 line 6: 3 line 7: 9 line 9: 20 line 12: 28 line 13: 31 line 14: 37 line 16: 48 line 18: 56 LocalVariableTable: Start Length Slot Name Signature 0 57 0 args [Ljava/lang/String; 3 54 1 a I 31 26 2 b I StackMapTable: number_of_entries = 4 frame_type = 252 /* append */ offset_delta = 20 locals = [ int ] frame_type = 7 /* same */ frame_type = 252 /* append */ offset_delta = 19 locals = [ int ] frame_type = 7 /* same */ } SourceFile: "HelloCondition.java"Copy the code

Method calls and return instructions

9.1 Method Call instructions

  • The Invokevirtual directive is used to invoke instance methods of an object and dispatch based on the actual type of the object (virtual method dispatch), which is the most common method dispatch method in the Java language.
  • The InvokeInterface directive, which invokes an interface method, searches at run time for an object that implements the interface method and finds an appropriate method to invoke.
  • The Invokespecial directive is used to invoke instance methods that require special handling, including instance initialization methods (§2.9), private methods, and superclass methods.
  • The Invokestatic directive is used to invoke class methods (static methods).

9.2 Interpreting call Instructions

public interface Service { int add(int a,int b); } public class ServiceImpl implements Service { @Override public int add(int a, int b) { return a+b; } } public class InvokerOpercode { public static void main(String[] args) { Service service = new ServiceImpl(); Int retStr = service. The add (1, 2); }}Copy the code
public static void main(java.lang.String[]); descriptor: ([Ljava/lang/String;)V flags: ACC_PUBLIC, ACC_STATIC Code: stack=3, locals=3, args_size=1 0: new #2 // class course/jvmstu/opcode/invo ke/ServiceImpl 3: dup 4: invokespecial #3 // Method course/jvmstu/opcode/inv oke/ServiceImpl."<init>":()V 7: astore_1 8: aload_1 9: iconst_1 10: iconst_2 11: invokeinterface #4, 3 // InterfaceMethod course/jvmstu/o pcode/invoke/Service.add:(II)I 16: istore_2 17: return LineNumberTable: line 5: 0 line 6: 8 line 7: 17 LocalVariableTable: Start Length Slot Name Signature 0 18 0 args [Ljava/lang/String; 8 10 1 service Lcourse/jvmstu/opcode/invoke/Service; 17 1 2 retStr I} SourceFile: "invokeropercode. JavaCopy the code

9.3 Method return instruction

Method call directives are independent of the data type. Method return directives are differentiated by the type of the value returned. They include iReturn (used when the return value is Boolean, byte, CHAR, short, or int), lReturn, freturn, dreturn, and Areturn. There is also a return directive for methods declared as void, instance initializers, and class initializers of classes and interfaces. Note: Even the void method has a return.

10 Exception handling commands

10.1 an overview of the

In addition to explicitly throwing an exception in a program that is implemented by the Athrow directive, there are other exceptions that are automatically thrown by the virtual machine when other Java virtual machine directives detect an exception.

10.2 interpretation

Public class ExcepOpercode {public static void main(String[] args) {throw new RuntimeException(" RuntimeException "); public class ExcepOpercode {public static void main(String[] args) {throw new RuntimeException(" RuntimeException "); Public static void main(java.lang.string []); descriptor: ([Ljava/lang/String;)V flags: ACC_PUBLIC, ACC_STATIC Code: stack=3, locals=1, args_size=1 0: New # 2 / class/Java/lang/RuntimeExceptio n 3: dup 4: LDC # 3 / / String a runtime exception 6: invokespecial #4 // Method java/lang/RuntimeExcepti on."<init>":(Ljava/lang/String;)V 9: athrow LineNumberTable: line 5: 0 LocalVariableTable: Start Length Slot Name Signature 0 10 0 args [Ljava/lang/String; } SourceFile: Excepopercode. Java "// The following exception is generated // 9: athrowCopy the code

10.3 Use of try Catch Parsing

public class ExcepOpercode2 { public static void main(String[] args) { try { int a = 1 / 0; } catch (Exception e) { int b = 100; Public static void main(java.lang.string []); descriptor: ([Ljava/lang/String;)V flags: ACC_PUBLIC, ACC_STATIC Code: stack=2, locals=3, args_size=1 0: iconst_1 1: iconst_0 2: idiv 3: istore_1 4: goto 11 7: astore_1 8: bipush 100 10: istore_2 11: return Exception table: from to target type 0 4 7 Class java/lang/Exception LineNumberTable: line 6: 0 line 9: 4 line 7: 7 line 8: 8 line 10: 11 LocalVariableTable: Start Length Slot Name Signature 8 3 1 e Ljava/lang/Exception; 0 12 0 args [Ljava/lang/String; StackMapTable: number_of_entries = 2 frame_type = 71 /* same_locals_1_stack_item */ stack = [ class java/lang/Exception ] frame_type = 3 /* same */ } SourceFile: "ExcepOpercode2.java"Copy the code

Based on looking at statements with a try catch, a try catch does not affect any performance without an exception. Use an Exception table to handle exceptions.(In older JDK’s try catch has some performance impact.

11 Synchronization Command

11.1 an overview of the

  • Java virtual machines can support method-level synchronization and synchronization of a sequence of instructions within a method, both of which are supported using Monitor.
  • Method-level synchronization is implicit, that is, controlled without bytecode instructions, and is implemented in method calls and return operations (§2.11.8). A virtual machine can distinguish whether a method is synchronized from the ACC_SYNCHRONIZED access flag in the method table Structure (method_info Structure, §4.6) in the method constant pool. When a method is invoked, the calling instruction checks to see if the ACC_SYNCHRONIZED access flag of the method is set, and if so, the executing thread holds the pipe, then executes the method, and finally releases the pipe when the method completes (either normally or abnormally). During method execution, the executing thread holds the pipe, and no other thread can get the same pipe again. If a synchronized method throws an exception during execution and cannot handle the exception inside the method, the pipe held by the synchronized method is automatically released when the exception is thrown outside the synchronized method.
  • Synchronizing a sequence of instructions is usually represented by the Synchronized block in the Java language. The Java VIRTUAL machine has monitorenter and Monitorexit directives to support the semantics of synchronized. Proper implementation of the synchronized keyword requires both compiler and Java virtual machine support (see §3.14 for a description of synchronization).

Synchronized is followed by the following bytecode: monitorenter monitoexit:

11.2 interpretation

public class SyncOpercode { public static void main(String[] args) { synchronized (SyncOpercode.class){ System.out.println("come to synchronized"); Public static void main(java.lang.string []); descriptor: ([Ljava/lang/String;)V flags: ACC_PUBLIC, ACC_STATIC Code: stack=2, locals=3, args_size=1 0: LDC # 2 / class/course/jvmstu/opcode/sync opercode/SyncOpercode 2: dup 3: astore_1 / / / / 4 into synchronized: monitorenter 5: getstatic #3 // Field java/lang/System.out:Ljav a/io/PrintStream; 8: ldc #4 // String come to synchronized 10: Invokevirtual #5 // Method Java/IO/printstream.prin TLN :(Ljava/lang/String;)V 13: aload_1 //// exit synchronized 14: Monitorexit //// if synhronized, it will go goto 23, 15: GOto 23 //// if abnormal 18: Astore_2 19: ALOAD_1 20: Monitorexit 21: Aload_2 22: athrow //// 23: return Exception table: from to target type 5 15 18 any 18 21 18 any LineNumberTable: line 5: 0 line 6: 5 line 7: 13 line 8: 23 LocalVariableTable: Start Length Slot Name Signature 0 24 0 args [Ljava/lang/String; StackMapTable: number_of_entries = 2 frame_type = 255 /* full_frame */ offset_delta = 18 locals = [ class "[Ljava/lang/String;", class java/lang/Object ] stack = [ class java/lang/Throwable ] frame_type = 250 /* chop */ offset_delta = 4 } SourceFile: "syncopercode. Java" //// enter synchronized 4: monitorenter //// exit synchronized 14: Monitorexit //// If synhronized, goto 23 line, 15: goto 23 //// continue if abnormal 18: astore_2 //// Exit directly 23: returnCopy the code

11.3 monitor

  • A tube (English: Monitors) is a program structure in which worker threads of subroutines (objects or modules) mutually exclusive access to shared resources. These shared resources are typically hardware devices or a set of variables.
  • A pipe program implements that at most one thread is executing a subroutine of a pipe program at any one time. Compared with concurrent programs that modify data structures to achieve mutually exclusive access, pipe-side implementations greatly simplify programming
  • All kinds of hardware resources and software resources in the system can be abstractly described by data structure, which means to represent the resources with a small amount of information and operations performed on the resources, while ignoring their internal structure and implementation details.
  • A shared data structure is used to represent the shared resources in the system abstractly, and the operations performed on the shared data structure are defined as a set of procedures.

12 Reference Article

Java bytecode instruction set assembly