Skip to content

Commit 8de9cc1

Browse files
committed
[GR-68675] Libgraal crash in com.oracle.truffle.api.test.polyglot.LoomTest.
PullRequest: graal/22717
2 parents 7fe1f65 + 6509e19 commit 8de9cc1

File tree

5 files changed

+137
-44
lines changed

5 files changed

+137
-44
lines changed

truffle/src/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/polyglot/LoomTest.java

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,6 @@
4747
import org.graalvm.polyglot.Context;
4848
import org.graalvm.polyglot.Value;
4949
import org.junit.Assume;
50-
import org.junit.Ignore;
5150
import org.junit.Test;
5251

5352
import java.io.ByteArrayOutputStream;
@@ -76,7 +75,6 @@ public void testEmbedderVirtualThread() throws Throwable {
7675
}
7776

7877
@Test
79-
@Ignore("GR-68675")
8078
public void testManyVirtualThreads() throws Throwable {
8179
Assume.assumeTrue(canCreateVirtualThreads() && !TruffleOptions.AOT);
8280

truffle/src/com.oracle.truffle.api/src/com/oracle/truffle/api/impl/Accessor.java

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1444,6 +1444,35 @@ public final void registerVirtualThreadMountHooks(Consumer<? super Thread> onMou
14441444

14451445
public abstract Thread currentCarrierThread();
14461446

1447+
/**
1448+
* Executes the given {@code action} while the current virtual thread is pinned to its
1449+
* carrier thread.
1450+
* <p>
1451+
* Pinning a virtual thread prevents the scheduler from mounting it on a different carrier
1452+
* thread for the duration of the {@code action}. This ensures that the carrier thread
1453+
* remains stable for operations that require thread local affinity or depend on native
1454+
* thread identity.
1455+
* <p>
1456+
* If the current thread is not a virtual thread, then no pinning is performed and the
1457+
* {@code action} is executed normally. In this case the call behaves as a simple
1458+
* {@code action.get()} invocation without any interaction with the virtual-thread
1459+
* scheduler.
1460+
* <p>
1461+
* Pinning is performed by the native method {@link #runPinned0(Supplier)}, which enters a
1462+
* region where the virtual-thread scheduler is prevented from unmounting the current
1463+
* virtual thread from its carrier thread. The virtual thread remains mounted on the same
1464+
* carrier for the duration of the call, and is unpinned when the native method returns.
1465+
*/
1466+
public final <T> T runInPinnedVirtualThread(Supplier<T> action) {
1467+
if (JDKAccessor.isVirtualThread(Thread.currentThread())) {
1468+
return runPinned0(action);
1469+
} else {
1470+
return action.get();
1471+
}
1472+
}
1473+
1474+
private static native <T> T runPinned0(Supplier<T> action);
1475+
14471476
private static native void registerJVMTIHook();
14481477

14491478
/** Called from a JVMTI VirtualThreadMount hook. */

truffle/src/com.oracle.truffle.attach/src/truffle_attach.c

Lines changed: 36 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (c) 2023, 2024, Oracle and/or its affiliates. All rights reserved.
2+
* Copyright (c) 2023, 2025, Oracle and/or its affiliates. All rights reserved.
33
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
44
*
55
* This code is free software; you can redistribute it and/or modify it
@@ -32,6 +32,11 @@
3232
return; \
3333
}
3434

35+
#define EXCEPTION_CHECK_OBJECT(env) \
36+
if ((*env)->ExceptionCheck(env)) { \
37+
return NULL; \
38+
}
39+
3540
#define CHECK_NONZERO(cond) \
3641
if (!(cond)) { \
3742
fprintf(stderr, "[engine::attach] ERROR in " #cond ", was unexpectedly 0\n"); \
@@ -62,6 +67,32 @@ JNIEXPORT void JNICALL Java_com_oracle_truffle_polyglot_JDKSupport_addExports0(J
6267
static jobject virtualThreadHooksClass;
6368
static jmethodID mountMethod;
6469
static jmethodID unmountMethod;
70+
static jclass supplierClassGlobal;
71+
static jmethodID supplierGetMethod;
72+
73+
JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM *vm, void *reserved) {
74+
JNIEnv *env;
75+
if ((*vm)->GetEnv(vm, (void **) &env, JNI_VERSION_21) != JNI_OK) {
76+
return JNI_ERR;
77+
}
78+
79+
jclass supplierClass = (*env)->FindClass(env, "java/util/function/Supplier");
80+
if (supplierClass == NULL) {
81+
return JNI_ERR;
82+
}
83+
84+
supplierClassGlobal = (*env)->NewGlobalRef(env, supplierClass);
85+
if (supplierClassGlobal == NULL) {
86+
return JNI_ERR;
87+
}
88+
89+
supplierGetMethod = (*env)->GetMethodID(env, supplierClassGlobal, "get", "()Ljava/lang/Object;");
90+
if (supplierGetMethod == NULL) {
91+
return JNI_ERR;
92+
}
93+
94+
return JNI_VERSION_21;
95+
}
6596

6697
// Parameters: (jvmtiEnv *jvmti, JNIEnv* env, jthread vthread)
6798
static void JNICALL mount_callback(jvmtiEnv *jvmti, ...) {
@@ -142,3 +173,7 @@ JNIEXPORT void JNICALL Java_com_oracle_truffle_api_impl_Accessor_00024JavaLangSu
142173
CHECK_ERROR((*jvmti)->SetExtensionEventCallback(jvmti, unmount_event_index, unmount_callback));
143174
CHECK_ERROR((*jvmti)->SetEventNotificationMode(jvmti, JVMTI_ENABLE, unmount_event_index, NULL));
144175
}
176+
177+
JNIEXPORT jobject JNICALL Java_com_oracle_truffle_api_impl_Accessor_00024JavaLangSupport_runPinned0(JNIEnv *env, jclass clz, jobject action) {
178+
return (*env)->CallObjectMethod(env, action, supplierGetMethod);
179+
}

truffle/src/com.oracle.truffle.runtime/src/com/oracle/truffle/runtime/hotspot/libgraal/LibGraalHotSpotTruffleCompiler.java

Lines changed: 15 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,7 @@
4848
import com.oracle.truffle.compiler.TruffleCompilationTask;
4949
import com.oracle.truffle.compiler.TruffleCompilerListener;
5050
import com.oracle.truffle.compiler.hotspot.HotSpotTruffleCompiler;
51+
import com.oracle.truffle.runtime.ModulesSupport;
5152
import com.oracle.truffle.runtime.hotspot.HotSpotTruffleRuntime;
5253

5354
import jdk.vm.ci.meta.ResolvedJavaMethod;
@@ -115,17 +116,25 @@ public void shutdown() {
115116
@Override
116117
@SuppressWarnings("try")
117118
public void installTruffleCallBoundaryMethod(ResolvedJavaMethod method, TruffleCompilable compilable) {
118-
try (LibGraalScope scope = new LibGraalScope(LibGraalScope.DetachAction.DETACH_RUNTIME_AND_RELEASE)) {
119-
TruffleToLibGraalCalls.installTruffleCallBoundaryMethod(getIsolateThread(), getOrCreateIsolate(compilable, false), LibGraal.translate(method));
120-
}
119+
Supplier<Void> action = () -> {
120+
try (LibGraalScope scope = new LibGraalScope(LibGraalScope.DetachAction.DETACH_RUNTIME_AND_RELEASE)) {
121+
TruffleToLibGraalCalls.installTruffleCallBoundaryMethod(getIsolateThread(), getOrCreateIsolate(compilable, false), LibGraal.translate(method));
122+
}
123+
return null;
124+
};
125+
ModulesSupport.getJavaLangSupport().runInPinnedVirtualThread(action);
121126
}
122127

123128
@Override
124129
@SuppressWarnings("try")
125130
public void installTruffleReservedOopMethod(ResolvedJavaMethod method, TruffleCompilable compilable) {
126-
try (LibGraalScope scope = new LibGraalScope(LibGraalScope.DetachAction.DETACH_RUNTIME_AND_RELEASE)) {
127-
TruffleToLibGraalCalls.installTruffleReservedOopMethod(getIsolateThread(), getOrCreateIsolate(compilable, false), LibGraal.translate(method));
128-
}
131+
Supplier<Void> action = () -> {
132+
try (LibGraalScope scope = new LibGraalScope(LibGraalScope.DetachAction.DETACH_RUNTIME_AND_RELEASE)) {
133+
TruffleToLibGraalCalls.installTruffleReservedOopMethod(getIsolateThread(), getOrCreateIsolate(compilable, false), LibGraal.translate(method));
134+
}
135+
return null;
136+
};
137+
ModulesSupport.getJavaLangSupport().runInPinnedVirtualThread(action);
129138
}
130139

131140
Integer pendingTransferToInterpreterOffset;

truffle/src/com.oracle.truffle.runtime/src/com/oracle/truffle/runtime/hotspot/libgraal/LibGraalTruffleCompilationSupport.java

Lines changed: 57 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -48,10 +48,13 @@
4848
import com.oracle.truffle.compiler.TruffleCompilerOptionDescriptor;
4949
import com.oracle.truffle.compiler.TruffleCompilerOptionDescriptor.Type;
5050
import com.oracle.truffle.compiler.TruffleCompilerRuntime;
51+
import com.oracle.truffle.runtime.ModulesSupport;
5152
import com.oracle.truffle.runtime.debug.JFRListener;
5253
import com.oracle.truffle.runtime.hotspot.HotSpotTruffleRuntime;
5354
import com.oracle.truffle.runtime.hotspot.libgraal.LibGraalScope.DetachAction;
5455

56+
import java.util.function.Supplier;
57+
5558
/**
5659
* Represents a truffle compilation bundling compilable and task into a single object. Also installs
5760
* the TTY filter to forward log messages to the truffle runtime.
@@ -94,9 +97,12 @@ public String getCompilerConfigurationName(TruffleCompilerRuntime runtime) {
9497

9598
@SuppressWarnings("try")
9699
private static String getCompilerConfigurationNameImpl(TruffleCompilerRuntime runtime) {
97-
try (LibGraalScope scope = new LibGraalScope(DetachAction.DETACH_RUNTIME_AND_RELEASE)) {
98-
return TruffleToLibGraalCalls.getCompilerConfigurationFactoryName(getIsolateThread(), handle(runtime));
99-
}
100+
Supplier<String> action = () -> {
101+
try (LibGraalScope scope = new LibGraalScope(DetachAction.DETACH_RUNTIME_AND_RELEASE)) {
102+
return TruffleToLibGraalCalls.getCompilerConfigurationFactoryName(getIsolateThread(), handle(runtime));
103+
}
104+
};
105+
return ModulesSupport.getJavaLangSupport().runInPinnedVirtualThread(action);
100106
}
101107

102108
@Override
@@ -107,12 +113,16 @@ public TruffleCompiler createCompiler(TruffleCompilerRuntime runtime) {
107113
@SuppressWarnings("try")
108114
@Override
109115
public void registerRuntime(TruffleCompilerRuntime runtime) {
110-
try (LibGraalScope scope = new LibGraalScope(DetachAction.DETACH_RUNTIME_AND_RELEASE)) {
111-
runtime().registerNativeMethods(TruffleToLibGraalCalls.class);
112-
if (!registerRuntimeImpl(runtime)) {
113-
throw new IllegalStateException("Truffle with libgraal cannot be loaded in multiple class loaders. Make sure Truffle is loaded with the system class loader.");
116+
Supplier<Void> action = () -> {
117+
try (LibGraalScope scope = new LibGraalScope(DetachAction.DETACH_RUNTIME_AND_RELEASE)) {
118+
runtime().registerNativeMethods(TruffleToLibGraalCalls.class);
119+
if (!registerRuntimeImpl(runtime)) {
120+
throw new IllegalStateException("Truffle with libgraal cannot be loaded in multiple class loaders. Make sure Truffle is loaded with the system class loader.");
121+
}
114122
}
115-
}
123+
return null;
124+
};
125+
ModulesSupport.getJavaLangSupport().runInPinnedVirtualThread(action);
116126
}
117127

118128
private static boolean registerRuntimeImpl(TruffleCompilerRuntime runtime) {
@@ -135,38 +145,47 @@ private static <T extends Throwable> T sthrow(Class<T> type, Throwable t) throws
135145
@SuppressWarnings("try")
136146
@Override
137147
public TruffleCompilerOptionDescriptor[] listCompilerOptions() {
138-
try (LibGraalScope scope = new LibGraalScope(DetachAction.DETACH_RUNTIME_AND_RELEASE)) {
139-
byte[] binary = TruffleToLibGraalCalls.listCompilerOptions(getIsolateThread());
140-
BinaryInput input = BinaryInput.create(binary);
141-
int length = input.readInt();
142-
TruffleCompilerOptionDescriptor[] descriptors = new TruffleCompilerOptionDescriptor[length];
143-
Type[] types = Type.values();
144-
for (int i = 0; i < length; i++) {
145-
String name = input.readUTF();
146-
int typeOrdinal = input.readInt();
147-
boolean deprecated = input.readBoolean();
148-
String help = input.readUTF();
149-
String deprecationMessage = input.readUTF();
150-
descriptors[i] = new TruffleCompilerOptionDescriptor(name, types[typeOrdinal], deprecated, help, deprecationMessage);
148+
Supplier<TruffleCompilerOptionDescriptor[]> action = () -> {
149+
try (LibGraalScope scope = new LibGraalScope(DetachAction.DETACH_RUNTIME_AND_RELEASE)) {
150+
byte[] binary = TruffleToLibGraalCalls.listCompilerOptions(getIsolateThread());
151+
BinaryInput input = BinaryInput.create(binary);
152+
int length = input.readInt();
153+
TruffleCompilerOptionDescriptor[] descriptors = new TruffleCompilerOptionDescriptor[length];
154+
Type[] types = Type.values();
155+
for (int i = 0; i < length; i++) {
156+
String name = input.readUTF();
157+
int typeOrdinal = input.readInt();
158+
boolean deprecated = input.readBoolean();
159+
String help = input.readUTF();
160+
String deprecationMessage = input.readUTF();
161+
descriptors[i] = new TruffleCompilerOptionDescriptor(name, types[typeOrdinal], deprecated, help, deprecationMessage);
162+
}
163+
return descriptors;
151164
}
152-
return descriptors;
153-
}
165+
};
166+
return ModulesSupport.getJavaLangSupport().runInPinnedVirtualThread(action);
154167
}
155168

156169
@SuppressWarnings("try")
157170
@Override
158171
public String validateCompilerOption(String key, String value) {
159-
try (LibGraalScope scope = new LibGraalScope(DetachAction.DETACH_RUNTIME_AND_RELEASE)) {
160-
return TruffleToLibGraalCalls.validateCompilerOption(getIsolateThread(), key, value);
161-
}
172+
Supplier<String> action = () -> {
173+
try (LibGraalScope scope = new LibGraalScope(DetachAction.DETACH_RUNTIME_AND_RELEASE)) {
174+
return TruffleToLibGraalCalls.validateCompilerOption(getIsolateThread(), key, value);
175+
}
176+
};
177+
return ModulesSupport.getJavaLangSupport().runInPinnedVirtualThread(action);
162178
}
163179

164180
@SuppressWarnings("try")
165181
@Override
166182
public boolean compilerOptionExists(String key) {
167-
try (LibGraalScope scope = new LibGraalScope(DetachAction.DETACH_RUNTIME_AND_RELEASE)) {
168-
return TruffleToLibGraalCalls.compilerOptionExists(getIsolateThread(), key);
169-
}
183+
Supplier<Boolean> action = () -> {
184+
try (LibGraalScope scope = new LibGraalScope(DetachAction.DETACH_RUNTIME_AND_RELEASE)) {
185+
return TruffleToLibGraalCalls.compilerOptionExists(getIsolateThread(), key);
186+
}
187+
};
188+
return ModulesSupport.getJavaLangSupport().runInPinnedVirtualThread(action);
170189
}
171190

172191
@Override
@@ -210,12 +229,15 @@ private static long initializeRuntimeImpl(TruffleCompilerRuntime runtime) {
210229
@SuppressWarnings("try")
211230
@Override
212231
public String getCompilerVersion() {
213-
try (LibGraalScope scope = new LibGraalScope(DetachAction.DETACH_RUNTIME_AND_RELEASE)) {
214-
return TruffleToLibGraalCalls.getCompilerVersion(getIsolateThread());
215-
} catch (UnsatisfiedLinkError linkError) {
216-
// An old libjvmcicompiler without the getReleaseVersion entry point.
217-
return null;
218-
}
232+
Supplier<String> action = () -> {
233+
try (LibGraalScope scope = new LibGraalScope(DetachAction.DETACH_RUNTIME_AND_RELEASE)) {
234+
return TruffleToLibGraalCalls.getCompilerVersion(getIsolateThread());
235+
} catch (UnsatisfiedLinkError linkError) {
236+
// An old libjvmcicompiler without the getReleaseVersion entry point.
237+
return null;
238+
}
239+
};
240+
return ModulesSupport.getJavaLangSupport().runInPinnedVirtualThread(action);
219241
}
220242

221243
}

0 commit comments

Comments
 (0)