Skip to content

Commit 56106df

Browse files
committed
[GR-68917] Fix engine shutdown to also cancel currently active compilations; Avoid waiting for compilations on native-image isolate tear down whenever possible.
PullRequest: graal/21919
2 parents 037ad7b + d433226 commit 56106df

File tree

15 files changed

+246
-75
lines changed

15 files changed

+246
-75
lines changed

compiler/src/jdk.graal.compiler.test/src/jdk/graal/compiler/truffle/test/PolyglotEngineOptionsTest.java

Lines changed: 16 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,8 @@
2424
*/
2525
package jdk.graal.compiler.truffle.test;
2626

27-
import com.oracle.truffle.sl.runtime.SLStrings;
27+
import java.util.ArrayList;
28+
import java.util.List;
2829

2930
import org.graalvm.options.OptionDescriptor;
3031
import org.graalvm.options.OptionStability;
@@ -38,6 +39,7 @@
3839
import com.oracle.truffle.runtime.OptimizedRuntimeOptions;
3940
import com.oracle.truffle.sl.runtime.SLContext;
4041
import com.oracle.truffle.sl.runtime.SLFunction;
42+
import com.oracle.truffle.sl.runtime.SLStrings;
4143

4244
public class PolyglotEngineOptionsTest extends TestWithSynchronousCompiling {
4345

@@ -51,6 +53,9 @@ public void testVisibleOptions() {
5153

5254
@Test
5355
public void testCompilationThreshold() {
56+
// cleanup gets in the way with recursive contexts
57+
this.automaticCleanup = false;
58+
5459
// does not work with a different inline cache size.
5560
Assert.assertEquals(2, SLFunction.INLINE_CACHE_SIZE);
5661

@@ -96,9 +101,16 @@ public void testParseUnknownMode() {
96101
}
97102

98103
private void testCompilationThreshold(int iterations, String compilationThresholdOption, Runnable doWhile) {
99-
Context ctx = setupContext(compilationThresholdOption == null ? new String[]{"engine.MultiTier", "false"}
100-
: new String[]{"engine.SingleTierCompilationThreshold", compilationThresholdOption, "engine.MultiTier", "false"});
104+
List<String> args = new ArrayList<>();
105+
args.add("engine.MultiTier");
106+
args.add("false");
107+
if (compilationThresholdOption != null) {
108+
args.add("engine.SingleTierCompilationThreshold");
109+
args.add(compilationThresholdOption);
110+
}
111+
Context ctx = setupContext(args.toArray(String[]::new));
101112
ctx.eval("sl", "function test() {}");
113+
102114
SLFunction test = SLContext.get(null).getFunctionRegistry().getFunction(SLStrings.fromJavaString("test"));
103115

104116
Assert.assertFalse(isExecuteCompiled(test));
@@ -114,6 +126,7 @@ private void testCompilationThreshold(int iterations, String compilationThreshol
114126
Assert.assertTrue(isExecuteCompiled(test));
115127
test.getCallTarget().call();
116128
Assert.assertTrue(isExecuteCompiled(test));
129+
cleanup();
117130
}
118131

119132
private static boolean isExecuteCompiled(SLFunction value) {

compiler/src/jdk.graal.compiler.test/src/jdk/graal/compiler/truffle/test/RewriteDuringCompilationTest.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -195,7 +195,7 @@ private void testCompilation(FrameDescriptor.Builder builder, BaseNode testedCod
195195
throws IOException, InterruptedException, ExecutionException {
196196
// DetectInvalidCodeNode.invalidTwice does not work with multi-tier
197197
// code can remain active of another tier with local invalidation.
198-
setupEnv(Context.newBuilder().allowExperimentalOptions(true).option("engine.MultiTier", "false"), new ProxyLanguage() {
198+
setupEnv(Context.newBuilder().allowExperimentalOptions(true).option("engine.MultiTier", "false").option("engine.MaximumCompilations", "-1"), new ProxyLanguage() {
199199
private CallTarget target;
200200

201201
@Override

compiler/src/jdk.graal.compiler.test/src/jdk/graal/compiler/truffle/test/TestWithPolyglotOptions.java

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@
3737
public abstract class TestWithPolyglotOptions {
3838

3939
private Context activeContext;
40+
protected boolean automaticCleanup = true;
4041

4142
@After
4243
public final void cleanup() {
@@ -70,7 +71,9 @@ protected final Context setupContext(String... keyValuePairs) {
7071
}
7172

7273
protected final Context setupContext(Context.Builder builder) {
73-
cleanup();
74+
if (automaticCleanup) {
75+
cleanup();
76+
}
7477
Context newContext = builder.build();
7578
newContext.enter();
7679
activeContext = newContext;

substratevm/src/com.oracle.svm.truffle/src/com/oracle/svm/truffle/api/SubstrateTruffleCompiler.java

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,9 @@ public interface SubstrateTruffleCompiler extends TruffleCompiler {
4141

4242
/**
4343
* Called on tear-down of the current isolate.
44+
*
45+
* @param shutdownCompilationsAndWaitAction action to perform before a compiler isolate would
46+
* shut down to cancel work that can delay the shutdown.
4447
*/
45-
void teardown();
48+
void teardown(Runnable shutdownCompilationsAndWaitAction);
4649
}

substratevm/src/com.oracle.svm.truffle/src/com/oracle/svm/truffle/api/SubstrateTruffleCompilerImpl.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -110,7 +110,7 @@ protected void parseGraalOptions(String[] options, EconomicMap<OptionKey<?>, Obj
110110
}
111111

112112
@Override
113-
public void teardown() {
113+
public void teardown(Runnable shutdownCompilationsAndWaitAction) {
114114
}
115115

116116
@Override

substratevm/src/com.oracle.svm.truffle/src/com/oracle/svm/truffle/api/SubstrateTruffleRuntime.java

Lines changed: 10 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -103,6 +103,7 @@ static boolean isMultiThreaded() {
103103
*/
104104
return SubstrateTruffleOptions.TruffleMultiThreaded.getValue();
105105
}
106+
106107
}
107108

108109
public final class SubstrateTruffleRuntime extends OptimizedTruffleRuntime {
@@ -166,7 +167,7 @@ private void initializeAtRuntime(OptimizedCallTarget callTarget) {
166167
Deoptimizer.Options.TraceDeoptimization.update(true);
167168
}
168169
installDefaultListeners();
169-
RuntimeSupport.getRuntimeSupport().addTearDownHook(isFirstIsolate -> teardown());
170+
RuntimeSupport.getRuntimeSupport().addTearDownHook(_ -> teardownCompilerIsolate());
170171
}
171172

172173
@Override
@@ -198,16 +199,16 @@ public ConstantFieldInfo getConstantFieldInfo(ResolvedJavaField field) {
198199
return super.getConstantFieldInfo(field);
199200
}
200201

201-
private void teardown() {
202-
long timeout = SubstrateUtil.assertionsEnabled() ? DEBUG_TEAR_DOWN_TIMEOUT : PRODUCTION_TEAR_DOWN_TIMEOUT;
203-
BackgroundCompileQueue queue = getCompileQueue();
204-
if (queue != null) {
205-
queue.shutdownAndAwaitTermination(timeout);
206-
}
207-
202+
private void teardownCompilerIsolate() {
208203
TruffleCompiler tcp = truffleCompiler;
209204
if (tcp != null) {
210-
((SubstrateTruffleCompiler) tcp).teardown();
205+
((SubstrateTruffleCompiler) tcp).teardown(() -> {
206+
long timeout = SubstrateUtil.assertionsEnabled() ? DEBUG_TEAR_DOWN_TIMEOUT : PRODUCTION_TEAR_DOWN_TIMEOUT;
207+
BackgroundCompileQueue queue = getCompileQueue();
208+
if (queue != null) {
209+
queue.shutdownAndAwaitTermination(timeout);
210+
}
211+
});
211212
}
212213
}
213214

substratevm/src/com.oracle.svm.truffle/src/com/oracle/svm/truffle/isolated/IsolateAwareTruffleCompiler.java

Lines changed: 24 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -229,9 +229,31 @@ private static void copyEncodedOptions(@SuppressWarnings("unused") @CEntryPoint.
229229
}
230230

231231
@Override
232-
public void teardown() {
232+
public void teardown(Runnable shutdownCompilationsAndWaitAction) {
233233
if (SubstrateOptions.shouldCompileInIsolates()) {
234-
tearDownIsolateOnShutdown();
234+
/*
235+
* Start a separate thread for shutting down any ongoing compilations. If we are in a
236+
* process with a single Truffle runtime (e.g. a language launcher), it can {@linkplain
237+
* System#exit exit} early without waiting for this thread to finish. If there are
238+
* potentially multiple isolates in the current process, the thread will delay the
239+
* shutdown of the runtime isolate until the compilation isolate has been fully torn
240+
* down.
241+
*/
242+
Thread t = new Thread(() -> {
243+
shutdownCompilationsAndWaitAction.run();
244+
tearDownIsolateOnShutdown();
245+
});
246+
// we ignore uncaught exceptions here. For example
247+
// if the waiting thread was interrupted.
248+
t.setUncaughtExceptionHandler((_, _) -> {
249+
});
250+
/*
251+
* Technically this does not need to be a daemon thread, as either way this thread is
252+
* still being waited on when tearing down the isolate. However it seems more correct to
253+
* mark this thread as daemon as it should not prevent the regular JVM shutdown.
254+
*/
255+
t.setDaemon(true);
256+
t.start();
235257
}
236258
}
237259

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

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -831,6 +831,7 @@ public abstract <T, G> Iterator<T> mergeHostGuestFrames(Object polyglotEngine, S
831831
public abstract DispatchOutputStream getEngineOut(Object engine);
832832

833833
public abstract InputStream getEngineIn(Object engine);
834+
834835
}
835836

836837
public abstract static class LanguageSupport extends Support {
@@ -1285,7 +1286,7 @@ public final FrameExtensions getFrameExtensionsUnsafe() {
12851286
@SuppressWarnings({"unchecked"})
12861287
public abstract <T> T unsafeCast(Object value, Class<T> type, boolean condition, boolean nonNull, boolean exact);
12871288

1288-
public abstract void flushCompileQueue(Object runtimeData);
1289+
public abstract void shutdownCompilationForEngine(Object engineData);
12891290

12901291
public abstract Object createRuntimeData(Object engine, OptionValues engineOptions, Function<String, TruffleLogger> loggerFactory, SandboxPolicy sandboxPolicy);
12911292

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -212,7 +212,7 @@ public Object[] castArrayFixedLength(Object[] args, int length) {
212212
}
213213

214214
@Override
215-
public void flushCompileQueue(Object runtimeData) {
215+
public void shutdownCompilationForEngine(Object runtimeData) {
216216
// default runtime has no compile queue.
217217
}
218218

truffle/src/com.oracle.truffle.polyglot/src/com/oracle/truffle/polyglot/PolyglotEngineImpl.java

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1366,6 +1366,11 @@ void ensureClosed(boolean force, boolean initiatedByContext) {
13661366

13671367
synchronized (this.lock) {
13681368
closed = true;
1369+
// We want to flush as early as possible to make sure we start cancelling fast.
1370+
// this also makes sure we are no longer accepting any compilations from this engine
1371+
if (runtimeData != null) {
1372+
EngineAccessor.RUNTIME.shutdownCompilationForEngine(runtimeData);
1373+
}
13691374
closingThread = null;
13701375
this.lock.notifyAll();
13711376
if (!activeSystemThreads.isEmpty()) {
@@ -1409,10 +1414,6 @@ void ensureClosed(boolean force, boolean initiatedByContext) {
14091414
}
14101415

14111416
polyglotHostService.notifyEngineClosed(this, force);
1412-
1413-
if (runtimeData != null) {
1414-
EngineAccessor.RUNTIME.flushCompileQueue(runtimeData);
1415-
}
14161417
getAPIAccess().engineClosed(weakAPI);
14171418
}
14181419
}

0 commit comments

Comments
 (0)