操作數棧


 操作數棧

每一個獨立的棧幀中除了包含局部變量表以外,還包含一個后進先出(Last-In-First-Out)的操作數棧,也可以稱之為表達式棧(Expression Stack)。操作數棧和局部變量表在訪問方式上存在着較大差異,操作數棧並非采用訪問索引的方式來進行數據訪問的,而是通過標准的入棧和出棧操作來完成一次數據訪問。每一個操作數棧都會擁有一個明確的棧深度用於存儲數值,一個32bit的數值可以用一個單位的棧深度來存儲,而2個單位的棧深度則可以保存一個64bit的數值,當然操作數棧所需的容量大小在編譯期就可以被完全確定下來,並保存在方法的Code屬性中。

在HotSpot中,除了PC寄存器之外,再也沒有包含其他任何的寄存器,並且之前曾經提及過,HotSpot中任何的操作都需要經過入棧和出棧來完成,那么由此可見,HotSpot的執行引擎架構必然就是基於棧式架構,而非傳統的寄存器架構。簡單來說,操作數棧就是JVM執行引擎的一個工作區,當一個方法被調用的時候,一個新的棧幀也會隨之被創建出來,但這個時候棧幀中的操作數棧卻是空的,只有方法在執行的過程中,才會有各種各樣的字節碼指令往操作數棧中執行入棧和出棧操作。比如在一個方法內部需要執行一個簡單的加法運算時,首先需要從操作數棧中將需要執行運算的兩個數值出棧,待運算執行完成后,再將運算結果入棧。如下所示:

代碼8-2  執行加法運算的字節碼指令

  1. public void testAddOperation();  
  2.         Code:  
  3.           0: bipush        15  
  4.      2: istore_1  
  5.      3: bipush        8  
  6.      5: istore_2  
  7.      6: iload_1  
  8.      7: iload_2  
  9.      8: iadd  
  10.      9: istore_3  
  11.      10: return 

在上述字節碼指令示例中,首先會由“bipush”指令將數值15從byte類型轉換為int類型后壓入操作數棧的棧頂(對於byte、short和char類型的值在入棧之前,會被轉換為int類型),當成功入棧之后,“istore_1”指令便會負責將棧頂元素出棧並存儲在局部變量表中訪問索引為1的Slot上。接下來再次執行“bipush”指令將數值8壓入棧頂后,通過“istore_2”指令將棧頂元素出棧並存儲在局部變量表中訪問索引為2的Slot上。“iload_1”和“iload_2”指令會負責將局部變量表中訪問索引為1和2的Slot上的數值15和8重新壓入操作數棧的棧頂,緊接着“iadd”指令便會將這2個數值出棧執行加法運算后再將運算結果重新壓入棧頂,“istore_3”指令會將運算結果出棧並存儲在局部變量表中訪問索引為3的Slot上。最后“return”指令的作用就是方法執行完成之后的返回操作。在操作數棧中,一項運算通常由多個子運算(subcomputation)嵌套進行,一個子運算過程的結果可以被其他外圍運算所使用。

在此大家需要注意,在操作數棧中的數據必須進行正確的操作。比如不能在入棧2個int類型的數值后,卻把它們當做long類型的數值去操作,或者入棧2個double類型的數值后,使用iadd指令對它們執行加法運算等情況出現。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM