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 處的指令之后達到一次。
然而,這并不意味著編譯器必須執行這樣的指令分析。編譯器具有從源代碼派生的代碼的更高級別模型,稱為抽象語法樹。
該結構將用于生成生成的字節碼,并且它還可能已經能夠預測該級別所需的堆棧大小。但是編譯器實際上是如何做到的,是依賴于實現的。
添加回答
舉報