public final class LambdaBootstrap
extends java.lang.Object
LambdaMetafactory since the Painless casting model
cannot be fully supported through this class.
For each lambda function/method reference used within a Painless script
a class will be generated at link-time using the
lambdaBootstrap(java.lang.invoke.MethodHandles.Lookup, java.lang.String, java.lang.invoke.MethodType, java.lang.invoke.MethodType, java.lang.String, int, java.lang.String, java.lang.invoke.MethodType, int) method that contains the following:
1. member fields for any captured variables
2. a constructor that will take in captured variables and assign them to
their respective member fields
3. a static ctor delegation method, if the lambda function is a ctor.
4. a method that will load the member fields representing captured variables
and take in any other necessary values based on the arguments passed into the
lambda function/reference method; it will then make a delegated call to the
actual lambda function/reference method
Take for example the following Painless script:
List list1 = new ArrayList(); "
list1.add(2); "
List list2 = new ArrayList(); "
list1.forEach(x -> list2.add(x));"
return list[0]"
The script contains a lambda function with a captured variable.
The following Lambda class would be generated:
public static final class $$Lambda0 implements Consumer {
private List arg$0;
private $$Lambda0(List arg$0) {
this.arg$0 = arg$0;
}
public static Consumer create$lambda(List arg$0) {
return new $$Lambda0(arg$0);
}
public void accept(Object val$0) {
Painless$Script.lambda$0(this.arg$0, val$0);
}
}
public class Painless$Script implements ... {
...
public static lambda$0(List list2, Object x) {
list2.add(x);
}
...
}
Also the accept method actually uses an invokedynamic
instruction to call the lambda$0 method so that
MethodHandle.asType(java.lang.invoke.MethodType) can be used to do the necessary
conversions between argument types without having to hard
code them. For method references to a constructor, a static
wrapper method is created, that creates a class instance and
calls the constructor. This method is used by the
invokedynamic call to initialize the instance.
When the CallSite is linked the linked method depends
on whether or not there are captures. If there are no captures
the same instance of the generated lambda class will be
returned each time by the factory method as there are no
changing values other than the arguments, the lambda is a singleton.
If there are captures, a new instance of the generated lambda class
will be returned each time with the captures passed into the
factory method to be stored in the member fields.
Instead of calling the ctor, a static factory method is created
in the lambda class, because a method handle to the ctor directly
is (currently) preventing Hotspot optimizer from correctly doing
escape analysis. Escape analysis is important to optimize the
code in a way, that a new instance is not created on each lambda
invocation with captures, stressing garbage collector (thanks
to Rémi Forax for the explanation about this on Jaxcon 2017!).| Constructor and Description |
|---|
LambdaBootstrap() |
| Modifier and Type | Method and Description |
|---|---|
static java.lang.invoke.CallSite |
delegateBootstrap(java.lang.invoke.MethodHandles.Lookup lookup,
java.lang.String delegateMethodName,
java.lang.invoke.MethodType interfaceMethodType,
java.lang.invoke.MethodHandle delegateMethodHandle)
Links the delegate method to the returned
CallSite. |
static java.lang.invoke.CallSite |
lambdaBootstrap(java.lang.invoke.MethodHandles.Lookup lookup,
java.lang.String interfaceMethodName,
java.lang.invoke.MethodType factoryMethodType,
java.lang.invoke.MethodType interfaceMethodType,
java.lang.String delegateClassName,
int delegateInvokeType,
java.lang.String delegateMethodName,
java.lang.invoke.MethodType delegateMethodType,
int isDelegateInterface)
Generates a lambda class for a lambda function/method reference
within a Painless script.
|
public static java.lang.invoke.CallSite lambdaBootstrap(java.lang.invoke.MethodHandles.Lookup lookup,
java.lang.String interfaceMethodName,
java.lang.invoke.MethodType factoryMethodType,
java.lang.invoke.MethodType interfaceMethodType,
java.lang.String delegateClassName,
int delegateInvokeType,
java.lang.String delegateMethodName,
java.lang.invoke.MethodType delegateMethodType,
int isDelegateInterface)
throws java.lang.invoke.LambdaConversionException
lookup - Standard MethodHandles.lookup()interfaceMethodName - Name of functional interface method that is calledfactoryMethodType - The type of method to be linked to this CallSite; note that
captured types are based on the parameters for this methodinterfaceMethodType - The type of method representing the functional interface methoddelegateClassName - The name of the class to delegate method call todelegateInvokeType - The type of method call to be made
(static, virtual, interface, or constructor)delegateMethodName - The name of the method to be called in the Painless script classdelegateMethodType - The type of method call in the Painless script class without
the captured typesisDelegateInterface - If the method to be called is owned by an interface where
if the value is '1' if the delegate is an interface and '0'
otherwise; note this is an int because the bootstrap method
cannot convert constants to booleanCallSite linked to a factory method for creating a lambda class
that implements the expected functional interfacejava.lang.invoke.LambdaConversionException - Thrown when an illegal type conversion occurs at link timepublic static java.lang.invoke.CallSite delegateBootstrap(java.lang.invoke.MethodHandles.Lookup lookup,
java.lang.String delegateMethodName,
java.lang.invoke.MethodType interfaceMethodType,
java.lang.invoke.MethodHandle delegateMethodHandle)
CallSite. The linked
delegate method will use converted types from the interface method. Using
invokedynamic to make the delegate method call allows
MethodHandle.asType(java.lang.invoke.MethodType) to be used to do the type conversion instead
of either a lot more code or requiring many Classes to be looked
up at link-time.