1 /* 2 * Copyright (c) 2020, 2024, Oracle and/or its affiliates. All rights reserved. 3 * Copyright (c) 2020, 2022, Red Hat Inc. 4 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 5 * 6 * This code is free software; you can redistribute it and/or modify it 7 * under the terms of the GNU General Public License version 2 only, as 8 * published by the Free Software Foundation. Oracle designates this 9 * particular file as subject to the "Classpath" exception as provided 10 * by Oracle in the LICENSE file that accompanied this code. 11 * 12 * This code is distributed in the hope that it will be useful, but WITHOUT 13 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 14 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 15 * version 2 for more details (a copy is included in the LICENSE file that 16 * accompanied this code). 17 * 18 * You should have received a copy of the GNU General Public License version 19 * 2 along with this work; if not, write to the Free Software Foundation, 20 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 21 * 22 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 23 * or visit www.oracle.com if you need additional information or have any 24 * questions. 25 */ 26 27 package java.lang; 28 29 import java.util.NoSuchElementException; 30 import java.util.Objects; 31 import java.lang.ref.Reference; 32 import java.util.concurrent.StructuredTaskScope; 33 import java.util.concurrent.StructureViolationException; 34 import java.util.function.Supplier; 35 import jdk.internal.access.JavaUtilConcurrentTLRAccess; 36 import jdk.internal.access.SharedSecrets; 37 import jdk.internal.javac.PreviewFeature; 38 import jdk.internal.vm.annotation.ForceInline; 39 import jdk.internal.vm.annotation.Hidden; 40 import jdk.internal.vm.ScopedValueContainer; 41 import sun.security.action.GetPropertyAction; 42 43 /** 44 * A value that may be safely and efficiently shared to methods without using method 45 * parameters. 46 * 47 * <p> In the Java programming language, data is usually passed to a method by means of a 48 * method parameter. The data may need to be passed through a sequence of many methods to 49 * get to the method that makes use of the data. Every method in the sequence of calls 50 * needs to declare the parameter and every method has access to the data. 51 * {@code ScopedValue} provides a means to pass data to a faraway method (typically a 52 * <em>callback</em>) without using method parameters. In effect, a {@code ScopedValue} 53 * is an <em>implicit method parameter</em>. It is "as if" every method in a sequence of 54 * calls has an additional parameter. None of the methods declare the parameter and only 55 * the methods that have access to the {@code ScopedValue} object can access its value 56 * (the data). {@code ScopedValue} makes it possible to securely pass data from a 57 * <em>caller</em> to a faraway <em>callee</em> through a sequence of intermediate methods 58 * that do not declare a parameter for the data and have no access to the data. 59 * 60 * <p> The {@code ScopedValue} API works by executing a method with a {@code ScopedValue} 61 * object <em>bound</em> to some value for the bounded period of execution of a method. 62 * The method may invoke another method, which in turn may invoke another. The unfolding 63 * execution of the methods define a <em>dynamic scope</em>. Code in these methods with 64 * access to the {@code ScopedValue} object may read its value. The {@code ScopedValue} 65 * object reverts to being <em>unbound</em> when the original method completes normally or 66 * with an exception. The {@code ScopedValue} API supports executing a {@link Runnable}, 67 * or {@link CallableOp} with a {@code ScopedValue} bound to a value. 68 * 69 * <p> Consider the following example with a scoped value "{@code NAME}" bound to the value 70 * "{@code duke}" for the execution of a {@code Runnable}'s {@code run} method. 71 * The {@code run} method, in turn, invokes a method {@code doSomething}. 72 * 73 * 74 * {@snippet lang=java : 75 * // @link substring="newInstance" target="#newInstance" : 76 * private static final ScopedValue<String> NAME = ScopedValue.newInstance(); 77 * 78 * // @link substring="runWhere" target="#runWhere(ScopedValue, Object, Runnable)" : 79 * ScopedValue.runWhere(NAME, "duke", () -> doSomething()); 80 * } 81 * Code executed directly or indirectly by {@code doSomething}, with access to the field 82 * {@code NAME}, can invoke {@code NAME.get()} to read the value "{@code duke}". {@code 83 * NAME} is bound while executing the {@code run} method. It reverts to being unbound when 84 * the {@code run} method completes. 85 * 86 * <p> The example using {@code runWhere} invokes a method that does not return a result. 87 * The {@link #callWhere(ScopedValue, Object, CallableOp) callWhere} method can be used 88 * to invoke a method that returns a result. 89 * In addition, {@code ScopedValue} defines the {@link #where(ScopedValue, Object)} method 90 * for cases where multiple mappings (of {@code ScopedValue} to value) are accumulated 91 * in advance of calling a method with all {@code ScopedValue}s bound to their value. 92 * 93 * <h2>Bindings are per-thread</h2> 94 * 95 * A {@code ScopedValue} binding to a value is per-thread. Invoking {@code xxxWhere} 96 * executes a method with a {@code ScopedValue} bound to a value for the current thread. 97 * The {@link #get() get} method returns the value bound for the current thread. 98 * 99 * <p> In the example, if code executed by one thread invokes this: 100 * {@snippet lang=java : 101 * ScopedValue.runWhere(NAME, "duke1", () -> doSomething()); 102 * } 103 * and code executed by another thread invokes: 104 * {@snippet lang=java : 105 * ScopedValue.runWhere(NAME, "duke2", () -> doSomething()); 106 * } 107 * then code in {@code doSomething} (or any method that it calls) invoking {@code NAME.get()} 108 * will read the value "{@code duke1}" or "{@code duke2}", depending on which thread is 109 * executing. 110 * 111 * <h2>Scoped values as capabilities</h2> 112 * 113 * A {@code ScopedValue} object should be treated as a <em>capability</em> or a key to 114 * access its value when the {@code ScopedValue} is bound. Secure usage depends on access 115 * control (see <cite>The Java Virtual Machine Specification</cite>, Section {@jvms 5.4.4}) 116 * and taking care to not share the {@code ScopedValue} object. In many cases, a {@code 117 * ScopedValue} will be declared in a {@code final} and {@code static} field so that it 118 * is only accessible to code in a single class (or nest). 119 * 120 * <h2><a id="rebind">Rebinding</a></h2> 121 * 122 * The {@code ScopedValue} API allows a new binding to be established for <em>nested 123 * dynamic scopes</em>. This is known as <em>rebinding</em>. A {@code ScopedValue} that 124 * is bound to a value may be bound to a new value for the bounded execution of a new 125 * method. The unfolding execution of code executed by that method defines the nested 126 * dynamic scope. When the method completes, the value of the {@code ScopedValue} reverts 127 * to its previous value. 128 * 129 * <p> In the above example, suppose that code executed by {@code doSomething} binds 130 * {@code NAME} to a new value with: 131 * {@snippet lang=java : 132 * ScopedValue.runWhere(NAME, "duchess", () -> doMore()); 133 * } 134 * Code executed directly or indirectly by {@code doMore()} that invokes {@code 135 * NAME.get()} will read the value "{@code duchess}". When {@code doMore()} completes 136 * then the value of {@code NAME} reverts to "{@code duke}". 137 * 138 * <h2><a id="inheritance">Inheritance</a></h2> 139 * 140 * {@code ScopedValue} supports sharing across threads. This sharing is limited to 141 * structured cases where child threads are started and terminate within the bounded 142 * period of execution by a parent thread. When using a {@link StructuredTaskScope}, 143 * scoped value bindings are <em>captured</em> when creating a {@code StructuredTaskScope} 144 * and inherited by all threads started in that task scope with the 145 * {@link StructuredTaskScope#fork(java.util.concurrent.Callable) fork} method. 146 * 147 * <p> A {@code ScopedValue} that is shared across threads requires that the value be an 148 * immutable object or for all access to the value to be appropriately synchronized. 149 * 150 * <p> In the following example, the {@code ScopedValue} {@code NAME} is bound to the 151 * value "{@code duke}" for the execution of a runnable operation. The code in the {@code 152 * run} method creates a {@code StructuredTaskScope} that forks three tasks. Code executed 153 * directly or indirectly by these threads running {@code childTask1()}, {@code childTask2()}, 154 * and {@code childTask3()} that invokes {@code NAME.get()} will read the value 155 * "{@code duke}". 156 * 157 * {@snippet lang=java : 158 * private static final ScopedValue<String> NAME = ScopedValue.newInstance(); 159 160 * ScopedValue.runWhere(NAME, "duke", () -> { 161 * // @link substring="open" target="StructuredTaskScope#open(Policy)" : 162 * try (var scope = StructuredTaskScope.open(policy)) { 163 * 164 * // @link substring="fork" target="StructuredTaskScope#fork(java.util.concurrent.Callable)" : 165 * scope.fork(() -> childTask1()); 166 * scope.fork(() -> childTask2()); 167 * scope.fork(() -> childTask3()); 168 * 169 * ... 170 * 171 * // @link substring="join" target="StructuredTaskScope#join()" : 172 * var result = scope.join(); 173 * } 174 * }); 175 * } 176 * 177 * <p> Unless otherwise specified, passing a {@code null} argument to a method in this 178 * class will cause a {@link NullPointerException} to be thrown. 179 * 180 * @apiNote 181 * A {@code ScopedValue} should be preferred over a {@link ThreadLocal} for cases where 182 * the goal is "one-way transmission" of data without using method parameters. While a 183 * {@code ThreadLocal} can be used to pass data to a method without using method parameters, 184 * it does suffer from a number of issues: 185 * <ol> 186 * <li> {@code ThreadLocal} does not prevent code in a faraway callee from {@linkplain 187 * ThreadLocal#set(Object) setting} a new value. 188 * <li> A {@code ThreadLocal} has an unbounded lifetime and thus continues to have a value 189 * after a method completes, unless explicitly {@linkplain ThreadLocal#remove() removed}. 190 * <li> {@linkplain InheritableThreadLocal Inheritance} is expensive - the map of 191 * thread-locals to values must be copied when creating each child thread. 192 * </ol> 193 * 194 * @implNote 195 * Scoped values are designed to be used in fairly small 196 * numbers. {@link #get} initially performs a search through enclosing 197 * scopes to find a scoped value's innermost binding. It 198 * then caches the result of the search in a small thread-local 199 * cache. Subsequent invocations of {@link #get} for that scoped value 200 * will almost always be very fast. However, if a program has many 201 * scoped values that it uses cyclically, the cache hit rate 202 * will be low and performance will be poor. This design allows 203 * scoped-value inheritance by {@link StructuredTaskScope} threads to 204 * be very fast: in essence, no more than copying a pointer, and 205 * leaving a scoped-value binding also requires little more than 206 * updating a pointer. 207 * 208 * <p>Because the scoped-value per-thread cache is small, clients 209 * should minimize the number of bound scoped values in use. For 210 * example, if it is necessary to pass a number of values in this way, 211 * it makes sense to create a record class to hold those values, and 212 * then bind a single {@code ScopedValue} to an instance of that record. 213 * 214 * <p>For this release, the reference implementation 215 * provides some system properties to tune the performance of scoped 216 * values. 217 * 218 * <p>The system property {@code java.lang.ScopedValue.cacheSize} 219 * controls the size of the (per-thread) scoped-value cache. This cache is crucial 220 * for the performance of scoped values. If it is too small, 221 * the runtime library will repeatedly need to scan for each 222 * {@link #get}. If it is too large, memory will be unnecessarily 223 * consumed. The default scoped-value cache size is 16 entries. It may 224 * be varied from 2 to 16 entries in size. {@code ScopedValue.cacheSize} 225 * must be an integer power of 2. 226 * 227 * <p>For example, you could use {@code -Djava.lang.ScopedValue.cacheSize=8}. 228 * 229 * <p>The other system property is {@code jdk.preserveScopedValueCache}. 230 * This property determines whether the per-thread scoped-value 231 * cache is preserved when a virtual thread is blocked. By default 232 * this property is set to {@code true}, meaning that every virtual 233 * thread preserves its scoped-value cache when blocked. Like {@code 234 * ScopedValue.cacheSize}, this is a space versus speed trade-off: in 235 * situations where many virtual threads are blocked most of the time, 236 * setting this property to {@code false} might result in a useful 237 * memory saving, but each virtual thread's scoped-value cache would 238 * have to be regenerated after a blocking operation. 239 * 240 * @param <T> the type of the value 241 * @since 21 242 */ 243 @PreviewFeature(feature = PreviewFeature.Feature.SCOPED_VALUES) 244 public final class ScopedValue<T> { 245 private final int hash; 246 247 @Override 248 public int hashCode() { return hash; } 249 250 /** 251 * An immutable map from {@code ScopedValue} to values. 252 * 253 * <p> Unless otherwise specified, passing a {@code null} argument to a constructor 254 * or method in this class will cause a {@link NullPointerException} to be thrown. 255 */ 256 static final class Snapshot { 257 final Snapshot prev; 258 final Carrier bindings; 259 final int bitmask; 260 261 private static final Object NIL = new Object(); 262 263 static final Snapshot EMPTY_SNAPSHOT = new Snapshot(); 264 265 Snapshot(Carrier bindings, Snapshot prev) { 266 this.prev = prev; 267 this.bindings = bindings; 268 this.bitmask = bindings.bitmask | prev.bitmask; 269 } 270 271 protected Snapshot() { 272 this.prev = null; 273 this.bindings = null; 274 this.bitmask = 0; 275 } 276 277 Object find(ScopedValue<?> key) { 278 int bits = key.bitmask(); 279 for (Snapshot snapshot = this; 280 containsAll(snapshot.bitmask, bits); 281 snapshot = snapshot.prev) { 282 for (Carrier carrier = snapshot.bindings; 283 carrier != null && containsAll(carrier.bitmask, bits); 284 carrier = carrier.prev) { 285 if (carrier.getKey() == key) { 286 Object value = carrier.get(); 287 return value; 288 } 289 } 290 } 291 return NIL; 292 } 293 } 294 295 /** 296 * A mapping of scoped values, as <em>keys</em>, to values. 297 * 298 * <p> A {@code Carrier} is used to accumulate mappings so that an operation (a {@link 299 * Runnable} or {@link CallableOp}) can be executed with all scoped values in the 300 * mapping bound to values. The following example runs an operation with {@code k1} 301 * bound (or rebound) to {@code v1}, and {@code k2} bound (or rebound) to {@code v2}. 302 * {@snippet lang=java : 303 * // @link substring="where" target="#where(ScopedValue, Object)" : 304 * ScopedValue.where(k1, v1).where(k2, v2).run(() -> ... ); 305 * } 306 * 307 * <p> A {@code Carrier} is immutable and thread-safe. The {@link 308 * #where(ScopedValue, Object) where} method returns a new {@code Carrier} object, 309 * it does not mutate an existing mapping. 310 * 311 * <p> Unless otherwise specified, passing a {@code null} argument to a method in 312 * this class will cause a {@link NullPointerException} to be thrown. 313 * 314 * @since 21 315 */ 316 @PreviewFeature(feature = PreviewFeature.Feature.SCOPED_VALUES) 317 public static final class Carrier { 318 // Bit masks: a 1 in postion n indicates that this set of bound values 319 // hits that slot in the cache. 320 final int bitmask; 321 final ScopedValue<?> key; 322 final Object value; 323 final Carrier prev; 324 325 Carrier(ScopedValue<?> key, Object value, Carrier prev) { 326 this.key = key; 327 this.value = value; 328 this.prev = prev; 329 int bits = key.bitmask(); 330 if (prev != null) { 331 bits |= prev.bitmask; 332 } 333 this.bitmask = bits; 334 } 335 336 /** 337 * Add a binding to this map, returning a new Carrier instance. 338 */ 339 private static <T> Carrier where(ScopedValue<T> key, T value, Carrier prev) { 340 return new Carrier(key, value, prev); 341 } 342 343 /** 344 * Returns a new {@code Carrier} with the mappings from this carrier plus a 345 * new mapping from {@code key} to {@code value}. If this carrier already has a 346 * mapping for the scoped value {@code key} then it will map to the new 347 * {@code value}. The current carrier is immutable, so it is not changed by this 348 * method. 349 * 350 * @param key the {@code ScopedValue} key 351 * @param value the value, can be {@code null} 352 * @param <T> the type of the value 353 * @return a new {@code Carrier} with the mappings from this carrier plus the new mapping 354 */ 355 public <T> Carrier where(ScopedValue<T> key, T value) { 356 return where(key, value, this); 357 } 358 359 /* 360 * Return a new set consisting of a single binding. 361 */ 362 static <T> Carrier of(ScopedValue<T> key, T value) { 363 return where(key, value, null); 364 } 365 366 Object get() { 367 return value; 368 } 369 370 ScopedValue<?> getKey() { 371 return key; 372 } 373 374 /** 375 * Returns the value of a {@link ScopedValue} in this mapping. 376 * 377 * @param key the {@code ScopedValue} key 378 * @param <T> the type of the value 379 * @return the value 380 * @throws NoSuchElementException if the key is not present in this mapping 381 */ 382 @SuppressWarnings("unchecked") 383 public <T> T get(ScopedValue<T> key) { 384 var bits = key.bitmask(); 385 for (Carrier carrier = this; 386 carrier != null && containsAll(carrier.bitmask, bits); 387 carrier = carrier.prev) { 388 if (carrier.getKey() == key) { 389 Object value = carrier.get(); 390 return (T) value; 391 } 392 } 393 throw new NoSuchElementException(); 394 } 395 396 /** 397 * Calls a value-returning operation with each scoped value in this mapping bound 398 * to its value in the current thread. 399 * When the operation completes (normally or with an exception), each scoped value 400 * in the mapping will revert to being unbound, or revert to its previous value 401 * when previously bound, in the current thread. If {@code op} completes with an 402 * exception then it propagated by this method. 403 * 404 * <p> Scoped values are intended to be used in a <em>structured manner</em>. If code 405 * invoked directly or indirectly by the operation creates a {@link StructuredTaskScope} 406 * but does not {@linkplain StructuredTaskScope#close() close} it, then it is detected 407 * as a <em>structure violation</em> when the operation completes (normally or with an 408 * exception). In that case, the underlying construct of the {@code StructuredTaskScope} 409 * is closed and {@link StructureViolationException} is thrown. 410 * 411 * @param op the operation to run 412 * @param <R> the type of the result of the operation 413 * @param <X> type of the exception thrown by the operation 414 * @return the result 415 * @throws StructureViolationException if a structure violation is detected 416 * @throws X if {@code op} completes with an exception 417 * @see ScopedValue#callWhere(ScopedValue, Object, CallableOp) 418 * @since 23 419 */ 420 public <R, X extends Throwable> R call(CallableOp<? extends R, X> op) throws X { 421 Objects.requireNonNull(op); 422 Cache.invalidate(bitmask); 423 var prevSnapshot = scopedValueBindings(); 424 var newSnapshot = new Snapshot(this, prevSnapshot); 425 return runWith(newSnapshot, op); 426 } 427 428 /** 429 * Execute the action with a set of ScopedValue bindings. 430 * 431 * The VM recognizes this method as special, so any changes to the 432 * name or signature require corresponding changes in 433 * JVM_FindScopedValueBindings(). 434 */ 435 @Hidden 436 @ForceInline 437 private <R, X extends Throwable> R runWith(Snapshot newSnapshot, CallableOp<R, X> op) { 438 try { 439 Thread.setScopedValueBindings(newSnapshot); 440 Thread.ensureMaterializedForStackWalk(newSnapshot); 441 return ScopedValueContainer.call(op); 442 } finally { 443 Reference.reachabilityFence(newSnapshot); 444 Thread.setScopedValueBindings(newSnapshot.prev); 445 Cache.invalidate(bitmask); 446 } 447 } 448 449 /** 450 * Runs an operation with each scoped value in this mapping bound to its value 451 * in the current thread. 452 * When the operation completes (normally or with an exception), each scoped value 453 * in the mapping will revert to being unbound, or revert to its previous value 454 * when previously bound, in the current thread. If {@code op} completes with an 455 * exception then it propagated by this method. 456 * 457 * <p> Scoped values are intended to be used in a <em>structured manner</em>. If code 458 * invoked directly or indirectly by the operation creates a {@link StructuredTaskScope} 459 * but does not {@linkplain StructuredTaskScope#close() close} it, then it is detected 460 * as a <em>structure violation</em> when the operation completes (normally or with an 461 * exception). In that case, the underlying construct of the {@code StructuredTaskScope} 462 * is closed and {@link StructureViolationException} is thrown. 463 * 464 * @param op the operation to run 465 * @throws StructureViolationException if a structure violation is detected 466 * @see ScopedValue#runWhere(ScopedValue, Object, Runnable) 467 */ 468 public void run(Runnable op) { 469 Objects.requireNonNull(op); 470 Cache.invalidate(bitmask); 471 var prevSnapshot = scopedValueBindings(); 472 var newSnapshot = new Snapshot(this, prevSnapshot); 473 runWith(newSnapshot, op); 474 } 475 476 /** 477 * Execute the action with a set of {@code ScopedValue} bindings. 478 * 479 * The VM recognizes this method as special, so any changes to the 480 * name or signature require corresponding changes in 481 * JVM_FindScopedValueBindings(). 482 */ 483 @Hidden 484 @ForceInline 485 private void runWith(Snapshot newSnapshot, Runnable op) { 486 try { 487 Thread.setScopedValueBindings(newSnapshot); 488 Thread.ensureMaterializedForStackWalk(newSnapshot); 489 ScopedValueContainer.run(op); 490 } finally { 491 Reference.reachabilityFence(newSnapshot); 492 Thread.setScopedValueBindings(newSnapshot.prev); 493 Cache.invalidate(bitmask); 494 } 495 } 496 } 497 498 /** 499 * An operation that returns a result and may throw an exception. 500 * 501 * @param <T> result type of the operation 502 * @param <X> type of the exception thrown by the operation 503 * @since 23 504 */ 505 @PreviewFeature(feature = PreviewFeature.Feature.SCOPED_VALUES) 506 @FunctionalInterface 507 public interface CallableOp<T, X extends Throwable> { 508 /** 509 * Executes this operation. 510 * @return the result, can be null 511 * @throws X if the operation completes with an exception 512 */ 513 T call() throws X; 514 } 515 516 /** 517 * Creates a new {@code Carrier} with a single mapping of a {@code ScopedValue} 518 * <em>key</em> to a value. The {@code Carrier} can be used to accumulate mappings so 519 * that an operation can be executed with all scoped values in the mapping bound to 520 * values. The following example runs an operation with {@code k1} bound (or rebound) 521 * to {@code v1}, and {@code k2} bound (or rebound) to {@code v2}. 522 * {@snippet lang=java : 523 * // @link substring="run" target="Carrier#run(Runnable)" : 524 * ScopedValue.where(k1, v1).where(k2, v2).run(() -> ... ); 525 * } 526 * 527 * @param key the {@code ScopedValue} key 528 * @param value the value, can be {@code null} 529 * @param <T> the type of the value 530 * @return a new {@code Carrier} with a single mapping 531 */ 532 public static <T> Carrier where(ScopedValue<T> key, T value) { 533 return Carrier.of(key, value); 534 } 535 536 /** 537 * Calls a value-returning operation with a {@code ScopedValue} bound to a value 538 * in the current thread. When the operation completes (normally or with an 539 * exception), the {@code ScopedValue} will revert to being unbound, or revert to 540 * its previous value when previously bound, in the current thread. If {@code op} 541 * completes with an exception then it propagated by this method. 542 * 543 * <p> Scoped values are intended to be used in a <em>structured manner</em>. If code 544 * invoked directly or indirectly by the operation creates a {@link StructuredTaskScope} 545 * but does not {@linkplain StructuredTaskScope#close() close} it, then it is detected 546 * as a <em>structure violation</em> when the operation completes (normally or with an 547 * exception). In that case, the underlying construct of the {@code StructuredTaskScope} 548 * is closed and {@link StructureViolationException} is thrown. 549 * 550 * @implNote 551 * This method is implemented to be equivalent to: 552 * {@snippet lang=java : 553 * // @link substring="call" target="Carrier#call(CallableOp)" : 554 * ScopedValue.where(key, value).call(op); 555 * } 556 * 557 * 558 * 559 * @param key the {@code ScopedValue} key 560 * @param value the value, can be {@code null} 561 * @param <T> the type of the value 562 * @param <R> the result type 563 * @param <X> type of the exception thrown by the operation 564 * @param op the operation to call 565 * @return the result 566 * @throws StructureViolationException if a structure violation is detected 567 * @throws X if the operation completes with an exception 568 * @since 23 569 */ 570 public static <T, R, X extends Throwable> R callWhere(ScopedValue<T> key, 571 T value, 572 CallableOp<? extends R, X> op) throws X { 573 return where(key, value).call(op); 574 } 575 576 /** 577 * Run an operation with a {@code ScopedValue} bound to a value in the current 578 * thread. When the operation completes (normally or with an exception), the 579 * {@code ScopedValue} will revert to being unbound, or revert to its previous value 580 * when previously bound, in the current thread. If {@code op} completes with an 581 * exception then it propagated by this method. 582 * 583 * <p> Scoped values are intended to be used in a <em>structured manner</em>. If code 584 * invoked directly or indirectly by the operation creates a {@link StructuredTaskScope} 585 * but does not {@linkplain StructuredTaskScope#close() close} it, then it is detected 586 * as a <em>structure violation</em> when the operation completes (normally or with an 587 * exception). In that case, the underlying construct of the {@code StructuredTaskScope} 588 * is closed and {@link StructureViolationException} is thrown. 589 * 590 * @implNote 591 * This method is implemented to be equivalent to: 592 * {@snippet lang=java : 593 * // @link substring="run" target="Carrier#run(Runnable)" : 594 * ScopedValue.where(key, value).run(op); 595 * } 596 * 597 * @param key the {@code ScopedValue} key 598 * @param value the value, can be {@code null} 599 * @param <T> the type of the value 600 * @param op the operation to call 601 * @throws StructureViolationException if a structure violation is detected 602 */ 603 public static <T> void runWhere(ScopedValue<T> key, T value, Runnable op) { 604 where(key, value).run(op); 605 } 606 607 private ScopedValue() { 608 this.hash = generateKey(); 609 } 610 611 /** 612 * Creates a scoped value that is initially unbound for all threads. 613 * 614 * @param <T> the type of the value 615 * @return a new {@code ScopedValue} 616 */ 617 public static <T> ScopedValue<T> newInstance() { 618 return new ScopedValue<T>(); 619 } 620 621 /** 622 * {@return the value of the scoped value if bound in the current thread} 623 * 624 * @throws NoSuchElementException if the scoped value is not bound 625 */ 626 @ForceInline 627 @SuppressWarnings("unchecked") 628 public T get() { 629 Object[] objects; 630 if ((objects = scopedValueCache()) != null) { 631 // This code should perhaps be in class Cache. We do it 632 // here because the generated code is small and fast and 633 // we really want it to be inlined in the caller. 634 int n = (hash & Cache.SLOT_MASK) * 2; 635 if (objects[n] == this) { 636 return (T)objects[n + 1]; 637 } 638 n = ((hash >>> Cache.INDEX_BITS) & Cache.SLOT_MASK) * 2; 639 if (objects[n] == this) { 640 return (T)objects[n + 1]; 641 } 642 } 643 return slowGet(); 644 } 645 646 @SuppressWarnings("unchecked") 647 private T slowGet() { 648 var value = findBinding(); 649 if (value == Snapshot.NIL) { 650 throw new NoSuchElementException(); 651 } 652 Cache.put(this, value); 653 return (T)value; 654 } 655 656 /** 657 * {@return {@code true} if this scoped value is bound in the current thread} 658 */ 659 public boolean isBound() { 660 Object[] objects = scopedValueCache(); 661 if (objects != null) { 662 int n = (hash & Cache.SLOT_MASK) * 2; 663 if (objects[n] == this) { 664 return true; 665 } 666 n = ((hash >>> Cache.INDEX_BITS) & Cache.SLOT_MASK) * 2; 667 if (objects[n] == this) { 668 return true; 669 } 670 } 671 var value = findBinding(); 672 boolean result = (value != Snapshot.NIL); 673 if (result) Cache.put(this, value); 674 return result; 675 } 676 677 /** 678 * Return the value of the scoped value or NIL if not bound. 679 */ 680 private Object findBinding() { 681 Object value = scopedValueBindings().find(this); 682 return value; 683 } 684 685 /** 686 * Returns the value of this scoped value if bound in the current thread, otherwise 687 * returns {@code other}. 688 * 689 * @param other the value to return if not bound, can be {@code null} 690 * @return the value of the scoped value if bound, otherwise {@code other} 691 */ 692 public T orElse(T other) { 693 Object obj = findBinding(); 694 if (obj != Snapshot.NIL) { 695 @SuppressWarnings("unchecked") 696 T value = (T) obj; 697 return value; 698 } else { 699 return other; 700 } 701 } 702 703 /** 704 * Returns the value of this scoped value if bound in the current thread, otherwise 705 * throws an exception produced by the exception supplying function. 706 * 707 * @param <X> the type of the exception that may be thrown 708 * @param exceptionSupplier the supplying function that produces the exception to throw 709 * @return the value of the scoped value if bound in the current thread 710 * @throws X if the scoped value is not bound in the current thread 711 */ 712 public <X extends Throwable> T orElseThrow(Supplier<? extends X> exceptionSupplier) throws X { 713 Objects.requireNonNull(exceptionSupplier); 714 Object obj = findBinding(); 715 if (obj != Snapshot.NIL) { 716 @SuppressWarnings("unchecked") 717 T value = (T) obj; 718 return value; 719 } else { 720 throw exceptionSupplier.get(); 721 } 722 } 723 724 private static Object[] scopedValueCache() { 725 return Thread.scopedValueCache(); 726 } 727 728 private static void setScopedValueCache(Object[] cache) { 729 Thread.setScopedValueCache(cache); 730 } 731 732 // Special value to indicate this is a newly-created Thread 733 // Note that his must match the declaration in j.l.Thread. 734 private static final Object NEW_THREAD_BINDINGS = Thread.class; 735 736 private static Snapshot scopedValueBindings() { 737 // Bindings can be in one of four states: 738 // 739 // 1: class Thread: this is a new Thread instance, and no 740 // scoped values have ever been bound in this Thread, and neither 741 // have any scoped value bindings been inherited from a parent. 742 // 2: EmptySnapshot.SINGLETON: This is effectively an empty binding. 743 // 3: A Snapshot instance: this contains one or more scoped value 744 // bindings. 745 // 4: null: there may be some bindings in this Thread, but we don't know 746 // where they are. We must invoke Thread.findScopedValueBindings() to walk 747 // the stack to find them. 748 749 Object bindings = Thread.scopedValueBindings(); 750 if (bindings == NEW_THREAD_BINDINGS) { 751 // This must be a new thread 752 return Snapshot.EMPTY_SNAPSHOT; 753 } 754 if (bindings == null) { 755 // Search the stack 756 bindings = Thread.findScopedValueBindings(); 757 if (bindings == NEW_THREAD_BINDINGS || bindings == null) { 758 // We've walked the stack without finding anything. 759 bindings = Snapshot.EMPTY_SNAPSHOT; 760 } 761 Thread.setScopedValueBindings(bindings); 762 } 763 assert (bindings != null); 764 return (Snapshot) bindings; 765 } 766 767 private static int nextKey = 0xf0f0_f0f0; 768 769 // A Marsaglia xor-shift generator used to generate hashes. This one has full period, so 770 // it generates 2**32 - 1 hashes before it repeats. We're going to use the lowest n bits 771 // and the next n bits as cache indexes, so we make sure that those indexes map 772 // to different slots in the cache. 773 private static synchronized int generateKey() { 774 int x = nextKey; 775 do { 776 x ^= x >>> 12; 777 x ^= x << 9; 778 x ^= x >>> 23; 779 } while (Cache.primarySlot(x) == Cache.secondarySlot(x)); 780 return (nextKey = x); 781 } 782 783 /** 784 * Return a bit mask that may be used to determine if this ScopedValue is 785 * bound in the current context. Each Carrier holds a bit mask which is 786 * the OR of all the bit masks of the bound ScopedValues. 787 * @return the bitmask 788 */ 789 int bitmask() { 790 return (1 << Cache.primaryIndex(this)) | (1 << (Cache.secondaryIndex(this) + Cache.TABLE_SIZE)); 791 } 792 793 // Return true iff bitmask, considered as a set of bits, contains all 794 // of the bits in targetBits. 795 static boolean containsAll(int bitmask, int targetBits) { 796 return (bitmask & targetBits) == targetBits; 797 } 798 799 // A small fixed-size key-value cache. When a scoped value's get() method 800 // is invoked, we record the result of the lookup in this per-thread cache 801 // for fast access in future. 802 private static final class Cache { 803 static final int INDEX_BITS = 4; // Must be a power of 2 804 static final int TABLE_SIZE = 1 << INDEX_BITS; 805 static final int TABLE_MASK = TABLE_SIZE - 1; 806 static final int PRIMARY_MASK = (1 << TABLE_SIZE) - 1; 807 808 // The number of elements in the cache array, and a bit mask used to 809 // select elements from it. 810 private static final int CACHE_TABLE_SIZE, SLOT_MASK; 811 // The largest cache we allow. Must be a power of 2 and greater than 812 // or equal to 2. 813 private static final int MAX_CACHE_SIZE = 16; 814 815 static { 816 final String propertyName = "java.lang.ScopedValue.cacheSize"; 817 var sizeString = GetPropertyAction.privilegedGetProperty(propertyName, "16"); 818 var cacheSize = Integer.valueOf(sizeString); 819 if (cacheSize < 2 || cacheSize > MAX_CACHE_SIZE) { 820 cacheSize = MAX_CACHE_SIZE; 821 System.err.println(propertyName + " is out of range: is " + sizeString); 822 } 823 if ((cacheSize & (cacheSize - 1)) != 0) { // a power of 2 824 cacheSize = MAX_CACHE_SIZE; 825 System.err.println(propertyName + " must be an integer power of 2: is " + sizeString); 826 } 827 CACHE_TABLE_SIZE = cacheSize; 828 SLOT_MASK = cacheSize - 1; 829 } 830 831 static int primaryIndex(ScopedValue<?> key) { 832 return key.hash & TABLE_MASK; 833 } 834 835 static int secondaryIndex(ScopedValue<?> key) { 836 return (key.hash >> INDEX_BITS) & TABLE_MASK; 837 } 838 839 private static int primarySlot(ScopedValue<?> key) { 840 return key.hashCode() & SLOT_MASK; 841 } 842 843 private static int secondarySlot(ScopedValue<?> key) { 844 return (key.hash >> INDEX_BITS) & SLOT_MASK; 845 } 846 847 static int primarySlot(int hash) { 848 return hash & SLOT_MASK; 849 } 850 851 static int secondarySlot(int hash) { 852 return (hash >> INDEX_BITS) & SLOT_MASK; 853 } 854 855 static void put(ScopedValue<?> key, Object value) { 856 Object[] theCache = scopedValueCache(); 857 if (theCache == null) { 858 theCache = new Object[CACHE_TABLE_SIZE * 2]; 859 setScopedValueCache(theCache); 860 } 861 // Update the cache to replace one entry with the value we just looked up. 862 // Each value can be in one of two possible places in the cache. 863 // Pick a victim at (pseudo-)random. 864 int k1 = primarySlot(key); 865 int k2 = secondarySlot(key); 866 var usePrimaryIndex = chooseVictim(); 867 int victim = usePrimaryIndex ? k1 : k2; 868 int other = usePrimaryIndex ? k2 : k1; 869 setKeyAndObjectAt(victim, key, value); 870 if (getKey(theCache, other) == key) { 871 setKeyAndObjectAt(other, key, value); 872 } 873 } 874 875 private static void setKeyAndObjectAt(int n, Object key, Object value) { 876 var cache = scopedValueCache(); 877 cache[n * 2] = key; 878 cache[n * 2 + 1] = value; 879 } 880 881 private static void setKeyAndObjectAt(Object[] cache, int n, Object key, Object value) { 882 cache[n * 2] = key; 883 cache[n * 2 + 1] = value; 884 } 885 886 private static Object getKey(Object[] objs, int n) { 887 return objs[n * 2]; 888 } 889 890 private static void setKey(Object[] objs, int n, Object key) { 891 objs[n * 2] = key; 892 } 893 894 private static final JavaUtilConcurrentTLRAccess THREAD_LOCAL_RANDOM_ACCESS 895 = SharedSecrets.getJavaUtilConcurrentTLRAccess(); 896 897 // Return either true or false, at pseudo-random, with a bias towards true. 898 // This chooses either the primary or secondary cache slot, but the 899 // primary slot is approximately twice as likely to be chosen as the 900 // secondary one. 901 private static boolean chooseVictim() { 902 int r = THREAD_LOCAL_RANDOM_ACCESS.nextSecondaryThreadLocalRandomSeed(); 903 return (r & 15) >= 5; 904 } 905 906 // Null a set of cache entries, indicated by the 1-bits given 907 static void invalidate(int toClearBits) { 908 toClearBits = (toClearBits >>> TABLE_SIZE) | (toClearBits & PRIMARY_MASK); 909 Object[] objects; 910 if ((objects = scopedValueCache()) != null) { 911 for (int bits = toClearBits; bits != 0; ) { 912 int index = Integer.numberOfTrailingZeros(bits); 913 setKeyAndObjectAt(objects, index & SLOT_MASK, null, null); 914 bits &= ~1 << index; 915 } 916 } 917 } 918 } 919 }