In both staticMethodHandle & lambdaMetafactory Dog::getName is
inlined, but using different mechanisms.
In staticMethodHandle target method is statically known , but in
case of lambdaMetafactory  compiler has to rely on profiling info
to devirtualize Function::apply(). The latter requires exact type
check on the receiver at runtime and that explains the difference you
But comparing that with nonStaticMethodHandle is not fair: there's no
inlining happening there.
I actually never dared to ask, what kind of information is really
provided by the java compiler here to make the static version so fast?
Java compiler doesn't do anything special in that case. All the "magic"
happens during JIT-compilation: JIT-compiler extracts method handle
instance from static final field (as if it were a constant from class
constant pool) and inlines through MH.invokeExact() down to the target
Is it because the static final version becomes a member of the class
pool? Is the lambdafactory so fast, because here the handle will become
the member of the pool of the generated class? And is there a way for me
In that particular case, no method handles are involved.
LambdaMetafactory produces a class file w/o any method handle constants.
The target method is directly referenced from bytecode .
to bring nonStaticMethodHandle more near to staticMethodHandle, short of
making it static?
CallSites are the best you can get (JITs treat CallSite.target as
constant and aggressively inlines through them), but you have to bind
CallSite instance either to invokedynamic call site or put it into
static final field.
If such scheme doesn't work for you, there's no way to match the
performance of invocations on constant method handles.
The best thing you can do is to wrap method handle constant into a newly
created class (put it into constant pool or static final field) and
define a method which invokes the method handle constant (both indy &
MH.invokeExact() work). The method should either implement a method from
super-interface or overrides a method from a super-class (so there's a
way to directly reference it at use sites). The latter is preferable,
because invokevirtual is faster than invokeinterface. (LambdaMetafactory
does the former and that's the reason it can't beat MH.invokeExact() on
final class org.lmf.LMF$$Lambda$37 implements java.util.function.Function
#19 = Methodref #15.#18 //
public java.lang.Object apply(java.lang.Object);
flags: (0x0001) ACC_PUBLIC
stack=1, locals=2, args_size=2
1: checkcast #15 // class org/lmf/LMF$Dog
4: invokevirtual #19 // Method
mlvm-dev mailing list