< 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.JavaLangAccess;
+import jdk.internal.misc.SharedSecrets;
 import jdk.internal.org.objectweb.asm.*;
 import sun.invoke.util.BytecodeDescriptor;
 import jdk.internal.misc.Unsafe;
 import sun.security.action.GetPropertyAction;
 
 import java.io.FilePermission;
 import java.io.Serializable;
 import java.lang.reflect.Constructor;
 import java.security.AccessController;
 import java.security.PrivilegedAction;
+import java.util.HashSet;
 import java.util.LinkedHashSet;
 import java.util.concurrent.atomic.AtomicInteger;
 import java.util.PropertyPermission;
 import java.util.Set;
 

@@ -48,10 +51,11 @@
  *
  * @see LambdaMetafactory
  */
 /* package */ final class InnerClassLambdaMetafactory extends AbstractValidatingLambdaMetafactory {
     private static final Unsafe UNSAFE = Unsafe.getUnsafe();
+    private static final JavaLangAccess JLA = SharedSecrets.getJavaLangAccess();
 
     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>";

@@ -295,10 +299,22 @@
         if (isSerializable)
             generateSerializationFriendlyMethods();
         else if (accidentallySerializable)
             generateSerializationHostileMethods();
 
+        // add ValueTypes attribute
+        Set<String> valueTypeNames = JLA.getDeclaredValueTypeNames(targetClass);
+        if (!valueTypeNames.isEmpty()) {
+            ValueTypesAttributeBuilder builder = new ValueTypesAttributeBuilder(valueTypeNames);
+            builder.add(invokedType)
+                   .add(samMethodType)
+                   .add(implMethodType)
+                   .add(instantiatedMethodType)
+                   .add(additionalBridges);
+            if (!builder.isEmpty())
+                cw.visitAttribute(builder.build());
+        }
         cw.visitEnd();
 
         // Define the generated class in this VM.
 
         final byte[] classBytes = cw.toByteArray();

@@ -543,6 +559,68 @@
         } else {
             return 4;
         }
     }
 
+    /*
+     * Build ValueTypes attribute
+     */
+    static class ValueTypesAttributeBuilder {
+        private final Set<String> declaredValueTypes;
+        private final Set<String> valueTypes;
+        ValueTypesAttributeBuilder(Set<String> valueTypeNames) {
+            this.declaredValueTypes = valueTypeNames;
+            this.valueTypes = new HashSet<>();
+        }
+
+        /*
+         * Add the value types referenced in the given MethodType.
+         */
+        ValueTypesAttributeBuilder add(MethodType mt) {
+            // parameter types
+            for (Class<?> paramType : mt.ptypes()) {
+                if (isDeclaredValueType(paramType))
+                    valueTypes.add(paramType.getName());
+            }
+            // return type
+            if (isDeclaredValueType(mt.returnType()))
+                valueTypes.add(mt.returnType().getName());
+            return this;
+        }
+
+        ValueTypesAttributeBuilder add(MethodType... mtypes) {
+            for (MethodType mt : mtypes) {
+                add(mt);
+            }
+            return this;
+        }
+
+        boolean isDeclaredValueType(Class<?> c) {
+            while (c.isArray())
+                c = c.getComponentType();
+            return declaredValueTypes.contains(c.getName());
+        }
+
+        boolean isEmpty() {
+            return valueTypes.isEmpty();
+        }
+
+        Attribute build() {
+            return new Attribute("ValueTypes") {
+                @Override
+                protected ByteVector write(ClassWriter cw,
+                                           byte[] code,
+                                           int len,
+                                           int maxStack,
+                                           int maxLocals) {
+                    ByteVector attr = new ByteVector();
+                    attr.putShort(valueTypes.size());
+                    for (String cn : valueTypes) {
+                        attr.putShort(cw.newClass(cn.replace('.', '/')));
+                    }
+                    return attr;
+                }
+            };
+        }
+    }
+
 }
< prev index next >