1 回答
TA贡献1802条经验 获得超5个赞
由于栈的初始状态,以及每条指令对它的影响是众所周知的,你可以精确地预测,在任何时候,操作数栈上会出现什么样的项:
[ ] // initially empty
[ I ] 0: iload_1
[ ] 1: ifne 6
[ I ] 4: iconst_1
[ ] 5: ireturn
[ I ] 6: iload_1
[ I O ] 7: aload_0
[ I O I ] 8: iload_1
[ I O I I ] 9: iconst_1
[ I O I ] 10: isub
[ I I ] 11: invokevirtual #2 // Method factorial:(I)I
[ I ] 14: imul
[ ] 15: ireturn
JVM 的验证器会这样做,在每条指令之后预测堆栈的内容,以检查它是否适合作为后续指令的输入。但它在这里有帮助,有一个声明的最大大小,所以验证器不需要维护一个动态增长的数据结构或为理论上可能的 64k 堆栈条目预分配内存。使用声明的最大大小,它可以在遇到会推送更多的指令时停止,因此它永远不需要比声明更多的内存。
如您所见,声明的最大堆栈大小恰好iconst_1在索引 9 处的指令之后达到一次。
然而,这并不意味着编译器必须执行这样的指令分析。编译器具有从源代码派生的代码的更高级别模型,称为抽象语法树。
该结构将用于生成生成的字节码,并且它还可能已经能够预测该级别所需的堆栈大小。但是编译器实际上是如何做到的,是依赖于实现的。
添加回答
举报