jvm中pop和pop2指令有什么区别?

时间:2018-05-21 11:40:44

标签: java jvm

我提到了下面的oracle jvm doc

https://docs.oracle.com/javase/specs/jvms/se7/html/jvms-6.html#jvms-6.5.pop

  

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

     

格式

     

pop forms pop = 87(0x57)

     

操作数堆栈......,值→

     

...

     

说明从操作数堆栈中弹出最高值。

     

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

     

pop2 操作弹出前一个或两个操作数堆栈值

     

格式

     

pop2表单pop2 = 88(0x58)

     

操作数堆栈表单1:

     

...,value2,value1→

     

...

     

其中value1和value2中的每一个都是类别1的值   计算类型(§2.11.1)。

     

表格2:

     

...,值→

     

...

     

其中value是类别2计算类型的值(第2.11.1节)。

     

说明从操作数堆栈中弹出前一个或两个值。

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

3 个答案:

答案 0 :(得分:4)

使用

编写一个包含main方法的小型java程序
System.currentTimeMillis();

不要使用此调用的结果。然后字节码看起来像

INVOKESTATIC java/lang/System.currentTimeMillis()J
POP2

System.currentTimeMillis()在堆栈上放置一个长值(64位,宽)。然而,这个堆栈内容不再被使用,因此必须弹出它以使其他堆栈内容可达。 32位(正常大小)需要一个简单的POP和64位(宽大小)需要一个POP2

答案 1 :(得分:1)

  

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

以这种方式考虑 1

  • POP字节码会弹出一个占用堆栈上一个x 32位字的值。

  • POP2字节码会弹出占用两个x 32位字的单个值,或者每个占用一个x 32位字的两个值。

  

使用POP2时会有什么示例?

  1. 弹出longdouble值;例如从方法调用中丢弃不需要的long结果,或
  2. 弹出两个int值。
  3. 请注意,当前生成 Oracle / OpenJDK javac编译器不会向弹出2值发出POP2。如果堆栈上有两个需要弹出的32位值,编译器会发出两条POP指令。所以,我不能举例说明普通Java代码的情况#2。 (但是Java或其他语言的第三方编译器可能会使用它。或者人们以其他方式创建字节码。)

    我对JVM内部结构的了解还不够,但有一个可能的原因就是如果你使用两个POP2指令来弹出(比方说)一个POP 1}},然后在序列的一部分,堆栈将处于无效状态。这可能会导致验证错误。

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

答案 2 :(得分:0)

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

正如你所看到的,只有long和double属于Category 2.这是因为所有其他的都是32位,而long和double是64位。

以下示例清楚说明。

public class PopVsPop2 {

public static int popint(){

    return  1;
}

public static long poplong() {
    return 1;
}


public static Long popLong() {
    return 1L;
}

public static void main(String[] args) {    

    popint();
    poplong();
    popLong();
}

上面的javacode有以下生成的字节码:

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 -Because int属于类别1。

poplong() - POP2 - 因为long是2类。同样是double。

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