2. Bytecode instructions

Reference: docs.oracle.com/javase/spec…

Then in the previous section, a study of two groups of bytecode instruction. One is public cn itcast. The JVM. T5. The HelloWorld (); Constructor bytecode instructions:

  • 2a => aload_0loadingslot 0Is the local variable of, i.ethisAs belowinvokespecialConstruct the arguments to the method call
  • b7 => invokespecialPrepare the call constructor, which method?
  • 00 01 Reference to the constant pool# 1Item, that is,”Method java/lang/Object."":()V
  • B1 means return

Public static void main(java.lang.string []); Bytecode instructions for the main method

b2 00 02 12 03 b6 00 04 b1
Copy the code
  • b2 => getstaticTo load a static variable, which static variable?
  • 00 02 References the constant pool# 2Item, that is,”Field java/lang/System.out:Ljava/io/PrintStream;
  • 12 => ldcLoad parameters, which parameters?
  • 03 Reference the constant pool# 3Item, that is,”String hello world
  • b6 => invokevirtualReady to call a member method, which method?
  • 00 04 Reference the constant pool# 4Item, that is,”Method java/io/PrintStream.println:(Ljava/lang/String;) V
  • B1 means return

\

Javap tool

Oracle provides a javap tool to decompile class files: javap -v helloworld.java

Classfile/D: / Note/notes/JDK source learning/IDEA - workspace/jdk8 / out/production/jdk8 / com/haust/JVM/HelloWorld class Last modified2021-4-28; size 562 bytes
  MD5 checksum f25f5eebfd7ea514993445cea4f6b104
  Compiled from "HelloWorld.java"
public class com.haust.jvm.HelloWorld
  minor version: 0
  major version: 52
  flags: ACC_PUBLIC.ACC_SUPER
Constant pool# 1:= Methodref          #6.#20         // java/lang/Object."<init>":()V
   #2 = Fieldref           #21.#22        // java/lang/System.out:Ljava/io/PrintStream;
   #3 = String             #23            // hello world!
   #4 = Methodref          #24.#25        // java/io/PrintStream.println:(Ljava/lang/String;) V
   #5 = Class              #26            // com/haust/jvm/HelloWorld
   #6 = Class              #27            // java/lang/Object
   #7 = Utf8               <init>
   #8 = Utf8               ()V
   #9 = Utf8               Code
  #10 = Utf8               LineNumberTable
  #11 = Utf8               LocalVariableTable
  #12 = Utf8               this
  #13 = Utf8               Lcom/haust/jvm/HelloWorld;
  #14 = Utf8               main
  #15 = Utf8               ([Ljava/lang/String;)V
  #16 = Utf8               args
  #17 = Utf8               [Ljava/lang/String;
  #18 = Utf8               SourceFile
  #19 = Utf8               HelloWorld.java
  #20 = NameAndType        #7: #8          // "<init>":()V
  #21 = Class              #28            // java/lang/System
  #22 = NameAndType        #29: #30        // out:Ljava/io/PrintStream;
  #23 = Utf8               hello world!
  #24 = Class              #31            // java/io/PrintStream
  #25 = NameAndType        #32: #33        // println:(Ljava/lang/String;) V
  #26 = Utf8               com/haust/jvm/HelloWorld
  #27 = Utf8               java/lang/Object
  #28 = Utf8               java/lang/System
  #29 = Utf8               out
  #30 = Utf8               Ljava/io/PrintStream;
  #31 = Utf8               java/io/PrintStream
  #32 = Utf8               println
  #33= Utf8 (Ljava/lang/String;) V {public com.haust.jvm.HelloWorld();
    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 8: 0
      LocalVariableTable:                                  
Copy the code

\

Graphical method execution flow

Example code is as follows:

/ * * *@author csp
 * @date2021-05-01 * Demo: Bytecode instruction, operand stack, constant pool relationship */
public class Demo3_1 {
    public static void main(String[] args) {
    	// Variables with small numbers are not stored in the constant pool, but in the bytecode instructions of the method
        int a = 10;
        // Short.MAX_VALUE: 32767
        // Short.MAX_VALUE+1, when Short.MAX_VALUE exceeds the maximum value, the variable is stored in the constant pool
        int b = Short.MAX_VALUE + 1;
        intc = a + b; System.out.println(c); }}Copy the code

The decompiled bytecode is as follows:

