From f142e0a2161e5e124c8ffbd0e689cb7fbec52251 Mon Sep 17 00:00:00 2001 From: Ryan VanderMeulen Date: Tue, 18 Jul 2017 12:58:46 -0400 Subject: [PATCH] Backed out 4 changesets (bug 1315885) for merge conflicts with bug 1377993. Backed out changeset c6dcdfe7ac54 (bug 1315885) Backed out changeset c8bc78492b81 (bug 1315885) Backed out changeset 7ba49d85f30c (bug 1315885) Backed out changeset d592ae3b61bf (bug 1315885) --- dom/base/CustomElementRegistry.cpp | 197 ++++++++++-------- dom/base/CustomElementRegistry.h | 92 +++----- dom/base/FragmentOrElement.cpp | 6 +- .../test_document_register_stack.html | 4 +- dom/webidl/ShadowRoot.webidl | 2 +- layout/build/nsLayoutStatics.cpp | 2 + 6 files changed, 143 insertions(+), 160 deletions(-) diff --git a/dom/base/CustomElementRegistry.cpp b/dom/base/CustomElementRegistry.cpp index 21dbb168639c..4e7eef67a7e8 100644 --- a/dom/base/CustomElementRegistry.cpp +++ b/dom/base/CustomElementRegistry.cpp @@ -55,10 +55,6 @@ CustomElementCallback::Call() mArgs.name, mArgs.oldValue, mArgs.newValue, rv); break; } - - // If callbacks throw exceptions, it'll be handled and reported in - // Lifecycle*Callback::Call function. - rv.SuppressException(); } void @@ -92,12 +88,26 @@ CustomElementData::CustomElementData(nsIAtom* aType) CustomElementData::CustomElementData(nsIAtom* aType, State aState) : mType(aType) + , mCurrentCallback(-1) , mElementIsBeingCreated(false) , mCreatedCallbackInvoked(true) + , mAssociatedMicroTask(-1) , mState(aState) { } +void +CustomElementData::RunCallbackQueue() +{ + // Note: It's possible to re-enter this method. + while (static_cast(++mCurrentCallback) < mCallbackQueue.Length()) { + mCallbackQueue[mCurrentCallback]->Call(); + } + + mCallbackQueue.Clear(); + mCurrentCallback = -1; +} + //----------------------------------------------------- // CustomElementRegistry @@ -114,7 +124,7 @@ NS_IMPL_CYCLE_COLLECTION_UNLINK_END NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(CustomElementRegistry) for (auto iter = tmp->mCustomDefinitions.Iter(); !iter.Done(); iter.Next()) { - auto& callbacks = iter.UserData()->mCallbacks; + nsAutoPtr& callbacks = iter.UserData()->mCallbacks; if (callbacks->mAttributeChangedCallback.WasPassed()) { NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb, @@ -178,6 +188,43 @@ CustomElementRegistry::IsCustomElementEnabled(JSContext* aCx, JSObject* aObject) nsContentUtils::IsWebComponentsEnabled(); } +/* static */ void +CustomElementRegistry::ProcessTopElementQueue() +{ + MOZ_ASSERT(nsContentUtils::IsSafeToRunScript()); + + nsTArray>& stack = *sProcessingStack; + uint32_t firstQueue = stack.LastIndexOf((CustomElementData*) nullptr); + + for (uint32_t i = firstQueue + 1; i < stack.Length(); ++i) { + // Callback queue may have already been processed in an earlier + // element queue or in an element queue that was popped + // off more recently. + if (stack[i]->mAssociatedMicroTask != -1) { + stack[i]->RunCallbackQueue(); + stack[i]->mAssociatedMicroTask = -1; + } + } + + // If this was actually the base element queue, don't bother trying to pop + // the first "queue" marker (sentinel). + if (firstQueue != 0) { + stack.SetLength(firstQueue); + } else { + // Don't pop sentinel for base element queue. + stack.SetLength(1); + } +} + +/* static */ void +CustomElementRegistry::XPCOMShutdown() +{ + sProcessingStack.reset(); +} + +/* static */ Maybe>> +CustomElementRegistry::sProcessingStack; + CustomElementRegistry::CustomElementRegistry(nsPIDOMWindowInner* aWindow) : mWindow(aWindow) , mIsCustomDefinitionRunning(false) @@ -187,6 +234,12 @@ CustomElementRegistry::CustomElementRegistry(nsPIDOMWindowInner* aWindow) MOZ_ALWAYS_TRUE(mConstructors.init()); mozilla::HoldJSObjects(this); + + if (!sProcessingStack) { + sProcessingStack.emplace(); + // Add the base queue sentinel to the processing stack. + sProcessingStack->AppendElement((CustomElementData*) nullptr); + } } CustomElementRegistry::~CustomElementRegistry() @@ -290,15 +343,14 @@ CustomElementRegistry::SetupCustomElement(Element* aElement, // Enqueuing the created callback will set the CustomElementData on the // element, causing prototype swizzling to occur in Element::WrapObject. - // We make it synchronously for createElement/createElementNS in order to - // pass tests. It'll be removed when we deprecate custom elements v0. - SyncInvokeReactions(nsIDocument::eCreated, aElement, definition); + EnqueueLifecycleCallback(nsIDocument::eCreated, aElement, nullptr, definition); } -UniquePtr -CustomElementRegistry::CreateCustomElementCallback( - nsIDocument::ElementCallbackType aType, Element* aCustomElement, - LifecycleCallbackArgs* aArgs, CustomElementDefinition* aDefinition) +void +CustomElementRegistry::EnqueueLifecycleCallback(nsIDocument::ElementCallbackType aType, + Element* aCustomElement, + LifecycleCallbackArgs* aArgs, + CustomElementDefinition* aDefinition) { RefPtr elementData = aCustomElement->GetCustomElementData(); MOZ_ASSERT(elementData, "CustomElementData should exist"); @@ -317,7 +369,7 @@ CustomElementRegistry::CreateCustomElementCallback( if (!definition || definition->mLocalName != info->NameAtom()) { // Trying to enqueue a callback for an element that is not // a custom element. We are done, nothing to do. - return nullptr; + return; } } @@ -351,7 +403,7 @@ CustomElementRegistry::CreateCustomElementCallback( // If there is no such callback, stop. if (!func) { - return nullptr; + return; } if (aType == nsIDocument::eCreated) { @@ -359,62 +411,55 @@ CustomElementRegistry::CreateCustomElementCallback( } else if (!elementData->mCreatedCallbackInvoked) { // Callbacks other than created callback must not be enqueued // until after the created callback has been invoked. - return nullptr; + return; } // Add CALLBACK to ELEMENT's callback queue. - auto callback = - MakeUnique(aCustomElement, aType, func, elementData); - + CustomElementCallback* callback = new CustomElementCallback(aCustomElement, + aType, + func, + elementData); + // Ownership of callback is taken by mCallbackQueue. + elementData->mCallbackQueue.AppendElement(callback); if (aArgs) { callback->SetArgs(*aArgs); } - return Move(callback); -} + if (!elementData->mElementIsBeingCreated) { + CustomElementData* lastData = + sProcessingStack->SafeLastElement(nullptr); -void -CustomElementRegistry::SyncInvokeReactions(nsIDocument::ElementCallbackType aType, - Element* aCustomElement, - CustomElementDefinition* aDefinition) -{ - auto callback = CreateCustomElementCallback(aType, aCustomElement, nullptr, - aDefinition); - if (!callback) { - return; + // A new element queue needs to be pushed if the queue at the + // top of the stack is associated with another microtask level. + bool shouldPushElementQueue = + (!lastData || lastData->mAssociatedMicroTask < + static_cast(nsContentUtils::MicroTaskLevel())); + + // Push a new element queue onto the processing stack when appropriate + // (when we enter a new microtask). + if (shouldPushElementQueue) { + // Push a sentinel value on the processing stack to mark the + // boundary between the element queues. + sProcessingStack->AppendElement((CustomElementData*) nullptr); + } + + sProcessingStack->AppendElement(elementData); + elementData->mAssociatedMicroTask = + static_cast(nsContentUtils::MicroTaskLevel()); + + // Add a script runner to pop and process the element queue at + // the top of the processing stack. + if (shouldPushElementQueue) { + // Lifecycle callbacks enqueued by user agent implementation + // should be invoked prior to returning control back to script. + // Create a script runner to process the top of the processing + // stack as soon as it is safe to run script. + nsCOMPtr runnable = NS_NewRunnableFunction( + "dom::CustomElementRegistry::EnqueueLifecycleCallback", + &CustomElementRegistry::ProcessTopElementQueue); + nsContentUtils::AddScriptRunner(runnable); + } } - - UniquePtr reaction(Move( - MakeUnique(this, aDefinition, - Move(callback)))); - - RefPtr runnable = - new SyncInvokeReactionRunnable(Move(reaction), aCustomElement); - - nsContentUtils::AddScriptRunner(runnable); -} - -void -CustomElementRegistry::EnqueueLifecycleCallback(nsIDocument::ElementCallbackType aType, - Element* aCustomElement, - LifecycleCallbackArgs* aArgs, - CustomElementDefinition* aDefinition) -{ - auto callback = - CreateCustomElementCallback(aType, aCustomElement, aArgs, aDefinition); - if (!callback) { - return; - } - - DocGroup* docGroup = mWindow->GetDocGroup(); - if (!docGroup) { - return; - } - - CustomElementReactionsStack* reactionsStack = - docGroup->CustomElementReactionsStack(); - reactionsStack->EnqueueCallbackReaction(this, aCustomElement, aDefinition, - Move(callback)); } void @@ -898,16 +943,6 @@ CustomElementReactionsStack::EnqueueUpgradeReaction(CustomElementRegistry* aRegi Enqueue(aElement, new CustomElementUpgradeReaction(aRegistry, aDefinition)); } -void -CustomElementReactionsStack::EnqueueCallbackReaction(CustomElementRegistry* aRegistry, - Element* aElement, - CustomElementDefinition* aDefinition, - UniquePtr aCustomElementCallback) -{ - Enqueue(aElement, new CustomElementCallbackReaction(aRegistry, aDefinition, - Move(aCustomElementCallback))); -} - void CustomElementReactionsStack::Enqueue(Element* aElement, CustomElementReaction* aReaction) @@ -949,7 +984,6 @@ CustomElementReactionsStack::InvokeBackupQueue() void CustomElementReactionsStack::InvokeReactions(ElementQueue& aElementQueue) { - // Note: It's possible to re-enter this method. for (uint32_t i = 0; i < aElementQueue.Length(); ++i) { nsCOMPtr element = do_QueryReferent(aElementQueue[i]); @@ -960,14 +994,10 @@ CustomElementReactionsStack::InvokeReactions(ElementQueue& aElementQueue) RefPtr elementData = element->GetCustomElementData(); MOZ_ASSERT(elementData, "CustomElementData should exist"); - auto& reactions = elementData->mReactionQueue; + nsTArray>& reactions = + elementData->mReactionQueue; for (uint32_t j = 0; j < reactions.Length(); ++j) { - // Transfer the ownership of the entry due to reentrant invocation of - // this funciton. The entry will be removed when bug 1379573 is landed. - auto reaction(Move(reactions.ElementAt(j))); - if (reaction) { - reaction->Invoke(element); - } + reactions.ElementAt(j)->Invoke(element); } reactions.Clear(); } @@ -1002,14 +1032,5 @@ CustomElementUpgradeReaction::Invoke(Element* aElement) mRegistry->Upgrade(aElement, mDefinition); } -//----------------------------------------------------- -// CustomElementCallbackReaction - -/* virtual */ void -CustomElementCallbackReaction::Invoke(Element* aElement) -{ - mCustomElementCallback->Call(); -} - } // namespace dom } // namespace mozilla diff --git a/dom/base/CustomElementRegistry.h b/dom/base/CustomElementRegistry.h index f39fa2dc7e19..6faf5c6463b8 100644 --- a/dom/base/CustomElementRegistry.h +++ b/dom/base/CustomElementRegistry.h @@ -85,14 +85,23 @@ struct CustomElementData explicit CustomElementData(nsIAtom* aType); CustomElementData(nsIAtom* aType, State aState); + // Objects in this array are transient and empty after each microtask + // checkpoint. + nsTArray> mCallbackQueue; // Custom element type, for