本例以一个简单的加减乘除的例子,来熟悉虚拟机的操作数栈的工作流程。
1package test;
2
3public class TestOperate {
4 public int calc() {
5 int a = 1;
6 int b = 2;
7 int c = 3;
8 int d = 4;
9 int r = (a - b + c) * d;
10 return r;
11 }
12
13}
该类对应的字节码指令如下:
1Classfile /D:/develop/IdeaProjects/learning/test01/target/classes/test/TestOperate.class
2 Last modified 2020-1-30; size 453 bytes
3 MD5 checksum d2d815a9c2ff7ca0d14e3d492a46b05c
4 Compiled from "TestOperate.java"
5public class test.TestOperate
6 minor version: 0
7 major version: 51
8 flags: ACC_PUBLIC, ACC_SUPER
9Constant pool:
10 #1 = Methodref #3.#21 // java/lang/Object."<init>":()V
11 #2 = Class #22 // test/TestOperate
12 #3 = Class #23 // java/lang/Object
13 #4 = Utf8 <init>
14 #5 = Utf8 ()V
15 #6 = Utf8 Code
16 #7 = Utf8 LineNumberTable
17 #8 = Utf8 LocalVariableTable
18 #9 = Utf8 this
19 #10 = Utf8 Ltest/TestOperate;
20 #11 = Utf8 calc
21 #12 = Utf8 ()I
22 #13 = Utf8 a
23 #14 = Utf8 I
24 #15 = Utf8 b
25 #16 = Utf8 c
26 #17 = Utf8 d
27 #18 = Utf8 r
28 #19 = Utf8 SourceFile
29 #20 = Utf8 TestOperate.java
30 #21 = NameAndType #4:#5 // "<init>":()V
31 #22 = Utf8 test/TestOperate
32 #23 = Utf8 java/lang/Object
33{
34 public test.TestOperate();
35 descriptor: ()V
36 flags: ACC_PUBLIC
37 Code:
38 stack=1, locals=1, args_size=1
39 0: aload_0
40 1: invokespecial #1 // Method java/lang/Object."<init>":()V
41 4: return
42 LineNumberTable:
43 line 3: 0
44 LocalVariableTable:
45 Start Length Slot Name Signature
46 0 5 0 this Ltest/TestOperate;
47
48 public int calc();
49 descriptor: ()I
50 flags: ACC_PUBLIC
51 Code:
52 stack=2, locals=6, args_size=1
53 0: iconst_1
54 1: istore_1
55 2: iconst_2
56 3: istore_2
57 4: iconst_3
58 5: istore_3
59 6: iconst_4
60 7: istore 4
61 9: iload_1
62 10: iload_2
63 11: isub
64 12: iload_3
65 13: iadd
66 14: iload 4
67 16: imul
68 17: istore 5
69 19: iload 5
70 21: ireturn
71 LineNumberTable:
72 line 5: 0
73 line 6: 2
74 line 7: 4
75 line 8: 6
76 line 9: 9
77 line 10: 19
78 LocalVariableTable:
79 Start Length Slot Name Signature
80 0 22 0 this Ltest/TestOperate;
81 2 20 1 a I
82 4 18 2 b I
83 6 16 3 c I
84 9 13 4 d I
85 19 3 5 r I
86}
87SourceFile: "TestOperate.java"
下面重点关注clac方法的方法体指令:
1 stack=2, locals=6, args_size=1
2 0: iconst_1
3 1: istore_1
4 2: iconst_2
5 3: istore_2
6 4: iconst_3
7 5: istore_3
8 6: iconst_4
9 7: istore 4
10 9: iload_1
11 10: iload_2
12 11: isub
13 12: iload_3
14 13: iadd
15 14: iload 4
16 16: imul
17 17: istore 5
18 19: iload 5
19 21: ireturn
栈深为2,局部变量为6:
- iconst_1:把整型1压入栈顶
- istore_1:弹出栈顶元素,将栈顶元素的值设置到局部变量表中索引为1的变量中,也就是变量a的值现在为1
- iconst_2:将整型2压入栈顶
- istore_2:弹出栈顶元素,将其值2设置给局部变量表中的第2个变量b,也就是b=2
- iconst_3:将3压入栈顶
- istore_3:弹出栈顶元素3,将其设置到局部变量表的第3个变量c,也就是c=3
- iconst_4:将4压入栈顶
- istore 4:将栈顶元素弹出,将其值4设置到局部变量表的第4个元素d,也就是d=4
- iload_1:iload表示将局部变量中的值压入栈顶,这里是把第一个变量a的值1压入栈顶
- iload_2:将第二个变量的值2压入栈顶,此时已经入栈的值1进入栈底
- isub:弹出2个元素进行相减,将结果压入栈顶,这里依次弹出2和1,结果1-2=-1压入栈顶
- iload_3:将变量c的值3压入栈顶,此时已经入栈的元素-1进入栈底
- iadd:弹出2个元素相加,将结果压入栈顶,也就是此时栈顶元素的值是2
- iload 4:将第四个变量d的值4压入栈顶,这时栈顶为4,栈底为2
- imul:弹出2个元素,相乘后将结果压入栈顶,也就是此时栈顶为8,栈顶为空
- istore 5:将栈顶元素的值8弹出,设置到第5个局部变量r
- iload 5:将第5个局部变量r的值8压入栈顶
- ireturn:返回方法的结果,也就是弹出栈顶元素8,将其压入调用方法栈帧的操作数栈的栈顶,当前方法的操作数栈的其他元素将会全部被丢弃。