Skip to content

Commit 82a59de

Browse files
committed
Ensure that virtual thread code is unreachable when disabled.
1 parent 209ecb7 commit 82a59de

File tree

8 files changed

+94
-157
lines changed

8 files changed

+94
-157
lines changed

substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/hub/LayoutEncoding.java

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -112,7 +112,7 @@ public static int forInstance(ResolvedJavaType type, int size) {
112112
guaranteeEncoding(type, size > LAST_SPECIAL_VALUE, "Instance type size must be above special values for encoding: " + size);
113113
int encoding = size;
114114
guaranteeEncoding(type, isInstance(encoding), "Instance type encoding must denote an instance");
115-
guaranteeEncoding(type, !isStoredContinuation(encoding), "Instance type encoding must not denote a stored continuation");
115+
guaranteeEncoding(type, !Continuation.isSupported() || !isStoredContinuation(encoding), "Instance type encoding must not denote a stored continuation");
116116
guaranteeEncoding(type, !isArray(encoding), "Instance type encoding must not denote an array");
117117
guaranteeEncoding(type, !isObjectArray(encoding), "Instance type encoding must not denote an object array");
118118
guaranteeEncoding(type, !isPrimitiveArray(encoding), "Instance type encoding must not denote a primitive array");
@@ -159,7 +159,7 @@ public static UnsignedWord getInstanceSize(int encoding) {
159159

160160
@Uninterruptible(reason = "Called from uninterruptible code.", mayBeInlined = true)
161161
public static boolean isStoredContinuation(int encoding) {
162-
return Continuation.isSupported() && encoding == STORED_CONTINUATION_VALUE;
162+
return encoding == STORED_CONTINUATION_VALUE;
163163
}
164164

165165
// May be inlined because it does not deal in Pointers.
@@ -221,7 +221,7 @@ public static UnsignedWord getSizeFromObjectInline(Object obj) {
221221
int encoding = KnownIntrinsics.readHub(obj).getLayoutEncoding();
222222
if (isArray(encoding)) {
223223
return getArraySize(encoding, ArrayLengthNode.arrayLength(obj));
224-
} else if (isStoredContinuation(encoding)) {
224+
} else if (Continuation.isSupported() && isStoredContinuation(encoding)) {
225225
return WordFactory.unsigned(StoredContinuationImpl.readSize((StoredContinuation) obj));
226226
} else {
227227
return getInstanceSize(encoding);

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

Lines changed: 11 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -45,19 +45,18 @@
4545
public class ContinuationsFeature implements Feature {
4646
@Override
4747
public void afterRegistration(AfterRegistrationAccess access) {
48-
VirtualThreads impl;
4948
if (Continuation.isSupported()) {
49+
VirtualThreads impl;
5050
if (LoomSupport.isEnabled()) {
5151
impl = new LoomVirtualThreads();
5252
} else {
5353
impl = new SubstrateVirtualThreads();
5454
}
55+
ImageSingletons.add(VirtualThreads.class, impl);
5556
} else {
56-
impl = new NoVirtualThreads();
5757
UserError.guarantee(!SubstrateOptions.UseLoom.getValue(), SubstrateOptionsParser.commandArgument(SubstrateOptions.UseLoom, "+") + " cannot be enabled without option " +
5858
SubstrateOptionsParser.commandArgument(SubstrateOptions.SupportContinuations, "+"));
5959
}
60-
ImageSingletons.add(VirtualThreads.class, impl);
6160
}
6261

6362
@Override
@@ -69,12 +68,15 @@ public void beforeAnalysis(BeforeAnalysisAccess access) {
6968
RuntimeReflection.register(ReflectionUtil.lookupMethod(ForkJoinPool.class, "compensatedBlock", ForkJoinPool.ManagedBlocker.class));
7069
}
7170
} else {
72-
access.registerReachabilityHandler(a -> UserError.abort(
73-
"Continuation support is used, but not enabled. Use options " +
74-
SubstrateOptionsParser.commandArgument(SubstrateOptions.SupportContinuations, "+") +
75-
" or " + SubstrateOptionsParser.commandArgument(SubstrateOptions.UseLoom, "+") + "."),
76-
StoredContinuationImpl.class,
77-
ReflectionUtil.lookupMethod(NoVirtualThreads.class, "unreachable"));
71+
access.registerReachabilityHandler(a -> abortIfUnsupported(), StoredContinuationImpl.class);
72+
}
73+
}
74+
75+
static void abortIfUnsupported() {
76+
if (!Continuation.isSupported()) {
77+
throw UserError.abort("Continuation support is used, but not enabled. Use options " +
78+
SubstrateOptionsParser.commandArgument(SubstrateOptions.SupportContinuations, "+") +
79+
" or " + SubstrateOptionsParser.commandArgument(SubstrateOptions.UseLoom, "+") + ".");
7880
}
7981
}
8082
}

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

Lines changed: 13 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -204,7 +204,7 @@ static boolean isInterrupted(Thread thread) {
204204
}
205205

206206
static boolean getAndClearInterrupt(Thread thread) {
207-
if (isVirtual(thread)) {
207+
if (supportsVirtual() && isVirtual(thread)) {
208208
return VirtualThreads.get().getAndClearInterrupt(thread);
209209
}
210210
return platformGetAndClearInterrupt(thread);
@@ -272,12 +272,15 @@ public static Thread fromVMThread(IsolateThread thread) {
272272
return platformThread.get(thread);
273273
}
274274

275-
@AlwaysInline("Inline checks.")
275+
@Fold
276+
static boolean supportsVirtual() {
277+
return VirtualThreads.isSupported();
278+
}
279+
276280
private static boolean isVirtual(Thread thread) {
277-
return VirtualThreads.get().isVirtual(thread);
281+
return supportsVirtual() && VirtualThreads.get().isVirtual(thread);
278282
}
279283

280-
@AlwaysInline("Inline checks.")
281284
private static boolean isVirtualDisallowLoom(Thread thread) {
282285
if (LoomSupport.isEnabled()) {
283286
assert !isVirtual(thread) : "should not see Loom virtual thread objects here";
@@ -323,7 +326,7 @@ static void join(Thread thread, long millis) throws InterruptedException {
323326
if (millis < 0) {
324327
throw new IllegalArgumentException("timeout value is negative");
325328
}
326-
if (isVirtual(thread)) {
329+
if (supportsVirtual() && isVirtual(thread)) {
327330
VirtualThreads.get().join(thread, millis);
328331
return;
329332
}
@@ -709,7 +712,7 @@ protected void beforeThreadRun(@SuppressWarnings("unused") Thread thread) {
709712
protected abstract void platformYield();
710713

711714
void yield() {
712-
if (isVirtualDisallowLoom(Thread.currentThread())) {
715+
if (supportsVirtual() && isVirtualDisallowLoom(Thread.currentThread())) {
713716
VirtualThreads.get().yield();
714717
} else {
715718
platformYield();
@@ -914,7 +917,7 @@ static void platformUnpark(Thread thread) {
914917
}
915918

916919
static void sleep(long millis) throws InterruptedException {
917-
if (isVirtualDisallowLoom(Thread.currentThread())) {
920+
if (supportsVirtual() && isVirtualDisallowLoom(Thread.currentThread())) {
918921
VirtualThreads.get().sleepMillis(millis);
919922
} else {
920923
platformSleep(millis);
@@ -986,7 +989,7 @@ static void platformInterrupt(Thread thread) {
986989
}
987990

988991
static boolean isAlive(Thread thread) {
989-
if (isVirtualDisallowLoom(thread)) {
992+
if (supportsVirtual() && isVirtualDisallowLoom(thread)) {
990993
return VirtualThreads.get().isAlive(thread);
991994
}
992995
return platformIsAlive(thread);
@@ -1009,7 +1012,7 @@ static ThreadData getCurrentThreadData() {
10091012

10101013
@Uninterruptible(reason = "Called from uninterruptible code.")
10111014
public static void setCurrentThreadLockHelper(Object root) {
1012-
if (VirtualThreads.get().isSupported()) {
1015+
if (supportsVirtual()) {
10131016
toTarget(Thread.currentThread()).lockHelper = root;
10141017
} else {
10151018
lockHelper.set(root);
@@ -1019,7 +1022,7 @@ public static void setCurrentThreadLockHelper(Object root) {
10191022
@AlwaysInline("Locking fast path.")
10201023
@Uninterruptible(reason = "Called from uninterruptible code.", mayBeInlined = true)
10211024
public static Object getCurrentThreadLockHelper() {
1022-
if (VirtualThreads.get().isSupported()) {
1025+
if (supportsVirtual()) {
10231026
return toTarget(platformThread.get()).lockHelper;
10241027
}
10251028
return lockHelper.get();

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

Lines changed: 58 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -28,36 +28,27 @@
2828

2929
import java.util.concurrent.ThreadFactory;
3030

31-
import org.graalvm.compiler.api.replacements.Fold;
31+
import org.graalvm.nativeimage.Platforms;
3232

3333
import com.oracle.svm.core.SubstrateUtil;
34-
import com.oracle.svm.core.annotate.AlwaysInline;
3534
import com.oracle.svm.core.util.VMError;
3635

3736
/**
3837
* Code specific to virtual threads is part of the {@link Thread} methods, e.g. {@code yield} or
3938
* {@code sleep}, and the implementation for platform threads generally in {@code yield0} or
4039
* {@code sleep0}, so we only substitute this platform thread code in
41-
* {@link Target_java_lang_Thread}, and never expect these methods to be reachable, therefore
42-
* extending {@link NoVirtualThreads}.
40+
* {@link Target_java_lang_Thread}, and never expect these methods to be reachable.
4341
*/
44-
final class LoomVirtualThreads extends NoVirtualThreads {
42+
final class LoomVirtualThreads implements VirtualThreads {
4543
private static Target_java_lang_VirtualThread cast(Thread thread) {
4644
return SubstrateUtil.cast(thread, Target_java_lang_VirtualThread.class);
4745
}
4846

49-
@Fold
50-
@Override
51-
public boolean isSupported() {
52-
return true;
53-
}
54-
5547
@Override
5648
public ThreadFactory createFactory() {
5749
throw VMError.unimplemented();
5850
}
5951

60-
@AlwaysInline("Eliminate code handling virtual threads.")
6152
@Override
6253
public boolean isVirtual(Thread thread) {
6354
return Target_java_lang_VirtualThread.class.isInstance(thread);
@@ -70,4 +61,59 @@ public void join(Thread thread, long millis) throws InterruptedException {
7061
cast(thread).joinNanos(nanos);
7162
}
7263
}
64+
65+
@Platforms({}) // error if reachable
66+
private static RuntimeException unreachable() {
67+
return VMError.shouldNotReachHere();
68+
}
69+
70+
@Override
71+
public boolean getAndClearInterrupt(Thread thread) {
72+
throw unreachable();
73+
}
74+
75+
@Override
76+
public void yield() {
77+
throw unreachable();
78+
}
79+
80+
@Override
81+
public void sleepMillis(long millis) {
82+
throw unreachable();
83+
}
84+
85+
@Override
86+
public boolean isAlive(Thread thread) {
87+
throw unreachable();
88+
}
89+
90+
@Override
91+
public void unpark(Thread thread) {
92+
throw unreachable();
93+
}
94+
95+
@Override
96+
public void park() {
97+
throw unreachable();
98+
}
99+
100+
@Override
101+
public void parkNanos(long nanos) {
102+
throw unreachable();
103+
}
104+
105+
@Override
106+
public void parkUntil(long deadline) {
107+
throw unreachable();
108+
}
109+
110+
@Override
111+
public void pinCurrent() {
112+
throw unreachable();
113+
}
114+
115+
@Override
116+
public void unpinCurrent() {
117+
throw unreachable();
118+
}
73119
}

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

Lines changed: 0 additions & 110 deletions
This file was deleted.

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

Lines changed: 0 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -31,8 +31,6 @@
3131
import java.util.concurrent.ThreadFactory;
3232
import java.util.concurrent.TimeUnit;
3333

34-
import org.graalvm.compiler.api.replacements.Fold;
35-
3634
/** Our own implementation of virtual threads that does not need Project Loom. */
3735
final class SubstrateVirtualThreads implements VirtualThreads {
3836
private static final class CarrierThread extends ForkJoinWorkerThread {
@@ -58,12 +56,6 @@ private static SubstrateVirtualThread current() {
5856
return (SubstrateVirtualThread) Thread.currentThread();
5957
}
6058

61-
@Fold
62-
@Override
63-
public boolean isSupported() {
64-
return true;
65-
}
66-
6759
@Override
6860
public ThreadFactory createFactory() {
6961
return task -> new SubstrateVirtualThread(null, task);

0 commit comments

Comments
 (0)