基于栈的指令集与基于寄存器的指令集
栈式指令集使用栈来管理运行,寄存器指令集使用寄存器进行工作。
Java 编译得到的字节码指令流,基本上是一种基于栈的指令集架构。
比较:
基于栈的指令集 | 基于寄存器的指令集 | |
---|---|---|
可移植性 | 不需要硬件支持,容易跨平台 | 依赖硬件寄存器 |
性能 | 在内存中操作,相对较慢 | 直接由 cpu 执行,速度快 |
指令数量 | 因为出栈、入栈操作,完成相同功能所需的指令数量更多 | 相比更少 |
设计 | 代码相对更加紧凑(大部分指令无参数) 编译器实现更加简单(不需要考虑空间分配的问题,所需空间都在栈上操作) |
示例
public int calc() {
int a = 100;
int b = 200;
int c = 300;
return (a + b) * c;
}
对应字节码:
0 bipush 100
2 istore_1
3 sipush 200
6 istore_2
7 sipush 300
10 istore_3
11 iload_1
12 iload_2
13 iadd
14 iload_3
15 imul
16 ireturn
查看字节码显示这段代码需要深度为 2 的操作数栈和 4 个变量槽的局部变量空间。
bipush、sipush都是整型入栈指令,只是针对不同的数值范围。
istore_1 指令的作用是将操作数栈顶的整型值出栈并存放到第 1 个局部变量槽中。
前六条指令都是先入栈到操作数栈中再出栈到局部变量槽中。
iload_1 指令的作用是将局部变量表第 1 个变量槽中的整型值复制到操作数栈顶,如上图。
iadd 指令的作用是将操作数栈中头两个栈顶元素出栈,做整型加法,然后把结果重新入栈。
imul 指令与 iadd 指令类似。
ireturn 指令是方法返回指令之一,它将结束方法执行并将操作数栈顶的整型值返回给该方法的调用者。
实际的运作过程并不会完全符合上面的描述,因为虚拟机中解析器和即时编译器都会对输入的字节码进行优化。