[开源JVM] yvm - 自制Java虚拟机

moonight.png

中文 | English
| Build Status | comiler-MSVC2017-brightgreen.svg | comiler-gcc7.0-brightgreen.svg

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

Github repo

https://github.com/racaljk/yvm

已支持语言特性

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

  • Java基本算术运算,流程控制语句,面向对象。
  • RTTI
  • 字符串拼接(+,+=符号重载)
  • 异常处理(可输出stacktrace)
  • 创建异步线程
  • Synchronized(支持对象锁)
  • 垃圾回收(标记清除算法)

构建和运行

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

运行效果

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

开发文档

1. 从字节码到对象

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

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")

现在虚拟机就可以使用这个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代替,源码参见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

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

License

所有代码基于MIT协议

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

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/369183.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

MacOSX环境上的多个Java JDK

同样&#xff0c;这是在Mac&#xff08;OSX 10.8.x &#xff09;上配置Java开发环境的一个小技巧。 如果您现在真的开始&#xff0c;我建议您阅读我以前的文章之一 &#xff0c;这是一种快速&#xff0c;干净的方法&#xff08;我想&#xff09;来设置环境变量并开始Java编码。…

浏览器的标准模式和怪异模式

面试题之浏览器的标准模式和怪异模式 1.浏览器的标准模式和怪异模式到底是什么&#xff1f; 标准模式&#xff1a; 是浏览器按照W3C标准解析执行代码&#xff0c;这样用规定的语法去渲染&#xff0c;就可以兼容各个浏览器&#xff0c;保证以正确的形式展示网页。 怪异模式&…

printf函数输出超出int时怎么办

int、long、long long在printf中的格式 https://blog.csdn.net/fz_ywj/article/details/8107582 蓝桥杯 2796. BASIC-11 十六进制转十进制 从键盘输入一个不超过8位的正的十六进制数字符串&#xff0c;将它转换为正的十进制数后输出。   注&#xff1a;十六进制数中的10~15…

升级glibc的影响_Java 11 升级:“债务”“危机”

导读&#xff1a;AJDK11(阿里内部基于openJDK11的定制版本)在19年3月左右发布&#xff0c;到现在也快1年了&#xff0c;不过目前整体使用的面还是比较窄&#xff0c;特性被了解的也不是很多&#xff0c;Java11作为OpenJDK发布的LTS版本&#xff0c;对我们来说&#xff0c;还是需…

The processing instruction target matching [xX][mM][lL] is not allowed.

原因&#xff1a;xml标签 必须在第一行。 转载于:https://www.cnblogs.com/wangkang0320/p/7569100.html

周五尾盘上涨,配合周末消息,周一套人的经典实例

吸取中国软件的教训&#xff1a;注意这次是温柔的&#xff0c;只是收了个十字星&#xff0c;因为前期上涨后的需要缓和调整一下&#xff0c;而不是为了出逃。以后注意找个出逃的例子1、上周五尾盘上涨2、周末利好消息3、周一开盘高开4、高开后快速下探&#xff08;5分钟内&…

Spring Data,MongoDB和JSF集成教程

示例应用程序简介&#xff08;MongoShop产品目录&#xff09; 在学习完本教程之后&#xff0c;将构建具有以下功能要求的示例应用程序&#xff08;MongoShop产品目录&#xff09;&#xff1a; 1.搜索具有不同条件的产品&#xff08;例如&#xff0c;sku&#xff0c;产品类型&am…

表单元素

一、form form代表表单&#xff0c;功能&#xff1a;用于申明表单&#xff0c;定义采集数据的范围&#xff0c;也就是<form>和</form>里面包含的数据将被提交到服务器或者电子邮件里。<form> 标签用于为用户输入创建 HTML 表单。表单能够包含input元素&#…

本人用python刷题时的错误总结

本人新手&#xff0c;在leetcode刷题过程中出现过很多问题&#xff0c;也发现了很多方法&#xff0c;故在此总结&#xff0c;不定时更新。 1、在创建一个二维列表的时候&#xff0c;我之前会用 a [[0] * 5] * 5, 但是这样输出的结果往往会跟期待的不一样&#xff0c;我一直以为…

增加 jQueryValidate的手机号验证功能

1、通过addMethod增加手机号的验证方法 &#xff08;位置&#xff1a;和$(form).validate({}) 同级别&#xff09; //增加手机号验证规则$.validator.addMethod("isMobile", function(value, element) {var length value.length;var mobile /^(13[0-9]{9})|(18[0-9…

C++的STL中accumulate的用法

https://blog.csdn.net/u011499425/article/details/52756242

Hibernate继承:每个类层次结构的表

在本教程中&#xff0c;我们将看到如何在hibernate中实现继承。有3种方法可以在hibernate中实现继承。在本文中&#xff0c;我们将看到其中一种&#xff0c;即每个类层次结构一个表。 休眠中的继承&#xff1a; Java是面向对象的语言&#xff0c;继承是Java的主要功能之一。关…

锁 mysql_Mysql的锁(S锁和X锁的区别)

共享锁和排它锁Mysql的锁系统&#xff1a;shared lock 和 exclusive lock (共享锁和排它锁&#xff0c;也叫读锁和写锁&#xff0c;即read lock和write lock)读锁是共享的&#xff0c;或者说是相互不阻塞的写锁是排他的&#xff0c;一个写锁会阻塞其他的写锁和读锁在实际的数据…

爬取新闻

import requests from bs4 import BeautifulSoup urlhttp://news.gzcc.cn/html/xiaoyuanxinwen/ resrequests.get(url) res.encodingutf-8 soupBeautifulSoup(res.text,html.parser) 1. 用requests库和BeautifulSoup库&#xff0c;爬取校园新闻首页新闻的标题、链接、正文。 fo…

平衡二叉树的自顶向下递归和自底向上递归

没太搞懂自顶向下和自底向上的递归区别

【简记】HTML CSS 的一些要点(不定时更新)

1.td占据多行 / 列时&#xff0c;其挤开的 td 不写&#xff08;但是包裹 td 的 tr 要写&#xff09; 2. display:td 的元素中的文本默认垂直不居中&#xff08;table中的td中的文本是垂直居中的&#xff09; 3.th虽然定义了表头标题&#xff0c;但是默认不跨行&#xff08;需…

通过地址访问 mysql_MySql通过ip地址进行访问的方法

1.登录mysql&#xff1a;mysql -u root -h 127.0.0.1 -p2.切换数据库use mysql3.授权grant all privileges on *.* to root127.0.0.1identified by 密码;将127.0.0.1换成公网的ip地址。4.检查my.ini4.1 看看是否有skip-networkingskip-networking开启该选项后就不能远程访问MyS…

幻像类型提高了编译时的安全性

介绍 使用幻像类型是一种非常简单的技术&#xff0c;可用于提高代码的编译时安全性。 有许多潜在的用例具有不同的复杂性级别&#xff0c;但是即使幻像类型的使用非常轻巧&#xff0c;也可以显着提高编译时的安全性。 幻像类型只是带有未使用类型参数的参数化类型。 例如&#…

NI Multisim元件库:在Multisim中创建自定义元器件

转载于&#xff1a; http://www.ni.com/tutorial/3173/zhs/ 概览 「在Multisim中创建自定义元器件」与「在 NI Ultiboard中创建自定义元器件」为您提供了关于如何直观、快速地学习如何创建您自己的自定义元器件的信息资源。目录 引言步骤一&#xff1a;输入初始元器件信息步骤二…