I'm comparing performance of MethodHandle::invoke and direct static method invokation. Here is the static method:
public class IntSum {
    public static int sum(int a, int b){
        return a + b;
    }
}
And here is my benchmark:
@State(Scope.Benchmark)
public class MyBenchmark {
    public int first;
    public int second;
    public final MethodHandle mhh;
    @Benchmark
    @OutputTimeUnit(TimeUnit.NANOSECONDS)
    @BenchmarkMode(Mode.AverageTime)
    public int directMethodCall() {
        return IntSum.sum(first, second);
    }
    @Benchmark
    @OutputTimeUnit(TimeUnit.NANOSECONDS)
    @BenchmarkMode(Mode.AverageTime)
    public int finalMethodHandle() throws Throwable {
        return (int) mhh.invoke(first, second);
    }
    public MyBenchmark() {
        MethodHandle mhhh = null;
        try {
            mhhh = MethodHandles.lookup().findStatic(IntSum.class, "sum", MethodType.methodType(int.class, int.class, int.class));
        } catch (NoSuchMethodException | IllegalAccessException e) {
            e.printStackTrace();
        }
        mhh = mhhh;
    }
    @Setup
    public void setup() throws Exception {
        first = 9857893;
        second = 893274;
    }
}
I got the following result:
Benchmark                      Mode  Cnt  Score   Error  Units
MyBenchmark.directMethodCall   avgt    5  3.069 ± 0.077  ns/op
MyBenchmark.finalMethodHandle  avgt    5  6.234 ± 0.150  ns/op
MethodHandle has some performance degradation. 
Running it with -prof perfasm shows this:
....[Hottest Regions]...............................................................................
 31.21%   31.98%         C2, level 4  java.lang.invoke.LambdaForm$DMH::invokeStatic_II_I, version 490 (27 bytes) 
 26.57%   28.02%         C2, level 4  org.sample.generated.MyBenchmark_finalMethodHandle_jmhTest::finalMethodHandle_avgt_jmhStub, version 514 (84 bytes) 
 20.98%   28.15%         C2, level 4  org.openjdk.jmh.infra.Blackhole::consume, version 497 (44 bytes) 
As far as I could figure out the reason for the benchmark result is that the Hottest Region 2 org.sample.generated.MyBenchmark_finalMethodHandle_jmhTest::finalMethodHandle_avgt_jmhStub contains all the type-checks performed by the MethodHandle::invoke inside the JHM loop. Assembly output fragment (some code ommitted):
....[Hottest Region 2]..............................................................................
C2, level 4, org.sample.generated.MyBenchmark_finalMethodHandle_jmhTest::finalMethodHandle_avgt_jmhStub, version 519 (84 bytes) 
;...
0x00007fa2112119b0: mov     0x60(%rsp),%r10
;...
0x00007fa2112119d4: mov     0x14(%r12,%r11,8),%r8d  ;*getfield form
0x00007fa2112119d9: mov     0x1c(%r12,%r8,8),%r10d  ;*getfield customized
0x00007fa2112119de: test    %r10d,%r10d
0x00007fa2112119e1: je      0x7fa211211a65    ;*ifnonnull
0x00007fa2112119e7: lea     (%r12,%r11,8),%rsi
0x00007fa2112119eb: callq   0x7fa211046020    ;*invokevirtual invokeBasic
;...
0x00007fa211211a01: movzbl  0x94(%r10),%r10d  ;*getfield isDone
;...
0x00007fa211211a13: test    %r10d,%r10d
;jumping at the begging of jmh loop if not done
0x00007fa211211a16: je      0x7fa2112119b0    ;*aload_1 
;...
Before calling the invokeBasic we perform the type-checking (inside the jmh loop) which affects the output avgt.
QUESTION: Why isn't all the type-check moved outside of the loop? I declared public final MethodHandle mhh; inside the benchmark. So I expected the compiler can figured it out and eliminate the same type-checks. How to make the same typechecks eliminated? Is it possible?
 
     
    