教你用Java開(kāi)發(fā)一個(gè)簡(jiǎn)單的JVM

一崎苗、前言

幾年前冯凹,接到一個(gè)開(kāi)發(fā)任務(wù):用Java開(kāi)發(fā)能運(yùn)行Java智能合約的虛擬機(jī)。在開(kāi)發(fā)Java智能合約時(shí)荞怒,只能使用智能合約SDK提供的類和一些Java常用類(8種基本數(shù)據(jù)類型包裝類耻讽;String察纯、BigInteger、BigDecimal针肥、List饼记、Map、Set 相關(guān)的類)慰枕。

完整的Java智能合約虛擬機(jī)比較復(fù)雜具则,且要保存Java智能合約狀態(tài)。 這篇文章僅介紹一個(gè)簡(jiǎn)單JVM實(shí)現(xiàn)具帮,支持少量字節(jié)碼博肋。 參考 Java 虛擬機(jī)規(guī)范(Java SE 8),里面寫到:要正確實(shí)現(xiàn) Java 虛擬機(jī)蜂厅,只需能夠讀取class文件格式并正確執(zhí)行其中指定的操作束昵。為了簡(jiǎn)化實(shí)現(xiàn),使用了 ASM解析class文件 葛峻。

二、使用ASM解析class文件

使用 ASM Tree API 解析class文件巴比,獲得一個(gè) ClassNode 對(duì)象术奖,里面包含 class 文件的各種信息。要運(yùn)行class定義的方法轻绞,先在ClassNode中找到這個(gè)方法(MethodNode包含方法的各種信息)采记,然后執(zhí)行方法的指令集。MethodNode.instructions 是這個(gè)方法的指令集政勃,遍歷指令集唧龄,執(zhí)行每個(gè)指令,只要正確執(zhí)行了指令奸远,方法就能完成運(yùn)行既棺。

教你用Java開(kāi)發(fā)一個(gè)簡(jiǎn)單的JVM

三、實(shí)現(xiàn)JVM運(yùn)行時(shí)數(shù)據(jù)區(qū)

要正確執(zhí)行指令懒叛,先要了解JVM結(jié)構(gòu)丸冕,參考 Java虛擬機(jī)規(guī)范第二章(JVM結(jié)構(gòu)),里面介紹了JVM運(yùn)行時(shí)數(shù)據(jù)區(qū)薛窥,定義了在程序執(zhí)行期間使用的各種運(yùn)行時(shí)數(shù)據(jù)區(qū)胖烛,如圖所示:

教你用Java開(kāi)發(fā)一個(gè)簡(jiǎn)單的JVM

下面簡(jiǎn)要介紹各種運(yùn)行時(shí)數(shù)據(jù)區(qū)眼姐,詳細(xì)信息查看 Java虛擬機(jī)規(guī)范第二章(JVM結(jié)構(gòu)),根據(jù)這些信息佩番,可以簡(jiǎn)單實(shí)現(xiàn)各種運(yùn)行時(shí)數(shù)據(jù)區(qū)众旗。

3.1 程序計(jì)數(shù)器

Java 虛擬機(jī)可以同時(shí)支持多個(gè)執(zhí)行線程。每個(gè)線程都有自己的程序計(jì)數(shù)器趟畏。程序計(jì)數(shù)器包含當(dāng)前線程正在執(zhí)行的 Java 虛擬機(jī)指令的地址贡歧。

程序計(jì)數(shù)器最主要作用就是包含當(dāng)前指令,程序計(jì)數(shù)器簡(jiǎn)單實(shí)現(xiàn)如下:

教你用Java開(kāi)發(fā)一個(gè)簡(jiǎn)單的JVM

3.2 虛擬機(jī)棧

每個(gè) Java 虛擬機(jī)線程都有一個(gè)Java 虛擬機(jī)棧拱镐。虛擬機(jī)棧存儲(chǔ)棧幀艘款,推入和彈出棧幀。

虛擬機(jī)棧就是一個(gè)保存棧幀的棧沃琅,實(shí)現(xiàn)如下:

教你用Java開(kāi)發(fā)一個(gè)簡(jiǎn)單的JVM

3.2.1 棧幀

