Backed out 4 changesets (bug 1315885) for merge conflicts with bug 1377993.
authorRyan VanderMeulen <ryanvm@gmail.com>
Tue, 18 Jul 2017 12:58:46 -0400
changeset 418309 944c576e7e20802c72946a0335986307bcd0f278
parent 418308 9fa7419d9080260365669174e4ed13c65280492d
child 418310 e95d76dbe6517d9d5a257588607917f93635c56a
push id7566
push usermtabara@mozilla.com
push dateWed, 02 Aug 2017 08:25:16 +0000
treeherdermozilla-beta@86913f512c3c [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
bugs1315885, 1377993
milestone56.0a1
backs outc6dcdfe7ac54e576e92388399cb912188b3248e8
c8bc78492b814d773578be165c7520db7e4254bc
7ba49d85f30c412332b9deacc8292dbf3cfcd0d3
d592ae3b61bfe90de61171b1494ed14af7d135ad
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
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
dom/base/CustomElementRegistry.h
dom/base/FragmentOrElement.cpp
dom/tests/mochitest/webcomponents/test_document_register_stack.html
dom/webidl/ShadowRoot.webidl
layout/build/nsLayoutStatics.cpp
--- a/dom/base/CustomElementRegistry.cpp
+++ b/dom/base/CustomElementRegistry.cpp
@@ -50,20 +50,16 @@ CustomElementCallback::Call()
     case nsIDocument::eDetached:
       static_cast<LifecycleDetachedCallback *>(mCallback.get())->Call(mThisObject, rv);
       break;
     case nsIDocument::eAttributeChanged:
       static_cast<LifecycleAttributeChangedCallback *>(mCallback.get())->Call(mThisObject,
         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
 CustomElementCallback::Traverse(nsCycleCollectionTraversalCallback& aCb) const
 {
   NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(aCb, "mThisObject");
   aCb.NoteXPCOMChild(mThisObject);
 
@@ -87,39 +83,53 @@ CustomElementCallback::CustomElementCall
 
 CustomElementData::CustomElementData(nsIAtom* aType)
   : CustomElementData(aType, CustomElementData::State::eUndefined)
 {
 }
 
 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<uint32_t>(++mCurrentCallback) < mCallbackQueue.Length()) {
+    mCallbackQueue[mCurrentCallback]->Call();
+  }
+
+  mCallbackQueue.Clear();
+  mCurrentCallback = -1;
+}
+
 //-----------------------------------------------------
 // CustomElementRegistry
 
 // Only needed for refcounted objects.
 NS_IMPL_CYCLE_COLLECTION_CLASS(CustomElementRegistry)
 
 NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(CustomElementRegistry)
   tmp->mCustomDefinitions.Clear();
   tmp->mConstructors.clear();
   NS_IMPL_CYCLE_COLLECTION_UNLINK(mWhenDefinedPromiseMap)
   NS_IMPL_CYCLE_COLLECTION_UNLINK(mWindow)
   NS_IMPL_CYCLE_COLLECTION_UNLINK_PRESERVED_WRAPPER
 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<LifecycleCallbacks>& callbacks = iter.UserData()->mCallbacks;
 
     if (callbacks->mAttributeChangedCallback.WasPassed()) {
       NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb,
         "mCustomDefinitions->mCallbacks->mAttributeChangedCallback");
       cb.NoteXPCOMChild(callbacks->mAttributeChangedCallback.Value());
     }
 
     if (callbacks->mCreatedCallback.WasPassed()) {
@@ -173,25 +183,68 @@ NS_INTERFACE_MAP_END
 
 /* static */ bool
 CustomElementRegistry::IsCustomElementEnabled(JSContext* aCx, JSObject* aObject)
 {
   return nsContentUtils::IsCustomElementsEnabled() ||
          nsContentUtils::IsWebComponentsEnabled();
 }
 
+/* static */ void
+CustomElementRegistry::ProcessTopElementQueue()
+{
+  MOZ_ASSERT(nsContentUtils::IsSafeToRunScript());
+
+  nsTArray<RefPtr<CustomElementData>>& 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<nsTArray<RefPtr<CustomElementData>>>
+CustomElementRegistry::sProcessingStack;
+
 CustomElementRegistry::CustomElementRegistry(nsPIDOMWindowInner* aWindow)
  : mWindow(aWindow)
  , mIsCustomDefinitionRunning(false)
 {
   MOZ_ASSERT(aWindow);
   MOZ_ASSERT(aWindow->IsInnerWindow());
   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()
 {
   mozilla::DropJSObjects(this);
 }
 
 CustomElementDefinition*
@@ -285,25 +338,24 @@ CustomElementRegistry::SetupCustomElemen
     // The element doesn't match the local name for the
     // definition, thus the element isn't a custom element
     // and we don't need to do anything more.
     return;
   }
 
   // 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<CustomElementCallback>
-CustomElementRegistry::CreateCustomElementCallback(
-  nsIDocument::ElementCallbackType aType, Element* aCustomElement,
-  LifecycleCallbackArgs* aArgs, CustomElementDefinition* aDefinition)
+void
+CustomElementRegistry::EnqueueLifecycleCallback(nsIDocument::ElementCallbackType aType,
+                                                Element* aCustomElement,
+                                                LifecycleCallbackArgs* aArgs,
+                                                CustomElementDefinition* aDefinition)
 {
   RefPtr<CustomElementData> elementData = aCustomElement->GetCustomElementData();
   MOZ_ASSERT(elementData, "CustomElementData should exist");
 
   // Let DEFINITION be ELEMENT's definition
   CustomElementDefinition* definition = aDefinition;
   if (!definition) {
     mozilla::dom::NodeInfo* info = aCustomElement->NodeInfo();
@@ -312,17 +364,17 @@ CustomElementRegistry::CreateCustomEleme
     // is a extended custom element e.g. <button is="x-button">.
     nsCOMPtr<nsIAtom> typeAtom = elementData ?
       elementData->mType.get() : info->NameAtom();
 
     definition = mCustomDefinitions.Get(typeAtom);
     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;
     }
   }
 
   // Let CALLBACK be the callback associated with the key NAME in CALLBACKS.
   CallbackFunction* func = nullptr;
   switch (aType) {
     case nsIDocument::eCreated:
       if (definition->mCallbacks->mCreatedCallback.WasPassed()) {
@@ -346,80 +398,73 @@ CustomElementRegistry::CreateCustomEleme
       if (definition->mCallbacks->mAttributeChangedCallback.WasPassed()) {
         func = definition->mCallbacks->mAttributeChangedCallback.Value();
       }
       break;
   }
 
   // If there is no such callback, stop.
   if (!func) {
-    return nullptr;
+    return;
   }
 
   if (aType == nsIDocument::eCreated) {
     elementData->mCreatedCallbackInvoked = false;
   } 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<CustomElementCallback>(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<int32_t>(nsContentUtils::MicroTaskLevel()));
 
-  UniquePtr<CustomElementReaction> reaction(Move(
-    MakeUnique<CustomElementCallbackReaction>(this, aDefinition,
-                                              Move(callback))));
-
-  RefPtr<SyncInvokeReactionRunnable> runnable =
-    new SyncInvokeReactionRunnable(Move(reaction), aCustomElement);
+    // 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);
+    }
 
-  nsContentUtils::AddScriptRunner(runnable);
-}
+    sProcessingStack->AppendElement(elementData);
+    elementData->mAssociatedMicroTask =
+      static_cast<int32_t>(nsContentUtils::MicroTaskLevel());
 
-void
-CustomElementRegistry::EnqueueLifecycleCallback(nsIDocument::ElementCallbackType aType,
-                                                Element* aCustomElement,
-                                                LifecycleCallbackArgs* aArgs,
-                                                CustomElementDefinition* aDefinition)
-{
-  auto callback =
-    CreateCustomElementCallback(aType, aCustomElement, aArgs, aDefinition);
-  if (!callback) {
-    return;
+    // 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<nsIRunnable> runnable = NS_NewRunnableFunction(
+        "dom::CustomElementRegistry::EnqueueLifecycleCallback",
+        &CustomElementRegistry::ProcessTopElementQueue);
+      nsContentUtils::AddScriptRunner(runnable);
+    }
   }
