tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

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:
Mdom/workers/RuntimeService.cpp | 6++++++
Mjs/public/Promise.h | 8++++++++
Mjs/src/builtin/Promise.cpp | 20++++++++++++++------
Mxpcom/base/CycleCollectedJSContext.cpp | 3---
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());