每次調(diào)用方法時(shí)都會(huì)創(chuàng)建一個(gè)棧幀哗咆,每個(gè)棧幀都有自己的局部變量數(shù)組和操作數(shù)棧,局部變量數(shù)組和操作數(shù)棧的大小在編譯時(shí)確定益眉。

新棧幀推入虛擬機(jī)棧晌柬,虛擬機(jī)棧的棧頂棧幀是當(dāng)前正在執(zhí)行的活動(dòng)棧幀,稱為當(dāng)前棧幀郭脂,其方法稱為當(dāng)前方法年碘,定義當(dāng)前方法的類是當(dāng)前類。 在方法返回時(shí)展鸡,當(dāng)前棧幀將其方法調(diào)用的結(jié)果(如果有)傳遞回前一棧幀屿衅。 虛擬機(jī)棧彈出當(dāng)前棧幀,前一棧幀成為當(dāng)前棧幀莹弊。 棧幀包含局部變量和操作數(shù)棧涤久,實(shí)現(xiàn)如下:

教你用Java開(kāi)發(fā)一個(gè)簡(jiǎn)單的JVM
教你用Java開(kāi)發(fā)一個(gè)簡(jiǎn)單的JVM
教你用Java開(kāi)發(fā)一個(gè)簡(jiǎn)單的JVM
教你用Java開(kāi)發(fā)一個(gè)簡(jiǎn)單的JVM

3.2.2 局部變量

每個(gè)棧幀都包含一個(gè)稱為局部變量的變量數(shù)組。Java 虛擬機(jī)使用局部變量在方法調(diào)用時(shí)傳遞參數(shù)忍弛。在類方法調(diào)用中响迂,參數(shù)從局部變量0開(kāi)始。在實(shí)例方法調(diào)用中细疚,局部變量0用于傳遞對(duì)象的引用蔗彤,隨后從局部變量1開(kāi)始傳遞任何參數(shù)。

局部變量用來(lái)傳遞方法參數(shù),實(shí)現(xiàn)如下:

教你用Java開(kāi)發(fā)一個(gè)簡(jiǎn)單的JVM

3.2.3 操作數(shù)棧

每個(gè)棧幀都包含一個(gè)操作數(shù)棧。創(chuàng)建棧幀時(shí)扒腕,操作數(shù)棧為空。Java 虛擬機(jī)提供將常量啦鸣、值從局部變量、字段加載到操作數(shù)棧的指令来氧。其他 Java 虛擬機(jī)指令從操作數(shù)棧中獲取操作數(shù)诫给,對(duì)其進(jìn)行操作香拉,并將結(jié)果推回到操作數(shù)棧上。操作數(shù)棧還用于準(zhǔn)備要傳遞給方法的參數(shù)和接收方法結(jié)果中狂。

操作數(shù)棧就是保存操作數(shù)的棧凫碌,實(shí)現(xiàn)如下:

教你用Java開(kāi)發(fā)一個(gè)簡(jiǎn)單的JVM

3.3 虛擬機(jī)棧

Java 虛擬機(jī)有一個(gè)在所有 Java 虛擬機(jī)線程之間共享的堆。堆是運(yùn)行時(shí)數(shù)據(jù)區(qū)胃榕,從中分配所有類實(shí)例和數(shù)組的內(nèi)存盛险。對(duì)象的堆存儲(chǔ)由垃圾收集器回收,對(duì)象永遠(yuǎn)不會(huì)被顯式釋放勋又。

簡(jiǎn)單實(shí)現(xiàn)堆苦掘,不用考慮垃圾回收,就是用來(lái)保存對(duì)象實(shí)例楔壤,實(shí)現(xiàn)如下:

教你用Java開(kāi)發(fā)一個(gè)簡(jiǎn)單的JVM

3.3.1 局部變量

對(duì)象實(shí)例是通過(guò)引用關(guān)聯(lián)的鹤啡,引用實(shí)現(xiàn)如下:

教你用Java開(kāi)發(fā)一個(gè)簡(jiǎn)單的JVM

3.4 方法區(qū)