-
-  DocGroup* docGroup = mWindow->GetDocGroup();
-  if (!docGroup) {
-    return;
-  }
-
-  CustomElementReactionsStack* reactionsStack =
-    docGroup->CustomElementReactionsStack();
-  reactionsStack->EnqueueCallbackReaction(this, aCustomElement, aDefinition,
-                                          Move(callback));
 }
 
 void
 CustomElementRegistry::GetCustomPrototype(nsIAtom* aAtom,
                                           JS::MutableHandle<JSObject*> aPrototype)
 {
   mozilla::dom::CustomElementDefinition* definition = mCustomDefinitions.Get(aAtom);
   if (definition) {
@@ -894,26 +939,16 @@ void
 CustomElementReactionsStack::EnqueueUpgradeReaction(CustomElementRegistry* aRegistry,
                                                     Element* aElement,
                                                     CustomElementDefinition* aDefinition)
 {
   Enqueue(aElement, new CustomElementUpgradeReaction(aRegistry, aDefinition));
 }
 
 void
-CustomElementReactionsStack::EnqueueCallbackReaction(CustomElementRegistry* aRegistry,
-                                                     Element* aElement,
-                                                     CustomElementDefinition* aDefinition,
-                                                     UniquePtr<CustomElementCallback> aCustomElementCallback)
-{
-  Enqueue(aElement, new CustomElementCallbackReaction(aRegistry, aDefinition,
-                                                      Move(aCustomElementCallback)));
-}
-
-void
 CustomElementReactionsStack::Enqueue(Element* aElement,
                                      CustomElementReaction* aReaction)
 {
   RefPtr<CustomElementData> elementData = aElement->GetCustomElementData();
   MOZ_ASSERT(elementData, "CustomElementData should exist");
 
   // Add element to the current element queue.
   if (!mReactionsStack.IsEmpty()) {
@@ -944,35 +979,30 @@ CustomElementReactionsStack::InvokeBacku
   if (!mBackupQueue.IsEmpty()) {
     InvokeReactions(mBackupQueue);
   }
 }
 
 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> element = do_QueryReferent(aElementQueue[i]);
 
     if (!element) {
       continue;
     }
 
     RefPtr<CustomElementData> elementData = element->GetCustomElementData();
     MOZ_ASSERT(elementData, "CustomElementData should exist");
 
-    auto& reactions = elementData->mReactionQueue;
+    nsTArray<nsAutoPtr<CustomElementReaction>>& 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();
   }
   aElementQueue.Clear();
 }
 
 //-----------------------------------------------------
 // CustomElementDefinition
@@ -997,19 +1027,10 @@ CustomElementDefinition::CustomElementDe
 // CustomElementUpgradeReaction
 
 /* virtual */ void
 CustomElementUpgradeReaction::Invoke(Element* aElement)
 {
   mRegistry->Upgrade(aElement, mDefinition);
 }
 
-//-----------------------------------------------------
-// CustomElementCallbackReaction
-
-/* virtual */ void
-CustomElementCallbackReaction::Invoke(Element* aElement)
-{
-  mCustomElementCallback->Call();
-}
-
 } // namespace dom
 } // namespace mozilla
