commit a7c16b5d07d299e4e5fd3a2894f6e3f4e7e4c09b
parent 269a06ecd851689a6b6e73f46bcd8639868fc692
Author: Matthew Gaudet <mgaudet@mozilla.com>
Date: Wed, 1 Oct 2025 21:38:52 +0000
Bug 1983154 - Select debugger queue where required r=arai,smaug,dom-worker-reviewers,asuth
I don't love having a virtual dispatch on this hot path, but this is required for matching
existing semantics, as revealed by dom/workers/test/test_WorkerDebugger_promise.xhtml
Longer term I'd love to do something else.
Differential Revision: https://phabricator.services.mozilla.com/D264131
Diffstat:
4 files changed, 28 insertions(+), 9 deletions(-)
diff --git a/dom/workers/RuntimeService.cpp b/dom/workers/RuntimeService.cpp
@@ -983,6 +983,12 @@ class WorkerJSContext final : public mozilla::CycleCollectedJSContext {
return NS_OK;
}
+ virtual bool useDebugQueue(JS::Handle<JSObject*> global) const override {
+ MOZ_ASSERT(!NS_IsMainThread());
+
+ return !(IsWorkerGlobal(global) || IsShadowRealmGlobal(global));
+ }
+
virtual void DispatchToMicroTask(
already_AddRefed<MicroTaskRunnable> aRunnable) override {
RefPtr<MicroTaskRunnable> runnable(aRunnable);
diff --git a/js/public/Promise.h b/js/public/Promise.h
@@ -113,6 +113,14 @@ class JS_PUBLIC_API JobQueue {
*/
virtual bool isDrainingStopped() const = 0;
+ /*
+ * When enqueueing a job, should the job be enqueued in the debug queue
+ * rather than the regular queue?
+ */
+ virtual bool useDebugQueue(JS::Handle<JSObject*> global) const {
+ return false;
+ }
+
protected:
friend class AutoDebuggerJobQueueInterruption;
diff --git a/js/src/builtin/Promise.cpp b/js/src/builtin/Promise.cpp
@@ -1677,6 +1677,17 @@ static bool ResolvePromiseFunction(JSContext* cx, unsigned argc, Value* vp) {
return true;
}
+static bool EnqueueJob(JSContext* cx, JS::MicroTask&& job) {
+ MOZ_ASSERT(cx->realm());
+
+ // Only check if we need to use the debug queue when we're not on main thread.
+ if (MOZ_UNLIKELY(!cx->runtime()->isMainRuntime() &&
+ cx->jobQueue->useDebugQueue(cx->global()))) {
+ return cx->microTaskQueues->enqueueDebugMicroTask(cx, std::move(job));
+ }
+ return cx->microTaskQueues->enqueueRegularMicroTask(cx, std::move(job));
+}
+
static bool PromiseReactionJob(JSContext* cx, unsigned argc, Value* vp);
/**
@@ -1902,8 +1913,7 @@ static bool PromiseReactionJob(JSContext* cx, unsigned argc, Value* vp);
}
// HostEnqueuePromiseJob(job.[[Job]], job.[[Realm]]).
- return cx->microTaskQueues->enqueueRegularMicroTask(
- cx, std::move(reactionVal.get()));
+ return EnqueueJob(cx, std::move(reactionVal.get()));
}
RootedField<JSObject*, 7> hostDefinedData(roots);
@@ -2920,8 +2930,7 @@ static bool PromiseResolveBuiltinThenableJob(JSContext* cx, unsigned argc,
thenableJob->setHostDefinedGlobalRepresentative(
hostDefinedGlobalRepresentative);
- return cx->microTaskQueues->enqueueRegularMicroTask(
- cx, ObjectValue(*thenableJob));
+ return EnqueueJob(cx, ObjectValue(*thenableJob));
}
// Step 1. Let job be a new Job Abstract Closure with no parameters that
@@ -2981,8 +2990,7 @@ static bool PromiseResolveBuiltinThenableJob(JSContext* cx, unsigned argc,
return false;
}
- return cx->microTaskQueues->enqueueRegularMicroTask(
- cx, ObjectValue(*thenableJob));
+ return EnqueueJob(cx, ObjectValue(*thenableJob));
}
// Step 1. Let job be a new Job Abstract Closure with no parameters that
diff --git a/xpcom/base/CycleCollectedJSContext.cpp b/xpcom/base/CycleCollectedJSContext.cpp
@@ -1284,10 +1284,7 @@ void CycleCollectedJSContext::PerformDebuggerMicroTaskCheckpoint() {
// this method is supposed to know what they are doing.
JSContext* cx = Context();
-
if (StaticPrefs::javascript_options_use_js_microtask_queue()) {
- MOZ_ASSERT(GetDebuggerMicroTaskQueue().empty());
-
while (JS::HasDebuggerMicroTasks(cx)) {
MOZ_ASSERT(mDebuggerMicroTaskQueue.empty());
MOZ_ASSERT(mPendingMicroTaskRunnables.empty());