--- 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 {@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;