< prev index next >
src/java.base/share/classes/java/lang/invoke/InnerClassLambdaMetafactory.java
        Print this page
rev 56749 : Initialize lambdas when executing generated bytecode
Changes the InnerClassLambdaMetaFactory to postpone lambda initialization
until the generated bytecode is executed. This is achieved by generating a
static field containing the singleton instance of the non-capturing lambda.
rev 56750 : Eagerly initialize lambdas by default
But leave an option (jdk.internal.lambda.disableEagerInitialization) to disable
this optimization.
        
*** 26,40 ****
  package java.lang.invoke;
  
  import jdk.internal.org.objectweb.asm.*;
  import sun.invoke.util.BytecodeDescriptor;
  import jdk.internal.misc.Unsafe;
  import sun.security.action.GetPropertyAction;
  
  import java.io.FilePermission;
  import java.io.Serializable;
- import java.lang.reflect.Constructor;
  import java.security.AccessController;
  import java.security.PrivilegedAction;
  import java.util.LinkedHashSet;
  import java.util.concurrent.atomic.AtomicInteger;
  import java.util.PropertyPermission;
--- 26,40 ----
  package java.lang.invoke;
  
  import jdk.internal.org.objectweb.asm.*;
  import sun.invoke.util.BytecodeDescriptor;
  import jdk.internal.misc.Unsafe;
+ import sun.security.action.GetBooleanAction;
  import sun.security.action.GetPropertyAction;
  
  import java.io.FilePermission;
  import java.io.Serializable;
  import java.security.AccessController;
  import java.security.PrivilegedAction;
  import java.util.LinkedHashSet;
  import java.util.concurrent.atomic.AtomicInteger;
  import java.util.PropertyPermission;
*** 54,63 ****
--- 54,64 ----
      private static final int CLASSFILE_VERSION = 52;
      private static final String METHOD_DESCRIPTOR_VOID = Type.getMethodDescriptor(Type.VOID_TYPE);
      private static final String JAVA_LANG_OBJECT = "java/lang/Object";
      private static final String NAME_CTOR = "<init>";
      private static final String NAME_FACTORY = "get$Lambda";
+     private static final String LAMBDA_INSTANCE_FIELD = "LAMBDA_INSTANCE$";
  
      //Serialization support
      private static final String NAME_SERIALIZED_LAMBDA = "java/lang/invoke/SerializedLambda";
      private static final String NAME_NOT_SERIALIZABLE_EXCEPTION = "java/io/NotSerializableException";
      private static final String DESCR_METHOD_WRITE_REPLACE = "()Ljava/lang/Object;";
*** 85,98 ****
      private static final AtomicInteger counter = new AtomicInteger(0);
  
      // For dumping generated classes to disk, for debugging purposes
      private static final ProxyClassesDumper dumper;
  
      static {
!         final String key = "jdk.internal.lambda.dumpProxyClasses";
!         String path = GetPropertyAction.privilegedGetProperty(key);
          dumper = (null == path) ? null : ProxyClassesDumper.getInstance(path);
      }
  
      // See context values in AbstractValidatingLambdaMetafactory
      private final String implMethodClassName;        // Name of type containing implementation "CC"
      private final String implMethodName;             // Name of implementation method "impl"
--- 86,105 ----
      private static final AtomicInteger counter = new AtomicInteger(0);
  
      // For dumping generated classes to disk, for debugging purposes
      private static final ProxyClassesDumper dumper;
  
+     // disable optimization that eagerly initializes lambdas
+     private static final boolean disableEagerInitialization;
+ 
      static {
!         final String dumpKey = "jdk.internal.lambda.dumpProxyClasses";
!         String path = GetPropertyAction.privilegedGetProperty(dumpKey);
          dumper = (null == path) ? null : ProxyClassesDumper.getInstance(path);
+ 
+         final String disableEagerInitializationKey = "jdk.internal.lambda.disableEagerInitialization";
+         disableEagerInitialization = GetBooleanAction.privilegedGetProperty(disableEagerInitializationKey);
      }
  
      // See context values in AbstractValidatingLambdaMetafactory
      private final String implMethodClassName;        // Name of type containing implementation "CC"
      private final String implMethodName;             // Name of implementation method "impl"
