commit be45c3dff0d54d13191e9684f34b8ebb10a8aff6
parent 683ff1c5684b7bfce9aec2f0c9b1f41699962897
Author: Tooru Fujisawa <arai_a@mac.com>
Date: Wed, 29 Oct 2025 09:18:44 +0000
Bug 1995991 - Do not assert the remaining tasks when force-quitting. r=iain
Differential Revision: https://phabricator.services.mozilla.com/D270100
Diffstat:
4 files changed, 39 insertions(+), 4 deletions(-)
diff --git a/js/src/jit-test/tests/atomics/waitAsync-quit.js b/js/src/jit-test/tests/atomics/waitAsync-quit.js
@@ -0,0 +1,11 @@
+// This shouldn't hit any assertion failure during the shutdown.
+
+let c = new SharedArrayBuffer(16);
+let d = new Int32Array(c);
+
+for (var i = 0; i < 200; i++) {
+ Atomics.waitAsync(d, 0, 0, 1);
+}
+
+// Any remainig delayed tasks for the timeout should be ignored.
+quit();
diff --git a/js/src/shell/js.cpp b/js/src/shell/js.cpp
@@ -2761,6 +2761,15 @@ static bool ConvertTranscodeResultToJSException(JSContext* cx,
static void SetQuitting(JSContext* cx, int32_t code) {
ShellContext* sc = GetShellContext(cx);
js::StopDrainingJobQueue(cx);
+#ifdef DEBUG
+ {
+ AutoLockHelperThreadState helperLock;
+
+ OffThreadPromiseRuntimeState& state =
+ cx->runtime()->offThreadPromiseState.ref();
+ state.setForceQuitting();
+ }
+#endif
sc->exitCode = code;
sc->quitting = true;
}
diff --git a/js/src/vm/OffThreadPromiseRuntimeState.cpp b/js/src/vm/OffThreadPromiseRuntimeState.cpp
@@ -249,13 +249,17 @@ OffThreadPromiseRuntimeState::OffThreadPromiseRuntimeState()
: dispatchToEventLoopCallback_(nullptr),
delayedDispatchToEventLoopCallback_(nullptr),
dispatchToEventLoopClosure_(nullptr),
+#ifdef DEBUG
+ forceQuitting_(false),
+#endif
numRegistered_(0),
- internalDispatchQueueClosed_(false) {}
+ internalDispatchQueueClosed_(false) {
+}
OffThreadPromiseRuntimeState::~OffThreadPromiseRuntimeState() {
- MOZ_ASSERT(numRegistered_ == 0);
- MOZ_ASSERT(numDelayed_ == 0);
- MOZ_ASSERT(internalDispatchQueue_.refNoCheck().empty());
+ MOZ_ASSERT_IF(!forceQuitting_, numRegistered_ == 0);
+ MOZ_ASSERT_IF(!forceQuitting_, numDelayed_ == 0);
+ MOZ_ASSERT_IF(!forceQuitting_, internalDispatchQueue_.refNoCheck().empty());
MOZ_ASSERT(!initialized());
}
diff --git a/js/src/vm/OffThreadPromiseRuntimeState.h b/js/src/vm/OffThreadPromiseRuntimeState.h
@@ -259,6 +259,13 @@ class OffThreadPromiseRuntimeState {
JS::DelayedDispatchToEventLoopCallback delayedDispatchToEventLoopCallback_;
void* dispatchToEventLoopClosure_;
+#ifdef DEBUG
+ // Set to true when the JS shell is force-quitting.
+ // In this case the tasks won't be drained and the destructor cannot
+ // assert anything.
+ HelperThreadLockData<bool> forceQuitting_;
+#endif
+
// A set of all OffThreadPromiseTasks that have successfully called 'init'.
// This set doesn't own tasks. OffThreadPromiseTask's destructor decrements
// this counter.
@@ -357,6 +364,10 @@ class OffThreadPromiseRuntimeState {
// shutdown() must be called by the JSRuntime while the JSRuntime is valid.
void shutdown(JSContext* cx);
+
+#ifdef DEBUG
+ void setForceQuitting() { forceQuitting_ = true; }
+#endif
};
} // namespace js