< 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 >