mirror of
https://repo.dactyloidae.xyz/Dactyloidae/UXP.git
synced 2026-08-15 08:53:07 +09:00
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:
parent
73b14eae31
commit
f059bb0a59
23 changed files with 260 additions and 347 deletions
|
|
@ -437,7 +437,7 @@ CycleCollectedJSContext::CycleCollectedJSContext()
|
|||
, mPrevGCNurseryCollectionCallback(nullptr)
|
||||
, mJSHolders(256)
|
||||
, mDoingStableStates(false)
|
||||
, mDisableMicroTaskCheckpoint(false)
|
||||
, mTargetedMicroTaskRecursionDepth(0)
|
||||
, mMicroTaskLevel(0)
|
||||
, mMicroTaskRecursionDepth(0)
|
||||
, mOutOfMemoryState(OOMState::OK)
|
||||
|
|
@ -458,8 +458,8 @@ CycleCollectedJSContext::~CycleCollectedJSContext()
|
|||
MOZ_ASSERT(!mDeferredFinalizerTable.Count());
|
||||
|
||||
// Last chance to process any events.
|
||||
ProcessMetastableStateQueue(mBaseRecursionDepth);
|
||||
MOZ_ASSERT(mMetastableStateEvents.IsEmpty());
|
||||
CleanupIDBTransactions(mBaseRecursionDepth);
|
||||
MOZ_ASSERT(mPendingIDBTransactions.IsEmpty());
|
||||
|
||||
ProcessStableStateQueue();
|
||||
MOZ_ASSERT(mStableStateEvents.IsEmpty());
|
||||
|
|
@ -467,8 +467,8 @@ CycleCollectedJSContext::~CycleCollectedJSContext()
|
|||
// Clear mPendingException first, since it might be cycle collected.
|
||||
mPendingException = nullptr;
|
||||
|
||||
MOZ_ASSERT(mDebuggerPromiseMicroTaskQueue.empty());
|
||||
MOZ_ASSERT(mPromiseMicroTaskQueue.empty());
|
||||
MOZ_ASSERT(mDebuggerMicroTaskQueue.empty());
|
||||
MOZ_ASSERT(mPendingMicroTaskRunnables.empty());
|
||||
|
||||
mUncaughtRejections.reset();
|
||||
mConsumedRejections.reset();
|
||||
|
|
@ -921,7 +921,7 @@ CycleCollectedJSContext::LargeAllocationFailureCallback(void* aData)
|
|||
self->OnLargeAllocationFailure();
|
||||
}
|
||||
|
||||
class PromiseJobRunnable final : public Runnable
|
||||
class PromiseJobRunnable final : public MicroTaskRunnable
|
||||
{
|
||||
public:
|
||||
PromiseJobRunnable(JS::HandleObject aCallback, JS::HandleObject aAllocationSite,
|
||||
|
|
@ -935,14 +935,20 @@ public:
|
|||
}
|
||||
|
||||
protected:
|
||||
NS_IMETHOD
|
||||
Run() override
|
||||
virtual void Run(AutoSlowOperation& aAso) override
|
||||
{
|
||||
nsIGlobalObject* global = xpc::NativeGlobal(mCallback->CallbackPreserveColor());
|
||||
if (global && !global->IsDying()) {
|
||||
mCallback->Call("promise callback");
|
||||
aAso.CheckForInterrupt();
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
virtual bool Suppressed() override
|
||||
{
|
||||
nsIGlobalObject* global =
|
||||
xpc::NativeGlobal(mCallback->CallbackPreserveColor());
|
||||
return global && global->IsInSyncOperation();
|
||||
}
|
||||
|
||||
private:
|
||||
|
|
@ -976,7 +982,7 @@ CycleCollectedJSContext::EnqueuePromiseJobCallback(JSContext* aCx,
|
|||
if (aIncumbentGlobal) {
|
||||
global = xpc::NativeGlobal(aIncumbentGlobal);
|
||||
}
|
||||
nsCOMPtr<nsIRunnable> runnable = new PromiseJobRunnable(aJob, aAllocationSite, global);
|
||||
RefPtr<MicroTaskRunnable> runnable = new PromiseJobRunnable(aJob, aAllocationSite, global);
|
||||
self->DispatchToMicroTask(runnable.forget());
|
||||
return true;
|
||||
}
|
||||
|
|
@ -1175,18 +1181,18 @@ CycleCollectedJSContext::SetPendingException(nsIException* aException)
|
|||
mPendingException = aException;
|
||||
}
|
||||
|
||||
std::queue<nsCOMPtr<nsIRunnable>>&
|
||||
CycleCollectedJSContext::GetPromiseMicroTaskQueue()
|
||||
std::queue<RefPtr<MicroTaskRunnable>>&
|
||||
CycleCollectedJSContext::GetMicroTaskQueue()
|
||||
{
|
||||
MOZ_ASSERT(mJSContext);
|
||||
return mPromiseMicroTaskQueue;
|
||||
return mPendingMicroTaskRunnables;
|
||||
}
|
||||
|
||||
std::queue<nsCOMPtr<nsIRunnable>>&
|
||||
CycleCollectedJSContext::GetDebuggerPromiseMicroTaskQueue()
|
||||
std::queue<RefPtr<MicroTaskRunnable>>&
|
||||
CycleCollectedJSContext::GetDebuggerMicroTaskQueue()
|
||||
{
|
||||
MOZ_ASSERT(mJSContext);
|
||||
return mDebuggerPromiseMicroTaskQueue;
|
||||
return mDebuggerMicroTaskQueue;
|
||||
}
|
||||
|
||||
nsCycleCollectionParticipant*
|
||||
|
|
@ -1345,24 +1351,24 @@ CycleCollectedJSContext::ProcessStableStateQueue()
|
|||
}
|
||||
|
||||
void
|
||||
CycleCollectedJSContext::ProcessMetastableStateQueue(uint32_t aRecursionDepth)
|
||||
CycleCollectedJSContext::CleanupIDBTransactions(uint32_t aRecursionDepth)
|
||||
{
|
||||
MOZ_ASSERT(mJSContext);
|
||||
MOZ_RELEASE_ASSERT(!mDoingStableStates);
|
||||
mDoingStableStates = true;
|
||||
|
||||
nsTArray<RunInMetastableStateData> localQueue = Move(mMetastableStateEvents);
|
||||
nsTArray<PendingIDBTransactionData> localQueue = Move(mPendingIDBTransactions);
|
||||
|
||||
for (uint32_t i = 0; i < localQueue.Length(); ++i)
|
||||
{
|
||||
RunInMetastableStateData& data = localQueue[i];
|
||||
PendingIDBTransactionData& data = localQueue[i];
|
||||
if (data.mRecursionDepth != aRecursionDepth) {
|
||||
continue;
|
||||
}
|
||||
|
||||
{
|
||||
nsCOMPtr<nsIRunnable> runnable = data.mRunnable.forget();
|
||||
runnable->Run();
|
||||
nsCOMPtr<nsIRunnable> transaction = data.mTransaction.forget();
|
||||
transaction->Run();
|
||||
}
|
||||
|
||||
localQueue.RemoveElementAt(i--);
|
||||
|
|
@ -1370,11 +1376,27 @@ CycleCollectedJSContext::ProcessMetastableStateQueue(uint32_t aRecursionDepth)
|
|||
|
||||
// If the queue has events in it now, they were added from something we called,
|
||||
// so they belong at the end of the queue.
|
||||
localQueue.AppendElements(mMetastableStateEvents);
|
||||
localQueue.SwapElements(mMetastableStateEvents);
|
||||
localQueue.AppendElements(mPendingIDBTransactions);
|
||||
localQueue.SwapElements(mPendingIDBTransactions);
|
||||
mDoingStableStates = false;
|
||||
}
|
||||
|
||||
void
|
||||
CycleCollectedJSContext::BeforeProcessTask(bool aMightBlock)
|
||||
{
|
||||
// If ProcessNextEvent was called during a microtask callback, we
|
||||
// must process any pending microtasks before blocking in the event loop,
|
||||
// otherwise we may deadlock until an event enters the queue later.
|
||||
if (aMightBlock && PerformMicroTaskCheckPoint()) {
|
||||
// If any microtask was processed, we post a dummy event in order to
|
||||
// force the ProcessNextEvent call not to block. This is required
|
||||
// to support nested event loops implemented using a pattern like
|
||||
// "while (condition) thread.processNextEvent(true)", in case the
|
||||
// condition is triggered here by a Promise "then" callback.
|
||||
NS_DispatchToMainThread(new Runnable());
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
CycleCollectedJSContext::AfterProcessTask(uint32_t aRecursionDepth)
|
||||
{
|
||||
|
|
@ -1382,39 +1404,20 @@ CycleCollectedJSContext::AfterProcessTask(uint32_t aRecursionDepth)
|
|||
|
||||
// See HTML 6.1.4.2 Processing model
|
||||
|
||||
// Execute any events that were waiting for a microtask to complete.
|
||||
// This is not (yet) in the spec.
|
||||
ProcessMetastableStateQueue(aRecursionDepth);
|
||||
|
||||
// Step 4.1: Execute microtasks.
|
||||
if (!mDisableMicroTaskCheckpoint) {
|
||||
PerformMicroTaskCheckPoint();
|
||||
if (NS_IsMainThread()) {
|
||||
Promise::PerformMicroTaskCheckpoint();
|
||||
} else {
|
||||
Promise::PerformWorkerMicroTaskCheckpoint();
|
||||
}
|
||||
}
|
||||
PerformMicroTaskCheckPoint();
|
||||
|
||||
// Step 4.2 Execute any events that were waiting for a stable state.
|
||||
ProcessStableStateQueue();
|
||||
}
|
||||
|
||||
void
|
||||
CycleCollectedJSContext::AfterProcessMicrotask()
|
||||
CycleCollectedJSContext::AfterProcessMicrotasks()
|
||||
{
|
||||
MOZ_ASSERT(mJSContext);
|
||||
AfterProcessMicrotask(RecursionDepth());
|
||||
}
|
||||
|
||||
void
|
||||
CycleCollectedJSContext::AfterProcessMicrotask(uint32_t aRecursionDepth)
|
||||
{
|
||||
MOZ_ASSERT(mJSContext);
|
||||
|
||||
// Between microtasks, execute any events that were waiting for a microtask
|
||||
// to complete.
|
||||
ProcessMetastableStateQueue(aRecursionDepth);
|
||||
// Cleanup Indexed Database transactions:
|
||||
// https://html.spec.whatwg.org/multipage/webappapis.html#perform-a-microtask-checkpoint
|
||||
CleanupIDBTransactions(RecursionDepth());
|
||||
}
|
||||
|
||||
uint32_t
|
||||
|
|
@ -1431,12 +1434,12 @@ CycleCollectedJSContext::RunInStableState(already_AddRefed<nsIRunnable>&& aRunna
|
|||
}
|
||||
|
||||
void
|
||||
CycleCollectedJSContext::RunInMetastableState(already_AddRefed<nsIRunnable>&& aRunnable)
|
||||
CycleCollectedJSContext::AddPendingIDBTransaction(already_AddRefed<nsIRunnable>&& aTransaction)
|
||||
{
|
||||
MOZ_ASSERT(mJSContext);
|
||||
|
||||
RunInMetastableStateData data;
|
||||
data.mRunnable = aRunnable;
|
||||
PendingIDBTransactionData data;
|
||||
data.mTransaction = aTransaction;
|
||||
|
||||
MOZ_ASSERT(mOwningThread);
|
||||
data.mRecursionDepth = RecursionDepth();
|
||||
|
|
@ -1453,7 +1456,7 @@ CycleCollectedJSContext::RunInMetastableState(already_AddRefed<nsIRunnable>&& aR
|
|||
}
|
||||
#endif
|
||||
|
||||
mMetastableStateEvents.AppendElement(Move(data));
|
||||
mPendingIDBTransactions.AppendElement(Move(data));
|
||||
}
|
||||
|
||||
IncrementalFinalizeRunnable::IncrementalFinalizeRunnable(CycleCollectedJSContext* aCx,
|
||||
|
|
@ -1659,14 +1662,14 @@ CycleCollectedJSContext::PrepareWaitingZonesForGC()
|
|||
}
|
||||
|
||||
void
|
||||
CycleCollectedJSContext::DispatchToMicroTask(already_AddRefed<nsIRunnable> aRunnable)
|
||||
CycleCollectedJSContext::DispatchToMicroTask(already_AddRefed<MicroTaskRunnable> aRunnable)
|
||||
{
|
||||
RefPtr<nsIRunnable> runnable(aRunnable);
|
||||
RefPtr<MicroTaskRunnable> runnable(aRunnable);
|
||||
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
MOZ_ASSERT(runnable);
|
||||
|
||||
mPromiseMicroTaskQueue.push(runnable.forget());
|
||||
mPendingMicroTaskRunnables.push(runnable.forget());
|
||||
}
|
||||
|
||||
class AsyncMutationHandler final : public mozilla::Runnable
|
||||
|
|
@ -1682,41 +1685,61 @@ public:
|
|||
}
|
||||
};
|
||||
|
||||
void
|
||||
bool
|
||||
CycleCollectedJSContext::PerformMicroTaskCheckPoint()
|
||||
{
|
||||
if (mPendingMicroTaskRunnables.empty()) {
|
||||
if (mPendingMicroTaskRunnables.empty() && mDebuggerMicroTaskQueue.empty()) {
|
||||
AfterProcessMicrotasks();
|
||||
// Nothing to do, return early.
|
||||
return;
|
||||
return false;
|
||||
}
|
||||
|
||||
uint32_t currentDepth = RecursionDepth();
|
||||
if (mMicroTaskRecursionDepth >= currentDepth) {
|
||||
// We are already executing microtasks for the current recursion depth.
|
||||
return;
|
||||
return false;
|
||||
}
|
||||
|
||||
if (mTargetedMicroTaskRecursionDepth != 0 &&
|
||||
mTargetedMicroTaskRecursionDepth != currentDepth) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (NS_IsMainThread() && !nsContentUtils::IsSafeToRunScript()) {
|
||||
// Special case for main thread where DOM mutations may happen when
|
||||
// it is not safe to run scripts.
|
||||
nsContentUtils::AddScriptRunner(new AsyncMutationHandler());
|
||||
return;
|
||||
return false;
|
||||
}
|
||||
|
||||
mozilla::AutoRestore<uint32_t> restore(mMicroTaskRecursionDepth);
|
||||
MOZ_ASSERT(currentDepth > 0);
|
||||
mMicroTaskRecursionDepth = currentDepth;
|
||||
|
||||
bool didProcess = false;
|
||||
AutoSlowOperation aso;
|
||||
|
||||
std::queue<RefPtr<MicroTaskRunnable>> suppressed;
|
||||
while (!mPendingMicroTaskRunnables.empty()) {
|
||||
RefPtr<MicroTaskRunnable> runnable =
|
||||
mPendingMicroTaskRunnables.front().forget();
|
||||
mPendingMicroTaskRunnables.pop();
|
||||
for (;;) {
|
||||
RefPtr<MicroTaskRunnable> runnable;
|
||||
if (!mDebuggerMicroTaskQueue.empty()) {
|
||||
runnable = mDebuggerMicroTaskQueue.front().forget();
|
||||
mDebuggerMicroTaskQueue.pop();
|
||||
} else if (!mPendingMicroTaskRunnables.empty()) {
|
||||
runnable = mPendingMicroTaskRunnables.front().forget();
|
||||
mPendingMicroTaskRunnables.pop();
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
|
||||
if (runnable->Suppressed()) {
|
||||
// Microtasks in worker shall never be suppressed.
|
||||
// Otherwise, mPendingMicroTaskRunnables will be replaced later with
|
||||
// all suppressed tasks in mDebuggerMicroTaskQueue unexpectedly.
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
suppressed.push(runnable);
|
||||
} else {
|
||||
didProcess = true;
|
||||
runnable->Run(aso);
|
||||
}
|
||||
}
|
||||
|
|
@ -1726,13 +1749,38 @@ CycleCollectedJSContext::PerformMicroTaskCheckPoint()
|
|||
// for some time, but no longer than spinning the event loop nestedly
|
||||
// (sync XHR, alert, etc.)
|
||||
mPendingMicroTaskRunnables.swap(suppressed);
|
||||
|
||||
AfterProcessMicrotasks();
|
||||
|
||||
return didProcess;
|
||||
}
|
||||
|
||||
void
|
||||
CycleCollectedJSContext::DispatchMicroTaskRunnable(
|
||||
already_AddRefed<MicroTaskRunnable> aRunnable)
|
||||
{
|
||||
mPendingMicroTaskRunnables.push(aRunnable);
|
||||
CycleCollectedJSContext::PerformDebuggerMicroTaskCheckpoint()
|
||||
{
|
||||
// Don't do normal microtask handling checks here, since whoever is calling
|
||||
// this method is supposed to know what they are doing.
|
||||
|
||||
AutoSlowOperation aso;
|
||||
for (;;) {
|
||||
// For a debugger microtask checkpoint, we always use the debugger microtask
|
||||
// queue.
|
||||
std::queue<RefPtr<MicroTaskRunnable>>* microtaskQueue =
|
||||
&GetDebuggerMicroTaskQueue();
|
||||
|
||||
if (microtaskQueue->empty()) {
|
||||
break;
|
||||
}
|
||||
|
||||
RefPtr<MicroTaskRunnable> runnable = microtaskQueue->front().forget();
|
||||
MOZ_ASSERT(runnable);
|
||||
|
||||
// This function can re-enter, so we remove the element before calling.
|
||||
microtaskQueue->pop();
|
||||
runnable->Run(aso);
|
||||
}
|
||||
|
||||
AfterProcessMicrotasks();
|
||||
}
|
||||
|
||||
void
|
||||
|
|
|
|||
|
|
@ -170,9 +170,6 @@ protected:
|
|||
virtual void CustomOutOfMemoryCallback() {}
|
||||
virtual void CustomLargeAllocationFailureCallback() {}
|
||||
|
||||
std::queue<nsCOMPtr<nsIRunnable>> mPromiseMicroTaskQueue;
|
||||
std::queue<nsCOMPtr<nsIRunnable>> mDebuggerPromiseMicroTaskQueue;
|
||||
|
||||
private:
|
||||
void
|
||||
DescribeGCThing(bool aIsMarked, JS::GCCellPtr aThing,
|
||||
|
|
@ -243,11 +240,11 @@ private:
|
|||
virtual void TraceNativeBlackRoots(JSTracer* aTracer) { };
|
||||
void TraceNativeGrayRoots(JSTracer* aTracer);
|
||||
|
||||
void AfterProcessMicrotask(uint32_t aRecursionDepth);
|
||||
void AfterProcessMicrotasks();
|
||||
public:
|
||||
void ProcessStableStateQueue();
|
||||
private:
|
||||
void ProcessMetastableStateQueue(uint32_t aRecursionDepth);
|
||||
void CleanupIDBTransactions(uint32_t aRecursionDepth);
|
||||
|
||||
public:
|
||||
enum DeferredFinalizeType {
|
||||
|
|
@ -306,8 +303,8 @@ public:
|
|||
already_AddRefed<nsIException> GetPendingException() const;
|
||||
void SetPendingException(nsIException* aException);
|
||||
|
||||
std::queue<nsCOMPtr<nsIRunnable>>& GetPromiseMicroTaskQueue();
|
||||
std::queue<nsCOMPtr<nsIRunnable>>& GetDebuggerPromiseMicroTaskQueue();
|
||||
std::queue<RefPtr<MicroTaskRunnable>>& GetMicroTaskQueue();
|
||||
std::queue<RefPtr<MicroTaskRunnable>>& GetDebuggerMicroTaskQueue();
|
||||
|
||||
nsCycleCollectionParticipant* GCThingParticipant();
|
||||
nsCycleCollectionParticipant* ZoneParticipant();
|
||||
|
|
@ -346,53 +343,25 @@ public:
|
|||
return JS::RootingContext::get(mJSContext);
|
||||
}
|
||||
|
||||
bool MicroTaskCheckpointDisabled() const
|
||||
void SetTargetedMicroTaskRecursionDepth(uint32_t aDepth)
|
||||
{
|
||||
return mDisableMicroTaskCheckpoint;
|
||||
mTargetedMicroTaskRecursionDepth = aDepth;
|
||||
}
|
||||
|
||||
void DisableMicroTaskCheckpoint(bool aDisable)
|
||||
{
|
||||
mDisableMicroTaskCheckpoint = aDisable;
|
||||
}
|
||||
|
||||
class MOZ_RAII AutoDisableMicroTaskCheckpoint
|
||||
{
|
||||
public:
|
||||
AutoDisableMicroTaskCheckpoint()
|
||||
: mCCJSCX(CycleCollectedJSContext::Get())
|
||||
{
|
||||
mOldValue = mCCJSCX->MicroTaskCheckpointDisabled();
|
||||
mCCJSCX->DisableMicroTaskCheckpoint(true);
|
||||
}
|
||||
|
||||
~AutoDisableMicroTaskCheckpoint()
|
||||
{
|
||||
mCCJSCX->DisableMicroTaskCheckpoint(mOldValue);
|
||||
}
|
||||
|
||||
CycleCollectedJSContext* mCCJSCX;
|
||||
bool mOldValue;
|
||||
};
|
||||
|
||||
protected:
|
||||
JSContext* MaybeContext() const { return mJSContext; }
|
||||
|
||||
public:
|
||||
// nsThread entrypoints
|
||||
virtual void BeforeProcessTask(bool aMightBlock) { };
|
||||
virtual void BeforeProcessTask(bool aMightBlock);
|
||||
virtual void AfterProcessTask(uint32_t aRecursionDepth);
|
||||
|
||||
// microtask processor entry point
|
||||
void AfterProcessMicrotask();
|
||||
|
||||
uint32_t RecursionDepth();
|
||||
|
||||
// Run in stable state (call through nsContentUtils)
|
||||
void RunInStableState(already_AddRefed<nsIRunnable>&& aRunnable);
|
||||
// This isn't in the spec at all yet, but this gets the behavior we want for IDB.
|
||||
// Runs after the current microtask completes.
|
||||
void RunInMetastableState(already_AddRefed<nsIRunnable>&& aRunnable);
|
||||
|
||||
void AddPendingIDBTransaction(already_AddRefed<nsIRunnable>&& aTransaction);
|
||||
|
||||
// Get the current thread's CycleCollectedJSContext. Returns null if there
|
||||
// isn't one.
|
||||
|
|
@ -411,7 +380,7 @@ public:
|
|||
void PrepareWaitingZonesForGC();
|
||||
|
||||
// Queue an async microtask to the current main or worker thread.
|
||||
virtual void DispatchToMicroTask(already_AddRefed<nsIRunnable> aRunnable);
|
||||
virtual void DispatchToMicroTask(already_AddRefed<MicroTaskRunnable> aRunnable);
|
||||
|
||||
// Call EnterMicroTask when you're entering JS execution.
|
||||
// Usually the best way to do this is to use nsAutoMicroTask.
|
||||
|
|
@ -442,9 +411,9 @@ public:
|
|||
mMicroTaskLevel = aLevel;
|
||||
}
|
||||
|
||||
void PerformMicroTaskCheckPoint();
|
||||
bool PerformMicroTaskCheckPoint();
|
||||
|
||||
void DispatchMicroTaskRunnable(already_AddRefed<MicroTaskRunnable> aRunnable);
|
||||
void PerformDebuggerMicroTaskCheckpoint();
|
||||
|
||||
// Storage for watching rejected promises waiting for some client to
|
||||
// consume their rejection.
|
||||
|
|
@ -483,21 +452,25 @@ private:
|
|||
nsCOMPtr<nsIException> mPendingException;
|
||||
nsThread* mOwningThread; // Manual refcounting to avoid include hell.
|
||||
|
||||
struct RunInMetastableStateData
|
||||
struct PendingIDBTransactionData
|
||||
{
|
||||
nsCOMPtr<nsIRunnable> mRunnable;
|
||||
nsCOMPtr<nsIRunnable> mTransaction;
|
||||
uint32_t mRecursionDepth;
|
||||
};
|
||||
|
||||
nsTArray<nsCOMPtr<nsIRunnable>> mStableStateEvents;
|
||||
nsTArray<RunInMetastableStateData> mMetastableStateEvents;
|
||||
nsTArray<PendingIDBTransactionData> mPendingIDBTransactions;
|
||||
uint32_t mBaseRecursionDepth;
|
||||
bool mDoingStableStates;
|
||||
|
||||
bool mDisableMicroTaskCheckpoint;
|
||||
// If set to none 0, microtasks will be processed only when recursion depth
|
||||
// is the set value.
|
||||
uint32_t mTargetedMicroTaskRecursionDepth;
|
||||
|
||||
uint32_t mMicroTaskLevel;
|
||||
|
||||
std::queue<RefPtr<MicroTaskRunnable>> mPendingMicroTaskRunnables;
|
||||
std::queue<RefPtr<MicroTaskRunnable>> mDebuggerMicroTaskQueue;
|
||||
|
||||
uint32_t mMicroTaskRecursionDepth;
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue