mirror of
https://repo.dactyloidae.xyz/Dactyloidae/UXP.git
synced 2026-09-06 15:58:39 +09:00
Bug 1421544 - Lazy push/pop CustomElementReactionsStack entry;
Tag UXP Issue #1344
This commit is contained in:
parent
a9b3ebace0
commit
a6339bef90
2 changed files with 96 additions and 19 deletions
|
|
@ -951,18 +951,24 @@ CustomElementRegistry::Upgrade(Element* aElement,
|
|||
void
|
||||
CustomElementReactionsStack::CreateAndPushElementQueue()
|
||||
{
|
||||
MOZ_ASSERT(mRecursionDepth);
|
||||
MOZ_ASSERT(!mIsElementQueuePushedForCurrentRecursionDepth);
|
||||
|
||||
// Push a new element queue onto the custom element reactions stack.
|
||||
mReactionsStack.AppendElement(MakeUnique<ElementQueue>());
|
||||
mIsElementQueuePushedForCurrentRecursionDepth = true;
|
||||
}
|
||||
|
||||
void
|
||||
CustomElementReactionsStack::PopAndInvokeElementQueue()
|
||||
{
|
||||
// Pop the element queue from the custom element reactions stack,
|
||||
// and invoke custom element reactions in that queue.
|
||||
MOZ_ASSERT(mRecursionDepth);
|
||||
MOZ_ASSERT(mIsElementQueuePushedForCurrentRecursionDepth);
|
||||
MOZ_ASSERT(!mReactionsStack.IsEmpty(),
|
||||
"Reaction stack shouldn't be empty");
|
||||
|
||||
// Pop the element queue from the custom element reactions stack,
|
||||
// and invoke custom element reactions in that queue.
|
||||
const uint32_t lastIndex = mReactionsStack.Length() - 1;
|
||||
ElementQueue* elementQueue = mReactionsStack.ElementAt(lastIndex).get();
|
||||
// Check element queue size in order to reduce function call overhead.
|
||||
|
|
@ -986,6 +992,7 @@ CustomElementReactionsStack::PopAndInvokeElementQueue()
|
|||
"reactions created by InvokeReactions() should be consumed and removed");
|
||||
|
||||
mReactionsStack.RemoveElementAt(lastIndex);
|
||||
mIsElementQueuePushedForCurrentRecursionDepth = false;
|
||||
}
|
||||
|
||||
void
|
||||
|
|
@ -1009,8 +1016,15 @@ CustomElementReactionsStack::Enqueue(Element* aElement,
|
|||
RefPtr<CustomElementData> elementData = aElement->GetCustomElementData();
|
||||
MOZ_ASSERT(elementData, "CustomElementData should exist");
|
||||
|
||||
// Add element to the current element queue.
|
||||
if (!mReactionsStack.IsEmpty()) {
|
||||
if (mRecursionDepth) {
|
||||
// If the element queue is not created for current recursion depth, create
|
||||
// and push an element queue to reactions stack first.
|
||||
if (!mIsElementQueuePushedForCurrentRecursionDepth) {
|
||||
CreateAndPushElementQueue();
|
||||
}
|
||||
|
||||
MOZ_ASSERT(!mReactionsStack.IsEmpty());
|
||||
// Add element to the current element queue.
|
||||
mReactionsStack.LastElement()->AppendElement(aElement);
|
||||
elementData->mReactionQueue.AppendElement(aReaction);
|
||||
return;
|
||||
|
|
@ -1018,6 +1032,8 @@ CustomElementReactionsStack::Enqueue(Element* aElement,
|
|||
|
||||
// If the custom element reactions stack is empty, then:
|
||||
// Add element to the backup element queue.
|
||||
MOZ_ASSERT(mReactionsStack.IsEmpty(),
|
||||
"custom element reactions stack should be empty");
|
||||
MOZ_ASSERT(!aReaction->IsUpgradeReaction(),
|
||||
"Upgrade reaction should not be scheduled to backup queue");
|
||||
mBackupQueue.AppendElement(aElement);
|
||||
|
|
|
|||
|
|
@ -258,6 +258,8 @@ public:
|
|||
|
||||
CustomElementReactionsStack()
|
||||
: mIsBackupQueueProcessing(false)
|
||||
, mRecursionDepth(0)
|
||||
, mIsElementQueuePushedForCurrentRecursionDepth(false)
|
||||
{
|
||||
}
|
||||
|
||||
|
|
@ -282,18 +284,67 @@ public:
|
|||
void EnqueueCallbackReaction(Element* aElement,
|
||||
UniquePtr<CustomElementCallback> aCustomElementCallback);
|
||||
|
||||
// [CEReactions] Before executing the algorithm's steps
|
||||
// Push a new element queue onto the custom element reactions stack.
|
||||
void CreateAndPushElementQueue();
|
||||
/**
|
||||
* [CEReactions] Before executing the algorithm's steps.
|
||||
* Increase the current recursion depth, and the element queue is pushed
|
||||
* lazily when we really enqueue reactions.
|
||||
*
|
||||
* @return true if the element queue is pushed for "previous" recursion depth.
|
||||
*/
|
||||
bool EnterCEReactions()
|
||||
{
|
||||
bool temp = mIsElementQueuePushedForCurrentRecursionDepth;
|
||||
mRecursionDepth++;
|
||||
// The is-element-queue-pushed flag is initially false when entering a new
|
||||
// recursion level. The original value will be cached in AutoCEReaction
|
||||
// and restored after leaving this recursion level.
|
||||
mIsElementQueuePushedForCurrentRecursionDepth = false;
|
||||
return temp;
|
||||
}
|
||||
|
||||
// [CEReactions] After executing the algorithm's steps
|
||||
// Pop the element queue from the custom element reactions stack,
|
||||
// and invoke custom element reactions in that queue.
|
||||
void PopAndInvokeElementQueue();
|
||||
/**
|
||||
* [CEReactions] After executing the algorithm's steps.
|
||||
* Pop and invoke the element queue if it is created and pushed for current
|
||||
* recursion depth, then decrease the current recursion depth.
|
||||
*
|
||||
* @param aCx JSContext used for handling exception thrown by algorithm's
|
||||
* steps, this could be a nullptr.
|
||||
* aWasElementQueuePushed used for restoring status after leaving
|
||||
* current recursion.
|
||||
*/
|
||||
void LeaveCEReactions(JSContext* aCx, bool aWasElementQueuePushed)
|
||||
{
|
||||
MOZ_ASSERT(mRecursionDepth);
|
||||
|
||||
if (mIsElementQueuePushedForCurrentRecursionDepth) {
|
||||
Maybe<JS::AutoSaveExceptionState> ases;
|
||||
if (aCx) {
|
||||
ases.emplace(aCx);
|
||||
}
|
||||
PopAndInvokeElementQueue();
|
||||
}
|
||||
mRecursionDepth--;
|
||||
// Restore the is-element-queue-pushed flag cached in AutoCEReaction when
|
||||
// leaving the recursion level.
|
||||
mIsElementQueuePushedForCurrentRecursionDepth = aWasElementQueuePushed;
|
||||
|
||||
MOZ_ASSERT_IF(!mRecursionDepth, mReactionsStack.IsEmpty());
|
||||
}
|
||||
|
||||
private:
|
||||
~CustomElementReactionsStack() {};
|
||||
|
||||
/**
|
||||
* Push a new element queue onto the custom element reactions stack.
|
||||
*/
|
||||
void CreateAndPushElementQueue();
|
||||
|
||||
/**
|
||||
* Pop the element queue from the custom element reactions stack, and invoke
|
||||
* custom element reactions in that queue.
|
||||
*/
|
||||
void PopAndInvokeElementQueue();
|
||||
|
||||
// The choice of 8 for the auto size here is based on gut feeling.
|
||||
AutoTArray<UniquePtr<ElementQueue>, 8> mReactionsStack;
|
||||
ElementQueue mBackupQueue;
|
||||
|
|
@ -310,6 +361,13 @@ private:
|
|||
|
||||
void Enqueue(Element* aElement, CustomElementReaction* aReaction);
|
||||
|
||||
// Current [CEReactions] recursion depth.
|
||||
uint32_t mRecursionDepth;
|
||||
// True if the element queue is pushed into reaction stack for current
|
||||
// recursion depth. This will be cached in AutoCEReaction when entering a new
|
||||
// CEReaction recursion and restored after leaving the recursion.
|
||||
bool mIsElementQueuePushedForCurrentRecursionDepth;
|
||||
|
||||
private:
|
||||
class BackupQueueMicroTask final : public mozilla::MicroTaskRunnable {
|
||||
public:
|
||||
|
|
@ -477,19 +535,22 @@ class MOZ_RAII AutoCEReaction final {
|
|||
// exception during the lifetime of the AutoCEReaction.
|
||||
AutoCEReaction(CustomElementReactionsStack* aReactionsStack, JSContext* aCx)
|
||||
: mReactionsStack(aReactionsStack)
|
||||
, mCx(aCx) {
|
||||
mReactionsStack->CreateAndPushElementQueue();
|
||||
, mCx(aCx)
|
||||
{
|
||||
mIsElementQueuePushedForPreviousRecursionDepth =
|
||||
mReactionsStack->EnterCEReactions();
|
||||
}
|
||||
~AutoCEReaction() {
|
||||
Maybe<JS::AutoSaveExceptionState> ases;
|
||||
if (mCx) {
|
||||
ases.emplace(mCx);
|
||||
}
|
||||
mReactionsStack->PopAndInvokeElementQueue();
|
||||
|
||||
~AutoCEReaction()
|
||||
{
|
||||
mReactionsStack->LeaveCEReactions(
|
||||
mCx, mIsElementQueuePushedForPreviousRecursionDepth);
|
||||
}
|
||||
|
||||
private:
|
||||
RefPtr<CustomElementReactionsStack> mReactionsStack;
|
||||
JSContext* mCx;
|
||||
bool mIsElementQueuePushedForPreviousRecursionDepth;
|
||||
};
|
||||
|
||||
} // namespace dom
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue