< prev index next >

src/java.base/share/classes/java/lang/invoke/MethodHandles.java

Print this page

        

*** 23,32 **** --- 23,33 ---- * questions. */ package java.lang.invoke; + import jdk.internal.access.JavaLangAccess; import jdk.internal.access.SharedSecrets; import jdk.internal.module.IllegalAccessLogger; import jdk.internal.org.objectweb.asm.ClassReader; import jdk.internal.reflect.CallerSensitive; import jdk.internal.reflect.Reflection;
*** 43,66 **** import java.lang.reflect.Member; import java.lang.reflect.Method; import java.lang.reflect.Modifier; import java.lang.reflect.ReflectPermission; import java.nio.ByteOrder; - import java.security.AccessController; - import java.security.PrivilegedAction; import java.security.ProtectionDomain; import java.util.ArrayList; import java.util.Arrays; import java.util.BitSet; import java.util.Iterator; import java.util.List; import java.util.Objects; import java.util.Set; import java.util.concurrent.ConcurrentHashMap; import java.util.stream.Collectors; import java.util.stream.Stream; import static java.lang.invoke.MethodHandleImpl.Intrinsic; import static java.lang.invoke.MethodHandleNatives.Constants.*; import static java.lang.invoke.MethodHandleStatics.newIllegalArgumentException; import static java.lang.invoke.MethodType.methodType; --- 44,67 ---- import java.lang.reflect.Member; import java.lang.reflect.Method; import java.lang.reflect.Modifier; import java.lang.reflect.ReflectPermission; import java.nio.ByteOrder; import java.security.ProtectionDomain; import java.util.ArrayList; import java.util.Arrays; import java.util.BitSet; import java.util.Iterator; import java.util.List; import java.util.Objects; import java.util.Set; + import java.util.WeakHashMap; import java.util.concurrent.ConcurrentHashMap; import java.util.stream.Collectors; import java.util.stream.Stream; + import static java.lang.invoke.MethodHandles.Lookup.ClassProperty.*; import static java.lang.invoke.MethodHandleImpl.Intrinsic; import static java.lang.invoke.MethodHandleNatives.Constants.*; import static java.lang.invoke.MethodHandleStatics.newIllegalArgumentException; import static java.lang.invoke.MethodType.methodType;
*** 178,196 **** * shared with trusted parties without giving away {@code PRIVATE} and {@code PACKAGE} * access to the caller. * @param targetClass the target class * @param lookup the caller lookup object * @return a lookup object for the target class, with private access ! * @throws IllegalArgumentException if {@code targetClass} is a primitve type or array class * @throws NullPointerException if {@code targetClass} or {@code caller} is {@code null} * @throws IllegalAccessException if the access check specified above fails * @throws SecurityException if denied by the security manager * @since 9 * @spec JPMS * @see Lookup#dropLookupMode */ public static Lookup privateLookupIn(Class<?> targetClass, Lookup lookup) throws IllegalAccessException { SecurityManager sm = System.getSecurityManager(); if (sm != null) sm.checkPermission(ACCESS_PERMISSION); if (targetClass.isPrimitive()) throw new IllegalArgumentException(targetClass + " is a primitive class"); if (targetClass.isArray()) --- 179,201 ---- * shared with trusted parties without giving away {@code PRIVATE} and {@code PACKAGE} * access to the caller. * @param targetClass the target class * @param lookup the caller lookup object * @return a lookup object for the target class, with private access ! * @throws IllegalArgumentException if {@code targetClass} is a primitive type or array class * @throws NullPointerException if {@code targetClass} or {@code caller} is {@code null} * @throws IllegalAccessException if the access check specified above fails * @throws SecurityException if denied by the security manager * @since 9 * @spec JPMS * @see Lookup#dropLookupMode */ public static Lookup privateLookupIn(Class<?> targetClass, Lookup lookup) throws IllegalAccessException { + if (lookup.allowedModes == Lookup.TRUSTED) { + return new Lookup(targetClass); + } + SecurityManager sm = System.getSecurityManager(); if (sm != null) sm.checkPermission(ACCESS_PERMISSION); if (targetClass.isPrimitive()) throw new IllegalArgumentException(targetClass + " is a primitive class"); if (targetClass.isArray())
*** 773,789 **** * Must be called by from a method in this package, * which in turn is called by a method not in this package. */ Lookup(Class<?> lookupClass) { this(lookupClass, FULL_POWER_MODES); - // make sure we haven't accidentally picked up a privileged class: - checkUnprivilegedlookupClass(lookupClass); } private Lookup(Class<?> lookupClass, int allowedModes) { this.lookupClass = lookupClass; this.allowedModes = allowedModes; } /** * Creates a lookup on the specified new lookup class. * The resulting object will report the specified --- 778,793 ---- * Must be called by from a method in this package, * which in turn is called by a method not in this package. */ Lookup(Class<?> lookupClass) { this(lookupClass, FULL_POWER_MODES); } private Lookup(Class<?> lookupClass, int allowedModes) { this.lookupClass = lookupClass; this.allowedModes = allowedModes; + assert !lookupClass.isPrimitive() && !lookupClass.isArray(); } /** * Creates a lookup on the specified new lookup class. * The resulting object will report the specified
*** 817,833 **** --- 821,844 ---- * which may change due to this operation. * * @param requestedLookupClass the desired lookup class for the new lookup object * @return a lookup object which reports the desired lookup class, or the same object * if there is no change + * @throws IllegalArgumentException if {@code requestedLookupClass} is + * a primitive type or array class * @throws NullPointerException if the argument is null * * @revised 9 * @spec JPMS */ public Lookup in(Class<?> requestedLookupClass) { Objects.requireNonNull(requestedLookupClass); + if (requestedLookupClass.isPrimitive()) + throw new IllegalArgumentException(requestedLookupClass + " is a primitive class"); + if (requestedLookupClass.isArray()) + throw new IllegalArgumentException(requestedLookupClass + " is an array class"); + if (allowedModes == TRUSTED) // IMPL_LOOKUP can make any lookup at all return new Lookup(requestedLookupClass, FULL_POWER_MODES); if (requestedLookupClass == this.lookupClass) return this; // keep same capabilities int newModes = (allowedModes & FULL_POWER_MODES);
*** 898,907 **** --- 909,922 ---- /** * Defines a class to the same class loader and in the same runtime package and * {@linkplain java.security.ProtectionDomain protection domain} as this lookup's * {@linkplain #lookupClass() lookup class}. * + * This method is equivalent to calling + * {@link #defineClass(byte[], ClassProperty[]) + * defineClass(bytes, (ClassProperty[])null)}. + * * <p> The {@linkplain #lookupModes() lookup modes} for this lookup must include * {@link #PACKAGE PACKAGE} access as default (package) members will be * accessible to the class. The {@code PACKAGE} lookup mode serves to authenticate * that the lookup object was created by a caller in the runtime package (or derived * from a lookup originally created by suitably privileged code to a target class in
*** 932,948 **** * @see Lookup#privateLookupIn * @see Lookup#dropLookupMode * @see ClassLoader#defineClass(String,byte[],int,int,ProtectionDomain) */ public Class<?> defineClass(byte[] bytes) throws IllegalAccessException { SecurityManager sm = System.getSecurityManager(); if (sm != null) sm.checkPermission(new RuntimePermission("defineClass")); ! if ((lookupModes() & PACKAGE) == 0) throw new IllegalAccessException("Lookup does not have PACKAGE access"); ! assert (lookupModes() & (MODULE|PUBLIC)) != 0; // parse class bytes to get class name (in internal form) bytes = bytes.clone(); String name; try { ClassReader reader = new ClassReader(bytes); --- 947,1237 ---- * @see Lookup#privateLookupIn * @see Lookup#dropLookupMode * @see ClassLoader#defineClass(String,byte[],int,int,ProtectionDomain) */ public Class<?> defineClass(byte[] bytes) throws IllegalAccessException { + return defineClass(bytes, (ClassProperty[])null); + } + + /** + * Defines a class to the same class loader and in the same runtime package + * and {@linkplain java.security.ProtectionDomain protection domain} as + * this lookup's {@linkplain #lookupClass() lookup class}. + * The {@code props} parameter specifies the properties of the class. + * + * <p> A class can be defined with the following properties: + * <ul> + * <li>A {@linkplain ClassProperty#NESTMATE <em>nestmate</em>} of the lookup class, + * i.e. in the same {@linkplain Class#getNestHost nest} + * of the lookup class. The class will have access to the private members + * of all classes and interfaces in the same nest. + * </li> + * <li>A {@linkplain ClassProperty#HIDDEN <em>hidden</em>} class, + * i.e. a class cannot be referenced by other classes. + * A hidden class has the following properties: + * <ul> + * <li>Naming: + * The name of this class is derived from the name of + * the class in the class bytes so that the class name does not + * collide with other classes defined to the same class loader. + * <li>Class resolution: + * The Java virtual machine does not find a hidden class with + * its name. A hidden class can reference its members + * locally with the name of the class in the class bytes as if + * a non-hidden class. The name returned by {@link Class#getName()} + * is not known when the class bytes are generated. + * <li>Class retransformation: + * The class is not modifiable by Java agents or tool agents using + * the <a href="{@docRoot}/../specs/jvmti.html">JVM Tool Interface</a>. + * </ul> + * </li> + * <li>A {@linkplain ClassProperty#WEAK <em>weak</em>} class, + * i.e. a class may be unloaded even if its defining class loader is + * <a href="../ref/package.html#reachability">reachable</a>, + * as if the defining class loader would only hold a + * {@linkplain java.lang.ref.WeakReference weak reference} of + * the class. + * A weak class is hidden. If the {@code WEAK} property is set, + * then it implies that {@code HIDDEN} property is also set.</li> + * </ul> + * + * <p> The {@linkplain #lookupModes() lookup modes} for this lookup must + * include {@link #PACKAGE PACKAGE} access as default (package) members + * will be accessible to the class. The {@code PACKAGE} lookup mode serves + * to authenticate that the lookup object was created by a caller in + * the runtime package (or derived from a lookup originally created by + * suitably privileged code to a target class in the runtime package). + * If the class is defined as a {@linkplain ClassProperty#NESTMATE nestmate} + * then the {@linkplain #lookupModes() lookup modes} for this lookup must + * include {@link #PRIVATE PRIVATE} access. </p> + * + * <p> The {@code bytes} parameter is the class bytes of a valid class file + * (as defined by the <em>The Java Virtual Machine Specification</em>) + * with a class name in the same package as the lookup class. + * The class bytes of a nestmate class must not contain + * the {@code NestHost} attribute nor the {@code NestMembers} attribute. </p> + * + * <p> If there is a security manager, its {@code checkPermission} method is first called + * to check {@code RuntimePermission("defineClass")}. </p> + * + * <p> This method does not run the class initializer. The class initializer + * may run at a later time, as detailed in section 12.4 of the The Java Language Specification. + * + * <p> The class can obtain {@code classData} by calling + * the {@link Lookup#classData()} method of its {@code Lookup} object. + * + * @apiNote An implementation of the Java Progamming Language may + * unload classes as specified in section 12.7 of the Java Language Specification. + * A class or interface may be unloaded if and only if + * its defining class loader may be reclaimed by the garbage collector. + * If the implementation supports class loading, a weak class + * may become weakly reachable as if the defining class loader would + * only hold a {@linkplain java.lang.ref.WeakReference weak reference} + * of the class. + * + * @param bytes the class bytes + * @param props {@linkplain ClassProperty class properties} + * @return the {@code Class} object for the class + * + * @throws IllegalArgumentException the bytes are for a class in a different package + * to the lookup class + * @throws IllegalAccessException if this lookup does not have {@code PACKAGE} access, or + * if {@code properties} contains {@code NESTMATE} but this lookup + * does not have {@code PRIVATE} access + * @throws LinkageError if the class is malformed ({@code ClassFormatError}), cannot be + * verified ({@code VerifyError}), is already defined, + * or another linkage error occurs + * @throws SecurityException if denied by the security manager + * @throws NullPointerException if {@code bytes} is {@code null} + * + * @since 12 + * @jls 12.7 Unloading of Classes and Interfaces + * @see Lookup#privateLookupIn(Class, Lookup) + * @see Lookup#dropLookupMode(int) + */ + public Class<?> defineClass(byte[] bytes, ClassProperty... props) throws IllegalAccessException { + Objects.requireNonNull(bytes); + + // clone the properties before access + Set<ClassProperty> properties; + if (props == null || props.length == 0) { + properties = EMPTY_PROPS; + } else { + properties = Set.of(props); + } + + // Is it ever possible to create Lookup for int.class or Object[].class? + assert !lookupClass.isPrimitive() && !lookupClass.isArray(); + + if ((lookupModes() & PACKAGE) == 0){ + throw new IllegalAccessException("Lookup does not have PACKAGE access"); + } + + if (properties.contains(NESTMATE) && (lookupModes() & PRIVATE) == 0){ + throw new IllegalAccessException("Lookup does not have PRIVATE access"); + } + + assert (lookupModes() & (MODULE | PUBLIC)) != 0; + SecurityManager sm = System.getSecurityManager(); if (sm != null) sm.checkPermission(new RuntimePermission("defineClass")); ! ! return defineClassWithNoCheck(bytes, classPropertiesToFlags(properties)); ! } ! ! /** ! * Defines a class to the same class loader and in the same runtime package ! * and {@linkplain java.security.ProtectionDomain protection domain} as ! * this lookup's {@linkplain #lookupClass() lookup class} with ! * the given class properties and {@code classData}. ! * ! * <p> This method defines a class as if calling ! * {@link #defineClass(byte[], ClassProperty...) defineClass(bytes, props)} ! * and then the class initializer with an injected the {@code classData} ! * as a pre-initialized static unnamed field. ! * The injected pre-initialized static unnamed field can be ! * obtained by calling the {@link Lookup#classData()} method of ! * its {@code Lookup} object. ! * ! * <p> If there is a security manager, its {@code checkPermission} method is first called ! * to check {@code RuntimePermission("defineClass")}. </p> ! * ! * @apiNote ! * This method initializes the class, as opposed to the {@link #defineClass(byte[], ClassProperty...)} ! * method which does not invoke {@code <clinit>}, because the returned {@code Class} ! * is as if it contains a private static unnamed field that is initialized to ! * the given {@code classData} along with other declared static fields ! * via {@code <clinit>}. ! * ! * @param bytes the class bytes ! * @param classData pre-initialized class data ! * @param props {@linkplain ClassProperty class properties} ! * @return the {@code Class} object for the class ! * ! * @throws IllegalArgumentException the bytes are for a class in a different package ! * to the lookup class ! * @throws IllegalAccessException if this lookup does not have {@code PACKAGE} access, or ! * if {@code properties} contains {@code NESTMATE} but this lookup ! * does not have {@code PRIVATE} access ! * @throws LinkageError if the class is malformed ({@code ClassFormatError}), cannot be ! * verified ({@code VerifyError}), is already defined, ! * or another linkage error occurs ! * @throws SecurityException if denied by the security manager ! * @throws NullPointerException if {@code bytes} or {@code classData} is {@code null} ! * ! * @since 12 ! * @jls 12.7 Unloading of Classes and Interfaces ! * @see Lookup#privateLookupIn(Class, Lookup) ! * @see Lookup#dropLookupMode(int) ! */ ! public Class<?> defineClassWithClassData(byte[] bytes, Object classData, ClassProperty... props) ! throws IllegalAccessException ! { ! Objects.requireNonNull(bytes); ! Objects.requireNonNull(classData); ! ! // Is it ever possible to create Lookup for int.class or Object[].class? ! assert !lookupClass.isPrimitive() && !lookupClass.isArray(); ! ! if ((lookupModes() & PACKAGE) == 0){ throw new IllegalAccessException("Lookup does not have PACKAGE access"); ! } + Set<ClassProperty> properties; + if (props == null || props.length == 0) { + properties = EMPTY_PROPS; + } else { + properties = Set.of(props); + } + + if (properties.contains(NESTMATE) && (lookupModes() & PRIVATE) == 0){ + throw new IllegalAccessException("Lookup does not have PRIVATE access"); + } + + assert (lookupModes() & (MODULE | PUBLIC)) != 0; + + SecurityManager sm = System.getSecurityManager(); + if (sm != null) + sm.checkPermission(new RuntimePermission("defineClass")); + + return defineClassWithNoCheck(bytes, classPropertiesToFlags(properties), classData); + } + + private static int classPropertiesToFlags(Set<ClassProperty> props) { + if (props.isEmpty()) return 0; + + int flags = 0; + for (ClassProperty cp : props) { + flags |= cp.flag; + if (cp == WEAK) { + // weak class property implies hidden + flags |= HIDDEN.flag; + } + } + return flags; + } + + /** + * Returns the class data associated with this lookup class. + * If this lookup class was defined via + * {@link #defineClassWithClassData(byte[], Object, ClassProperty...) + * defineClassWithClassData(bytes, classData, properties)} + * then the supplied {@code classData} object is returned; otherwise, + * {@code null}. + * + * <p> This method will invoke the static class initializer of + * this lookup class if it has not been initialized. + * + * @apiNote + * A class data can be considered as + * private static unnamed field that has been pre-initialized + * and supplied at define class time. + * + * <p> For example a class can pack one or more pre-initialized objects + * in a {@code List} as the class data and at class initialization + * time unpack them for subsequent access. + * The class data is {@code List.of(o1, o2, o3....)} + * passed to {@link #defineClassWithClassData(byte[], Object, ClassProperty...)} where + * {@code <clinit>} of the class bytes does the following: + * + * <pre>{@code + * private static final T t; + * private static final R r; + * static { + * List<Object> data = (List<Object>) MethodHandles.lookup().classData(); + * t = (T)data.get(0); + * r = (R)data.get(1); + * } + *}</pre> + * + * @return the class data if this lookup class was defined via + * {@link #defineClassWithClassData(byte[], Object, ClassProperty...)}; otherwise {@code null}. + * + * @throws IllegalAccessException if this lookup does not have {@code PRIVATE} access + * @since 12 + */ + public Object classData() throws IllegalAccessException { + if ((lookupModes() & PRIVATE) == 0){ + throw new IllegalAccessException("Lookup does not have PRIVATE access"); + } + + // should we allow clearing? getAndClearClassData + return MethodHandleNatives.classData(lookupClass); + } + + // package-private + static final int HIDDEN_NESTMATE = NESTMATE_CLASS|NONFINDABLE_CLASS|ACCESS_VM_ANNOTATIONS; + static final int WEAK_HIDDEN_NESTMATE = WEAK_CLASS|NESTMATE_CLASS|NONFINDABLE_CLASS|ACCESS_VM_ANNOTATIONS; + static final Set<ClassProperty> EMPTY_PROPS = Set.of(); + + Class<?> defineClassWithNoCheck(byte[] bytes, int flags) { + return defineClassWithNoCheck(bytes, flags, null); + } + + Class<?> defineClassWithNoCheck(byte[] bytes, int flags, Object classData) { + // Can't use lambda during bootstrapping // parse class bytes to get class name (in internal form) bytes = bytes.clone(); String name; try { ClassReader reader = new ClassReader(bytes);
*** 963,1000 **** } else { cn = name.replace('/', '.'); pn = cn.substring(0, index); } if (!pn.equals(lookupClass.getPackageName())) { ! throw new IllegalArgumentException("Class not in same package as lookup class"); } // invoke the class loader's defineClass method ClassLoader loader = lookupClass.getClassLoader(); ProtectionDomain pd = (loader != null) ? lookupClassProtectionDomain() : null; ! String source = "__Lookup_defineClass__"; ! Class<?> clazz = SharedSecrets.getJavaLangAccess().defineClass(loader, cn, bytes, pd, source); return clazz; } private ProtectionDomain lookupClassProtectionDomain() { ProtectionDomain pd = cachedProtectionDomain; if (pd == null) { ! cachedProtectionDomain = pd = protectionDomain(lookupClass); } return pd; } - private ProtectionDomain protectionDomain(Class<?> clazz) { - PrivilegedAction<ProtectionDomain> pa = clazz::getProtectionDomain; - return AccessController.doPrivileged(pa); - } - // cached protection domain private volatile ProtectionDomain cachedProtectionDomain; - // Make sure outer class is initialized first. static { IMPL_NAMES.getClass(); } /** Package-private version of lookup which is trusted. */ static final Lookup IMPL_LOOKUP = new Lookup(Object.class, TRUSTED); --- 1252,1292 ---- } else { cn = name.replace('/', '.'); pn = cn.substring(0, index); } if (!pn.equals(lookupClass.getPackageName())) { ! throw new IllegalArgumentException(cn + " not in same package as lookup class: " + lookupClass.getName()); ! } ! ! if ((flags & NONFINDABLE_CLASS) != 0) { ! // ## TODO use '/' as in the name of the VM anonymous class. ! cn = cn + '\\' + ++seq; } // invoke the class loader's defineClass method ClassLoader loader = lookupClass.getClassLoader(); ProtectionDomain pd = (loader != null) ? lookupClassProtectionDomain() : null; ! Class<?> clazz = JLA.defineClass(loader, lookupClass, cn, bytes, pd, flags, classData); ! assert clazz.getClassLoader() == lookupClass.getClassLoader() ! && clazz.getPackageName().equals(lookupClass.getPackageName()); ! return clazz; } + private static volatile int seq = 0; + private ProtectionDomain lookupClassProtectionDomain() { ProtectionDomain pd = cachedProtectionDomain; if (pd == null) { ! cachedProtectionDomain = pd = JLA.protectionDomain(lookupClass); } return pd; } // cached protection domain private volatile ProtectionDomain cachedProtectionDomain; // Make sure outer class is initialized first. static { IMPL_NAMES.getClass(); } /** Package-private version of lookup which is trusted. */ static final Lookup IMPL_LOOKUP = new Lookup(Object.class, TRUSTED);
*** 1003,1012 **** --- 1295,1306 ---- * It can only be used to create method handles to publicly accessible * members in packages that are exported unconditionally. */ static final Lookup PUBLIC_LOOKUP = new Lookup(Object.class, (PUBLIC|UNCONDITIONAL)); + static final JavaLangAccess JLA = SharedSecrets.getJavaLangAccess(); + private static void checkUnprivilegedlookupClass(Class<?> lookupClass) { String name = lookupClass.getName(); if (name.startsWith("java.lang.invoke.")) throw newIllegalArgumentException("illegal lookupClass: "+lookupClass); }
*** 1284,1301 **** * load the requested class, and then determines whether the class is accessible to this lookup object. * * @param targetName the fully qualified name of the class to be looked up. * @return the requested class. * @exception SecurityException if a security manager is present and it ! * <a href="MethodHandles.Lookup.html#secmgr">refuses access</a> * @throws LinkageError if the linkage fails ! * @throws ClassNotFoundException if the class cannot be loaded by the lookup class' loader. ! * @throws IllegalAccessException if the class is not accessible, using the allowed access ! * modes. ! * @exception SecurityException if a security manager is present and it ! * <a href="MethodHandles.Lookup.html#secmgr">refuses access</a> * @since 9 */ public Class<?> findClass(String targetName) throws ClassNotFoundException, IllegalAccessException { Class<?> targetClass = Class.forName(targetName, false, lookupClass.getClassLoader()); return accessClass(targetClass); } --- 1578,1595 ---- * load the requested class, and then determines whether the class is accessible to this lookup object. * * @param targetName the fully qualified name of the class to be looked up. * @return the requested class. * @exception SecurityException if a security manager is present and it ! * <a href="MethodHandles.Lookup.html#secmgr">refuses access</a> * @throws LinkageError if the linkage fails ! * @throws ClassNotFoundException if the class cannot be loaded by the lookup class' loader ! * or the class is not {@linkplain Class#isHidden hidden} ! * @throws IllegalAccessException if the class is not accessible, using the allowed access modes. ! * @since 9 + * @see Class#isHidden */ public Class<?> findClass(String targetName) throws ClassNotFoundException, IllegalAccessException { Class<?> targetClass = Class.forName(targetName, false, lookupClass.getClassLoader()); return accessClass(targetClass); }
*** 2552,2561 **** --- 2846,2901 ---- // oops throw newIllegalArgumentException("bad MethodHandle constant #"+member); } static ConcurrentHashMap<MemberName, DirectMethodHandle> LOOKASIDE_TABLE = new ConcurrentHashMap<>(); + + /** + * Property of a class to be defined via the + * {@link Lookup#defineClass(byte[], ClassProperty[]) Lookup.defineClass} method. + * + * @since 12 + * @see Lookup#defineClass(byte[], ClassProperty[]) + * @see Lookup#defineClassWithClassData(byte[], Object, ClassProperty[]) + */ + public enum ClassProperty { + /** + * A nestmate is a class that is in the same {@linkplain Class#getNestHost nest} + * of a lookup class. It has access to the private members of all + * classes and interfaces in the same nest. + * + * @see Class#getNestHost() + */ + NESTMATE(NESTMATE_CLASS), + + /** + * A hidden class is a class that cannot be referenced by other + * classes. A Java Virtual Machine implementation may hide + * the hidden frames from {@linkplain Throwable#getStackTrace() + * stack traces}. + * + * @see Class#isHidden() + * @see StackWalker.Option#SHOW_HIDDEN_FRAMES + */ + HIDDEN(NONFINDABLE_CLASS), + + /** + * A weak class is a class that may be unloaded even if + * its defining class loader is + * <a href="../ref/package.html#reachability">reachable</a>. + * A weak class is {@linkplain #HIDDEN hidden}. + * + * @jls 12.7 Unloading of Classes and Interfaces + */ + WEAK(WEAK_CLASS); + + /* the flag value is used by VM at define class time */ + final int flag; + ClassProperty(int flag) { + this.flag = flag; + } + } } /** * Produces a method handle constructing arrays of a desired type, * as if by the {@code anewarray} bytecode.
< prev index next >