From 8be22cce2d96cd80ad0d55cf452ec7d8d5050784 Mon Sep 17 00:00:00 2001 From: Robert Field Date: Mon, 17 Jun 2013 20:31:04 -0700 Subject: [PATCH] 8015402: Lambda metafactory should not attempt to determine bridge methods Paired with 8013789: Compiler should emit bridges in interfaces Reviewed-by: twisti --- .../AbstractValidatingLambdaMetafactory.java | 179 +++++------------- .../invoke/InnerClassLambdaMetafactory.java | 142 +++++++------- .../java/lang/invoke/LambdaMetafactory.java | 146 +++++++++----- 3 files changed, 220 insertions(+), 247 deletions(-) diff --git a/jdk/src/share/classes/java/lang/invoke/AbstractValidatingLambdaMetafactory.java b/jdk/src/share/classes/java/lang/invoke/AbstractValidatingLambdaMetafactory.java index 892a9dd5316..9f6e91e0728 100644 --- a/jdk/src/share/classes/java/lang/invoke/AbstractValidatingLambdaMetafactory.java +++ b/jdk/src/share/classes/java/lang/invoke/AbstractValidatingLambdaMetafactory.java @@ -24,14 +24,11 @@ */ 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. @@ -67,34 +64,52 @@ 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 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 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, MethodHandle implMethod, MethodType instantiatedMethodType, - int flags, - Class[] markerInterfaces) + boolean isSerializable, + Class[] markerInterfaces, + MethodType[] additionalBridges) throws ReflectiveOperationException, LambdaConversionException { this.targetClass = caller.lookupClass(); this.invokedType = invokedType; @@ -118,32 +133,22 @@ 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()) { throw new LambdaConversionException(String.format( - "Functional interface %s is not an interface", - samClass.getName())); + "Functional interface %s is not an interface", samClass.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())); + "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; } /** @@ -265,9 +270,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 +304,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 +342,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 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 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 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; - } - } } diff --git a/jdk/src/share/classes/java/lang/invoke/InnerClassLambdaMetafactory.java b/jdk/src/share/classes/java/lang/invoke/InnerClassLambdaMetafactory.java index 16703fc0917..80e2bd3be2b 100644 --- a/jdk/src/share/classes/java/lang/invoke/InnerClassLambdaMetafactory.java +++ b/jdk/src/share/classes/java/lang/invoke/InnerClassLambdaMetafactory.java @@ -25,15 +25,16 @@ 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. @@ -41,6 +42,8 @@ import java.security.PrivilegedAction; * @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"; @@ -77,36 +80,51 @@ 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 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 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, 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, samMethod, implMethod, instantiatedMethodType, + isSerializable, markerInterfaces, additionalBridges); implMethodClassName = implDefiningClass.getName().replace('.', '/'); implMethodName = implInfo.getName(); implMethodDesc = implMethodType.toMethodDescriptorString(); @@ -134,7 +152,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 { @@ -174,8 +193,16 @@ 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('.', '/'); @@ -197,28 +224,22 @@ import java.security.PrivilegedAction; 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, samInfo.getName(), 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, samInfo.getName(), methodDescriptor, null, null); + new ForwardingMethodGenerator(mv).generate(methodDescriptor); } } - if (isSerializable) { + if (isSerializable) generateWriteReplace(); - } cw.visitEnd(); @@ -247,8 +268,8 @@ 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); } /** @@ -265,7 +286,8 @@ import java.security.PrivilegedAction; 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 @@ -283,7 +305,7 @@ import java.security.PrivilegedAction; 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('.', '/')); @@ -312,24 +334,6 @@ import java.security.PrivilegedAction; 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. @@ -340,26 +344,26 @@ 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()); } - 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); + Type samReturnType = Type.getReturnType(methodDescriptor); convertType(implMethodReturnType, samReturnType, samReturnType); visitInsn(samReturnType.getOpcode(Opcodes.IRETURN)); diff --git a/jdk/src/share/classes/java/lang/invoke/LambdaMetafactory.java b/jdk/src/share/classes/java/lang/invoke/LambdaMetafactory.java index d179d438e8a..1aeed0090f2 100644 --- a/jdk/src/share/classes/java/lang/invoke/LambdaMetafactory.java +++ b/jdk/src/share/classes/java/lang/invoke/LambdaMetafactory.java @@ -25,6 +25,9 @@ package java.lang.invoke; +import java.io.Serializable; +import java.util.Arrays; + /** *

Bootstrap methods for converting lambda expressions and method references to functional interface objects.

* @@ -44,16 +47,11 @@ package java.lang.invoke; * *

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 - * interface I<T> { int m(T x); } if this functional interface type is used in a lambda - * I<Byte> v = ..., we need both the actual functional interface method which has the signature - * (Object)int and the erased instantiated type of the functional interface method (or simply + * {@code interface I { int m(T x); }} if this functional interface type is used in a lambda + * {@code I; 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 * instantiated method type), which has signature - * (Byte)int. - * - *

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}. * *

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 @@ -144,38 +142,59 @@ package java.lang.invoke; */ 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; - private static final Class[] EMPTY_CLASS_ARRAY = new Class[0]; + /** + * Flag for alternate metafactories indicating the lambda object requires + * additional bridge methods + */ + public static final int FLAG_BRIDGES = 1 << 2; -/** - * Standard meta-factory for conversion of lambda expressions or method references to functional interfaces. + 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. * - * @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. + * @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 + * @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 - * @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 static CallSite metaFactory(MethodHandles.Lookup caller, String invokedName, @@ -185,15 +204,17 @@ public class LambdaMetafactory { MethodType instantiatedMethodType) throws ReflectiveOperationException, LambdaConversionException { AbstractValidatingLambdaMetafactory mf; - mf = new InnerClassLambdaMetafactory(caller, invokedType, samMethod, implMethod, instantiatedMethodType, - 0, EMPTY_CLASS_ARRAY); + mf = new InnerClassLambdaMetafactory(caller, invokedType, samMethod, + 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: * @@ -213,21 +234,28 @@ public class LambdaMetafactory { * 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 + * @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 args flags and optional arguments, as described above + * @return a CallSite, which, when invoked, will return an instance of the + * functional interface * @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 static CallSite altMetaFactory(MethodHandles.Lookup caller, String invokedName, @@ -239,6 +267,7 @@ public class LambdaMetafactory { 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 +277,30 @@ 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, samMethod, + implMethod, instantiatedMethodType, + isSerializable, markerInterfaces, bridges); mf.validateMetafactoryArgs(); return mf.buildCallSite(); }