Is it possible to make java.lang.invoke.MethodHandle as fast as direct invokation?

夙愿已清 提交于 2019-12-03 12:55:25

You use reflective invocation of MethodHandle. It works roughly like Method.invoke, but with less run-time checks and without boxing/unboxing. Since this MethodHandle is not static final, JVM does not treat it as constant, that is, MethodHandle's target is a black box and cannot be inlined.

Even though mhh is final, it contains instance fields like MethodType type and LambdaForm form that are reloaded on each iteration. These loads are not hoisted out of the loop because of a black-box call inside (see above). Furthermore, LambdaForm of a MethodHandle can be changed (customized) in run-time between calls, so it needs to be reloaded.

How to make the call faster?

  1. Use static final MethodHandle. JIT will know the target of such MethodHandle and thus may inline it at the call site.

  2. Even if you have non-static MethodHandle, you may bind it to a static CallSite and invoke it as fast as direct methods. This is similar to how lambdas are called.

    private static final MutableCallSite callSite = new MutableCallSite(
            MethodType.methodType(int.class, int.class, int.class));
    private static final MethodHandle invoker = callSite.dynamicInvoker();
    
    public MethodHandle mh;
    
    public MyBenchmark() {
        mh = ...;
        callSite.setTarget(mh);
    }
    
    @Benchmark
    public int boundMethodHandle() throws Throwable {
        return (int) invoker.invokeExact(first, second);
    }
    
    1. Use regular invokeinterface instead of MethodHandle.invoke as @Holger suggested. An instance of interface for calling given MethodHandle can be generated with LambdaMetafactory.metafactory().

Make MethodHandle mhh static:

Benchmark            Mode  Samples  Score   Error  Units
directMethodCall     avgt        5  0,942 ± 0,095  ns/op
finalMethodHandle    avgt        5  0,906 ± 0,078  ns/op

Non-static:

Benchmark            Mode  Samples  Score   Error  Units
directMethodCall     avgt        5  0,897 ± 0,059  ns/op
finalMethodHandle    avgt        5  4,041 ± 0,463  ns/op
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!