< 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,15 +26,15 @@
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.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;
@@ -54,10 +54,11 @@
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,14 +86,20 @@
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 key = "jdk.internal.lambda.dumpProxyClasses";
- String path = GetPropertyAction.privilegedGetProperty(key);
+ 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,53 +185,28 @@
* 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 {
+ if (!disableEagerInitialization) {
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);
+ 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,12 +252,13 @@
null, null);
fv.visitEnd();
}
generateConstructor();
-
- if (invokedType.parameterCount() != 0) {
+ if (invokedType.parameterCount() == 0) {
+ generateStaticField();
+ } else {
generateFactory();
}
// Forward the SAM method
MethodVisitor mv = cw.visitMethod(ACC_PUBLIC, samMethodName,
@@ -320,27 +303,54 @@
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);
- int parameterCount = invokedType.parameterCount();
- for (int typeIndex = 0, varIndex = 0; typeIndex < parameterCount; typeIndex++) {
+ 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);
- m.visitInsn(ARETURN);
- m.visitMaxs(-1, -1);
- m.visitEnd();
}
/**
* Generate the constructor for the class
*/
< prev index next >