< prev index next >
src/java.base/share/classes/java/lang/invoke/InnerClassLambdaMetafactory.java
Print this page
@@ -25,40 +25,38 @@
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 sun.security.action.GetBooleanAction;
import java.io.FilePermission;
import java.io.Serializable;
+import java.lang.invoke.MethodHandles.Lookup;
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;
import java.util.Set;
+import static java.lang.invoke.MethodHandles.Lookup.ClassOption.NESTMATE;
import static jdk.internal.org.objectweb.asm.Opcodes.*;
/**
* Lambda metafactory implementation which dynamically creates an
* inner-class-like class per lambda callsite.
*
* @see LambdaMetafactory
*/
/* package */ final class InnerClassLambdaMetafactory extends AbstractValidatingLambdaMetafactory {
- private static final Unsafe UNSAFE = Unsafe.getUnsafe();
-
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";
//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;";
@@ -76,12 +74,10 @@
+ DESCR_STRING + DESCR_STRING + DESCR_STRING + DESCR_STRING + "[" + DESCR_OBJECT + ")V";
private static final String DESCR_CTOR_NOT_SERIALIZABLE_EXCEPTION = "(Ljava/lang/String;)V";
private static final String[] SER_HOSTILE_EXCEPTIONS = new String[] {NAME_NOT_SERIALIZABLE_EXCEPTION};
- private static final String DESCR_HIDDEN = "Ljdk/internal/vm/annotation/Hidden;";
-
private static final String[] EMPTY_STRING_ARRAY = new String[0];
// Used to ensure that each spun class name is unique
private static final AtomicInteger counter = new AtomicInteger(0);
@@ -161,11 +157,11 @@
isSerializable, markerInterfaces, additionalBridges);
implMethodClassName = implClass.getName().replace('.', '/');
implMethodName = implInfo.getName();
implMethodDesc = implInfo.getMethodType().toMethodDescriptorString();
constructorType = invokedType.changeReturnType(Void.TYPE);
- lambdaClassName = targetClass.getName().replace('.', '/') + "$$Lambda$" + counter.incrementAndGet();
+ lambdaClassName = lambdaClassName(targetClass);
cw = new ClassWriter(ClassWriter.COMPUTE_MAXS);
int parameterCount = invokedType.parameterCount();
if (parameterCount > 0) {
argNames = new String[parameterCount];
argDescs = new String[parameterCount];
@@ -176,10 +172,19 @@
} else {
argNames = argDescs = EMPTY_STRING_ARRAY;
}
}
+ private static String lambdaClassName(Class<?> targetClass) {
+ String name = targetClass.getName();
+ if (targetClass.isHiddenClass()) {
+ // use the original class name
+ name = name.replace('/', '_');
+ }
+ return name.replace('.', '/') + "$$Lambda$" + counter.incrementAndGet();
+ }
+
/**
* Build the CallSite. Generate a class file which implements the functional
* interface, define the class, if there are no parameters create an instance
* of the class which the CallSite will return, otherwise, generate handles
* which will call the class' constructor.
@@ -191,10 +196,11 @@
* is not found
*/
@Override
CallSite buildCallSite() throws LambdaConversionException {
final Class<?> innerClass = spinInnerClass();
+ assert innerClass.isHiddenClass() : innerClass.toString();
if (invokedType.parameterCount() == 0 && !disableEagerInitialization) {
// In the case of a non-capturing lambda, we optimize linkage by pre-computing a single instance,
// unless we've suppressed eager initialization
final Constructor<?>[] ctrs = AccessController.doPrivileged(
new PrivilegedAction<>() {
@@ -215,24 +221,18 @@
}
try {
Object inst = ctrs[0].newInstance();
return new ConstantCallSite(MethodHandles.constant(samBase, inst));
- }
- catch (ReflectiveOperationException e) {
+ } 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) {
+ MethodHandle mh = caller.findConstructor(innerClass, invokedType.changeReturnType(void.class));
+ return new ConstantCallSite(mh.asType(invokedType));
+ } catch (ReflectiveOperationException e) {
throw new LambdaConversionException("Exception finding constructor", e);
}
}
}
@@ -281,26 +281,20 @@
fv.visitEnd();
}
generateConstructor();
- if (invokedType.parameterCount() != 0 || disableEagerInitialization) {
- generateFactory();
- }
-
// Forward the SAM method
MethodVisitor mv = cw.visitMethod(ACC_PUBLIC, samMethodName,
samMethodType.toMethodDescriptorString(), null, null);
- mv.visitAnnotation(DESCR_HIDDEN, true);
new ForwardingMethodGenerator(mv).generate(samMethodType);
// Forward the bridges
if (additionalBridges != null) {
for (MethodType mt : additionalBridges) {
mv = cw.visitMethod(ACC_PUBLIC|ACC_BRIDGE, samMethodName,
mt.toMethodDescriptorString(), null, null);
- mv.visitAnnotation(DESCR_HIDDEN, true);
new ForwardingMethodGenerator(mv).generate(mt);
}
}
if (isSerializable)
@@ -311,11 +305,10 @@
cw.visitEnd();
// Define the generated class in this VM.
final byte[] classBytes = cw.toByteArray();
-
// If requested, dump out to a file for debugging purposes
if (dumper != null) {
AccessController.doPrivileged(new PrivilegedAction<>() {
@Override
public Void run() {
@@ -325,32 +318,16 @@
}, null,
new FilePermission("<<ALL FILES>>", "read, write"),
// createDirectories may need it
new PropertyPermission("user.dir", "read"));
}
-
- return UNSAFE.defineAnonymousClass(targetClass, classBytes, null);
+ try {
+ // this class is linked at the indy callsite; so define a hidden nestmate
+ return caller.defineHiddenClass(classBytes, !disableEagerInitialization, NESTMATE).lookupClass();
+ } catch (IllegalAccessException e) {
+ throw new LambdaConversionException("Exception defining lambda proxy class", e);
}
-
- /**
- * 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
*/
< prev index next >