--- a/dom/base/CustomElementRegistry.h
+++ b/dom/base/CustomElementRegistry.h
@@ -80,33 +80,45 @@ struct CustomElementData
   enum class State {
     eUndefined,
     eFailed,
     eCustom
   };
 
   explicit CustomElementData(nsIAtom* aType);
   CustomElementData(nsIAtom* aType, State aState);
+  // Objects in this array are transient and empty after each microtask
+  // checkpoint.
+  nsTArray<nsAutoPtr<CustomElementCallback>> mCallbackQueue;
   // Custom element type, for <button is="x-button"> or <x-button>
   // this would be x-button.
   nsCOMPtr<nsIAtom> mType;
+  // The callback that is next to be processed upon calling RunCallbackQueue.
+  int32_t mCurrentCallback;
   // Element is being created flag as described in the custom elements spec.
   bool mElementIsBeingCreated;
   // Flag to determine if the created callback has been invoked, thus it
   // determines if other callbacks can be enqueued.
   bool mCreatedCallbackInvoked;
+  // The microtask level associated with the callbacks in the callback queue,
+  // it is used to determine if a new queue needs to be pushed onto the
+  // processing stack.
+  int32_t mAssociatedMicroTask;
   // Custom element state as described in the custom element spec.
   State mState;
   // custom element reaction queue as described in the custom element spec.
   // There is 1 reaction in reaction queue, when 1) it becomes disconnected,
   // 2) it’s adopted into a new document, 3) its attributes are changed,
   // appended, removed, or replaced.
   // There are 3 reactions in reaction queue when doing upgrade operation,
   // e.g., create an element, insert a node.
