< prev index next >

src/java.base/share/classes/java/lang/invoke/InnerClassLambdaMetafactory.java

Print this page
*** 23,20 ***
--- 23,23 ---
   * 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;

*** 312,11 ***
                  accidentallySerializable |= !isSerializable && Serializable.class.isAssignableFrom(i);
              }
              interfaceNames = itfs.toArray(new String[itfs.size()]);
          }
  
!         cw.visit(CLASSFILE_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++) {
--- 315,12 ---
                  accidentallySerializable |= !isSerializable && Serializable.class.isAssignableFrom(i);
              }
              interfaceNames = itfs.toArray(new String[itfs.size()]);
          }
  
!         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++) {

*** 350,10 ***
--- 354,22 ---
          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();

*** 564,10 ***
--- 580,72 ---
                  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 >