中文 | English

| | |

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

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

Github repo

https://github.com/racaljk/yvm

已支持语言特性

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

构建和运行

  • 先决条件

    • 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



  • 快速排序



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

[开源JVM] yvm - 自制Java虚拟机的更多相关文章

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

    项目地址 : https://github.com/racaljk/yvm 虚拟机现在已可运行(不过还有很多待发现待修复的bugs),已支持语言特性有: Java基本算术运算,流程控制语句,面向对象. ...

  2. 自制Java虚拟机(四)-对象、new、invokespecial

    自制Java虚拟机(四)-对象.new.invokespecial 一.对象的表示 刚开始学Java的时候,图书馆各种教程,书名往往都是“Java面向对象高级编程”,通常作者都会与C++做个比较,列出 ...

  3. [转]JVM内幕:Java虚拟机详解

    本文由 ImportNew - 挖坑的张师傅 翻译自 jamesdbloom.欢迎加入翻译小组.转载请见文末要求. 这篇文章解释了Java 虚拟机(JVM)的内部架构.下图显示了遵守Java SE 7 ...

  4. JVM内幕:Java虚拟机详解

    这篇文章解释了Java 虚拟机(JVM)的内部架构.下图显示了遵守 Java SE 7 规范的典型的 JVM 核心内部组件. 上图显示的组件分两个章节解释.第一章讨论针对每个线程创建的组件,第二章节讨 ...

  5. JVM原理二----JAVA虚拟机体系结构

    组成: 指令集,寄存器,栈,无用单元收集(GC),方法区域.JAVA核心 1,指令集:这个不太清楚 2,寄存器:和处理器中的寄存器类似 pc:Java程序计数器. optop:指向*作数栈顶端的指针. ...

  6. Java虚拟机(一):JVM简介

    JVM简介 Java虚拟机(JVM)是由Java虚拟机规范定义的,其上运行的是字节码指令集.这种字节码指令集包含一个字节的操作码(opcode),零至多个操作数(oprand),虚拟机规范明确定义了每 ...

  7. Java虚拟机(一):JVM内存结构

    所有的Java开发人员可能会遇到这样的困惑?我该为堆内存设置多大空间呢?OutOfMemoryError的异常到底涉及到运行时数据的哪块区域?该怎么解决呢?其实如果你经常解决服务器性能问题,那么这些问 ...

  8. Java虚拟机规范----JVM体系结构

    一.Java平台的结构图 二.JVM与JRE.JDK关系? JVM:Java Virtual Machine(Java虚拟机),负责执行符合规范的Class文件 JRE:Java Runtime En ...

  9. 关于Java虚拟机JVM的简单了解

    JVM主要功能 Java是一种高级编程语言. 用高级语言编写的程序不能直接在任何机器上运行. 首先,需要将其翻译成特定的机器语言,javac编译器就专门来干这个事儿的,它把Java程序(含有的.jav ...

随机推荐

  1. Linux 下启动两个tomcat

    Linux 下启动两个tomcat 闲来无事学习nginx,想要配置个load balance.可是先决条件是:得有两个web容器.两个电脑是不用想了.只能想办法在一个机器上启动两个tomcat.原以 ...

  2. linux系统中的命令替换与整数运算$(),$(())

    一.$()与`` 在 bash shell 中,$( ) 与 ` ` (反引号) 都是用来做命令替换(command substitution)用的. 所谓的命令替换与我们第五章学过的变量替换差不多, ...

  3. impdp报错ORA-39083 ORA-02304 Object type TYPE failed to create

    环境Red Hat Enterprise Linux Server release 5.8 (Tikanga)ORACLE Release 11.2.0.3.0 Production 我用expdp, ...

  4. 第一个Django应用程序_part2

    一.数据库配置 此文延续第一个Django应用程序_part1. 打开mystic/settings.py.这是一个普通的Python模块,其模块变量表示Django配置 默认情况下,配置使用SQLi ...

  5. .NET 使用HttpWebRequest 伪造Request.UrlReferrer

    在网上找了许久关于伪造UrlReferrer地址资料,也许是搜索的关键词不对吧,还是内容涉及到了什么敏感的东西,愣是没找到,换成自定义UrlReferrer也找不到.经过仔细研究,原来在.NET中要自 ...

  6. EXTI—外部中断事件控制器

    外部中断概述 STM32F4的每个IO都可以作为外部中断输入. STM32F4的中断控制器支持22个外部中断/事件请求: 从上面可以看出,STM32F4供IO使用的中断线只有16个,但是STM32F4 ...

  7. C#调用COM组件遇到的问题及解决办法

    1.无法嵌入互操作类型"xxx",请改用适用的接口. 解决办法: - 将所引用的程序集的[嵌入互操作类型]属性设置为[False]. 2.System.Runtime.Intero ...

  8. Django学习笔记:为Model添加Action

    |- Django版本:1.8 |- Python版本:3.4 models.py 1 class Story(models.Model): #编辑Story状态 STATUS_CHOICES = ( ...

  9. MySQL的四种外键

    来自:某一位网友的博客    转自:http://blog.csdn.net/cnjsnt_s/article/details/5548280 具体使用时需要参考:http://blog.csdn.n ...

  10. Spring框架总结(五)

    自动装配(了解) 根据名称自动装配:autowire="byName" 自动去IOC容器中找与属性名同名的引用的对象,并自动注入 延续使用user.dao.service.acti ...