< prev index next > src/java.base/share/classes/java/lang/invoke/InnerClassLambdaMetafactory.java
Print this page
* questions.
*/
package java.lang.invoke;
+ import jdk.internal.misc.PreviewFeatures;
import jdk.internal.misc.CDS;
import jdk.internal.org.objectweb.asm.*;
import jdk.internal.util.ClassFileDumper;
import sun.invoke.util.BytecodeDescriptor;
import sun.invoke.util.VerifyAccess;
import sun.security.action.GetBooleanAction;
import java.io.Serializable;
import java.lang.constant.ConstantDescs;
+ import java.lang.reflect.AccessFlag;
import java.lang.reflect.Modifier;
+ import java.util.HashSet;
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;
accidentallySerializable |= !isSerializable && Serializable.class.isAssignableFrom(i);
}
interfaceNames = itfs.toArray(new String[itfs.size()]);
}
- cw.visit(CLASSFILE_VERSION, ACC_SUPER + ACC_FINAL + ACC_SYNTHETIC,
+ int version = CLASSFILE_VERSION | (PreviewFeatures.isEnabled() ? Opcodes.V_PREVIEW : 0);
+ cw.visit(version, ACC_SUPER + ACC_FINAL + ACC_SYNTHETIC,
lambdaClassName, null,
JAVA_LANG_OBJECT, interfaceNames);
// Generate final fields to be filled in by constructor
for (int i = 0; i < argDescs.length; i++) {
if (isSerializable)
generateSerializationFriendlyMethods();
else if (accidentallySerializable)
generateSerializationHostileMethods();
+ // generate LoadableDescriptors attribute if it references any value class
+ if (PreviewFeatures.isEnabled()) {
+ LoadableDescriptorsAttributeBuilder builder = new LoadableDescriptorsAttributeBuilder(targetClass);
+ builder.add(factoryType)
+ .add(interfaceMethodType)
+ .add(implMethodType)
+ .add(dynamicMethodType)
+ .add(altMethods);
+ if (!builder.isEmpty())
+ cw.visitAttribute(builder.build());
+ }
+
cw.visitEnd();
// Define the generated class in this VM.
final byte[] classBytes = cw.toByteArray();
default -> throw new InternalError("Unexpected invocation kind: " + implKind);
};
}
}
+ /*
+ * LoadableDescriptors attribute builder
+ */
+ static class LoadableDescriptorsAttributeBuilder {
+ private final Set<String> loadableDescriptors = new HashSet<>();
+ LoadableDescriptorsAttributeBuilder(Class<?> targetClass) {
+ if (requiresLoadableDescriptors(targetClass)) {
+ loadableDescriptors.add(Type.getDescriptor(targetClass));
+ }
+ }
+
+ /*
+ * Add the value types referenced in the given MethodType.
+ */
+ LoadableDescriptorsAttributeBuilder add(MethodType mt) {
+ // parameter types
+ for (Class<?> paramType : mt.ptypes()) {
+ if (requiresLoadableDescriptors(paramType)) {
+ loadableDescriptors.add(Type.getDescriptor(paramType));
+ }
+ }
+ // return type
+ if (requiresLoadableDescriptors(mt.returnType())) {
+ loadableDescriptors.add(Type.getDescriptor(mt.returnType()));
+ }
+ return this;
+ }
+
+ LoadableDescriptorsAttributeBuilder add(MethodType... mtypes) {
+ for (MethodType mt : mtypes) {
+ add(mt);
+ }
+ return this;
+ }
+
+ boolean requiresLoadableDescriptors(Class<?> cls) {
+ return cls.isValue() && cls.accessFlags().contains(AccessFlag.FINAL);
+ }
+
+ boolean isEmpty() {
+ return loadableDescriptors.isEmpty();
+ }
+
+ Attribute build() {
+ return new Attribute("LoadableDescriptors") {
+ @Override
+ protected ByteVector write(ClassWriter cw,
+ byte[] code,
+ int len,
+ int maxStack,
+ int maxLocals) {
+ ByteVector attr = new ByteVector();
+ attr.putShort(loadableDescriptors.size());
+ for (String s : loadableDescriptors) {
+ attr.putShort(cw.newUTF8(s));
+ }
+ return attr;
+ }
+ };
+ }
+ }
+
static int getParameterSize(Class<?> c) {
if (c == Void.TYPE) {
return 0;
} else if (c == Long.TYPE || c == Double.TYPE) {
return 2;
< prev index next >