1. 程式人生 > 程式設計 >用 Java 實現一個簡單的虛擬機器器 ?

用 Java 實現一個簡單的虛擬機器器 ?

Learning By Doing.

最近開了個新坑,目的是用 Java 8 實現一個簡單的解釋型 JVM. 目前零零散散提交了 100 多 commits. 最終的目標是 自舉.
目前進度大概 60%,基本的 ClassFile 解析,類載入,位元組碼執行,方法呼叫,物件例項化,多型,介面基本可用.

0x00 背景

mini-jvm 專案的動機.

  1. 這有點意思.
  2. 個人日常工作中主要使用 Java,需要對 JVM 有一定的理解,然而 Hotspot 原始碼實在是看不下去.
  3. Learning By Doing.

寫此文的目的.

  1. 稍加記錄,以備日後回顧,
  2. 廣而告之,以期對 JVM 感興趣的同學能瞭解到有這麼一個專案.
  3. 尋道友,希望感興趣的同學可以聯絡我,以期繼續完善這個專案.

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 的輸出,去除了一些冗餘資訊.
下為實際截圖

1574438006.png

稍複雜一點的 sum10

1574438135.png

更復雜一點的 sumN

1574438239.png

0x03 尾聲

簡介到此告一段落,更多資訊可往 github repo 瞭解.
若有興趣參與,務必聯絡我,虛左以待.

聯絡方式
vx: echo "Z3V4aW5na2VfCg==" | base64 -d
mail: echo "YWRtaW5AZ3V4aW5na2UuY29tCg==" | base64 -d

專案地址
github: github.com/guxingke/mi…