frozen arrays
Stuart Marks
stuart.marks at oracle.com
Sat Feb 27 00:57:14 UTC 2021
Hi John,
Thanks for posting these drafts, and for separating them into internal and public
components. As a libraries maintainer, I see a lot of immediate applicability for
using frozen arrays internally, particularly the ability to create and populate an
array in the usual fashion and then to freeze it in-place. I took a look through a
bunch of JDK classes and I came up with the following use cases:
1. private static final arrays with computed values
It's very common in the JDK to have an array that is filled with values that are
computed or constructed at static initialization time, that is then treated as a
constant thereafter. See [1] for an example. This is the main use case for the
"freeze-in-place" operation. Right now the array is simply allocated and filled in,
and it's only treated as a constant by convention -- we ensure that no code writes
to it after it's initialized. A create-a-frozen-copy operation would require
allocation of and copying into another array, which seems unnecessary here. Since
this is JDK internal code, it's ok to expose it to the concept of a frozen-in-place
array, and we get the added bonuses of some assurance that the contents can never be
changed, as well as some possible compiler optimizations.
2. private static final arrays with constant values
This is also a very common case. See [2] for an example. The difference is that the
values are compile-time constants instead of values that are computed at runtime.
This may afford some additional optimizations now or in the future, such as using
condy to load the data out of the constant pool into a frozen array.
3. javac-generated arrays from language translation
Each Enum class has a private $VALUES array that contains all the enum constant
instances. This is constructed during static initialization of the enum class.
Additionally, code that switches over enums creates a $SwitchMap$ class that
contains an int[] containing the ordinals of the enum constants. This is constructed
by a static initializer, I think the first time the switch is evaluated.
Probably both of these arrays could be frozen-in-place. But note this is in
javac-generated bytecode, so that would require making the freeze-in-place operation
public. Or, the compiler could generate a call to the public make-a-frozen-copy
operation, and the compiler might be able to optimize it away. (But static
initialization is often interpreted. Hmmm.)
4. unmodifiable collections (List.of [3] Set.of [4] et al)
The unmodifiable collections create arrays to contain their elements. Since they are
unmodifiable (shallowly immutable) they could also be frozen arrays.
The unmodifiable Set [4] and Map [5] implementations need to create the array and
hash the elements into place, so the freeze-in-place operation would be applicable
to these. The unmodifiable List [3] implementations could use a create-a-frozen-copy
operation; the List's internal array could be a copy created by freezing the varargs
array passed to the List.of(E...) method, or a frozen copy of the array obtained by
calling toArray() on the argument of List.copyOf(arg).
**
I'm finding it fairly difficult to come up with use cases for the proposed public
create-a-frozen-copy operation. In particular it doesn't seem too useful for
avoiding making defensive copies.
For example, one pain point is that the array returned by Enum.values() must be a
copy of the internal $VALUES array, because all such arrays are implicitly
modifiable. Even if $VALUES itself becomes frozen, the array returned by values() is
modifiable and so must be a copy. We'd have to change or add a new API to allow the
returned array to be frozen. (Maybe APIs like this could be part of the preview.)
Another example is the copy-constructors for various modifiable collections such as
ArrayList. When one is created by a copy constructor, it first calls toArray() on
the argument to get the argument's contents. Then it copies the array *again* for
internal use. Neither array can be frozen, since toArray() implicitly returns a
modifiable array, and the ArrayList internal array must also be modifiable.
Given that all APIs that return arrays implicitly require those arrays to be
modifiable (even if it's unlikely they'll be modified by the caller), new APIs would
have to be added to return frozen arrays. I suspect that most such usages are
already read-only, such as Enum.values() and various array-returning reflection
methods. Perhaps another useful exercise would be to examine various APIs where
frozen-array counterparts could be added.
s'marks
[1]
https://github.com/openjdk/jdk16/blob/master/src/java.base/share/classes/java/math/BigDecimal.java#L287
[2]
https://github.com/openjdk/jdk16/blob/master/src/java.base/share/classes/java/math/BigDecimal.java#L4054
[3]
https://docs.oracle.com/en/java/javase/15/docs/api/java.base/java/util/List.html#unmodifiable
[4]
https://docs.oracle.com/en/java/javase/15/docs/api/java.base/java/util/Set.html#unmodifiable
[5]
https://docs.oracle.com/en/java/javase/15/docs/api/java.base/java/util/Map.html#unmodifiable
On 2/3/21 4:23 PM, John Rose wrote:
> We use @Stable arrays internally to instruct the JIT
> to constant-fold through array elements.
>
> A long-term goal is to replace those (when lazy
> evaluation is not required) with first-class frozen
> arrays. Doing this right, as a generally useful
> feature (not an internal hack) will require a
> carefully balanced user model, changes to the
> language and VM specs, and some JIT and
> runtime work.
>
> Towards that end, I have filed a pair of JEPs
> which document a way forward towards
> frozen arrays, starting with an internal
> alternative to @Stable.
>
> Please see:
>
> the name is Arrays, Frozen Arrays
> https://bugs.openjdk.java.net/browse/JDK-8261007
>
> and Internal Frozen Arrays (the prequel)
> https://bugs.openjdk.java.net/browse/JDK-8261099
>
> — John
>
> P.S. Hat tip to early commenters on Slack: Brian, Stuart,
> Jon, and Alan. Stuart convinced me to split it into two.
>
More information about the hotspot-runtime-dev
mailing list