< 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 >