-  AutoTArray<UniquePtr<CustomElementReaction>, 3> mReactionQueue;
+  AutoTArray<nsAutoPtr<CustomElementReaction>, 3> mReactionQueue;
+
+  // Empties the callback queue.
+  void RunCallbackQueue();
 
 private:
   virtual ~CustomElementData() {}
 };
 
 // The required information for a custom element as defined in:
 // https://html.spec.whatwg.org/multipage/scripting.html#custom-element-definition
 struct CustomElementDefinition
@@ -126,17 +138,17 @@ struct CustomElementDefinition
 
   // The custom element constructor.
   JS::Heap<JSObject *> mConstructor;
 
   // The prototype to use for new custom elements of this type.
   JS::Heap<JSObject *> mPrototype;
 
   // The lifecycle callbacks to call for this custom element.
-  UniquePtr<mozilla::dom::LifecycleCallbacks> mCallbacks;
+  nsAutoPtr<mozilla::dom::LifecycleCallbacks> mCallbacks;
 
   // A construction stack.
   // TODO: Bug 1287348 - Implement construction stack for upgrading an element
 
   // The document custom element order.
   uint32_t mDocOrder;
 
   bool IsCustomBuiltIn() {
@@ -147,23 +159,20 @@ struct CustomElementDefinition
 class CustomElementReaction
 {
 public:
   explicit CustomElementReaction(CustomElementRegistry* aRegistry,
                                  CustomElementDefinition* aDefinition)
     : mRegistry(aRegistry)
     , mDefinition(aDefinition)
   {
-  }
+  };
 
   virtual ~CustomElementReaction() = default;
   virtual void Invoke(Element* aElement) = 0;
-  virtual void Traverse(nsCycleCollectionTraversalCallback& aCb) const
-  {
-  }
 
 protected:
   CustomElementRegistry* mRegistry;
   CustomElementDefinition* mDefinition;
 };
 
 class CustomElementUpgradeReaction final : public CustomElementReaction
 {
@@ -173,37 +182,16 @@ public:
     : CustomElementReaction(aRegistry, aDefinition)
   {
   }
 
 private:
    virtual void Invoke(Element* aElement) override;
 };
 
