Skip to content

Commit aeb670f

Browse files
committed
Add support for jdk.incubator.concurrent.ScopedValue.
1 parent 5c85d57 commit aeb670f

File tree

3 files changed

+57
-30
lines changed

3 files changed

+57
-30
lines changed

substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/thread/JavaThreadsFeature.java

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@
3030
import org.graalvm.nativeimage.ImageSingletons;
3131
import org.graalvm.nativeimage.Platform;
3232
import org.graalvm.nativeimage.Platforms;
33+
import org.graalvm.nativeimage.hosted.RuntimeClassInitialization;
3334

3435
import com.oracle.svm.core.feature.InternalFeature;
3536
import com.oracle.svm.core.feature.AutomaticallyRegisteredFeature;
@@ -61,6 +62,12 @@ static JavaThreadsFeature singleton() {
6162
@Override
6263
public void duringSetup(DuringSetupAccess access) {
6364
access.registerObjectReplacer(this::collectReachableObjects);
65+
66+
/*
67+
* This currently only means that we don't support setting custom values for
68+
* jdk.incubator.concurrent.ScopedValue.cacheSize at runtime.
69+
*/
70+
RuntimeClassInitialization.initializeAtBuildTime("jdk.incubator.concurrent");
6471
}
6572

6673
private Object collectReachableObjects(Object original) {

substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/thread/Target_java_lang_Thread.java

Lines changed: 36 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,6 @@
3131
import java.util.Map;
3232
import java.util.Objects;
3333
import java.util.concurrent.ThreadFactory;
34-
import java.util.function.BooleanSupplier;
3534

3635
import org.graalvm.compiler.api.directives.GraalDirectives;
3736
import org.graalvm.compiler.replacements.ReplacementsUtil;
@@ -59,11 +58,11 @@
5958
import com.oracle.svm.core.jdk.JDK17OrLater;
6059
import com.oracle.svm.core.jdk.JDK19OrEarlier;
6160
import com.oracle.svm.core.jdk.JDK19OrLater;
61+
import com.oracle.svm.core.jdk.JDK20OrLater;
6262
import com.oracle.svm.core.jdk.LoomJDK;
6363
import com.oracle.svm.core.jdk.NotLoomJDK;
6464
import com.oracle.svm.core.monitor.MonitorSupport;
6565
import com.oracle.svm.core.util.VMError;
66-
import com.oracle.svm.util.ReflectionUtil;
6766

6867
@TargetClass(Thread.class)
6968
@SuppressWarnings({"unused"})
@@ -80,6 +79,10 @@ public final class Target_java_lang_Thread {
8079
@Alias //
8180
@TargetElement(onlyWith = JDK19OrLater.class) //
8281
static int NO_INHERIT_THREAD_LOCALS;
82+
83+
@Alias //
84+
@TargetElement(onlyWith = JDK20OrLater.class) //
85+
static Object NEW_THREAD_BINDINGS;
8386
// Checkstyle: resume
8487

8588
/** This field is initialized when the thread actually starts executing. */
@@ -190,10 +193,13 @@ public final class Target_java_lang_Thread {
190193
@RecomputeFieldValue(kind = RecomputeFieldValue.Kind.Reset) //
191194
Object lockHelper;
192195

193-
@Inject @TargetElement(onlyWith = {HasScopedValueCache.class, HasExtentLocalCache.class, LoomJDK.class}) //
196+
@Inject @TargetElement(onlyWith = JDK19OrLater.class) //
194197
@RecomputeFieldValue(kind = RecomputeFieldValue.Kind.Reset) //
195198
Object[] scopedValueCache;
196199

200+
@Alias @TargetElement(onlyWith = JDK20OrLater.class) //
201+
Object scopedValueBindings;
202+
197203
@Alias
198204
@Platforms(InternalPlatform.NATIVE_ONLY.class)
199205
native void setPriority(int newPriority);
@@ -370,6 +376,10 @@ private Target_java_lang_Thread(
370376
boolean allowThreadLocals = (characteristics & NO_THREAD_LOCALS) == 0;
371377
boolean inheritThreadLocals = (characteristics & NO_INHERIT_THREAD_LOCALS) == 0;
372378
JavaThreads.initializeNewThread(this, g, target, nameLocal, stackSize, acc, allowThreadLocals, inheritThreadLocals);
379+
380+
if (JavaVersionUtil.JAVA_SPEC >= 20) {
381+
this.scopedValueBindings = NEW_THREAD_BINDINGS;
382+
}
373383
}
374384

375385
@Substitute
@@ -394,6 +404,10 @@ private Target_java_lang_Thread(String name, int characteristics, boolean bound)
394404
boolean allowThreadLocals = (characteristics & NO_THREAD_LOCALS) == 0;
395405
boolean inheritThreadLocals = (characteristics & NO_INHERIT_THREAD_LOCALS) == 0;
396406
JavaThreads.initNewThreadLocalsAndLoader(this, allowThreadLocals, inheritThreadLocals, Thread.currentThread());
407+
408+
if (JavaVersionUtil.JAVA_SPEC >= 20) {
409+
this.scopedValueBindings = NEW_THREAD_BINDINGS;
410+
}
397411
}
398412

399413
@SuppressWarnings("hiding")
@@ -665,29 +679,44 @@ static Thread startVirtualThreadWithoutLoom(Runnable task) {
665679
}
666680

667681
@Substitute
668-
@TargetElement(onlyWith = HasExtentLocalCache.class)
682+
@TargetElement(onlyWith = {JDK19OrLater.class, JDK19OrEarlier.class})
669683
static Object[] extentLocalCache() {
670684
return JavaThreads.toTarget(currentCarrierThread()).scopedValueCache;
671685
}
672686

673687
@Substitute
674-
@TargetElement(onlyWith = HasExtentLocalCache.class)
688+
@TargetElement(onlyWith = {JDK19OrLater.class, JDK19OrEarlier.class})
675689
static void setExtentLocalCache(Object[] cache) {
676690
JavaThreads.toTarget(currentCarrierThread()).scopedValueCache = cache;
677691
}
678692

679693
@Substitute
680-
@TargetElement(onlyWith = HasScopedValueCache.class)
694+
@TargetElement(onlyWith = JDK20OrLater.class)
681695
static Object[] scopedValueCache() {
682696
return JavaThreads.toTarget(currentCarrierThread()).scopedValueCache;
683697
}
684698

685699
@Substitute
686-
@TargetElement(onlyWith = HasScopedValueCache.class)
700+
@TargetElement(onlyWith = JDK20OrLater.class)
687701
static void setScopedValueCache(Object[] cache) {
688702
JavaThreads.toTarget(currentCarrierThread()).scopedValueCache = cache;
689703
}
690704

705+
@Substitute
706+
@TargetElement(onlyWith = JDK20OrLater.class)
707+
static Object findScopedValueBindings() {
708+
/*
709+
* We don't have the means to extract the bindings object parameter from runWith frames on
710+
* the stack like HotSpot does. However, at this time, we need to support only two cases:
711+
* current bindings in a virtual thread, and current bindings in the carrier thread.
712+
*/
713+
Object bindings = JavaThreads.toTarget(Thread.currentThread()).scopedValueBindings;
714+
if (bindings != null) {
715+
return bindings;
716+
}
717+
return JavaThreads.toTarget(currentCarrierThread()).scopedValueBindings;
718+
}
719+
691720
@Substitute
692721
static void blockedOn(Target_sun_nio_ch_Interruptible b) {
693722
JavaThreads.blockedOn(b);
@@ -725,22 +754,6 @@ boolean isTerminated() {
725754
@Alias
726755
@TargetElement(onlyWith = JDK19OrLater.class)
727756
native long threadId();
728-
729-
private static class HasExtentLocalCache implements BooleanSupplier {
730-
@Override
731-
public boolean getAsBoolean() {
732-
boolean result = ReflectionUtil.lookupMethod(true, Thread.class, "extentLocalCache") != null;
733-
assert !result || JavaVersionUtil.JAVA_SPEC == 19 : "extentLocalCache should not exist as of JDK 20";
734-
return result;
735-
}
736-
}
737-
738-
public static class HasScopedValueCache implements BooleanSupplier {
739-
@Override
740-
public boolean getAsBoolean() {
741-
return ReflectionUtil.lookupMethod(true, Thread.class, "scopedValueCache") != null;
742-
}
743-
}
744757
}
745758

746759
@TargetClass(value = Thread.class, innerClass = "Builder", onlyWith = JDK19OrLater.class)

substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/thread/Target_jdk_internal_vm_ThreadContainers.java

Lines changed: 14 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -24,20 +24,25 @@
2424
*/
2525
package com.oracle.svm.core.thread;
2626

27-
import com.oracle.svm.core.annotate.KeepOriginal;
27+
import java.lang.ref.ReferenceQueue;
28+
import java.lang.ref.WeakReference;
29+
import java.util.Set;
30+
import java.util.stream.Stream;
31+
32+
import com.oracle.svm.core.annotate.Delete;
2833
import com.oracle.svm.core.annotate.Substitute;
2934
import com.oracle.svm.core.annotate.TargetClass;
3035
import com.oracle.svm.core.jdk.JDK19OrLater;
3136

3237
/**
33-
* The purpose of the target class is to support debugging and monitoring of threads. Because we
34-
* currently don't provide/expose means for doing so, we replace it with an almost empty
35-
* implementation.
38+
* We currently don't provide/expose means for debugging and monitoring of threads, so we replace
39+
* these methods with an empty implementation.
3640
*/
3741
@TargetClass(className = "jdk.internal.vm.ThreadContainers", onlyWith = JDK19OrLater.class)
38-
@Substitute
3942
@SuppressWarnings("unused")
4043
final class Target_jdk_internal_vm_ThreadContainers {
44+
@Delete static Set<WeakReference<Target_jdk_internal_vm_ThreadContainer>> CONTAINER_REGISTRY;
45+
@Delete static ReferenceQueue<Object> QUEUE;
4146

4247
@Substitute
4348
public static Object registerContainer(Target_jdk_internal_vm_ThreadContainer container) {
@@ -48,8 +53,10 @@ public static Object registerContainer(Target_jdk_internal_vm_ThreadContainer co
4853
public static void deregisterContainer(Object key) {
4954
}
5055

51-
@KeepOriginal
52-
public static native Target_jdk_internal_vm_ThreadContainer root();
56+
@Substitute
57+
static Stream<Target_jdk_internal_vm_ThreadContainer> children(Target_jdk_internal_vm_ThreadContainer container) {
58+
return Stream.empty();
59+
}
5360
}
5461

5562
@TargetClass(className = "jdk.internal.vm.ThreadContainer", onlyWith = JDK19OrLater.class)

0 commit comments

Comments
 (0)