深入虚拟机笔记之栈和局部变量操作

第10章 栈和局部变量操作

    由于java虚拟机是基于栈的机器,几乎所有java虚拟机的指令都与操作数栈有关;绝大多数指令都会在执行自己功能的时候进行入栈、出栈操作。

    常量入栈操作:操作码在执行常量入栈操作之前,使用三种方式指明常量的值:常量值隐式包含在操作码内部、常量值在字节码流中如同操作数一样紧随在操作码之后、或者从常量池中取出常量。

    一些操作码自行指明入栈的常量的类型和值,相对于从字节码流中取出操作数或者指向常量池的指令来说,这种指令都是冗余指令,但它们更有效率。这种指令在字节码流中仅仅占据一个字节的空间。

    java栈中的每一个位置的长度都是一个字长(至少32为宽)。 每当一个int或者float类型被压入栈时,它都将占据一个位置。

    每当一个long或者double类型的值被压入栈时,它都将占据2个位置。

    aconst_null操作码将一个空的对象引用类型压入栈。给一个对象赋空值的过程中,将会使用该指令。

    byte和short数据类型入栈,整数常量的值必须在byte和short的有效范围之内。紧随操作码的byte或short类型在压入栈之前被扩展成int类型值,将int类型值压入栈的操作实际上取代了将byte和short类型值压入栈的操作。

    从常量池取出常量的操作码使用表示常量池索引的操作数,java虚拟机通过给定的索引查找相应的常量池入口,决定这些常量的类型和值,并把它们压入栈。常量池索引是一个无符号值,在字节码流中紧随在操作码后面。

    ldc和ldc_w两个操作码把一个字长的项压入栈,该项或者是一个int、float类型的值,或者是一个String类型的对象引用。ldc的索引只有一个字节,只能指向常量池中的1-255(0位置没有使用)范围内的位置。ldc_w有两个字节长度的索引,因此,它能指向任何包含long或double类型(占据两个字节)的常量池位置。

    java源码中的所有字符串文字最终都作为入口存储在常量池中,如果同一个应用的多个类使用相同序列的字符串文字,那么此字符串文字将在它的所有类的class文件中出现;java虚拟机解析一个字符串文字的常量池入口时,它“拘留”(intern)这个字符串,这样其他类在解析这个字符串时直接返回被拘留的字符串文字引用,而不会新建一个字符串对象。

    通用栈操作:尽管java虚拟机指令集中的大多数指令只处理一种特定的类型,但还是有一些指令可以今夕类型无关的栈操作;这些通用指令不能用于分解两个字长的值。


 

    局部变量入栈:一些操作码隐式地指向一个通常使用的局部变量位置;而其他局部变量则被一个紧随操作码后的第一个字节位置所代表局部变量索引的操作码压入栈。

    int和float类型的局部变量入栈:

    long和double类型的局部变量入栈:这种指令从栈帧的局部变量区向操作数栈移动了两个字长的数据。

 

    对象引用(占据一个字长)从栈帧的局部变量区向操作数栈移动:

    弹出栈顶部元素,将其赋值给局部变量:对于每个将局部变量压入栈的操作码,都存在对应的弹出栈顶部元素并将其存储到局部变量中的操作码。

    int和float类型出栈操作码:从操作数栈顶部向局部变量移动一个字长的值。

    long和double类型出栈操作码:从操作数栈顶部向局部变量移动两个字长的值。

    对象引用出栈操作数码:从操作数栈顶部弹出一个对象引用,并将其存储到局部变量中。

 

猜你喜欢

转载自jaesonchen.iteye.com/blog/2289515