<p align="center"><img height="60%" width="80%" src="https://github.com/racaljk/yvm/raw/master/public/moonight.png"></p>java
YVM是用C++寫的一個Java虛擬機,如今支持Java大部分功能,以及一個基於標記清除算法的併發垃圾回收器. 不過還有不少bug等待修復。 感興趣的朋友pull request/fork/star吧。github
https://github.com/racaljk/yvm算法
高級特性逐步支持中,能夠開Issue提議或者直接PR數組
CMakeLists.txt
中手動配置Boost庫位置$ cd yvm $ cmake . $ make -j4 $ make test
$ ./yvm --help Usage: --help List help documentations and usages. --runtime arg Attach java runtime libraries where yvm would lookup classes at --run arg Program which would be executed soon You must specify the "runtime" flag to tell yvm where it could find jdk classes, and also program name is required. $ ./yvm --runtime=C:\Users\Cthulhu\Desktop\yvm\bytecode ydk.test.QuickSort
MethodArea
負責管理字節碼到JavaClass的完整生命週期。MethodArea
的方法是自解釋的:bash
class MethodArea { public: // 方法區須要從運行時目錄中搜索相關的*.class文件 MethodArea(const vector<string>& libPaths); ~MethodArea(); // 查看一個類是否存在 JavaClass* findJavaClass(const string& jcName); //加載jcName類 bool loadJavaClass(const string& jcName); //移除jcName(該方法用於垃圾回收器) bool removeJavaClass(const string& jcName); //連接jcName類,初始化static字段 void linkJavaClass(const string& jcName); //初始化jcName,初始化靜態字段,調用static{} void initJavaClass(CodeExecution& exec, const string& jcName); public: //輔助方法,若是不存在jcName則加載 JavaClass* loadClassIfAbsent(const string& jcName); //若是未連接jcName則連接 void linkClassIfAbsent(const string& jcName); //若是未初始化jcName則初始化 void initClassIfAbsent(CodeExecution& exec, const string& jcName); }
假設磁盤存在一個Test.class
文件,它會經歷以下過程:併發
Test.class[磁盤中]
-> loadJavaClass("Test.class")[內存中]
-> linkJavaClass("Test.class")
->initJavaClass("Test.class")
dom
如今虛擬機就可使用這個JavaClass建立對應的對象了:異步
// yrt 是全局運行時對象,ma表示方法區模塊,jheap表示堆模塊 JavaClass* testClass = yrt.ma->findJavaClass("Test.class"); JObject* testInstance = yrt.jheap->createObject(*testClass);
虛擬機執行時棧上存放的都是JObject,它的結構以下:ui
struct JObject { std::size_t offset = 0; const JavaClass* jc{}; };
offset
惟一表明一個對象,全部在堆上面的操做都須要這個offset。jc
指向對象的Class表示。 堆中的對象是按照<offset,fields>方式進行存放的:
[1] -> [field_a, field_b, field_c] [2] -> [] [3] -> [field_a,field_b] [4] -> [field_a] [..] -> [...]
只要咱們持有offset,就能夠查找/添加/刪除對應的field
數組幾乎和上面相似,只是多了長度,少了Class指針
struct JArray { int length = 0; std::size_t offset = 0; }; [1] -> <3, [field_a, field_b, field_c]> [2] -> <0, []> [3] -> <2, [field_a,field_b]> [4] -> <1, [field_a]> [..] -> <..,[...]>
上面提到,對象持有一個offset和jc,其中jc表示的JavaClass是由MethodArea
負責管理的,offset則是由JavaHeap
負責管理。JavaHeap
提供了大量API,這裏選取的是最重要的:
class JavaHeap { public: //建立對象和數組 JObject* createObject(const JavaClass& javaClass); JArray* createObjectArray(const JavaClass& jc, int length); //獲取對象字段 auto getFieldByName(const JavaClass* jc, const string& name, const string& descriptor, JObject* object); //設置對象字段 void putFieldByName(const JavaClass* jc, const string& name, const string& descriptor, JObject* object, JType* value); //設置數組元素 void putElement(const JArray& array, size_t index, JType* value); //獲取數組元素 auto getElement(const JArray& array, size_t index); //移除對象和數組 void removeArray(size_t offset; void removeObject(size_t offset); };
仍是Test.class
那個例子,假設對應的Test.java
構造以下:
public class Test{ public int k; private String hello; }
在第一步咱們已經獲取到了Test類在虛擬機中的類表示以及對象表示,如今就能夠對類的字段進行操做了:
const JavaClass* testClass = yrt.ma->findJavaClass("Test.class"); JObject* testInstance = yrt.jheap->createObject(*testClass); //獲取hello字段 JObject* helloField = yrt.jheap->getFieldByName(testClass,"hello","Ljava/lang/String;",testInstance); //設置k字段 yrt.jheap->putFieldByName(testClass,"k","I",testInstance);
部分JDK類是JVM運行攸關的,但因爲JDK比較複雜不便於初期開發,因此這裏用重寫過的JDK代替,源碼參見javaclass目錄,可使用compilejava.bat
進行編譯,編譯後*.class
文件位於bytecode. 目前重寫過的JDK類有:
java.lang.String
java.lang.StringBuilder
java.lang.Throwable
java.lang.Math(::random())
java.lang.Runnable
java.lang.Thread
</details>
Wiki和源碼中有不少詳細的開發文檔,若是想探索關於YVM
的更多內容,請移步瀏覽.
全部代碼基於MIT協議