JEP draft: Internal Frozen Arrays

OwnerJohn Rose
TypeFeature
ScopeJDK
StatusDraft
Componenthotspot
Created2021/02/03 23:02
Updated2021/02/05 20:14
Issue8261099

Summary

Allow trusted implementors, internal to the JDK, to lock down selected arrays in such a way that the JVM rejects all future writes to them.

Goals

This JEP allows the Java Virtual Machine to treat specially-marked array instances as read-only. A so-called "frozen array" can have any type, length, or contents, but its elements can never be reassigned. Frozen arrays will support certain optimizations and safety techniques (such as constant folding and defensive copying) which ordinary mutable arrays cannot support.

This is a private feature within HotSpot and the java.base module. It is intended for use in internal optimizations, and also as a primitive for implementing user-visible frozen arrays.

Non-Goals

This JEP proposes no changes to the Java programming language. Changes to the Java language specification to allow for the existence of frozen arrays are the subject of a separate follow-on JEP, JDK-8261007. Building of a full user model for frozen arrays is also deferred to that JEP.

Because they cannot be mutated, frozen arrays are non-compliant with the Java language (until the language is adjusted to admit them), and must not be exposed from any standard API until suitable adjustments are made. Thus, this JEP changes no standard API points in a way that would expose frozen array objects.

Motivation

This is a first step towards user-visible frozen arrays. Please see JDK-8261007 for the full motivation.

Description

Define three new secure methods in jdk.internal.misc.Unsafe:

/**
 * Returns true if the given object is a frozen array.
 * The reference must be non-null and to an array.
 */
public boolean isFrozenArray(Object array) ...

/**
 * Freeze the given array object.
 * The reference must be non-null and to an array
 * created by {@code makeLarvalArray} and
 * which has not yet been frozen.
 * The returned object is the same as the input
 * array, which has been frozen, or perhaps a copy
 * with the same type and contents.
 *
 * The input array must not be used an any way
 * (whether loads, stores, re-freezing, or anything
 * else) after the call returns.  User should
 * Operations on the returned object must proceed as
 * if it were a fresh copy of the input array, even if
 * (as is likely in many cases but not all) the JVM
 * manages to recycle the object identity of the input array.
 *
 * The user must not rely on the JVM to actually check these
 * restrictions, which is why this method is unsafe.
 *
 * JIT IR representations should treat the input and output
 * values as distinct names.
 */
public Object freezeLarvalArray(Object array) ...

/**
 * Create a new array of the given class and length,
 * with all elements initialized to their default values.
 * This array must not made visible to other threads,
 * or synchronized on.  It may be passed as an input
 * to {@code freezeLarvalArray}.
 *
 * The user must not rely on the JVM to actually check these
 * restrictions, which is why this method is unsafe.
 */
public Object makeLarvalArray(Class<?> arrayClass, int length) ...

This is a first step towards user-visible frozen arrays. Please see JDK-8261007 for the full description of non-internal APIs and use cases.

It seems best to add these methods to Unsafe for these reasons:

Alternatives

We could plow ahead and introduce frozen arrays in the language with a user model. This JEP proposes a more incremental approach, validating internal use cases and optimizations before rolling it out to users.

The current workaround for lack of constant folding is an internal annotation called @jdk.internal.vm.annotation.Stable. (In fact, frozen arrays are likely to use some of the same JIT optimization techniques as stable arrays.) We could continue to rely on that feature, without frozen arrays. But that has two problems: First, stable arrays are null-hostile, which sometimes causes inconveniences for (internal) users. Second, stable arrays do not yet have a well-accepted safe user model (as frozen arrays are likely to) so that stable arrays might never roll out as a public featuure.

This is a first step towards user-visible frozen arrays. Please see JDK-8261007 for the full description of non-internal APIs and use cases.

Risks and Assumptions

The extra checks on array stores require some careful optimizer work, analogous to null pointer removal. These might cause performance problems.

We might fail to build a user model, and be prevented from making these arrays available to end users, thus limiting their benefit.

Dependencies and Future Work

There are no dependencies on existing work.

Some engineering of array store checks for Project Valhalla may cross-apply to the mutability store checks required by this JEP.

This is a first step towards user-visible frozen arrays. Please see JDK-8261007, which depends on the low-level internal primitives defined by this work.