Issue #2240 - Align Microtasks and promises scheduling with spec

Microtasks, resolved Promises and Observers are handled after the sync
task that caused them, in the order they were generated.
Also simplifies reentrancy handling.

Based-on: m-c 1193394
This commit is contained in:
Martok 2024-01-05 17:19:42 +01:00 committed by roytam1
commit f059bb0a59
23 changed files with 260 additions and 347 deletions

View file

@ -1007,6 +1007,10 @@ public:
: mWorkerPrivate(aWorkerPrivate)
{
MOZ_ASSERT(aWorkerPrivate);
// Magical number 2. Workers have the base recursion depth 1, and normal
// runnables run at level 2, and we don't want to process microtasks
// at any other level.
SetTargetedMicroTaskRecursionDepth(2);
}
~WorkerJSContext()
@ -1092,26 +1096,14 @@ public:
}
}
virtual void AfterProcessTask(uint32_t aRecursionDepth) override
virtual void DispatchToMicroTask(already_AddRefed<MicroTaskRunnable> aRunnable) override
{
// Only perform the Promise microtask checkpoint on the outermost event
// loop. Don't run it, for example, during sync XHR or importScripts.
if (aRecursionDepth == 2) {
CycleCollectedJSContext::AfterProcessTask(aRecursionDepth);
} else if (aRecursionDepth > 2) {
AutoDisableMicroTaskCheckpoint disableMicroTaskCheckpoint;
CycleCollectedJSContext::AfterProcessTask(aRecursionDepth);
}
}
virtual void DispatchToMicroTask(already_AddRefed<nsIRunnable> aRunnable) override
{
RefPtr<nsIRunnable> runnable(aRunnable);
RefPtr<MicroTaskRunnable> runnable(aRunnable);
MOZ_ASSERT(!NS_IsMainThread());
MOZ_ASSERT(runnable);
std::queue<nsCOMPtr<nsIRunnable>>* microTaskQueue = nullptr;
std::queue<RefPtr<MicroTaskRunnable>>* microTaskQueue = nullptr;
JSContext* cx = GetCurrentThreadJSContext();
NS_ASSERTION(cx, "This should never be null!");
@ -1120,15 +1112,15 @@ public:
NS_ASSERTION(global, "This should never be null!");
// On worker threads, if the current global is the worker global, we use the
// main promise micro task queue. Otherwise, the current global must be
// main micro task queue. Otherwise, the current global must be
// either the debugger global or a debugger sandbox, and we use the debugger
// promise micro task queue instead.
// micro task queue instead.
if (IsWorkerGlobal(global)) {
microTaskQueue = &mPromiseMicroTaskQueue;
microTaskQueue = &GetMicroTaskQueue();
} else {
MOZ_ASSERT(IsDebuggerGlobal(global) || IsDebuggerSandbox(global));
microTaskQueue = &mDebuggerPromiseMicroTaskQueue;
microTaskQueue = &GetDebuggerMicroTaskQueue();
}
microTaskQueue->push(runnable.forget());