虛擬機字節碼操作引擎-----基於棧的字節碼解釋引擎
虛擬機調用方法可以有解析和分派兩種方式,那麽虛擬機是如何執行方法中的字節碼指令的?
1.解釋執行
談是解釋執行還是翻譯執行沒有意義了,只有確定了某種具體的java實現版本和執行引擎運行模式時,談解釋執行還是編譯執行才比較貼切。
如今,基於物理機、java虛擬機,或者非Java的其他高級語言虛擬機的語言,大多都會遵循這種基於現代經典編譯原理的思路,在執行前先對程序源碼進行詞法分析和語法分析處理,把源碼轉化為抽象語法樹 。對於一門具體語言的實現來說,詞法分析、語法分析以致後面的優化器和目標代碼生成器都可以選擇獨立於執行引擎,形成一個完整意義的編譯器趨勢線,這類代表是C/C++語言。也可以選擇把其中一部分步驟實現為一個半獨立的編譯期,這類代表是java語言。又或者把這些步驟和執行引擎全部集中封裝在一個封閉的黑匣子之中,如大多數的JavaScript執行器。
Java語言中,javac編譯器完成了程序代碼經過詞法分析、語法分析到抽象語法樹,再遍歷語法樹生成線性的字節碼指令劉的過程。因為這一部分動作是在java虛擬機之外進行的,而解釋器在虛擬機內部,所以java程序的編譯就是半獨立的實現。
2.基於棧的指令集與基於寄存器的指令集
java編譯器輸出的指令劉,基本上是一種基於棧的指令集架構,指令流之中大部分都會是零地址指令,他們依賴於操作數棧進行工作。與之相對的另外一套常用的指令集架構是基於寄存器的指令集,最典型的就是x86的二進制指令集,也是我們主流PC機中直接支持的指令集架構,這些指令依賴寄存器進行工作。這兩種有什麽不同?
舉個例子:1+1
基於棧的指令集會是:
iconst_1
iconst_1
iadd
istore_0
如果基於寄存器,程序可能是:
mov eax,1
add eax,1
mov指令把EAX寄存器的值設為1,然後add指令再把這個值加1,結果就保存在EAX寄存器裏面。
優缺點:
基於棧的指令集主要的優點就是可移植,寄存器由硬件直接提供,程序直接依賴這些硬件寄存器則不可避免地要受到硬件的約束。缺點是執行速度相對來說稍慢一點。
③基於棧的解釋器執行過程
public int calc(){ int a=100; int b=200; int c=300; return(a+b)*c; }
執行偏移地址 | 解釋 | 程序計數器 | 局部變量表 | 棧頂 |
0 | 將100推送到棧頂 | 0 | this | 100 |
1 | 將100出棧放到第一個局部變量slot中 | 1 | this 100 | null |
11 | 第一個局部變量slot中的數值復制到棧頂 | 11 |
this 100 200 300 |
100 |
12 | 第二個局部變量slot中的數值復制到棧頂 | 12 |
this 100 200 300 |
200 |
13 | 將200和100出棧,加完之後入棧 | 13 |
this 100 200 300 |
300 |
14 | b把300復制到操作數棧中,imul和iadd完全類似,下面省略 | 14 |
this 100 200 300 |
300 |
16 | 結束方法並將操作舒展定的整型值返回給此方法的調用者 | 16 |
this 100 200 300 |
90000 |
虛擬機字節碼操作引擎-----基於棧的字節碼解釋引擎