HotSpot VM有没有对invokeinterface指令的方法表搜索进行优化?

软件工程师、主攻高级编程语言虚拟机的设计与实现

84 👍 / 11 💬

问题描述

JVM可以记住某个方法在方法表的位置 ,从而下次执行invokevirtual时就不需要搜索方法表了。
但是invokeinterface无法确定出方法在方法表中的位置,那么hotspot的实现有没有用其它方法对此进行优化?
如果没有,是不是意味着invokeinterface要比invokevirtual慢呢?

先简短说:HotSpot VM有对invokeinterface做优化。最快的情况下它跟invokevirtual的最快情况一样快;最慢的情况下它慢于invokevirtual最慢的情况。

HotSpot VM实现invokeinterface可以有下面几种层次,从快到慢:

  1. 完全去虚化(devirtualize)并且完全内联:没有任何虚方法分派或调用开销。在C1或C2编译的代码中使用;
  2. 条件去虚化(guarded devirtualize)并且内联:有简单的直接类型检查开销,除此之外没有额外的调用开销。这种内联在每个调用点可以内联最多两个目标类型/方法。仅在C2编译的代码中使用;
  3. 完全去虚化但是没有内联:没有虚方法分派查找目标方法的开销,但是有普通的直接调用开销(所谓直接调用就是类似没有内联时的invokespecial一样,目标是固定的,不用查表)。在C1或C2编译的代码中使用;
  4. 条件去虚化但是没有内联:有简单的直接类型检查开销,然后有普通的直接调用开销。仅在C2编译的代码中使用;
  5. 单态内联缓存(monomorphic inline cache)调用:有一个简单的直接类型检查开销,然后是普通的直接调用开销。在C1或C2编译的代码中使用;
  6. 劣化到超多态(megamorphic)状态的内联缓存(inline cache)调用:这是(5)的劣化情况——当一个内联缓存调用点遇到多于一种实际被调用对象类型就会这样。此时实际上会通过接口方法表(interface method table,简称itable)查找目标方法,然后再调用过去。这是最慢的情况之一,在C1或C2编译的代码中使用;
  7. 直接通过itable查找目标然后调用:最慢的情况的另一版本。仅在解释器里使用。

上述invokeinterface的7种情况里,头5种都跟invokevirtual一样,都不需要查表,因而这些情况下两者的性能一模一样;最后两种是属于慢速情况,此时由于HotSpot VM的虚方法表(virtual method Table,简称vtable)比itable结构简单,所以invokevirtual会比invokeinterface快一些。

涉及的关键字:

题主想知道详细的话我回头再写点。

=================================================

1. 完全去虚化并且完全内联

这主要是通过编译器分析出被调用对象的具体类型,或者通过CHA实现的。其效果是⋯⋯(待续)