Java jvm中pop指令和pop2指令的区别是什么?

Java jvm中pop指令和pop2指令的区别是什么?,java,jvm,Java,Jvm,我参考了下面的oracle jvm文档 pop操作弹出操作操作数堆栈的顶部值 格式 pop表格pop=87(0x57) 操作数堆栈…,值→ 说明从操作数堆栈中弹出顶部值 除非值是的值,否则不得使用pop指令 第1类计算类型(§2.11.1) pop2操作弹出顶部的一个或两个操作数堆栈值 格式 pop2表格pop2=88(0x58) 操作数堆栈格式1: …,值2,值1→ 其中,value1和value2均为类别1的值 计算类型(§2.11.1) 表格2: …,价值→ 其中,值是第2类计算类

我参考了下面的oracle jvm文档

pop操作弹出操作操作数堆栈的顶部值

格式

pop表格pop=87(0x57)

操作数堆栈…,值→

说明从操作数堆栈中弹出顶部值

除非值是的值,否则不得使用pop指令 第1类计算类型(§2.11.1)

pop2操作弹出顶部的一个或两个操作数堆栈值

格式

pop2表格pop2=88(0x58)

操作数堆栈格式1:

…,值2,值1→

其中,value1和value2均为类别1的值 计算类型(§2.11.1)

表格2:

…,价值→

其中,值是第2类计算类型的值(§2.11.1)

说明从操作数堆栈中弹出顶部的一个或两个值


“从操作数堆栈中弹出顶部的一个或两个值”是什么意思?使用pop2时会有什么例子?

编写一个小java程序,其中包含一个带有

System.currentTimeMillis();
不要使用此调用的结果。然后字节码看起来像

INVOKESTATIC java/lang/System.currentTimeMillis()J
POP2
System.currentTimeMillis()
在堆栈上放置一个长值(64位,宽)。但是,这个堆栈内容不再使用,因此必须弹出它,以便可以访问其他堆栈内容。32位(正常大小)需要一个简单的
POP
,64位(宽大小)需要一个
POP2

“从操作数堆栈中弹出顶部的一个或两个值”是什么意思

这样想吧1:

  • POP
    字节码会弹出一个值,该值占据堆栈上的一个32位字

  • POP2
    字节码要么弹出一个占用两个x 32位字的值,要么弹出两个占用一个x 32位字的值

使用
POP2
时会有什么示例

  • 弹出一个
    long
    double
    值;e、 g.丢弃方法调用产生的不需要的
    long
    结果,或
  • 弹出两个
    int
  • 请注意,当前一代Oracle/OpenJDK
    javac
    编译器不会向POP2发出
    POP2
    值。如果堆栈上有两个32位值需要弹出,编译器将发出两条
    POP
    指令。所以,对于普通Java代码,我不能给出案例2的例子。(但Java或其他语言的第三方编译器可能会使用它,或者人们用其他方式创建字节码。)

    我对JVM内部的了解还不够清楚,但拥有
    POP2
    的一个可能原因是,如果使用两条
    POP
    指令来弹出(比如)一个
    long
    ,那么在序列的一部分,堆栈将处于无效状态。这可能导致验证错误



    1-这不是严格正确的。堆栈上的值严格来说不是32或64位。例如,64位机器上的引用或返回地址是64位。。。但它仍然被建模为1类值。对此的解释是,字节码指令集最初设计用于在32位机器上进行解释。

    POP:从堆栈中弹出顶部的单个字项并将其丢弃

    POP2:从堆栈中删除两个单字项(例如,两个整数,或一个整数和一个对象引用)或一个双字项(例如,双字或沿双字)

    问题中提到的相同javadoc包含以下信息:

    表2.3。Java虚拟机中的实际类型和计算类型

    Actual type Computational type Category 1. byte int 1 2. char int 1 3. short int 1 4. int int 1 5. float float 1 6. reference reference 1 7. returnAddress returnAddress 1 8. boolean int 1 9. long long 2 10. double double 2 上述Java代码生成了以下字节码:

    public static main(String[]) : void
       L0
        LINENUMBER 24 L0
        INVOKESTATIC PopVsPop2.popint () : int
        POP
       L1
        LINENUMBER 25 L1
        INVOKESTATIC PopVsPop2.poplong () : long
        POP2
       L2
        LINENUMBER 26 L2
        INVOKESTATIC PopVsPop2.popLong () : Long
        POP
       L3
        LINENUMBER 27 L3
        RETURN
       L4
        LOCALVARIABLE args String[] L0 L4 0
        MAXSTACK = 2
        MAXLOCALS = 1
    
    如你所见

    popint()-POP-因为int属于类别1

    poplong()-POP2-因为long属于类别2。双人也一样


    popLong()-POP-因为这里Long指的是java.lang.Long,它是一种引用类型。因此属于类别1。

    您是否检查了堆栈中弹出的值的长度?也许pop2可以达到这个目的。@CoronA您能举一个代码片段的例子吗?
    long
    double
    值占据操作数堆栈上的两个插槽。要以原子方式删除它们,
    pop
    指令不是很高-因此特殊的
    pop2
    指令。两个后续的
    pop
    可以工作,但会违反原子性约束,对吗?我假设pop2也用于忽略双返回值。
    public static main(String[]) : void
       L0
        LINENUMBER 24 L0
        INVOKESTATIC PopVsPop2.popint () : int
        POP
       L1
        LINENUMBER 25 L1
        INVOKESTATIC PopVsPop2.poplong () : long
        POP2
       L2
        LINENUMBER 26 L2
        INVOKESTATIC PopVsPop2.popLong () : Long
        POP
       L3
        LINENUMBER 27 L3
        RETURN
       L4
        LOCALVARIABLE args String[] L0 L4 0
        MAXSTACK = 2
        MAXLOCALS = 1