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..3f6553f58a04a --- /dev/null +++ b/src/java.base/share/classes/java/lang/StableValue.java @@ -0,0 +1,654 @@ +/* + * Copyright (c) 2024, 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.javac.PreviewFeature; +import jdk.internal.lang.stable.StableValueImpl; +import jdk.internal.lang.stable.StableValueFactories; + +import java.io.Serializable; +import java.util.Collection; +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 shallowly immutable holder of deferred content. + *
+ * A {@linkplain StableValue {@code StableValue
+ * A stable value that is set is treated as a constant by the JVM, enabling the
+ * same performance optimizations that are available for {@code final} fields.
+ * As such, stable values can be used to replace {@code final} fields in cases where
+ * at-most-once update semantics is crucial, but where the eager initialization
+ * semantics associated with {@code final} fields is too restrictive.
+ *
+ * Consider the following example where a stable value field "{@code logger}" is a
+ * shallowly immutable holder of content of type {@code Logger} and that is initially
+ * created as unset, which means it holds no content. Later in the example, the
+ * state of the "{@code logger}" field is checked and if it is still unset,
+ * the content is set:
+ *
+ * {@snippet lang = java:
+ * public class Component {
+ *
+ * // Creates a new unset stable value with no content
+ * // @link substring="of" target="#of" :
+ * private final StableValue
+ * Note that the holder value can only be set at most once.
+ * In the example above, the {@code logger} field is declared {@code final} which is
+ * a prerequisite for being treated as a constant by the JVM.
+ *
+ *
+ * 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 content is atomically and lazily computed 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 content
+ * // @link substring="of" target="#of" :
+ * private final StableValue
+ * The {@code getLogger()} method calls {@code logger.orElseSet()} on the stable value to
+ * retrieve its content. If the stable value is unset, then {@code orElseSet()}
+ * evaluates and sets the content; the content is then returned to the client. In other
+ * words, {@code orElseSet()} guarantees that a stable value's content is set
+ * before it is used.
+ *
+ * Furthermore, {@code orElseSet()} guarantees that the supplier provided is
+ * evaluated only once, even when {@code logger.orElseSet()} is invoked concurrently.
+ * This property is crucial as evaluation of the supplier may have side effects,
+ * e.g., the call above to {@code Logger.getLogger()} 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 int function is created via the
+ * {@linkplain StableValue#intFunction(int, IntFunction) StableValue.intFunction()}
+ * factory. Upon creation, the input range (i.e. [0, size)) is specified together with
+ * an original {@linkplain IntFunction} which is invoked at most once per input value. In
+ * effect, the stable int function will act like a cache for the original {@linkplain IntFunction}:
+ *
+ * {@snippet lang = java:
+ * public final class SqrtUtil {
+ *
+ * private SqrtUtil(){}
+ *
+ * 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 original
+ * {@linkplain Function} which is invoked at most once per input value. In effect, the
+ * stable function will act like a cache for the original {@linkplain Function}:
+ *
+ * {@snippet lang = java:
+ * public final class SqrtUtil {
+ *
+ * private SqrtUtil(){}
+ *
+ * private static final Function
+ * 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:
+ * public final class SqrtUtil {
+ *
+ * private SqrtUtil(){}
+ *
+ * private static final Map
+ * Here is another example where a more complex dependency graph is created in which
+ * integers in the Fibonacci delta series are lazily computed:
+ * {@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 dependency graph with no circular dependencies (i.e.,
+ * it is a dependency tree). If there are circular dependencies in a dependency graph,
+ * a stable value will eventually throw a {@linkplain StackOverflowError} upon referencing
+ * elements in a circularity.
+ *
+ *
+ * The at-most-once write operation on a stable value that succeeds
+ * (e.g. {@linkplain #trySet(Object) trySet()})
+ * happens-before
+ * any subsequent read operation (e.g. {@linkplain #orElseThrow()}).
+ *
+ * The method {@linkplain StableValue#orElseSet(Supplier) orElseSet()} guarantees that
+ * the provided {@linkplain Supplier} is invoked successfully at most once even under
+ * race. Since stable functions and stable collections are built on top of
+ * {@linkplain StableValue#orElseSet(Supplier) orElseSet()} they too are
+ * thread safe and guarantee at-most-once-per-input invocation.
+ *
+ *
+ * Stable functions and collections are not {@link Serializable} as this would require
+ * {@linkplain #list(int, IntFunction) mappers} to be {@link Serializable} as well,
+ * which would introduce security vulnerabilities.
+ *
+ * As objects can be set via stable values but never removed, this can be a source
+ * of unintended memory leaks. A stable value's content is
+ * {@linkplain java.lang.ref##reachability strongly reachable}. Clients are advised that
+ * {@linkplain java.lang.ref##reachability reachable} stable values will hold their set
+ * content perpetually.
+ *
+ * A {@linkplain 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. Clients can instead use
+ * {@linkplain #list(int, IntFunction) a stable list} of arbitrary depth, which provides
+ * stable components. More generally, a stable value can hold other stable values of
+ * arbitrary depth and still provide transitive constantness.
+ *
+ * @implSpec Implementing classes of {@linkplain StableValue} are free to synchronize on
+ * {@code this} and consequently, care should be taken whenever
+ * (directly or indirectly) synchronizing on a {@code StableValue}. Failure to
+ * do this may lead to deadlock. Stable functions and collections on the
+ * other hand are guaranteed not to synchronize on {@code this}.
+ *
+ * @implNote A {@linkplain 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.
+ *
+ * @param
+ * When this method returns, the content is always set.
+ *
+ * @param value to set
+ */
+ boolean trySet(T value);
+
+ /**
+ * {@return the content if set, otherwise, returns the provided {@code other} value}
+ *
+ * @param other to return if the content is not set
+ */
+ T orElse(T other);
+
+ /**
+ * {@return the content if set, otherwise, throws {@code NoSuchElementException}}
+ *
+ * @throws NoSuchElementException if no content is set
+ */
+ T orElseThrow();
+
+ /**
+ * {@return {@code true} if the content is set, {@code false} otherwise}
+ */
+ boolean isSet();
+
+ /**
+ * {@return the content; if unset, first attempts to compute and set the
+ * content 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 the supplier throws an (unchecked) exception, the exception is rethrown, and no
+ * content 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 witness = stable.orElseSet(Value::new);
+ * }
+ *
+ * When this method returns successfully, the content is always set.
+ *
+ * @implSpec The implementation logic is equivalent to the following steps for this
+ * {@code stable}:
+ *
+ * {@snippet lang=java:
+ * if (stable.isSet()) {
+ * return stable.get();
+ * } else {
+ * T newValue = supplier.get();
+ * stable.setOrThrow(newValue);
+ * return newValue;
+ * }
+ * }
+ * Except it is thread-safe and will only return the same witness value
+ * regardless if invoked by several threads. Also, 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 content, if not previously set
+ */
+ T orElseSet(Supplier extends T> supplier);
+
+ // Convenience methods
+
+ /**
+ * Sets the content to the provided {@code value}, or, if already set,
+ * throws {@code IllegalStateException}.
+ *
+ * When this method returns (or throws an exception), the content is always set.
+ *
+ * @param value to set
+ * @throws IllegalStateException if the content was already set
+ */
+ void setOrThrow(T value);
+
+ // 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 content.
+ *
+ * The returned stable value is not {@link Serializable}.
+ *
+ * @param
+ * The returned stable value is not {@link Serializable}.
+ *
+ * @param content to set
+ * @param
+ * The returned {@linkplain Supplier supplier} is a caching supplier that records
+ * the value of the provided {@code original} supplier upon being first accessed via
+ * the returned supplier's {@linkplain Supplier#get() get()} method.
+ *
+ * The provided {@code original} 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.
+ *
+ * If the provided {@code original} supplier throws an exception, it is relayed
+ * to the initial caller and no content is recorded.
+ *
+ * The returned supplier is not {@link Serializable}.
+ *
+ * @param original supplier used to compute a cached value
+ * @param
+ * The returned {@link IntFunction int function} is a caching int function that,
+ * for each allowed input, records the values of the provided {@code original}
+ * int function upon being first accessed via the returned int function's
+ * {@linkplain IntFunction#apply(int) apply()} method.
+ *
+ * The provided {@code original} int function is guaranteed to be successfully invoked
+ * at most once per allowed input, even in a multi-threaded environment. Competing
+ * threads invoking the returned int 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 the provided {@code original} int function throws an exception, it is relayed
+ * to the initial caller and no content is recorded.
+ *
+ * The returned int function is not {@link Serializable}.
+ *
+ * @param size the size of the allowed inputs in {@code [0, size)}
+ * @param original IntFunction used to compute cached values
+ * @param
+ * The returned {@link Function function} is a caching function that, for each allowed
+ * input in the given set of {@code inputs}, records the values of the provided
+ * {@code original} function upon being first accessed via the returned function's
+ * {@linkplain Function#apply(Object) apply()} method.
+ *
+ * The provided {@code original} 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 the provided {@code original} function throws an exception, it is relayed to
+ * the initial caller and no content is recorded.
+ *
+ * The returned function is not {@link Serializable}.
+ *
+ * @param inputs the set of allowed input values
+ * @param original Function used to compute cached values
+ * @param
+ * The returned list is an {@linkplain Collection##unmodifiable unmodifiable} list
+ * whose size is known at construction. 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} int 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 the provided {@code mapper} throws an exception, it is relayed to the initial
+ * caller and no value for the element is recorded.
+ *
+ * The returned list and its {@link List#subList(int, int) subList} views implement
+ * the {@link RandomAccess} interface.
+ *
+ * The returned list is not {@link Serializable} and, as it is unmodifiable, does
+ * not implement the {@linkplain Collection##optional-operation optional operations}
+ * in the {@linkplain List} interface.
+ *
+ * @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 the provided {@code mapper} throws an exception, it is relayed to the initial
+ * caller and no value associated with the provided key is recorded.
+ *
+ * The returned map is not {@link Serializable} and, as it is unmodifiable, does
+ * not implement the {@linkplain Collection##optional-operations optional operations}
+ * in the {@linkplain Map} interface.
+ *
+ * @param keys the 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 later use. A stable supplier is created via the
+ * {@linkplain StableValue#supplier(Supplier) StableValue.supplier()} factory, by
+ * providing an original {@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:
+ * public final class SqrtUtil {
+ *
+ * private SqrtUtil(){}
+ *
+ * private static final ListComposing stable values
+ * A stable value can depend on other stable values, thereby creating a dependency graph
+ * that can be lazily computed but where access to individual elements still can be
+ * constant-folded. 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 content 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 other updates
+ * are blocked until the stable value becomes set.
+ * Miscellaneous
+ * Except for a StableValue's content 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.
+ *