Java 虛擬機(jī)有一個(gè)在所有 Java 虛擬機(jī)線程之間共享的方法區(qū)。它存儲(chǔ)每個(gè)類的結(jié)構(gòu)蹲嚣,例如運(yùn)行時(shí)常量池递瑰、字段和方法數(shù)據(jù),以及方法和構(gòu)造函數(shù)的代碼隙畜,包括在類和實(shí)例初始化和接口初始化中使用的特殊方法抖部。

方法區(qū)用來(lái)保存類結(jié)構(gòu),實(shí)現(xiàn)如下:

教你用Java開(kāi)發(fā)一個(gè)簡(jiǎn)單的JVM
教你用Java開(kāi)發(fā)一個(gè)簡(jiǎn)單的JVM
教你用Java開(kāi)發(fā)一個(gè)簡(jiǎn)單的JVM
教你用Java開(kāi)發(fā)一個(gè)簡(jiǎn)單的JVM

3.5 本地方法棧

本地方法棧是為 Java 虛擬機(jī)運(yùn)行 native 方法服務(wù)的议惰,由于很多 native 方法都是用 C 語(yǔ)言實(shí)現(xiàn)的慎颗,所以它通常又叫 C 棧。本地方法棧與虛擬機(jī)棧所發(fā)揮的作用非常相似言询,甚至有的虛擬機(jī)直接把本地方法棧和虛擬機(jī)棧合二為一哗总。

四、實(shí)現(xiàn)JVM

前面對(duì)JVM運(yùn)行時(shí)數(shù)據(jù)區(qū)做了簡(jiǎn)單實(shí)現(xiàn)倍试,現(xiàn)在需要把這些運(yùn)行時(shí)數(shù)據(jù)區(qū)關(guān)聯(lián)起來(lái),實(shí)現(xiàn)一個(gè)簡(jiǎn)單JVM蛋哭,這個(gè)JVM不考慮線程县习,直接在Jvm類中關(guān)聯(lián)運(yùn)行時(shí)數(shù)據(jù)區(qū)。

簡(jiǎn)單JVM實(shí)現(xiàn)如下:

教你用Java開(kāi)發(fā)一個(gè)簡(jiǎn)單的JVM
教你用Java開(kāi)發(fā)一個(gè)簡(jiǎn)單的JVM
教你用Java開(kāi)發(fā)一個(gè)簡(jiǎn)單的JVM
教你用Java開(kāi)發(fā)一個(gè)簡(jiǎn)單的JVM
教你用Java開(kāi)發(fā)一個(gè)簡(jiǎn)單的JVM
教你用Java開(kāi)發(fā)一個(gè)簡(jiǎn)單的JVM

這是一個(gè)簡(jiǎn)單JVM谆趾,不會(huì)實(shí)現(xiàn)所有字節(jié)碼躁愿,寫一個(gè)示例合約,運(yùn)行這個(gè)合約時(shí)沪蓬,用到了哪些字節(jié)碼彤钟,就實(shí)現(xiàn)哪些字節(jié)碼。

五跷叉、示例合約

寫一個(gè)示例合約:

教你用Java開(kāi)發(fā)一個(gè)簡(jiǎn)單的JVM

寫一個(gè)智能合約SDK提供的工具類逸雹,里面有一個(gè)native方法营搅,需要JVM去調(diào)用真正的實(shí)現(xiàn)。

教你用Java開(kāi)發(fā)一個(gè)簡(jiǎn)單的JVM

native方法實(shí)現(xiàn)

教你用Java開(kāi)發(fā)一個(gè)簡(jiǎn)單的JVM
教你用Java開(kāi)發(fā)一個(gè)簡(jiǎn)單的JVM

運(yùn)行示例合約

教你用Java開(kāi)發(fā)一個(gè)簡(jiǎn)單的JVM

六梆砸、實(shí)現(xiàn)字節(jié)碼

運(yùn)行示例合約转质,可以看到需要實(shí)現(xiàn)哪些字節(jié)碼,把這些字節(jié)碼都實(shí)現(xiàn)帖世。多次運(yùn)行休蟹、實(shí)現(xiàn)后,相關(guān)字節(jié)碼都實(shí)現(xiàn)了日矫。再次運(yùn)行赂弓,就可以看到控制臺(tái)輸出:1024。

