mirror of
https://repo.dactyloidae.xyz/Dactyloidae/UXP.git
synced 2026-09-05 15:28:39 +09:00
Bug 1406922 - Make CycleCollectedJSContext to handle microtasks and make MutationObserver to use them
Tag UXP Issue #1344
This commit is contained in:
parent
fb6f6ec903
commit
249667092c
5 changed files with 164 additions and 48 deletions
|
|
@ -440,6 +440,7 @@ CycleCollectedJSContext::CycleCollectedJSContext()
|
|||
, mDoingStableStates(false)
|
||||
, mDisableMicroTaskCheckpoint(false)
|
||||
, mMicroTaskLevel(0)
|
||||
, mMicroTaskRecursionDepth(0)
|
||||
, mOutOfMemoryState(OOMState::OK)
|
||||
, mLargeAllocationFailureState(OOMState::OK)
|
||||
{
|
||||
|
|
@ -1380,8 +1381,8 @@ CycleCollectedJSContext::AfterProcessTask(uint32_t aRecursionDepth)
|
|||
|
||||
// Step 4.1: Execute microtasks.
|
||||
if (!mDisableMicroTaskCheckpoint) {
|
||||
PerformMicroTaskCheckPoint();
|
||||
if (NS_IsMainThread()) {
|
||||
PerformMainThreadMicroTaskCheckpoint();
|
||||
Promise::PerformMicroTaskCheckpoint();
|
||||
} else {
|
||||
Promise::PerformWorkerMicroTaskCheckpoint();
|
||||
|
|
@ -1661,12 +1662,70 @@ CycleCollectedJSContext::DispatchToMicroTask(already_AddRefed<nsIRunnable> aRunn
|
|||
mPromiseMicroTaskQueue.push(runnable.forget());
|
||||
}
|
||||
|
||||
void
|
||||
CycleCollectedJSContext::PerformMainThreadMicroTaskCheckpoint()
|
||||
class AsyncMutationHandler final : public mozilla::Runnable
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
public:
|
||||
NS_IMETHOD Run() override
|
||||
{
|
||||
CycleCollectedJSContext* ccjs = CycleCollectedJSContext::Get();
|
||||
if (ccjs) {
|
||||
ccjs->PerformMicroTaskCheckPoint();
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
};
|
||||
|
||||
nsDOMMutationObserver::HandleMutations();
|
||||
void
|
||||
CycleCollectedJSContext::PerformMicroTaskCheckPoint()
|
||||
{
|
||||
if (mPendingMicroTaskRunnables.empty()) {
|
||||
// Nothing to do, return early.
|
||||
return;
|
||||
}
|
||||
|
||||
uint32_t currentDepth = RecursionDepth();
|
||||
if (mMicroTaskRecursionDepth >= currentDepth) {
|
||||
// We are already executing microtasks for the current recursion depth.
|
||||
return;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
mozilla::AutoRestore<uint32_t> restore(mMicroTaskRecursionDepth);
|
||||
MOZ_ASSERT(currentDepth > 0);
|
||||
mMicroTaskRecursionDepth = currentDepth;
|
||||
|
||||
AutoSlowOperation aso;
|
||||
|
||||
std::queue<RefPtr<MicroTaskRunnable>> suppressed;
|
||||
while (!mPendingMicroTaskRunnables.empty()) {
|
||||
RefPtr<MicroTaskRunnable> runnable =
|
||||
mPendingMicroTaskRunnables.front().forget();
|
||||
mPendingMicroTaskRunnables.pop();
|
||||
if (runnable->Suppressed()) {
|
||||
suppressed.push(runnable);
|
||||
} else {
|
||||
runnable->Run(aso);
|
||||
}
|
||||
}
|
||||
|
||||
// Put back the suppressed microtasks so that they will be run later.
|
||||
// Note, it is possible that we end up keeping these suppressed tasks around
|
||||
// for some time, but no longer than spinning the event loop nestedly
|
||||
// (sync XHR, alert, etc.)
|
||||
mPendingMicroTaskRunnables.swap(suppressed);
|
||||
}
|
||||
|
||||
void
|
||||
CycleCollectedJSContext::DispatchMicroTaskRunnable(
|
||||
already_AddRefed<MicroTaskRunnable> aRunnable)
|
||||
{
|
||||
mPendingMicroTaskRunnables.push(aRunnable);
|
||||
}
|
||||
|
||||
void
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue