• 操作数栈


     操作数栈

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

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

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

    1. public void testAddOperation();  
    2.         Code:  
    3.           0: bipush        15  
    4.      2: istore_1  
    5.      3: bipush        8  
    6.      5: istore_2  
    7.      6: iload_1  
    8.      7: iload_2  
    9.      8: iadd  
    10.      9: istore_3  
    11.      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指令对它们执行加法运算等情况出现。

  • 相关阅读:
    TSQL编程的全局变量
    一、读大学,究竟读什么?
    受用一生的心理寓言
    字符串函数
    android wait notify实现线程挂起与恢复
    Java Thread.interrupt 中断JAVA线程
    android实现文件下载功能的3种方法
    Android startActivityForResult 和 setResult的使用
    Android 软键盘盖住输入框的问题
    Android蓝牙操作
  • 原文地址:https://www.cnblogs.com/shizhiyi/p/7857764.html
Copyright © 2020-2023  润新知