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