Revert "Replace style sharing cousin list search with LRU"

This reverts commit r156070 because of a performance regression.

BUG=273605
TBR=esprehn

Review URL: https://chromiumcodereview.appspot.com/22966004

git-svn-id: svn://svn.chromium.org/blink/trunk@156247 bbb929c8-8fbe-4397-9dbb-9b2b20218538
diff --git a/Source/core/css/resolver/SharedStyleFinder.cpp b/Source/core/css/resolver/SharedStyleFinder.cpp
index d3899ad..ee83ce2 100644
--- a/Source/core/css/resolver/SharedStyleFinder.cpp
+++ b/Source/core/css/resolver/SharedStyleFinder.cpp
@@ -56,11 +56,64 @@
 
 using namespace HTMLNames;
 
+static const unsigned cStyleSearchThreshold = 10;
+static const unsigned cStyleSearchLevelThreshold = 10;
+
 static inline bool parentElementPreventsSharing(const Element* parentElement)
 {
+    if (!parentElement)
+        return false;
     return parentElement->hasFlagsSetDuringStylingOfChildren();
 }
 
+Node* SharedStyleFinder::locateCousinList(Element* parent, unsigned& visitedNodeCount) const
+{
+    if (visitedNodeCount >= cStyleSearchThreshold * cStyleSearchLevelThreshold)
+        return 0;
+    if (!parent || !parent->isStyledElement())
+        return 0;
+    if (parent->hasScopedHTMLStyleChild())
+        return 0;
+    if (parent->inlineStyle())
+        return 0;
+    if (parent->isSVGElement() && toSVGElement(parent)->animatedSMILStyleProperties())
+        return 0;
+    if (parent->hasID() && m_features.idsInRules.contains(parent->idForStyleResolution().impl()))
+        return 0;
+    if (isShadowHost(parent) && parent->shadow()->containsActiveStyles())
+        return 0;
+
+    RenderStyle* parentStyle = parent->renderStyle();
+    unsigned subcount = 0;
+    Node* thisCousin = parent;
+    Node* currentNode = parent->previousSibling();
+
+    // Reserve the tries for this level. This effectively makes sure that the algorithm
+    // will never go deeper than cStyleSearchLevelThreshold levels into recursion.
+    visitedNodeCount += cStyleSearchThreshold;
+    while (thisCousin) {
+        while (currentNode) {
+            ++subcount;
+            if (!currentNode->hasScopedHTMLStyleChild() && currentNode->renderStyle() == parentStyle && currentNode->lastChild()
+                && currentNode->isElementNode() && !parentElementPreventsSharing(toElement(currentNode))
+                && !toElement(currentNode)->shadow()
+                ) {
+                // Adjust for unused reserved tries.
+                visitedNodeCount -= cStyleSearchThreshold - subcount;
+                return currentNode->lastChild();
+            }
+            if (subcount >= cStyleSearchThreshold)
+                return 0;
+            currentNode = currentNode->previousSibling();
+        }
+        currentNode = locateCousinList(thisCousin->parentElement(), visitedNodeCount);
+        thisCousin = currentNode;
+    }
+
+    return 0;
+}
+
+
 bool SharedStyleFinder::canShareStyleWithControl(const ElementResolveContext& context, Element* element) const
 {
     if (!element->hasTagName(inputTag) || !context.element()->hasTagName(inputTag))
@@ -161,16 +214,9 @@
 
 bool SharedStyleFinder::canShareStyleWithElement(const ElementResolveContext& context, Element* element) const
 {
-    if (context.element() == element)
-        return false;
-    Element* parent = element->parentElement();
     RenderStyle* style = element->renderStyle();
     if (!style)
         return false;
-    if (!parent)
-        return false;
-    if (context.element()->parentElement()->renderStyle() != parent->renderStyle())
-        return false;
     if (style->unique())
         return false;
     if (style->hasUniquePseudoStyle())
@@ -250,24 +296,22 @@
             return false;
     }
 
-    if (context.element()->parentElement() != parent) {
-        if (!parent->isStyledElement())
-            return false;
-        if (parent->hasScopedHTMLStyleChild())
-            return false;
-        if (parent->inlineStyle())
-            return false;
-        if (parent->isSVGElement() && toSVGElement(parent)->animatedSMILStyleProperties())
-            return false;
-        if (parent->hasID() && m_features.idsInRules.contains(parent->idForStyleResolution().impl()))
-            return false;
-        if (parentElementPreventsSharing(parent))
-            return false;
-    }
-
     return true;
 }
 