實(shí)現(xiàn)參考 Java虛擬機(jī)規(guī)范第六章(JVM指令集)哪轿,下面是其中一個(gè)字節(jié)碼的實(shí)現(xiàn)盈魁,更多字節(jié)碼實(shí)現(xiàn),可以看完整代碼缔逛。

教你用Java開(kāi)發(fā)一個(gè)簡(jiǎn)單的JVM

七备埃、結(jié)束

這是一個(gè)簡(jiǎn)單的JVM,很多實(shí)現(xiàn)都很簡(jiǎn)化褐奴“唇牛可以不斷豐富示例代碼,然后實(shí)現(xiàn)更多字節(jié)碼敦冬,在實(shí)現(xiàn)字節(jié)碼過(guò)程中辅搬,就會(huì)發(fā)現(xiàn)以前實(shí)現(xiàn)的問(wèn)題,多次迭代后脖旱,JVM就會(huì)更完善堪遂。

下載完整代碼:
https://gitee.com/xdehuan/contract-jvm

希望以上內(nèi)容能對(duì)有需要的人有所幫助

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市萌庆,隨后出現(xiàn)的幾起案子溶褪,更是在濱河造成了極大的恐慌,老刑警劉巖践险,帶你破解...
    沈念sama閱讀 206,311評(píng)論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件猿妈,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡巍虫,警方通過(guò)查閱死者的電腦和手機(jī)彭则,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,339評(píng)論 2 382
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)占遥,“玉大人俯抖,你說(shuō)我怎么就攤上這事⊥咛ィ” “怎么了芬萍?”我有些...
    開(kāi)封第一講書人閱讀 152,671評(píng)論 0 342
  • 文/不壞的土叔 我叫張陵尤揣,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我担忧,道長(zhǎng)芹缔,這世上最難降的妖魔是什么? 我笑而不...
    開(kāi)封第一講書人閱讀 55,252評(píng)論 1 279
  • 正文 為了忘掉前任瓶盛,我火速辦了婚禮最欠,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘惩猫。我一直安慰自己芝硬,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,253評(píng)論 5 371
  • 文/花漫 我一把揭開(kāi)白布轧房。 她就那樣靜靜地躺著拌阴,像睡著了一般。 火紅的嫁衣襯著肌膚如雪奶镶。 梳的紋絲不亂的頭發(fā)上迟赃,一...
    開(kāi)封第一講書人閱讀 49,031評(píng)論 1 285
  • 那天,我揣著相機(jī)與錄音厂镇,去河邊找鬼纤壁。 笑死,一個(gè)胖子當(dāng)著我的面吹牛捺信,可吹牛的內(nèi)容都是我干的酌媒。 我是一名探鬼主播,決...
    沈念sama閱讀 38,340評(píng)論 3 399
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼迄靠,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼秒咨!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起掌挚,我...
    開(kāi)封第一講書人閱讀 36,973評(píng)論 0 259
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤雨席,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后吠式,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體舅世,經(jīng)...
    沈念sama閱讀 43,466評(píng)論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 35,937評(píng)論 2 323
  • 正文 我和宋清朗相戀三年奇徒,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片缨硝。...
    茶點(diǎn)故事閱讀 38,039評(píng)論 1 333
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡摩钙,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出查辩,到底是詐尸還是另有隱情胖笛,我是刑警寧澤网持,帶...
    沈念sama閱讀 33,701評(píng)論 4 323
  • 正文 年R本政府宣布,位于F島的核電站长踊,受9級(jí)特大地震影響功舀,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜身弊,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,254評(píng)論 3 307
  • 文/蒙蒙 一辟汰、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧阱佛,春花似錦帖汞、人聲如沸。這莊子的主人今日做“春日...
    開(kāi)封第一講書人閱讀 30,259評(píng)論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至淮逊,卻和暖如春催首,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背泄鹏。 一陣腳步聲響...
    開(kāi)封第一講書人閱讀 31,485評(píng)論 1 262
  • 我被黑心中介騙來(lái)泰國(guó)打工郎任, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人命满。 一個(gè)月前我還...
    沈念sama閱讀 45,497評(píng)論 2 354
  • 正文 我出身青樓涝滴,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親胶台。 傳聞我的和親對(duì)象是個(gè)殘疾皇子歼疮,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,786評(píng)論 2 345

推薦閱讀更多精彩內(nèi)容