--- old/src/java.base/share/classes/java/lang/invoke/MethodHandles.java 2020-03-17 11:31:37.000000000 -0700
+++ new/src/java.base/share/classes/java/lang/invoke/MethodHandles.java 2020-03-17 11:31:36.000000000 -0700
@@ -27,6 +27,7 @@
import jdk.internal.access.JavaLangAccess;
import jdk.internal.access.SharedSecrets;
+import jdk.internal.misc.VM;
import jdk.internal.module.IllegalAccessLogger;
import jdk.internal.org.objectweb.asm.ClassReader;
import jdk.internal.org.objectweb.asm.Opcodes;
@@ -1825,7 +1826,7 @@
*
If the {@code initialize} parameter is {@code true},
* then {@code C} is initialized by the Java Virtual Machine.
*
- *
The newly created class or interface {@code C} is hidden, in the sense that
+ *
The newly created class or interface {@code C} is hidden, in the sense that
* no other class or interface can refer to {@code C} via a constant pool entry.
* That is, a hidden class or interface cannot be named as a supertype, a field type,
* a method parameter type, or a method return type by any other class.
@@ -1840,23 +1841,60 @@
* modifiable} by Java agents or tool agents using the
* JVM Tool Interface.
*
- *
If {@code options} has the {@link ClassOption#NESTMATE NESTMATE} option, then
- * the newly created class or interface {@code C} is a member of a nest. The nest
- * to which {@code C} belongs is not based on any {@code NestHost} attribute in
- * the {@code ClassFile} structure from which {@code C} was derived.
+ *
A class or interface created by
+ * {@linkplain ClassLoader#defineClass(String, byte[], int, int, ProtectionDomain)
+ * a class loader} has a strong relationship with that class loader.
+ * That is, every {@code Class} object contains a reference to the {@code ClassLoader}
+ * that {@linkplain Class#getClassLoader() defined it}.
+ * This means that a class created by a class loader may be unloaded if and
+ * only if its defining loader is not reachable and thus may be reclaimed
+ * by a garbage collector (JLS 12.7).
+ *
+ * By default, however, a hidden class or interface may be unloaded even if
+ * the class loader that is marked as its defining loader is
+ * reachable.
+ * This behavior is useful when a hidden class or interface serves multiple
+ * classes defined by arbitrary class loaders. In other cases, a hidden
+ * class or interface may be linked to a single class (or a small number of classes)
+ * with the same defining loader as the hidden class or interface.
+ * In such cases, where the hidden class or interface must be coterminous
+ * with a normal class or interface, the {@link ClassOption#STRONG STRONG}
+ * option may be passed in {@code options}.
+ * This arranges for a hidden class to have the same strong relationship
+ * with the class loader marked as its defining loader,
+ * as a normal class or interface has with its own defining loader.
+ *
+ * If {@code STRONG} is not used, then the invoker of {@code defineHiddenClass}
+ * may still prevent a hidden class or interface from being
+ * unloaded by ensuring that the {@code Class} object is reachable.
+ *
+ *
The unloading characteristics are set for each hidden class when it is
+ * defined, and cannot be changed later. An advantage of allowing hidden classes
+ * to be unloaded independently of the loader deemed as their defining loader
+ * is that a very large number of hidden classes may be created by an application.
+ * In contrast, if {@code STRONG} is used, then the JVM may run out of memory,
+ * just as if normal classes were created by class loaders.
+ *
+ *
Classes and interfaces in a nest are allowed to have mutual access to
+ * their private members. The nest relationship is determined by
+ * the {@code NestHost} attribute (JVMS 4.7.28) and
+ * the {@code NestMembers} attribute (JVMS 4.7.29) in a {@code class} file.
+ * By default, a hidden class belongs to a nest consisting only of itself
+ * because a hidden class has no binary name.
+ * The {@link ClassOption#NESTMATE NESTMATE} option can be passed in {@code options}
+ * to create a hidden class or interface {@code C} as a member of a nest.
+ * The nest to which {@code C} belongs is not based on any {@code NestHost} attribute
+ * in the {@code ClassFile} structure from which {@code C} was derived.
* Instead, the following rules determine the nest host of {@code C}:
*
* - If the nest host of the lookup class of this {@code Lookup} has previously
- * been determined, then {@code H} be the nest host of the lookup class.
- * - Otherwise, it is determined using the algorithm in JVMS 5.4.4, yielding {@code H}.
- * - The nest host of {@code C} is determined to be {@code H}, the nest host of the lookup class.
+ * been determined, then let {@code H} be the nest host of the lookup class.
+ * Otherwise, the nest host of the lookup class is determined using the
+ * algorithm in JVMS 5.4.4, yielding {@code H}.
+ * - The nest host of {@code C} is determined to be {@code H},
+ * the nest host of the lookup class.
*
*
- * If {@code options} has {@link ClassOption#WEAK WEAK} option, then
- * the newly created class or interface is not strongly referenced from
- * its defining class loader. Therefore, it may be unloaded while
- * its defining class loader is strongly reachable.
- *
*
A hidden class or interface may be serializable, but this requires a custom
* serialization mechanism in order to ensure that instances are properly serialized
* and deserialized. The default serialization mechanism supports only classes and
@@ -1890,11 +1928,14 @@
* @see Class#isHiddenClass()
* @jvms 4.2.1 Binary Class and Interface Names
* @jvms 4.2.2 Unqualified Names
+ * @jvms 4.7.28 The {@code NestHost} Attribute
+ * @jvms 4.7.29 The {@code NestMembers} Attribute
* @jvms 5.4.3.1 Class and Interface Resolution
* @jvms 5.4.4 Access Control
* @jvms 5.3.5 Deriving a {@code Class} from a {@code class} File Representation
* @jvms 5.4 Linking
* @jvms 5.5 Initialization
+ * @jls 12.7 Unloading of Classes and Interfaces
*/
public Lookup defineHiddenClass(byte[] bytes, boolean initialize, ClassOption... options)
throws IllegalAccessException
@@ -1908,7 +1949,7 @@
}
Set opts = options.length > 0 ? Set.of(options) : Set.of();
- return makeHiddenClassDefiner(bytes.clone(), opts).defineClassAsLookup(initialize);
+ return makeHiddenClassDefiner(bytes.clone(), opts, false).defineClassAsLookup(initialize);
}
/**
@@ -1961,34 +2002,81 @@
}
Set opts = options.length > 0 ? Set.of(options) : Set.of();
- return makeHiddenClassDefiner(bytes.clone(), opts).defineClassAsLookup(initialize, classData);
+ return makeHiddenClassDefiner(bytes.clone(), opts, false)
+ .defineClassAsLookup(initialize, classData);
}
private ClassDefiner makeClassDefiner(byte[] bytes) {
- return new ClassDefiner(this, bytes, Set.of(), 0);
+ return new ClassDefiner(this, bytes, STRONG_LOADER_LINK);
}
/**
* Returns a ClassDefiner that creates a {@code Class} object of a hidden class
- * from the given bytes and options.
+ * from the given bytes.
*
- * @param bytes class bytes
+ * @param bytes class bytes
+ * @return ClassDefiner that defines a hidden class of the given bytes.
+ */
+ ClassDefiner makeHiddenClassDefiner(byte[] bytes) {
+ return makeHiddenClassDefiner(bytes, Set.of(), false);
+ }
+
+ /**
+ * Returns a ClassDefiner that creates a {@code Class} object of a hidden class
+ * from the given bytes.
+ *
+ * @param name fully-qualified name that specifies the prefix of the hidden class
+ * @param bytes class bytes
+ * @return ClassDefiner that defines a hidden class of the given bytes.
+ */
+ ClassDefiner makeHiddenClassDefiner(String name, byte[] bytes) {
+ return makeHiddenClassDefiner(name, bytes, Set.of(), false);
+ }
+
+ /**
+ * Returns a ClassDefiner that creates a {@code Class} object of a hidden class
+ * from the given bytes and options. This method will read the class file
+ * and obtain the class name.
+ *
+ * @param bytes class bytes
* @param options class options
+ * @param accessVmAnnotations true to give the hidden class access to VM annotations
* @return ClassDefiner that defines a hidden class of the given bytes and options
*/
- ClassDefiner makeHiddenClassDefiner(byte[] bytes, Set options) {
- return new ClassDefiner(this, bytes, options, HIDDEN_CLASS);
+ ClassDefiner makeHiddenClassDefiner(byte[] bytes,
+ Set options,
+ boolean accessVmAnnotations) {
+ int flags = HIDDEN_CLASS | ClassOption.optionsToFlag(options);
+ if (accessVmAnnotations | VM.isSystemDomainLoader(lookupClass.getClassLoader())) {
+ // jdk.internal.vm.annotations are permitted for classes
+ // defined to boot loader and platform loader
+ flags |= ACCESS_VM_ANNOTATIONS;
+ }
+
+ return new ClassDefiner(this, bytes, flags);
}
/**
- * This method is only called by MethodHandleImpl.BindCaller.makeInjectedInvoker.
+ * Returns a ClassDefiner that creates a {@code Class} object of a hidden class
+ * from the given bytes and options.
*
* @param name the name of the class and the name in the class bytes is ignored.
* @param bytes class bytes
- * @return ClassDefiner that defines a hidden class of the given bytes
+ * @param options class options
+ * @param accessVmAnnotations true to give the hidden class access to VM annotations
*/
- ClassDefiner makeHiddenClassDefiner(String name, byte[] bytes, int flags) {
- return new ClassDefiner(this, name, bytes, HIDDEN_CLASS|flags);
+ ClassDefiner makeHiddenClassDefiner(String name,
+ byte[] bytes,
+ Set options,
+ boolean accessVmAnnotations) {
+ int flags = HIDDEN_CLASS | ClassOption.optionsToFlag(options);
+ if (accessVmAnnotations | VM.isSystemDomainLoader(lookupClass.getClassLoader())) {
+ // jdk.internal.vm.annotations are permitted for classes
+ // defined to boot loader and platform loader
+ flags |= ACCESS_VM_ANNOTATIONS;
+ }
+
+ return new ClassDefiner(this, name, bytes, flags);
}
static class ClassDefiner {
@@ -1999,10 +2087,12 @@
// caller should make a defensive copy of the arguments if needed
// before calling this constructor
- private ClassDefiner(Lookup lookup, byte[] bytes, Set options, int flags) {
+ private ClassDefiner(Lookup lookup, byte[] bytes, int flags) {
+ // defining an ordinary class which must be a strongly referenced by its defining loader
+ assert ((flags & HIDDEN_CLASS) != 0 || (flags & STRONG_LOADER_LINK) == STRONG_LOADER_LINK);
this.lookup = lookup;
this.bytes = bytes;
- this.classFlags = flags | ClassOption.optionsToFlag(options);
+ this.classFlags = flags;
this.name = className(bytes);
int index = name.lastIndexOf('.');
@@ -2015,6 +2105,7 @@
// skip package name check
private ClassDefiner(Lookup lookup, String name, byte[] bytes, int flags) {
+ assert ((flags & HIDDEN_CLASS) != 0 || (flags & STRONG_LOADER_LINK) == STRONG_LOADER_LINK);
this.lookup = lookup;
this.bytes = bytes;
this.classFlags = flags;
@@ -3741,10 +3832,9 @@
/**
* The set of class options that specify whether a hidden class created by
* {@link Lookup#defineHiddenClass(byte[], boolean, ClassOption...)
- * Lookup::defineHiddenMethod} method is dynamically added as
- * a new member to the nest of a lookup class and whether a hidden class
- * is weak such that it may be unloaded while its defining class loader
- * is strongly reachable.
+ * Lookup::defineHiddenClass} method is dynamically added as a new member
+ * to the nest of a lookup class and/or whether a hidden class has
+ * a strong relationship with the class loader marked as its defining loader.
*
* @since 15
*/
@@ -3762,14 +3852,22 @@
NESTMATE(NESTMATE_CLASS),
/**
- * This class option specifies the hidden class be weak so that
- * the class is not strongly referenced by its defining class loader.
- * A weak class may be unloaded while its defining class loader is
- * strongly reachable.
+ *
+ * This class option specifies the hidden class to have a strong
+ * relationship with the class loader marked as its defining loader,
+ * as a normal class or interface has with its own defining loader.
+ * This means that the hidden class may be unloaded if and only if
+ * its defining loader is not reachable and thus may be reclaimed
+ * by a garbage collector (JLS 12.7).
+ *
+ * By default, a hidden class or interface may be unloaded
+ * even if the class loader that is marked as its defining loader is
+ * reachable.
+
*
* @jls 12.7 Unloading of Classes and Interfaces
*/
- WEAK(WEAK_CLASS);
+ STRONG(STRONG_LOADER_LINK);
/* the flag value is used by VM at define class time */
private final int flag;