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