引子:
這是本系列的最后一篇文章(后面如果有必要的話會(huì)寫一篇關(guān)于mini jvm代碼實(shí)現(xiàn), 類結(jié)構(gòu)的文章, 讓大家更好的理解), 介紹一下jvm的執(zhí)行引擎. 其實(shí)一個(gè)執(zhí)行引擎要做的事情就是找到class的main方法, 然后從main方法開始執(zhí)行整個(gè)程序, 直到程序結(jié)束. 而執(zhí)行的代碼就在之前解析的方法數(shù)據(jù)結(jié)構(gòu)中的Code Attribute屬性中.
1. 運(yùn)行時(shí)棧幀結(jié)構(gòu)
之前解析的class文件都是一些靜態(tài)的結(jié)構(gòu), 當(dāng)執(zhí)行引擎運(yùn)行的時(shí)候需要把之前靜態(tài)的結(jié)構(gòu)轉(zhuǎn)成運(yùn)行時(shí)的結(jié)構(gòu). 先來看一看JVM的運(yùn)行時(shí)結(jié)構(gòu)
因?yàn)镴VM是一個(gè)基于棧的虛擬機(jī), 所以基本上所有的操作都是需要通過對(duì)棧的操作完成的. 執(zhí)行的過程就是從main函數(shù)開始(一開始就會(huì)為main函數(shù)創(chuàng)建一個(gè)函數(shù)棧幀), 執(zhí)行main函數(shù)的指令(在Code Attribute中), 如果要調(diào)用方法就創(chuàng)建一個(gè)新的函數(shù)棧幀, 如果函數(shù)執(zhí)行完成就彈出第一個(gè)函數(shù)棧幀.
2. JVM的指令
不管你在java源文件中寫了什么函數(shù), 用了什么NB的算法, 經(jīng)過編譯器的編譯, 到了class文件中都是一個(gè)個(gè)的字節(jié), 而Code Attribute中的code[]字段中的字節(jié)就是函數(shù)翻譯過來的字節(jié)碼指令.
JVM支持的指令大致上可以分成3種沒有操作數(shù)的, 1個(gè)操作數(shù)的, 2個(gè)操作數(shù)的. 因?yàn)镴VM用一個(gè)字節(jié)來表示指令, 所以指令的最多只有256個(gè).
JVM指令通用形式如下:
所以mini jvm就是要用java來執(zhí)行JVM的指令來完成功能
3. 幾個(gè)常用的指令解析
因?yàn)閖vm的指令太多了, 在這里不可能全部都解析一遍, 所以就選擇了幾個(gè)mini jvm中比較關(guān)鍵的也已經(jīng)實(shí)現(xiàn)了的指令進(jìn)行解析
3.1 invokespecial
說明: invokespecial用于調(diào)用實(shí)例方法, 專門用來處理調(diào)用超類方法产场、私有方法和實(shí)例初始化方法.
indexByte1和indexByte2用于組成常量池中的索引((indexbyte1 << 8)|indexbyte2). 所指向的常量項(xiàng)必須是MethodRef Info類型. 同時(shí)該條指令還會(huì)創(chuàng)建一個(gè)函數(shù)棧幀, 然后從當(dāng)前的操作數(shù)棧中出棧被調(diào)用的方法的參數(shù), 并且將其放到被調(diào)用方法的函數(shù)棧幀的本地變量表中.
3.2 aload_n
說明: aload_n從局部變量表加載一個(gè) reference 類型值到操作數(shù)棧中. 至于從當(dāng)前函數(shù)棧幀的本地變量表中加載哪個(gè)變量是有N的值決定的.
3.3 astore_n
說明: 將一個(gè) reference 類型數(shù)據(jù)保存到局部變量表中. 至于保存在局部變量表的哪個(gè)位置就由N的值決定.
好了, 指令就介紹到這里, 要看所有指令的說明可以看oracle的jvm指令集. 里面有對(duì)每一個(gè)指令的詳細(xì)說明.
所以執(zhí)行引擎要做的工作就是根據(jù)每一個(gè)指令要執(zhí)行的功能進(jìn)行對(duì)應(yīng)的實(shí)現(xiàn).
至于到底是怎么做的就請(qǐng)大家看代碼吧, 這里就不詳述了.
4. 總結(jié)
對(duì)于真正的jvm, 現(xiàn)在實(shí)現(xiàn)的mini jvm的功能真的是太弱太弱了, 但是即使是實(shí)現(xiàn)這么弱的功能也花費(fèi)了我大概一個(gè)月的時(shí)間, 可想而知真正的jvm的功能的強(qiáng)大以及其的復(fù)雜度.
這次的mini jvm主要是對(duì)之前看的一些jvm的文章書籍的一次實(shí)戰(zhàn)演練, 雖然實(shí)現(xiàn)的功能比較弱, 但是更加形象的了解了jvm的組成, java代碼的執(zhí)行流程, 雖然還不能像第一篇文章開頭說的那樣對(duì)自己寫的每一個(gè)字節(jié)都了如指掌, 但是相比較以前也是有了長足的進(jìn)步.
總之, 這次的mini jvm自己是受益良多. 其中代碼中留下的一些todo在后面也會(huì)慢慢的補(bǔ)充, 如果有同學(xué)感興趣的話歡迎一起來完善這個(gè)"小玩意".
5. 代碼地址
6. 參考
- 深入理解Java虛擬機(jī):JVM高級(jí)特性與最佳實(shí)踐(第2版)
- 深入java虛擬機(jī)第二版
7. 本系列其他文章
手把手教你擼一個(gè)Mini JVM系列(1)之解析Class File -- 初探
手把手教你擼一個(gè)Mini JVM系列(2)之解析Class File -- 常量池
手把手教你擼一個(gè)Mini JVM系列(3)之解析Class File -- 字段、方法、屬性
手把手教你擼一個(gè)Mini JVM系列(5)之源碼分析 -- 常量池从撼、訪問標(biāo)志胚嘲、類索引
手把手教你擼一個(gè)Mini JVM系列(6)之控制流 -- 條件判斷和循環(huán)