< prev index next >

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

Print this page
*** 23,20 ***
--- 23,22 ---
   * 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.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++) {
--- 314,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 ***
--- 353,20 ---
          if (isSerializable)
              generateSerializationFriendlyMethods();
          else if (accidentallySerializable)
              generateSerializationHostileMethods();
  
+         // generate Preload attribute if it references any value class
+         PreloadAttributeBuilder builder = new PreloadAttributeBuilder(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 ***
--- 577,76 ---
                  default -> throw new InternalError("Unexpected invocation kind: " + implKind);
              };
          }
      }
  
+     /*
+      * Preload attribute builder
+      */
+     static class PreloadAttributeBuilder {
+         private final Set<Class<?>> preloadClasses = new HashSet<>();
+         PreloadAttributeBuilder(Class<?> targetClass) {
+             if (requiresPreload(targetClass)) {
+                 preloadClasses.add(targetClass);
+             }
+         }
+ 
+         /*
+          * Add the value types referenced in the given MethodType.
+          */
+         PreloadAttributeBuilder add(MethodType mt) {
+             // parameter types
+             for (Class<?> paramType : mt.ptypes()) {
+                 if (requiresPreload(paramType)) {
+                     preloadClasses.add(paramType);
+                 }
+             }
+             // return type
+             if (requiresPreload(mt.returnType())) {
+                 preloadClasses.add(mt.returnType());
+             }
+             return this;
+         }
+ 
+         PreloadAttributeBuilder add(MethodType... mtypes) {
+             for (MethodType mt : mtypes) {
+                 add(mt);
+             }
+             return this;
+         }
+ 
+         boolean requiresPreload(Class<?> cls) {
+             Class<?> c = cls;
+             while (c.isArray()) {
+                 c = c.getComponentType();
+             }
+             return c.isValue();
+         }
+ 
+         boolean isEmpty() {
+             return preloadClasses.isEmpty();
+         }
+ 
+         Attribute build() {
+             return new Attribute("Preload") {
+                 @Override
+                 protected ByteVector write(ClassWriter cw,
+                                            byte[] code,
+                                            int len,
+                                            int maxStack,
+                                            int maxLocals) {
+                     ByteVector attr = new ByteVector();
+                     attr.putShort(preloadClasses.size());
+                     for (Class<?> c : preloadClasses) {
+                         attr.putShort(cw.newClass(Type.getInternalName(c)));
+                     }
+                     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 >