基于棧的字節碼解釋執行引擎

聲明:本文摘抄自《深入理解Java虛擬機》一書,本文完全為自我學習,請感興趣的同學購買正版,支持原創

Java語言經常被人們定位為“解釋執行”語言,在Java初生的JDK1.0時代,這種定義還比較準確的,但當主流的虛擬機中都包含了即時編譯后,Class文件中的代碼到底會被解釋執行還是編譯執行,就成了只有虛擬機自己才能準確判斷的事情。再后來,Java也發展出來了直接生成本地代碼的編譯器[如何GCJ(GNU Compiler for the Java)],而C/C++也出現了通過解釋器執行的版本(如CINT),這時候再籠統的說“解釋執行”,對于整個Java語言來說就成了幾乎沒有任何意義的概念。

基于棧的指令集和基于寄存器的指令集

Java編譯器輸出的指令流,基本上是一種基于棧的指令集架構(Instruction Set Architecture,ISA),指令流中的指令大部分都是零地址指令,它們依賴操作數棧進行工作。與之相對應的另一套常用的指令集架構是基于寄存器的指令集,最典型的就是X86的地址指令集,說的通俗一下,就是現在我們主流的PC機中直接支持的指令集架構,這些指令集依賴寄存器工作。那么,基于棧的指令集和基于寄存器的指令集這兩者有什么不同呢?

舉個簡單例子,分別使用這兩種指令計算1+1的結果,基于棧的指令集會是這個樣子:

iconst_1
iconst_1
iadd
istore_0

兩條iconst_1指令連續把兩個常量1壓入棧后,iadd指令把棧頂的兩個值出棧、相加,然后將結果放回棧頂,最后istore_0把棧頂的值放到局部變量表中的第0個Slot中。
如果基于寄存器的指令集,那程序可能會是這個樣子:

mov eax, 1
add eax, 1

mov指令把EAX寄存器的值設置為1,然后add指令再把這個值加1,將結果就保存在EAX寄存器里面。
基于棧的指令集主要的優點就是可移植,寄存器是由硬件直接提供,程序直接依賴這些硬件寄存器則不可避免地要受到硬件的約束。例如,現在32位80x86體系的處理器中提供了8個32位的寄存器,而ARM體系的CPU則提供了16個32位的通用寄存器。如果使用棧架構的指令集,用戶程序不會直接使用寄存器,就可以由虛擬機實現來自行決定把一些訪問最頻繁的數據(程序計數器、棧頂緩存等)放到寄存器中以獲得最好的性能,這樣實現起來也更加簡單一些。棧架構的指令集還有一些其他的優點,如代碼相對更加緊湊,編譯器實現更加簡單等。
棧架構指令集的只要缺點是執行速度相對來說會稍微慢一些。雖然棧架構指令集的代碼非常緊湊,但是完成相同功能所需要的指令數量一般會比寄存器架構多,因為出棧、入棧操作本身就產生了相當多的操作指令數量。
更重要的是,棧實現在內存之中,頻繁的棧操作意味著頻繁的內存訪問,相對于處理器來說,內存始終是執行速度的瓶頸。盡管虛擬機采取棧頂緩存的優化手段,把最常用的操作映射到寄存器中避免直接內存訪問,但這也只能是優化措施而不是解決本質問題的方法。由于指令數量和內存訪問的原因,所以導致棧架構指令集的執行速度會相對較慢。

基于棧的解釋器的執行過程

public int calc() {
    int a = 100;
    int b = 200;
    int c = 300;
    return (a + b) * c;
}

以上面的代碼為例,看看虛擬機是如何執行的。使用javap命令查看它的字節碼指令,字節碼指令如下:

  public int calc();
    descriptor: ()I
    flags: ACC_PUBLIC
    Code:
      stack=2, locals=4, args_size=1
         0: bipush        100
         2: istore_1
         3: sipush        200
         6: istore_2
         7: sipush        300
        10: istore_3
        11: iload_1
        12: iload_2
        13: iadd
        14: iload_3
        15: imul
        16: ireturn
      LineNumberTable:
        line 3: 0
        line 4: 3
        line 5: 7
        line 6: 11
}

編譯后的字節碼指令顯示這段代碼需要深度為2的操作數棧和4個Slot的局部變量空間。我們通過下面幾張圖來了解代碼執行過程中的代碼、操作數棧和局部變量表的變化情況。


執行偏移地址為0的指令情況
  1. 首先執行偏移地址為0的指令,bipush指令的作用是將單個字節的整形常量值(-128~127)推入操作棧頂,跟隨有一個參數,指明推送的常量值,這里是100。
  2. 執行偏移地址為2的指令,istore_1指令的作用是將操作棧頂的整形值出棧并存入局部變量表Slot中。后續4條指令都是做一樣的事情,也就是在對應代碼中把變量a、b、c賦值為100、200、300。
  3. 執行偏移地址為11的指令,iload_1指令的作用是將局部變量表第一個Slot中的整形值復制到操作棧頂。
  4. 執行偏移地址為12的指令,iload_2指令的執行過程與iload_1類似,把第2個Slot的整形值入棧。當前局部變量表和操作棧如下圖所屬:


    執行偏移地址為12的指令情況

    5.執行偏移地址為13的指令,iadd指令的作用是將操作數棧中頭兩個棧頂元素出棧,做整形加法,然后把結果重新入棧。在iadd指令執行完畢后,棧中原有的100和200出棧,它們的和300重新入棧。

  5. 執行偏移地址為14的指令,iload_3指令把存放在第3個局部變量Slot中的300壓入操作棧中。這時操作棧中為兩個整數300。下一條指令imul是將操作棧中頭兩個棧頂元素出棧,做整形乘法,然后把結果重新入棧,與iadd完全類似。
  6. 執行偏移地址16的指令,ireturn指令是方法返回指令之一,它將結束方法執行并將操作棧頂的整形值返回給此方法的調用者。到此為止,這段代碼執行結束。
最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 229,732評論 6 539
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 99,214評論 3 426
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 177,781評論 0 382
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 63,588評論 1 316
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 72,315評論 6 410
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 55,699評論 1 327
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,698評論 3 446
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 42,882評論 0 289
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 49,441評論 1 335
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 41,189評論 3 356
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 43,388評論 1 372
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,933評論 5 363
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,613評論 3 348
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 35,023評論 0 28
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 36,310評論 1 293
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 52,112評論 3 398
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 48,334評論 2 377

推薦閱讀更多精彩內容