--- old/src/share/classes/java/lang/invoke/AbstractValidatingLambdaMetafactory.java Wed Jun 19 10:01:08 2013 +++ new/src/share/classes/java/lang/invoke/AbstractValidatingLambdaMetafactory.java Wed Jun 19 10:01:07 2013 @@ -24,12 +24,15 @@ */ 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. * @@ -64,43 +67,26 @@ 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 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 + * @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 * @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, @@ -107,9 +93,8 @@ MethodHandle samMethod, MethodHandle implMethod, MethodType instantiatedMethodType, - boolean isSerializable, - Class[] markerInterfaces, - MethodType[] additionalBridges) + int flags, + Class[] markerInterfaces) throws ReflectiveOperationException, LambdaConversionException { this.targetClass = caller.lookupClass(); this.invokedType = invokedType; @@ -133,22 +118,32 @@ 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; } /** @@ -270,9 +265,9 @@ } /** - * Check type adaptability for parameter types. - * @param fromType Type to convert from - * @param toType Type to convert to + * Check type adaptability + * @param fromType + * @param toType * @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' */ @@ -304,14 +299,15 @@ } } else { // both are reference types: fromType should be a superclass of toType. - return !strict || toType.isAssignableFrom(fromType); + return strict? toType.isAssignableFrom(fromType) : true; } } } /** - * Check type adaptability for return types -- special handling of void type) - * and parameterized fromType + * Check type adaptability for return types -- special handling of void type) and parameterized fromType + * @param fromType + * @param toType * @return True if 'fromType' can be converted to 'toType' */ private boolean isAdaptableToAsReturn(Class fromType, Class toType) { @@ -342,4 +338,89 @@ } ***********************/ + /** + * 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; + } + } } --- old/src/share/classes/java/lang/invoke/InnerClassLambdaMetafactory.java Wed Jun 19 10:01:09 2013 +++ new/src/share/classes/java/lang/invoke/InnerClassLambdaMetafactory.java Wed Jun 19 10:01:09 2013 @@ -25,17 +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. * @@ -42,8 +41,6 @@ * @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"; @@ -80,39 +77,26 @@ private final Type[] instantiatedArgumentTypes; // ASM types for the functional interface arguments /** - * General meta-factory constructor, supporting both standard cases and - * allowing for uncommon options such as serialization or bridging. + * General meta-factory constructor, standard cases and allowing for uncommon options such as serialization. * - * @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 + * @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. * @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, @@ -119,12 +103,10 @@ MethodHandle samMethod, MethodHandle implMethod, MethodType instantiatedMethodType, - boolean isSerializable, - Class[] markerInterfaces, - MethodType[] additionalBridges) + int flags, + Class[] markerInterfaces) throws ReflectiveOperationException, LambdaConversionException { - super(caller, invokedType, samMethod, implMethod, instantiatedMethodType, - isSerializable, markerInterfaces, additionalBridges); + super(caller, invokedType, samMethod, implMethod, instantiatedMethodType, flags, markerInterfaces); implMethodClassName = implDefiningClass.getName().replace('.', '/'); implMethodName = implInfo.getName(); implMethodDesc = implMethodType.toMethodDescriptorString(); @@ -152,8 +134,7 @@ * @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 { @@ -193,16 +174,8 @@ * 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('.', '/'); @@ -224,22 +197,28 @@ generateConstructor(); + MethodAnalyzer ma = new MethodAnalyzer(); + // Forward the SAM method - String methodDescriptor = samMethodType.toMethodDescriptorString(); - MethodVisitor mv = cw.visitMethod(ACC_PUBLIC, samInfo.getName(), methodDescriptor, null, null); - new ForwardingMethodGenerator(mv).generate(methodDescriptor); + if (ma.getSamMethod() == null) { + throw new LambdaConversionException(String.format("Functional interface method not found: %s", samMethodType)); + } else { + generateForwardingMethod(ma.getSamMethod(), false); + } // Forward the bridges - 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); + // @@@ 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 (isSerializable) + if (isSerializable) { generateWriteReplace(); + } cw.visitEnd(); @@ -268,8 +247,8 @@ } ); - return UNSAFE.defineClass(lambdaClassName, classBytes, 0, classBytes.length, - loader, pd); + return (Class) Unsafe.getUnsafe().defineClass(lambdaClassName, classBytes, 0, classBytes.length, + loader, pd); } /** @@ -286,8 +265,7 @@ 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 @@ -305,7 +283,7 @@ 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('.', '/')); @@ -335,6 +313,24 @@ } /** + * 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. */ @@ -344,12 +340,12 @@ super(mv); } - void generate(String methodDescriptor) { + void generate(Method m) throws InternalError { visitCode(); if (implKind == MethodHandleInfo.REF_newInvokeSpecial) { visitTypeInsn(NEW, implMethodClassName); - visitInsn(DUP); + visitInsn(DUP);; } for (int i = 0; i < argTypes.length; i++) { visitVarInsn(ALOAD, 0); @@ -356,7 +352,7 @@ visitFieldInsn(GETFIELD, lambdaClassName, argNames[i], argTypes[i].getDescriptor()); } - convertArgumentTypes(Type.getArgumentTypes(methodDescriptor)); + convertArgumentTypes(Type.getArgumentTypes(m)); // Invoke the method we want to forward to visitMethodInsn(invocationOpcode(), implMethodClassName, implMethodName, implMethodDesc); @@ -363,7 +359,7 @@ // 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(methodDescriptor); + Type samReturnType = Type.getReturnType(m); convertType(implMethodReturnType, samReturnType, samReturnType); visitInsn(samReturnType.getOpcode(Opcodes.IRETURN)); --- old/src/share/classes/java/lang/invoke/LambdaMetafactory.java Wed Jun 19 10:01:10 2013 +++ new/src/share/classes/java/lang/invoke/LambdaMetafactory.java Wed Jun 19 10:01:10 2013 @@ -25,9 +25,6 @@ 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.

* @@ -47,12 +44,17 @@ * *

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 { 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 + * 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 * instantiated method type), which has signature - * {@code (Byte)int}. + * (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. + * *

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 * captured by the lambda expression; there may also be differences resulting from permitted adaptations of @@ -142,59 +144,38 @@ */ 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. + * @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, @@ -204,17 +185,15 @@ MethodType instantiatedMethodType) throws ReflectiveOperationException, LambdaConversionException { AbstractValidatingLambdaMetafactory mf; - mf = new InnerClassLambdaMetafactory(caller, invokedType, samMethod, - implMethod, instantiatedMethodType, - false, EMPTY_CLASS_ARRAY, EMPTY_MT_ARRAY); + mf = new InnerClassLambdaMetafactory(caller, invokedType, samMethod, implMethod, instantiatedMethodType, + 0, EMPTY_CLASS_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: * @@ -234,28 +213,21 @@ * 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 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 + * @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 - * @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, @@ -267,7 +239,6 @@ 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++]; @@ -277,30 +248,9 @@ } else markerInterfaces = EMPTY_CLASS_ARRAY; - 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); + AbstractValidatingLambdaMetafactory mf; + mf = new InnerClassLambdaMetafactory(caller, invokedType, samMethod, implMethod, instantiatedMethodType, + flags, markerInterfaces); mf.validateMetafactoryArgs(); return mf.buildCallSite(); }