Oracle发布了多语种虚拟机平台GraalVM的1.0版本。初始发布版包括运行Java和JVM语言(通过字节码)的能力,对JavaScript和Node.JS的全面支持,以及对Ruby、Python、R语言和LLVM字节码的测试性支持。
整个平台包含多个组件:
- Graal:一个由Java语言编写的JIT编译器。
- SubstrateVM:一个对执行容器抽象层的轻量级封装。
- Truffle:一个用于构建语言解析器的工具集和API。
整个平台的目的是提供一个可以嵌入到另一个执行容器中的多语言执行环境,不论这个执行容器是OpenJDK容器还是诸如Oracle或者MySQL数据库之类的均可。
InfoQ与Oracle实验室研究总监Thomas Wuerthinger就GraalVM进行了深入访谈。
InfoQ:您能介绍一下GraalVM的历史吗?它源自于哪里呢?
Thomas Wuerthinger:这个项目最初的想法是编译器不应该对编程语言语义有特殊支持。究其原因是Oracle内部对包括JavaScript、R和Ruby在内的多种编程语言都有所涉猎。
我们觉得以下两个核心领域可以通过研究进行突破:
* 当时软件工业对于虚拟机架构普通认为,如果希望获得最佳的性能,一个语言的虚拟机需要针对虚拟机的语义进行特定的设计。
* 从Java7开始,通过在JVM规范中增加invokedynamic字节码指令,Java架构支持了多种语言。GraalVM团队觉得由于Java字节码已经内置了太多Java语义,100%的兼容实现长期来看会有更好的性能。
同时我们还有一个目标是构建一个有竞争力的完备的多语言引擎,因此我们开始和一些大学开始合作开展支持其他语言的工作。
普渡大学的一个团队做了R语言的一个实现,加州大学欧文分校的一个团队在2012年到2014年完成了Python语言的一个实现。一个实习生将Ruby语言实现作为他的论文项目,它有很多新奇有趣的特性,我们认为它很好地证明了我们的多语言编译器是完全通用的。随后,我们将这些语言的项目带到了Oracle实验室以为这些语言编写工业质量的实现。
随着GraalVM 1.0的发布,我们认为我们已经证明了拥有高性能的多语言虚拟机是可能的,并且实现这个目标的最佳方式不是通过类似Java和微软CLR那样带有语言特性的字节码。
InfoQ:组成GraalVM的核心技术是什么?这些技术将如何帮助开发人员?
Wuerthinger:GraalVM的核心技术称为“部分评估”,它是一项将解释器自动转换成编译器的技术。语言开发者能够仅仅专注于构建一个抽象语法树(Abstract Syntax Tree,AST)解释器,而无需编写代码生成器和其他诸如垃圾回收器等低级运行时功能。
我们内置于GraalVM的一项核心技术是逻辑/物理数据分离。这使得任何内存数据布局都能够表现为一个本地语言对象。大部分虚拟机对于对象都有一个特定的布局(对象头通常称为“盒子”),因此为了获取对象在编程语言中的语义,对象内存结构必须有相同的布局。
这意味着在大部分虚拟机中,用户必须为一个“对象”分配内存和复制数据。
在Graal中,不同语言互操作可以实现零开销,因为JavaScript对象表现的行为可以是JavaScript对象,也可以是R对象,而无需额外的对象创建和数据复制。
该特性也允许例如以特定二进制格式暴露高级语言对象数据,而无需实际创建这些高级语言对象。
另一项核心技术是LLVM解释器。我们实现了一个针对LLVM字节码的GraalVM解释器,该字节码是LLVM编译器的输出,因此可以完美支持生成原生二进制可执行文件的语言(例如C++、FORTRAN、Rust等等)。
实现语言支持的一个主要问题是,这些语言通常有使用本地字节码实现的库文件(通常是C/C++),并且它们会使用暴露语言内部的API。因此如果希望兼容一个语言系统,我们必须支持本地库。
像JRuby和Nashorn那样的实现方式其中一个问题就是,它们无法支持包含本地库的模块,这会导致兼容性问题。
GraalVM最后增加的独立模块称为SubstrateVM。它的做法是将虚拟机在混合和匹配的基础上变得可嵌入。类似Java Hotspot这样的常规语言虚拟机期望能够控制所有东西:哪个线程能够被调度,内存分配器如何工作,访问操作系统等等。
因此,我们需要一种允许底层系统提供这些服务的技术层,而SubstrateVM通过支持动态JIT编译器(如垃圾回收器)所需要的内容来弥补这一缺失。例如,当我们运行在一个数据库中时,数据库希望能够控制内存管理、线程分配等。
SubstrateVM是一个“极薄”的虚拟机,能够嵌入到类似数据库这样的系统中。因此如果用户需要在数据库中运行Graal编译器,数据库可以指定最大堆内存和不是通过Java虚拟机机制,通知数据库可以管理代码构件而不是JVM类加载器。
SubstrateVM实现这一功能的最重要方式是像Graal一样对Java代码进行提前编译(ahead-of-time compilation)而成为本地二进制代码,当然需要假设所有依赖自包含封闭世界假定(closed world assumption)(所有需要使用的类在编译期都需要明确)。因此,当用户将Graal编译器部署到数据库的时候,需要使用Graal将GraalVM语言编译成本地共享库,并且它们不必在运行时编译。
InfoQ:什么是Truffle?为什么需要它?
Wuerthinger:Truffle是构建一个新的GraalVM语言时所依赖的GraalVM解释器API。解释器的工作首先是将源码解析成所谓的抽象语法树(Abstract Syntax Tree,AST)。例如,如果我们的代码是:c = a + b,那么AST将会包含2个节点,一个是加操作,它包括两个子节点a和b,第二个节点是赋值操作,包含子节点c和加操作节点。
解释器内部实现,例如AST相关操作需要继承Truffle接口,如果这样做了Graal编译器将会观察语言解释器活动以学习语言语义,因此可以生成针对这种语言的编译器。
InfoQ:GraalVM的最令人瞩目的组件之一是Graal编译器,它是一个名为“Graal”、基于Java的JIT编译器。您能介绍一下Graal希望能够改进当前的C2编译器(目前OpenJDK中使用的由C++编写的JIT编译器)遇到的难点吗?另外,Graal未来有希望替代C2称为OpenJDK主线的默认编译器吗?
Wuerthinger:Graal编译器在Java 10中是一个实验性的编译器,Oracle对于它将来能够成为默认编译器是乐观的。
类似Graal这样的编译器最大的优势是它首先编译其自身(因为它由Java编写),这使得可以直接在高级语言层面编写Graal,而不用像C2那样直接操作AST。举例来说,对于Graal来说能够更容易的进行积极内联和对象逃逸分析,这使得程序能够自动的移除更多的对象分配。总的来说,程序写的约抽象,Graal编译器能够做的更多,因此我们会看见Graal对于Java 8或者Scala中支持的流(Stream)和Lambda等功能会有更大的性能提升。
InfoQ:Oracle正在将GraalVM作为多语言虚拟机进行大力推广。其1.0版本发布的内容和Java 10中包含的部分内容有什么区别?对于类似JRuby开发者来说,应该选择哪个?GraalVM应该被视作是一个独立的项目,还是OpenJDK的一部分?未来Graal的发布节奏会与Java发布节奏保持一致,还是会独立进行?
Wuerthinger:GraalVM和Java是100%独立的项目,它们都拥有大量的开源存在和独立的发布节奏,并且它们都同时从彼此项目中获取各种技术。Java 10从GraalVM中获取了编译器(作为实验性选择),而GraalVM将Java 8作为其支持的语言之一。GraalVM支持许多语言,不仅仅是Java,因此我们也使用了来自Node.js、JRuby的技术,来自GNU R语言的实现等内容。
和大多数组织中的技术生产者/消费者关系类似,消费者会从其他提供者处等待新技术的成熟,然后使用它。类似的,Java平台组织(Java Platform Group)在引入新技术的时候也是保守的,他们需要确认这项技术不会破坏现存的部署,以及一系列向下和向上兼容性考虑,所以会有一些滞后。
InfoQ:IBM实现的OpenJ9运行时环境使用了和GraalVM不同的实现方式。您能解释一下您了解到的和OpenJ9/OMR主要区别是什么,GraalVM有什么独到之处?
Wuerthinger:OpenJ9试图通过增加一些限制性的JIT编译功能来加速已经存在的单一语言运行时环境(例如Ruby的MRI解释器)。他们这种实现方式的优点是适配和兼容已经存在的运行时环境比较方便。主要的劣势是提升比较有限。
首先,与在GraalVM上运行的Ruby数量级相比,他们的Ruby原型的性能优势非常小。主要原因是GraalVM可以进行更多的分析和推测优化,而OMR保留了现有解释器的数据结构。
其次,他们需要开发者编写一个代码生成器,并且无法通过部分评估自动从解释器中得到编译后的代码。
第三,没有内置的物理/逻辑数据分离。
这点直接导致了最终到的第四点:通过他们的实现方式没有能力实现高效的语言互操作性。
OMR可以对类似Ruby MRI这样尚未进行很好优化的现存单语言运行时提供微小的性能提升。GraalVM使用了完全不同的方式对这些语言有了数量级的改进,并且对于任何支持的语言有零开销的互操作性。
InfoQ:对于Graal更广泛的社区参与情况如何?Twitter是有记录的早期使用者和在生产环境中使用运行Graal的公司,其他还有已经使用的场景吗?您与非Oracle开发人员一起工作的经验是什么?Graal未来的开发模式会是如何的?它是否会使用和OpenJDK类似的模型?
Wuerthinger:OpenJDK的任务和GraalVM的完全不同。
OpenJDK对于开发者来说水很深,因为它总是创建一个新的语言特性或者新的库。开发者不得不跟随OpenJDK改变而修改代码,而这些改动的目的是让社区对其价值达成共识。OpenJDK社区非常庞大,有许多不同的观点,他们的流程主要用于帮助社区达成共识。
GraalVM的目的是让已经存在的代码和库能够更高效、在更多平台的运行,同时拥有更多的互操作性,并且不修改语言语义(对大部分语言来说)。对于开发者接口的唯一主要部分是互操作API,它能够允许在其他运行时环境中调用外部语言函数,我们尽可能保持对外接口的稳定。
GraalVM支持语言的社区都有自己的发展规划。
和OpenJDK一样,GraalVM有许多来自厂商的巨大贡献,其中Red Hat、Intel和AMD贡献最大。Red Hat在不久前在我们没有多大的投入之下为GraalVM构建了一个ARM后端,这对于我们来说非常有用。你可以已经注意到Oracle最近投资了ARM,因此我们会更加关注该生态系统。
这些厂商认为GraalVM将获得足够的认可以确保投资回报,他们的兴趣主要不是自身使用。正如你指出的,Twitter也对GraalVM作出了贡献,因为他们正在使用。其他还有一些主要的科技厂商在使用GraalVM但是没有像Twitter那样公布出来,另外Oracle内部也有使用者。
InfoQ:Oracle通常很少谈论未来路线图。您能否告诉我们在未来18个月内GraalVM的发展轨迹可能会带给我们什么?
Wuerthinger:好吧,GraalVM团队属于Oracle实验室,因此我们会有相反的问题,就是我们有许多公开研究性的项目,它们或多或少会超出我们在学术会议论上发表论文的范围。Oracle实验室有一批研究生合作者,希望通过使用GraalVM尝试新的创意。
我们有一个学生正在考虑将GraalVM链接到Chromium中,这样我们可以在浏览器中使用任何语言,而不仅仅是JavaScript。但是我认为很明显这不可能称为Oracle的一个产品而发布。你可以查阅GraalVM相关学术论文来了解这些疯狂的想法。我们已经完成了对其他一些语言社区的调查,但是否支持得根据社区的兴趣。
关于路线图我能够告诉你的是,我们正在致力于支持更多的平台。初始发布的版本只能运行在Linux/X86和Mac/X86平台上,以降低“发布压力”。我们正在积极致力于Windows平台和ARM平台的支持(和Red Hat一起)。对于目前被标记为“实验性”的语言来说,例如R、Ruby和Python,还有许多稳定性和完善性的工作要做。
就整合而言,我们将通过多种方式将GraalVM更深入的集成到MySQL和Oracle RDBMS中,这些会在未来18个月中看见。但是18个月后GraalVM会是什么样子,这非常依赖整个社区的反馈和贡献。
查看英文原文:Oracle Releases GraalVM 1.0, a Polyglot Virtual Machine and Platform
转自 http://www.infoq.com/cn/news/2018/05/oracle-graalvm-v1