8016281: The SAM method should be passed to the metafactory as a MethodType not a MethodHandle
8020010: Move lambda bridge creation from metafactory and VM to compiler JDK/metafactory component of the bridge fix and and MethodType vs. MethodHandle changes. Reviewed-by: twisti, briangoetz, forax
This commit is contained in:
parent
51ac0c583f
commit
381356dde3
jdk/src/share/classes/java/lang/invoke
@ -24,24 +24,23 @@
|
||||
*/
|
||||
package java.lang.invoke;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.lang.reflect.Method;
|
||||
import java.lang.reflect.Modifier;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import sun.invoke.util.Wrapper;
|
||||
import static sun.invoke.util.Wrapper.*;
|
||||
|
||||
import static sun.invoke.util.Wrapper.forPrimitiveType;
|
||||
import static sun.invoke.util.Wrapper.forWrapperType;
|
||||
import static sun.invoke.util.Wrapper.isWrapperType;
|
||||
|
||||
/**
|
||||
* Abstract implementation of a lambda metafactory which provides parameter unrolling and input validation.
|
||||
* Abstract implementation of a lambda metafactory which provides parameter
|
||||
* unrolling and input validation.
|
||||
*
|
||||
* @see LambdaMetafactory
|
||||
*/
|
||||
/* package */ abstract class AbstractValidatingLambdaMetafactory {
|
||||
|
||||
/*
|
||||
* For context, the comments for the following fields are marked in quotes with their values, given this program:
|
||||
* For context, the comments for the following fields are marked in quotes
|
||||
* with their values, given this program:
|
||||
* interface II<T> { Object foo(T x); }
|
||||
* interface JJ<R extends Number> extends II<R> { }
|
||||
* class CC { String impl(int i) { return "impl:"+i; }}
|
||||
@ -54,9 +53,7 @@ import static sun.invoke.util.Wrapper.*;
|
||||
final Class<?> targetClass; // The class calling the meta-factory via invokedynamic "class X"
|
||||
final MethodType invokedType; // The type of the invoked method "(CC)II"
|
||||
final Class<?> samBase; // The type of the returned instance "interface JJ"
|
||||
final MethodHandle samMethod; // Raw method handle for the functional interface method
|
||||
final MethodHandleInfo samInfo; // Info about the SAM method handle "MethodHandleInfo[9 II.foo(Object)Object]"
|
||||
final Class<?> samClass; // Interface containing the SAM method "interface II"
|
||||
final String samMethodName; // Name of the SAM method "foo"
|
||||
final MethodType samMethodType; // Type of the SAM method "(Object)Object"
|
||||
final MethodHandle implMethod; // Raw method handle for the implementation method
|
||||
final MethodHandleInfo implInfo; // Info about the implementation method handle "MethodHandleInfo[5 CC.impl(int)String]"
|
||||
@ -67,44 +64,64 @@ import static sun.invoke.util.Wrapper.*;
|
||||
final MethodType instantiatedMethodType; // Instantiated erased functional interface method type "(Integer)Object"
|
||||
final boolean isSerializable; // Should the returned instance be serializable
|
||||
final Class<?>[] markerInterfaces; // Additional marker interfaces to be implemented
|
||||
final MethodType[] additionalBridges; // Signatures of additional methods to bridge
|
||||
|
||||
|
||||
/**
|
||||
* Meta-factory constructor.
|
||||
*
|
||||
* @param caller Stacked automatically by VM; represents a lookup context with the accessibility privileges
|
||||
* of the caller.
|
||||
* @param invokedType Stacked automatically by VM; the signature of the invoked method, which includes the
|
||||
* expected static type of the returned lambda object, and the static types of the captured
|
||||
* arguments for the lambda. In the event that the implementation method is an instance method,
|
||||
* the first argument in the invocation signature will correspond to the receiver.
|
||||
* @param samMethod The primary method in the functional interface to which the lambda or method reference is
|
||||
* being converted, represented as a method handle.
|
||||
* @param implMethod The implementation method which should be called (with suitable adaptation of argument
|
||||
* types, return types, and adjustment for captured arguments) when methods of the resulting
|
||||
* functional interface instance are invoked.
|
||||
* @param instantiatedMethodType The signature of the primary functional interface method after type variables
|
||||
* are substituted with their instantiation from the capture site
|
||||
* @param caller Stacked automatically by VM; represents a lookup context
|
||||
* with the accessibility privileges of the caller.
|
||||
* @param invokedType Stacked automatically by VM; the signature of the
|
||||
* invoked method, which includes the expected static
|
||||
* type of the returned lambda object, and the static
|
||||
* types of the captured arguments for the lambda. In
|
||||
* the event that the implementation method is an
|
||||
* instance method, the first argument in the invocation
|
||||
* signature will correspond to the receiver.
|
||||
* @param samMethodName Name of the method in the functional interface to
|
||||
* which the lambda or method reference is being
|
||||
* converted, represented as a String.
|
||||
* @param samMethodType Type of the method in the functional interface to
|
||||
* which the lambda or method reference is being
|
||||
* converted, represented as a MethodType.
|
||||
* @param implMethod The implementation method which should be called
|
||||
* (with suitable adaptation of argument types, return
|
||||
* types, and adjustment for captured arguments) when
|
||||
* methods of the resulting functional interface instance
|
||||
* are invoked.
|
||||
* @param instantiatedMethodType The signature of the primary functional
|
||||
* interface method after type variables are
|
||||
* substituted with their instantiation from
|
||||
* the capture site
|
||||
* @param isSerializable Should the lambda be made serializable? If set,
|
||||
* either the target type or one of the additional SAM
|
||||
* types must extend {@code Serializable}.
|
||||
* @param markerInterfaces Additional interfaces which the lambda object
|
||||
* should implement.
|
||||
* @param additionalBridges Method types for additional signatures to be
|
||||
* bridged to the implementation method
|
||||
* @throws ReflectiveOperationException
|
||||
* @throws LambdaConversionException If any of the meta-factory protocol invariants are violated
|
||||
* @throws LambdaConversionException If any of the meta-factory protocol
|
||||
* invariants are violated
|
||||
*/
|
||||
AbstractValidatingLambdaMetafactory(MethodHandles.Lookup caller,
|
||||
MethodType invokedType,
|
||||
MethodHandle samMethod,
|
||||
String samMethodName,
|
||||
MethodType samMethodType,
|
||||
MethodHandle implMethod,
|
||||
MethodType instantiatedMethodType,
|
||||
int flags,
|
||||
Class<?>[] markerInterfaces)
|
||||
boolean isSerializable,
|
||||
Class<?>[] markerInterfaces,
|
||||
MethodType[] additionalBridges)
|
||||
throws ReflectiveOperationException, LambdaConversionException {
|
||||
this.targetClass = caller.lookupClass();
|
||||
this.invokedType = invokedType;
|
||||
|
||||
this.samBase = invokedType.returnType();
|
||||
|
||||
this.samMethod = samMethod;
|
||||
this.samInfo = new MethodHandleInfo(samMethod);
|
||||
this.samClass = samInfo.getDeclaringClass();
|
||||
this.samMethodType = samInfo.getMethodType();
|
||||
this.samMethodName = samMethodName;
|
||||
this.samMethodType = samMethodType;
|
||||
|
||||
this.implMethod = implMethod;
|
||||
this.implInfo = new MethodHandleInfo(implMethod);
|
||||
@ -118,32 +135,24 @@ import static sun.invoke.util.Wrapper.*;
|
||||
implKind == MethodHandleInfo.REF_invokeInterface;
|
||||
this.implDefiningClass = implInfo.getDeclaringClass();
|
||||
this.implMethodType = implInfo.getMethodType();
|
||||
|
||||
this.instantiatedMethodType = instantiatedMethodType;
|
||||
this.isSerializable = isSerializable;
|
||||
this.markerInterfaces = markerInterfaces;
|
||||
this.additionalBridges = additionalBridges;
|
||||
|
||||
if (!samClass.isInterface()) {
|
||||
if (!samBase.isInterface()) {
|
||||
throw new LambdaConversionException(String.format(
|
||||
"Functional interface %s is not an interface",
|
||||
samClass.getName()));
|
||||
samBase.getName()));
|
||||
}
|
||||
|
||||
boolean foundSerializableSupertype = Serializable.class.isAssignableFrom(samBase);
|
||||
for (Class<?> c : markerInterfaces) {
|
||||
if (!c.isInterface()) {
|
||||
throw new LambdaConversionException(String.format(
|
||||
"Marker interface %s is not an interface",
|
||||
c.getName()));
|
||||
}
|
||||
foundSerializableSupertype |= Serializable.class.isAssignableFrom(c);
|
||||
}
|
||||
this.isSerializable = ((flags & LambdaMetafactory.FLAG_SERIALIZABLE) != 0)
|
||||
|| foundSerializableSupertype;
|
||||
|
||||
if (isSerializable && !foundSerializableSupertype) {
|
||||
markerInterfaces = Arrays.copyOf(markerInterfaces, markerInterfaces.length + 1);
|
||||
markerInterfaces[markerInterfaces.length-1] = Serializable.class;
|
||||
}
|
||||
this.markerInterfaces = markerInterfaces;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -153,20 +162,14 @@ import static sun.invoke.util.Wrapper.*;
|
||||
* functional interface
|
||||
* @throws ReflectiveOperationException
|
||||
*/
|
||||
abstract CallSite buildCallSite() throws ReflectiveOperationException, LambdaConversionException;
|
||||
abstract CallSite buildCallSite()
|
||||
throws ReflectiveOperationException, LambdaConversionException;
|
||||
|
||||
/**
|
||||
* Check the meta-factory arguments for errors
|
||||
* @throws LambdaConversionException if there are improper conversions
|
||||
*/
|
||||
void validateMetafactoryArgs() throws LambdaConversionException {
|
||||
// Check target type is a subtype of class where SAM method is defined
|
||||
if (!samClass.isAssignableFrom(samBase)) {
|
||||
throw new LambdaConversionException(
|
||||
String.format("Invalid target type %s for lambda conversion; not a subtype of functional interface %s",
|
||||
samBase.getName(), samClass.getName()));
|
||||
}
|
||||
|
||||
switch (implKind) {
|
||||
case MethodHandleInfo.REF_invokeInterface:
|
||||
case MethodHandleInfo.REF_invokeVirtual:
|
||||
@ -265,9 +268,9 @@ import static sun.invoke.util.Wrapper.*;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check type adaptability
|
||||
* @param fromType
|
||||
* @param toType
|
||||
* Check type adaptability for parameter types.
|
||||
* @param fromType Type to convert from
|
||||
* @param toType Type to convert to
|
||||
* @param strict If true, do strict checks, else allow that fromType may be parameterized
|
||||
* @return True if 'fromType' can be passed to an argument of 'toType'
|
||||
*/
|
||||
@ -299,15 +302,14 @@ import static sun.invoke.util.Wrapper.*;
|
||||
}
|
||||
} else {
|
||||
// both are reference types: fromType should be a superclass of toType.
|
||||
return strict? toType.isAssignableFrom(fromType) : true;
|
||||
return !strict || toType.isAssignableFrom(fromType);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Check type adaptability for return types -- special handling of void type) and parameterized fromType
|
||||
* @param fromType
|
||||
* @param toType
|
||||
* Check type adaptability for return types --
|
||||
* special handling of void type) and parameterized fromType
|
||||
* @return True if 'fromType' can be converted to 'toType'
|
||||
*/
|
||||
private boolean isAdaptableToAsReturn(Class<?> fromType, Class<?> toType) {
|
||||
@ -338,89 +340,4 @@ import static sun.invoke.util.Wrapper.*;
|
||||
}
|
||||
***********************/
|
||||
|
||||
/**
|
||||
* Find the functional interface method and corresponding abstract methods
|
||||
* which should be bridged. The functional interface method and those to be
|
||||
* bridged will have the same name and number of parameters. Check for
|
||||
* matching default methods (non-abstract), the VM will create bridges for
|
||||
* default methods; We don't have enough readily available type information
|
||||
* to distinguish between where the functional interface method should be
|
||||
* bridged and where the default method should be bridged; This situation is
|
||||
* flagged.
|
||||
*/
|
||||
class MethodAnalyzer {
|
||||
private final Method[] methods = samBase.getMethods();
|
||||
|
||||
private Method samMethod = null;
|
||||
private final List<Method> methodsToBridge = new ArrayList<>(methods.length);
|
||||
private boolean conflictFoundBetweenDefaultAndBridge = false;
|
||||
|
||||
MethodAnalyzer() {
|
||||
String samMethodName = samInfo.getName();
|
||||
Class<?>[] samParamTypes = samMethodType.parameterArray();
|
||||
int samParamLength = samParamTypes.length;
|
||||
Class<?> samReturnType = samMethodType.returnType();
|
||||
Class<?> objectClass = Object.class;
|
||||
List<Method> defaultMethods = new ArrayList<>(methods.length);
|
||||
|
||||
for (Method m : methods) {
|
||||
if (m.getName().equals(samMethodName) && m.getDeclaringClass() != objectClass) {
|
||||
Class<?>[] mParamTypes = m.getParameterTypes();
|
||||
if (mParamTypes.length == samParamLength) {
|
||||
// Method matches name and parameter length -- and is not Object
|
||||
if (Modifier.isAbstract(m.getModifiers())) {
|
||||
// Method is abstract
|
||||
if (m.getReturnType().equals(samReturnType)
|
||||
&& Arrays.equals(mParamTypes, samParamTypes)) {
|
||||
// Exact match, this is the SAM method signature
|
||||
samMethod = m;
|
||||
} else if (!hasMatchingBridgeSignature(m)) {
|
||||
// Record bridges, exclude methods with duplicate signatures
|
||||
methodsToBridge.add(m);
|
||||
}
|
||||
} else {
|
||||
// Record default methods for conflict testing
|
||||
defaultMethods.add(m);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
for (Method dm : defaultMethods) {
|
||||
if (hasMatchingBridgeSignature(dm)) {
|
||||
conflictFoundBetweenDefaultAndBridge = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Method getSamMethod() {
|
||||
return samMethod;
|
||||
}
|
||||
|
||||
List<Method> getMethodsToBridge() {
|
||||
return methodsToBridge;
|
||||
}
|
||||
|
||||
boolean conflictFoundBetweenDefaultAndBridge() {
|
||||
return conflictFoundBetweenDefaultAndBridge;
|
||||
}
|
||||
|
||||
/**
|
||||
* Search the list of previously found bridge methods to determine if there is a method with the same signature
|
||||
* (return and parameter types) as the specified method.
|
||||
*
|
||||
* @param m The method to match
|
||||
* @return True if the method was found, False otherwise
|
||||
*/
|
||||
private boolean hasMatchingBridgeSignature(Method m) {
|
||||
Class<?>[] ptypes = m.getParameterTypes();
|
||||
Class<?> rtype = m.getReturnType();
|
||||
for (Method md : methodsToBridge) {
|
||||
if (md.getReturnType().equals(rtype) && Arrays.equals(ptypes, md.getParameterTypes())) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -25,22 +25,26 @@
|
||||
|
||||
package java.lang.invoke;
|
||||
|
||||
import java.lang.reflect.Constructor;
|
||||
import java.lang.reflect.Method;
|
||||
import java.security.ProtectionDomain;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
import jdk.internal.org.objectweb.asm.*;
|
||||
import static jdk.internal.org.objectweb.asm.Opcodes.*;
|
||||
import sun.misc.Unsafe;
|
||||
|
||||
import java.lang.reflect.Constructor;
|
||||
import java.security.AccessController;
|
||||
import java.security.PrivilegedAction;
|
||||
import java.security.ProtectionDomain;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
|
||||
import static jdk.internal.org.objectweb.asm.Opcodes.*;
|
||||
|
||||
/**
|
||||
* Lambda metafactory implementation which dynamically creates an inner-class-like class per lambda callsite.
|
||||
* Lambda metafactory implementation which dynamically creates an
|
||||
* inner-class-like class per lambda callsite.
|
||||
*
|
||||
* @see LambdaMetafactory
|
||||
*/
|
||||
/* package */ final class InnerClassLambdaMetafactory extends AbstractValidatingLambdaMetafactory {
|
||||
private static final Unsafe UNSAFE = Unsafe.getUnsafe();
|
||||
|
||||
private static final int CLASSFILE_VERSION = 51;
|
||||
private static final String METHOD_DESCRIPTOR_VOID = Type.getMethodDescriptor(Type.VOID_TYPE);
|
||||
private static final String NAME_MAGIC_ACCESSOR_IMPL = "java/lang/invoke/MagicLambdaImpl";
|
||||
@ -54,7 +58,7 @@ import java.security.PrivilegedAction;
|
||||
private static final String DESCR_CTOR_SERIALIZED_LAMBDA
|
||||
= MethodType.methodType(void.class,
|
||||
Class.class,
|
||||
int.class, String.class, String.class, String.class,
|
||||
String.class, String.class, String.class,
|
||||
int.class, String.class, String.class, String.class,
|
||||
String.class,
|
||||
Object[].class).toMethodDescriptorString();
|
||||
@ -77,36 +81,56 @@ import java.security.PrivilegedAction;
|
||||
private final Type[] instantiatedArgumentTypes; // ASM types for the functional interface arguments
|
||||
|
||||
/**
|
||||
* General meta-factory constructor, standard cases and allowing for uncommon options such as serialization.
|
||||
* General meta-factory constructor, supporting both standard cases and
|
||||
* allowing for uncommon options such as serialization or bridging.
|
||||
*
|
||||
* @param caller Stacked automatically by VM; represents a lookup context with the accessibility privileges
|
||||
* of the caller.
|
||||
* @param invokedType Stacked automatically by VM; the signature of the invoked method, which includes the
|
||||
* expected static type of the returned lambda object, and the static types of the captured
|
||||
* arguments for the lambda. In the event that the implementation method is an instance method,
|
||||
* the first argument in the invocation signature will correspond to the receiver.
|
||||
* @param samMethod The primary method in the functional interface to which the lambda or method reference is
|
||||
* being converted, represented as a method handle.
|
||||
* @param implMethod The implementation method which should be called (with suitable adaptation of argument
|
||||
* types, return types, and adjustment for captured arguments) when methods of the resulting
|
||||
* functional interface instance are invoked.
|
||||
* @param instantiatedMethodType The signature of the primary functional interface method after type variables
|
||||
* are substituted with their instantiation from the capture site
|
||||
* @param flags A bitmask containing flags that may influence the translation of this lambda expression. Defined
|
||||
* fields include FLAG_SERIALIZABLE.
|
||||
* @param markerInterfaces Additional interfaces which the lambda object should implement.
|
||||
* @param caller Stacked automatically by VM; represents a lookup context
|
||||
* with the accessibility privileges of the caller.
|
||||
* @param invokedType Stacked automatically by VM; the signature of the
|
||||
* invoked method, which includes the expected static
|
||||
* type of the returned lambda object, and the static
|
||||
* types of the captured arguments for the lambda. In
|
||||
* the event that the implementation method is an
|
||||
* instance method, the first argument in the invocation
|
||||
* signature will correspond to the receiver.
|
||||
* @param samMethodName Name of the method in the functional interface to
|
||||
* which the lambda or method reference is being
|
||||
* converted, represented as a String.
|
||||
* @param samMethodType Type of the method in the functional interface to
|
||||
* which the lambda or method reference is being
|
||||
* converted, represented as a MethodType.
|
||||
* @param implMethod The implementation method which should be called (with
|
||||
* suitable adaptation of argument types, return types,
|
||||
* and adjustment for captured arguments) when methods of
|
||||
* the resulting functional interface instance are invoked.
|
||||
* @param instantiatedMethodType The signature of the primary functional
|
||||
* interface method after type variables are
|
||||
* substituted with their instantiation from
|
||||
* the capture site
|
||||
* @param isSerializable Should the lambda be made serializable? If set,
|
||||
* either the target type or one of the additional SAM
|
||||
* types must extend {@code Serializable}.
|
||||
* @param markerInterfaces Additional interfaces which the lambda object
|
||||
* should implement.
|
||||
* @param additionalBridges Method types for additional signatures to be
|
||||
* bridged to the implementation method
|
||||
* @throws ReflectiveOperationException
|
||||
* @throws LambdaConversionException If any of the meta-factory protocol invariants are violated
|
||||
* @throws LambdaConversionException If any of the meta-factory protocol
|
||||
* invariants are violated
|
||||
*/
|
||||
public InnerClassLambdaMetafactory(MethodHandles.Lookup caller,
|
||||
MethodType invokedType,
|
||||
MethodHandle samMethod,
|
||||
String samMethodName,
|
||||
MethodType samMethodType,
|
||||
MethodHandle implMethod,
|
||||
MethodType instantiatedMethodType,
|
||||
int flags,
|
||||
Class<?>[] markerInterfaces)
|
||||
boolean isSerializable,
|
||||
Class<?>[] markerInterfaces,
|
||||
MethodType[] additionalBridges)
|
||||
throws ReflectiveOperationException, LambdaConversionException {
|
||||
super(caller, invokedType, samMethod, implMethod, instantiatedMethodType, flags, markerInterfaces);
|
||||
super(caller, invokedType, samMethodName, samMethodType,
|
||||
implMethod, instantiatedMethodType,
|
||||
isSerializable, markerInterfaces, additionalBridges);
|
||||
implMethodClassName = implDefiningClass.getName().replace('.', '/');
|
||||
implMethodName = implInfo.getName();
|
||||
implMethodDesc = implMethodType.toMethodDescriptorString();
|
||||
@ -124,7 +148,8 @@ import java.security.PrivilegedAction;
|
||||
for (int i = 0; i < argTypes.length; i++) {
|
||||
argNames[i] = "arg$" + (i + 1);
|
||||
}
|
||||
instantiatedArgumentTypes = Type.getArgumentTypes(instantiatedMethodType.toMethodDescriptorString());
|
||||
instantiatedArgumentTypes = Type.getArgumentTypes(
|
||||
instantiatedMethodType.toMethodDescriptorString());
|
||||
}
|
||||
|
||||
/**
|
||||
@ -136,7 +161,8 @@ import java.security.PrivilegedAction;
|
||||
* @return a CallSite, which, when invoked, will return an instance of the
|
||||
* functional interface
|
||||
* @throws ReflectiveOperationException
|
||||
* @throws LambdaConversionException If properly formed functional interface is not found
|
||||
* @throws LambdaConversionException If properly formed functional interface
|
||||
* is not found
|
||||
*/
|
||||
@Override
|
||||
CallSite buildCallSite() throws ReflectiveOperationException, LambdaConversionException {
|
||||
@ -167,8 +193,8 @@ import java.security.PrivilegedAction;
|
||||
} else {
|
||||
return new ConstantCallSite(
|
||||
MethodHandles.Lookup.IMPL_LOOKUP
|
||||
.findConstructor(innerClass, constructorType)
|
||||
.asType(constructorType.changeReturnType(samBase)));
|
||||
.findConstructor(innerClass, constructorType)
|
||||
.asType(constructorType.changeReturnType(samBase)));
|
||||
}
|
||||
}
|
||||
|
||||
@ -176,13 +202,20 @@ import java.security.PrivilegedAction;
|
||||
* Generate a class file which implements the functional
|
||||
* interface, define and return the class.
|
||||
*
|
||||
* @implNote The class that is generated does not include signature
|
||||
* information for exceptions that may be present on the SAM method.
|
||||
* This is to reduce classfile size, and is harmless as checked exceptions
|
||||
* are erased anyway, no one will ever compile against this classfile,
|
||||
* and we make no guarantees about the reflective properties of lambda
|
||||
* objects.
|
||||
*
|
||||
* @return a Class which implements the functional interface
|
||||
* @throws LambdaConversionException If properly formed functional interface is not found
|
||||
* @throws LambdaConversionException If properly formed functional interface
|
||||
* is not found
|
||||
*/
|
||||
private Class<?> spinInnerClass() throws LambdaConversionException {
|
||||
String samName = samBase.getName().replace('.', '/');
|
||||
String[] interfaces = new String[markerInterfaces.length + 1];
|
||||
interfaces[0] = samName;
|
||||
interfaces[0] = samBase.getName().replace('.', '/');
|
||||
for (int i=0; i<markerInterfaces.length; i++) {
|
||||
interfaces[i+1] = markerInterfaces[i].getName().replace('.', '/');
|
||||
}
|
||||
@ -192,35 +225,33 @@ import java.security.PrivilegedAction;
|
||||
|
||||
// Generate final fields to be filled in by constructor
|
||||
for (int i = 0; i < argTypes.length; i++) {
|
||||
FieldVisitor fv = cw.visitField(ACC_PRIVATE + ACC_FINAL, argNames[i], argTypes[i].getDescriptor(),
|
||||
FieldVisitor fv = cw.visitField(ACC_PRIVATE + ACC_FINAL,
|
||||
argNames[i],
|
||||
argTypes[i].getDescriptor(),
|
||||
null, null);
|
||||
fv.visitEnd();
|
||||
}
|
||||
|
||||
generateConstructor();
|
||||
|
||||
MethodAnalyzer ma = new MethodAnalyzer();
|
||||
|
||||
// Forward the SAM method
|
||||
if (ma.getSamMethod() == null) {
|
||||
throw new LambdaConversionException(String.format("Functional interface method not found: %s", samMethodType));
|
||||
} else {
|
||||
generateForwardingMethod(ma.getSamMethod(), false);
|
||||
}
|
||||
String methodDescriptor = samMethodType.toMethodDescriptorString();
|
||||
MethodVisitor mv = cw.visitMethod(ACC_PUBLIC, samMethodName,
|
||||
methodDescriptor, null, null);
|
||||
new ForwardingMethodGenerator(mv).generate(methodDescriptor);
|
||||
|
||||
// Forward the bridges
|
||||
// @@@ The commented-out code is temporary, pending the VM's ability to bridge all methods on request
|
||||
// @@@ Once the VM can do fail-over, uncomment the !ma.wasDefaultMethodFound() test, and emit the appropriate
|
||||
// @@@ classfile attribute to request custom bridging. See 8002092.
|
||||
if (!ma.getMethodsToBridge().isEmpty() /* && !ma.conflictFoundBetweenDefaultAndBridge() */ ) {
|
||||
for (Method m : ma.getMethodsToBridge()) {
|
||||
generateForwardingMethod(m, true);
|
||||
if (additionalBridges != null) {
|
||||
for (MethodType mt : additionalBridges) {
|
||||
methodDescriptor = mt.toMethodDescriptorString();
|
||||
mv = cw.visitMethod(ACC_PUBLIC|ACC_BRIDGE, samMethodName,
|
||||
methodDescriptor, null, null);
|
||||
new ForwardingMethodGenerator(mv).generate(methodDescriptor);
|
||||
}
|
||||
}
|
||||
|
||||
if (isSerializable) {
|
||||
if (isSerializable)
|
||||
generateWriteReplace();
|
||||
}
|
||||
|
||||
cw.visitEnd();
|
||||
|
||||
@ -229,11 +260,14 @@ import java.security.PrivilegedAction;
|
||||
final byte[] classBytes = cw.toByteArray();
|
||||
|
||||
/*** Uncomment to dump the generated file
|
||||
System.out.printf("Loaded: %s (%d bytes) %n", lambdaClassName, classBytes.length);
|
||||
try (FileOutputStream fos = new FileOutputStream(lambdaClassName.replace('/', '.') + ".class")) {
|
||||
System.out.printf("Loaded: %s (%d bytes) %n", lambdaClassName,
|
||||
classBytes.length);
|
||||
try (FileOutputStream fos = new FileOutputStream(lambdaClassName
|
||||
.replace('/', '.') + ".class")) {
|
||||
fos.write(classBytes);
|
||||
} catch (IOException ex) {
|
||||
PlatformLogger.getLogger(InnerClassLambdaMetafactory.class.getName()).severe(ex.getMessage(), ex);
|
||||
PlatformLogger.getLogger(InnerClassLambdaMetafactory.class
|
||||
.getName()).severe(ex.getMessage(), ex);
|
||||
}
|
||||
***/
|
||||
|
||||
@ -249,8 +283,9 @@ import java.security.PrivilegedAction;
|
||||
}
|
||||
);
|
||||
|
||||
return (Class<?>) Unsafe.getUnsafe().defineClass(lambdaClassName, classBytes, 0, classBytes.length,
|
||||
loader, pd);
|
||||
return UNSAFE.defineClass(lambdaClassName,
|
||||
classBytes, 0, classBytes.length,
|
||||
loader, pd);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -258,19 +293,23 @@ import java.security.PrivilegedAction;
|
||||
*/
|
||||
private void generateConstructor() {
|
||||
// Generate constructor
|
||||
MethodVisitor ctor = cw.visitMethod(ACC_PRIVATE, NAME_CTOR, constructorDesc, null, null);
|
||||
MethodVisitor ctor = cw.visitMethod(ACC_PRIVATE, NAME_CTOR,
|
||||
constructorDesc, null, null);
|
||||
ctor.visitCode();
|
||||
ctor.visitVarInsn(ALOAD, 0);
|
||||
ctor.visitMethodInsn(INVOKESPECIAL, NAME_MAGIC_ACCESSOR_IMPL, NAME_CTOR, METHOD_DESCRIPTOR_VOID);
|
||||
ctor.visitMethodInsn(INVOKESPECIAL, NAME_MAGIC_ACCESSOR_IMPL, NAME_CTOR,
|
||||
METHOD_DESCRIPTOR_VOID);
|
||||
int lvIndex = 0;
|
||||
for (int i = 0; i < argTypes.length; i++) {
|
||||
ctor.visitVarInsn(ALOAD, 0);
|
||||
ctor.visitVarInsn(argTypes[i].getOpcode(ILOAD), lvIndex + 1);
|
||||
lvIndex += argTypes[i].getSize();
|
||||
ctor.visitFieldInsn(PUTFIELD, lambdaClassName, argNames[i], argTypes[i].getDescriptor());
|
||||
ctor.visitFieldInsn(PUTFIELD, lambdaClassName, argNames[i],
|
||||
argTypes[i].getDescriptor());
|
||||
}
|
||||
ctor.visitInsn(RETURN);
|
||||
ctor.visitMaxs(-1, -1); // Maxs computed by ClassWriter.COMPUTE_MAXS, these arguments ignored
|
||||
// Maxs computed by ClassWriter.COMPUTE_MAXS, these arguments ignored
|
||||
ctor.visitMaxs(-1, -1);
|
||||
ctor.visitEnd();
|
||||
}
|
||||
|
||||
@ -279,18 +318,18 @@ import java.security.PrivilegedAction;
|
||||
*/
|
||||
private void generateWriteReplace() {
|
||||
TypeConvertingMethodAdapter mv
|
||||
= new TypeConvertingMethodAdapter(cw.visitMethod(ACC_PRIVATE + ACC_FINAL,
|
||||
NAME_METHOD_WRITE_REPLACE, DESCR_METHOD_WRITE_REPLACE,
|
||||
null, null));
|
||||
= new TypeConvertingMethodAdapter(
|
||||
cw.visitMethod(ACC_PRIVATE + ACC_FINAL,
|
||||
NAME_METHOD_WRITE_REPLACE, DESCR_METHOD_WRITE_REPLACE,
|
||||
null, null));
|
||||
|
||||
mv.visitCode();
|
||||
mv.visitTypeInsn(NEW, NAME_SERIALIZED_LAMBDA);
|
||||
mv.visitInsn(DUP);;
|
||||
mv.visitInsn(DUP);
|
||||
mv.visitLdcInsn(Type.getType(targetClass));
|
||||
mv.visitLdcInsn(samInfo.getReferenceKind());
|
||||
mv.visitLdcInsn(invokedType.returnType().getName().replace('.', '/'));
|
||||
mv.visitLdcInsn(samInfo.getName());
|
||||
mv.visitLdcInsn(samInfo.getMethodType().toMethodDescriptorString());
|
||||
mv.visitLdcInsn(samMethodName);
|
||||
mv.visitLdcInsn(samMethodType.toMethodDescriptorString());
|
||||
mv.visitLdcInsn(implInfo.getReferenceKind());
|
||||
mv.visitLdcInsn(implInfo.getDeclaringClass().getName().replace('.', '/'));
|
||||
mv.visitLdcInsn(implInfo.getName());
|
||||
@ -303,35 +342,19 @@ import java.security.PrivilegedAction;
|
||||
mv.visitInsn(DUP);
|
||||
mv.iconst(i);
|
||||
mv.visitVarInsn(ALOAD, 0);
|
||||
mv.visitFieldInsn(GETFIELD, lambdaClassName, argNames[i], argTypes[i].getDescriptor());
|
||||
mv.visitFieldInsn(GETFIELD, lambdaClassName, argNames[i],
|
||||
argTypes[i].getDescriptor());
|
||||
mv.boxIfTypePrimitive(argTypes[i]);
|
||||
mv.visitInsn(AASTORE);
|
||||
}
|
||||
mv.visitMethodInsn(INVOKESPECIAL, NAME_SERIALIZED_LAMBDA, NAME_CTOR,
|
||||
DESCR_CTOR_SERIALIZED_LAMBDA);
|
||||
mv.visitInsn(ARETURN);
|
||||
mv.visitMaxs(-1, -1); // Maxs computed by ClassWriter.COMPUTE_MAXS, these arguments ignored
|
||||
// Maxs computed by ClassWriter.COMPUTE_MAXS, these arguments ignored
|
||||
mv.visitMaxs(-1, -1);
|
||||
mv.visitEnd();
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate a method which calls the lambda implementation method,
|
||||
* converting arguments, as needed.
|
||||
* @param m The method whose signature should be generated
|
||||
* @param isBridge True if this methods should be flagged as a bridge
|
||||
*/
|
||||
private void generateForwardingMethod(Method m, boolean isBridge) {
|
||||
Class<?>[] exceptionTypes = m.getExceptionTypes();
|
||||
String[] exceptionNames = new String[exceptionTypes.length];
|
||||
for (int i = 0; i < exceptionTypes.length; i++) {
|
||||
exceptionNames[i] = exceptionTypes[i].getName().replace('.', '/');
|
||||
}
|
||||
String methodDescriptor = Type.getMethodDescriptor(m);
|
||||
int access = isBridge? ACC_PUBLIC | ACC_BRIDGE : ACC_PUBLIC;
|
||||
MethodVisitor mv = cw.visitMethod(access, m.getName(), methodDescriptor, null, exceptionNames);
|
||||
new ForwardingMethodGenerator(mv).generate(m);
|
||||
}
|
||||
|
||||
/**
|
||||
* This class generates a method body which calls the lambda implementation
|
||||
* method, converting arguments, as needed.
|
||||
@ -342,36 +365,39 @@ import java.security.PrivilegedAction;
|
||||
super(mv);
|
||||
}
|
||||
|
||||
void generate(Method m) throws InternalError {
|
||||
void generate(String methodDescriptor) {
|
||||
visitCode();
|
||||
|
||||
if (implKind == MethodHandleInfo.REF_newInvokeSpecial) {
|
||||
visitTypeInsn(NEW, implMethodClassName);
|
||||
visitInsn(DUP);;
|
||||
visitInsn(DUP);
|
||||
}
|
||||
for (int i = 0; i < argTypes.length; i++) {
|
||||
visitVarInsn(ALOAD, 0);
|
||||
visitFieldInsn(GETFIELD, lambdaClassName, argNames[i], argTypes[i].getDescriptor());
|
||||
visitFieldInsn(GETFIELD, lambdaClassName, argNames[i],
|
||||
argTypes[i].getDescriptor());
|
||||
}
|
||||
|
||||
convertArgumentTypes(Type.getArgumentTypes(m));
|
||||
convertArgumentTypes(Type.getArgumentTypes(methodDescriptor));
|
||||
|
||||
// Invoke the method we want to forward to
|
||||
visitMethodInsn(invocationOpcode(), implMethodClassName, implMethodName, implMethodDesc);
|
||||
|
||||
// Convert the return value (if any) and return it
|
||||
// Note: if adapting from non-void to void, the 'return' instruction will pop the unneeded result
|
||||
Type samReturnType = Type.getReturnType(m);
|
||||
// Note: if adapting from non-void to void, the 'return'
|
||||
// instruction will pop the unneeded result
|
||||
Type samReturnType = Type.getReturnType(methodDescriptor);
|
||||
convertType(implMethodReturnType, samReturnType, samReturnType);
|
||||
visitInsn(samReturnType.getOpcode(Opcodes.IRETURN));
|
||||
|
||||
visitMaxs(-1, -1); // Maxs computed by ClassWriter.COMPUTE_MAXS, these arguments ignored
|
||||
// Maxs computed by ClassWriter.COMPUTE_MAXS,these arguments ignored
|
||||
visitMaxs(-1, -1);
|
||||
visitEnd();
|
||||
}
|
||||
|
||||
private void convertArgumentTypes(Type[] samArgumentTypes) {
|
||||
int lvIndex = 0;
|
||||
boolean samIncludesReceiver = implIsInstanceMethod && argTypes.length == 0;
|
||||
boolean samIncludesReceiver = implIsInstanceMethod &&
|
||||
argTypes.length == 0;
|
||||
int samReceiverLength = samIncludesReceiver ? 1 : 0;
|
||||
if (samIncludesReceiver) {
|
||||
// push receiver
|
||||
@ -395,7 +421,9 @@ import java.security.PrivilegedAction;
|
||||
}
|
||||
|
||||
private void convertType(Type argType, Type targetType, Type functionalType) {
|
||||
convertType(argType.getDescriptor(), targetType.getDescriptor(), functionalType.getDescriptor());
|
||||
convertType(argType.getDescriptor(),
|
||||
targetType.getDescriptor(),
|
||||
functionalType.getDescriptor());
|
||||
}
|
||||
|
||||
private int invocationOpcode() throws InternalError {
|
||||
|
@ -25,6 +25,9 @@
|
||||
|
||||
package java.lang.invoke;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.Arrays;
|
||||
|
||||
/**
|
||||
* <p>Bootstrap methods for converting lambda expressions and method references to functional interface objects.</p>
|
||||
*
|
||||
@ -44,16 +47,11 @@ package java.lang.invoke;
|
||||
*
|
||||
* <p>When parameterized types are used, the instantiated type of the functional interface method may be different
|
||||
* from that in the functional interface. For example, consider
|
||||
* <code>interface I<T> { int m(T x); }</code> if this functional interface type is used in a lambda
|
||||
* <code>I<Byte> v = ...</code>, we need both the actual functional interface method which has the signature
|
||||
* <code>(Object)int</code> and the erased instantiated type of the functional interface method (or simply
|
||||
* {@code interface I<T> { int m(T x); }} if this functional interface type is used in a lambda
|
||||
* {@code I<Byte>; v = ...}, we need both the actual functional interface method which has the signature
|
||||
* {@code (Object)int} and the erased instantiated type of the functional interface method (or simply
|
||||
* <I>instantiated method type</I>), which has signature
|
||||
* <code>(Byte)int</code>.
|
||||
*
|
||||
* <p>While functional interfaces only have a single abstract method from the language perspective (concrete
|
||||
* methods in Object are and default methods may be present), at the bytecode level they may actually have multiple
|
||||
* methods because of the need for bridge methods. Invoking any of these methods on the lambda object will result
|
||||
* in invoking the implementation method.
|
||||
* {@code (Byte)int}.
|
||||
*
|
||||
* <p>The argument list of the implementation method and the argument list of the functional interface method(s)
|
||||
* may differ in several ways. The implementation methods may have additional arguments to accommodate arguments
|
||||
@ -137,108 +135,147 @@ package java.lang.invoke;
|
||||
* </tr>
|
||||
* </table>
|
||||
*
|
||||
* The default bootstrap ({@link #metaFactory}) represents the common cases and uses an optimized protocol.
|
||||
* Alternate bootstraps (e.g., {@link #altMetaFactory}) exist to support uncommon cases such as serialization
|
||||
* The default bootstrap ({@link #metafactory}) represents the common cases and uses an optimized protocol.
|
||||
* Alternate bootstraps (e.g., {@link #altMetafactory}) exist to support uncommon cases such as serialization
|
||||
* or additional marker superinterfaces.
|
||||
*
|
||||
*/
|
||||
public class LambdaMetafactory {
|
||||
|
||||
/** Flag for alternate metafactories indicating the lambda object is must to be serializable */
|
||||
/** Flag for alternate metafactories indicating the lambda object is
|
||||
* must to be serializable */
|
||||
public static final int FLAG_SERIALIZABLE = 1 << 0;
|
||||
|
||||
/**
|
||||
* Flag for alternate metafactories indicating the lambda object implements other marker interfaces
|
||||
* Flag for alternate metafactories indicating the lambda object implements
|
||||
* other marker interfaces
|
||||
* besides Serializable
|
||||
*/
|
||||
public static final int FLAG_MARKERS = 1 << 1;
|
||||
|
||||
/**
|
||||
* Flag for alternate metafactories indicating the lambda object requires
|
||||
* additional bridge methods
|
||||
*/
|
||||
public static final int FLAG_BRIDGES = 1 << 2;
|
||||
|
||||
private static final Class<?>[] EMPTY_CLASS_ARRAY = new Class<?>[0];
|
||||
private static final MethodType[] EMPTY_MT_ARRAY = new MethodType[0];
|
||||
|
||||
/**
|
||||
* Standard meta-factory for conversion of lambda expressions or method references to functional interfaces.
|
||||
* Standard meta-factory for conversion of lambda expressions or method
|
||||
* references to functional interfaces.
|
||||
*
|
||||
* @param caller Stacked automatically by VM; represents a lookup context with the accessibility privileges
|
||||
* of the caller.
|
||||
* @param invokedName Stacked automatically by VM; the name of the invoked method as it appears at the call site.
|
||||
* Currently unused.
|
||||
* @param invokedType Stacked automatically by VM; the signature of the invoked method, which includes the
|
||||
* expected static type of the returned lambda object, and the static types of the captured
|
||||
* arguments for the lambda. In the event that the implementation method is an instance method,
|
||||
* the first argument in the invocation signature will correspond to the receiver.
|
||||
* @param samMethod The primary method in the functional interface to which the lambda or method reference is
|
||||
* being converted, represented as a method handle.
|
||||
* @param implMethod The implementation method which should be called (with suitable adaptation of argument
|
||||
* types, return types, and adjustment for captured arguments) when methods of the resulting
|
||||
* functional interface instance are invoked.
|
||||
* @param instantiatedMethodType The signature of the primary functional interface method after type variables
|
||||
* are substituted with their instantiation from the capture site
|
||||
* @return a CallSite, which, when invoked, will return an instance of the functional interface
|
||||
* @throws ReflectiveOperationException if the caller is not able to reconstruct one of the method handles
|
||||
* @throws LambdaConversionException If any of the meta-factory protocol invariants are violated
|
||||
* @param caller Stacked automatically by VM; represents a lookup context
|
||||
* with the accessibility privileges of the caller.
|
||||
* @param invokedName Stacked automatically by VM; the name of the invoked
|
||||
* method as it appears at the call site.
|
||||
* Used as the name of the functional interface method
|
||||
* to which the lambda or method reference is being
|
||||
* converted.
|
||||
* @param invokedType Stacked automatically by VM; the signature of the
|
||||
* invoked method, which includes the expected static
|
||||
* type of the returned lambda object, and the static
|
||||
* types of the captured arguments for the lambda.
|
||||
* In the event that the implementation method is an
|
||||
* instance method, the first argument in the invocation
|
||||
* signature will correspond to the receiver.
|
||||
* @param samMethodType MethodType of the method in the functional interface
|
||||
* to which the lambda or method reference is being
|
||||
* converted, represented as a MethodType.
|
||||
* @param implMethod The implementation method which should be called
|
||||
* (with suitable adaptation of argument types, return
|
||||
* types, and adjustment for captured arguments) when
|
||||
* methods of the resulting functional interface instance
|
||||
* are invoked.
|
||||
* @param instantiatedMethodType The signature of the primary functional
|
||||
* interface method after type variables
|
||||
* are substituted with their instantiation
|
||||
* from the capture site
|
||||
* @return a CallSite, which, when invoked, will return an instance of the
|
||||
* functional interface
|
||||
* @throws ReflectiveOperationException if the caller is not able to
|
||||
* reconstruct one of the method handles
|
||||
* @throws LambdaConversionException If any of the meta-factory protocol
|
||||
* invariants are violated
|
||||
*/
|
||||
public static CallSite metaFactory(MethodHandles.Lookup caller,
|
||||
public static CallSite metafactory(MethodHandles.Lookup caller,
|
||||
String invokedName,
|
||||
MethodType invokedType,
|
||||
MethodHandle samMethod,
|
||||
MethodType samMethodType,
|
||||
MethodHandle implMethod,
|
||||
MethodType instantiatedMethodType)
|
||||
throws ReflectiveOperationException, LambdaConversionException {
|
||||
AbstractValidatingLambdaMetafactory mf;
|
||||
mf = new InnerClassLambdaMetafactory(caller, invokedType, samMethod, implMethod, instantiatedMethodType,
|
||||
0, EMPTY_CLASS_ARRAY);
|
||||
mf = new InnerClassLambdaMetafactory(caller, invokedType,
|
||||
invokedName, samMethodType,
|
||||
implMethod, instantiatedMethodType,
|
||||
false, EMPTY_CLASS_ARRAY, EMPTY_MT_ARRAY);
|
||||
mf.validateMetafactoryArgs();
|
||||
return mf.buildCallSite();
|
||||
}
|
||||
|
||||
/**
|
||||
* Alternate meta-factory for conversion of lambda expressions or method references to functional interfaces,
|
||||
* which supports serialization and other uncommon options.
|
||||
* Alternate meta-factory for conversion of lambda expressions or method
|
||||
* references to functional interfaces, which supports serialization and
|
||||
* other uncommon options.
|
||||
*
|
||||
* The declared argument list for this method is:
|
||||
*
|
||||
* CallSite altMetaFactory(MethodHandles.Lookup caller,
|
||||
* CallSite altMetafactory(MethodHandles.Lookup caller,
|
||||
* String invokedName,
|
||||
* MethodType invokedType,
|
||||
* Object... args)
|
||||
*
|
||||
* but it behaves as if the argument list is:
|
||||
*
|
||||
* CallSite altMetaFactory(MethodHandles.Lookup caller,
|
||||
* CallSite altMetafactory(MethodHandles.Lookup caller,
|
||||
* String invokedName,
|
||||
* MethodType invokedType,
|
||||
* MethodHandle samMethod
|
||||
* MethodType samMethodType
|
||||
* MethodHandle implMethod,
|
||||
* MethodType instantiatedMethodType,
|
||||
* int flags,
|
||||
* int markerInterfaceCount, // IF flags has MARKERS set
|
||||
* Class... markerInterfaces // IF flags has MARKERS set
|
||||
* int bridgeCount, // IF flags has BRIDGES set
|
||||
* MethodType... bridges // IF flags has BRIDGES set
|
||||
* )
|
||||
*
|
||||
*
|
||||
* @param caller Stacked automatically by VM; represents a lookup context with the accessibility privileges
|
||||
* of the caller.
|
||||
* @param invokedName Stacked automatically by VM; the name of the invoked method as it appears at the call site.
|
||||
* Currently unused.
|
||||
* @param invokedType Stacked automatically by VM; the signature of the invoked method, which includes thefu
|
||||
* expected static type of the returned lambda object, and the static types of the captured
|
||||
* arguments for the lambda. In the event that the implementation method is an instance method,
|
||||
* the first argument in the invocation signature will correspond to the receiver.
|
||||
* @param args argument to pass, flags, marker interface count, and marker interfaces as described above
|
||||
* @return a CallSite, which, when invoked, will return an instance of the functional interface
|
||||
* @throws ReflectiveOperationException if the caller is not able to reconstruct one of the method handles
|
||||
* @throws LambdaConversionException If any of the meta-factory protocol invariants are violated
|
||||
* @param caller Stacked automatically by VM; represents a lookup context
|
||||
* with the accessibility privileges of the caller.
|
||||
* @param invokedName Stacked automatically by VM; the name of the invoked
|
||||
* method as it appears at the call site.
|
||||
* Used as the name of the functional interface method
|
||||
* to which the lambda or method reference is being
|
||||
* converted.
|
||||
* @param invokedType Stacked automatically by VM; the signature of the
|
||||
* invoked method, which includes the expected static
|
||||
* type of the returned lambda object, and the static
|
||||
* types of the captured arguments for the lambda.
|
||||
* In the event that the implementation method is an
|
||||
* instance method, the first argument in the invocation
|
||||
* signature will correspond to the receiver.
|
||||
* @param args flags and optional arguments, as described above
|
||||
* @return a CallSite, which, when invoked, will return an instance of the
|
||||
* functional interface
|
||||
* @throws ReflectiveOperationException if the caller is not able to
|
||||
* reconstruct one of the method handles
|
||||
* @throws LambdaConversionException If any of the meta-factory protocol
|
||||
* invariants are violated
|
||||
*/
|
||||
public static CallSite altMetaFactory(MethodHandles.Lookup caller,
|
||||
public static CallSite altMetafactory(MethodHandles.Lookup caller,
|
||||
String invokedName,
|
||||
MethodType invokedType,
|
||||
Object... args)
|
||||
throws ReflectiveOperationException, LambdaConversionException {
|
||||
MethodHandle samMethod = (MethodHandle)args[0];
|
||||
MethodType samMethodType = (MethodType)args[0];
|
||||
MethodHandle implMethod = (MethodHandle)args[1];
|
||||
MethodType instantiatedMethodType = (MethodType)args[2];
|
||||
int flags = (Integer) args[3];
|
||||
Class<?>[] markerInterfaces;
|
||||
MethodType[] bridges;
|
||||
int argIndex = 4;
|
||||
if ((flags & FLAG_MARKERS) != 0) {
|
||||
int markerCount = (Integer) args[argIndex++];
|
||||
@ -248,9 +285,33 @@ public class LambdaMetafactory {
|
||||
}
|
||||
else
|
||||
markerInterfaces = EMPTY_CLASS_ARRAY;
|
||||
AbstractValidatingLambdaMetafactory mf;
|
||||
mf = new InnerClassLambdaMetafactory(caller, invokedType, samMethod, implMethod, instantiatedMethodType,
|
||||
flags, markerInterfaces);
|
||||
if ((flags & FLAG_BRIDGES) != 0) {
|
||||
int bridgeCount = (Integer) args[argIndex++];
|
||||
bridges = new MethodType[bridgeCount];
|
||||
System.arraycopy(args, argIndex, bridges, 0, bridgeCount);
|
||||
argIndex += bridgeCount;
|
||||
}
|
||||
else
|
||||
bridges = EMPTY_MT_ARRAY;
|
||||
|
||||
boolean foundSerializableSupertype = Serializable.class.isAssignableFrom(invokedType.returnType());
|
||||
for (Class<?> c : markerInterfaces)
|
||||
foundSerializableSupertype |= Serializable.class.isAssignableFrom(c);
|
||||
boolean isSerializable = ((flags & LambdaMetafactory.FLAG_SERIALIZABLE) != 0)
|
||||
|| foundSerializableSupertype;
|
||||
|
||||
if (isSerializable && !foundSerializableSupertype) {
|
||||
markerInterfaces = Arrays.copyOf(markerInterfaces, markerInterfaces.length + 1);
|
||||
markerInterfaces[markerInterfaces.length-1] = Serializable.class;
|
||||
}
|
||||
|
||||
AbstractValidatingLambdaMetafactory mf
|
||||
= new InnerClassLambdaMetafactory(caller, invokedType,
|
||||
invokedName, samMethodType,
|
||||
implMethod,
|
||||
instantiatedMethodType,
|
||||
isSerializable,
|
||||
markerInterfaces, bridges);
|
||||
mf.validateMetafactoryArgs();
|
||||
return mf.buildCallSite();
|
||||
}
|
||||
|
@ -44,7 +44,6 @@ public final class SerializedLambda implements Serializable {
|
||||
private final String functionalInterfaceClass;
|
||||
private final String functionalInterfaceMethodName;
|
||||
private final String functionalInterfaceMethodSignature;
|
||||
private final int functionalInterfaceMethodKind;
|
||||
private final String implClass;
|
||||
private final String implMethodName;
|
||||
private final String implMethodSignature;
|
||||
@ -53,28 +52,32 @@ public final class SerializedLambda implements Serializable {
|
||||
private final Object[] capturedArgs;
|
||||
|
||||
/**
|
||||
* Create a {@code SerializedLambda} from the low-level information present at the lambda factory site.
|
||||
* Create a {@code SerializedLambda} from the low-level information present
|
||||
* at the lambda factory site.
|
||||
*
|
||||
* @param capturingClass The class in which the lambda expression appears
|
||||
* @param functionalInterfaceMethodKind Method handle kind (see {@link MethodHandleInfo}) for the
|
||||
* functional interface method handle present at the lambda factory site
|
||||
* @param functionalInterfaceClass Name, in slash-delimited form, for the functional interface class present at the
|
||||
* lambda factory site
|
||||
* @param functionalInterfaceMethodName Name of the primary method for the functional interface present at the
|
||||
* @param functionalInterfaceClass Name, in slash-delimited form, of static
|
||||
* type of the returned lambda object
|
||||
* @param functionalInterfaceMethodName Name of the functional interface
|
||||
* method for the present at the
|
||||
* lambda factory site
|
||||
* @param functionalInterfaceMethodSignature Signature of the primary method for the functional interface present
|
||||
* at the lambda factory site
|
||||
* @param functionalInterfaceMethodSignature Signature of the functional
|
||||
* interface method present at
|
||||
* the lambda factory site
|
||||
* @param implMethodKind Method handle kind for the implementation method
|
||||
* @param implClass Name, in slash-delimited form, for the class holding the implementation method
|
||||
* @param implClass Name, in slash-delimited form, for the class holding
|
||||
* the implementation method
|
||||
* @param implMethodName Name of the implementation method
|
||||
* @param implMethodSignature Signature of the implementation method
|
||||
* @param instantiatedMethodType The signature of the primary functional interface method after type variables
|
||||
* are substituted with their instantiation from the capture site
|
||||
* @param capturedArgs The dynamic arguments to the lambda factory site, which represent variables captured by
|
||||
* @param instantiatedMethodType The signature of the primary functional
|
||||
* interface method after type variables
|
||||
* are substituted with their instantiation
|
||||
* from the capture site
|
||||
* @param capturedArgs The dynamic arguments to the lambda factory site,
|
||||
* which represent variables captured by
|
||||
* the lambda
|
||||
*/
|
||||
public SerializedLambda(Class<?> capturingClass,
|
||||
int functionalInterfaceMethodKind,
|
||||
String functionalInterfaceClass,
|
||||
String functionalInterfaceMethodName,
|
||||
String functionalInterfaceMethodSignature,
|
||||
@ -85,7 +88,6 @@ public final class SerializedLambda implements Serializable {
|
||||
String instantiatedMethodType,
|
||||
Object[] capturedArgs) {
|
||||
this.capturingClass = capturingClass;
|
||||
this.functionalInterfaceMethodKind = functionalInterfaceMethodKind;
|
||||
this.functionalInterfaceClass = functionalInterfaceClass;
|
||||
this.functionalInterfaceMethodName = functionalInterfaceMethodName;
|
||||
this.functionalInterfaceMethodSignature = functionalInterfaceMethodSignature;
|
||||
@ -106,10 +108,10 @@ public final class SerializedLambda implements Serializable {
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the name of the functional interface class to which this
|
||||
* Get the name of the invoked type to which this
|
||||
* lambda has been converted
|
||||
* @return the name of the functional interface this lambda has
|
||||
* been converted to
|
||||
* @return the name of the functional interface class to which
|
||||
* this lambda has been converted
|
||||
*/
|
||||
public String getFunctionalInterfaceClass() {
|
||||
return functionalInterfaceClass;
|
||||
@ -134,17 +136,6 @@ public final class SerializedLambda implements Serializable {
|
||||
return functionalInterfaceMethodSignature;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the method handle kind (see {@link MethodHandleInfo}) of
|
||||
* the primary method for the functional interface to which this
|
||||
* lambda has been converted
|
||||
* @return the method handle kind of the primary method of
|
||||
* functional interface
|
||||
*/
|
||||
public int getFunctionalInterfaceMethodKind() {
|
||||
return functionalInterfaceMethodKind;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the name of the class containing the implementation
|
||||
* method.
|
||||
@ -234,11 +225,17 @@ public final class SerializedLambda implements Serializable {
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return String.format("SerializedLambda[capturingClass=%s, functionalInterfaceMethod=%s %s.%s:%s, " +
|
||||
"implementation=%s %s.%s:%s, instantiatedMethodType=%s, numCaptured=%d]",
|
||||
capturingClass, MethodHandleInfo.getReferenceKindString(functionalInterfaceMethodKind),
|
||||
functionalInterfaceClass, functionalInterfaceMethodName, functionalInterfaceMethodSignature,
|
||||
MethodHandleInfo.getReferenceKindString(implMethodKind), implClass, implMethodName,
|
||||
implMethodSignature, instantiatedMethodType, capturedArgs.length);
|
||||
String implKind=MethodHandleInfo.getReferenceKindString(implMethodKind);
|
||||
return String.format("SerializedLambda[%s=%s, %s=%s.%s:%s, " +
|
||||
"%s=%s %s.%s:%s, %s=%s, %s=%d]",
|
||||
"capturingClass", capturingClass,
|
||||
"functionalInterfaceMethod", functionalInterfaceClass,
|
||||
functionalInterfaceMethodName,
|
||||
functionalInterfaceMethodSignature,
|
||||
"implementation",
|
||||
implKind,
|
||||
implClass, implMethodName, implMethodSignature,
|
||||
"instantiatedMethodType", instantiatedMethodType,
|
||||
"numCaptured", capturedArgs.length);
|
||||
}
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user