changeset 59288:65bc09903227 nestmates

[nestmates] defineHiddenClassWithClassData always invokes <clinit>
author mchung
date Fri, 20 Mar 2020 14:26:50 -0700
parents bc0cdc243ca0
children 40c00294e1df
files src/java.base/share/classes/java/lang/invoke/MethodHandles.java test/jdk/java/lang/invoke/defineHiddenClass/DefineClassWithClassData.java test/jdk/java/lang/invoke/nestmates/NestmateTest.java
diffstat 3 files changed, 28 insertions(+), 22 deletions(-) [+]
line wrap: on
line diff
--- a/src/java.base/share/classes/java/lang/invoke/MethodHandles.java	Fri Mar 20 14:25:29 2020 -0700
+++ b/src/java.base/share/classes/java/lang/invoke/MethodHandles.java	Fri Mar 20 14:26:50 2020 -0700
@@ -272,7 +272,7 @@
      * of the specified {@code Lookup} object, or {@code null}.
      *
      * <p> Classes can be created with class data by calling
-     * {@link Lookup#defineHiddenClassWithClassData(byte[], Object, boolean, Lookup.ClassOption...)
+     * {@link Lookup#defineHiddenClassWithClassData(byte[], Object, Lookup.ClassOption...)
      * Lookup::defineHiddenClassWithClassData}.
      * A hidden class with a class data behaves as if the hidden class
      * has a private static final unnamed field pre-initialized with
@@ -307,7 +307,7 @@
      * original caller access
      * @throws ClassCastException if the class data cannot be converted to
      * the specified {@code type}
-     * @see Lookup#defineHiddenClassWithClassData(byte[], Object, boolean, Lookup.ClassOption...)
+     * @see Lookup#defineHiddenClassWithClassData(byte[], Object, Lookup.ClassOption...)
      * @since 15
      */
     public static <T> T classData(Lookup caller, String name, Class<T> type) throws IllegalAccessException {
@@ -1956,19 +1956,22 @@
         }
 
         /**
-         * Creates a <em>hidden</em> class or interface from {@code bytes} with {@code classData},
+         * Creates a <em>hidden</em> class or interface from {@code bytes} with associated
+         * {@linkplain MethodHandles#classData(Lookup, String, Class) class data},
          * returning a {@code Lookup} on the newly created class or interface.
          *
          * <p> This method is equivalent to calling
-         * {@link #defineHiddenClass(byte[], boolean, ClassOption...) defineHiddenClass(bytes, initialize, options)}
-         * as if the hidden class has a private static final unnamed field
-         * pre-initialized with the given {@code classData}.
-         * The {@link MethodHandles#classData(Lookup, String, Class) MethodHandles::classData} method
-         * can be used to retrieve the {@code classData}.
+         * {@link #defineHiddenClass(byte[], boolean, ClassOption...) defineHiddenClass(bytes, true, options)}
+         * as if the hidden class has a private static final unnamed field whose value
+         * is initialized to {@code classData} right before the class initializer is
+         * executed.  The newly created class is linked and initialized by the Java
+         * Virtual Machine.
+         *
+         * <p> The {@link MethodHandles#classData(Lookup, String, Class) MethodHandles::classData}
+         * method can be used to retrieve the {@code classData}.
          *
          * @param bytes     the class bytes
          * @param classData pre-initialized class data
-         * @param initialize if {@code true} the class will be initialized.
          * @param options   {@linkplain ClassOption class options}
          * @return the {@code Lookup} object on the hidden class
          *
@@ -1980,10 +1983,11 @@
          * @throws UnsupportedClassVersionError if {@code bytes} is not of a supported major or minor version
          * @throws IllegalArgumentException if {@code bytes} is not a class or interface or
          * {@bytes} denotes a class in a different package than the lookup class
-         * @throws IncompatibleClassChangeError if the class or interface named as the direct superclass of {@code C}
-         * is in fact an interface, or if any of the classes or interfaces named as direct superinterfaces of {@code C}
-         * are not in fact interfaces
-         * @throws ClassCircularityError if any of the superclasses or superinterfaces of {@code C} is {@code C} itself
+         * @throws IncompatibleClassChangeError if the class or interface named as
+         * the direct superclass of {@code C} is in fact an interface, or if any of the classes
+         * or interfaces named as direct superinterfaces of {@code C} are not in fact interfaces
+         * @throws ClassCircularityError if any of the superclasses or superinterfaces of
+         * {@code C} is {@code C} itself
          * @throws VerifyError if the newly created class cannot be verified
          * @throws LinkageError if the newly created class cannot be linked for any other reason
          * @throws NullPointerException if any parameter is {@code null}
@@ -1992,7 +1996,7 @@
          * @see Lookup#defineHiddenClass(byte[], boolean, ClassOption...)
          * @see Class#isHiddenClass()
          */
-        public Lookup defineHiddenClassWithClassData(byte[] bytes, Object classData, boolean initialize, ClassOption... options)
+        public Lookup defineHiddenClassWithClassData(byte[] bytes, Object classData, ClassOption... options)
                 throws IllegalAccessException
         {
             Objects.requireNonNull(bytes);
@@ -2006,7 +2010,7 @@
 
             Set<ClassOption> opts = options.length > 0 ? Set.of(options) : Set.of();
             return makeHiddenClassDefiner(bytes.clone(), opts, false)
-                       .defineClassAsLookup(initialize, classData);
+                       .defineClassAsLookup(true, classData);
         }
 
         private ClassDefiner makeClassDefiner(byte[] bytes) {
@@ -2148,6 +2152,8 @@
             }
 
             Lookup defineClassAsLookup(boolean initialize, Object classData) {
+                // initialize must be true if classData is non-null
+                assert classData == null || initialize == true;
                 Class<?> c = defineClass(initialize, classData);
                 return new Lookup(c, null, FULL_POWER_MODES);
             }
--- a/test/jdk/java/lang/invoke/defineHiddenClass/DefineClassWithClassData.java	Fri Mar 20 14:25:29 2020 -0700
+++ b/test/jdk/java/lang/invoke/defineHiddenClass/DefineClassWithClassData.java	Fri Mar 20 14:26:50 2020 -0700
@@ -80,7 +80,7 @@
     @Test
     public void defineNestMate() throws Throwable {
         // define a nestmate
-        Lookup lookup = MethodHandles.lookup().defineHiddenClassWithClassData(T_CLASS_BYTES, classData, true, NESTMATE);
+        Lookup lookup = MethodHandles.lookup().defineHiddenClassWithClassData(T_CLASS_BYTES, classData, NESTMATE);
         Class<?> c = lookup.lookupClass();
         assertTrue(c.getNestHost() == DefineClassWithClassData.class);
         assertEquals(classData, injectedData(c));
@@ -97,7 +97,7 @@
     @Test
     public void defineHiddenClass() throws Throwable {
         // define a hidden class
-        Lookup lookup = MethodHandles.lookup().defineHiddenClassWithClassData(T_CLASS_BYTES, classData, false, NESTMATE);
+        Lookup lookup = MethodHandles.lookup().defineHiddenClassWithClassData(T_CLASS_BYTES, classData, NESTMATE);
         Class<?> c = lookup.lookupClass();
         assertTrue(c.getNestHost() == DefineClassWithClassData.class);
         assertTrue(c.isHiddenClass());
@@ -114,7 +114,7 @@
 
     @Test
     public void defineStrongClass() throws Throwable {
-        Lookup lookup = MethodHandles.lookup().defineHiddenClassWithClassData(T_CLASS_BYTES, classData, true, STRONG);
+        Lookup lookup = MethodHandles.lookup().defineHiddenClassWithClassData(T_CLASS_BYTES, classData, STRONG);
         Class<?> c = lookup.lookupClass();
         assertTrue(c.getNestHost() == c);
         assertTrue(c.isHiddenClass());
@@ -123,13 +123,13 @@
     @Test(expectedExceptions = IllegalAccessException.class)
     public void noPrivateLookupAccess() throws Throwable {
         Lookup lookup = MethodHandles.lookup().dropLookupMode(Lookup.PRIVATE);
-        lookup.defineHiddenClassWithClassData(T2_CLASS_BYTES, classData, false, NESTMATE);
+        lookup.defineHiddenClassWithClassData(T2_CLASS_BYTES, classData, NESTMATE);
     }
 
     @Test
     public void teleportToNestmate() throws Throwable {
         Lookup lookup = MethodHandles.lookup()
-            .defineHiddenClassWithClassData(T_CLASS_BYTES, classData, false, NESTMATE);
+            .defineHiddenClassWithClassData(T_CLASS_BYTES, classData, NESTMATE);
         Class<?> c = lookup.lookupClass();
         assertTrue(c.getNestHost() == DefineClassWithClassData.class);
         assertEquals(classData, injectedData(c));
@@ -138,7 +138,7 @@
         // Teleport to a nestmate
         Lookup lookup2 =  MethodHandles.lookup().in(DefineClassWithClassData.class);
         assertTrue((lookup2.lookupModes() & PRIVATE) != 0);
-        Lookup lc = lookup2.defineHiddenClassWithClassData(T2_CLASS_BYTES, classData, false, NESTMATE);
+        Lookup lc = lookup2.defineHiddenClassWithClassData(T2_CLASS_BYTES, classData, NESTMATE);
         assertTrue(lc.lookupClass().getNestHost() == DefineClassWithClassData.class);
         assertTrue(lc.lookupClass().isHiddenClass());
     }
--- a/test/jdk/java/lang/invoke/nestmates/NestmateTest.java	Fri Mar 20 14:25:29 2020 -0700
+++ b/test/jdk/java/lang/invoke/nestmates/NestmateTest.java	Fri Mar 20 14:26:50 2020 -0700
@@ -137,7 +137,7 @@
         Path path = Paths.get(System.getProperty("test.classes"), "Invoker.class");
         byte[] bytes = Files.readAllBytes(path);
         Lookup lookup = MyThreadLocal.lookup()
-                .defineHiddenClassWithClassData(bytes, mh.bindTo(tl), false, ClassOption.NESTMATE);
+                .defineHiddenClassWithClassData(bytes, mh.bindTo(tl), ClassOption.NESTMATE);
         Class<?> hiddenClass = lookup.lookupClass();
         assertTrue(hiddenClass.isHiddenClass());