JVM中invokevirtual的实现

Implementation of invokevirtual in JVM

我原以为 Java 虚拟机会使用简单的查找 table 进行正常的方法调用:该对象包含一个指向查找 table 的指针,其中包含所有地址class实现的方法(包括super-classes实现的方法)。一个特定的方法简单地由 table 中的索引表示。 JVM在table中查找方法的地址,并跳转到该地址。

但是 JVM 规范指定了在 运行 时间查找正确方法的漫长而复杂的过程(参见 the official spec):

The unsigned indexbyte1 and indexbyte2 are used to construct an index into the run-time constant pool of the current class [which] must be a symbolic reference to a method , which gives the name and descriptor of the method as well as a symbolic reference to the class in which the method is to be found. The named method is resolved. [...] then the invokevirtual instruction proceeds as follows.

If C contains a declaration for an instance method m that overrides (§5.4.5) the resolved method, then m is the method to be invoked, and the lookup procedure terminates.

Otherwise, if C has a superclass, this same lookup procedure is performed recursively using the direct superclass of C; the method to be invoked is the result of the recursive invocation of this lookup procedure.

我预计这个复杂而漫长的过程需要很长时间。因为它是为每个正常的方法调用完成的,所以几乎所有基于 JVM 的程序的时间都会花在这个过程中。

真正的 (Oracle) JVM 真的是这样实现的吗?或者 JVM 是否对查找进行 JIT 类型的编译 table?有具体的JVM具体是如何实现的描述吗?

Java 语言规范或 Java 虚拟机规范中没有任何内容规定任何特定的实施策略。每个实施者都可以自由选择他们想要的任何实施策略,只要结果相同 AS-IF 他们实施了规范中描述的算法。

换句话说,规范中的算法描述了最终结果而不是配方

最简单和最明显的优化可能只是愚蠢地执行所描述的算法,但缓存结果而不是丢弃它。

大多数现代高性能 JVM 都源自 Smalltalk VM,并使用 Smalltalk 社区在 1980 年代发明的技术。

Eclipse OpenJ9 以 IBM J9 开始其生命,而 IBM J9 又衍生自 IBM VisualAge for Java Universal Virtual Machine(能够无缝执行 JVM 字节码和 Smalltalk 字节码的混合) ,它又基于 IBM VisualAge for Smalltalk VM。

Oracle HotSpot 基于 LongView 的 Animorphic Smalltalk VM,后者又基于 Self VM。 (Animorphic Smalltalk VM 也是 Google 的 V8 ECMAScript 引擎的原始基础。)

Azul Zing 源自 HotSpot。 Oracle Labs Maxine RVM 是由一些老的 Smalltalk 和 Self 开发人员基于 Klein VM(一个用 Self 编写的实验性元循环 Self VM)的想法开发的。

消除动态运行时虚拟消息调度开销的一些最著名的技术是

[您会注意到,几乎所有源代码都是针对 Self 或 Smalltalk 的。两个主要原因是 Self 开创了很多这些技术,Smalltalk 和 Smalltalk VM 对 Java 和 JVM 产生了重大影响。]

我最熟悉的 JVM(Eclipse OpenJ9、Oracle HotSpot、Oracle Labs Maxine RVM、Azul Zing)实现了上述大部分内容。

在 Java 7 中引入 JVM 规范的 invokedynamic 字节码允许程序员访问上述优化,但 提供他们自己的方法查找算法 而不是一个硬编码到 JVM 中。这使得在 JVM 之上为方法查找算法与 Java 不兼容的语言创建高性能实现成为可能。