< prev index next > src/java.base/share/classes/java/lang/invoke/InnerClassLambdaMetafactory.java
Print this page
import sun.invoke.util.VerifyAccess;
import sun.security.action.GetBooleanAction;
import java.io.Serializable;
import java.lang.constant.ConstantDescs;
import java.lang.reflect.Modifier;
! import java.util.LinkedHashSet;
- import java.util.Set;
import static java.lang.invoke.MethodHandleStatics.CLASSFILE_VERSION;
import static java.lang.invoke.MethodHandles.Lookup.ClassOption.NESTMATE;
import static java.lang.invoke.MethodHandles.Lookup.ClassOption.STRONG;
import static java.lang.invoke.MethodType.methodType;
import sun.invoke.util.VerifyAccess;
import sun.security.action.GetBooleanAction;
import java.io.Serializable;
import java.lang.constant.ConstantDescs;
+ import java.lang.reflect.code.op.CoreOp.FuncOp;
+ import java.lang.reflect.code.Quoted;
+ import java.lang.reflect.code.interpreter.Interpreter;
+ import java.lang.reflect.code.parser.OpParser;
+ import java.lang.invoke.MethodHandles.Lookup;
import java.lang.reflect.Modifier;
! import java.util.*;
import static java.lang.invoke.MethodHandleStatics.CLASSFILE_VERSION;
import static java.lang.invoke.MethodHandles.Lookup.ClassOption.NESTMATE;
import static java.lang.invoke.MethodHandles.Lookup.ClassOption.STRONG;
import static java.lang.invoke.MethodType.methodType;
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;";
private static final String DESCR_METHOD_WRITE_OBJECT = "(Ljava/io/ObjectOutputStream;)V";
private static final String DESCR_METHOD_READ_OBJECT = "(Ljava/io/ObjectInputStream;)V";
+ private static final String DESCR_METHOD_QUOTED = "()Ljava/lang/reflect/code/Quoted;";
private static final String NAME_METHOD_WRITE_REPLACE = "writeReplace";
private static final String NAME_METHOD_READ_OBJECT = "readObject";
private static final String NAME_METHOD_WRITE_OBJECT = "writeObject";
+ private static final String NAME_METHOD_QUOTED = "quoted";
private static final String DESCR_CLASS = "Ljava/lang/Class;";
private static final String DESCR_STRING = "Ljava/lang/String;";
private static final String DESCR_OBJECT = "Ljava/lang/Object;";
private static final String DESCR_CTOR_SERIALIZED_LAMBDA
private static final boolean disableEagerInitialization;
// condy to load implMethod from class data
private static final ConstantDynamic implMethodCondy;
+ // condy to load reflective field from class data
+ private static final ConstantDynamic reflectiveFieldCondy;
+
+ private static final ConstantDynamic makeQuotedMethodCondy;
+
+ private static final MethodHandle HANDLE_MAKE_QUOTED;
+
+ private static final String quotedInstanceFieldName = "quoted";
+ private static final String quotedInstanceFieldDesc = Quoted.class.descriptorString();
+
+
static {
// To dump the lambda proxy classes, set this system property:
// -Djdk.invoke.LambdaMetafactory.dumpProxyClassFiles
// or -Djdk.invoke.LambdaMetafactory.dumpProxyClassFiles=true
final String dumpProxyClassesKey = "jdk.invoke.LambdaMetafactory.dumpProxyClassFiles";
final String disableEagerInitializationKey = "jdk.internal.lambda.disableEagerInitialization";
disableEagerInitialization = GetBooleanAction.privilegedGetProperty(disableEagerInitializationKey);
// condy to load implMethod from class data
! MethodType classDataMType = methodType(Object.class, MethodHandles.Lookup.class, String.class, Class.class);
! Handle classDataBsm = new Handle(H_INVOKESTATIC, Type.getInternalName(MethodHandles.class), "classData",
! classDataMType.descriptorString(), false);
! implMethodCondy = new ConstantDynamic(ConstantDescs.DEFAULT_NAME, MethodHandle.class.descriptorString(), classDataBsm);
}
// See context values in AbstractValidatingLambdaMetafactory
private final String implMethodClassName; // Name of type containing implementation "CC"
private final String implMethodName; // Name of implementation method "impl"
final String disableEagerInitializationKey = "jdk.internal.lambda.disableEagerInitialization";
disableEagerInitialization = GetBooleanAction.privilegedGetProperty(disableEagerInitializationKey);
// condy to load implMethod from class data
! MethodType classDataAtMType = methodType(Object.class, MethodHandles.Lookup.class, String.class, Class.class, int.class);
! Handle classDataBsm = new Handle(H_INVOKESTATIC, Type.getInternalName(MethodHandles.class), "classDataAt",
! classDataAtMType.descriptorString(), false);
! implMethodCondy = new ConstantDynamic(ConstantDescs.DEFAULT_NAME, MethodHandle.class.descriptorString(), classDataBsm, 0);
+ reflectiveFieldCondy = new ConstantDynamic(ConstantDescs.DEFAULT_NAME, MethodHandle.class.descriptorString(), classDataBsm, 1);
+ makeQuotedMethodCondy = new ConstantDynamic(ConstantDescs.DEFAULT_NAME, MethodHandle.class.descriptorString(), classDataBsm, 2);
+
+ try {
+ HANDLE_MAKE_QUOTED = MethodHandles.lookup().findStatic(
+ InnerClassLambdaMetafactory.class, "makeQuoted",
+ MethodType.methodType(Quoted.class, String.class, Object[].class));
+ } catch (Throwable ex) {
+ throw new AssertionError(ex);
+ }
}
// See context values in AbstractValidatingLambdaMetafactory
private final String implMethodClassName; // Name of type containing implementation "CC"
private final String implMethodName; // Name of implementation method "impl"
* types must extend {@code Serializable}.
* @param altInterfaces Additional interfaces which the lambda object
* should implement.
* @param altMethods Method types for additional signatures to be
* implemented by invoking the implementation method
+ * @param reflectiveField a {@linkplain MethodHandles.Lookup#findGetter(Class, String, Class) getter}
+ * method handle that is used to retrieve the string representation of the
+ * quotable lambda's associated intermediate representation.
* @throws LambdaConversionException If any of the meta-factory protocol
* invariants are violated
* @throws SecurityException If a security manager is present, and it
* <a href="MethodHandles.Lookup.html#secmgr">denies access</a>
* from {@code caller} to the package of {@code implementation}.
MethodType interfaceMethodType,
MethodHandle implementation,
MethodType dynamicMethodType,
boolean isSerializable,
Class<?>[] altInterfaces,
! MethodType[] altMethods)
throws LambdaConversionException {
super(caller, factoryType, interfaceMethodName, interfaceMethodType,
implementation, dynamicMethodType,
! isSerializable, altInterfaces, altMethods);
implMethodClassName = implClass.getName().replace('.', '/');
implMethodName = implInfo.getName();
implMethodDesc = implInfo.getMethodType().toMethodDescriptorString();
constructorType = factoryType.changeReturnType(Void.TYPE);
lambdaClassName = lambdaClassName(targetClass);
MethodType interfaceMethodType,
MethodHandle implementation,
MethodType dynamicMethodType,
boolean isSerializable,
Class<?>[] altInterfaces,
! MethodType[] altMethods,
+ MethodHandle reflectiveField)
throws LambdaConversionException {
super(caller, factoryType, interfaceMethodName, interfaceMethodType,
implementation, dynamicMethodType,
! isSerializable, altInterfaces, altMethods, reflectiveField);
implMethodClassName = implClass.getName().replace('.', '/');
implMethodName = implInfo.getName();
implMethodDesc = implInfo.getMethodType().toMethodDescriptorString();
constructorType = factoryType.changeReturnType(Void.TYPE);
lambdaClassName = lambdaClassName(targetClass);
argDescs[i],
null, null);
fv.visitEnd();
}
+ // if quotable, generate the field that will hold the value of quoted
+ if (quotableOpField != null) {
+ cw.visitField(ACC_PRIVATE + ACC_FINAL,
+ quotedInstanceFieldName,
+ quotedInstanceFieldDesc,
+ null, null);
+ }
+
generateConstructor();
if (factoryType.parameterCount() == 0 && disableEagerInitialization) {
generateClassInitializer();
}
if (isSerializable)
generateSerializationFriendlyMethods();
else if (accidentallySerializable)
generateSerializationHostileMethods();
cw.visitEnd();
// Define the generated class in this VM.
final byte[] classBytes = cw.toByteArray();
try {
// this class is linked at the indy callsite; so define a hidden nestmate
! var classdata = useImplMethodHandle? implementation : null;
return caller.makeHiddenClassDefiner(lambdaClassName, classBytes, Set.of(NESTMATE, STRONG), lambdaProxyClassFileDumper)
.defineClass(!disableEagerInitialization, classdata);
} catch (Throwable t) {
throw new InternalError(t);
if (isSerializable)
generateSerializationFriendlyMethods();
else if (accidentallySerializable)
generateSerializationHostileMethods();
+ if (quotableOpField != null) {
+ generateQuotableMethod();
+ }
+
cw.visitEnd();
// Define the generated class in this VM.
final byte[] classBytes = cw.toByteArray();
try {
// this class is linked at the indy callsite; so define a hidden nestmate
! List<?> classdata;
+ if (useImplMethodHandle || quotableOpField != null) {
+ classdata = quotableOpField == null ?
+ List.of(implementation) :
+ List.of(implementation, quotableOpField, HANDLE_MAKE_QUOTED);
+ } else {
+ classdata = null;
+ }
return caller.makeHiddenClassDefiner(lambdaClassName, classBytes, Set.of(NESTMATE, STRONG), lambdaProxyClassFileDumper)
.defineClass(!disableEagerInitialization, classdata);
} catch (Throwable t) {
throw new InternalError(t);
Class<?> argType = factoryType.parameterType(i);
ctor.visitVarInsn(getLoadOpcode(argType), lvIndex + 1);
lvIndex += getParameterSize(argType);
ctor.visitFieldInsn(PUTFIELD, lambdaClassName, argNames[i], argDescs[i]);
}
+
+ if (quotableOpField != null) {
+ generateQuotedFieldInitializer(ctor);
+ }
+
ctor.visitInsn(RETURN);
// Maxs computed by ClassWriter.COMPUTE_MAXS, these arguments ignored
ctor.visitMaxs(-1, -1);
ctor.visitEnd();
}
+ private void generateQuotedFieldInitializer(MethodVisitor ctor) {
+ ctor.visitCode();
+
+ // push the receiver on the stack for operand of put field instruction
+ ctor.visitVarInsn(ALOAD, 0);
+
+ ctor.visitLdcInsn(makeQuotedMethodCondy);
+
+ // load op string from field
+
+ ctor.visitLdcInsn(reflectiveFieldCondy);
+ MethodType mtype = quotableOpFieldInfo.getMethodType();
+ if (quotableOpFieldInfo.getReferenceKind() != MethodHandleInfo.REF_getStatic) {
+ mtype = mtype.insertParameterTypes(0, implClass);
+ }
+ ctor.visitMethodInsn(INVOKEVIRTUAL, "java/lang/invoke/MethodHandle",
+ "invokeExact", mtype.descriptorString(), false);
+
+ // load captured args in array
+
+ ctor.visitLdcInsn(quotableOpType.parameterCount());
+ ctor.visitTypeInsn(ANEWARRAY, JAVA_LANG_OBJECT);
+ int capturedArity = factoryType.parameterCount() - reflectiveCaptureCount();
+ // initialize quoted captures
+ TypeConvertingMethodAdapter tcmv = new TypeConvertingMethodAdapter(ctor);
+ for (int i = 0; i < reflectiveCaptureCount(); i++) {
+ ctor.visitInsn(DUP);
+ ctor.visitIntInsn(BIPUSH, i); // is it possible that i can be greater than Byte.MAX_VALUE ?
+ ctor.visitVarInsn(ALOAD, 0);
+ ctor.visitFieldInsn(GETFIELD, lambdaClassName, argNames[capturedArity + i], argDescs[capturedArity + i]);
+ tcmv.boxIfTypePrimitive(Type.getType(argDescs[capturedArity + i]));
+ ctor.visitInsn(AASTORE);
+ }
+
+ // now create a Quoted from String and captured args Object[]
+
+ ctor.visitMethodInsn(INVOKEVIRTUAL, "java/lang/invoke/MethodHandle",
+ "invokeExact", HANDLE_MAKE_QUOTED.type().toMethodDescriptorString(), false);
+ ctor.visitFieldInsn(PUTFIELD, lambdaClassName, quotedInstanceFieldName, quotedInstanceFieldDesc);
+ }
+
/**
* Generate a writeReplace method that supports serialization
*/
private void generateSerializationFriendlyMethods() {
TypeConvertingMethodAdapter mv
// Maxs computed by ClassWriter.COMPUTE_MAXS, these arguments ignored
mv.visitMaxs(-1, -1);
mv.visitEnd();
}
+ /**
+ * Generate a writeReplace method that supports serialization
+ */
+ private void generateQuotableMethod() {
+ MethodVisitor mv = cw.visitMethod(ACC_PUBLIC + ACC_FINAL,
+ NAME_METHOD_QUOTED, DESCR_METHOD_QUOTED,
+ null, null);
+
+ mv.visitVarInsn(ALOAD, 0);
+ mv.visitFieldInsn(GETFIELD, lambdaClassName, quotedInstanceFieldName, quotedInstanceFieldDesc);
+ mv.visitInsn(ARETURN);
+
+ // Maxs computed by ClassWriter.COMPUTE_MAXS, these arguments ignored
+ mv.visitMaxs(-1, -1);
+ mv.visitEnd();
+ }
+
/**
* Generate a readObject/writeObject method that is hostile to serialization
*/
private void generateSerializationHostileMethods() {
MethodVisitor mv = cw.visitMethod(ACC_PRIVATE + ACC_FINAL,
visitInsn(DUP);
}
if (useImplMethodHandle) {
visitLdcInsn(implMethodCondy);
}
! for (int i = 0; i < argNames.length; i++) {
visitVarInsn(ALOAD, 0);
visitFieldInsn(GETFIELD, lambdaClassName, argNames[i], argDescs[i]);
}
convertArgumentTypes(methodType);
visitInsn(DUP);
}
if (useImplMethodHandle) {
visitLdcInsn(implMethodCondy);
}
! for (int i = 0; i < argNames.length - reflectiveCaptureCount(); i++) {
visitVarInsn(ALOAD, 0);
visitFieldInsn(GETFIELD, lambdaClassName, argNames[i], argDescs[i]);
}
convertArgumentTypes(methodType);
}
private void convertArgumentTypes(MethodType samType) {
int lvIndex = 0;
int samParametersLength = samType.parameterCount();
! int captureArity = factoryType.parameterCount();
for (int i = 0; i < samParametersLength; i++) {
Class<?> argType = samType.parameterType(i);
visitVarInsn(getLoadOpcode(argType), lvIndex + 1);
lvIndex += getParameterSize(argType);
convertType(argType, implMethodType.parameterType(captureArity + i), dynamicMethodType.parameterType(i));
}
private void convertArgumentTypes(MethodType samType) {
int lvIndex = 0;
int samParametersLength = samType.parameterCount();
! int captureArity = factoryType.parameterCount() - reflectiveCaptureCount();
for (int i = 0; i < samParametersLength; i++) {
Class<?> argType = samType.parameterType(i);
visitVarInsn(getLoadOpcode(argType), lvIndex + 1);
lvIndex += getParameterSize(argType);
convertType(argType, implMethodType.parameterType(captureArity + i), dynamicMethodType.parameterType(i));
} else {
return 4;
}
}
+ private static Quoted makeQuoted(String opText, Object[] args) {
+ FuncOp op = (FuncOp)OpParser.fromStringOfFuncOp(opText);
+ return (Quoted)Interpreter.invoke(Lookup.IMPL_LOOKUP, op, args);
+ }
}
< prev index next >