用 Java 實現一個簡單的虛擬機器器 ?
Learning By Doing.
最近開了個新坑,目的是用 Java 8 實現一個簡單的解釋型 JVM. 目前零零散散提交了 100 多 commits. 最終的目標是 自舉.
目前進度大概 60%,基本的 ClassFile 解析,類載入,位元組碼執行,方法呼叫,物件例項化,多型,介面基本可用.
0x00 背景
mini-jvm 專案的動機.
- 這有點意思.
- 個人日常工作中主要使用 Java,需要對 JVM 有一定的理解,然而 Hotspot 原始碼實在是看不下去.
- Learning By Doing.
寫此文的目的.
- 稍加記錄,以備日後回顧,
- 廣而告之,以期對 JVM 感興趣的同學能瞭解到有這麼一個專案.
- 尋道友,希望感興趣的同學可以聯絡我,以期繼續完善這個專案.
0x01
在實現的過程中,已力保程式碼簡單,可讀,可測. 目前為止程式碼 5000 行出頭,竊以為,對於想了解 JVM 基本原理的同學是個不錯的入門專案. 在此基礎上,為了便於理解一些概念,比如基於棧的虛擬機器器實現原理,會特意實現一個邊緣特性用來快速理解.
0x02 基於棧的虛擬機器器基本實現.
對 JVM 位元組碼執行引擎稍有了解的話,應該對棧幀有所瞭解
棧幀(Stack Frame)是用於支援虛擬機器器進行方法呼叫和方法執行的資料結構 棧幀隨著方法呼叫而建立,隨著方法結束而銷燬,棧幀的儲存空間分配在 Java 虛擬機器器棧中,每個棧幀擁有自己的區域性變量表(Local Variables)運算元棧(Operand Stack)
如果嘗試用過 javap -v classfile,method 區塊亦有所體現.
下面看一個簡單的例子
public class Hello {
public static int return1() {
return 1;
}
}
複製程式碼
編譯並使用
cat <<EOF > Hello.java
public class Hello {
public static int return1() {
return 1;
}
}
EOF
# 很明顯,如果 return1 方法被呼叫,返回結果一定是 1 .
javac Hello.java
javap -v Hello.class
複製程式碼
輸出較長,只摘抄方法部分如下
public static int return1();
descriptor: ()I
flags: ACC_PUBLIC,ACC_STATIC
Code:
stack=1,locals=0,args_size=0
0: iconst_1
1: ireturn
複製程式碼
stack=1 即此方法棧運算元棧大小為 1 locals=0 即此方法區域性變量表大小為 0 args_size 即此方法引數個數為 0
0: iconst_1
1: ireturn
複製程式碼
這即是該方法的位元組碼
0: iconst_1,表示該方法指令集 0 位置 的指令為 iconst_1,iconst_1 的含義是 將 int 值 1 push 到運算元棧.
1: ireturn,表示該方法指令集 1 位置 的指令為 ireturn,ireturn 的含義是,將當前運算元棧棧頂 int 型別值彈出,並且把當前棧幀彈出,並將從運算元棧彈出的 int 型別值 push 到當前棧幀的運算元棧.
類似 iconst_1 這種指令,JVM 規範定義了 200 + 個.
為了方便理解. 專案實現了一個簡單的類組合語言來描述位元組碼,並解釋執行.
return1 1 0 0
0 iconst_1
1 ireturn
複製程式碼
對比上方 javap -v 的輸出,去除了一些冗餘資訊.
下為實際截圖
稍複雜一點的 sum10
更復雜一點的 sumN
0x03 尾聲
簡介到此告一段落,更多資訊可往 github repo 瞭解.
若有興趣參與,務必聯絡我,虛左以待.
聯絡方式
vx: echo "Z3V4aW5na2VfCg==" | base64 -d
mail: echo "YWRtaW5AZ3V4aW5na2UuY29tCg==" | base64 -d
專案地址
github: github.com/guxingke/mi…