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

Print this page
rev 9538 : generates MH link to static factory for lambdas
rev 9539 : fix bytecode loading constructor parameters
rev 9540 : whitespace cleaning


  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
  41  * inner-class-like class per lambda callsite.
  42  *
  43  * @see LambdaMetafactory
  44  */
  45 /* package */ final class InnerClassLambdaMetafactory extends AbstractValidatingLambdaMetafactory {
  46     private static final Unsafe UNSAFE = Unsafe.getUnsafe();
  47 
  48     private static final int CLASSFILE_VERSION = 51;
  49     private static final String METHOD_DESCRIPTOR_VOID = Type.getMethodDescriptor(Type.VOID_TYPE);
  50     private static final String NAME_MAGIC_ACCESSOR_IMPL = "java/lang/invoke/MagicLambdaImpl";
  51     private static final String NAME_CTOR = "<init>";

  52 
  53     //Serialization support
  54     private static final String NAME_SERIALIZED_LAMBDA = "java/lang/invoke/SerializedLambda";
  55     private static final String DESCR_METHOD_WRITE_REPLACE = "()Ljava/lang/Object;";
  56     private static final String NAME_METHOD_WRITE_REPLACE = "writeReplace";
  57     private static final String NAME_OBJECT = "java/lang/Object";
  58     private static final String DESCR_CTOR_SERIALIZED_LAMBDA
  59             = MethodType.methodType(void.class,
  60                                     Class.class,
  61                                     String.class, String.class, String.class,
  62                                     int.class, String.class, String.class, String.class,
  63                                     String.class,
  64                                     Object[].class).toMethodDescriptorString();
  65 
  66     // Used to ensure that each spun class name is unique
  67     private static final AtomicInteger counter = new AtomicInteger(0);
  68 
  69     // See context values in AbstractValidatingLambdaMetafactory
  70     private final String implMethodClassName;        // Name of type containing implementation "CC"
  71     private final String implMethodName;             // Name of implementation method "impl"


 175                     return innerClass.getDeclaredConstructors();
 176                 }
 177             });
 178             if (ctrs.length != 1) {
 179                 throw new ReflectiveOperationException("Expected one lambda constructor for "
 180                         + innerClass.getCanonicalName() + ", got " + ctrs.length);
 181             }
 182             // The lambda implementing inner class constructor is private, set
 183             // it accessible (by us) before creating the constant sole instance
 184             AccessController.doPrivileged(new PrivilegedAction<Void>() {
 185                 @Override
 186                 public Void run() {
 187                     ctrs[0].setAccessible(true);
 188                     return null;
 189                 }
 190             });
 191             Object inst = ctrs[0].newInstance();
 192             return new ConstantCallSite(MethodHandles.constant(samBase, inst));
 193         } else {
 194             return new ConstantCallSite(
 195                     MethodHandles.Lookup.IMPL_LOOKUP
 196                                         .findConstructor(innerClass, constructorType)
 197                                         .asType(constructorType.changeReturnType(samBase)));
 198         }
 199     }
 200 
 201     /**
 202      * Generate a class file which implements the functional
 203      * interface, define and return the class.
 204      *
 205      * @implNote The class that is generated does not include signature
 206      * information for exceptions that may be present on the SAM method.
 207      * This is to reduce classfile size, and is harmless as checked exceptions
 208      * are erased anyway, no one will ever compile against this classfile,
 209      * and we make no guarantees about the reflective properties of lambda
 210      * objects.
 211      *
 212      * @return a Class which implements the functional interface
 213      * @throws LambdaConversionException If properly formed functional interface
 214      * is not found
 215      */
 216     private Class<?> spinInnerClass() throws LambdaConversionException {
 217         String[] interfaces = new String[markerInterfaces.length + 1];
 218         interfaces[0] = samBase.getName().replace('.', '/');
 219         for (int i=0; i<markerInterfaces.length; i++) {
 220             interfaces[i+1] = markerInterfaces[i].getName().replace('.', '/');
 221         }
 222         cw.visit(CLASSFILE_VERSION, ACC_SUPER + ACC_FINAL + ACC_SYNTHETIC,
 223                  lambdaClassName, null,
 224                  NAME_MAGIC_ACCESSOR_IMPL, interfaces);
 225 
 226         // Generate final fields to be filled in by constructor
 227         for (int i = 0; i < argTypes.length; i++) {
 228             FieldVisitor fv = cw.visitField(ACC_PRIVATE + ACC_FINAL,
 229                                             argNames[i],
 230                                             argTypes[i].getDescriptor(),
 231                                             null, null);
 232             fv.visitEnd();
 233         }
 234 
 235         generateConstructor();
 236 




 237         // Forward the SAM method
 238         String methodDescriptor = samMethodType.toMethodDescriptorString();
 239         MethodVisitor mv = cw.visitMethod(ACC_PUBLIC, samMethodName,
 240                                           methodDescriptor, null, null);
 241         new ForwardingMethodGenerator(mv).generate(methodDescriptor);
 242 
 243         // Forward the bridges
 244         if (additionalBridges != null) {
 245             for (MethodType mt : additionalBridges) {
 246                 methodDescriptor = mt.toMethodDescriptorString();
 247                 mv = cw.visitMethod(ACC_PUBLIC|ACC_BRIDGE, samMethodName,
 248                                     methodDescriptor, null, null);
 249                 new ForwardingMethodGenerator(mv).generate(methodDescriptor);
 250             }
 251         }
 252 
 253         if (isSerializable)
 254             generateWriteReplace();
 255 
 256         cw.visitEnd();


 269                 PlatformLogger.getLogger(InnerClassLambdaMetafactory.class
 270                                       .getName()).severe(ex.getMessage(), ex);
 271             }
 272         ***/
 273 
 274         ClassLoader loader = targetClass.getClassLoader();
 275         ProtectionDomain pd = (loader == null)
 276             ? null
 277             : AccessController.doPrivileged(
 278             new PrivilegedAction<ProtectionDomain>() {
 279                 @Override
 280                 public ProtectionDomain run() {
 281                     return targetClass.getProtectionDomain();
 282                 }
 283             }
 284         );
 285 
 286         return UNSAFE.defineClass(lambdaClassName,
 287                                   classBytes, 0, classBytes.length,
 288                                   loader, pd);


















 289     }
 290 
 291     /**
 292      * Generate the constructor for the class
 293      */
 294     private void generateConstructor() {
 295         // Generate constructor
 296         MethodVisitor ctor = cw.visitMethod(ACC_PRIVATE, NAME_CTOR,
 297                                             constructorDesc, null, null);
 298         ctor.visitCode();
 299         ctor.visitVarInsn(ALOAD, 0);
 300         ctor.visitMethodInsn(INVOKESPECIAL, NAME_MAGIC_ACCESSOR_IMPL, NAME_CTOR,
 301                              METHOD_DESCRIPTOR_VOID);
 302         int lvIndex = 0;
 303         for (int i = 0; i < argTypes.length; i++) {
 304             ctor.visitVarInsn(ALOAD, 0);
 305             ctor.visitVarInsn(argTypes[i].getOpcode(ILOAD), lvIndex + 1);
 306             lvIndex += argTypes[i].getSize();
 307             ctor.visitFieldInsn(PUTFIELD, lambdaClassName, argNames[i],
 308                                 argTypes[i].getDescriptor());




  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
  41  * inner-class-like class per lambda callsite.
  42  *
  43  * @see LambdaMetafactory
  44  */
  45 /* package */ final class InnerClassLambdaMetafactory extends AbstractValidatingLambdaMetafactory {
  46     private static final Unsafe UNSAFE = Unsafe.getUnsafe();
  47 
  48     private static final int CLASSFILE_VERSION = 51;
  49     private static final String METHOD_DESCRIPTOR_VOID = Type.getMethodDescriptor(Type.VOID_TYPE);
  50     private static final String NAME_MAGIC_ACCESSOR_IMPL = "java/lang/invoke/MagicLambdaImpl";
  51     private static final String NAME_CTOR = "<init>";
  52     private static final String NAME_FACTORY = "get$Lambda";
  53 
  54     //Serialization support
  55     private static final String NAME_SERIALIZED_LAMBDA = "java/lang/invoke/SerializedLambda";
  56     private static final String DESCR_METHOD_WRITE_REPLACE = "()Ljava/lang/Object;";
  57     private static final String NAME_METHOD_WRITE_REPLACE = "writeReplace";
  58     private static final String NAME_OBJECT = "java/lang/Object";
  59     private static final String DESCR_CTOR_SERIALIZED_LAMBDA
  60             = MethodType.methodType(void.class,
  61                                     Class.class,
  62                                     String.class, String.class, String.class,
  63                                     int.class, String.class, String.class, String.class,
  64                                     String.class,
  65                                     Object[].class).toMethodDescriptorString();
  66 
  67     // Used to ensure that each spun class name is unique
  68     private static final AtomicInteger counter = new AtomicInteger(0);
  69 
  70     // See context values in AbstractValidatingLambdaMetafactory
  71     private final String implMethodClassName;        // Name of type containing implementation "CC"
  72     private final String implMethodName;             // Name of implementation method "impl"


 176                     return innerClass.getDeclaredConstructors();
 177                 }
 178             });
 179             if (ctrs.length != 1) {
 180                 throw new ReflectiveOperationException("Expected one lambda constructor for "
 181                         + innerClass.getCanonicalName() + ", got " + ctrs.length);
 182             }
 183             // The lambda implementing inner class constructor is private, set
 184             // it accessible (by us) before creating the constant sole instance
 185             AccessController.doPrivileged(new PrivilegedAction<Void>() {
 186                 @Override
 187                 public Void run() {
 188                     ctrs[0].setAccessible(true);
 189                     return null;
 190                 }
 191             });
 192             Object inst = ctrs[0].newInstance();
 193             return new ConstantCallSite(MethodHandles.constant(samBase, inst));
 194         } else {
 195             return new ConstantCallSite(
 196                     MethodHandles.Lookup.IMPL_LOOKUP.findStatic(innerClass, NAME_FACTORY, invokedType));


 197         }
 198     }
 199 
 200     /**
 201      * Generate a class file which implements the functional
 202      * interface, define and return the class.
 203      *
 204      * @implNote The class that is generated does not include signature
 205      * information for exceptions that may be present on the SAM method.
 206      * This is to reduce classfile size, and is harmless as checked exceptions
 207      * are erased anyway, no one will ever compile against this classfile,
 208      * and we make no guarantees about the reflective properties of lambda
 209      * objects.
 210      *
 211      * @return a Class which implements the functional interface
 212      * @throws LambdaConversionException If properly formed functional interface
 213      * is not found
 214      */
 215     private Class<?> spinInnerClass() throws LambdaConversionException {
 216         String[] interfaces = new String[markerInterfaces.length + 1];
 217         interfaces[0] = samBase.getName().replace('.', '/');
 218         for (int i=0; i<markerInterfaces.length; i++) {
 219             interfaces[i+1] = markerInterfaces[i].getName().replace('.', '/');
 220         }
 221         cw.visit(CLASSFILE_VERSION, ACC_SUPER + ACC_FINAL + ACC_SYNTHETIC,
 222                  lambdaClassName, null,
 223                  NAME_MAGIC_ACCESSOR_IMPL, interfaces);
 224 
 225         // Generate final fields to be filled in by constructor
 226         for (int i = 0; i < argTypes.length; i++) {
 227             FieldVisitor fv = cw.visitField(ACC_PRIVATE + ACC_FINAL,
 228                                             argNames[i],
 229                                             argTypes[i].getDescriptor(),
 230                                             null, null);
 231             fv.visitEnd();
 232         }
 233 
 234         generateConstructor();
 235 
 236         if (invokedType.parameterCount() != 0) {
 237             generateFactory();
 238         }
 239 
 240         // Forward the SAM method
 241         String methodDescriptor = samMethodType.toMethodDescriptorString();
 242         MethodVisitor mv = cw.visitMethod(ACC_PUBLIC, samMethodName,
 243                                           methodDescriptor, null, null);
 244         new ForwardingMethodGenerator(mv).generate(methodDescriptor);
 245 
 246         // Forward the bridges
 247         if (additionalBridges != null) {
 248             for (MethodType mt : additionalBridges) {
 249                 methodDescriptor = mt.toMethodDescriptorString();
 250                 mv = cw.visitMethod(ACC_PUBLIC|ACC_BRIDGE, samMethodName,
 251                                     methodDescriptor, null, null);
 252                 new ForwardingMethodGenerator(mv).generate(methodDescriptor);
 253             }
 254         }
 255 
 256         if (isSerializable)
 257             generateWriteReplace();
 258 
 259         cw.visitEnd();


 272                 PlatformLogger.getLogger(InnerClassLambdaMetafactory.class
 273                                       .getName()).severe(ex.getMessage(), ex);
 274             }
 275         ***/
 276 
 277         ClassLoader loader = targetClass.getClassLoader();
 278         ProtectionDomain pd = (loader == null)
 279             ? null
 280             : AccessController.doPrivileged(
 281             new PrivilegedAction<ProtectionDomain>() {
 282                 @Override
 283                 public ProtectionDomain run() {
 284                     return targetClass.getProtectionDomain();
 285                 }
 286             }
 287         );
 288 
 289         return UNSAFE.defineClass(lambdaClassName,
 290                                   classBytes, 0, classBytes.length,
 291                                   loader, pd);
 292     }
 293 
 294     /**
 295      * Generate the factory method for the class
 296      */
 297     private void generateFactory() {
 298         MethodVisitor m = cw.visitMethod(ACC_PRIVATE | ACC_STATIC, NAME_FACTORY, invokedType.toMethodDescriptorString(), null, null);
 299         m.visitCode();
 300         m.visitTypeInsn(NEW, lambdaClassName);
 301         m.visitInsn(Opcodes.DUP);
 302         for (int typeIndex = 0, varIndex = 0; typeIndex < argTypes.length; typeIndex++) {
 303             m.visitVarInsn(argTypes[typeIndex].getOpcode(ILOAD), varIndex);
 304             varIndex += argTypes[typeIndex].getSize();
 305         }
 306         m.visitMethodInsn(INVOKESPECIAL, lambdaClassName, NAME_CTOR, constructorDesc);
 307         m.visitInsn(ARETURN);
 308         m.visitMaxs(-1, -1);
 309         m.visitEnd();
 310     }
 311 
 312     /**
 313      * Generate the constructor for the class
 314      */
 315     private void generateConstructor() {
 316         // Generate constructor
 317         MethodVisitor ctor = cw.visitMethod(ACC_PRIVATE, NAME_CTOR,
 318                                             constructorDesc, null, null);
 319         ctor.visitCode();
 320         ctor.visitVarInsn(ALOAD, 0);
 321         ctor.visitMethodInsn(INVOKESPECIAL, NAME_MAGIC_ACCESSOR_IMPL, NAME_CTOR,
 322                              METHOD_DESCRIPTOR_VOID);
 323         int lvIndex = 0;
 324         for (int i = 0; i < argTypes.length; i++) {
 325             ctor.visitVarInsn(ALOAD, 0);
 326             ctor.visitVarInsn(argTypes[i].getOpcode(ILOAD), lvIndex + 1);
 327             lvIndex += argTypes[i].getSize();
 328             ctor.visitFieldInsn(PUTFIELD, lambdaClassName, argNames[i],
 329                                 argTypes[i].getDescriptor());