張世杰
摘要:該文介紹了基于Golang的GOJVM的總體設計以及各功能模塊的實現(xiàn),通過功能測試說明它支持自動拆裝箱、反射等Java語言特性,并對Java1.5-1.8的程序可以正確解析并解釋執(zhí)行。
關(guān)鍵詞:Java;Golang;Java虛擬機
中圖分類號:TP311? ? 文獻標識碼:A
文章編號:1009-3044(2019)27-0077-02
1 緒論
在企業(yè)開發(fā)中,Java虛擬機的底層運行及結(jié)構(gòu)設計非常重要。然而學習Java的運行原理、特性實現(xiàn)以及相關(guān)虛擬機以及操作系統(tǒng)的底層知識對企業(yè)運維人員卻存在一定的困難[1]。因此,基于Golang設計并實現(xiàn)一款Java虛擬機GOJVM(Golang Java virtual machines)[2],摒棄繁雜的細節(jié),通過GOJVM的運行和源碼,從底層開始,認識虛擬機理論、操作系統(tǒng)以及相關(guān)數(shù)據(jù)結(jié)構(gòu)和算法將有助于學習者盡快掌握相關(guān)知識。
2 總體設計
GOJVM虛擬機根據(jù)功能需要分為命令行參數(shù)和JVM虛擬機兩大模塊,具體的各個功能模塊如圖1所示。
GOJVM調(diào)用CMD進行命令行參數(shù)解析,判斷是否啟動JVM。正常啟動后根據(jù)命令行參數(shù)或是系統(tǒng)變量,首先調(diào)用classpath模塊,解析并獲取JRE路徑;然后調(diào)用classfile模塊加載標準庫類文件,解析和初始化虛擬機;通過調(diào)用rtda模塊申請并維護為Java提供寄存器、計數(shù)器、方法棧等運行時的數(shù)據(jù)區(qū);最后調(diào)用解釋器模塊,啟動指定類文件的main函數(shù)。
2.1命令行參數(shù)模塊
為了模擬Oracle的Java指令,GOJVM需要一個命令行工具用于接受選項、主類名、main()方法三組參數(shù),進而確定GOJVM的運行方式,同時設計了一個-j指令,用于打印所使用的JRE路徑和JRE路徑的來源[3]。另外,設計-showClass和-log兩個選項用于使用戶清晰地看到Java運行的方式和類加載過程。-showClass指定虛擬機運行時將類加載過程打印到控制臺,-log指定虛擬機打印出程序執(zhí)行過程中執(zhí)行的Java字節(jié)碼指令。Golang標準庫中自帶了flag包,通過調(diào)用flag.BoolVar、flag.StringVar、flag.Parse等方法將命令行參數(shù)解析并注入一個CMD結(jié)構(gòu)體之中,最終返回CMD結(jié)構(gòu)體指針。
2.2 JVM模塊
本模塊首先接受CMD模塊封裝好的命令行參數(shù)、運行類名以及Java程序參數(shù);然后調(diào)用classpath模塊解析JRE路徑;再通過調(diào)用運行時數(shù)據(jù)區(qū)模塊,初始化類加載器,對JRE路徑下的標準庫進行加載;最后初始化運行時數(shù)據(jù)區(qū),返回一個包裝命令行參數(shù)、Class Loader、主線程的JVM對象[4]。
1)classpath模塊
GOJVM使用class path進行類的搜索,同時使用Oracle JDK附帶的JRE來作為Java類庫。在實現(xiàn)中,類路徑分為三類,分別為啟動類路徑(bootstrap classpath)、擴展類路徑(extension classpath)和用戶類路徑(user classpath)[5]。具體流程如圖2所示。
由于GOJVM需要能從多種形式的類路徑中查找class文件,因此將類路徑抽象為一個接口,Golang定義如下:
需要支持的類路徑形式有目錄形式、zip或jar包形式、組合類路徑模式。
2)classfile模塊
classpath模塊已經(jīng)將class文件正確加載到內(nèi)存中,但是二進制字節(jié)碼[7] 的文件內(nèi)容直接使用并不方便,因此需要對文件內(nèi)容進行解析和封裝。抽象出的classfile模塊嚴格按照Java虛擬機的規(guī)范對class文件進行解析。Java類文件格式通過使用常量池,在一定程度上實現(xiàn)了其緊湊性[6]。
3)運行時數(shù)據(jù)區(qū)模塊
虛擬機在運行程序時,需要存儲空間存放運行時所需要的數(shù)據(jù),這個區(qū)域就是運行時數(shù)據(jù)區(qū)。Java虛擬機規(guī)范定義了在程序執(zhí)行過程中使用的各種運行時數(shù)據(jù)區(qū)域[7]。
4)指令模塊
虛擬機定義了205條指令,并依據(jù)虛擬機規(guī)范逐個實現(xiàn)這些指令。Java字節(jié)碼指令自帶了操作數(shù)類型,分為常量指令、存儲指令、加載指令、數(shù)學指令、操作數(shù)棧指令、比較指令、轉(zhuǎn)換指令、引用指令、控制指令、擴展指令和保留指令。一個指令的執(zhí)行首先獲取該指令的操作數(shù),其次執(zhí)行指令相應的操作。
5)解釋器模塊
解釋器主要是根據(jù)Java程序的指令運行,直至程序結(jié)束。核心是通過loop()函數(shù)循環(huán)執(zhí)行計算pc、解碼指令、執(zhí)行指令三個步驟。
6)本地方法模塊
對操作系統(tǒng)中的基本系統(tǒng)調(diào)用主要通過本地方法完成[10]。首先完成本地方法注冊表,將已經(jīng)實現(xiàn)的所有本地方法,定義一個go文件并注冊在一個map之中,使用類名、方法名、方法描述符來確定一個方法。
然后設計本地方法調(diào)用功能,在本地方法調(diào)用時,使用虛擬機棧frame的0XFE和0XFF兩條指令,構(gòu)造一個空的虛擬機棧幀,從本地方法注冊表查找本地方法實現(xiàn)并執(zhí)行[8]。
3 系統(tǒng)測試
1)命令行參數(shù)模塊測試
[功能 功能說明 測試用例 測試結(jié)果 打印幫助 打印出GOJVM命令行幫助信息 -help、-? 通過 指定classpath 指定classpath搜尋和加載類文件 -cp、-classpath 通過 打印classpath路徑 打印出classpath的來源類型和值 -j 通過 打印類加載過程 類加載打印出類文件路徑以及類名 -showClass 通過 打印指令 打印出解釋器執(zhí)行的字節(jié)碼指令 -log 通過 打印版本 輸出GOJVM版本信息 -version 通過 ]
2)classpath模塊測試
[功能 功能說明 測試用例 測試結(jié)果 解析出classpath 解析出啟動類路徑、擴展類路徑
用戶類路徑三種類路徑 JAVA_HOME 通過 讀取class文件 將class文件的內(nèi)容加載進內(nèi)存 HelloWorld 通過 ]
3)classfile模塊測試
[功能 功能說明 測試用例 測試結(jié)果 檢測class版本 對class文件校驗
不支持版本程序拋出異常 Jdk12編譯的HelloWorld 通過 解析class文件 從文件內(nèi)容中解析出類的各項數(shù)據(jù) Stack 通過 ]
4)集成測試
軟件測試是為了發(fā)現(xiàn)錯誤而執(zhí)行程序的過程[14]。本地方法模塊、運行時數(shù)據(jù)區(qū)模塊、解釋器模塊等與其他模塊耦合較深,因此不參與單元測試,直接進行集成功能測試。
[功能 功能說明 測試用例 測試結(jié)果 HelloWorld 打印hello world,測試程序能否運行 HelloWorld.class 通過 數(shù)學支持 測試數(shù)學相關(guān)指令是否正確 MathTest.class 通過 字符串支持 測試字符串拼接、輸出功能 StringTest.class 通過 函數(shù)調(diào)用與返回 測試能否正常獲取函數(shù)返回值 FibonacciTest.class 通過 異常處理 測試Java異常處理機制支持 ExceptionTest.class 通過 反射支持 測試能否實現(xiàn)Java反射功能 ArrayClassTest.class 通過 Switch支持 測試switch功能 SwitchTest.class 通過 ]
4 結(jié)論
本文在對Java虛擬機理論和設計規(guī)范的詳細研究基礎(chǔ)之上,完成了基于Golang的Java虛擬機GOJVM的實現(xiàn),并對Java相關(guān)功能在該虛擬機上進行了測試。目前該虛擬機實現(xiàn)僅支持到Java 8,今后將會繼續(xù)改進對Java 9、10、11、12的支持。
參考文獻:
[1] 王勝利.淺談Java虛擬機的內(nèi)部機制[J].軍民兩用技術(shù)與產(chǎn)品,2017(16):57.
[2] Meyerson J.The Go Programming Language[J]. IEEE Software, 2014,31(5):104.
[3] 張秀宏.自己動手寫Java虛擬機[M].北京:機械工業(yè)出版社,2016.
[4] 周志明.深入理解Java虛擬機[M]. 北京: 機械工業(yè)出版社, 2013.
[5] 張洪娜,劉怡俊, 艾君銳. Java Class文件的結(jié)構(gòu)分析及其解析執(zhí)行[J].計算機應用與軟件, 2011,28(7):180-182.
[6] Tim Lindholm, Frank Yellin. Java Virtual Machine Specification[Z]// The Java Virtual Machine Specification: Java SE. 2016.
[7] Tim Lindholm, Frank Yellin. Java Virtual Machine Specification[Z]// The Java Virtual Machine Specification: Java SE. 2016.
[8] 安百俊,高棟,張偉,等.通過Java調(diào)用本地方法[J].微處理機, 2011,32(2):41-44.
【通聯(lián)編輯:梁書】