src/share/classes/java/lang/invoke/InnerClassLambdaMetafactory.java

Print this page




   8  * particular file as subject to the "Classpath" exception as provided
   9  * by Oracle in the LICENSE file that accompanied this code.
  10  *
  11  * This code is distributed in the hope that it will be useful, but WITHOUT
  12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  14  * version 2 for more details (a copy is included in the LICENSE file that
  15  * accompanied this code).
  16  *
  17  * You should have received a copy of the GNU General Public License version
  18  * 2 along with this work; if not, write to the Free Software Foundation,
  19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  20  *
  21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  22  * or visit www.oracle.com if you need additional information or have any
  23  * questions.
  24  */
  25 
  26 package java.lang.invoke;
  27 




  28 import jdk.internal.org.objectweb.asm.*;

  29 import sun.misc.Unsafe;
  30 
  31 import java.lang.reflect.Constructor;
  32 import java.security.AccessController;
  33 import java.security.PrivilegedAction;
  34 import java.security.ProtectionDomain;
  35 import java.util.concurrent.atomic.AtomicInteger;
  36 
  37 import static jdk.internal.org.objectweb.asm.Opcodes.*;
  38 
  39 /**
  40  * Lambda metafactory implementation which dynamically creates an inner-class-like class per lambda callsite.
  41  *
  42  * @see LambdaMetafactory
  43  */
  44 /* package */ final class InnerClassLambdaMetafactory extends AbstractValidatingLambdaMetafactory {
  45     private static final Unsafe UNSAFE = Unsafe.getUnsafe();
  46 
  47     private static final int CLASSFILE_VERSION = 51;
  48     private static final String METHOD_DESCRIPTOR_VOID = Type.getMethodDescriptor(Type.VOID_TYPE);
  49     private static final String NAME_MAGIC_ACCESSOR_IMPL = "java/lang/invoke/MagicLambdaImpl";
  50     private static final String NAME_CTOR = "<init>";
  51 
  52     //Serialization support
  53     private static final String NAME_SERIALIZED_LAMBDA = "java/lang/invoke/SerializedLambda";
  54     private static final String DESCR_METHOD_WRITE_REPLACE = "()Ljava/lang/Object;";
  55     private static final String NAME_METHOD_WRITE_REPLACE = "writeReplace";
  56     private static final String NAME_OBJECT = "java/lang/Object";
  57     private static final String DESCR_CTOR_SERIALIZED_LAMBDA
  58             = MethodType.methodType(void.class,
  59                                     Class.class,
  60                                     int.class, String.class, String.class, String.class,
  61                                     int.class, String.class, String.class, String.class,
  62                                     String.class,
  63                                     Object[].class).toMethodDescriptorString();
  64 
  65     // Used to ensure that each spun class name is unique
  66     private static final AtomicInteger counter = new AtomicInteger(0);
  67 
  68     // See context values in AbstractValidatingLambdaMetafactory
  69     private final String implMethodClassName;        // Name of type containing implementation "CC"
  70     private final String implMethodName;             // Name of implementation method "impl"
  71     private final String implMethodDesc;             // Type descriptor for implementation methods "(I)Ljava/lang/String;"
  72     private final Type[] implMethodArgumentTypes;    // ASM types for implementaion method parameters
  73     private final Type implMethodReturnType;         // ASM type for implementaion method return type "Ljava/lang/String;"
  74     private final MethodType constructorType;        // Generated class constructor type "(CC)void"
  75     private final String constructorDesc;            // Type descriptor for constructor "(LCC;)V"
  76     private final ClassWriter cw;                    // ASM class writer
  77     private final Type[] argTypes;                   // ASM types for the constructor arguments
  78     private final String[] argNames;                 // Generated names for the constructor arguments
  79     private final String lambdaClassName;            // Generated name for the generated class "X$$Lambda$1"
  80     private final Type[] instantiatedArgumentTypes;  // ASM types for the functional interface arguments
  81 
  82     /**
  83      * General meta-factory constructor, supporting both standard cases and
  84      * allowing for uncommon options such as serialization or bridging.
  85      *
  86      * @param caller Stacked automatically by VM; represents a lookup context
  87      *               with the accessibility privileges of the caller.
  88      * @param invokedType Stacked automatically by VM; the signature of the
  89      *                    invoked method, which includes the expected static
  90      *                    type of the returned lambda object, and the static
  91      *                    types of the captured arguments for the lambda.  In
  92      *                    the event that the implementation method is an
  93      *                    instance method, the first argument in the invocation
  94      *                    signature will correspond to the receiver.
  95      * @param samMethod The primary method in the functional interface to which
  96      *                  the lambda or method reference is being converted,
  97      *                  represented as a method handle.
  98      * @param implMethod The implementation method which should be called (with
  99      *                   suitable adaptation of argument types, return types,
 100      *                   and adjustment for captured arguments) when methods of
 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
 113      * @throws ReflectiveOperationException
 114      * @throws LambdaConversionException If any of the meta-factory protocol
 115      * invariants are violated
 116      */
 117     public InnerClassLambdaMetafactory(MethodHandles.Lookup caller,
 118                                        MethodType invokedType,
 119                                        MethodHandle samMethod,
 120                                        MethodHandle implMethod,
 121                                        MethodType instantiatedMethodType,
 122                                        boolean isSerializable,
 123                                        Class<?>[] markerInterfaces,
 124                                        MethodType[] additionalBridges)
 125             throws ReflectiveOperationException, LambdaConversionException {
 126         super(caller, invokedType, samMethod, implMethod, instantiatedMethodType,
 127               isSerializable, markerInterfaces, additionalBridges);
 128         implMethodClassName = implDefiningClass.getName().replace('.', '/');
 129         implMethodName = implInfo.getName();
 130         implMethodDesc = implMethodType.toMethodDescriptorString();
 131         Type implMethodAsmType = Type.getMethodType(implMethodDesc);
 132         implMethodArgumentTypes = implMethodAsmType.getArgumentTypes();
 133         implMethodReturnType = implMethodAsmType.getReturnType();
 134         constructorType = invokedType.changeReturnType(Void.TYPE);
 135         constructorDesc = constructorType.toMethodDescriptorString();
 136         lambdaClassName = targetClass.getName().replace('.', '/') + "$$Lambda$" + counter.incrementAndGet();
 137         cw = new ClassWriter(ClassWriter.COMPUTE_MAXS);
 138         argTypes = Type.getArgumentTypes(constructorDesc);
 139         argNames = new String[argTypes.length];
 140         for (int i = 0; i < argTypes.length; i++) {
 141             argNames[i] = "arg$" + (i + 1);
 142         }
 143         instantiatedArgumentTypes = Type.getArgumentTypes(instantiatedMethodType.toMethodDescriptorString());
 144     }
 145 
 146     /**
 147      * Build the CallSite. Generate a class file which implements the functional
 148      * interface, define the class, if there are no parameters create an instance
 149      * of the class which the CallSite will return, otherwise, generate handles
 150      * which will call the class' constructor.
 151      *
 152      * @return a CallSite, which, when invoked, will return an instance of the
 153      * functional interface
 154      * @throws ReflectiveOperationException
 155      * @throws LambdaConversionException If properly formed functional interface
 156      * is not found
 157      */
 158     @Override
 159     CallSite buildCallSite() throws ReflectiveOperationException, LambdaConversionException {
 160         final Class<?> innerClass = spinInnerClass();
 161         if (invokedType.parameterCount() == 0) {
 162             final Constructor[] ctrs = AccessController.doPrivileged(
 163                     new PrivilegedAction<Constructor[]>() {
 164                 @Override
 165                 public Constructor[] run() {
 166                     return innerClass.getDeclaredConstructors();
 167                 }
 168             });
 169             if (ctrs.length != 1) {
 170                 throw new ReflectiveOperationException("Expected one lambda constructor for "
 171                         + innerClass.getCanonicalName() + ", got " + ctrs.length);
 172             }
 173             // The lambda implementing inner class constructor is private, set
 174             // it accessible (by us) before creating the constant sole instance
 175             AccessController.doPrivileged(new PrivilegedAction<Void>() {
 176                 @Override
 177                 public Void run() {
 178                     ctrs[0].setAccessible(true);
 179                     return null;
 180                 }
 181             });
 182             Object inst = ctrs[0].newInstance();
 183             return new ConstantCallSite(MethodHandles.constant(samBase, inst));
 184         } else {
 185             return new ConstantCallSite(
 186                     MethodHandles.Lookup.IMPL_LOOKUP
 187                                         .findConstructor(innerClass, constructorType)
 188                                         .asType(constructorType.changeReturnType(samBase)));
 189         }
 190     }
 191 
 192     /**
 193      * Generate a class file which implements the functional
 194      * interface, define and return the class.
 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      *
 203      * @return a Class which implements the functional interface
 204      * @throws LambdaConversionException If properly formed functional interface
 205      * is not found
 206      */
 207     private Class<?> spinInnerClass() throws LambdaConversionException {
 208         String samName = samBase.getName().replace('.', '/');
 209         String[] interfaces = new String[markerInterfaces.length + 1];
 210         interfaces[0] = samName;
 211         for (int i=0; i<markerInterfaces.length; i++) {
 212             interfaces[i+1] = markerInterfaces[i].getName().replace('.', '/');
 213         }
 214         cw.visit(CLASSFILE_VERSION, ACC_SUPER + ACC_FINAL + ACC_SYNTHETIC,
 215                  lambdaClassName, null,
 216                  NAME_MAGIC_ACCESSOR_IMPL, interfaces);
 217 
 218         // Generate final fields to be filled in by constructor
 219         for (int i = 0; i < argTypes.length; i++) {
 220             FieldVisitor fv = cw.visitField(ACC_PRIVATE + ACC_FINAL, argNames[i], argTypes[i].getDescriptor(),
 221                                             null, null);
 222             fv.visitEnd();
 223         }
 224 
 225         generateConstructor();
 226 


 227         // Forward the SAM method
 228         String methodDescriptor = samMethodType.toMethodDescriptorString();
 229         MethodVisitor mv = cw.visitMethod(ACC_PUBLIC, samInfo.getName(), methodDescriptor, null, null);
 230         new ForwardingMethodGenerator(mv).generate(methodDescriptor);


 231 
 232         // Forward the bridges
 233         if (additionalBridges != null) {
 234             for (MethodType mt : additionalBridges) {
 235                 methodDescriptor = mt.toMethodDescriptorString();
 236                 mv = cw.visitMethod(ACC_PUBLIC|ACC_BRIDGE, samInfo.getName(), methodDescriptor, null, null);
 237                 new ForwardingMethodGenerator(mv).generate(methodDescriptor);

 238             }
 239         }
 240 
 241         if (isSerializable)
 242             generateWriteReplace();

 243 
 244         cw.visitEnd();
 245 
 246         // Define the generated class in this VM.
 247 
 248         final byte[] classBytes = cw.toByteArray();
 249 
 250         /*** Uncomment to dump the generated file
 251             System.out.printf("Loaded: %s (%d bytes) %n", lambdaClassName, classBytes.length);
 252             try (FileOutputStream fos = new FileOutputStream(lambdaClassName.replace('/', '.') + ".class")) {
 253                 fos.write(classBytes);
 254             } catch (IOException ex) {
 255                 PlatformLogger.getLogger(InnerClassLambdaMetafactory.class.getName()).severe(ex.getMessage(), ex);
 256             }
 257         ***/
 258 
 259         ClassLoader loader = targetClass.getClassLoader();
 260         ProtectionDomain pd = (loader == null)
 261             ? null
 262             : AccessController.doPrivileged(
 263             new PrivilegedAction<ProtectionDomain>() {
 264                 @Override
 265                 public ProtectionDomain run() {
 266                     return targetClass.getProtectionDomain();
 267                 }
 268             }
 269         );
 270 
 271         return UNSAFE.defineClass(lambdaClassName, classBytes, 0, classBytes.length,
 272                                   loader, pd);
 273     }
 274 
 275     /**
 276      * Generate the constructor for the class
 277      */
 278     private void generateConstructor() {
 279         // Generate constructor
 280         MethodVisitor ctor = cw.visitMethod(ACC_PRIVATE, NAME_CTOR, constructorDesc, null, null);
 281         ctor.visitCode();
 282         ctor.visitVarInsn(ALOAD, 0);
 283         ctor.visitMethodInsn(INVOKESPECIAL, NAME_MAGIC_ACCESSOR_IMPL, NAME_CTOR, METHOD_DESCRIPTOR_VOID);
 284         int lvIndex = 0;
 285         for (int i = 0; i < argTypes.length; i++) {
 286             ctor.visitVarInsn(ALOAD, 0);
 287             ctor.visitVarInsn(argTypes[i].getOpcode(ILOAD), lvIndex + 1);
 288             lvIndex += argTypes[i].getSize();
 289             ctor.visitFieldInsn(PUTFIELD, lambdaClassName, argNames[i],
 290                                 argTypes[i].getDescriptor());
 291         }
 292         ctor.visitInsn(RETURN);
 293         ctor.visitMaxs(-1, -1); // Maxs computed by ClassWriter.COMPUTE_MAXS, these arguments ignored
 294         ctor.visitEnd();
 295     }
 296 
 297     /**
 298      * Generate the writeReplace method (if needed for serialization)
 299      */
 300     private void generateWriteReplace() {
 301         TypeConvertingMethodAdapter mv
 302                 = new TypeConvertingMethodAdapter(cw.visitMethod(ACC_PRIVATE + ACC_FINAL,
 303                                                                  NAME_METHOD_WRITE_REPLACE, DESCR_METHOD_WRITE_REPLACE,
 304                                                                  null, null));
 305 
 306         mv.visitCode();
 307         mv.visitTypeInsn(NEW, NAME_SERIALIZED_LAMBDA);
 308         mv.visitInsn(DUP);
 309         mv.visitLdcInsn(Type.getType(targetClass));
 310         mv.visitLdcInsn(samInfo.getReferenceKind());
 311         mv.visitLdcInsn(invokedType.returnType().getName().replace('.', '/'));
 312         mv.visitLdcInsn(samInfo.getName());
 313         mv.visitLdcInsn(samInfo.getMethodType().toMethodDescriptorString());
 314         mv.visitLdcInsn(implInfo.getReferenceKind());
 315         mv.visitLdcInsn(implInfo.getDeclaringClass().getName().replace('.', '/'));
 316         mv.visitLdcInsn(implInfo.getName());
 317         mv.visitLdcInsn(implInfo.getMethodType().toMethodDescriptorString());
 318         mv.visitLdcInsn(instantiatedMethodType.toMethodDescriptorString());
 319 
 320         mv.iconst(argTypes.length);
 321         mv.visitTypeInsn(ANEWARRAY, NAME_OBJECT);
 322         for (int i = 0; i < argTypes.length; i++) {
 323             mv.visitInsn(DUP);
 324             mv.iconst(i);
 325             mv.visitVarInsn(ALOAD, 0);
 326             mv.visitFieldInsn(GETFIELD, lambdaClassName, argNames[i], argTypes[i].getDescriptor());
 327             mv.boxIfTypePrimitive(argTypes[i]);
 328             mv.visitInsn(AASTORE);
 329         }
 330         mv.visitMethodInsn(INVOKESPECIAL, NAME_SERIALIZED_LAMBDA, NAME_CTOR,
 331                 DESCR_CTOR_SERIALIZED_LAMBDA);
 332         mv.visitInsn(ARETURN);
 333         mv.visitMaxs(-1, -1); // Maxs computed by ClassWriter.COMPUTE_MAXS, these arguments ignored
 334         mv.visitEnd();
 335     }
 336 
 337     /**


















 338      * This class generates a method body which calls the lambda implementation
 339      * method, converting arguments, as needed.
 340      */
 341     private class ForwardingMethodGenerator extends TypeConvertingMethodAdapter {
 342 
 343         ForwardingMethodGenerator(MethodVisitor mv) {
 344             super(mv);
 345         }
 346 
 347         void generate(String methodDescriptor) {
 348             visitCode();
 349 
 350             if (implKind == MethodHandleInfo.REF_newInvokeSpecial) {
 351                 visitTypeInsn(NEW, implMethodClassName);
 352                 visitInsn(DUP);
 353             }
 354             for (int i = 0; i < argTypes.length; i++) {
 355                 visitVarInsn(ALOAD, 0);
 356                 visitFieldInsn(GETFIELD, lambdaClassName, argNames[i], argTypes[i].getDescriptor());
 357             }
 358 
 359             convertArgumentTypes(Type.getArgumentTypes(methodDescriptor));
 360 
 361             // Invoke the method we want to forward to
 362             visitMethodInsn(invocationOpcode(), implMethodClassName, implMethodName, implMethodDesc);
 363 
 364             // Convert the return value (if any) and return it
 365             // Note: if adapting from non-void to void, the 'return' instruction will pop the unneeded result
 366             Type samReturnType = Type.getReturnType(methodDescriptor);
 367             convertType(implMethodReturnType, samReturnType, samReturnType);
 368             visitInsn(samReturnType.getOpcode(Opcodes.IRETURN));
 369 
 370             visitMaxs(-1, -1); // Maxs computed by ClassWriter.COMPUTE_MAXS, these arguments ignored
 371             visitEnd();
 372         }
 373 
 374         private void convertArgumentTypes(Type[] samArgumentTypes) {
 375             int lvIndex = 0;
 376             boolean samIncludesReceiver = implIsInstanceMethod && argTypes.length == 0;
 377             int samReceiverLength = samIncludesReceiver ? 1 : 0;
 378             if (samIncludesReceiver) {
 379                 // push receiver
 380                 Type rcvrType = samArgumentTypes[0];
 381                 Type instantiatedRcvrType = instantiatedArgumentTypes[0];
 382 
 383                 visitVarInsn(rcvrType.getOpcode(ILOAD), lvIndex + 1);
 384                 lvIndex += rcvrType.getSize();
 385                 convertType(rcvrType, Type.getType(implDefiningClass), instantiatedRcvrType);
 386             }




   8  * particular file as subject to the "Classpath" exception as provided
   9  * by Oracle in the LICENSE file that accompanied this code.
  10  *
  11  * This code is distributed in the hope that it will be useful, but WITHOUT
  12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  14  * version 2 for more details (a copy is included in the LICENSE file that
  15  * accompanied this code).
  16  *
  17  * You should have received a copy of the GNU General Public License version
  18  * 2 along with this work; if not, write to the Free Software Foundation,
  19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  20  *
  21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  22  * or visit www.oracle.com if you need additional information or have any
  23  * questions.
  24  */
  25 
  26 package java.lang.invoke;
  27 
  28 import java.lang.reflect.Constructor;
  29 import java.lang.reflect.Method;
  30 import java.security.ProtectionDomain;
  31 import java.util.concurrent.atomic.AtomicInteger;
  32 import jdk.internal.org.objectweb.asm.*;
  33 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 /**
  39  * Lambda metafactory implementation which dynamically creates an inner-class-like class per lambda callsite.
  40  *
  41  * @see LambdaMetafactory
  42  */
  43 /* package */ final class InnerClassLambdaMetafactory extends AbstractValidatingLambdaMetafactory {


  44     private static final int CLASSFILE_VERSION = 51;
  45     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";
  47     private static final String NAME_CTOR = "<init>";
  48 
  49     //Serialization support
  50     private static final String NAME_SERIALIZED_LAMBDA = "java/lang/invoke/SerializedLambda";
  51     private static final String DESCR_METHOD_WRITE_REPLACE = "()Ljava/lang/Object;";
  52     private static final String NAME_METHOD_WRITE_REPLACE = "writeReplace";
  53     private static final String NAME_OBJECT = "java/lang/Object";
  54     private static final String DESCR_CTOR_SERIALIZED_LAMBDA
  55             = MethodType.methodType(void.class,
  56                                     Class.class,
  57                                     int.class, String.class, String.class, String.class,
  58                                     int.class, String.class, String.class, String.class,
  59                                     String.class,
  60                                     Object[].class).toMethodDescriptorString();
  61 
  62     // Used to ensure that each spun class name is unique
  63     private static final AtomicInteger counter = new AtomicInteger(0);
  64 
  65     // See context values in AbstractValidatingLambdaMetafactory
  66     private final String implMethodClassName;        // Name of type containing implementation "CC"
  67     private final String implMethodName;             // Name of implementation method "impl"
  68     private final String implMethodDesc;             // Type descriptor for implementation methods "(I)Ljava/lang/String;"
  69     private final Type[] implMethodArgumentTypes;    // ASM types for implementaion method parameters
  70     private final Type implMethodReturnType;         // ASM type for implementaion method return type "Ljava/lang/String;"
  71     private final MethodType constructorType;        // Generated class constructor type "(CC)void"
  72     private final String constructorDesc;            // Type descriptor for constructor "(LCC;)V"
  73     private final ClassWriter cw;                    // ASM class writer
  74     private final Type[] argTypes;                   // ASM types for the constructor arguments
  75     private final String[] argNames;                 // Generated names for the constructor arguments
  76     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
  78 
  79     /**
  80      * General meta-factory constructor, standard cases and allowing for uncommon options such as serialization.

  81      *
  82      * @param caller Stacked automatically by VM; represents a lookup context with the accessibility privileges
  83      *               of the caller.
  84      * @param invokedType Stacked automatically by VM; the signature of the invoked method, which includes the
  85      *                    expected static type of the returned lambda object, and the static types of the captured
  86      *                    arguments for the lambda.  In the event that the implementation method is an instance method,
  87      *                    the first argument in the invocation signature will correspond to the receiver.
  88      * @param samMethod The primary method in the functional interface to which the lambda or method reference is
  89      *                  being converted, represented as a method handle.
  90      * @param implMethod The implementation method which should be called (with suitable adaptation of argument
  91      *                   types, return types, and adjustment for captured arguments) when methods of the resulting
  92      *                   functional interface instance are invoked.
  93      * @param instantiatedMethodType The signature of the primary functional interface method after type variables
  94      *                               are substituted with their instantiation from the capture site
  95      * @param flags A bitmask containing flags that may influence the translation of this lambda expression.  Defined
  96      *              fields include FLAG_SERIALIZABLE.
  97      * @param markerInterfaces Additional interfaces which the lambda object should implement.











  98      * @throws ReflectiveOperationException
  99      * @throws LambdaConversionException If any of the meta-factory protocol invariants are violated

 100      */
 101     public InnerClassLambdaMetafactory(MethodHandles.Lookup caller,
 102                                        MethodType invokedType,
 103                                        MethodHandle samMethod,
 104                                        MethodHandle implMethod,
 105                                        MethodType instantiatedMethodType,
 106                                        int flags,
 107                                        Class<?>[] markerInterfaces)

 108             throws ReflectiveOperationException, LambdaConversionException {
 109         super(caller, invokedType, samMethod, implMethod, instantiatedMethodType, flags, markerInterfaces);

 110         implMethodClassName = implDefiningClass.getName().replace('.', '/');
 111         implMethodName = implInfo.getName();
 112         implMethodDesc = implMethodType.toMethodDescriptorString();
 113         Type implMethodAsmType = Type.getMethodType(implMethodDesc);
 114         implMethodArgumentTypes = implMethodAsmType.getArgumentTypes();
 115         implMethodReturnType = implMethodAsmType.getReturnType();
 116         constructorType = invokedType.changeReturnType(Void.TYPE);
 117         constructorDesc = constructorType.toMethodDescriptorString();
 118         lambdaClassName = targetClass.getName().replace('.', '/') + "$$Lambda$" + counter.incrementAndGet();
 119         cw = new ClassWriter(ClassWriter.COMPUTE_MAXS);
 120         argTypes = Type.getArgumentTypes(constructorDesc);
 121         argNames = new String[argTypes.length];
 122         for (int i = 0; i < argTypes.length; i++) {
 123             argNames[i] = "arg$" + (i + 1);
 124         }
 125         instantiatedArgumentTypes = Type.getArgumentTypes(instantiatedMethodType.toMethodDescriptorString());
 126     }
 127 
 128     /**
 129      * Build the CallSite. Generate a class file which implements the functional
 130      * interface, define the class, if there are no parameters create an instance
 131      * of the class which the CallSite will return, otherwise, generate handles
 132      * which will call the class' constructor.
 133      *
 134      * @return a CallSite, which, when invoked, will return an instance of the
 135      * functional interface
 136      * @throws ReflectiveOperationException
 137      * @throws LambdaConversionException If properly formed functional interface is not found

 138      */
 139     @Override
 140     CallSite buildCallSite() throws ReflectiveOperationException, LambdaConversionException {
 141         final Class<?> innerClass = spinInnerClass();
 142         if (invokedType.parameterCount() == 0) {
 143             final Constructor[] ctrs = AccessController.doPrivileged(
 144                     new PrivilegedAction<Constructor[]>() {
 145                 @Override
 146                 public Constructor[] run() {
 147                     return innerClass.getDeclaredConstructors();
 148                 }
 149             });
 150             if (ctrs.length != 1) {
 151                 throw new ReflectiveOperationException("Expected one lambda constructor for "
 152                         + innerClass.getCanonicalName() + ", got " + ctrs.length);
 153             }
 154             // The lambda implementing inner class constructor is private, set
 155             // it accessible (by us) before creating the constant sole instance
 156             AccessController.doPrivileged(new PrivilegedAction<Void>() {
 157                 @Override
 158                 public Void run() {
 159                     ctrs[0].setAccessible(true);
 160                     return null;
 161                 }
 162             });
 163             Object inst = ctrs[0].newInstance();
 164             return new ConstantCallSite(MethodHandles.constant(samBase, inst));
 165         } else {
 166             return new ConstantCallSite(
 167                     MethodHandles.Lookup.IMPL_LOOKUP
 168                                         .findConstructor(innerClass, constructorType)
 169                                         .asType(constructorType.changeReturnType(samBase)));
 170         }
 171     }
 172 
 173     /**
 174      * Generate a class file which implements the functional
 175      * interface, define and return the class.
 176      *







 177      * @return a Class which implements the functional interface
 178      * @throws LambdaConversionException If properly formed functional interface is not found

 179      */
 180     private Class<?> spinInnerClass() throws LambdaConversionException {
 181         String samName = samBase.getName().replace('.', '/');
 182         String[] interfaces = new String[markerInterfaces.length + 1];
 183         interfaces[0] = samName;
 184         for (int i=0; i<markerInterfaces.length; i++) {
 185             interfaces[i+1] = markerInterfaces[i].getName().replace('.', '/');
 186         }
 187         cw.visit(CLASSFILE_VERSION, ACC_SUPER + ACC_FINAL + ACC_SYNTHETIC,
 188                  lambdaClassName, null,
 189                  NAME_MAGIC_ACCESSOR_IMPL, interfaces);
 190 
 191         // Generate final fields to be filled in by constructor
 192         for (int i = 0; i < argTypes.length; i++) {
 193             FieldVisitor fv = cw.visitField(ACC_PRIVATE + ACC_FINAL, argNames[i], argTypes[i].getDescriptor(),
 194                                             null, null);
 195             fv.visitEnd();
 196         }
 197 
 198         generateConstructor();
 199 
 200         MethodAnalyzer ma = new MethodAnalyzer();
 201 
 202         // Forward the SAM method
 203         if (ma.getSamMethod() == null) {
 204             throw new LambdaConversionException(String.format("Functional interface method not found: %s", samMethodType));
 205         } else {
 206             generateForwardingMethod(ma.getSamMethod(), false);
 207         }
 208 
 209         // Forward the bridges
 210         // @@@ The commented-out code is temporary, pending the VM's ability to bridge all methods on request
 211         // @@@ Once the VM can do fail-over, uncomment the !ma.wasDefaultMethodFound() test, and emit the appropriate
 212         // @@@ classfile attribute to request custom bridging.  See 8002092.
 213         if (!ma.getMethodsToBridge().isEmpty() /* && !ma.conflictFoundBetweenDefaultAndBridge() */ ) {
 214             for (Method m : ma.getMethodsToBridge()) {
 215                 generateForwardingMethod(m, true);
 216             }
 217         }
 218 
 219         if (isSerializable) {
 220             generateWriteReplace();
 221         }
 222 
 223         cw.visitEnd();
 224 
 225         // Define the generated class in this VM.
 226 
 227         final byte[] classBytes = cw.toByteArray();
 228 
 229         /*** Uncomment to dump the generated file
 230             System.out.printf("Loaded: %s (%d bytes) %n", lambdaClassName, classBytes.length);
 231             try (FileOutputStream fos = new FileOutputStream(lambdaClassName.replace('/', '.') + ".class")) {
 232                 fos.write(classBytes);
 233             } catch (IOException ex) {
 234                 PlatformLogger.getLogger(InnerClassLambdaMetafactory.class.getName()).severe(ex.getMessage(), ex);
 235             }
 236         ***/
 237 
 238         ClassLoader loader = targetClass.getClassLoader();
 239         ProtectionDomain pd = (loader == null)
 240             ? null
 241             : AccessController.doPrivileged(
 242             new PrivilegedAction<ProtectionDomain>() {
 243                 @Override
 244                 public ProtectionDomain run() {
 245                     return targetClass.getProtectionDomain();
 246                 }
 247             }
 248         );
 249 
 250         return (Class<?>) Unsafe.getUnsafe().defineClass(lambdaClassName, classBytes, 0, classBytes.length,
 251                                                                    loader, pd);
 252     }
 253 
 254     /**
 255      * Generate the constructor for the class
 256      */
 257     private void generateConstructor() {
 258         // Generate constructor
 259         MethodVisitor ctor = cw.visitMethod(ACC_PRIVATE, NAME_CTOR, constructorDesc, null, null);
 260         ctor.visitCode();
 261         ctor.visitVarInsn(ALOAD, 0);
 262         ctor.visitMethodInsn(INVOKESPECIAL, NAME_MAGIC_ACCESSOR_IMPL, NAME_CTOR, METHOD_DESCRIPTOR_VOID);
 263         int lvIndex = 0;
 264         for (int i = 0; i < argTypes.length; i++) {
 265             ctor.visitVarInsn(ALOAD, 0);
 266             ctor.visitVarInsn(argTypes[i].getOpcode(ILOAD), lvIndex + 1);
 267             lvIndex += argTypes[i].getSize();
 268             ctor.visitFieldInsn(PUTFIELD, lambdaClassName, argNames[i], argTypes[i].getDescriptor());

 269         }
 270         ctor.visitInsn(RETURN);
 271         ctor.visitMaxs(-1, -1); // Maxs computed by ClassWriter.COMPUTE_MAXS, these arguments ignored
 272         ctor.visitEnd();
 273     }
 274 
 275     /**
 276      * Generate the writeReplace method (if needed for serialization)
 277      */
 278     private void generateWriteReplace() {
 279         TypeConvertingMethodAdapter mv
 280                 = new TypeConvertingMethodAdapter(cw.visitMethod(ACC_PRIVATE + ACC_FINAL,
 281                                                                  NAME_METHOD_WRITE_REPLACE, DESCR_METHOD_WRITE_REPLACE,
 282                                                                  null, null));
 283 
 284         mv.visitCode();
 285         mv.visitTypeInsn(NEW, NAME_SERIALIZED_LAMBDA);
 286         mv.visitInsn(DUP);;
 287         mv.visitLdcInsn(Type.getType(targetClass));
 288         mv.visitLdcInsn(samInfo.getReferenceKind());
 289         mv.visitLdcInsn(invokedType.returnType().getName().replace('.', '/'));
 290         mv.visitLdcInsn(samInfo.getName());
 291         mv.visitLdcInsn(samInfo.getMethodType().toMethodDescriptorString());
 292         mv.visitLdcInsn(implInfo.getReferenceKind());
 293         mv.visitLdcInsn(implInfo.getDeclaringClass().getName().replace('.', '/'));
 294         mv.visitLdcInsn(implInfo.getName());
 295         mv.visitLdcInsn(implInfo.getMethodType().toMethodDescriptorString());
 296         mv.visitLdcInsn(instantiatedMethodType.toMethodDescriptorString());
 297 
 298         mv.iconst(argTypes.length);
 299         mv.visitTypeInsn(ANEWARRAY, NAME_OBJECT);
 300         for (int i = 0; i < argTypes.length; i++) {
 301             mv.visitInsn(DUP);
 302             mv.iconst(i);
 303             mv.visitVarInsn(ALOAD, 0);
 304             mv.visitFieldInsn(GETFIELD, lambdaClassName, argNames[i], argTypes[i].getDescriptor());
 305             mv.boxIfTypePrimitive(argTypes[i]);
 306             mv.visitInsn(AASTORE);
 307         }
 308         mv.visitMethodInsn(INVOKESPECIAL, NAME_SERIALIZED_LAMBDA, NAME_CTOR,
 309                 DESCR_CTOR_SERIALIZED_LAMBDA);
 310         mv.visitInsn(ARETURN);
 311         mv.visitMaxs(-1, -1); // Maxs computed by ClassWriter.COMPUTE_MAXS, these arguments ignored
 312         mv.visitEnd();
 313     }
 314 
 315     /**
 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
 335      * method, converting arguments, as needed.
 336      */
 337     private class ForwardingMethodGenerator extends TypeConvertingMethodAdapter {
 338 
 339         ForwardingMethodGenerator(MethodVisitor mv) {
 340             super(mv);
 341         }
 342 
 343         void generate(Method m) throws InternalError {
 344             visitCode();
 345 
 346             if (implKind == MethodHandleInfo.REF_newInvokeSpecial) {
 347                 visitTypeInsn(NEW, implMethodClassName);
 348                 visitInsn(DUP);;
 349             }
 350             for (int i = 0; i < argTypes.length; i++) {
 351                 visitVarInsn(ALOAD, 0);
 352                 visitFieldInsn(GETFIELD, lambdaClassName, argNames[i], argTypes[i].getDescriptor());
 353             }
 354 
 355             convertArgumentTypes(Type.getArgumentTypes(m));
 356 
 357             // Invoke the method we want to forward to
 358             visitMethodInsn(invocationOpcode(), implMethodClassName, implMethodName, implMethodDesc);
 359 
 360             // 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
 362             Type samReturnType = Type.getReturnType(m);
 363             convertType(implMethodReturnType, samReturnType, samReturnType);
 364             visitInsn(samReturnType.getOpcode(Opcodes.IRETURN));
 365 
 366             visitMaxs(-1, -1); // Maxs computed by ClassWriter.COMPUTE_MAXS, these arguments ignored
 367             visitEnd();
 368         }
 369 
 370         private void convertArgumentTypes(Type[] samArgumentTypes) {
 371             int lvIndex = 0;
 372             boolean samIncludesReceiver = implIsInstanceMethod && argTypes.length == 0;
 373             int samReceiverLength = samIncludesReceiver ? 1 : 0;
 374             if (samIncludesReceiver) {
 375                 // push receiver
 376                 Type rcvrType = samArgumentTypes[0];
 377                 Type instantiatedRcvrType = instantiatedArgumentTypes[0];
 378 
 379                 visitVarInsn(rcvrType.getOpcode(ILOAD), lvIndex + 1);
 380                 lvIndex += rcvrType.getSize();
 381                 convertType(rcvrType, Type.getType(implDefiningClass), instantiatedRcvrType);
 382             }