+inline Element* SharedStyleFinder::findSiblingForStyleSharing(const ElementResolveContext& context, Node* node, unsigned& count) const
+{
+    for (; node; node = node->previousSibling()) {
+        if (!node->isStyledElement())
+            continue;
+        if (canShareStyleWithElement(context, toElement(node)))
+            break;
+        if (count++ == cStyleSearchThreshold)
+            return 0;
+    }
+    return toElement(node);
+}
+
 #ifdef STYLE_STATS
 Element* SharedStyleFinder::searchDocumentForSharedStyle(const ElementResolveContext& context) const
 {
@@ -279,28 +323,10 @@
 }
 #endif
 
-inline Element* SharedStyleFinder::findElementForStyleSharing(const ElementResolveContext& context) const
-{
-    StyleSharingList& styleSharingList = m_styleResolver->styleSharingList();
-    for (StyleSharingList::iterator iter = styleSharingList.begin(); iter != styleSharingList.end(); ++iter) {
-        if (canShareStyleWithElement(context, *iter)) {
-            Element* element = *iter;
-            if (iter != styleSharingList.begin()) {
-                // Move the element to the front of the LRU
-                styleSharingList.remove(iter);
-                styleSharingList.prepend(element);
-            }
-            return element;
-        }
-    }
-    m_styleResolver->addToStyleSharingList(context.element());
-    return 0;
-}
-
 RenderStyle* SharedStyleFinder::locateSharedStyle(const ElementResolveContext& context, RenderStyle* newStyle)
 {
     STYLE_STATS_ADD_SEARCH();
-    if (!context.element() || !context.element()->isStyledElement() || !context.element()->parentElement())
+    if (!context.element() || !context.element()->isStyledElement())
         return 0;
 
     // If the element has inline style it is probably unique.
@@ -344,7 +370,17 @@
     // FIXME: This should be an explicit out parameter, instead of a member variable.
     m_elementAffectedByClassRules = context.element() && context.element()->hasClass() && classNamesAffectedByRules(context.element()->classNames());
 
-    Element* shareElement = findElementForStyleSharing(context);
+    // Check previous siblings and their cousins.
+    unsigned count = 0;
+    unsigned visitedNodeCount = 0;
+    Element* shareElement = 0;
+    Node* cousinList = context.element()->previousSibling();
+    while (cousinList) {
+        shareElement = findSiblingForStyleSharing(context, cousinList, count);
+        if (shareElement)
+            break;
+        cousinList = locateCousinList(cousinList->parentElement(), visitedNodeCount);
+    }
 
 #ifdef STYLE_STATS
     // FIXME: these stats don't to into account whether or not sibling/attribute
diff --git a/Source/core/css/resolver/SharedStyleFinder.h b/Source/core/css/resolver/SharedStyleFinder.h
index d407279..7734c36 100644
--- a/Source/core/css/resolver/SharedStyleFinder.h
+++ b/Source/core/css/resolver/SharedStyleFinder.h
@@ -51,7 +51,8 @@
     RenderStyle* locateSharedStyle(const ElementResolveContext&, RenderStyle* newStyle);
 
 private:
-    Element* findElementForStyleSharing(const ElementResolveContext&) const;
+    Node* locateCousinList(Element* parent, unsigned& visitedNodeCount) const;
+    Element* findSiblingForStyleSharing(const ElementResolveContext&, Node*, unsigned& count) const;
 
     // Only used when we're collecting stats on styles
     Element* searchDocumentForSharedStyle(const ElementResolveContext&) const;
diff --git a/Source/core/css/resolver/StyleResolver.cpp b/Source/core/css/resolver/StyleResolver.cpp
index 8070d0f..9c2ca3b 100644
--- a/Source/core/css/resolver/StyleResolver.cpp
+++ b/Source/core/css/resolver/StyleResolver.cpp
@@ -243,18 +243,6 @@
     m_uncommonAttributeRuleSet = makeRuleSet(m_features.uncommonAttributeRules);
 }
 