-class CustomElementCallbackReaction final : public CustomElementReaction
-{
-  public:
-    CustomElementCallbackReaction(CustomElementRegistry* aRegistry,
-                                  CustomElementDefinition* aDefinition,
-                                  UniquePtr<CustomElementCallback> aCustomElementCallback)
-      : CustomElementReaction(aRegistry, aDefinition)
-      , mCustomElementCallback(Move(aCustomElementCallback))
-    {
-    }
-
-    virtual void Traverse(nsCycleCollectionTraversalCallback& aCb) const override
-    {
-      mCustomElementCallback->Traverse(aCb);
-    }
-
-  private:
-    virtual void Invoke(Element* aElement) override;
-    UniquePtr<CustomElementCallback> mCustomElementCallback;
-};
-
 // https://html.spec.whatwg.org/multipage/scripting.html#custom-element-reactions-stack
 class CustomElementReactionsStack
 {
 public:
   NS_INLINE_DECL_REFCOUNTING(CustomElementReactionsStack)
 
   CustomElementReactionsStack()
     : mIsBackupQueueProcessing(false)
@@ -219,25 +207,16 @@ public:
   /**
    * Enqueue a custom element upgrade reaction
    * https://html.spec.whatwg.org/multipage/scripting.html#enqueue-a-custom-element-upgrade-reaction
    */
   void EnqueueUpgradeReaction(CustomElementRegistry* aRegistry,
                               Element* aElement,
                               CustomElementDefinition* aDefinition);
 
-  /**
-   * Enqueue a custom element callback reaction
-   * https://html.spec.whatwg.org/multipage/scripting.html#enqueue-a-custom-element-callback-reaction
-   */
-  void EnqueueCallbackReaction(CustomElementRegistry* aRegistry,
-                               Element* aElement,
-                               CustomElementDefinition* aDefinition,
-                               UniquePtr<CustomElementCallback> aCustomElementCallback);
-
   // [CEReactions] Before executing the algorithm's steps
   // Push a new element queue onto the custom element reactions stack.
   void CreateAndPushElementQueue();
 
   // [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();
@@ -296,16 +275,20 @@ class CustomElementRegistry final : publ
 public:
   NS_DECL_CYCLE_COLLECTING_ISUPPORTS
   NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS(CustomElementRegistry)
 
 public:
   static bool IsCustomElementEnabled(JSContext* aCx = nullptr,
                                      JSObject* aObject = nullptr);
 
+  static void ProcessTopElementQueue();
+
+  static void XPCOMShutdown();
+
   explicit CustomElementRegistry(nsPIDOMWindowInner* aWindow);
 
   /**
    * Looking up a custom element definition.
    * https://html.spec.whatwg.org/#look-up-a-custom-element-definition
    */
   CustomElementDefinition* LookupCustomElementDefinition(
     const nsAString& aLocalName, const nsAString* aIs = nullptr) const;
@@ -328,23 +311,16 @@ public:
   void GetCustomPrototype(nsIAtom* aAtom,
                           JS::MutableHandle<JSObject*> aPrototype);
 
   void Upgrade(Element* aElement, CustomElementDefinition* aDefinition);
 
 private:
   ~CustomElementRegistry();
 
-  UniquePtr<CustomElementCallback> CreateCustomElementCallback(
-    nsIDocument::ElementCallbackType aType, Element* aCustomElement,
-    LifecycleCallbackArgs* aArgs, CustomElementDefinition* aDefinition);
-
-  void SyncInvokeReactions(nsIDocument::ElementCallbackType aType,
-                           Element* aCustomElement,
-                           CustomElementDefinition* aDefinition);
   /**
    * Registers an unresolved custom element that is a candidate for
    * upgrade when the definition is registered via registerElement.
    * |aTypeName| is the name of the custom element type, if it is not
    * provided, then element name is used. |aTypeName| should be provided
    * when registering a custom element that extends an existing
    * element. e.g. <button is="x-button">.
    */
@@ -381,16 +357,24 @@ private:
 
   // The "upgrade candidates map" from the web components spec. Maps from a
   // namespace id and local name to a list of elements to upgrade if that
   // element is registered as a custom element.
   CandidateMap mCandidatesMap;
 
   nsCOMPtr<nsPIDOMWindowInner> mWindow;
 
+  // Array representing the processing stack in the custom elements
+  // specification. The processing stack is conceptually a stack of
+  // element queues. Each queue is represented by a sequence of
+  // CustomElementData in this array, separated by nullptr that
+  // represent the boundaries of the items in the stack. The first
+  // queue in the stack is the base element queue.
+  static mozilla::Maybe<nsTArray<RefPtr<CustomElementData>>> sProcessingStack;
+
   // It is used to prevent reentrant invocations of element definition.
   bool mIsCustomDefinitionRunning;
 
 private:
   class MOZ_RAII AutoSetRunningFlag final {
     public:
       explicit AutoSetRunningFlag(CustomElementRegistry* aRegistry)
         : mRegistry(aRegistry)
@@ -403,38 +387,16 @@ private:
       ~AutoSetRunningFlag() {
         mRegistry->mIsCustomDefinitionRunning = false;
       }
 
     private:
       CustomElementRegistry* mRegistry;
   };
 
-  class SyncInvokeReactionRunnable : public mozilla::Runnable {
-    public:
-      SyncInvokeReactionRunnable(
-        UniquePtr<CustomElementReaction> aReaction, Element* aCustomElement)
-        : Runnable(
-            "dom::CustomElementRegistry::SyncInvokeReactionRunnable")
-        , mReaction(Move(aReaction))
-        , mCustomElement(aCustomElement)
-      {
-      }
-
-      NS_IMETHOD Run() override
-      {
-        mReaction->Invoke(mCustomElement);
-        return NS_OK;
-      }
-
-    private:
-      UniquePtr<CustomElementReaction> mReaction;
-      Element* mCustomElement;
-  };
-
 public:
   nsISupports* GetParentObject() const;
 
   virtual JSObject* WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto) override;
 
   void Define(const nsAString& aName, Function& aFunctionConstructor,
               const ElementDefinitionOptions& aOptions, ErrorResult& aRv);
 
