jdk/src/share/classes/java/lang/invoke/InnerClassLambdaMetafactory.java
changeset 18182 a86f1b828425
parent 16859 45fbee947921
child 18284 e281a0a2583e
equal deleted inserted replaced
18181:4f0a36582461 18182:a86f1b828425
    23  * questions.
    23  * questions.
    24  */
    24  */
    25 
    25 
    26 package java.lang.invoke;
    26 package java.lang.invoke;
    27 
    27 
       
    28 import jdk.internal.org.objectweb.asm.*;
       
    29 import sun.misc.Unsafe;
       
    30 
    28 import java.lang.reflect.Constructor;
    31 import java.lang.reflect.Constructor;
    29 import java.lang.reflect.Method;
    32 import java.security.AccessController;
       
    33 import java.security.PrivilegedAction;
    30 import java.security.ProtectionDomain;
    34 import java.security.ProtectionDomain;
    31 import java.util.concurrent.atomic.AtomicInteger;
    35 import java.util.concurrent.atomic.AtomicInteger;
    32 import jdk.internal.org.objectweb.asm.*;
    36 
    33 import static jdk.internal.org.objectweb.asm.Opcodes.*;
    37 import static jdk.internal.org.objectweb.asm.Opcodes.*;
    34 import sun.misc.Unsafe;
       
    35 import java.security.AccessController;
       
    36 import java.security.PrivilegedAction;
       
    37 
    38 
    38 /**
    39 /**
    39  * Lambda metafactory implementation which dynamically creates an inner-class-like class per lambda callsite.
    40  * Lambda metafactory implementation which dynamically creates an inner-class-like class per lambda callsite.
    40  *
    41  *
    41  * @see LambdaMetafactory
    42  * @see LambdaMetafactory
    42  */
    43  */
    43 /* package */ final class InnerClassLambdaMetafactory extends AbstractValidatingLambdaMetafactory {
    44 /* package */ final class InnerClassLambdaMetafactory extends AbstractValidatingLambdaMetafactory {
       
    45     private static final Unsafe UNSAFE = Unsafe.getUnsafe();
       
    46 
    44     private static final int CLASSFILE_VERSION = 51;
    47     private static final int CLASSFILE_VERSION = 51;
    45     private static final String METHOD_DESCRIPTOR_VOID = Type.getMethodDescriptor(Type.VOID_TYPE);
    48     private static final String METHOD_DESCRIPTOR_VOID = Type.getMethodDescriptor(Type.VOID_TYPE);
    46     private static final String NAME_MAGIC_ACCESSOR_IMPL = "java/lang/invoke/MagicLambdaImpl";
    49     private static final String NAME_MAGIC_ACCESSOR_IMPL = "java/lang/invoke/MagicLambdaImpl";
    47     private static final String NAME_CTOR = "<init>";
    50     private static final String NAME_CTOR = "<init>";
    48 
    51 
    75     private final String[] argNames;                 // Generated names for the constructor arguments
    78     private final String[] argNames;                 // Generated names for the constructor arguments
    76     private final String lambdaClassName;            // Generated name for the generated class "X$$Lambda$1"
    79     private final String lambdaClassName;            // Generated name for the generated class "X$$Lambda$1"
    77     private final Type[] instantiatedArgumentTypes;  // ASM types for the functional interface arguments
    80     private final Type[] instantiatedArgumentTypes;  // ASM types for the functional interface arguments
    78 
    81 
    79     /**
    82     /**
    80      * General meta-factory constructor, standard cases and allowing for uncommon options such as serialization.
    83      * General meta-factory constructor, supporting both standard cases and
       
    84      * allowing for uncommon options such as serialization or bridging.
    81      *
    85      *
    82      * @param caller Stacked automatically by VM; represents a lookup context with the accessibility privileges
    86      * @param caller Stacked automatically by VM; represents a lookup context
    83      *               of the caller.
    87      *               with the accessibility privileges of the caller.
    84      * @param invokedType Stacked automatically by VM; the signature of the invoked method, which includes the
    88      * @param invokedType Stacked automatically by VM; the signature of the
    85      *                    expected static type of the returned lambda object, and the static types of the captured
    89      *                    invoked method, which includes the expected static
    86      *                    arguments for the lambda.  In the event that the implementation method is an instance method,
    90      *                    type of the returned lambda object, and the static
    87      *                    the first argument in the invocation signature will correspond to the receiver.
    91      *                    types of the captured arguments for the lambda.  In
    88      * @param samMethod The primary method in the functional interface to which the lambda or method reference is
    92      *                    the event that the implementation method is an
    89      *                  being converted, represented as a method handle.
    93      *                    instance method, the first argument in the invocation
    90      * @param implMethod The implementation method which should be called (with suitable adaptation of argument
    94      *                    signature will correspond to the receiver.
    91      *                   types, return types, and adjustment for captured arguments) when methods of the resulting
    95      * @param samMethod The primary method in the functional interface to which
    92      *                   functional interface instance are invoked.
    96      *                  the lambda or method reference is being converted,
    93      * @param instantiatedMethodType The signature of the primary functional interface method after type variables
    97      *                  represented as a method handle.
    94      *                               are substituted with their instantiation from the capture site
    98      * @param implMethod The implementation method which should be called (with
    95      * @param flags A bitmask containing flags that may influence the translation of this lambda expression.  Defined
    99      *                   suitable adaptation of argument types, return types,
    96      *              fields include FLAG_SERIALIZABLE.
   100      *                   and adjustment for captured arguments) when methods of
    97      * @param markerInterfaces Additional interfaces which the lambda object should implement.
   101      *                   the resulting functional interface instance are invoked.
       
   102      * @param instantiatedMethodType The signature of the primary functional
       
   103      *                               interface method after type variables are
       
   104      *                               substituted with their instantiation from
       
   105      *                               the capture site
       
   106      * @param isSerializable Should the lambda be made serializable?  If set,
       
   107      *                       either the target type or one of the additional SAM
       
   108      *                       types must extend {@code Serializable}.
       
   109      * @param markerInterfaces Additional interfaces which the lambda object
       
   110      *                       should implement.
       
   111      * @param additionalBridges Method types for additional signatures to be
       
   112      *                          bridged to the implementation method
    98      * @throws ReflectiveOperationException
   113      * @throws ReflectiveOperationException
    99      * @throws LambdaConversionException If any of the meta-factory protocol invariants are violated
   114      * @throws LambdaConversionException If any of the meta-factory protocol
       
   115      * invariants are violated
   100      */
   116      */
   101     public InnerClassLambdaMetafactory(MethodHandles.Lookup caller,
   117     public InnerClassLambdaMetafactory(MethodHandles.Lookup caller,
   102                                        MethodType invokedType,
   118                                        MethodType invokedType,
   103                                        MethodHandle samMethod,
   119                                        MethodHandle samMethod,
   104                                        MethodHandle implMethod,
   120                                        MethodHandle implMethod,
   105                                        MethodType instantiatedMethodType,
   121                                        MethodType instantiatedMethodType,
   106                                        int flags,
   122                                        boolean isSerializable,
   107                                        Class<?>[] markerInterfaces)
   123                                        Class<?>[] markerInterfaces,
       
   124                                        MethodType[] additionalBridges)
   108             throws ReflectiveOperationException, LambdaConversionException {
   125             throws ReflectiveOperationException, LambdaConversionException {
   109         super(caller, invokedType, samMethod, implMethod, instantiatedMethodType, flags, markerInterfaces);
   126         super(caller, invokedType, samMethod, implMethod, instantiatedMethodType,
       
   127               isSerializable, markerInterfaces, additionalBridges);
   110         implMethodClassName = implDefiningClass.getName().replace('.', '/');
   128         implMethodClassName = implDefiningClass.getName().replace('.', '/');
   111         implMethodName = implInfo.getName();
   129         implMethodName = implInfo.getName();
   112         implMethodDesc = implMethodType.toMethodDescriptorString();
   130         implMethodDesc = implMethodType.toMethodDescriptorString();
   113         Type implMethodAsmType = Type.getMethodType(implMethodDesc);
   131         Type implMethodAsmType = Type.getMethodType(implMethodDesc);
   114         implMethodArgumentTypes = implMethodAsmType.getArgumentTypes();
   132         implMethodArgumentTypes = implMethodAsmType.getArgumentTypes();
   132      * which will call the class' constructor.
   150      * which will call the class' constructor.
   133      *
   151      *
   134      * @return a CallSite, which, when invoked, will return an instance of the
   152      * @return a CallSite, which, when invoked, will return an instance of the
   135      * functional interface
   153      * functional interface
   136      * @throws ReflectiveOperationException
   154      * @throws ReflectiveOperationException
   137      * @throws LambdaConversionException If properly formed functional interface is not found
   155      * @throws LambdaConversionException If properly formed functional interface
       
   156      * is not found
   138      */
   157      */
   139     @Override
   158     @Override
   140     CallSite buildCallSite() throws ReflectiveOperationException, LambdaConversionException {
   159     CallSite buildCallSite() throws ReflectiveOperationException, LambdaConversionException {
   141         final Class<?> innerClass = spinInnerClass();
   160         final Class<?> innerClass = spinInnerClass();
   142         if (invokedType.parameterCount() == 0) {
   161         if (invokedType.parameterCount() == 0) {
   172 
   191 
   173     /**
   192     /**
   174      * Generate a class file which implements the functional
   193      * Generate a class file which implements the functional
   175      * interface, define and return the class.
   194      * interface, define and return the class.
   176      *
   195      *
       
   196      * @implNote The class that is generated does not include signature
       
   197      * information for exceptions that may be present on the SAM method.
       
   198      * This is to reduce classfile size, and is harmless as checked exceptions
       
   199      * are erased anyway, no one will ever compile against this classfile,
       
   200      * and we make no guarantees about the reflective properties of lambda
       
   201      * objects.
       
   202      *
   177      * @return a Class which implements the functional interface
   203      * @return a Class which implements the functional interface
   178      * @throws LambdaConversionException If properly formed functional interface is not found
   204      * @throws LambdaConversionException If properly formed functional interface
       
   205      * is not found
   179      */
   206      */
   180     private Class<?> spinInnerClass() throws LambdaConversionException {
   207     private Class<?> spinInnerClass() throws LambdaConversionException {
   181         String samName = samBase.getName().replace('.', '/');
   208         String samName = samBase.getName().replace('.', '/');
   182         String[] interfaces = new String[markerInterfaces.length + 1];
   209         String[] interfaces = new String[markerInterfaces.length + 1];
   183         interfaces[0] = samName;
   210         interfaces[0] = samName;
   195             fv.visitEnd();
   222             fv.visitEnd();
   196         }
   223         }
   197 
   224 
   198         generateConstructor();
   225         generateConstructor();
   199 
   226 
   200         MethodAnalyzer ma = new MethodAnalyzer();
       
   201 
       
   202         // Forward the SAM method
   227         // Forward the SAM method
   203         if (ma.getSamMethod() == null) {
   228         String methodDescriptor = samMethodType.toMethodDescriptorString();
   204             throw new LambdaConversionException(String.format("Functional interface method not found: %s", samMethodType));
   229         MethodVisitor mv = cw.visitMethod(ACC_PUBLIC, samInfo.getName(), methodDescriptor, null, null);
   205         } else {
   230         new ForwardingMethodGenerator(mv).generate(methodDescriptor);
   206             generateForwardingMethod(ma.getSamMethod(), false);
       
   207         }
       
   208 
   231 
   209         // Forward the bridges
   232         // Forward the bridges
   210         // @@@ The commented-out code is temporary, pending the VM's ability to bridge all methods on request
   233         if (additionalBridges != null) {
   211         // @@@ Once the VM can do fail-over, uncomment the !ma.wasDefaultMethodFound() test, and emit the appropriate
   234             for (MethodType mt : additionalBridges) {
   212         // @@@ classfile attribute to request custom bridging.  See 8002092.
   235                 methodDescriptor = mt.toMethodDescriptorString();
   213         if (!ma.getMethodsToBridge().isEmpty() /* && !ma.conflictFoundBetweenDefaultAndBridge() */ ) {
   236                 mv = cw.visitMethod(ACC_PUBLIC|ACC_BRIDGE, samInfo.getName(), methodDescriptor, null, null);
   214             for (Method m : ma.getMethodsToBridge()) {
   237                 new ForwardingMethodGenerator(mv).generate(methodDescriptor);
   215                 generateForwardingMethod(m, true);
   238             }
   216             }
   239         }
   217         }
   240 
   218 
   241         if (isSerializable)
   219         if (isSerializable) {
       
   220             generateWriteReplace();
   242             generateWriteReplace();
   221         }
       
   222 
   243 
   223         cw.visitEnd();
   244         cw.visitEnd();
   224 
   245 
   225         // Define the generated class in this VM.
   246         // Define the generated class in this VM.
   226 
   247 
   245                     return targetClass.getProtectionDomain();
   266                     return targetClass.getProtectionDomain();
   246                 }
   267                 }
   247             }
   268             }
   248         );
   269         );
   249 
   270 
   250         return (Class<?>) Unsafe.getUnsafe().defineClass(lambdaClassName, classBytes, 0, classBytes.length,
   271         return UNSAFE.defineClass(lambdaClassName, classBytes, 0, classBytes.length,
   251                                                                    loader, pd);
   272                                   loader, pd);
   252     }
   273     }
   253 
   274 
   254     /**
   275     /**
   255      * Generate the constructor for the class
   276      * Generate the constructor for the class
   256      */
   277      */
   263         int lvIndex = 0;
   284         int lvIndex = 0;
   264         for (int i = 0; i < argTypes.length; i++) {
   285         for (int i = 0; i < argTypes.length; i++) {
   265             ctor.visitVarInsn(ALOAD, 0);
   286             ctor.visitVarInsn(ALOAD, 0);
   266             ctor.visitVarInsn(argTypes[i].getOpcode(ILOAD), lvIndex + 1);
   287             ctor.visitVarInsn(argTypes[i].getOpcode(ILOAD), lvIndex + 1);
   267             lvIndex += argTypes[i].getSize();
   288             lvIndex += argTypes[i].getSize();
   268             ctor.visitFieldInsn(PUTFIELD, lambdaClassName, argNames[i], argTypes[i].getDescriptor());
   289             ctor.visitFieldInsn(PUTFIELD, lambdaClassName, argNames[i],
       
   290                                 argTypes[i].getDescriptor());
   269         }
   291         }
   270         ctor.visitInsn(RETURN);
   292         ctor.visitInsn(RETURN);
   271         ctor.visitMaxs(-1, -1); // Maxs computed by ClassWriter.COMPUTE_MAXS, these arguments ignored
   293         ctor.visitMaxs(-1, -1); // Maxs computed by ClassWriter.COMPUTE_MAXS, these arguments ignored
   272         ctor.visitEnd();
   294         ctor.visitEnd();
   273     }
   295     }
   281                                                                  NAME_METHOD_WRITE_REPLACE, DESCR_METHOD_WRITE_REPLACE,
   303                                                                  NAME_METHOD_WRITE_REPLACE, DESCR_METHOD_WRITE_REPLACE,
   282                                                                  null, null));
   304                                                                  null, null));
   283 
   305 
   284         mv.visitCode();
   306         mv.visitCode();
   285         mv.visitTypeInsn(NEW, NAME_SERIALIZED_LAMBDA);
   307         mv.visitTypeInsn(NEW, NAME_SERIALIZED_LAMBDA);
   286         mv.visitInsn(DUP);;
   308         mv.visitInsn(DUP);
   287         mv.visitLdcInsn(Type.getType(targetClass));
   309         mv.visitLdcInsn(Type.getType(targetClass));
   288         mv.visitLdcInsn(samInfo.getReferenceKind());
   310         mv.visitLdcInsn(samInfo.getReferenceKind());
   289         mv.visitLdcInsn(invokedType.returnType().getName().replace('.', '/'));
   311         mv.visitLdcInsn(invokedType.returnType().getName().replace('.', '/'));
   290         mv.visitLdcInsn(samInfo.getName());
   312         mv.visitLdcInsn(samInfo.getName());
   291         mv.visitLdcInsn(samInfo.getMethodType().toMethodDescriptorString());
   313         mv.visitLdcInsn(samInfo.getMethodType().toMethodDescriptorString());
   311         mv.visitMaxs(-1, -1); // Maxs computed by ClassWriter.COMPUTE_MAXS, these arguments ignored
   333         mv.visitMaxs(-1, -1); // Maxs computed by ClassWriter.COMPUTE_MAXS, these arguments ignored
   312         mv.visitEnd();
   334         mv.visitEnd();
   313     }
   335     }
   314 
   336 
   315     /**
   337     /**
   316      * Generate a method which calls the lambda implementation method,
       
   317      * converting arguments, as needed.
       
   318      * @param m The method whose signature should be generated
       
   319      * @param isBridge True if this methods should be flagged as a bridge
       
   320      */
       
   321     private void generateForwardingMethod(Method m, boolean isBridge) {
       
   322         Class<?>[] exceptionTypes = m.getExceptionTypes();
       
   323         String[] exceptionNames = new String[exceptionTypes.length];
       
   324         for (int i = 0; i < exceptionTypes.length; i++) {
       
   325             exceptionNames[i] = exceptionTypes[i].getName().replace('.', '/');
       
   326         }
       
   327         String methodDescriptor = Type.getMethodDescriptor(m);
       
   328         int access = isBridge? ACC_PUBLIC | ACC_BRIDGE : ACC_PUBLIC;
       
   329         MethodVisitor mv = cw.visitMethod(access, m.getName(), methodDescriptor, null, exceptionNames);
       
   330         new ForwardingMethodGenerator(mv).generate(m);
       
   331     }
       
   332 
       
   333     /**
       
   334      * This class generates a method body which calls the lambda implementation
   338      * This class generates a method body which calls the lambda implementation
   335      * method, converting arguments, as needed.
   339      * method, converting arguments, as needed.
   336      */
   340      */
   337     private class ForwardingMethodGenerator extends TypeConvertingMethodAdapter {
   341     private class ForwardingMethodGenerator extends TypeConvertingMethodAdapter {
   338 
   342 
   339         ForwardingMethodGenerator(MethodVisitor mv) {
   343         ForwardingMethodGenerator(MethodVisitor mv) {
   340             super(mv);
   344             super(mv);
   341         }
   345         }
   342 
   346 
   343         void generate(Method m) throws InternalError {
   347         void generate(String methodDescriptor) {
   344             visitCode();
   348             visitCode();
   345 
   349 
   346             if (implKind == MethodHandleInfo.REF_newInvokeSpecial) {
   350             if (implKind == MethodHandleInfo.REF_newInvokeSpecial) {
   347                 visitTypeInsn(NEW, implMethodClassName);
   351                 visitTypeInsn(NEW, implMethodClassName);
   348                 visitInsn(DUP);;
   352                 visitInsn(DUP);
   349             }
   353             }
   350             for (int i = 0; i < argTypes.length; i++) {
   354             for (int i = 0; i < argTypes.length; i++) {
   351                 visitVarInsn(ALOAD, 0);
   355                 visitVarInsn(ALOAD, 0);
   352                 visitFieldInsn(GETFIELD, lambdaClassName, argNames[i], argTypes[i].getDescriptor());
   356                 visitFieldInsn(GETFIELD, lambdaClassName, argNames[i], argTypes[i].getDescriptor());
   353             }
   357             }
   354 
   358 
   355             convertArgumentTypes(Type.getArgumentTypes(m));
   359             convertArgumentTypes(Type.getArgumentTypes(methodDescriptor));
   356 
   360 
   357             // Invoke the method we want to forward to
   361             // Invoke the method we want to forward to
   358             visitMethodInsn(invocationOpcode(), implMethodClassName, implMethodName, implMethodDesc);
   362             visitMethodInsn(invocationOpcode(), implMethodClassName, implMethodName, implMethodDesc);
   359 
   363 
   360             // Convert the return value (if any) and return it
   364             // Convert the return value (if any) and return it
   361             // Note: if adapting from non-void to void, the 'return' instruction will pop the unneeded result
   365             // Note: if adapting from non-void to void, the 'return' instruction will pop the unneeded result
   362             Type samReturnType = Type.getReturnType(m);
   366             Type samReturnType = Type.getReturnType(methodDescriptor);
   363             convertType(implMethodReturnType, samReturnType, samReturnType);
   367             convertType(implMethodReturnType, samReturnType, samReturnType);
   364             visitInsn(samReturnType.getOpcode(Opcodes.IRETURN));
   368             visitInsn(samReturnType.getOpcode(Opcodes.IRETURN));
   365 
   369 
   366             visitMaxs(-1, -1); // Maxs computed by ClassWriter.COMPUTE_MAXS, these arguments ignored
   370             visitMaxs(-1, -1); // Maxs computed by ClassWriter.COMPUTE_MAXS, these arguments ignored
   367             visitEnd();
   371             visitEnd();