< 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,54 ****
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;
--- 44,53 ----
*** 211,220 ****
--- 210,223 ----
* @spec JPMS
* @see Lookup#dropLookupMode
* @see <a href="MethodHandles.Lookup.html#cross-module-lookup">Cross-module lookups</a>
*/
public static Lookup privateLookupIn(Class<?> targetClass, Lookup caller) throws IllegalAccessException {
+ if (caller.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())
*** 1093,1104 ****
* to allow applications to check such cross-loader references.
* These checks apply to both the {@code MethodHandles.Lookup} API
* and the Core Reflection API
* (as found on {@link java.lang.Class Class}).
* <p>
! * If a security manager is present, member and class lookups are subject to
! * additional checks.
* From one to three calls are made to the security manager.
* Any of these calls can refuse access by throwing a
* {@link java.lang.SecurityException SecurityException}.
* Define {@code smgr} as the security manager,
* {@code lookc} as the lookup class of the current lookup object,
--- 1096,1107 ----
* to allow applications to check such cross-loader references.
* These checks apply to both the {@code MethodHandles.Lookup} API
* and the Core Reflection API
* (as found on {@link java.lang.Class Class}).
* <p>
! * If a security manager is present, member and class lookups are
! * subject to additional checks.
* From one to three calls are made to the security manager.
* Any of these calls can refuse access by throwing a
* {@link java.lang.SecurityException SecurityException}.
* Define {@code smgr} as the security manager,
* {@code lookc} as the lookup class of the current lookup object,
*** 1138,1147 ****
--- 1141,1157 ----
* </ul>
* Security checks are performed after other access checks have passed.
* Therefore, the above rules presuppose a member or class that is public,
* or else that is being accessed from a lookup class that has
* rights to access the member or class.
+ * <p>
+ * If a security manager is present and the current lookup object does not have
+ * <a href="MethodHandles.Lookup.html#privacc">private access</a>, then
+ * {@link #defineClass(byte[]) defineClass} and
+ * {@link #defineHiddenClass(byte[], boolean, ClassOption...) defineHiddenClass}
+ * call {@link SecurityManager#checkPermission smgr.checkPermission}
+ * with {@code RuntimePermission("defineClass")} is called.
*
* <h2><a id="callsens"></a>Caller sensitive methods</h2>
* A small number of Java methods have a special property called caller sensitivity.
* A <em>caller-sensitive</em> method can behave differently depending on the
* identity of its immediate caller.
*** 1375,1395 ****
* 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, null, FULL_POWER_MODES);
- // make sure we haven't accidentally picked up a privileged class:
- checkUnprivilegedlookupClass(lookupClass);
}
private Lookup(Class<?> lookupClass, Class<?> prevLookupClass, int allowedModes) {
assert prevLookupClass == null || ((allowedModes & MODULE) == 0
&& prevLookupClass.getModule() != lookupClass.getModule());
assert !lookupClass.isArray() && !lookupClass.isPrimitive();
this.lookupClass = lookupClass;
this.prevLookupClass = prevLookupClass;
this.allowedModes = allowedModes;
}
private static Lookup newLookup(Class<?> lookupClass, Class<?> prevLookupClass, int allowedModes) {
// make sure we haven't accidentally picked up a privileged class:
checkUnprivilegedlookupClass(lookupClass);
--- 1385,1404 ----
* 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, null, FULL_POWER_MODES);
}
private Lookup(Class<?> lookupClass, Class<?> prevLookupClass, int allowedModes) {
assert prevLookupClass == null || ((allowedModes & MODULE) == 0
&& prevLookupClass.getModule() != lookupClass.getModule());
assert !lookupClass.isArray() && !lookupClass.isPrimitive();
this.lookupClass = lookupClass;
this.prevLookupClass = prevLookupClass;
this.allowedModes = allowedModes;
+ assert !lookupClass.isPrimitive() && !lookupClass.isArray();
}
private static Lookup newLookup(Class<?> lookupClass, Class<?> prevLookupClass, int allowedModes) {
// make sure we haven't accidentally picked up a privileged class:
checkUnprivilegedlookupClass(lookupClass);
*** 1500,1511 ****
/**
* Creates a lookup on the same lookup class which this lookup object
* finds members, but with a lookup mode that has lost the given lookup mode.
* The lookup mode to drop is one of {@link #PUBLIC PUBLIC}, {@link #MODULE
* MODULE}, {@link #PACKAGE PACKAGE}, {@link #PROTECTED PROTECTED} or {@link #PRIVATE PRIVATE}.
! * {@link #PROTECTED PROTECTED} is always
! * dropped and so the resulting lookup mode will never have this access capability.
* When dropping {@code PACKAGE} then the resulting lookup will not have {@code PACKAGE}
* or {@code PRIVATE} access. When dropping {@code MODULE} then the resulting lookup will
* not have {@code MODULE}, {@code PACKAGE}, or {@code PRIVATE} access. If {@code PUBLIC}
* is dropped then the resulting lookup has no access. If {@code UNCONDITIONAL}
* is dropped then the resulting lookup has no access.
--- 1509,1520 ----
/**
* Creates a lookup on the same lookup class which this lookup object
* finds members, but with a lookup mode that has lost the given lookup mode.
* The lookup mode to drop is one of {@link #PUBLIC PUBLIC}, {@link #MODULE
* MODULE}, {@link #PACKAGE PACKAGE}, {@link #PROTECTED PROTECTED} or {@link #PRIVATE PRIVATE}.
! * {@link #PROTECTED PROTECTED} is always dropped and
! * so the resulting lookup mode will never have this access capability.
* When dropping {@code PACKAGE} then the resulting lookup will not have {@code PACKAGE}
* or {@code PRIVATE} access. When dropping {@code MODULE} then the resulting lookup will
* not have {@code MODULE}, {@code PACKAGE}, or {@code PRIVATE} access. If {@code PUBLIC}
* is dropped then the resulting lookup has no access. If {@code UNCONDITIONAL}
* is dropped then the resulting lookup has no access.
*** 1587,1649 ****
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);
! name = reader.getClassName();
} catch (RuntimeException e) {
// ASM exceptions are poorly specified
ClassFormatError cfe = new ClassFormatError();
cfe.initCause(e);
throw cfe;
}
-
- // get package and class name in binary form
- String cn, pn;
- int index = name.lastIndexOf('/');
- if (index == -1) {
- cn = name;
- pn = "";
- } 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, null, TRUSTED);
--- 1596,1876 ----
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;
+ return makeClassDefiner(bytes.clone()).defineClass(false);
+ }
+
+ private void checkDefineClassPermission() {
+ SecurityManager sm = System.getSecurityManager();
+ if (sm == null) return;
+ if (allowedModes == TRUSTED) return;
+
+ if (!hasPrivateAccess()) {
+ sm.checkPermission(new RuntimePermission("defineClass"));
+ }
+ }
+
+ /**
+ * Creates a {@code Lookup} on a <em>hidden class</em> defined 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}.
+ *
+ * If {@code options} has {@link ClassOption#NESTMATE NESTMATE} class
+ * option, then the hidden class is added as a member into
+ * {@linkplain Class#getNestHost() the nest} of this lookup's lookup class.
+ *
+ * If {@code options} has {@link ClassOption#WEAK WEAK}, then
+ * the hidden class is weakly referenced from its defining class loader
+ * and may be unloaded while its defining class loader is strongly reachable.
+ *
+ * The hidden class is initialized if the {@code initialize} parameter is
+ * {@code true}.
+ *
+ * <p> A {@link Class#isHiddenClass() <em>hidden</em>} class has the
+ * following additional properties:
+ * <ul>
+ * <li>Naming:
+ * The name of a hidden class returned by {@link Class#getName()} is
+ * defined by the JVM of this form:
+ * {@code <fully-qualified binary name> + '/' + <suffix>}<br>
+ * where {@code <fully-qualified binary name>} is the class name
+ * from the class bytes and {@code <suffix>} must be an unique unqualified
+ * name (see JVMS 4.2.2)
+ * <li>Class resolution:
+ * A hidden class cannot be referenced in other classes and cannot be
+ * named as a field type, a method parameter type and a method return type.
+ * It is not discoverable by its class loader for example via
+ * {@link Class#forName(String, boolean, ClassLoader)},
+ * {@link ClassLoader#loadClass(String, boolean)} and also bytecode linkage.
+ * <li>Class retransformation:
+ * A hidden class 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>.
+ * <li>Serialization:
+ * The default serialization mechanism records the name of a class in
+ * its serialized form and finds the class by name during deserialization.
+ * A <em>serializable</em> hidden class requires a custom serialization
+ * mechanism in order to ensure that instances are properly serialized
+ * and deserialized.
+ * </ul>
+ *
+ * <p> The {@linkplain #lookupModes() lookup modes} for this lookup must
+ * have {@code PRIVATE} and {@code MODULE} access to create a hidden class
+ * in the module of this lookup class.
+ *
+ * <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.
+ *
+ * @param bytes the class bytes
+ * @param initialize if {@code true} the class will be initialized.
+ * @param options {@linkplain ClassOption class options}
+ * @return the {@code Lookup} object on the hidden 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 PRIVATE} and {@code MODULE} 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 a security manager is present and it
+ * <a href="MethodHandles.Lookup.html#secmgr">refuses access</a>
+ * @throws NullPointerException if {@code bytes} is {@code null}
+ *
+ * @since 14
+ * @see Class#isHiddenClass()
+ * @jvms 4.2.2 Unqualified Names
+ * @jls 12.3 Linking of Classes and Interfaces
+ * @jls 12.4 Initialization of Classes and Interfaces
+ */
+ public Lookup defineHiddenClass(byte[] bytes, boolean initialize, ClassOption... options)
+ throws IllegalAccessException
+ {
+ Objects.requireNonNull(bytes);
+
+ checkDefineClassPermission();
+ if ((lookupModes() & (PRIVATE|MODULE)) != (PRIVATE|MODULE)){
+ throw new IllegalAccessException(this + " does not have PRIVATE or MODULE access");
+ }
+
+ Set<ClassOption> opts = (options != null && options.length > 0) ? Set.of(options) : Set.of();
+ Class<?> c = makeHiddenClassDefiner(bytes.clone(), opts).defineClass(initialize, null);
+ return new Lookup(c, null, FULL_POWER_MODES);
+ }
+
+ /**
+ * Creates a {@code Lookup} on a <em>hidden class</em> with {@code classData}
+ * defined 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 options.
+ *
+ * <p> This method is equivalent to calling
+ * {@link #defineHiddenClass(byte[], boolean, ClassOption...) defineHiddenClass(bytes, initialize, options)}
+ * as if the hidden class has a private static final unnamed field
+ * pre-initialized with the given {@code classData}.
+ * The {@link MethodHandles#classData(Lookup, String, Class) MethodHandles::classData} method
+ * can be used to retrieve the {@code classData}.
+ *
+ * <p> The {@linkplain #lookupModes() lookup modes} for this lookup must
+ * have {@code PRIVATE} and {@code MODULE} access in order to create a
+ * hidden class in the module of this lookup class.
+ *
+ * @param bytes the class bytes
+ * @param classData pre-initialized class data
+ * @param initialize if {@code true} the class will be initialized.
+ * @param options {@linkplain ClassOption class options}
+ * @return the {@code Lookup} object on the hidden 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 PRIVATE} and {@code MODULE} 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 a security manager is present and it
+ * <a href="MethodHandles.Lookup.html#secmgr">refuses access</a>
+ * @throws NullPointerException if {@code bytes} is {@code null}
+ *
+ * @since 14
+ * @see Lookup#defineHiddenClass(byte[], boolean, ClassOption...)
+ * @see Class#isHiddenClass()
+ */
+ /* package-private */ Lookup defineHiddenClassWithClassData(byte[] bytes, Object classData, boolean initialize, ClassOption... options)
+ throws IllegalAccessException
+ {
+ Objects.requireNonNull(bytes);
+ Objects.requireNonNull(classData);
+
+ checkDefineClassPermission();
+ if ((lookupModes() & (PRIVATE|MODULE)) != (PRIVATE|MODULE)){
+ throw new IllegalAccessException(this + " does not have PRIVATE or MODULE access");
+ }
+
+ Set<ClassOption> opts = (options != null && options.length > 0) ? Set.of(options) : Set.of();
+ Class<?> c = makeHiddenClassDefiner(bytes.clone(), opts).defineClass(initialize, classData);
+ return new Lookup(c, null, FULL_POWER_MODES);
+ }
+
+ 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) {
! return new ClassDefiner(this, name, bytes, HIDDEN_CLASS);
! }
!
! 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())) {
! throw newIllegalArgumentException(name + " not in same package as lookup class: " +
! lookup.lookupClass().getName());
! }
! }
!
! // skip package name check
! private ClassDefiner(Lookup lookup, String name, byte[] bytes, int flags) {
! this.lookup = lookup;
! this.bytes = bytes;
! this.classFlags = flags;
! this.name = name;
! }
!
! String className() {
! return name;
! }
!
! Class<?> defineClass(boolean initialize) {
! return defineClass(initialize, null);
! }
!
! /**
! * Defines the class of the given bytes and the given classData.
! * If {@code initialize} parameter is true, then the class will be initialized.
! *
! * @param initialize true if the class to be initialized
! * @param classData classData or null
! * @return the class
! *
! * @throws LinkageError linkage error
! */
! Class<?> defineClass(boolean initialize, Object classData) {
! Class<?> lookupClass = lookup.lookupClass();
! ClassLoader loader = lookupClass.getClassLoader();
! ProtectionDomain pd = (loader != null) ? lookup.lookupClassProtectionDomain() : null;
! Class<?> c = JLA.defineClass(loader, lookupClass, name, bytes, pd, initialize, classFlags, classData);
! assert !isNestmate() || c.getNestHost() == lookupClass.getNestHost();
! return c;
! }
!
! private boolean isNestmate() {
! return (classFlags & NESTMATE_CLASS) != 0;
! }
!
! private static String className(byte[] bytes) {
try {
ClassReader reader = new ClassReader(bytes);
! String name = reader.getClassName();
! return name.replace('/', '.');
! } catch (IllegalArgumentException e) {
! throw e;
} catch (RuntimeException e) {
// ASM exceptions are poorly specified
ClassFormatError cfe = new ClassFormatError();
cfe.initCause(e);
throw cfe;
}
}
}
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, null, TRUSTED);
*** 1652,1661 ****
--- 1879,1890 ----
* 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, null, 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);
}
*** 1710,1724 ****
case PUBLIC|MODULE:
return cname + "/module";
case PUBLIC|PACKAGE:
case PUBLIC|MODULE|PACKAGE:
return cname + "/package";
! case FULL_POWER_MODES & (~PROTECTED):
! case FULL_POWER_MODES & ~(PROTECTED|MODULE):
return cname + "/private";
case FULL_POWER_MODES:
! case FULL_POWER_MODES & (~MODULE):
return cname;
case TRUSTED:
return "/trusted"; // internal only; not exported
default: // Should not happen, but it's a bitfield...
cname = cname + "/" + Integer.toHexString(allowedModes);
--- 1939,1953 ----
case PUBLIC|MODULE:
return cname + "/module";
case PUBLIC|PACKAGE:
case PUBLIC|MODULE|PACKAGE:
return cname + "/package";
! case PUBLIC|PACKAGE|PRIVATE:
! case PUBLIC|MODULE|PACKAGE|PRIVATE:
return cname + "/private";
case FULL_POWER_MODES:
! case FULL_POWER_MODES & ~(MODULE):
return cname;
case TRUSTED:
return "/trusted"; // internal only; not exported
default: // Should not happen, but it's a bitfield...
cname = cname + "/" + Integer.toHexString(allowedModes);
*** 3258,3267 ****
--- 3487,3543 ----
// oops
throw newIllegalArgumentException("bad MethodHandle constant #"+member);
}
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 weakly referenced by its defining class loader.
+ *
+ * @since 14
+ */
+ public enum ClassOption {
+ /**
+ * This class option specifies the hidden class be added to
+ * {@linkplain Class#getNestHost nest} of a lookup class as
+ * a nestmate.
+ *
+ * <p> A hidden nestmate class has access to the private members of all
+ * classes and interfaces in the same nest.
+ *
+ * @see Class#getNestHost()
+ */
+ NESTMATE(NESTMATE_CLASS),
+
+ /**
+ * This class option specifies the hidden class be weakly
+ * referenced by its defining class loader such that it
+ * 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;
+ }
+
+ static int optionsToFlag(Set<ClassOption> options) {
+ int flags = 0;
+ for (ClassOption cp : options) {
+ flags |= cp.flag;
+ }
+ return flags;
+ }
+ }
}
/**
* Produces a method handle constructing arrays of a desired type,
* as if by the {@code anewarray} bytecode.
< prev index next >