tor-browser

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

commit 52e447e5854d0298d1a9545e1e4941ff2df33beb
parent 4c47a4eb09689eb87cb1d2fd327cdbe781f73266
Author: Cristina Horotan <chorotan@mozilla.com>
Date:   Sat, 13 Dec 2025 01:08:37 +0200

Revert "Bug 1988289 - Don't terminate worker when there are pending JS async tasks. r=iain,asuth,dom-worker-reviewers,smaug,edenchuang" for causing SM failures

This reverts commit 54d5bd08f37314363b2b6de2fec6ac389b8bc2ce.

Diffstat:
Mdom/base/nsJSEnvironment.cpp | 5++---
Mdom/workers/RuntimeService.cpp | 30++++++------------------------
Mdom/workers/WorkerPrivate.cpp | 27---------------------------
Mdom/workers/WorkerPrivate.h | 9+--------
Mdom/worklet/WorkletThread.cpp | 6+++---
Mjs/public/Promise.h | 116+++++++++++--------------------------------------------------------------------
Mjs/src/jsapi.cpp | 17+++++------------
Mjs/src/vm/OffThreadPromiseRuntimeState.cpp | 127+++++++++++++++++++++----------------------------------------------------------
Mjs/src/vm/OffThreadPromiseRuntimeState.h | 16+++-------------
9 files changed, 69 insertions(+), 284 deletions(-)

