<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协议