Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,9 @@
import com.oracle.svm.core.feature.InternalFeature;
import com.oracle.svm.core.heap.StoredContinuation;
import com.oracle.svm.core.heap.StoredContinuationAccess;
import com.oracle.svm.core.option.SubstrateOptionsParser;
import com.oracle.svm.core.util.UserError;
import com.oracle.svm.core.util.VMError;
import com.oracle.svm.util.ReflectionUtil;

@AutomaticallyRegisteredFeature
Expand All @@ -45,43 +47,52 @@ public class ContinuationsFeature implements InternalFeature {

@Override
public void afterRegistration(AfterRegistrationAccess access) {
final int firstLoomPreviewVersion = 19;
final int lastLoomPreviewVersion = 20;

boolean supportLoom = false;
if (JavaVersionUtil.JAVA_SPEC >= 19) {
boolean haveLoom = false;
try {
haveLoom = (Boolean) Class.forName("jdk.internal.misc.PreviewFeatures")
.getDeclaredMethod("isEnabled").invoke(null);
} catch (ReflectiveOperationException ignored) {
}
if (!haveLoom) {
// Can still get initialized and fail the image build despite substitution, so defer
RuntimeClassInitialization.initializeAtRunTime("jdk.internal.vm.Continuation");
if (JavaVersionUtil.JAVA_SPEC >= firstLoomPreviewVersion) {
boolean haveLoom;
if (JavaVersionUtil.JAVA_SPEC > lastLoomPreviewVersion) {
haveLoom = true;
} else {
try {
haveLoom = (Boolean) Class.forName("jdk.internal.misc.PreviewFeatures")
.getDeclaredMethod("isEnabled").invoke(null);
} catch (ReflectiveOperationException e) {
throw VMError.shouldNotReachHere(e);
}
if (!haveLoom) {
// Defer: can get initialized and fail the image build despite substitution
RuntimeClassInitialization.initializeAtRunTime("jdk.internal.vm.Continuation");
}
}
// Fail if virtual threads are used and runtime compilation is enabled
supportLoom = haveLoom && !DeoptimizationSupport.enabled() && !SubstrateOptions.useLLVMBackend();
}

/*
* Note: missing support for Loom due to preview features being off, runtime compilation, or
* the LLVM backend is reported at runtime to allow probing without failing the image build.
*/
if (supportLoom) {
LoomVirtualThreads vt = new LoomVirtualThreads();
ImageSingletons.add(VirtualThreads.class, vt);
ImageSingletons.add(LoomVirtualThreads.class, vt); // for simpler check in LoomSupport
} else if (SubstrateOptions.SupportContinuations.getValue()) {
if (SubstrateOptions.useLLVMBackend()) {
throw UserError.abort("Virtual threads are not supported together with the LLVM backend.");
if (DeoptimizationSupport.enabled()) {
throw UserError.abort("Option %s is in use, but is not supported together with Truffle JIT compilation.",
SubstrateOptionsParser.commandArgument(SubstrateOptions.SupportContinuations, "+"));
} else if (SubstrateOptions.useLLVMBackend()) {
throw UserError.abort("Option %s is in use, but is not supported together with the LLVM backend.",
SubstrateOptionsParser.commandArgument(SubstrateOptions.SupportContinuations, "+"));
} else if (JavaVersionUtil.JAVA_SPEC == 17) {
if (DeoptimizationSupport.enabled()) {
throw UserError.abort("Virtual threads are enabled, but are currently not supported together with Truffle JIT compilation.");
}
ImageSingletons.add(VirtualThreads.class, new SubstrateVirtualThreads());
} else if (JavaVersionUtil.JAVA_SPEC >= firstLoomPreviewVersion && JavaVersionUtil.JAVA_SPEC <= lastLoomPreviewVersion) {
throw UserError.abort("Virtual threads on JDK %d are supported only with preview features enabled (--enable-preview). Using option %s is unnecessary.",
JavaVersionUtil.JAVA_SPEC, SubstrateOptionsParser.commandArgument(SubstrateOptions.SupportContinuations, "+"));
} else {
/*
* GR-37518: on 11, ForkJoinPool syncs on a String that doesn't have its own monitor
* field, and unparking a virtual thread in additionalMonitorsLock.unlock causes a
* deadlock between carrier thread and virtual thread. 17 uses a ReentrantLock.
*
* We intentionally do not advertise non-Loom continuation support on 17.
*/
throw UserError.abort("Virtual threads are supported only on JDK 19 with preview features enabled (--enable-preview).");
throw UserError.abort("Option %s is in use, but is not supported on JDK %d.",
SubstrateOptionsParser.commandArgument(SubstrateOptions.SupportContinuations, "+"), JavaVersionUtil.JAVA_SPEC);
}
}
finishedRegistration = true;
Expand All @@ -105,11 +116,6 @@ public void beforeAnalysis(BeforeAnalysisAccess access) {
ReflectionUtil.lookupMethod(StoredContinuationAccess.class, "allocate", int.class));
} else {
access.registerReachabilityHandler(a -> abortIfUnsupported(), StoredContinuationAccess.class);
if (JavaVersionUtil.JAVA_SPEC >= 19) {
access.registerReachabilityHandler(a -> abortIfUnsupported(),
ReflectionUtil.lookupMethod(Thread.class, "ofVirtual"),
ReflectionUtil.lookupMethod(Thread.class, "startVirtualThread", Runnable.class));
}
}
}

Expand All @@ -123,11 +129,6 @@ public void beforeCompilation(BeforeCompilationAccess access) {
}

static void abortIfUnsupported() {
if (!Continuation.isSupported()) {
if (DeoptimizationSupport.enabled()) {
throw UserError.abort("Virtual threads are used in code, but are currently not supported together with Truffle JIT compilation.");
}
throw UserError.abort("Virtual threads are used in code, but are not currently available or active. Use JDK 19 with preview features enabled (--enable-preview).");
}
VMError.guarantee(Continuation.isSupported(), "Virtual thread internals are reachable but support is not available or active.");
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,6 @@
import java.util.concurrent.ThreadFactory;
import java.util.function.BooleanSupplier;

import com.oracle.svm.util.ReflectionUtil;
import org.graalvm.compiler.api.directives.GraalDirectives;
import org.graalvm.compiler.replacements.ReplacementsUtil;
import org.graalvm.compiler.serviceprovider.JavaVersionUtil;
Expand All @@ -52,6 +51,7 @@
import com.oracle.svm.core.annotate.Substitute;
import com.oracle.svm.core.annotate.TargetClass;
import com.oracle.svm.core.annotate.TargetElement;
import com.oracle.svm.core.deopt.DeoptimizationSupport;
import com.oracle.svm.core.jdk.ContinuationsNotSupported;
import com.oracle.svm.core.jdk.ContinuationsSupported;
import com.oracle.svm.core.jdk.JDK11OrEarlier;
Expand All @@ -63,6 +63,7 @@
import com.oracle.svm.core.jdk.NotLoomJDK;
import com.oracle.svm.core.monitor.MonitorSupport;
import com.oracle.svm.core.util.VMError;
import com.oracle.svm.util.ReflectionUtil;

@TargetClass(Thread.class)
@SuppressWarnings({"unused"})
Expand Down Expand Up @@ -635,17 +636,27 @@ private static void clearInterruptEvent() {
@TargetElement(onlyWith = LoomJDK.class)
public static native Target_java_lang_Thread_Builder ofVirtual();

/** This method being reachable fails the image build, see {@link ContinuationsFeature}. */
@Substitute
@TargetElement(name = "ofVirtual", onlyWith = {JDK19OrLater.class, NotLoomJDK.class})
public static Target_java_lang_Thread_Builder ofVirtualWithoutLoom() {
if (Target_jdk_internal_misc_PreviewFeatures.isEnabled()) {
if (DeoptimizationSupport.enabled()) {
throw new UnsupportedOperationException("Virtual threads are not supported together with Truffle JIT compilation.");
}
if (SubstrateOptions.useLLVMBackend()) {
throw new UnsupportedOperationException("Virtual threads are not supported together with the LLVM backend.");
}
} else {
Target_jdk_internal_misc_PreviewFeatures.ensureEnabled(); // throws
}
throw VMError.shouldNotReachHere();
}

/** This method being reachable fails the image build, see {@link ContinuationsFeature}. */
@Substitute
@TargetElement(onlyWith = {JDK19OrLater.class, NotLoomJDK.class})
static Thread startVirtualThread(Runnable task) {
@TargetElement(name = "startVirtualThread", onlyWith = {JDK19OrLater.class, NotLoomJDK.class})
static Thread startVirtualThreadWithoutLoom(Runnable task) {
Objects.requireNonNull(task);
ofVirtualWithoutLoom(); // throws
throw VMError.shouldNotReachHere();
}

Expand Down Expand Up @@ -783,3 +794,12 @@ interface Target_sun_nio_ch_Interruptible {
@Alias
void interrupt(Thread t);
}

@TargetClass(className = "jdk.internal.misc.PreviewFeatures", onlyWith = JDK19OrLater.class)
final class Target_jdk_internal_misc_PreviewFeatures {
@Alias
static native boolean isEnabled();

@Alias
static native void ensureEnabled();
}