我用 Rust 写了一个 JVM

最近,我花了相当多的时间来学习 Rust,就像任何有理智的人都会做的那样,在编写了几个 100 行程序之后,我决定做一些更加雄心勃勃的事情——我用Rust写了一个 Java 虚拟机。🎉 

我在其中实现了很多独创特性,我把它称为『rjvm』。目前代码已经开源,各位可以在 GitHub 上获取。

https://github.com/andreabergia/rjvm

我想强调的是,这是一个玩具型 JVM,是为了学习目的而构建的,而不是一个严肃的实现。特别是,它不支持:

  • 泛型

  • 线程

  • 反射

  • 注释

  • 输入/输出

  • 及时编译器

  • 字符串处理

实际上,我已经实现了大多数重要的事情。比如:

  • 控制流语句 ( if, for, ...)

  • 原始和对象创建

  • 虚拟方法和静态方法调用

  • 例外处理

  • 垃圾收集

  • jar文件中的类解析

例如,以下是测试套件的一部分:

class StackTracePrinting {
    public static void main(String[] args) {
        Throwable ex = new Exception();
        StackTraceElement[] stackTrace = ex.getStackTrace();
        for (StackTraceElement element : stackTrace) {
            tempPrint(
                    element.getClassName() + "::" + element.getMethodName() + " - " +
                            element.getFileName() + ":" + element.getLineNumber());
        }
    }

    // We use this in place of System.out.println because we don't have real I/O
    private static native void tempPrint(String value);
}

我使用真实的包,它来自OpenJDK 7 的rt.jar类。所以在上面的示例中,该类来自真实的 JDK!java.lang.StackTraceElement。

我对自己学到的关于 Rust 知识,以及如何实现虚拟机的知识感到非常满意。

特别是,我非常兴奋能够实现一个真正的、有效的垃圾收集器。它很普通,但它是我亲自写出来的,我很喜欢它。💘 

鉴于我已经实现了最初的目标,我决定停止这个项目。我知道存在一些错误,但我并不打算修复它们。

概述 在这篇文章中,我将向您概述 JVM 的工作原理。

代码组织 

该代码是一个标准的 Rust 项目。我把它分成了三个代码空间(即包):

  • reader,它能够读取.class文件,并包含对其内容进行建模以及各种数据类型;

  • vm,其中包含可以将代码作为库执行的虚拟机;

  • vm_cli,其中包含一个非常简单的命令行启动器来运行虚拟机,可执行java文件。

我正在考虑将reader提取到单独的存储库中并将其发布到crates.io上,因为它实际上对其他的开发者可能有用。

解析.class文件 

如大家所知晓的,Java 是一种半编译语言 -javac编译器获取.java源文件并生成各种.class文件,通常压缩在一个.jar文件中 - 这是一个zip文件. 因此,执行一些 Java 代码要做的第一件事就是加载一个.class文件,其中包含编译器生成的字节码。

其中,类文件包含如下内容:

  • 有关类的元数据,例如其名称或源文件名

  • 超类名称

  • 实现的接口

  • 字段及其类型与注释

  • 接下来是方法:

    • 它们的描述符,它是一个字符串,表示每个参数的类型和方法的返回类型

    • 元数据,例如throws子句、注释、泛型信息

    • 字节码以及一些额外的元数据,例如异常处理程序表与行号表。