Classfile/D: / Note/notes/JDK source learning/IDEA - workspace/jdk8 / out/production/jdk8 / com/haust/JVM/Demo3_1 class Last modified2021-5-1; size 611 bytes
  MD5 checksum 5367d11bd9bc1af8bf3b0b037ad7c13f
  Compiled from "Demo3_1.java"
public class com.haust.jvm.Demo3_1
  minor version: 0
  major version: 52
  flags: ACC_PUBLIC.ACC_SUPER
Constant pool# 1:= Methodref          #7.#25         // java/lang/Object."<init>":()V
   #2 = Class              #26            // java/lang/Short
   #3 = Integer            32768
   #4 = Fieldref           #27.#28        // java/lang/System.out:Ljava/io/PrintStream;
   #5 = Methodref          #29.#30        // java/io/PrintStream.println:(I)V
   #6 = Class              #31            // com/haust/jvm/Demo3_1
   #7 = Class              #32            // java/lang/Object
   #8 = Utf8               <init>
   #9 = Utf8               ()V
  #10 = Utf8               Code
  #11 = Utf8               LineNumberTable
  #12 = Utf8               LocalVariableTable
  #13 = Utf8               this
  #14 = Utf8               Lcom/haust/jvm/Demo3_1;
  #15 = Utf8               main
  #16 = Utf8               ([Ljava/lang/String;)V
  #17 = Utf8               args
  #18 = Utf8               [Ljava/lang/String;
  #19 = Utf8               a
  #20 = Utf8               I
  #21 = Utf8               b
  #22 = Utf8               c
  #23 = Utf8               SourceFile
  #24 = Utf8               Demo3_1.java
  #25 = NameAndType        #8: #9          // "<init>":()V
  #26 = Utf8               java/lang/Short
  #27 = Class              #33            // java/lang/System
  #28 = NameAndType        #34: #35        // out:Ljava/io/PrintStream;
  #29 = Class              #36            // java/io/PrintStream
  #30 = NameAndType        #37: #38        // println:(I)V
  #31 = Utf8               com/haust/jvm/Demo3_1
  #32 = Utf8               java/lang/Object
  #33 = Utf8               java/lang/System
  #34 = Utf8               out
  #35 = Utf8               Ljava/io/PrintStream;
  #36 = Utf8               java/io/PrintStream
  #37 = Utf8               println
  #38 = Utf8               (I)V
{
  public com.haust.jvm.Demo3_1();
    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 8: 0
      LocalVariableTable:
        Start  Length  Slot  Name   Signature
            0       5     0  this   Lcom/haust/jvm/Demo3_1;

  public static void main(java.lang.String[]);
    descriptor: ([Ljava/lang/String;)V
    flags: ACC_PUBLIC, ACC_STATIC
    Code:
      stack=2, locals=4, args_size=1
         0: bipush        10
         2: istore_1
         3: ldc           #3                  // int 32768
         5: istore_2
         6: iload_1
         7: iload_2
         8: iadd
         9: istore_3
        10: getstatic     #4                  // Field java/lang/System.out:Ljava/io/PrintStream;
        13: iload_3
        14: invokevirtual #5                  // Method java/io/PrintStream.println:(I)V
        17: return
      LineNumberTable:
        line 10: 0
        line 11: 3
        line 12: 6
        line 13: 10
        line 14: 17
      LocalVariableTable:
        Start  Length  Slot  Name   Signature
            0      18     0  args   [Ljava/lang/String;
            3      15     1     a   I
            6      12     2     b   I
           10       8     3     c   I
}
SourceFile: "Demo3_1.java"
Copy the code

\

1. Constant pool Loads the runtime constant pool

The constant pool is also part of the method area, but it is listed here separately:

2. Method bytecode loads the method area

3. The Main thread starts running and allocates stack frame memory

(stack=2, locals=4) Operand stack has 2 Spaces (4 bytes each) and 4 slots in the local variable table:

4. The execution engine starts to execute bytecode

Bipush 10: pushes a byte number onto the operand stack ()~

  • To push a byte onto the operand stack (the operand stack is 4 bytes wide, so when a byte is pushed, it will complement the operand stack by 4 bytes), similar instructions include:
  • Sipush pushes a short onto the operand stack (its length fills out by 4 bytes)
  • LDC pushes an int onto the operand stack
  • Ldc2_w pushes a long onto the operand stack (the operand stack is 4 bytes wide, so long is pushed twice, and long is 8 bytes wide)
  • Small numbers are stored with bytecode instructions, and numbers beyond the short range are stored in the constant pool

Istore 1:

  • Eject the top element of the operand stack into slot 1 of the local variable table.
a = 10;
Copy the code

ldc #3

Read #3, or 32768, from the runtime constant pool (where numbers beyond the maximum range of short are placed) and load it into the operand stack

MAX_VALUE is 32767, so 32768 = Short.MAX_VALUE + 1 is actually computed at compile time.

istore 2

Pops an element from the operand stack into position 2 of the local variable table.

Iload1 and iload2

Place the elements at position 1 and position 2 in the local variable table on the operand stack.

  • Because operations can only be performed in the operand stack

iadd

Two elements in the operand stack are popped and added, resulting in being pushed onto the operand stack.

istore 3

Pops an element from the operand stack into position 3 of the local variable table.

getstatic #4

Find #4 in the runtime constant pool and find it to be an object.

The object is found in heap memory and its reference is placed on the operand stack.

iload 3

Pushes the element at position 3 in the local variable table onto the operand stack.

invokevirtual 5

Find the constant pool # 5, orientation to the method of area Java/IO/PrintStream println method: (I) V.

Generate a new stack frame (allocation locals, stack, etc.), pass the parameters, and execute the bytecode in the new stack frame.

After execution, the stack frame pops up and clears the main operand stack.

return

Complete the main method call, pop up the main stack frame, the end of the program.

\

5. A. ++ + ++ B

The case code is as follows:

/** * a++ */
public class Demo3_2 {
    public static void main(String[] args) {
        int a = 10;
        int b = a++ + ++a + a--;
        System.out.println(a);/ / 11
        System.out.println(b);/ / 34}}Copy the code

Why does x end up being 0? This is known by analyzing bytecode instructions

public static void main(java.lang.String[]);
	descriptor: ([Ljava/lang/String;)V
	flags: (0x0009) ACC_PUBLIC, ACC_STATIC
	Code:
		stack=2, locals=3, args_size=1
            0: bipush 			10
            2: istore_1
            3: iload_1
            4: iinc 			1.1
            7: iinc 			1.1
            10: iload_1
            11: iadd
            12: iload_1
            13: iinc 			1, -1
            16: iadd
            17: istore_2
            21: iload_1
            22: invokevirtual 	#3 // Method java/io/PrintStream.println:(I)V
			25: getstatic 		#2 // Field java/lang/System.out:Ljava/io/PrintStream;
            28: iload_2
            29: invokevirtual 	#3 // Method java/io/PrintStream.println:(I)V
			32: return
		LineNumberTable:
            line 8: 0
            line 9: 3
            line 10: 18
            line 11: 25
            line 12: 32
        LocalVariableTable:
			Start Length Slot Name Signature
                0 	  33    0 args [Ljava/lang/String;
                3     30    1    a         I
               18     15    2    b 		   I        
Copy the code

Analysis:

  • Note that the iinc directive operates directly on the local variable slot.
  • a++++aThe difference is whether iloAD (read a) is executed first or iInc.a++Iload and iINC,++aOn the contrary.

bipush 10Action is thea = 10Add to operand stack:



istore 1To pop 10 out of the operand stack and put it in slot 1 of the local variable table:



Next to executea++Operations, as we explained earlier,a++Is performed firstiloadRead, and then executeiincAdd 1

  • iload 1The variablea=10, read into the operand stack:

  • performiincCommand, perform +1 operation on a on the local variable table, where A is 11:



The following implementation++aOperation, the firstiinciniload:

  • performiincCommand, perform +1 operation on a on the local variable table, where a is 12:

  • iload 1Place local variables in the scalea=12, read into the operand stack:



The following area++ + ++aOperation, add in the operand stack, resulting in 22, at which point the first addition completes:



Let’s do the second addition(a++ + ++a) +a --Operation:

  • a--To perform firstiloadCommand, in executioninc 1,-1The following command reads 12 from the local table into the operand stack:

  • Next to executeinc 1,-1Command, perform -1 operation in the local variation table, then the value in the local variation table is reduced from 12 to 11:

  • In the operand stack, the second addition is performed, yielding 34:



    Finally, pop the data in the operand stack into the local variable table and assign the value of slot 2 B =34:



    Therefore, the running results of the program are as follows:A is 11, b is 34.

\