博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
[开源JVM] yvm - 自制Java虚拟机
阅读量:4683 次
发布时间:2019-06-09

本文共 4171 字,大约阅读时间需要 13 分钟。

moonight.png

|

| | comiler-MSVC2017-brightgreen.svg | comiler-gcc7.0-brightgreen.svg

YVM是用C++写的一个Java虚拟机,现在支持Java大部分功能,以及一个基于标记清除算法的并发垃圾回收器. 不过还有很多bug等待修复。

感兴趣的朋友pull request/fork/star吧。

Github repo

已支持语言特性

高级特性逐步支持中,可以开Issue提议或者直接PR

  • Java基本算术运算,流程控制语句,面向对象。

构建和运行

  • 先决条件
    • (>=1.65) 请在CMakeLists.txt中手动配置Boost库位置
    • CMake(>=3.5)
    • C++14
    • gcc/msvc/mingw均可
  • 老生常谈
$ cd yvm$ cmake .$ make -j4$ make test
$ ./yvm --helpUsage:    --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 soonYou 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

运行效果

  • helloworld
    hw.png
    helloworld.png
  • 快速排序
    quicksort_java.png
    quicksort_console.png
  • and more see its github repository ...

开发文档

1. 从字节码到对象

MethodArea负责管理字节码到JavaClass的完整生命周期。MethodArea的方法是自解释的:

class MethodArea {public:    // 方法区需要从运行时目录中搜索相关的*.class文件    MethodArea(const vector
& 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")

现在虚拟机就可以使用这个JavaClass创建对应的对象了:

// yrt 是全局运行时对象,ma表示方法区模块,jheap表示堆模块JavaClass* testClass = yrt.ma->findJavaClass("Test.class");JObject* testInstance = yrt.jheap->createObject(*testClass);

2.1 对象内部构造

虚拟机执行时栈上存放的都是JObject,它的结构如下:

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]>[..] ->   <..,[...]>

2.2 从对象创建到消亡

上面提到,对象持有一个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

部分JDK类是JVM运行攸关的,但由于JDK比较复杂不便于初期开发,所以这里用重写过的JDK代替,源码参见目录,可以使用compilejava.bat进行编译,编译后*.class文件位于.

目前重写过的JDK类有:

  • java.lang.String
  • java.lang.StringBuilder
  • java.lang.Throwable
  • java.lang.Math(::random())
  • java.lang.Runnable
  • java.lang.Thread

和源码中有很多详细的开发文档,如果想探索关于YVM的更多内容,请移步浏览.

License

所有代码基于协议

转载于:https://www.cnblogs.com/ysherlock/p/8688454.html

你可能感兴趣的文章
CSS 文字溢出 变成省略号 ...
查看>>
python线程池/进程池创建
查看>>
java 文件操作
查看>>
Spring事务
查看>>
离线下载最新Dropbox安装包
查看>>
ACM-ICPC 2018 沈阳赛区网络预赛 I(模拟)
查看>>
asp.net 将word文档进行编辑并导出一个新的word
查看>>
如何在CMainFrame类中调用CxxxView视图类中的成员
查看>>
java编程基础(三)流程控制语句
查看>>
让数据库跑的更快的7个MySQL优化建议
查看>>
jquery 取id模糊查询
查看>>
解决在vue中,自用mask模态框出来后,下层的元素依旧可以滑动的问题
查看>>
修改node节点名称
查看>>
Java 文件下载
查看>>
图论——读书笔记 (深度优先搜索)
查看>>
PAT(B) 1014 福尔摩斯的约会(Java)
查看>>
PAT甲级题解-1123. Is It a Complete AVL Tree (30)-AVL树+满二叉树
查看>>
不要过早追求通用
查看>>
带ifrmae的弹窗
查看>>
20172310 2017-2018《程序设计与数据结构》(下)第二周学习总结
查看>>