我用 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子句、注释、泛型信息
字节码以及一些额外的元数据,例如异常处理程序表与行号表。