Reduce a shadow root object's size by not inheriting DoublyLinkedList

Using DoublyLinkedList increases a shadow root object's size by adding two pointers,
m_prev and m_next.

Because these pointers are only required for multiple shadow roots,
these pointers can be moved to ShadowRootRareDataV0.

- Maintain a doubly linked list manually, instead of inheriting DoublyLinkedList.
- ElementShadow has only one shadowRoot object, instead of having DoublyLinkedList<ShadowRoot>.
- ElementShadow::m_shadowRoot acts as the oldest shadow root in case for multiple shadow roots.

BUG=531990

Review URL: https://codereview.chromium.org/1904923002

Cr-Commit-Position: refs/heads/master@{#389013}
diff --git a/third_party/WebKit/Source/core/dom/shadow/ElementShadow.cpp b/third_party/WebKit/Source/core/dom/shadow/ElementShadow.cpp
index b4e93ba..393a0ea 100644
--- a/third_party/WebKit/Source/core/dom/shadow/ElementShadow.cpp
+++ b/third_party/WebKit/Source/core/dom/shadow/ElementShadow.cpp
@@ -144,23 +144,35 @@
 {
 }
 
+ShadowRoot& ElementShadow::youngestShadowRoot() const
+{
+    ShadowRoot* current = m_shadowRoot;
+    DCHECK(current);
+    while (current->youngerShadowRoot())
+        current = current->youngerShadowRoot();
+    return *current;
+}
+
 ShadowRoot& ElementShadow::addShadowRoot(Element& shadowHost, ShadowRootType type)
 {
     EventDispatchForbiddenScope assertNoEventDispatch;
     ScriptForbiddenScope forbidScript;
 
-    if (type == ShadowRootType::V0 && !m_shadowRoots.isEmpty()) {
-        DCHECK_NE(ShadowRootType::UserAgent, m_shadowRoots.head()->type());
+    if (type == ShadowRootType::V0 && m_shadowRoot) {
+        DCHECK_EQ(m_shadowRoot->type(), ShadowRootType::V0);
         Deprecation::countDeprecation(shadowHost.document(), UseCounter::ElementCreateShadowRootMultiple);
     }
 
-    for (ShadowRoot* root = m_shadowRoots.head(); root; root = root->olderShadowRoot())
-        root->lazyReattachIfAttached();
+    if (m_shadowRoot) {
+        // TODO(hayato): Is the order, from the youngest to the oldest, important?
+        for (ShadowRoot* root = &youngestShadowRoot(); root; root = root->olderShadowRoot())
+            root->lazyReattachIfAttached();
+    }
 
     ShadowRoot* shadowRoot = ShadowRoot::create(shadowHost.document(), type);
     shadowRoot->setParentOrShadowHostNode(&shadowHost);
     shadowRoot->setParentTreeScope(shadowHost.treeScope());
-    m_shadowRoots.push(shadowRoot);
+    appendShadowRoot(*shadowRoot);
     setNeedsDistributionRecalc();
 
     shadowRoot->insertedInto(&shadowHost);
@@ -172,6 +184,19 @@
     return *shadowRoot;
 }
 
+void ElementShadow::appendShadowRoot(ShadowRoot& shadowRoot)
+{
+    if (!m_shadowRoot) {
+        m_shadowRoot = &shadowRoot;
+        return;
+    }
+    ShadowRoot& youngest = youngestShadowRoot();
+    DCHECK(shadowRoot.type() == ShadowRootType::V0);
+    DCHECK(youngest.type() == ShadowRootType::V0);
+    youngest.setYoungerShadowRoot(shadowRoot);
+    shadowRoot.setOlderShadowRoot(youngest);
+}
+
 void ElementShadow::attach(const Node::AttachContext& context)
 {
     Node::AttachContext childrenContext(context);
@@ -354,10 +379,7 @@
 {
     visitor->trace(m_nodeToInsertionPoints);
     visitor->trace(m_selectFeatures);
-    // Shadow roots are linked with previous and next pointers which are traced.
-    // It is therefore enough to trace one of the shadow roots here and the
-    // rest will be traced from there.
-    visitor->trace(m_shadowRoots.head());
+    visitor->trace(m_shadowRoot);
 }
 
 } // namespace blink
diff --git a/third_party/WebKit/Source/core/dom/shadow/ElementShadow.h b/third_party/WebKit/Source/core/dom/shadow/ElementShadow.h
index 7725df6..a8aa549 100644
--- a/third_party/WebKit/Source/core/dom/shadow/ElementShadow.h
+++ b/third_party/WebKit/Source/core/dom/shadow/ElementShadow.h
@@ -32,7 +32,6 @@
 #include "core/dom/shadow/SelectRuleFeatureSet.h"
 #include "core/dom/shadow/ShadowRoot.h"
 #include "platform/heap/Handle.h"
-#include "wtf/DoublyLinkedList.h"
 #include "wtf/HashMap.h"
 #include "wtf/Noncopyable.h"
 
@@ -45,8 +44,8 @@
     ~ElementShadow();
 
     Element* host() const;
-    ShadowRoot& youngestShadowRoot() const { DCHECK(m_shadowRoots.head()); return *m_shadowRoots.head(); }
-    ShadowRoot* oldestShadowRoot() const { return m_shadowRoots.tail(); }
+    ShadowRoot& youngestShadowRoot() const;
+    ShadowRoot* oldestShadowRoot() const { return m_shadowRoot; }
     ElementShadow* containingShadow() const;
 
     ShadowRoot& addShadowRoot(Element& shadowHost, ShadowRootType);
@@ -76,6 +75,8 @@
 private:
     ElementShadow();
 
+    void appendShadowRoot(ShadowRoot&);
+
     void distribute();
     void clearDistribution();
 
@@ -92,16 +93,15 @@
     NodeToDestinationInsertionPoints m_nodeToInsertionPoints;
 
     SelectRuleFeatureSet m_selectFeatures;
-    // TODO(Oilpan): add a heap-based version of DoublyLinkedList<>.
-    DoublyLinkedList<ShadowRoot> m_shadowRoots;
+    Member<ShadowRoot> m_shadowRoot;
     bool m_needsDistributionRecalc;
     bool m_needsSelectFeatureSet;
 };
 
 inline Element* ElementShadow::host() const
 {
-    DCHECK(!m_shadowRoots.isEmpty());
-    return youngestShadowRoot().host();
+    DCHECK(m_shadowRoot);
+    return m_shadowRoot->host();
 }
 
 inline ShadowRoot* Node::youngestShadowRoot() const
diff --git a/third_party/WebKit/Source/core/dom/shadow/ShadowRoot.cpp b/third_party/WebKit/Source/core/dom/shadow/ShadowRoot.cpp
index 76797f1..cb6536b 100644
--- a/third_party/WebKit/Source/core/dom/shadow/ShadowRoot.cpp
+++ b/third_party/WebKit/Source/core/dom/shadow/ShadowRoot.cpp
@@ -43,9 +43,9 @@
 
 namespace blink {
 
-struct SameSizeAsShadowRoot : public DocumentFragment, public TreeScope, public DoublyLinkedListNode<ShadowRoot> {
+struct SameSizeAsShadowRoot : public DocumentFragment, public TreeScope {
     char emptyClassFieldsDueToGCMixinMarker[1];
-    Member<void*> willbeMember[5];
+    Member<void*> willbeMember[3];
     unsigned countersAndFlags[1];
 };
 
@@ -54,9 +54,6 @@
 ShadowRoot::ShadowRoot(Document& document, ShadowRootType type)
     : DocumentFragment(0, CreateShadowRoot)
     , TreeScope(*this, document)
-    , m_prev(nullptr)
-    , m_next(nullptr)
-    , m_slotAssignment(nullptr)
     , m_numberOfStyles(0)
     , m_type(static_cast<unsigned>(type))
     , m_registeredWithParentShadowRoot(false)
@@ -70,6 +67,20 @@
 {
 }
 
+ShadowRoot* ShadowRoot::youngerShadowRoot() const
+{
+    if (type() == ShadowRootType::V0 && m_shadowRootRareDataV0)
+        return m_shadowRootRareDataV0->youngerShadowRoot();
+    return nullptr;
+}
+
+ShadowRoot* ShadowRoot::olderShadowRoot() const
+{
+    if (type() == ShadowRootType::V0 && m_shadowRootRareDataV0)
+        return m_shadowRootRareDataV0->olderShadowRoot();
+    return nullptr;
+}
+
 ShadowRoot* ShadowRoot::olderShadowRootForBindings() const
 {
     ShadowRoot* older = olderShadowRoot();
@@ -79,6 +90,18 @@
     return older;
 }
 
+void ShadowRoot::setYoungerShadowRoot(ShadowRoot& root)
+{
+    DCHECK_EQ(type(), ShadowRootType::V0);
+    ensureShadowRootRareDataV0().setYoungerShadowRoot(root);
+}
+
+void ShadowRoot::setOlderShadowRoot(ShadowRoot& root)
+{
+    DCHECK_EQ(type(), ShadowRootType::V0);
+    ensureShadowRootRareDataV0().setOlderShadowRoot(root);
+}
+
 Node* ShadowRoot::cloneNode(bool, ExceptionState& exceptionState)
 {
     exceptionState.throwDOMException(NotSupportedError, "ShadowRoot nodes are not clonable.");
@@ -186,22 +209,22 @@
     --m_numberOfStyles;
 }
 
-ShadowRootRareData* ShadowRoot::ensureShadowRootRareData()
+ShadowRootRareData& ShadowRoot::ensureShadowRootRareData()
 {
     if (m_shadowRootRareData)
-        return m_shadowRootRareData.get();
+        return *m_shadowRootRareData;
 
     m_shadowRootRareData = new ShadowRootRareData;
-    return m_shadowRootRareData.get();
+    return *m_shadowRootRareData;
 }
 
-ShadowRootRareDataV0* ShadowRoot::ensureShadowRootRareDataV0()
+ShadowRootRareDataV0& ShadowRoot::ensureShadowRootRareDataV0()
 {
     if (m_shadowRootRareDataV0)
-        return m_shadowRootRareDataV0.get();
+        return *m_shadowRootRareDataV0;
 
     m_shadowRootRareDataV0 = new ShadowRootRareDataV0;
-    return m_shadowRootRareDataV0.get();
+    return *m_shadowRootRareDataV0;
 }
 
 bool ShadowRoot::containsShadowElements() const
@@ -233,12 +256,12 @@
 {
     if (!m_shadowRootRareDataV0 && !shadowInsertionPoint)
         return;
-    ensureShadowRootRareDataV0()->setShadowInsertionPointOfYoungerShadowRoot(shadowInsertionPoint);
+    ensureShadowRootRareDataV0().setShadowInsertionPointOfYoungerShadowRoot(shadowInsertionPoint);
 }
 
 void ShadowRoot::didAddInsertionPoint(InsertionPoint* insertionPoint)
 {
-    ensureShadowRootRareDataV0()->didAddInsertionPoint(insertionPoint);
+    ensureShadowRootRareDataV0().didAddInsertionPoint(insertionPoint);
     invalidateDescendantInsertionPoints();
 }
 
@@ -250,7 +273,7 @@
 
 void ShadowRoot::addChildShadowRoot()
 {
-    ensureShadowRootRareData()->didAddChildShadowRoot();
+    ensureShadowRootRareData().didAddChildShadowRoot();
 }
 
 void ShadowRoot::removeChildShadowRoot()
@@ -287,14 +310,14 @@
     for (InsertionPoint& insertionPoint : Traversal<InsertionPoint>::descendantsOf(*this))
         insertionPoints.append(&insertionPoint);
 
-    ensureShadowRootRareDataV0()->setDescendantInsertionPoints(insertionPoints);
+    ensureShadowRootRareDataV0().setDescendantInsertionPoints(insertionPoints);
 
     return m_shadowRootRareDataV0->descendantInsertionPoints();
 }
 
 StyleSheetList* ShadowRoot::styleSheets()
 {
-    if (!ensureShadowRootRareData()->styleSheets())
+    if (!ensureShadowRootRareData().styleSheets())
         m_shadowRootRareData->setStyleSheets(StyleSheetList::create(this));
 
     return m_shadowRootRareData->styleSheets();
@@ -302,7 +325,7 @@
 
 void ShadowRoot::didAddSlot()
 {
-    ensureShadowRootRareData()->didAddSlot();
+    ensureShadowRootRareData().didAddSlot();
     invalidateDescendantSlots();
 }
 
@@ -353,8 +376,6 @@
 
 DEFINE_TRACE(ShadowRoot)
 {
-    visitor->trace(m_prev);
-    visitor->trace(m_next);
     visitor->trace(m_shadowRootRareData);
     visitor->trace(m_shadowRootRareDataV0);
     visitor->trace(m_slotAssignment);
diff --git a/third_party/WebKit/Source/core/dom/shadow/ShadowRoot.h b/third_party/WebKit/Source/core/dom/shadow/ShadowRoot.h
index b1d3653..9060e14c 100644
--- a/third_party/WebKit/Source/core/dom/shadow/ShadowRoot.h
+++ b/third_party/WebKit/Source/core/dom/shadow/ShadowRoot.h
@@ -33,8 +33,6 @@
 #include "core/dom/Element.h"
 #include "core/dom/TreeScope.h"
 #include "core/dom/shadow/SlotAssignment.h"
-#include "wtf/DoublyLinkedList.h"
-#include <iosfwd>
 
 namespace blink {
 
@@ -54,10 +52,9 @@
     Closed
 };
 
-class CORE_EXPORT ShadowRoot final : public DocumentFragment, public TreeScope, public DoublyLinkedListNode<ShadowRoot> {
+class CORE_EXPORT ShadowRoot final : public DocumentFragment, public TreeScope {
     DEFINE_WRAPPERTYPEINFO();
     USING_GARBAGE_COLLECTED_MIXIN(ShadowRoot);
-    friend class WTF::DoublyLinkedListNode<ShadowRoot>;
 public:
     // FIXME: Current implementation does not work well if a shadow root is dynamically created.
     // So multiple shadow subtrees in several elements are prohibited.
@@ -78,10 +75,13 @@
     Element* host() const { return toElement(parentOrShadowHostNode()); }
     ElementShadow* owner() const { return host() ? host()->shadow() : 0; }
 
-    ShadowRoot* youngerShadowRoot() const { return prev(); }
-
+    ShadowRoot* youngerShadowRoot() const;
+    ShadowRoot* olderShadowRoot() const;
     ShadowRoot* olderShadowRootForBindings() const;
 
+    void setYoungerShadowRoot(ShadowRoot&);
+    void setOlderShadowRoot(ShadowRoot&);
+
     String mode() const { return (type() == ShadowRootType::V0 || type() == ShadowRootType::Open) ? "open" : "closed"; };
 
     bool isOpenOrV0() const { return type() == ShadowRootType::V0 || type() == ShadowRootType::Open; }
@@ -135,11 +135,8 @@
     using TreeScope::setDocument;
     using TreeScope::setParentTreeScope;
 
-public:
     Element* activeElement() const;
 
-    ShadowRoot* olderShadowRoot() const { return next(); }
-
     String innerHTML() const;
     void setInnerHTML(const String&, ExceptionState&);
 
@@ -158,8 +155,8 @@
 
     void childrenChanged(const ChildrenChange&) override;
 
-    ShadowRootRareData* ensureShadowRootRareData();
-    ShadowRootRareDataV0* ensureShadowRootRareDataV0();
+    ShadowRootRareData& ensureShadowRootRareData();
+    ShadowRootRareDataV0& ensureShadowRootRareDataV0();
 
     void addChildShadowRoot();
     void removeChildShadowRoot();
@@ -174,11 +171,8 @@
     void invalidateDescendantSlots();
     unsigned descendantSlotCount() const;
 
-    Member<ShadowRoot> m_prev;
-    Member<ShadowRoot> m_next;
     Member<ShadowRootRareData> m_shadowRootRareData;
     Member<ShadowRootRareDataV0> m_shadowRootRareDataV0;
-
     Member<SlotAssignment> m_slotAssignment;
     unsigned m_numberOfStyles : 26;
     unsigned m_type : 2;
diff --git a/third_party/WebKit/Source/core/dom/shadow/ShadowRootRareDataV0.h b/third_party/WebKit/Source/core/dom/shadow/ShadowRootRareDataV0.h
index c0f62d2..6c7e033 100644
--- a/third_party/WebKit/Source/core/dom/shadow/ShadowRootRareDataV0.h
+++ b/third_party/WebKit/Source/core/dom/shadow/ShadowRootRareDataV0.h
@@ -59,13 +59,23 @@
     void setDescendantInsertionPoints(HeapVector<Member<InsertionPoint>>& list) { m_descendantInsertionPoints.swap(list); }
     void clearDescendantInsertionPoints() { m_descendantInsertionPoints.clear(); }
 
+    void setYoungerShadowRoot(ShadowRoot& youngerShadowRoot) { m_youngerShadowRoot = &youngerShadowRoot; }
+    void setOlderShadowRoot(ShadowRoot& olderShadowRoot) { m_olderShadowRoot = &olderShadowRoot; }
+
+    ShadowRoot* youngerShadowRoot() const { return m_youngerShadowRoot; }
+    ShadowRoot* olderShadowRoot() const { return m_olderShadowRoot; }
+
     DEFINE_INLINE_TRACE()
     {
+        visitor->trace(m_youngerShadowRoot);
+        visitor->trace(m_olderShadowRoot);
         visitor->trace(m_shadowInsertionPointOfYoungerShadowRoot);
         visitor->trace(m_descendantInsertionPoints);
     }
 
 private:
+    Member<ShadowRoot> m_youngerShadowRoot;
+    Member<ShadowRoot> m_olderShadowRoot;
     Member<HTMLShadowElement> m_shadowInsertionPointOfYoungerShadowRoot;
     unsigned m_descendantShadowElementCount;
     unsigned m_descendantContentElementCount;