JDK-8261099 : Internal Frozen Arrays
  • Type: JEP
  • Component: hotspot
  • Sub-Component: compiler
  • Priority: P3
  • Status: Draft
  • Resolution: Unresolved
  • Submitted: 2021-02-03
  • Updated: 2024-06-06
Related Reports
Relates :  
Relates :  
Description
# 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][JDK-8261007].

[JDK-8261007]: <https://bugs.openjdk.java.net/browse/JDK-8261007>


# 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][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][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][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:

 - They are in fact unsafe in the presence of race conditions,
   since an array might have concurrent state changes which are
   inconsistent with one thread's intentions to lock down an array.

 - They are also unsafe because they can be applied to "uncooperative"
   arrays, causing possibly dangerous failures (denials of service)
   when the affected arrays are used later by other modules.

 - They need to be "held tightly" until a safer user model is rolled
   out.

 - Any current user of `Unsafe` is likely to be "peeking and poking"
   into arrays, and must therefore be upgraded to respect the
   immutability of frozen arrays.  Putting these methods into a new
   restricted API would make it incrementally more difficult to
   find and fix affected `Unsafe` code.

# 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][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][JDK-8261007], which depends on the low-level internal
primitives defined by this work.