--- a/dom/base/FragmentOrElement.cpp
+++ b/dom/base/FragmentOrElement.cpp
@@ -706,20 +706,18 @@ FragmentOrElement::nsDOMSlots::Traverse(
 
   NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb, "mSlots->mLabelsList");
   cb.NoteXPCOMChild(NS_ISUPPORTS_CAST(nsIDOMNodeList*, mLabelsList));
 
   NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb, "mSlots->mClassList");
   cb.NoteXPCOMChild(mClassList.get());
 
   if (mCustomElementData) {
-    for (uint32_t i = 0; i < mCustomElementData->mReactionQueue.Length(); i++) {
-      if (mCustomElementData->mReactionQueue[i]) {
-        mCustomElementData->mReactionQueue[i]->Traverse(cb);
-      }
+    for (uint32_t i = 0; i < mCustomElementData->mCallbackQueue.Length(); i++) {
+      mCustomElementData->mCallbackQueue[i]->Traverse(cb);
     }
   }
 
   for (auto iter = mRegisteredIntersectionObservers.Iter(); !iter.Done(); iter.Next()) {
     DOMIntersectionObserver* observer = iter.Key();
     NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb, "mSlots->mRegisteredIntersectionObservers[i]");
     cb.NoteXPCOMChild(observer);
   }
--- a/dom/tests/mochitest/webcomponents/test_document_register_stack.html
+++ b/dom/tests/mochitest/webcomponents/test_document_register_stack.html
@@ -23,25 +23,25 @@ function testChangeAttributeInCreatedCal
   var attributeChangedCallbackCalled = false;
 
   var p = Object.create(HTMLElement.prototype);
   p.createdCallback = function() {
     is(createdCallbackCalled, false, "Created callback should be called before attached callback.");
     createdCallbackCalled = true;
     is(attributeChangedCallbackCalled, false, "Attribute changed callback should not have been called prior to setting the attribute.");
     this.setAttribute("foo", "bar");
-    is(attributeChangedCallbackCalled, true, "While element is being created, element should be added to the current element callback queue.");
-    runNextTest();
+    is(attributeChangedCallbackCalled, false, "While element is being created, element should not be added to the current element callback queue.");
   };
 
   p.attributeChangedCallback = function(name, oldValue, newValue) {
     is(createdCallbackCalled, true, "attributeChanged callback should be called after the created callback because it was enqueued during created callback.");
     is(attributeChangedCallbackCalled, false, "attributeChanged callback should only be called once in this tests.");
     is(newValue, "bar", "The new value should be 'bar'");
     attributeChangedCallbackCalled = true;
+    runNextTest();
   };
 
   document.registerElement("x-one", { prototype: p });
   document.createElement("x-one");
 }
 
 function testChangeAttributeInEnteredViewCallback() {
   var p = Object.create(HTMLElement.prototype);
--- a/dom/webidl/ShadowRoot.webidl
+++ b/dom/webidl/ShadowRoot.webidl
@@ -12,16 +12,16 @@
 
 [Func="nsDocument::IsWebComponentsEnabled"]
 interface ShadowRoot : DocumentFragment
 {
   Element? getElementById(DOMString elementId);
   HTMLCollection getElementsByTagName(DOMString localName);
   HTMLCollection getElementsByTagNameNS(DOMString? namespace, DOMString localName);
   HTMLCollection getElementsByClassName(DOMString classNames);
-  [CEReactions, SetterThrows, TreatNullAs=EmptyString]
+  [SetterThrows,TreatNullAs=EmptyString]
   attribute DOMString innerHTML;
   readonly attribute Element host;
   readonly attribute ShadowRoot? olderShadowRoot;
   attribute boolean applyAuthorStyles;
   readonly attribute StyleSheetList styleSheets;
 };
 
--- a/layout/build/nsLayoutStatics.cpp
+++ b/layout/build/nsLayoutStatics.cpp
@@ -429,12 +429,14 @@ nsLayoutStatics::Shutdown()
   nsDOMMutationObserver::Shutdown();
 
   DateTimeFormat::Shutdown();
 
   ContentParent::ShutDown();
 
   DisplayItemClip::Shutdown();
 
+  CustomElementRegistry::XPCOMShutdown();
+
   CacheObserver::Shutdown();
 
   PromiseDebugging::Shutdown();
 }