我提到了下面的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时会有什么例子?
答案 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
时会有什么示例?
long
或double
值;例如从方法调用中丢弃不需要的long
结果,或int
值。请注意,当前生成 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类。