Method handles, like inner classes, are encapsulated behavior and values, and can be type-profiled for optimistic compilation. The required profiling is different, however, since it needs to look at the MethodHandle.form.vmentry field, rather than the Object._klass field. Since method handle invocation is done with a special hidden bytecode "invokehandle", the profiling machinery should be modified to capture that extra data when executing "invokehandle" instructions.
Background:
A method handle's meaning or behavior breaks into three parts:
1. the compiled bytecode of its LambdaForm (MethodHandle.form.vmentry)
2. the constants embedded in the LambdaForm expressions
3. bound values stored in the method handle itself (as a BoundMethodHandle subclass)
Parts 1 and 2 correspond to the (often anonymous) class of an inner class object which adapts some functional interface. Part 3 corresponds to the instance variables of that object. Normal class-based type profiling in the JVM allows the JIT to produce good code for inner class objects in many cases.
Currently, part 2 is merged into part 1, because bytecodes are customized to contain all LF constants. JDK-8001106 aims share bytecodes (part 1) among many similar LFs, where the only differences are constant arguments stored in the LF expressions.
The profiling of method handles therefore has three possible levels:
A. (Coarse) Detect call sites with one or two distinct bytecode (vmentry values) and optimistically compile code that loads parts 2 and 3 as non-constants.
B. (Medium) Detect call sites with one or two distinct lambda forms (form values) and optimistically compile code that loads part 3 as non-constants. (Most similar to inner classes.)
C. (Fine) Detect call sites with one or two distinct method handles (receiver values) and optimistically compile code that inlines the whole method handle.
Case C. would be a subsumed by instance profiling, as in JDK-8016580.