-void StyleResolver::addToStyleSharingList(Element* element)
-{
-    if (m_styleSharingList.size() >= styleSharingListSize)
-        m_styleSharingList.remove(--m_styleSharingList.end());
-    m_styleSharingList.prepend(element);
-}
-
-void StyleResolver::clearStyleSharingList()
-{
-    m_styleSharingList.clear();
-}
-
 void StyleResolver::pushParentElement(Element* parent)
 {
     const ContainerNode* parentsParent = parent->parentOrShadowHostElement();
diff --git a/Source/core/css/resolver/StyleResolver.h b/Source/core/css/resolver/StyleResolver.h
index 15db7d4..a8fd43f 100644
--- a/Source/core/css/resolver/StyleResolver.h
+++ b/Source/core/css/resolver/StyleResolver.h
@@ -36,7 +36,6 @@
 #include "core/css/resolver/StyleBuilder.h"
 #include "core/css/resolver/StyleResolverState.h"
 #include "core/css/resolver/StyleResourceLoader.h"
-#include "wtf/Deque.h"
 #include "wtf/HashMap.h"
 #include "wtf/HashSet.h"
 #include "wtf/RefPtr.h"
@@ -86,9 +85,6 @@
     MatchOnlyUserAgentRules,
 };
 
-const unsigned styleSharingListSize = 20;
-typedef WTF::Deque<Element*, styleSharingListSize> StyleSharingList;
-
 #undef STYLE_STATS
 
 #ifdef STYLE_STATS
@@ -279,11 +275,6 @@
 
     const RuleFeatureSet& ruleFeatureSet() const { return m_features; }
 
-    StyleSharingList& styleSharingList() { return m_styleSharingList; }
-
-    void addToStyleSharingList(Element*);
-    void clearStyleSharingList();
-
 #ifdef STYLE_STATS
     ALWAYS_INLINE static StyleSharingStats& styleSharingStats() { return m_styleSharingStats; }
 #endif
@@ -367,8 +358,6 @@
 
     StyleResourceLoader m_styleResourceLoader;
 
-    StyleSharingList m_styleSharingList;
-
 #ifdef STYLE_STATS
     static StyleSharingStats m_styleSharingStats;
 #endif
diff --git a/Source/core/dom/ContainerNode.cpp b/Source/core/dom/ContainerNode.cpp
index 0fb80f0..1b26b71 100644
--- a/Source/core/dom/ContainerNode.cpp
+++ b/Source/core/dom/ContainerNode.cpp
@@ -25,7 +25,6 @@
 
 #include "bindings/v8/ExceptionState.h"
 #include "bindings/v8/ExceptionStatePlaceholder.h"
-#include "core/css/resolver/StyleResolver.h"
 #include "core/dom/ChildListMutationScope.h"
 #include "core/dom/ContainerNodeAlgorithms.h"
 #include "core/dom/EventNames.h"
@@ -683,8 +682,6 @@
 
         if (s_postAttachCallbackQueue)
             dispatchPostAttachCallbacks();
-        if (StyleResolver* resolver = document()->styleResolverIfExists())
-            resolver->clearStyleSharingList();
     }
     --s_attachDepth;
 }
@@ -1039,8 +1036,6 @@
             child->lazyAttach();
         else
             child->attach();
-        if (StyleResolver* resolver = parent->document()->document()->styleResolverIfExists())
-            resolver->clearStyleSharingList();
     }
 
     dispatchChildInsertionEvents(child);
diff --git a/Source/core/dom/Document.cpp b/Source/core/dom/Document.cpp
index 7be6a8e..9abe48b 100644
--- a/Source/core/dom/Document.cpp
+++ b/Source/core/dom/Document.cpp
@@ -1679,10 +1679,8 @@
         m_inStyleRecalc = false;
 
         // Pseudo element removal and similar may only work with these flags still set. Reset them after the style recalc.
-        if (m_styleResolver) {
+        if (m_styleResolver)
             m_styleSheetCollection->resetCSSFeatureFlags(m_styleResolver->ruleFeatureSet());
-            m_styleResolver->clearStyleSharingList();
-        }
 
         if (frameView) {
             frameView->resumeScheduledEvents();
diff --git a/Source/core/dom/Element.cpp b/Source/core/dom/Element.cpp
index 01190e0..a108336 100644
--- a/Source/core/dom/Element.cpp
+++ b/Source/core/dom/Element.cpp
@@ -1514,9 +1514,6 @@
             change = Force;
         else if (change != Force)
             change = localChange;
-    } else {
-        // We still want to seed the style sharing list when just walking the tree to maximize sharing.
-        document()->styleResolver()->addToStyleSharingList(this);
     }
     StyleResolverParentPusher parentPusher(this);