< prev index next >
src/java.base/share/classes/java/lang/invoke/MethodHandles.java
Print this page
*** 25,34 ****
--- 25,35 ----
package java.lang.invoke;
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;
import jdk.internal.reflect.CallerSensitive;
import jdk.internal.reflect.Reflection;
*** 1823,1833 ****
* </ul>
*
* <p> If the {@code initialize} parameter is {@code true},
* then {@code C} is initialized by the Java Virtual Machine.
*
! * <p>The newly created class or interface {@code C} is <em>hidden</em>, 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.
* This is because a hidden class or interface does not have a binary name, so
* there is no internal form available to record in any class's constant pool.
--- 1824,1834 ----
* </ul>
*
* <p> If the {@code initialize} parameter is {@code true},
* then {@code C} is initialized by the Java Virtual Machine.
*
! * <p> The newly created class or interface {@code C} is <em>hidden</em>, 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.
* This is because a hidden class or interface does not have a binary name, so
* there is no internal form available to record in any class's constant pool.
*** 1838,1864 ****
* {@link ClassLoader#loadClass(String, boolean)}, or {@link #findClass(String)}, and
* is not {@linkplain java.lang.instrument.Instrumentation#isModifiableClass(Class)
* modifiable} by Java agents or tool agents using the <a href="{@docRoot}/../specs/jvmti.html">
* JVM Tool Interface</a>.
*
! * <p> 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.
* Instead, the following rules determine the nest host of {@code C}:
* <ul>
* <li>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.</li>
! * <li>Otherwise, it is determined using the algorithm in JVMS 5.4.4, yielding {@code H}.</li>
! * <li>The nest host of {@code C} is determined to be {@code H}, the nest host of the lookup class.</li>
* </ul>
*
- * <p> If {@code options} has {@link ClassOption#WEAK WEAK} option, then
- * the newly created class or interface is <em>not strongly referenced</em> from
- * its defining class loader. Therefore, it may be unloaded while
- * its defining class loader is strongly reachable.
- *
* <p> 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
* interfaces that are discoverable by their class name.
*
--- 1839,1902 ----
* {@link ClassLoader#loadClass(String, boolean)}, or {@link #findClass(String)}, and
* is not {@linkplain java.lang.instrument.Instrumentation#isModifiableClass(Class)
* modifiable} by Java agents or tool agents using the <a href="{@docRoot}/../specs/jvmti.html">
* JVM Tool Interface</a>.
*
! * <p> 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
! * <a href="../ref/package.html#reachability">reachable</a>.
! * 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.
! *
! * <p> 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.
! *
! * <p> 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}:
* <ul>
* <li>If the nest host of the lookup class of this {@code Lookup} has previously
! * 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}.</li>
! * <li>The nest host of {@code C} is determined to be {@code H},
! * the nest host of the lookup class.</li>
* </ul>
*
* <p> 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
* interfaces that are discoverable by their class name.
*
*** 1888,1902 ****
--- 1926,1943 ----
*
* @since 15
* @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
{
Objects.requireNonNull(bytes);
*** 1906,1916 ****
if (!hasFullPrivilegeAccess()) {
throw new IllegalAccessException(this + " does not have full privilege access");
}
Set<ClassOption> opts = options.length > 0 ? Set.of(options) : Set.of();
! return makeHiddenClassDefiner(bytes.clone(), opts).defineClassAsLookup(initialize);
}
/**
* Creates a <em>hidden</em> class or interface from {@code bytes} with {@code classData},
* returning a {@code Lookup} on the newly created class or interface.
--- 1947,1957 ----
if (!hasFullPrivilegeAccess()) {
throw new IllegalAccessException(this + " does not have full privilege access");
}
Set<ClassOption> opts = options.length > 0 ? Set.of(options) : Set.of();
! return makeHiddenClassDefiner(bytes.clone(), opts, false).defineClassAsLookup(initialize);
}
/**
* Creates a <em>hidden</em> class or interface from {@code bytes} with {@code classData},
* returning a {@code Lookup} on the newly created class or interface.
*** 1959,2010 ****
if (!hasFullPrivilegeAccess()) {
throw new IllegalAccessException(this + " does not have full privilege access");
}
Set<ClassOption> opts = options.length > 0 ? Set.of(options) : Set.of();
! return makeHiddenClassDefiner(bytes.clone(), opts).defineClassAsLookup(initialize, classData);
}
private ClassDefiner makeClassDefiner(byte[] bytes) {
! return new ClassDefiner(this, bytes, Set.of(), 0);
}
/**
* Returns a ClassDefiner that creates a {@code Class} object of a hidden class
! * from the given bytes and options.
*
* @param bytes class bytes
* @param options class options
* @return ClassDefiner that defines a hidden class of the given bytes and options
*/
! ClassDefiner makeHiddenClassDefiner(byte[] bytes, Set<ClassOption> options) {
! return new ClassDefiner(this, bytes, options, HIDDEN_CLASS);
}
/**
! * This method is only called by MethodHandleImpl.BindCaller.makeInjectedInvoker.
*
* @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
*/
! ClassDefiner makeHiddenClassDefiner(String name, byte[] bytes, int flags) {
! return new ClassDefiner(this, name, bytes, HIDDEN_CLASS|flags);
}
static class ClassDefiner {
private final Lookup lookup;
private final String name;
private final byte[] bytes;
private final int classFlags;
// caller should make a defensive copy of the arguments if needed
// before calling this constructor
! private ClassDefiner(Lookup lookup, byte[] bytes, Set<ClassOption> options, int flags) {
this.lookup = lookup;
this.bytes = bytes;
! this.classFlags = flags | ClassOption.optionsToFlag(options);
this.name = className(bytes);
int index = name.lastIndexOf('.');
String pn = (index == -1) ? "" : name.substring(0, index);
if (!pn.equals(lookup.lookupClass().getPackageName())) {
--- 2000,2100 ----
if (!hasFullPrivilegeAccess()) {
throw new IllegalAccessException(this + " does not have full privilege access");
}
Set<ClassOption> opts = options.length > 0 ? Set.of(options) : Set.of();
! return makeHiddenClassDefiner(bytes.clone(), opts, false)
! .defineClassAsLookup(initialize, classData);
}
private ClassDefiner makeClassDefiner(byte[] bytes) {
! 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.
! *
! * @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<ClassOption> 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);
}
/**
! * 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
! * @param options class options
! * @param accessVmAnnotations true to give the hidden class access to VM annotations
*/
! ClassDefiner makeHiddenClassDefiner(String name,
! byte[] bytes,
! Set<ClassOption> 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 {
private final Lookup lookup;
private final String name;
private final byte[] bytes;
private final int classFlags;
// caller should make a defensive copy of the arguments if needed
// before calling this constructor
! 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;
this.name = className(bytes);
int index = name.lastIndexOf('.');
String pn = (index == -1) ? "" : name.substring(0, index);
if (!pn.equals(lookup.lookupClass().getPackageName())) {
*** 2013,2022 ****
--- 2103,2113 ----
}
}
// 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;
this.name = name;
}
*** 3739,3752 ****
static ConcurrentHashMap<MemberName, DirectMethodHandle> LOOKASIDE_TABLE = new ConcurrentHashMap<>();
/**
* 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 <a href="../ref/package.html#reachability">strongly reachable</a>.
*
* @since 15
*/
public enum ClassOption {
/**
--- 3830,3842 ----
static ConcurrentHashMap<MemberName, DirectMethodHandle> LOOKASIDE_TABLE = new ConcurrentHashMap<>();
/**
* The set of class options that specify whether a hidden class created by
* {@link Lookup#defineHiddenClass(byte[], boolean, ClassOption...)
! * 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
*/
public enum ClassOption {
/**
*** 3760,3777 ****
* @see Class#getNestHost()
*/
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
! * <a href="../ref/package.html#reachability">strongly reachable</a>.
*
* @jls 12.7 Unloading of Classes and Interfaces
*/
! WEAK(WEAK_CLASS);
/* the flag value is used by VM at define class time */
private final int flag;
ClassOption(int flag) {
this.flag = flag;
--- 3850,3875 ----
* @see Class#getNestHost()
*/
NESTMATE(NESTMATE_CLASS),
/**
! *
! * This class option specifies the hidden class to have a <em>strong</em>
! * 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).
! *
! * <p> By default, a hidden class or interface may be unloaded
! * even if the class loader that is marked as its defining loader is
! * <a href="../ref/package.html#reachability">reachable</a>.
!
*
* @jls 12.7 Unloading of Classes and Interfaces
*/
! STRONG(STRONG_LOADER_LINK);
/* the flag value is used by VM at define class time */
private final int flag;
ClassOption(int flag) {
this.flag = flag;
< prev index next >