--- old/src/java.base/share/classes/java/lang/Class.java 2019-12-03 19:37:18.000000000 -0800 +++ new/src/java.base/share/classes/java/lang/Class.java 2019-12-03 19:37:18.000000000 -0800 @@ -28,6 +28,7 @@ import java.lang.annotation.Annotation; import java.lang.constant.ClassDesc; import java.lang.invoke.TypeDescriptor; +import java.lang.invoke.MethodHandles; import java.lang.module.ModuleReader; import java.lang.ref.SoftReference; import java.io.IOException; @@ -62,8 +63,6 @@ import java.util.Map; import java.util.Objects; import java.util.Optional; -import java.util.StringJoiner; -import java.util.stream.Stream; import java.util.stream.Collectors; import jdk.internal.HotSpotIntrinsicCandidate; @@ -128,6 +127,11 @@ * other members are the classes and interfaces whose declarations are * enclosed within the top-level class declaration. * + *

Some methods of class {@code Class} expose some characteristics of + * hidden classes. Hidden classes are created by calling + * {@link java.lang.invoke.MethodHandles.Lookup#defineHiddenClass(byte[], boolean, MethodHandles.Lookup.ClassOption...) + * Lookup::defineHiddenClass}. + * *

The following example uses a {@code Class} object to print the * class name of an object: * @@ -457,7 +461,7 @@ * @param name The binary name * of the class * @return {@code Class} object of the given name defined in the given module; - * {@code null} if not found. + * {@code null} if not found * * @throws NullPointerException if the given module or name is {@code null} * @@ -786,6 +790,16 @@ * * * + * + *

If this class object represents a {@linkplain #isHiddenClass() hidden class}, + * then the name is defined by the JVM of the following format: + *

+ * {@code + '/' + } + *
+ * where the fully-qualified binary name is the class name in the {@code ClassFile} + * from which this {@code Class} object was derived and the suffix is an unique + * unqualified name as specified in JVMS 4.2.2. + * *

The class or interface name classname is the binary name of * the class specified above. * @@ -803,6 +817,8 @@ * * @return the name of the class or interface * represented by this object. + * + * @jvms 4.2.2 Unqualified Names */ public String getName() { String name = this.name; @@ -1631,7 +1647,7 @@ else return ReflectionData.NULL_SENTINEL; } - if (isLocalOrAnonymousClass()) + if (isHiddenClass() || isLocalOrAnonymousClass()) return ReflectionData.NULL_SENTINEL; Class enclosingClass = getEnclosingClass(); if (enclosingClass == null) { // top level class @@ -1646,7 +1662,8 @@ /** * Returns {@code true} if and only if the underlying class - * is an anonymous class. + * is an anonymous class. An anonymous class is not a + * {@linkplain #isHiddenClass() hidden class}. * * @return {@code true} if and only if this class is an anonymous class. * @since 1.5 @@ -2807,6 +2824,11 @@ if (sm != null) { sm.checkPermission(SecurityConstants.GET_PD_PERMISSION); } + return protectionDomain(); + } + + // package-private + java.security.ProtectionDomain protectionDomain() { java.security.ProtectionDomain pd = getProtectionDomain0(); if (pd == null) { if (allPermDomain == null) { @@ -2821,7 +2843,6 @@ return pd; } - /** * Returns the ProtectionDomain of this class. */ @@ -3913,6 +3934,14 @@ * a member of the nest by the nest host, then it is considered to belong * to its own nest and {@code this} is returned as the host. * + *

If this class is a {@linkplain Class#isHiddenClass() hidden class} + * created by calling + * {@link MethodHandles.Lookup#defineHiddenClass(byte[], boolean, MethodHandles.Lookup.ClassOption...) + * Lookup::defineHiddenClass} with {@link MethodHandles.Lookup.ClassOption#NESTMATE + * NESTMATE} option, then the hidden class is added as a member to + * the nest of a {@linkplain MethodHandles.Lookup#lookupClass() lookup class} + * dynamically and it has the same nest host as the lookup class. + * * @apiNote A {@code class} file of version 55.0 or greater may record the * host of the nest to which it belongs by using the {@code NestHost} * attribute (JVMS 4.7.28). Alternatively, a {@code class} file of @@ -3941,18 +3970,16 @@ if (isPrimitive() || isArray()) { return this; } - Class host; - try { + + Class host = this.nest; + if (host == null) { host = getNestHost0(); - } catch (LinkageError e) { - // if we couldn't load our nest-host then we + // if null then nest membership validation failed, so we // act as-if we have no nest-host attribute - return this; - } - // if null then nest membership validation failed, so we - // act as-if we have no nest-host attribute - if (host == null || host == this) { - return this; + if (host == null || host == this) { + return this.nest = this; + } + this.nest = host; } // returning a different class requires a security check SecurityManager sm = System.getSecurityManager(); @@ -3963,6 +3990,9 @@ return host; } + // keep a strong reference to the nest host + private transient Class nest; + /** * Determines if the given {@code Class} is a nestmate of the * class or interface represented by this {@code Class} object. @@ -3983,11 +4013,8 @@ c.isPrimitive() || c.isArray()) { return false; } - try { - return getNestHost0() == c.getNestHost0(); - } catch (LinkageError e) { - return false; - } + + return getNestHost() == c.getNestHost(); } private native Class[] getNestMembers0(); @@ -4013,6 +4040,13 @@ * interface records itself as a member of that same nest. Any exceptions * that occur during this validation are rethrown by this method. * + * @apiNote + * This method returns the nest members listed in the {@code NestMembers} + * attribute. The returned array does not include any hidden class that + * were added to the nest of this class via + * {@link MethodHandles.Lookup#defineHiddenClass(byte[], boolean, MethodHandles.Lookup.ClassOption...) + * Lookup::defineHiddenClass}. + * * @return an array of all classes and interfaces in the same nest as * this class * @@ -4113,5 +4147,23 @@ @Override public Optional describeConstable() { return Optional.of(ClassDesc.ofDescriptor(descriptorString())); - } + } + + /** + * Returns {@code true} if and only if the underlying class is a hidden class. + * + *

A hidden class is created by calling + * {@link MethodHandles.Lookup#defineHiddenClass(byte[], boolean, MethodHandles.Lookup.ClassOption...) + * Lookup::defineHiddenClass}. A hidden class is non-discoverable + * by name via {@link Class#forName(String) Class::forName}, + * {@link ClassLoader#loadClass(String) ClassLoader::loadClass}, and bytecode linkage. + * + * @return {@code true} if and only if this class is a hidden class. + * + * @since 14 + * @see MethodHandles.Lookup#defineHiddenClass + */ + @HotSpotIntrinsicCandidate + public native boolean isHiddenClass(); + }