/* * Copyright (c) 2020, 2024, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2020, 2022, Red Hat Inc. * 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 java.util.NoSuchElementException; import java.util.Objects; import java.lang.ref.Reference; import java.util.concurrent.StructuredTaskScope; import java.util.concurrent.StructureViolationException; import java.util.function.Supplier; import jdk.internal.access.JavaUtilConcurrentTLRAccess; import jdk.internal.access.SharedSecrets; import jdk.internal.javac.PreviewFeature; import jdk.internal.vm.annotation.ForceInline; import jdk.internal.vm.annotation.Hidden; import jdk.internal.vm.ScopedValueContainer; import sun.security.action.GetPropertyAction; /** * A value that may be safely and efficiently shared to methods without using method * parameters. * *
In the Java programming language, data is usually passed to a method by means of a * method parameter. The data may need to be passed through a sequence of many methods to * get to the method that makes use of the data. Every method in the sequence of calls * needs to declare the parameter and every method has access to the data. * {@code ScopedValue} provides a means to pass data to a faraway method (typically a * callback) without using method parameters. In effect, a {@code ScopedValue} * is an implicit method parameter. It is "as if" every method in a sequence of * calls has an additional parameter. None of the methods declare the parameter and only * the methods that have access to the {@code ScopedValue} object can access its value * (the data). {@code ScopedValue} makes it possible to securely pass data from a * caller to a faraway callee through a sequence of intermediate methods * that do not declare a parameter for the data and have no access to the data. * *
The {@code ScopedValue} API works by executing a method with a {@code ScopedValue} * object bound to some value for the bounded period of execution of a method. * The method may invoke another method, which in turn may invoke another. The unfolding * execution of the methods define a dynamic scope. Code in these methods with * access to the {@code ScopedValue} object may read its value. The {@code ScopedValue} * object reverts to being unbound when the original method completes normally or * with an exception. The {@code ScopedValue} API supports executing a {@link Runnable}, * or {@link CallableOp} with a {@code ScopedValue} bound to a value. * *
Consider the following example with a scoped value "{@code NAME}" bound to the value
* "{@code duke}" for the execution of a {@code Runnable}'s {@code run} method.
* The {@code run} method, in turn, invokes a method {@code doSomething}.
*
*
* {@snippet lang=java :
* // @link substring="newInstance" target="#newInstance" :
* private static final ScopedValue The example using {@code runWhere} invokes a method that does not return a result.
* The {@link #callWhere(ScopedValue, Object, CallableOp) callWhere} method can be used
* to invoke a method that returns a result.
* In addition, {@code ScopedValue} defines the {@link #where(ScopedValue, Object)} method
* for cases where multiple mappings (of {@code ScopedValue} to value) are accumulated
* in advance of calling a method with all {@code ScopedValue}s bound to their value.
*
* In the example, if code executed by one thread invokes this:
* {@snippet lang=java :
* ScopedValue.runWhere(NAME, "duke1", () -> doSomething());
* }
* and code executed by another thread invokes:
* {@snippet lang=java :
* ScopedValue.runWhere(NAME, "duke2", () -> doSomething());
* }
* then code in {@code doSomething} (or any method that it calls) invoking {@code NAME.get()}
* will read the value "{@code duke1}" or "{@code duke2}", depending on which thread is
* executing.
*
* In the above example, suppose that code executed by {@code doSomething} binds
* {@code NAME} to a new value with:
* {@snippet lang=java :
* ScopedValue.runWhere(NAME, "duchess", () -> doMore());
* }
* Code executed directly or indirectly by {@code doMore()} that invokes {@code
* NAME.get()} will read the value "{@code duchess}". When {@code doMore()} completes
* then the value of {@code NAME} reverts to "{@code duke}".
*
* A {@code ScopedValue} that is shared across threads requires that the value be an
* immutable object or for all access to the value to be appropriately synchronized.
*
* In the following example, the {@code ScopedValue} {@code NAME} is bound to the
* value "{@code duke}" for the execution of a runnable operation. The code in the {@code
* run} method creates a {@code StructuredTaskScope} that forks three tasks. Code executed
* directly or indirectly by these threads running {@code childTask1()}, {@code childTask2()},
* and {@code childTask3()} that invokes {@code NAME.get()} will read the value
* "{@code duke}".
*
* {@snippet lang=java :
* private static final ScopedValue Unless otherwise specified, passing a {@code null} argument to a method in this
* class will cause a {@link NullPointerException} to be thrown.
*
* @apiNote
* A {@code ScopedValue} should be preferred over a {@link ThreadLocal} for cases where
* the goal is "one-way transmission" of data without using method parameters. While a
* {@code ThreadLocal} can be used to pass data to a method without using method parameters,
* it does suffer from a number of issues:
* Because the scoped-value per-thread cache is small, clients
* should minimize the number of bound scoped values in use. For
* example, if it is necessary to pass a number of values in this way,
* it makes sense to create a record class to hold those values, and
* then bind a single {@code ScopedValue} to an instance of that record.
*
* For this release, the reference implementation
* provides some system properties to tune the performance of scoped
* values.
*
* The system property {@code java.lang.ScopedValue.cacheSize}
* controls the size of the (per-thread) scoped-value cache. This cache is crucial
* for the performance of scoped values. If it is too small,
* the runtime library will repeatedly need to scan for each
* {@link #get}. If it is too large, memory will be unnecessarily
* consumed. The default scoped-value cache size is 16 entries. It may
* be varied from 2 to 16 entries in size. {@code ScopedValue.cacheSize}
* must be an integer power of 2.
*
* For example, you could use {@code -Djava.lang.ScopedValue.cacheSize=8}.
*
* The other system property is {@code jdk.preserveScopedValueCache}.
* This property determines whether the per-thread scoped-value
* cache is preserved when a virtual thread is blocked. By default
* this property is set to {@code true}, meaning that every virtual
* thread preserves its scoped-value cache when blocked. Like {@code
* ScopedValue.cacheSize}, this is a space versus speed trade-off: in
* situations where many virtual threads are blocked most of the time,
* setting this property to {@code false} might result in a useful
* memory saving, but each virtual thread's scoped-value cache would
* have to be regenerated after a blocking operation.
*
* @param Unless otherwise specified, passing a {@code null} argument to a constructor
* or method in this class will cause a {@link NullPointerException} to be thrown.
*/
static final class Snapshot {
final Snapshot prev;
final Carrier bindings;
final int bitmask;
private static final Object NIL = new Object();
static final Snapshot EMPTY_SNAPSHOT = new Snapshot();
Snapshot(Carrier bindings, Snapshot prev) {
this.prev = prev;
this.bindings = bindings;
this.bitmask = bindings.bitmask | prev.bitmask;
}
protected Snapshot() {
this.prev = null;
this.bindings = null;
this.bitmask = 0;
}
Object find(ScopedValue> key) {
int bits = key.bitmask();
for (Snapshot snapshot = this;
containsAll(snapshot.bitmask, bits);
snapshot = snapshot.prev) {
for (Carrier carrier = snapshot.bindings;
carrier != null && containsAll(carrier.bitmask, bits);
carrier = carrier.prev) {
if (carrier.getKey() == key) {
Object value = carrier.get();
return value;
}
}
}
return NIL;
}
}
/**
* A mapping of scoped values, as keys, to values.
*
* A {@code Carrier} is used to accumulate mappings so that an operation (a {@link
* Runnable} or {@link CallableOp}) can be executed with all scoped values in the
* mapping bound to values. The following example runs an operation with {@code k1}
* bound (or rebound) to {@code v1}, and {@code k2} bound (or rebound) to {@code v2}.
* {@snippet lang=java :
* // @link substring="where" target="#where(ScopedValue, Object)" :
* ScopedValue.where(k1, v1).where(k2, v2).run(() -> ... );
* }
*
* A {@code Carrier} is immutable and thread-safe. The {@link
* #where(ScopedValue, Object) where} method returns a new {@code Carrier} object,
* it does not mutate an existing mapping.
*
* Unless otherwise specified, passing a {@code null} argument to a method in
* this class will cause a {@link NullPointerException} to be thrown.
*
* @since 21
*/
@PreviewFeature(feature = PreviewFeature.Feature.SCOPED_VALUES)
public static final class Carrier {
// Bit masks: a 1 in postion n indicates that this set of bound values
// hits that slot in the cache.
final int bitmask;
final ScopedValue> key;
final Object value;
final Carrier prev;
Carrier(ScopedValue> key, Object value, Carrier prev) {
this.key = key;
this.value = value;
this.prev = prev;
int bits = key.bitmask();
if (prev != null) {
bits |= prev.bitmask;
}
this.bitmask = bits;
}
/**
* Add a binding to this map, returning a new Carrier instance.
*/
private static Scoped values are intended to be used in a structured manner. If code
* invoked directly or indirectly by the operation creates a {@link StructuredTaskScope}
* but does not {@linkplain StructuredTaskScope#close() close} it, then it is detected
* as a structure violation when the operation completes (normally or with an
* exception). In that case, the underlying construct of the {@code StructuredTaskScope}
* is closed and {@link StructureViolationException} is thrown.
*
* @param op the operation to run
* @param Scoped values are intended to be used in a structured manner. If code
* invoked directly or indirectly by the operation creates a {@link StructuredTaskScope}
* but does not {@linkplain StructuredTaskScope#close() close} it, then it is detected
* as a structure violation when the operation completes (normally or with an
* exception). In that case, the underlying construct of the {@code StructuredTaskScope}
* is closed and {@link StructureViolationException} is thrown.
*
* @param op the operation to run
* @throws StructureViolationException if a structure violation is detected
* @see ScopedValue#runWhere(ScopedValue, Object, Runnable)
*/
public void run(Runnable op) {
Objects.requireNonNull(op);
Cache.invalidate(bitmask);
var prevSnapshot = scopedValueBindings();
var newSnapshot = new Snapshot(this, prevSnapshot);
runWith(newSnapshot, op);
}
/**
* Execute the action with a set of {@code ScopedValue} bindings.
*
* The VM recognizes this method as special, so any changes to the
* name or signature require corresponding changes in
* JVM_FindScopedValueBindings().
*/
@Hidden
@ForceInline
private void runWith(Snapshot newSnapshot, Runnable op) {
try {
Thread.setScopedValueBindings(newSnapshot);
Thread.ensureMaterializedForStackWalk(newSnapshot);
ScopedValueContainer.run(op);
} finally {
Reference.reachabilityFence(newSnapshot);
Thread.setScopedValueBindings(newSnapshot.prev);
Cache.invalidate(bitmask);
}
}
}
/**
* An operation that returns a result and may throw an exception.
*
* @param Scoped values are intended to be used in a structured manner. If code
* invoked directly or indirectly by the operation creates a {@link StructuredTaskScope}
* but does not {@linkplain StructuredTaskScope#close() close} it, then it is detected
* as a structure violation when the operation completes (normally or with an
* exception). In that case, the underlying construct of the {@code StructuredTaskScope}
* is closed and {@link StructureViolationException} is thrown.
*
* @implNote
* This method is implemented to be equivalent to:
* {@snippet lang=java :
* // @link substring="call" target="Carrier#call(CallableOp)" :
* ScopedValue.where(key, value).call(op);
* }
*
*
*
* @param key the {@code ScopedValue} key
* @param value the value, can be {@code null}
* @param Scoped values are intended to be used in a structured manner. If code
* invoked directly or indirectly by the operation creates a {@link StructuredTaskScope}
* but does not {@linkplain StructuredTaskScope#close() close} it, then it is detected
* as a structure violation when the operation completes (normally or with an
* exception). In that case, the underlying construct of the {@code StructuredTaskScope}
* is closed and {@link StructureViolationException} is thrown.
*
* @implNote
* This method is implemented to be equivalent to:
* {@snippet lang=java :
* // @link substring="run" target="Carrier#run(Runnable)" :
* ScopedValue.where(key, value).run(op);
* }
*
* @param key the {@code ScopedValue} key
* @param value the value, can be {@code null}
* @param Bindings are per-thread
*
* A {@code ScopedValue} binding to a value is per-thread. Invoking {@code xxxWhere}
* executes a method with a {@code ScopedValue} bound to a value for the current thread.
* The {@link #get() get} method returns the value bound for the current thread.
*
* Scoped values as capabilities
*
* A {@code ScopedValue} object should be treated as a capability or a key to
* access its value when the {@code ScopedValue} is bound. Secure usage depends on access
* control (see The Java Virtual Machine Specification, Section {@jvms 5.4.4})
* and taking care to not share the {@code ScopedValue} object. In many cases, a {@code
* ScopedValue} will be declared in a {@code final} and {@code static} field so that it
* is only accessible to code in a single class (or nest).
*
* Rebinding
*
* The {@code ScopedValue} API allows a new binding to be established for nested
* dynamic scopes. This is known as rebinding. A {@code ScopedValue} that
* is bound to a value may be bound to a new value for the bounded execution of a new
* method. The unfolding execution of code executed by that method defines the nested
* dynamic scope. When the method completes, the value of the {@code ScopedValue} reverts
* to its previous value.
*
* Inheritance
*
* {@code ScopedValue} supports sharing across threads. This sharing is limited to
* structured cases where child threads are started and terminate within the bounded
* period of execution by a parent thread. When using a {@link StructuredTaskScope},
* scoped value bindings are captured when creating a {@code StructuredTaskScope}
* and inherited by all threads started in that task scope with the
* {@link StructuredTaskScope#fork(java.util.concurrent.Callable) fork} method.
*
*
*
*
* @implNote
* Scoped values are designed to be used in fairly small
* numbers. {@link #get} initially performs a search through enclosing
* scopes to find a scoped value's innermost binding. It
* then caches the result of the search in a small thread-local
* cache. Subsequent invocations of {@link #get} for that scoped value
* will almost always be very fast. However, if a program has many
* scoped values that it uses cyclically, the cache hit rate
* will be low and performance will be poor. This design allows
* scoped-value inheritance by {@link StructuredTaskScope} threads to
* be very fast: in essence, no more than copying a pointer, and
* leaving a scoped-value binding also requires little more than
* updating a pointer.
*
*