*** 178,230 ****
       * of the class which the CallSite will return, otherwise, generate handles
       * which will call the class' constructor.
       *
       * @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
       */
      @Override
      CallSite buildCallSite() throws LambdaConversionException {
          final Class<?> innerClass = spinInnerClass();
-         if (invokedType.parameterCount() == 0) {
-             final Constructor<?>[] ctrs = AccessController.doPrivileged(
-                     new PrivilegedAction<>() {
-                 @Override
-                 public Constructor<?>[] run() {
-                     Constructor<?>[] ctrs = innerClass.getDeclaredConstructors();
-                     if (ctrs.length == 1) {
-                         // The lambda implementing inner class constructor is private, set
-                         // it accessible (by us) before creating the constant sole instance
-                         ctrs[0].setAccessible(true);
-                     }
-                     return ctrs;
-                 }
-                     });
-             if (ctrs.length != 1) {
-                 throw new LambdaConversionException("Expected one lambda constructor for "
-                         + innerClass.getCanonicalName() + ", got " + ctrs.length);
-             }
- 
-             try {
-                 Object inst = ctrs[0].newInstance();
-                 return new ConstantCallSite(MethodHandles.constant(samBase, inst));
-             }
-             catch (ReflectiveOperationException e) {
-                 throw new LambdaConversionException("Exception instantiating lambda object", e);
-             }
-         } else {
              try {
                  UNSAFE.ensureClassInitialized(innerClass);
-                 return new ConstantCallSite(
-                         MethodHandles.Lookup.IMPL_LOOKUP
-                              .findStatic(innerClass, NAME_FACTORY, invokedType));
              }
!             catch (ReflectiveOperationException e) {
!                 throw new LambdaConversionException("Exception finding constructor", e);
              }
          }
      }
  
      /**
       * Generate a class file which implements the functional
--- 185,212 ----
       * of the class which the CallSite will return, otherwise, generate handles
       * which will call the class' constructor.
       *
       * @return a CallSite, which, when invoked, will return an instance of the
       * functional interface
       * @throws LambdaConversionException If properly formed functional interface
       * is not found
       */
      @Override
      CallSite buildCallSite() throws LambdaConversionException {
          final Class<?> innerClass = spinInnerClass();
          try {
+             if (!disableEagerInitialization) {
                  UNSAFE.ensureClassInitialized(innerClass);
              }
!             MethodHandle lambdaHandle = invokedType.parameterCount() == 0
!                     ? MethodHandles.Lookup.IMPL_LOOKUP.findStaticGetter(innerClass, LAMBDA_INSTANCE_FIELD, invokedType.returnType())
!                     : MethodHandles.Lookup.IMPL_LOOKUP.findStatic(innerClass, NAME_FACTORY, invokedType);
! 
!             return new ConstantCallSite(lambdaHandle);
          }
+         catch (ReflectiveOperationException e) {
+             throw new LambdaConversionException("Exception finding lambda ", e);
          }
      }
  
      /**
       * Generate a class file which implements the functional
*** 270,281 ****
                                              null, null);
              fv.visitEnd();
          }
  
          generateConstructor();
! 
!         if (invokedType.parameterCount() != 0) {
              generateFactory();
          }
  
          // Forward the SAM method
          MethodVisitor mv = cw.visitMethod(ACC_PUBLIC, samMethodName,
--- 252,264 ----
                                              null, null);
              fv.visitEnd();
          }
  
          generateConstructor();
!         if (invokedType.parameterCount() == 0) {
!             generateStaticField();
!         } else {
              generateFactory();
          }
  
          // Forward the SAM method
          MethodVisitor mv = cw.visitMethod(ACC_PUBLIC, samMethodName,
*** 320,346 ****
  
          return UNSAFE.defineAnonymousClass(targetClass, classBytes, null);
      }
  
      /**
       * Generate the factory method for the class
       */
      private void generateFactory() {
          MethodVisitor m = cw.visitMethod(ACC_PRIVATE | ACC_STATIC, NAME_FACTORY, invokedType.toMethodDescriptorString(), null, null);
          m.visitCode();
          m.visitTypeInsn(NEW, lambdaClassName);
          m.visitInsn(Opcodes.DUP);
!         int parameterCount = invokedType.parameterCount();
!         for (int typeIndex = 0, varIndex = 0; typeIndex < parameterCount; typeIndex++) {
              Class<?> argType = invokedType.parameterType(typeIndex);
              m.visitVarInsn(getLoadOpcode(argType), varIndex);
              varIndex += getParameterSize(argType);
          }
          m.visitMethodInsn(INVOKESPECIAL, lambdaClassName, NAME_CTOR, constructorType.toMethodDescriptorString(), false);
-         m.visitInsn(ARETURN);
-         m.visitMaxs(-1, -1);
-         m.visitEnd();
      }
  
      /**
       * Generate the constructor for the class
       */
--- 303,356 ----
  
          return UNSAFE.defineAnonymousClass(targetClass, classBytes, null);
      }
  
      /**
+      * Generate a static field that contains the singleton instance of the lambda
+      */
+     private void generateStaticField() {
+         String lambdaTypeDescriptor = BytecodeDescriptor.unparse(invokedType.returnType());
+ 
+         // Generate the static final field that holds the lambda singleton
+         FieldVisitor fv = cw.visitField(ACC_PRIVATE | ACC_STATIC | ACC_FINAL, LAMBDA_INSTANCE_FIELD, lambdaTypeDescriptor, null, null);
+         fv.visitEnd();
+ 
+         // Instantiate the lambda and store it to the static final field
+         MethodVisitor clinit = cw.visitMethod(ACC_STATIC, "<clinit>", "()V", null, null);
+         clinit.visitCode();
+ 
+         instantiateLambda(clinit);
+         clinit.visitFieldInsn(PUTSTATIC, lambdaClassName, LAMBDA_INSTANCE_FIELD, lambdaTypeDescriptor);
+ 
+         clinit.visitInsn(RETURN);
+         clinit.visitMaxs(-1, -1);
+         clinit.visitEnd();
+     }
+ 
+     /**
       * Generate the factory method for the class
       */
      private void generateFactory() {
          MethodVisitor m = cw.visitMethod(ACC_PRIVATE | ACC_STATIC, NAME_FACTORY, invokedType.toMethodDescriptorString(), null, null);
          m.visitCode();
+ 
+         instantiateLambda(m);
+         m.visitInsn(ARETURN);
+ 
+         m.visitMaxs(-1, -1);
+         m.visitEnd();
+     }
+ 
+     private void instantiateLambda(MethodVisitor m) {
          m.visitTypeInsn(NEW, lambdaClassName);
          m.visitInsn(Opcodes.DUP);
!         for (int typeIndex = 0, varIndex = 0; typeIndex < invokedType.parameterCount(); typeIndex++) {
              Class<?> argType = invokedType.parameterType(typeIndex);
              m.visitVarInsn(getLoadOpcode(argType), varIndex);
              varIndex += getParameterSize(argType);
          }
          m.visitMethodInsn(INVOKESPECIAL, lambdaClassName, NAME_CTOR, constructorType.toMethodDescriptorString(), false);
      }
  
      /**
       * Generate the constructor for the class
       */
< prev index next >