Jvm(61),虚拟机字节码执行引擎----操作数栈

Posted qingruihappy

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Jvm(61),虚拟机字节码执行引擎----操作数栈相关的知识,希望对你有一定的参考价值。

每一个独立的栈帧中除了包含局部变量表以外,还包含一个后进先出(Last-In-First-Out)的操作数栈,也可以称之为表达式栈(Expression Stack)。操作数栈和局部变量表在访问方式上存在着较大差异,操作数栈并非采用访问索引的方式来进行数据访问的,而是通过标准的入栈和出栈操作来完成一次数据访问。每一个操作数栈都会拥有一个明确的栈深度用于存储数值,一个32bit的数值可以用一个单位的栈深度来存储,而2个单位的栈深度则可以保存一个64bit的数值,当然操作数栈所需的容量大小在编译期就可以被完全确定下来,并保存在方法的Code属性中。

在HotSpot中,除了PC寄存器之外,再也没有包含其他任何的寄存器,并且之前曾经提及

过,HotSpot中任何的操作都需要经过入栈和出栈来完成,那么由此可见,HotSpot的执行引擎架构必然就是基于栈式架构,而非传统的寄存器架构。简单来说,操作数栈就是JVM执行引擎的一个工作区,当一个方法被调用的时候,一个新的栈帧也会随之被创建出来,但这个时候栈帧中的操作数栈却是空的,只有方法在执行的过程中,才会有各种各样的字节码指令往操作数栈中执行入栈和出栈操作。比如在一个方法内部需要执行一个简单的加法运算时,首先需要从操作数栈中将需要执行运算的两个数值出栈,待运算执行完成后,再将运算结果入栈。如下所示:

代码8-2 执行加法运算的字节码指令

public void testAddOperation();

Code:

0: bipush 15

2: istore_1

3: bipush 8

5: istore_2

6: iload_1

7: iload_2

8: iadd

9: istore_3

10: return

在上述字节码指令示例中,首先会由"bipush"指令将数值15从byte类型转换为int类型后压入操作数栈的栈顶(对于byte、short和char类型的值在入栈之前,会被转换为int类型),当成功入栈之后,"istore_1"指令便会负责将栈顶元素出栈并存储在局部变量表中访问索引为1的Slot上。接下来再次执行"bipush"指令将数值8压入栈顶后,通过"istore_2"指令将栈顶元素出栈并存储在局部变量表中访问索引为2的Slot 上。"iload_1"和"iload_2"指令会负责将局部变量表中访问索引为1和2的Slot上的数值 15和8重新压入操作数栈的栈顶,紧接着"iadd"指令便会将这2个数值出栈执行加法运算后再将运算结果重新压入栈顶,"istore_3"指令会将运算结果出栈并存储在局部变量表中访问索引为3的Slot上。最后"return"指令的作用就是方法执行完成之后的返回操作。在操作数栈中,一项运算通常由多个子运算(subcomputation)嵌套进行,一个子运算过程的结果可以被其他外围运算所使用。

在此大家需要注意,在操作数栈中的数据必须进行正确的操作。比如不能在入栈2个int类型的数值后,却把它们当做long类型的数值去操作,或者入栈2个double类型的数值后,使用iadd指令对它们执行加法运算等情况出现。

以上是关于Jvm(61),虚拟机字节码执行引擎----操作数栈的主要内容,如果未能解决你的问题,请参考以下文章

深入理解JVM学习笔记——-8虚拟机字节码执行引擎

深入理解JVM学习笔记——-8虚拟机字节码执行引擎

Jvm(59),虚拟机字节码执行引擎----运行时栈帧结构

JVM字节码执行引擎和动态绑定原理

基于栈的虚拟机字节码执行引擎

《JVM系列》 第七章 -- 字节码执行引擎