提交 7ce092d9 编写于 作者: M mcimadamore

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
Summary: JDK/metafactory component of the bridge fix and and MethodType vs. MethodHandle changes.
Reviewed-by: twisti, briangoetz, forax
Contributed-by: robert.field@oracle.com
上级 b500185e
...@@ -24,24 +24,23 @@ ...@@ -24,24 +24,23 @@
*/ */
package java.lang.invoke; 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 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 * @see LambdaMetafactory
*/ */
/* package */ abstract class AbstractValidatingLambdaMetafactory { /* 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 II<T> { Object foo(T x); }
* interface JJ<R extends Number> extends II<R> { } * interface JJ<R extends Number> extends II<R> { }
* class CC { String impl(int i) { return "impl:"+i; }} * class CC { String impl(int i) { return "impl:"+i; }}
...@@ -54,9 +53,7 @@ import static sun.invoke.util.Wrapper.*; ...@@ -54,9 +53,7 @@ import static sun.invoke.util.Wrapper.*;
final Class<?> targetClass; // The class calling the meta-factory via invokedynamic "class X" 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 MethodType invokedType; // The type of the invoked method "(CC)II"
final Class<?> samBase; // The type of the returned instance "interface JJ" final Class<?> samBase; // The type of the returned instance "interface JJ"
final MethodHandle samMethod; // Raw method handle for the functional interface method final String samMethodName; // Name of the SAM method "foo"
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 MethodType samMethodType; // Type of the SAM method "(Object)Object" final MethodType samMethodType; // Type of the SAM method "(Object)Object"
final MethodHandle implMethod; // Raw method handle for the implementation method 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]" 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.*; ...@@ -67,44 +64,64 @@ import static sun.invoke.util.Wrapper.*;
final MethodType instantiatedMethodType; // Instantiated erased functional interface method type "(Integer)Object" final MethodType instantiatedMethodType; // Instantiated erased functional interface method type "(Integer)Object"
final boolean isSerializable; // Should the returned instance be serializable final boolean isSerializable; // Should the returned instance be serializable
final Class<?>[] markerInterfaces; // Additional marker interfaces to be implemented final Class<?>[] markerInterfaces; // Additional marker interfaces to be implemented
final MethodType[] additionalBridges; // Signatures of additional methods to bridge
/** /**
* Meta-factory constructor. * Meta-factory constructor.
* *
* @param caller Stacked automatically by VM; represents a lookup context with the accessibility privileges * @param caller Stacked automatically by VM; represents a lookup context
* of the caller. * with the accessibility privileges of the caller.
* @param invokedType Stacked automatically by VM; the signature of the invoked method, which includes the * @param invokedType Stacked automatically by VM; the signature of the
* expected static type of the returned lambda object, and the static types of the captured * invoked method, which includes the expected static
* arguments for the lambda. In the event that the implementation method is an instance method, * type of the returned lambda object, and the static
* the first argument in the invocation signature will correspond to the receiver. * types of the captured arguments for the lambda. In
* @param samMethod The primary method in the functional interface to which the lambda or method reference is * the event that the implementation method is an
* being converted, represented as a method handle. * instance method, the first argument in the invocation
* @param implMethod The implementation method which should be called (with suitable adaptation of argument * signature will correspond to the receiver.
* types, return types, and adjustment for captured arguments) when methods of the resulting * @param samMethodName Name of the method in the functional interface to
* functional interface instance are invoked. * which the lambda or method reference is being
* @param instantiatedMethodType The signature of the primary functional interface method after type variables * converted, represented as a String.
* are substituted with their instantiation from the capture site * @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 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, AbstractValidatingLambdaMetafactory(MethodHandles.Lookup caller,
MethodType invokedType, MethodType invokedType,
MethodHandle samMethod, String samMethodName,
MethodType samMethodType,
MethodHandle implMethod, MethodHandle implMethod,
MethodType instantiatedMethodType, MethodType instantiatedMethodType,
int flags, boolean isSerializable,
Class<?>[] markerInterfaces) Class<?>[] markerInterfaces,
MethodType[] additionalBridges)
throws ReflectiveOperationException, LambdaConversionException { throws ReflectiveOperationException, LambdaConversionException {
this.targetClass = caller.lookupClass(); this.targetClass = caller.lookupClass();
this.invokedType = invokedType; this.invokedType = invokedType;
this.samBase = invokedType.returnType(); this.samBase = invokedType.returnType();
this.samMethod = samMethod; this.samMethodName = samMethodName;
this.samInfo = new MethodHandleInfo(samMethod); this.samMethodType = samMethodType;
this.samClass = samInfo.getDeclaringClass();
this.samMethodType = samInfo.getMethodType();
this.implMethod = implMethod; this.implMethod = implMethod;
this.implInfo = new MethodHandleInfo(implMethod); this.implInfo = new MethodHandleInfo(implMethod);
...@@ -118,32 +135,24 @@ import static sun.invoke.util.Wrapper.*; ...@@ -118,32 +135,24 @@ import static sun.invoke.util.Wrapper.*;
implKind == MethodHandleInfo.REF_invokeInterface; implKind == MethodHandleInfo.REF_invokeInterface;
this.implDefiningClass = implInfo.getDeclaringClass(); this.implDefiningClass = implInfo.getDeclaringClass();
this.implMethodType = implInfo.getMethodType(); this.implMethodType = implInfo.getMethodType();
this.instantiatedMethodType = instantiatedMethodType; this.instantiatedMethodType = instantiatedMethodType;
this.isSerializable = isSerializable;
this.markerInterfaces = markerInterfaces;
this.additionalBridges = additionalBridges;
if (!samClass.isInterface()) { if (!samBase.isInterface()) {
throw new LambdaConversionException(String.format( throw new LambdaConversionException(String.format(
"Functional interface %s is not an interface", "Functional interface %s is not an interface",
samClass.getName())); samBase.getName()));
} }
boolean foundSerializableSupertype = Serializable.class.isAssignableFrom(samBase);
for (Class<?> c : markerInterfaces) { for (Class<?> c : markerInterfaces) {
if (!c.isInterface()) { if (!c.isInterface()) {
throw new LambdaConversionException(String.format( throw new LambdaConversionException(String.format(
"Marker interface %s is not an interface", "Marker interface %s is not an interface",
c.getName())); 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.*; ...@@ -153,20 +162,14 @@ import static sun.invoke.util.Wrapper.*;
* functional interface * functional interface
* @throws ReflectiveOperationException * @throws ReflectiveOperationException
*/ */
abstract CallSite buildCallSite() throws ReflectiveOperationException, LambdaConversionException; abstract CallSite buildCallSite()
throws ReflectiveOperationException, LambdaConversionException;
/** /**
* Check the meta-factory arguments for errors * Check the meta-factory arguments for errors
* @throws LambdaConversionException if there are improper conversions * @throws LambdaConversionException if there are improper conversions
*/ */
void validateMetafactoryArgs() throws LambdaConversionException { 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) { switch (implKind) {
case MethodHandleInfo.REF_invokeInterface: case MethodHandleInfo.REF_invokeInterface:
case MethodHandleInfo.REF_invokeVirtual: case MethodHandleInfo.REF_invokeVirtual:
...@@ -265,9 +268,9 @@ import static sun.invoke.util.Wrapper.*; ...@@ -265,9 +268,9 @@ import static sun.invoke.util.Wrapper.*;
} }
/** /**
* Check type adaptability * Check type adaptability for parameter types.
* @param fromType * @param fromType Type to convert from
* @param toType * @param toType Type to convert to
* @param strict If true, do strict checks, else allow that fromType may be parameterized * @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' * @return True if 'fromType' can be passed to an argument of 'toType'
*/ */
...@@ -299,15 +302,14 @@ import static sun.invoke.util.Wrapper.*; ...@@ -299,15 +302,14 @@ import static sun.invoke.util.Wrapper.*;
} }
} else { } else {
// both are reference types: fromType should be a superclass of toType. // 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 * Check type adaptability for return types --
* @param fromType * special handling of void type) and parameterized fromType
* @param toType
* @return True if 'fromType' can be converted to 'toType' * @return True if 'fromType' can be converted to 'toType'
*/ */
private boolean isAdaptableToAsReturn(Class<?> fromType, Class<?> toType) { private boolean isAdaptableToAsReturn(Class<?> fromType, Class<?> toType) {
...@@ -338,89 +340,4 @@ import static sun.invoke.util.Wrapper.*; ...@@ -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,6 +25,9 @@ ...@@ -25,6 +25,9 @@
package java.lang.invoke; 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> * <p>Bootstrap methods for converting lambda expressions and method references to functional interface objects.</p>
* *
...@@ -44,16 +47,11 @@ package java.lang.invoke; ...@@ -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 * <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 * from that in the functional interface. For example, consider
* <code>interface I&lt;T&gt; { int m(T x); }</code> if this functional interface type is used in a lambda * {@code interface I<T> { int m(T x); }} if this functional interface type is used in a lambda
* <code>I&lt;Byte&gt; v = ...</code>, we need both the actual functional interface method which has the signature * {@code I<Byte>; v = ...}, 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 (Object)int} and the erased instantiated type of the functional interface method (or simply
* <I>instantiated method type</I>), which has signature * <I>instantiated method type</I>), which has signature
* <code>(Byte)int</code>. * {@code (Byte)int}.
*
* <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.
* *
* <p>The argument list of the implementation method and the argument list of the functional interface method(s) * <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 * may differ in several ways. The implementation methods may have additional arguments to accommodate arguments
...@@ -137,108 +135,147 @@ package java.lang.invoke; ...@@ -137,108 +135,147 @@ package java.lang.invoke;
* </tr> * </tr>
* </table> * </table>
* *
* The default bootstrap ({@link #metaFactory}) represents the common cases and uses an optimized protocol. * 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 * Alternate bootstraps (e.g., {@link #altMetafactory}) exist to support uncommon cases such as serialization
* or additional marker superinterfaces. * or additional marker superinterfaces.
* *
*/ */
public class LambdaMetafactory { 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; 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 * besides Serializable
*/ */
public static final int FLAG_MARKERS = 1 << 1; 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 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 * @param caller Stacked automatically by VM; represents a lookup context
* of the caller. * 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. * @param invokedName Stacked automatically by VM; the name of the invoked
* Currently unused. * method as it appears at the call site.
* @param invokedType Stacked automatically by VM; the signature of the invoked method, which includes the * Used as the name of the functional interface method
* expected static type of the returned lambda object, and the static types of the captured * to which the lambda or method reference is being
* arguments for the lambda. In the event that the implementation method is an instance method, * converted.
* the first argument in the invocation signature will correspond to the receiver. * @param invokedType Stacked automatically by VM; the signature of the
* @param samMethod The primary method in the functional interface to which the lambda or method reference is * invoked method, which includes the expected static
* being converted, represented as a method handle. * type of the returned lambda object, and the static
* @param implMethod The implementation method which should be called (with suitable adaptation of argument * types of the captured arguments for the lambda.
* types, return types, and adjustment for captured arguments) when methods of the resulting * In the event that the implementation method is an
* functional interface instance are invoked. * instance method, the first argument in the invocation
* @param instantiatedMethodType The signature of the primary functional interface method after type variables * signature will correspond to the receiver.
* are substituted with their instantiation from the capture site * @param samMethodType MethodType of the method in the functional interface
* @return a CallSite, which, when invoked, will return an instance of the functional interface * to which the lambda or method reference is being
* @throws ReflectiveOperationException if the caller is not able to reconstruct one of the method handles * converted, represented as a MethodType.
* @throws LambdaConversionException If any of the meta-factory protocol invariants are violated * @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, String invokedName,
MethodType invokedType, MethodType invokedType,
MethodHandle samMethod, MethodType samMethodType,
MethodHandle implMethod, MethodHandle implMethod,
MethodType instantiatedMethodType) MethodType instantiatedMethodType)
throws ReflectiveOperationException, LambdaConversionException { throws ReflectiveOperationException, LambdaConversionException {
AbstractValidatingLambdaMetafactory mf; AbstractValidatingLambdaMetafactory mf;
mf = new InnerClassLambdaMetafactory(caller, invokedType, samMethod, implMethod, instantiatedMethodType, mf = new InnerClassLambdaMetafactory(caller, invokedType,
0, EMPTY_CLASS_ARRAY); invokedName, samMethodType,
implMethod, instantiatedMethodType,
false, EMPTY_CLASS_ARRAY, EMPTY_MT_ARRAY);
mf.validateMetafactoryArgs(); mf.validateMetafactoryArgs();
return mf.buildCallSite(); return mf.buildCallSite();
} }
/** /**
* Alternate meta-factory for conversion of lambda expressions or method references to functional interfaces, * Alternate meta-factory for conversion of lambda expressions or method
* which supports serialization and other uncommon options. * references to functional interfaces, which supports serialization and
* other uncommon options.
* *
* The declared argument list for this method is: * The declared argument list for this method is:
* *
* CallSite altMetaFactory(MethodHandles.Lookup caller, * CallSite altMetafactory(MethodHandles.Lookup caller,
* String invokedName, * String invokedName,
* MethodType invokedType, * MethodType invokedType,
* Object... args) * Object... args)
* *
* but it behaves as if the argument list is: * but it behaves as if the argument list is:
* *
* CallSite altMetaFactory(MethodHandles.Lookup caller, * CallSite altMetafactory(MethodHandles.Lookup caller,
* String invokedName, * String invokedName,
* MethodType invokedType, * MethodType invokedType,
* MethodHandle samMethod * MethodType samMethodType
* MethodHandle implMethod, * MethodHandle implMethod,
* MethodType instantiatedMethodType, * MethodType instantiatedMethodType,
* int flags, * int flags,
* int markerInterfaceCount, // IF flags has MARKERS set * int markerInterfaceCount, // IF flags has MARKERS set
* Class... markerInterfaces // 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 * @param caller Stacked automatically by VM; represents a lookup context
* of the caller. * 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. * @param invokedName Stacked automatically by VM; the name of the invoked
* Currently unused. * method as it appears at the call site.
* @param invokedType Stacked automatically by VM; the signature of the invoked method, which includes thefu * Used as the name of the functional interface method
* expected static type of the returned lambda object, and the static types of the captured * to which the lambda or method reference is being
* arguments for the lambda. In the event that the implementation method is an instance method, * converted.
* the first argument in the invocation signature will correspond to the receiver. * @param invokedType Stacked automatically by VM; the signature of the
* @param args argument to pass, flags, marker interface count, and marker interfaces as described above * invoked method, which includes the expected static
* @return a CallSite, which, when invoked, will return an instance of the functional interface * type of the returned lambda object, and the static
* @throws ReflectiveOperationException if the caller is not able to reconstruct one of the method handles * types of the captured arguments for the lambda.
* @throws LambdaConversionException If any of the meta-factory protocol invariants are violated * 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, String invokedName,
MethodType invokedType, MethodType invokedType,
Object... args) Object... args)
throws ReflectiveOperationException, LambdaConversionException { throws ReflectiveOperationException, LambdaConversionException {
MethodHandle samMethod = (MethodHandle)args[0]; MethodType samMethodType = (MethodType)args[0];
MethodHandle implMethod = (MethodHandle)args[1]; MethodHandle implMethod = (MethodHandle)args[1];
MethodType instantiatedMethodType = (MethodType)args[2]; MethodType instantiatedMethodType = (MethodType)args[2];
int flags = (Integer) args[3]; int flags = (Integer) args[3];
Class<?>[] markerInterfaces; Class<?>[] markerInterfaces;
MethodType[] bridges;
int argIndex = 4; int argIndex = 4;
if ((flags & FLAG_MARKERS) != 0) { if ((flags & FLAG_MARKERS) != 0) {
int markerCount = (Integer) args[argIndex++]; int markerCount = (Integer) args[argIndex++];
...@@ -248,9 +285,33 @@ public class LambdaMetafactory { ...@@ -248,9 +285,33 @@ public class LambdaMetafactory {
} }
else else
markerInterfaces = EMPTY_CLASS_ARRAY; markerInterfaces = EMPTY_CLASS_ARRAY;
AbstractValidatingLambdaMetafactory mf; if ((flags & FLAG_BRIDGES) != 0) {
mf = new InnerClassLambdaMetafactory(caller, invokedType, samMethod, implMethod, instantiatedMethodType, int bridgeCount = (Integer) args[argIndex++];
flags, markerInterfaces); 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(); mf.validateMetafactoryArgs();
return mf.buildCallSite(); return mf.buildCallSite();
} }
......
...@@ -44,7 +44,6 @@ public final class SerializedLambda implements Serializable { ...@@ -44,7 +44,6 @@ public final class SerializedLambda implements Serializable {
private final String functionalInterfaceClass; private final String functionalInterfaceClass;
private final String functionalInterfaceMethodName; private final String functionalInterfaceMethodName;
private final String functionalInterfaceMethodSignature; private final String functionalInterfaceMethodSignature;
private final int functionalInterfaceMethodKind;
private final String implClass; private final String implClass;
private final String implMethodName; private final String implMethodName;
private final String implMethodSignature; private final String implMethodSignature;
...@@ -53,28 +52,32 @@ public final class SerializedLambda implements Serializable { ...@@ -53,28 +52,32 @@ public final class SerializedLambda implements Serializable {
private final Object[] capturedArgs; 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 capturingClass The class in which the lambda expression appears
* @param functionalInterfaceMethodKind Method handle kind (see {@link MethodHandleInfo}) for the * @param functionalInterfaceClass Name, in slash-delimited form, of static
* functional interface method handle present at the lambda factory site * type of the returned lambda object
* @param functionalInterfaceClass Name, in slash-delimited form, for the functional interface class present at the * @param functionalInterfaceMethodName Name of the functional interface
* lambda factory site * method for the present at the
* @param functionalInterfaceMethodName Name of the primary method for the functional interface present at the
* lambda factory site * lambda factory site
* @param functionalInterfaceMethodSignature Signature of the primary method for the functional interface present * @param functionalInterfaceMethodSignature Signature of the functional
* at the lambda factory site * interface method present at
* the lambda factory site
* @param implMethodKind Method handle kind for the implementation method * @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 implMethodName Name of the implementation method
* @param implMethodSignature Signature of the implementation method * @param implMethodSignature Signature of the implementation method
* @param instantiatedMethodType The signature of the primary functional interface method after type variables * @param instantiatedMethodType The signature of the primary functional
* are substituted with their instantiation from the capture site * interface method after type variables
* @param capturedArgs The dynamic arguments to the lambda factory site, which represent variables captured by * 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 * the lambda
*/ */
public SerializedLambda(Class<?> capturingClass, public SerializedLambda(Class<?> capturingClass,
int functionalInterfaceMethodKind,
String functionalInterfaceClass, String functionalInterfaceClass,
String functionalInterfaceMethodName, String functionalInterfaceMethodName,
String functionalInterfaceMethodSignature, String functionalInterfaceMethodSignature,
...@@ -85,7 +88,6 @@ public final class SerializedLambda implements Serializable { ...@@ -85,7 +88,6 @@ public final class SerializedLambda implements Serializable {
String instantiatedMethodType, String instantiatedMethodType,
Object[] capturedArgs) { Object[] capturedArgs) {
this.capturingClass = capturingClass; this.capturingClass = capturingClass;
this.functionalInterfaceMethodKind = functionalInterfaceMethodKind;
this.functionalInterfaceClass = functionalInterfaceClass; this.functionalInterfaceClass = functionalInterfaceClass;
this.functionalInterfaceMethodName = functionalInterfaceMethodName; this.functionalInterfaceMethodName = functionalInterfaceMethodName;
this.functionalInterfaceMethodSignature = functionalInterfaceMethodSignature; this.functionalInterfaceMethodSignature = functionalInterfaceMethodSignature;
...@@ -106,10 +108,10 @@ public final class SerializedLambda implements Serializable { ...@@ -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 * lambda has been converted
* @return the name of the functional interface this lambda has * @return the name of the functional interface class to which
* been converted to * this lambda has been converted
*/ */
public String getFunctionalInterfaceClass() { public String getFunctionalInterfaceClass() {
return functionalInterfaceClass; return functionalInterfaceClass;
...@@ -134,17 +136,6 @@ public final class SerializedLambda implements Serializable { ...@@ -134,17 +136,6 @@ public final class SerializedLambda implements Serializable {
return functionalInterfaceMethodSignature; 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 * Get the name of the class containing the implementation
* method. * method.
...@@ -234,11 +225,17 @@ public final class SerializedLambda implements Serializable { ...@@ -234,11 +225,17 @@ public final class SerializedLambda implements Serializable {
@Override @Override
public String toString() { public String toString() {
return String.format("SerializedLambda[capturingClass=%s, functionalInterfaceMethod=%s %s.%s:%s, " + String implKind=MethodHandleInfo.getReferenceKindString(implMethodKind);
"implementation=%s %s.%s:%s, instantiatedMethodType=%s, numCaptured=%d]", return String.format("SerializedLambda[%s=%s, %s=%s.%s:%s, " +
capturingClass, MethodHandleInfo.getReferenceKindString(functionalInterfaceMethodKind), "%s=%s %s.%s:%s, %s=%s, %s=%d]",
functionalInterfaceClass, functionalInterfaceMethodName, functionalInterfaceMethodSignature, "capturingClass", capturingClass,
MethodHandleInfo.getReferenceKindString(implMethodKind), implClass, implMethodName, "functionalInterfaceMethod", functionalInterfaceClass,
implMethodSignature, instantiatedMethodType, capturedArgs.length); functionalInterfaceMethodName,
functionalInterfaceMethodSignature,
"implementation",
implKind,
implClass, implMethodName, implMethodSignature,
"instantiatedMethodType", instantiatedMethodType,
"numCaptured", capturedArgs.length);
} }
} }
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册