JVM可以内联本机方法吗?

时间:2015-09-22 16:50:16

标签: java x86 jvm jit

我写了一个小的静态JNI函数,它只有5个指令长。 JVM是否可以将此代码内联到一个经常调用它的方法体中,或者它是否总是在JITed方法中生成call指令?

例如:

public class SomeClass {
    private static native long func();

    public void doLoop() {
        for(int i = 0; i < 0xFFFFFF; i++) {
             func();
        }
    }  

    public static void main(String[] args) {
        for(int i = 0; i < 0xFFFFFF; i++) {
            doLoop();
        }
    }
}

JVM是否可以将func的代码内嵌到doLoop中,或者只是将其编译为call func

3 个答案:

答案 0 :(得分:11)

不,JVM基本上不能。

本机函数的实现是二进制黑盒子; JVM唯一知道的就是入口点地址。

本机代码不由虚拟机管理,不能在Java方法的上下文中执行。 JVM将&#39; in_java&#39; 状态的线程与&#39; in_native&#39; 中的线程区分开来。例如,本机线程不会在JVM安全点停止,只是因为JVM无法执行此操作。

此外,本机方法调用不是那么简单的操作。需要A special procedure来解决JNI呼叫的所有方面。

答案 1 :(得分:4)

这将是非常困难的并且有大量的角落情况让JVM完全安全地完成它,所以几乎肯定没有。

e.g。考虑以

结尾的C函数
return memcpy(dest, src, count);

一个不错的编译器会进行尾调用优化,因此该函数将编译为类似

的函数
mov   rdi, dest
mov   rsi, src
mov   edx, count
jmp   memcpy

而不是

...
call memcpy
ret

因此,在确定是否/如何内联一段本地机器代码时,JVM必须做的不仅仅是查找ret指令。

要正确内联本机方法,JVM作者必须考虑每个可能的极端情况。他们很可能不会尝试。

除了棘手的跳转之外,本机代码中的段错误将显示在内联目标中,而不是显示在单独的堆栈帧中。

最佳建议:制作一个包含所需循环的本机函数的版本,或者它是否真的有5个简单的行(不是库函数,或者扩展到很多asm的其他东西),只需用Java编写即可。让JIT编译器担心它。

答案 2 :(得分:0)

从字面上看,本机方法无法内联。

但是,JVM可以用内在函数替换Java方法和本机方法。例如许多不安全的方法被视为内在因素,并且不会为JNI支付预付款。

因此,可以有效地内联本机化的本地方法。