jvmbenchmarkingbytecodejvm-bytecodemethodhandle

Fastest way to invoke method handle fields


I'm generating bytecode roughly equivalent to a class like:

final class MyCls {
  final MethodHandle handle1;
  final MethodHandle handle2;
  // and so on

  // This needs to invoke `handle1`, `handle2`, etc. in it somehow
  final static myMethod() {
    // ...
  }

}

The class is fairly long-lived and I wish to call the MethodHandles from inside other methods, with ideally as little overhead as possible. What would be the best way to do this? The two ideas that come to mind are:

The handles will vary in signatures (although their use-sites should all use the right signatures - I can detect/enforce that at codegen time).

Update

Here's some extra context on what I'm actually doing. The classes represent compiled WASM modules, the method handles are imported functions, and each instance of the class in another instance of the WASM module.

Using MethodHandle to represent imported functions isn't a necessity here - I could also accept something like a java.util.function.Function or maybe even just a virtual method invocation. I do need a MethodHandle representation sometimes, but I could summon one up from a virtual method too (and I could implement a virtual method manually calling a Function too).

The module class instances themselves might end up being stored in static fields but that's not guaranteed. If there is a way to speed up that case, I could recommend users use that.


Solution

  • The simple answer is to just generate invokeExact calls. With the code shape you've shown, there's no need to use invokedynamic (in fact that doesn't seem possible, since invokedynamic calls a bootstrap method which supplies the implementation dynamically).

    Since the handles are stored instance fields, they are not seen as constants, and so the calls will be out of line, which adds overhead, as well as missed optimization opportunities due to a lack of inlining.

    If you really want this to be as fast as possible, you'd need to generate a new class per combination of method handles you want to use, and store the method handles in static final fields, or in the constant pool (for instance using constant pool patching, or hidden classes + class data + dynamic constants [1]).