diff --git a/src/java.base/share/classes/java/lang/StableValue.java b/src/java.base/share/classes/java/lang/StableValue.java new file mode 100644 index 0000000000000..b12d6f5e92128 --- /dev/null +++ b/src/java.base/share/classes/java/lang/StableValue.java @@ -0,0 +1,757 @@ +/* + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package java.lang; + +import jdk.internal.access.SharedSecrets; +import jdk.internal.javac.PreviewFeature; +import jdk.internal.lang.stable.StableEnumFunction; +import jdk.internal.lang.stable.StableFunction; +import jdk.internal.lang.stable.StableIntFunction; +import jdk.internal.lang.stable.StableSupplier; +import jdk.internal.lang.stable.StableUtil; +import jdk.internal.lang.stable.StableValueImpl; + +import java.io.Serializable; +import java.util.Collection; +import java.util.EnumSet; +import java.util.List; +import java.util.Map; +import java.util.NoSuchElementException; +import java.util.Objects; +import java.util.RandomAccess; +import java.util.Set; +import java.util.function.Function; +import java.util.function.IntFunction; +import java.util.function.Supplier; + +/** + * A stable value is a holder of contents that can be set at most once. + *
+ * A {@code StableValue
+ * Consider the following example where a stable value field "{@code logger}" is a
+ * shallowly immutable holder of contents of type {@code Logger} and that is initially
+ * created as unset, which means it holds no contents. Later in the example, the
+ * state of the "{@code logger}" field is checked and if it is still unset,
+ * the contents is set:
+ *
+ * {@snippet lang = java:
+ * public class Component {
+ *
+ * // Creates a new unset stable value with no contents
+ * // @link substring="of" target="#of" :
+ * private final StableValue
+ * If {@code getLogger()} is called from several threads, several instances of
+ * {@code Logger} might be created. However, the contents can only be set at most once
+ * meaning the first writer wins.
+ *
+ * In order to guarantee that, even under races, only one instance of {@code Logger} is
+ * ever created, the {@linkplain #orElseSet(Supplier) orElseSet()} method can be used
+ * instead, where the contents are lazily computed, and atomically set, via a
+ * {@linkplain Supplier supplier}. In the example below, the supplier is provided in the
+ * form of a lambda expression:
+ *
+ * {@snippet lang = java:
+ * public class Component {
+ *
+ * // Creates a new unset stable value with no contents
+ * // @link substring="of" target="#of" :
+ * private final StableValue
+ * The {@code getLogger()} method calls {@code logger.orElseSet()} on the stable value to
+ * retrieve its contents. If the stable value is unset, then {@code orElseSet()}
+ * evaluates the given supplier, and sets the contents to the result; the result is then
+ * returned to the client. In other words, {@code orElseSet()} guarantees that a
+ * stable value's contents is set before it returns.
+ *
+ * Furthermore, {@code orElseSet()} guarantees that out of one or more suppliers provided,
+ * only at most one is ever evaluated, and that one is only ever evaluated once,
+ * even when {@code logger.orElseSet()} is invoked concurrently. This property is crucial
+ * as evaluation of the supplier may have side effects, for example, the call above to
+ * {@code Logger.create()} may result in storage resources being prepared.
+ *
+ *
+ * A stable int function is a function that takes an {@code int} parameter and
+ * uses it to compute a result that is then cached by the backing stable value storage
+ * for that parameter value. A stable {@link IntFunction} is created via the
+ * {@linkplain StableValue#intFunction(int, IntFunction) StableValue.intFunction()}
+ * factory. Upon creation, the input range (i.e. {@code [0, size)}) is specified together
+ * with an underlying {@linkplain IntFunction} which is invoked at most once per input
+ * value. In effect, the stable int function will act like a cache for the underlying
+ * {@linkplain IntFunction}:
+ *
+ * {@snippet lang = java:
+ * final class PowerOf2Util {
+ *
+ * private PowerOf2Util() {}
+ *
+ * private static final int SIZE = 6;
+ * private static final IntFunction
+ * A stable function is a function that takes a parameter (of type {@code T}) and
+ * uses it to compute a result (of type {@code R}) that is then cached by the backing
+ * stable value storage for that parameter value. A stable function is created via the
+ * {@linkplain StableValue#function(Set, Function) StableValue.function()} factory.
+ * Upon creation, the input {@linkplain Set} is specified together with an underlying
+ * {@linkplain Function} which is invoked at most once per input value. In effect, the
+ * stable function will act like a cache for the underlying {@linkplain Function}:
+ *
+ * {@snippet lang = java:
+ * class Log2Util {
+ *
+ * private Log2Util() {}
+ *
+ * private static final Set
+ * Similarly, a stable map is an unmodifiable map whose keys are known at
+ * construction. The stable map values are computed when they are first accessed,
+ * using a provided {@linkplain Function}:
+ *
+ * {@snippet lang = java:
+ * class Log2Util {
+ *
+ * private Log2Util() {}
+ *
+ * private static final Set
+ * Another example, which has a more complex dependency graph, is to compute the
+ * Fibonacci sequence lazily:
+ * {@snippet lang = java:
+ * public final class Fibonacci {
+ *
+ * private Fibonacci() {}
+ *
+ * private static final int MAX_SIZE_INT = 46;
+ *
+ * private static final IntFunction
+ * The fibonacci example above is a directed acyclic graph (i.e.,
+ * it has no circular dependencies and is therefore a dependency tree):
+ *{@snippet lang=text :
+ *
+ * ___________fib(5)____________
+ * / \
+ * ____fib(4)____ ____fib(3)____
+ * / \ / \
+ * fib(3) fib(2) fib(2) fib(1)
+ * / \ / \ / \
+ * fib(2) fib(1) fib(1) fib(0) fib(1) fib(0)
+ *}
+ *
+ * If there are circular dependencies in a dependency graph, a stable value will
+ * eventually throw an {@linkplain IllegalStateException} upon referencing elements in
+ * a circularity.
+ *
+ *
+ * The at-most-once write operation on a stable value that succeeds
+ * (e.g. {@linkplain #trySet(Object) trySet()})
+ * {@linkplain java.util.concurrent##MemoryVisibility happens-before}
+ * any successful read operation (e.g. {@linkplain #orElseThrow()}).
+ * A successful write operation can be either:
+ *
+ * The method {@link #orElseSet(Supplier)} guarantees that the provided
+ * {@linkplain Supplier} is invoked successfully at most once, even under race.
+ * Invocations of {@link #setOrThrow(Object)} form a total order of zero or more
+ * exceptional invocations followed by zero (if the contents were already set) or one
+ * successful invocation. Since stable functions and stable collections are built on top
+ * of the same principles as {@linkplain StableValue#orElseSet(Supplier) orElseSet()} they
+ * too are thread safe and guarantee at-most-once-per-input invocation.
+ *
+ *
+ * Except for a {@code StableValue}'s contents itself,
+ * an {@linkplain #orElse(Object) orElse(other)} parameter, and
+ * an {@linkplain #equals(Object) equals(obj)} parameter; all
+ * method parameters must be non-null or a {@link NullPointerException}
+ * will be thrown.
+ *
+ * @implNote A {@code StableValue} is mainly intended to be a non-public field in
+ * a class and is usually neither exposed directly via accessors nor passed as
+ * a method parameter.
+ *
+ * Stable functions and collections make reasonable efforts to provide
+ * {@link Object#toString()} operations that do not trigger evaluation
+ * of the internal stable values when called.
+ * Stable collections have {@link Object#equals(Object)} operations that try
+ * to minimize evaluation of the internal stable values when called.
+ *
+ * As objects can be set via stable values but never removed, this can be a
+ * source of unintended memory leaks. A stable value's contents are
+ * {@linkplain java.lang.ref##reachability strongly reachable}.
+ * Be advised that reachable stable values will hold their set contents until
+ * the stable value itself is collected.
+ *
+ * A {@code StableValue} that has a type parameter {@code T} that is an array
+ * type (of arbitrary rank) will only allow the JVM to treat the
+ * array reference as a stable value but not its components.
+ * Instead, a {@linkplain #list(int, IntFunction) a stable list} of arbitrary
+ * depth can be used, which provides stable components. More generally, a
+ * stable value can hold other stable values of arbitrary depth and still
+ * provide transitive constantness.
+ *
+ * Stable values, functions, and collections are not {@link Serializable}.
+ *
+ * @param
+ * When this method returns, the contents of this StableValue is always set.
+ *
+ * @return {@code true} if the contents of this StableValue was set to the
+ * provided {@code contents}, {@code false} otherwise
+ * @param contents to set
+ * @throws IllegalStateException if a supplier invoked by {@link #orElseSet(Supplier)}
+ * recursively attempts to set this stable value by calling this method
+ * directly or indirectly.
+ */
+ boolean trySet(T contents);
+
+ /**
+ * {@return the contents if set, otherwise, returns the provided {@code other} value}
+ *
+ * @param other to return if the contents is not set
+ */
+ T orElse(T other);
+
+ /**
+ * {@return the contents if set, otherwise, throws {@code NoSuchElementException}}
+ *
+ * @throws NoSuchElementException if no contents is set
+ */
+ T orElseThrow();
+
+ /**
+ * {@return {@code true} if the contents is set, {@code false} otherwise}
+ */
+ boolean isSet();
+
+ /**
+ * {@return the contents; if unset, first attempts to compute and set the
+ * contents using the provided {@code supplier}}
+ *
+ * The provided {@code supplier} is guaranteed to be invoked at most once if it
+ * completes without throwing an exception. If this method is invoked several times
+ * with different suppliers, only one of them will be invoked provided it completes
+ * without throwing an exception.
+ *
+ * If the supplier throws an (unchecked) exception, the exception is rethrown and no
+ * contents is set. The most common usage is to construct a new object serving
+ * as a lazily computed value or memoized result, as in:
+ *
+ * {@snippet lang=java:
+ * Value v = stable.orElseSet(Value::new);
+ * }
+ *
+ * When this method returns successfully, the contents is always set.
+ *
+ * The provided {@code supplier} will only be invoked once even if invoked from
+ * several threads unless the {@code supplier} throws an exception.
+ *
+ * @param supplier to be used for computing the contents, if not previously set
+ * @throws IllegalStateException if the provided {@code supplier} recursively
+ * attempts to set this stable value.
+ */
+ T orElseSet(Supplier extends T> supplier);
+
+ // Convenience methods
+
+ /**
+ * Sets the contents of this StableValue to the provided {@code contents}, or, if
+ * already set, throws {@code IllegalStateException}.
+ *
+ * When this method returns (or throws an exception), the contents is always set.
+ *
+ * @param contents to set
+ * @throws IllegalStateException if the contents was already set
+ */
+ void setOrThrow(T contents);
+
+ // Object methods
+
+ /**
+ * {@return {@code true} if {@code this == obj}, {@code false} otherwise}
+ *
+ * @param obj to check for equality
+ */
+ boolean equals(Object obj);
+
+ /**
+ * {@return the {@linkplain System#identityHashCode(Object) identity hash code} of
+ * {@code this} object}
+ */
+ int hashCode();
+
+ // Factories
+
+ /**
+ * {@return a new unset stable value}
+ *
+ * An unset stable value has no contents.
+ *
+ * @param
+ * The returned {@linkplain Supplier supplier} is a caching supplier that records
+ * the value of the provided {@code underlying} supplier upon being first accessed via
+ * the returned supplier's {@linkplain Supplier#get() get()} method.
+ *
+ * The provided {@code underlying} supplier is guaranteed to be successfully invoked
+ * at most once even in a multi-threaded environment. Competing threads invoking the
+ * returned supplier's {@linkplain Supplier#get() get()} method when a value is
+ * already under computation will block until a value is computed or an exception is
+ * thrown by the computing thread. The computing threads will then observe the newly
+ * computed value (if any) and will then never execute.
+ *
+ * If the provided {@code underlying} supplier throws an exception, it is rethrown
+ * to the initial caller and no contents is recorded.
+ *
+ * If the provided {@code underlying} supplier recursively calls the returned
+ * supplier, an {@linkplain IllegalStateException} will be thrown.
+ *
+ * @param underlying supplier used to compute a cached value
+ * @param
+ * The returned function is a caching function that, for each allowed {@code int}
+ * input, records the values of the provided {@code underlying}
+ * function upon being first accessed via the returned function's
+ * {@linkplain IntFunction#apply(int) apply()} method. If the returned function is
+ * invoked with an input that is not in the range {@code [0, size)}, an
+ * {@link IllegalArgumentException} will be thrown.
+ *
+ * The provided {@code underlying} function is guaranteed to be successfully invoked
+ * at most once per allowed input, even in a multi-threaded environment. Competing
+ * threads invoking the returned function's
+ * {@linkplain IntFunction#apply(int) apply()} method when a value is already under
+ * computation will block until a value is computed or an exception is thrown by
+ * the computing thread.
+ *
+ * If invoking the provided {@code underlying} function throws an exception, it is
+ * rethrown to the initial caller and no contents is recorded.
+ *
+ * If the provided {@code underlying} function recursively calls the returned
+ * function for the same input, an {@linkplain IllegalStateException} will
+ * be thrown.
+ *
+ * @param size the size of the allowed inputs in the continuous
+ * interval {@code [0, size)}
+ * @param underlying IntFunction used to compute cached values
+ * @param
+ * The returned function is a caching function that, for each allowed
+ * input in the given set of {@code inputs}, records the values of the provided
+ * {@code underlying} function upon being first accessed via the returned function's
+ * {@linkplain Function#apply(Object) apply()} method. If the returned function is
+ * invoked with an input that is not in {@code inputs}, an {@link IllegalArgumentException}
+ * will be thrown.
+ *
+ * The provided {@code underlying} function is guaranteed to be successfully invoked
+ * at most once per allowed input, even in a multi-threaded environment. Competing
+ * threads invoking the returned function's {@linkplain Function#apply(Object) apply()}
+ * method when a value is already under computation will block until a value is
+ * computed or an exception is thrown by the computing thread.
+ *
+ * If invoking the provided {@code underlying} function throws an exception, it is
+ * rethrown to the initial caller and no contents is recorded.
+ *
+ * If the provided {@code underlying} function recursively calls the returned
+ * function for the same input, an {@linkplain IllegalStateException} will
+ * be thrown.
+ *
+ * @param inputs the set of (non-null) allowed input values
+ * @param underlying {@code Function} used to compute cached values
+ * @param
+ * The returned list is an {@linkplain Collection##unmodifiable unmodifiable} list
+ * with the provided {@code size}. The list's elements are computed via the
+ * provided {@code mapper} when they are first accessed
+ * (e.g. via {@linkplain List#get(int) List::get}).
+ *
+ * The provided {@code mapper} function is guaranteed to be successfully invoked
+ * at most once per list index, even in a multi-threaded environment. Competing
+ * threads accessing an element already under computation will block until an element
+ * is computed or an exception is thrown by the computing thread.
+ *
+ * If invoking the provided {@code mapper} function throws an exception, it
+ * is rethrown to the initial caller and no value for the element is recorded.
+ *
+ * Any direct {@link List#subList(int, int) subList} or {@link List#reversed()} views
+ * of the returned list are also stable.
+ *
+ * The returned list and its {@link List#subList(int, int) subList} or
+ * {@link List#reversed()} views implement the {@link RandomAccess} interface.
+ *
+ * The returned list is unmodifiable and does not implement the
+ * {@linkplain Collection##optional-operation optional operations} in the
+ * {@linkplain List} interface.
+ *
+ * If the provided {@code mapper} recursively calls the returned list for the
+ * same index, an {@linkplain IllegalStateException} will be thrown.
+ *
+ * @param size the size of the returned list
+ * @param mapper to invoke whenever an element is first accessed
+ * (may return {@code null})
+ * @param
+ * The returned map is an {@linkplain Collection##unmodifiable unmodifiable} map whose
+ * keys are known at construction. The map's values are computed via the provided
+ * {@code mapper} when they are first accessed
+ * (e.g. via {@linkplain Map#get(Object) Map::get}).
+ *
+ * The provided {@code mapper} function is guaranteed to be successfully invoked
+ * at most once per key, even in a multi-threaded environment. Competing
+ * threads accessing a value already under computation will block until an element
+ * is computed or an exception is thrown by the computing thread.
+ *
+ * If invoking the provided {@code mapper} function throws an exception, it
+ * is rethrown to the initial caller and no value associated with the provided key
+ * is recorded.
+ *
+ * Any direct {@link Map#values()} or {@link Map#entrySet()} views
+ * of the returned map are also stable.
+ *
+ * The returned map is unmodifiable and does not implement the
+ * {@linkplain Collection##optional-operations optional operations} in the
+ * {@linkplain Map} interface.
+ *
+ * If the provided {@code mapper} recursively calls the returned map for
+ * the same key, an {@linkplain IllegalStateException} will be thrown.
+ *
+ * @param keys the (non-null) keys in the returned map
+ * @param mapper to invoke whenever an associated value is first accessed
+ * (may return {@code null})
+ * @param Stable Functions
+ * Stable values provide the foundation for higher-level functional abstractions. A
+ * stable supplier is a supplier that computes a value and then caches it into
+ * a backing stable value storage for subsequent use. A stable supplier is created via the
+ * {@linkplain StableValue#supplier(Supplier) StableValue.supplier()} factory, by
+ * providing an underlying {@linkplain Supplier} which is invoked when the stable supplier
+ * is first accessed:
+ *
+ * {@snippet lang = java:
+ * public class Component {
+ *
+ * private final SupplierStable Collections
+ * Stable values can also be used as backing storage for
+ * {@linkplain Collection##unmodifiable unmodifiable collections}. A stable list
+ * is an unmodifiable list, backed by an array of stable values. The stable list elements
+ * are computed when they are first accessed, using a provided {@linkplain IntFunction}:
+ *
+ * {@snippet lang = java:
+ * final class PowerOf2Util {
+ *
+ * private PowerOf2Util() {}
+ *
+ * private static final int SIZE = 6;
+ * private static final IntFunctionComposing stable values
+ * A stable value can depend on other stable values, forming a dependency graph
+ * that can be lazily computed but where access to individual elements can still be
+ * performant. In the following example, a single {@code Foo} and a {@code Bar}
+ * instance (that is dependent on the {@code Foo} instance) are lazily created, both of
+ * which are held by stable values:
+ * {@snippet lang = java:
+ * public final class DependencyUtil {
+ *
+ * private DependencyUtil() {}
+ *
+ * public static class Foo {
+ * // ...
+ * }
+ *
+ * public static class Bar {
+ * public Bar(Foo foo) {
+ * // ...
+ * }
+ * }
+ *
+ * private static final SupplierThread Safety
+ * The contents of a stable value is guaranteed to be set at most once. If competing
+ * threads are racing to set a stable value, only one update succeeds, while the other
+ * updates are blocked until the stable value is set, whereafter the other updates
+ * observes the stable value is set and leave the stable value unchanged.
+ *
+ *
+ * A successful read operation can be either:
+ *
+ *
+ * Performance
+ * As the contents of a stable value can never change after it has been set, a JVM
+ * implementation may, for a set stable value, elide all future reads of that
+ * stable value, and instead directly use any contents that it has previously observed.
+ * This is true if the reference to the stable value is a constant (e.g. in cases where
+ * the stable value itself is stored in a {@code static final} field). Stable functions
+ * and collections are built on top of StableValue. As such, they might also be eligible
+ * for the same JVM optimizations as for StableValue.
+ *
+ * @implSpec Implementing classes of {@code StableValue} are free to synchronize on
+ * {@code this} and consequently, it should be avoided to
+ * (directly or indirectly) synchronize on a {@code StableValue}. Hence,
+ * synchronizing on {@code this} may lead to deadlock.
+ *