diff --git a/dom/base/nsJSEnvironment.cpp b/dom/base/nsJSEnvironment.cpp @@ -1806,9 +1806,8 @@ void nsJSContext::EnsureStatics() { JS::SetCreateGCSliceBudgetCallback(jsapi.cx(), CreateGCSliceBudget); - JS::InitAsyncTaskCallbacks(jsapi.cx(), DispatchToEventLoop, - DelayedDispatchToEventLoop, nullptr, nullptr, - nullptr); + JS::InitDispatchsToEventLoop(jsapi.cx(), DispatchToEventLoop, + DelayedDispatchToEventLoop, nullptr); JS::InitConsumeStreamCallback(jsapi.cx(), ConsumeStream, FetchUtil::ReportJSStreamError); diff --git a/dom/workers/RuntimeService.cpp b/dom/workers/RuntimeService.cpp @@ -345,11 +345,9 @@ void LoadJSGCMemoryOptions(const char* aPrefName, void* /* aClosure */) { JSGCParamKey key; }; -#define PREF(suffix_, key_) \ - { \ - nsLiteralCString(suffix_), \ - PREF_JS_OPTIONS_PREFIX PREF_MEM_OPTIONS_PREFIX suffix_, key_ \ - } +#define PREF(suffix_, key_) \ + {nsLiteralCString(suffix_), \ + PREF_JS_OPTIONS_PREFIX PREF_MEM_OPTIONS_PREFIX suffix_, key_} constexpr WorkerGCPref kWorkerPrefs[] = { PREF("max", JSGC_MAX_BYTES), PREF("gc_high_frequency_time_limit_ms", JSGC_HIGH_FREQUENCY_TIME_LIMIT), @@ -727,22 +725,6 @@ static bool DelayedDispatchToEventLoop( return true; } -static void AsyncTaskStarted(void* aClosure, JS::Dispatchable* aDispatchable) { - // See comment at JS::InitDispatchsToEventLoop() below for how we know the - // WorkerPrivate is alive. - WorkerPrivate* workerPrivate = reinterpret_cast<WorkerPrivate*>(aClosure); - workerPrivate->AssertIsOnWorkerThread(); - workerPrivate->JSAsyncTaskStarted(aDispatchable); -} - -static void AsyncTaskFinished(void* aClosure, JS::Dispatchable* aDispatchable) { - // See comment at JS::InitDispatchsToEventLoop() below for how we know the - // WorkerPrivate is alive. - WorkerPrivate* workerPrivate = reinterpret_cast<WorkerPrivate*>(aClosure); - workerPrivate->AssertIsOnWorkerThread(); - workerPrivate->JSAsyncTaskFinished(aDispatchable); -} - static bool ConsumeStream(JSContext* aCx, JS::Handle<JSObject*> aObj, JS::MimeType aMimeType, JS::StreamConsumer* aConsumer) { @@ -784,9 +766,9 @@ bool InitJSContextForWorker(WorkerPrivate* aWorkerPrivate, // A WorkerPrivate lives strictly longer than its JSRuntime so we can safely // store a raw pointer as the callback's closure argument on the JSRuntime. - JS::InitAsyncTaskCallbacks(aWorkerCx, DispatchToEventLoop, - DelayedDispatchToEventLoop, AsyncTaskStarted, - AsyncTaskFinished, (void*)aWorkerPrivate); + JS::InitDispatchsToEventLoop(aWorkerCx, DispatchToEventLoop, + DelayedDispatchToEventLoop, + (void*)aWorkerPrivate); JS::InitConsumeStreamCallback(aWorkerCx, ConsumeStream, FetchUtil::ReportJSStreamError); diff --git a/dom/workers/WorkerPrivate.cpp b/dom/workers/WorkerPrivate.cpp @@ -2999,7 +2999,6 @@ WorkerPrivate::WorkerPrivate( WorkerPrivate::~WorkerPrivate() { MOZ_DIAGNOSTIC_ASSERT(mTopLevelWorkerFinishedRunnableCount == 0); MOZ_DIAGNOSTIC_ASSERT(mWorkerFinishedRunnableCount == 0); - MOZ_DIAGNOSTIC_ASSERT(mPendingJSAsyncTasks.empty()); mWorkerDebuggerEventTarget->ForgetWorkerPrivate(this); @@ -5041,19 +5040,6 @@ nsresult WorkerPrivate::UnregisterShutdownTask(nsITargetShutdownTask* aTask) { return mShutdownTasks.RemoveTask(aTask); } -void WorkerPrivate::JSAsyncTaskStarted(JS::Dispatchable* aDispatchable) { - RefPtr<StrongWorkerRef> ref = StrongWorkerRef::Create(this, "JSAsyncTask"); - MOZ_ASSERT_DEBUG_OR_FUZZING(ref); - if (NS_WARN_IF(!ref)) { - return; - } - MOZ_ALWAYS_TRUE(mPendingJSAsyncTasks.putNew(aDispatchable, std::move(ref))); -} - -void WorkerPrivate::JSAsyncTaskFinished(JS::Dispatchable* aDispatchable) { - mPendingJSAsyncTasks.remove(aDispatchable); -} - void WorkerPrivate::RunShutdownTasks() { TargetShutdownTaskSet::TasksArray shutdownTasks; @@ -5810,19 +5796,6 @@ bool WorkerPrivate::NotifyInternal(WorkerStatus aStatus) { if (aStatus >= Closing) { CancelAllTimeouts(); - - JSContext* cx = GetJSContext(); - if (cx) { - // This will invoke the JS async task finished callback for cancellable - // JS tasks, which will invoke JSAsyncTaskFinished and remove from - // mPendingJSAsyncTasks. - // - // There may still be outstanding JS tasks for things that couldn't be - // cancelled. These must either finish normally, or be blocked on - // through a call to JS::ShutdownAsyncTasks. Cycle collector shutdown - // will call this during worker shutdown. - JS::CancelAsyncTasks(cx); - } } if (aStatus == Closing && GlobalScope()) { diff --git a/dom/workers/WorkerPrivate.h b/dom/workers/WorkerPrivate.h @@ -61,8 +61,7 @@ class nsIThreadInternal; namespace JS { struct RuntimeStats; -class Dispatchable; -} // namespace JS +} namespace mozilla { class ThrottledEventQueue; @@ -1209,9 +1208,6 @@ class WorkerPrivate final void IncreaseWorkerFinishedRunnableCount() { ++mWorkerFinishedRunnableCount; } void DecreaseWorkerFinishedRunnableCount() { --mWorkerFinishedRunnableCount; } - void JSAsyncTaskStarted(JS::Dispatchable* aDispatchable); - void JSAsyncTaskFinished(JS::Dispatchable* aDispatchable); - void RunShutdownTasks(); bool CancelBeforeWorkerScopeConstructed() const { @@ -1719,9 +1715,6 @@ class WorkerPrivate final Atomic<uint32_t> mTopLevelWorkerFinishedRunnableCount; Atomic<uint32_t> mWorkerFinishedRunnableCount; - // A set of active JS async tasks that should prevent idle shutdown. - HashMap<JS::Dispatchable*, RefPtr<StrongWorkerRef>> mPendingJSAsyncTasks; - TargetShutdownTaskSet mShutdownTasks MOZ_GUARDED_BY(mMutex); bool mShutdownTasksRun MOZ_GUARDED_BY(mMutex) = false; diff --git a/dom/worklet/WorkletThread.cpp b/dom/worklet/WorkletThread.cpp @@ -387,9 +387,9 @@ void WorkletThread::EnsureCycleCollectedJSContext( // A thread lives strictly longer than its JSRuntime so we can safely // store a raw pointer as the callback's closure argument on the JSRuntime. - JS::InitAsyncTaskCallbacks(context->Context(), DispatchToEventLoop, - DelayedDispatchToEventLoop, nullptr, nullptr, - NS_GetCurrentThread()); + JS::InitDispatchsToEventLoop(context->Context(), DispatchToEventLoop, + DelayedDispatchToEventLoop, + NS_GetCurrentThread()); JS_SetNativeStackQuota(context->Context(), WORKLET_CONTEXT_NATIVE_STACK_LIMIT); diff --git a/js/public/Promise.h b/js/public/Promise.h @@ -664,7 +664,7 @@ class JS_PUBLIC_API Dispatchable { }; /** - * Callback to dispatch a JS::Dispatchable to a JSContext's thread's event + * Callbacks to dispatch a JS::Dispatchable to a JSContext's thread's event * loop. * * The DispatchToEventLoopCallback set on a particular JSContext must accept @@ -680,9 +680,6 @@ class JS_PUBLIC_API Dispatchable { * If a timeout manager is not available for given context, it should return * false, optionally with a warning message printed. * - * The callback accepts a closure that is the same as the one given by the call - * to JS::InitAsyncTaskCallbacks. - * * If the callback returns `true`, it must eventually run the given * Dispatchable; otherwise, SpiderMonkey may leak memory or hang. * @@ -690,113 +687,30 @@ class JS_PUBLIC_API Dispatchable { * shutting down and is no longer accepting runnables. Shutting down is a * one-way transition: once the callback has rejected a runnable, it must reject * all subsequently submitted runnables as well. + * + * To establish a DispatchToEventLoopCallback, the embedding may either call + * InitDispatchsToEventLoop to provide its own, or call js::UseInternalJobQueues + * to select a default implementation built into SpiderMonkey. This latter + * depends on the embedding to call js::RunJobs on the JavaScript thread to + * process queued Dispatchables at appropriate times. */ typedef bool (*DispatchToEventLoopCallback)( void* closure, js::UniquePtr<Dispatchable>&& dispatchable); -/** - * Callback to dispatch a JS::Dispatchable to a JSContext's thread's event - * loop with a delay. - * - * The DelayedDispatchToEventLoopCallback set on a particular JSContext must - * accept JS::Dispatchable instances and arrange for their `run` methods to be - * called after the given delay on the JSContext's thread. This is used for - * cross-thread dispatch, so the callback itself must be safe to call from any - * thread. It cannot trigger a GC. - * - * The embeddings must have its own timeout manager to handle the delay. - * If a timeout manager is not available for given context, it should return - * false, optionally with a warning message printed. - * - * The callback accepts a closure that is the same as the one given by the call - * to JS::InitAsyncTaskCallbacks. - * - * If the callback returns `true`, it must eventually run the given - * Dispatchable; otherwise, SpiderMonkey may leak memory or hang. - * - * The callback may return `false` to indicate that the JSContext's thread is - * shutting down and is no longer accepting runnables. Shutting down is a - * one-way transition: once the callback has rejected a runnable, it must reject - * all subsequently submitted runnables as well. - */ - typedef bool (*DelayedDispatchToEventLoopCallback)( void* closure, js::UniquePtr<Dispatchable>&& dispatchable, uint32_t delay); -/** - * Callback to notify the embedder that a background task has begun. This can - * be used to keep the JSContext's thread alive if it's subject to garbage - * collection (e.g. as web workers are). - * - * This callback will be called on the same thread as the JSContext, but it - * must not perform any garbage collection or re-enter the engine. - * - * The passed dispatchable can be used to track the async task. Most async - * tasks will finish in a bounded amount of time, but some - * (i.e. Atomics.waitAsync) are not guaranteed to finish. These tasks may be - * canceled using JS::CancelAsyncTasks. - * - * The callback accepts a closure that is the same as the one given by the call - * to JS::InitAsyncTaskCallbacks. - */ -typedef void (*AsyncTaskStartedCallback)(void* closure, - Dispatchable* dispatchable); - -/** - * Callback to notify the embedder that a background task has finished. This can - * be used to keep the JSContext's thread alive if it's subject to garbage - * collection (e.g. as web workers are). - * - * This callback will be called on the same thread as the JSContext, but it - * must not perform any garbage collection or re-enter the engine. - * - * The passed dispatchable will be the same as the one given in - * AsyncTaskStartedCallback. See that callback for more information. - * - * The callback accepts a closure that is the same as the one given by the call - * to JS::InitAsyncTaskCallbacks. - */ -typedef void (*AsyncTaskFinishedCallback)(void* closure, - Dispatchable* dispatchable); - -/** - * Initialize the async task callbacks. Embedders must use this or else call - * js::UseInternalJobQueues to select a default implementation built into - * SpiderMonkey. This latter depends on the embedding to call js::RunJobs on - * the JavaScript thread to process queued Dispatchables at appropriate times. - * - * The dispatchCallback and delayedDispatchCallback are mandatory. - * asyncTaskStartedCallback and asyncTaskFinishedCallback are optional and may - * be null. - * - */ -extern JS_PUBLIC_API void InitAsyncTaskCallbacks( - JSContext* cx, DispatchToEventLoopCallback dispatchCallback, - DelayedDispatchToEventLoopCallback delayedDispatchCallback, - AsyncTaskStartedCallback asyncTaskStartedCallback, - AsyncTaskFinishedCallback asyncTaskFinishedCallback, void* closure); - -/** - * Cancel all cancellable async tasks. Some tasks may not be cancellable, and - * must be waited on through a call to JS::ShutdownAsyncTasks. - * - * This will fire JSAsyncTaskFinished callbacks for cancelled tasks. - */ -extern JS_PUBLIC_API void CancelAsyncTasks(JSContext* cx); +extern JS_PUBLIC_API void InitDispatchsToEventLoop( + JSContext* cx, DispatchToEventLoopCallback callback, + DelayedDispatchToEventLoopCallback delayedCallback, void* closure); /** - * Cancel all cancellable async tasks and block until non-cancellable tasks are - * finished. - * - * This will fire JSAsyncTaskFinished callbacks for all tasks, and there should - * be no outstanding tasks after this returns. All roots held by tasks will be - * released. - * - * Destroying a JSRuntime will implicitly perform this. However, this is not - * soon enough for cycle collection, which needs to have roots dropped earlier - * so that the cycle collector can transitively remove roots for a future GC. - * For these and other cases, the set of pending async tasks can be canceled + * When a JSRuntime is destroyed it implicitly cancels all async tasks in + * progress, releasing any roots held by the task. However, this is not soon + * enough for cycle collection, which needs to have roots dropped earlier so + * that the cycle collector can transitively remove roots for a future GC. For + * these and other cases, the set of pending async tasks can be canceled * with this call earlier than JSRuntime destruction. */ diff --git a/js/src/jsapi.cpp b/js/src/jsapi.cpp @@ -3179,18 +3179,11 @@ JS_PUBLIC_API JSObject* JS::GetWaitForAllPromise( return js::GetWaitForAllPromise(cx, promises); } -JS_PUBLIC_API void JS::InitAsyncTaskCallbacks( - JSContext* cx, JS::DispatchToEventLoopCallback dispatchCallback, - JS::DelayedDispatchToEventLoopCallback delayedDispatchCallback, - JS::AsyncTaskStartedCallback asyncTaskStartedCallback, - JS::AsyncTaskFinishedCallback asyncTaskFinishedCallback, void* closure) { - cx->runtime()->offThreadPromiseState.ref().init( - dispatchCallback, delayedDispatchCallback, asyncTaskStartedCallback, - asyncTaskFinishedCallback, closure); -} - -JS_PUBLIC_API void JS::CancelAsyncTasks(JSContext* cx) { - cx->runtime()->offThreadPromiseState.ref().cancelTasks(cx); +JS_PUBLIC_API void JS::InitDispatchsToEventLoop( + JSContext* cx, JS::DispatchToEventLoopCallback callback, + JS::DelayedDispatchToEventLoopCallback delayCallback, void* closure) { + cx->runtime()->offThreadPromiseState.ref().init(callback, delayCallback, + closure); } JS_PUBLIC_API void JS::ShutdownAsyncTasks(JSContext* cx) { diff --git a/js/src/vm/OffThreadPromiseRuntimeState.cpp b/js/src/vm/OffThreadPromiseRuntimeState.cpp @@ -63,7 +63,8 @@ bool OffThreadPromiseTask::init(JSContext* cx, OffThreadPromiseRuntimeState& state = runtime_->offThreadPromiseState.ref(); MOZ_ASSERT(state.initialized()); - state.registerTask(cx, this); + state.numRegistered_++; + registered_ = true; return true; } @@ -87,20 +88,14 @@ bool OffThreadPromiseTask::InitCancellable( return false; } - if (!state.cancellable().putNew(task.get())) { + OffThreadPromiseTask* rawTask = task.release(); + if (!state.cancellable().putNew(rawTask)) { + state.numRegistered_--; + rawTask->registered_ = false; ReportOutOfMemory(cx); - // The task will be freed and unregistered because it's only owned by this - // function. return false; } - - // We're infallible from this point on. - OffThreadPromiseTask* rawTask = task.release(); - - // Only mark the task as cancellable once we've added it to the cancellable - // set. The destructor will remove from the set if this flag is set. rawTask->cancellable_ = true; - return true; } @@ -111,7 +106,12 @@ void OffThreadPromiseTask::unregister(OffThreadPromiseRuntimeState& state) { void OffThreadPromiseTask::unregister(OffThreadPromiseRuntimeState& state, const AutoLockHelperThreadState& lock) { MOZ_ASSERT(registered_); - state.unregisterTask(this); + if (cancellable_) { + cancellable_ = false; + state.cancellable().remove(this); + } + state.numRegistered_--; + registered_ = false; } void OffThreadPromiseTask::run(JSContext* cx, @@ -229,7 +229,8 @@ void OffThreadPromiseTask::DispatchResolveAndDestroy( { // Hazard analysis can't tell that the callback does not GC. JS::AutoSuppressGCAnalysis nogc; - if (state.dispatchToEventLoop(std::move(task))) { + if (state.dispatchToEventLoopCallback_(state.dispatchToEventLoopClosure_, + std::move(task))) { return; } } @@ -247,8 +248,6 @@ void OffThreadPromiseTask::DispatchResolveAndDestroy( OffThreadPromiseRuntimeState::OffThreadPromiseRuntimeState() : dispatchToEventLoopCallback_(nullptr), delayedDispatchToEventLoopCallback_(nullptr), - asyncTaskStartedCallback_(nullptr), - asyncTaskFinishedCallback_(nullptr), dispatchToEventLoopClosure_(nullptr), #ifdef DEBUG forceQuitting_(false), @@ -265,16 +264,12 @@ OffThreadPromiseRuntimeState::~OffThreadPromiseRuntimeState() { } void OffThreadPromiseRuntimeState::init( - JS::DispatchToEventLoopCallback dispatchCallback, - JS::DelayedDispatchToEventLoopCallback delayedDispatchCallback, - JS::AsyncTaskStartedCallback asyncTaskStartedCallback, - JS::AsyncTaskFinishedCallback asyncTaskFinishedCallback, void* closure) { + JS::DispatchToEventLoopCallback callback, + JS::DelayedDispatchToEventLoopCallback delayedCallback, void* closure) { MOZ_ASSERT(!initialized()); - dispatchToEventLoopCallback_ = dispatchCallback; - delayedDispatchToEventLoopCallback_ = delayedDispatchCallback; - asyncTaskStartedCallback_ = asyncTaskStartedCallback; - asyncTaskFinishedCallback_ = asyncTaskFinishedCallback; + dispatchToEventLoopCallback_ = callback; + delayedDispatchToEventLoopCallback_ = delayedCallback; dispatchToEventLoopClosure_ = closure; MOZ_ASSERT(initialized()); @@ -292,46 +287,6 @@ bool OffThreadPromiseRuntimeState::delayedDispatchToEventLoop( std::move(dispatchable), delay); } -void OffThreadPromiseRuntimeState::registerTask(JSContext* cx, - OffThreadPromiseTask* task) { - // Track the total number of pending async tasks - numRegistered_++; - - // Mark the task as registered - task->registered_ = true; - - if (!asyncTaskStartedCallback_) { - return; - } - - // The embedder must not perform a GC, suppress GC analysis here. - JS::AutoSuppressGCAnalysis nogc(cx); - asyncTaskStartedCallback_(dispatchToEventLoopClosure_, task); -} - -void OffThreadPromiseRuntimeState::unregisterTask(OffThreadPromiseTask* task) { - // Track the total number of pending async tasks - MOZ_ASSERT(numRegistered_ != 0); - numRegistered_--; - - // Mark the task as unregistered - task->registered_ = false; - - // If the task was cancellable, remove from our cancellable set. - if (task->cancellable_) { - task->cancellable_ = false; - cancellable().remove(task); - } - - if (!asyncTaskFinishedCallback_) { - return; - } - - // The embedder must not perform a GC, suppress GC analysis here. - JS::AutoSuppressGCAnalysis nogc; - asyncTaskFinishedCallback_(dispatchToEventLoopClosure_, task); -} - /* static */ bool OffThreadPromiseRuntimeState::internalDispatchToEventLoop( void* closure, js::UniquePtr<JS::Dispatchable>&& d) { @@ -425,8 +380,7 @@ bool OffThreadPromiseRuntimeState::usingInternalDispatchQueue() const { } void OffThreadPromiseRuntimeState::initInternalDispatchQueue() { - init(internalDispatchToEventLoop, internalDelayedDispatchToEventLoop, nullptr, - nullptr, this); + init(internalDispatchToEventLoop, internalDelayedDispatchToEventLoop, this); MOZ_ASSERT(usingInternalDispatchQueue()); } @@ -492,14 +446,14 @@ void OffThreadPromiseRuntimeState::stealFailedTask(JS::Dispatchable* task) { } } -void OffThreadPromiseRuntimeState::cancelTasks( - js::AutoLockHelperThreadState& lock, JSContext* cx) { - MOZ_ASSERT(initialized()); +void OffThreadPromiseRuntimeState::shutdown(JSContext* cx) { if (!initialized()) { return; } - // Cancel all undispatched tasks that are cancellable. + AutoLockHelperThreadState lock; + + // Cancel all undispatched tasks. for (auto iter = cancellable().modIter(); !iter.done(); iter.next()) { OffThreadPromiseTask* task = iter.get(); MOZ_ASSERT(task->cancellable_); @@ -507,26 +461,6 @@ void OffThreadPromiseRuntimeState::cancelTasks( OffThreadPromiseTask::DestroyUndispatchedTask(task, *this, lock); } -} - -void OffThreadPromiseRuntimeState::cancelTasks(JSContext* cx) { - if (!initialized()) { - return; - } - - AutoLockHelperThreadState lock; - cancelTasks(lock, cx); -} - -void OffThreadPromiseRuntimeState::shutdown(JSContext* cx) { - if (!initialized()) { - return; - } - - AutoLockHelperThreadState lock; - - // Cancel all undispatched tasks. - cancelTasks(lock, cx); MOZ_ASSERT(cancellable().empty()); // When the shell is using the internal event loop, we must simulate our @@ -602,11 +536,18 @@ js::PromiseObject* OffThreadPromiseTask::ExtractAndForget( task->runtime()->offThreadPromiseState.ref(); MOZ_ASSERT(state.initialized()); MOZ_ASSERT(task->registered_); + + // TODO: This has overlap with removeFromCancellableListAndDispatch. + // The two methods should be refactored so that they are consistant and + // we don't have unnecessary repetition or distribution of responsibilities. + state.numRegistered_--; + if (task->cancellable_) { + state.cancellable().remove(task); + } + task->registered_ = false; + js::PromiseObject* promise = task->promise_; - // Call the unregister method manually with our provided lock, otherwise the - // destructor will try to acquire it and fail. - task->unregister(state, lock); - // Now we can call the destructor. js_delete(task); + return promise; } diff --git a/js/src/vm/OffThreadPromiseRuntimeState.h b/js/src/vm/OffThreadPromiseRuntimeState.h @@ -257,8 +257,6 @@ class OffThreadPromiseRuntimeState { // not require a lock. JS::DispatchToEventLoopCallback dispatchToEventLoopCallback_; JS::DelayedDispatchToEventLoopCallback delayedDispatchToEventLoopCallback_; - JS::AsyncTaskStartedCallback asyncTaskStartedCallback_; - JS::AsyncTaskFinishedCallback asyncTaskFinishedCallback_; void* dispatchToEventLoopClosure_; #ifdef DEBUG @@ -307,6 +305,7 @@ class OffThreadPromiseRuntimeState { // mean "the DispatchToEventLoopCallback failed after this task was dispatched // for execution". HelperThreadLockData<ConditionVariable> allFailed_; + HelperThreadLockData<size_t> numFailed_; // The queue of JS::Dispatchables used by the DispatchToEventLoopCallback that // calling js::UseInternalJobQueues installs. @@ -342,17 +341,11 @@ class OffThreadPromiseRuntimeState { void operator=(const OffThreadPromiseRuntimeState&) = delete; OffThreadPromiseRuntimeState(const OffThreadPromiseRuntimeState&) = delete; - // Used by OffThreadPromiseTask - void registerTask(JSContext* cx, OffThreadPromiseTask* task); - void unregisterTask(OffThreadPromiseTask* task); - public: OffThreadPromiseRuntimeState(); ~OffThreadPromiseRuntimeState(); - void init(JS::DispatchToEventLoopCallback dispatchCallback, - JS::DelayedDispatchToEventLoopCallback delayedDispatchCallback, - JS::AsyncTaskStartedCallback asyncTaskStartedCallback, - JS::AsyncTaskFinishedCallback asyncTaskFinishedCallback, + void init(JS::DispatchToEventLoopCallback callback, + JS::DelayedDispatchToEventLoopCallback delayCallback, void* closure); void initInternalDispatchQueue(); bool initialized() const; @@ -369,9 +362,6 @@ class OffThreadPromiseRuntimeState { bool delayedDispatchToEventLoop( js::UniquePtr<JS::Dispatchable>&& dispatchable, uint32_t delay); - void cancelTasks(JSContext* cx); - void cancelTasks(AutoLockHelperThreadState& lock, JSContext* cx); - // shutdown() must be called by the JSRuntime while the JSRuntime is valid. void shutdown(JSContext* cx);