Title: [101524] trunk/Source/WebCore
Revision
101524
Author
an...@apple.com
Date
2011-11-30 09:25:17 -0800 (Wed, 30 Nov 2011)

Log Message

Reuse cached style fully if the parent inherited styles are equal 
https://bugs.webkit.org/show_bug.cgi?id=73421

Reviewed by Oliver Hunt.

The matched declaration cache currently restores the non-inherted properties from the cache
entry but still applies all inherited properties normally. In case the current parent
inherited style is equivalent to the cache entry's, also the inherited style can be reused
and no properties need to be applied. This is faster and saves memory (by sharing the
style substructures better).
        
The new optimized code path has a pretty good hit rate, >50% of all cases on many pages.
        
Loading the HTML5 spec this reduces style memory consumption by ~20% (5MB, ~2.5% of total) and 
speeds up style applying by ~25% for ~0.4s (2-3%) gain in the spec loading benchmark.
        
* css/CSSStyleSelector.cpp:
(WebCore::CSSStyleSelector::applyDeclaration):
(WebCore::CSSStyleSelector::applyDeclarations):
        
    Remove the code that dynamically disables inherited only applying. We now don't allow
    styles with explicitly inherited properties to be cached in the first place.
        
(WebCore::CSSStyleSelector::findFromMatchedDeclarationCache):
        
    Return the full cache item.
        
(WebCore::CSSStyleSelector::addToMatchedDeclarationCache):
        
    Also the parent style is now needed for the check for full sharing.
        
(WebCore::isCacheableInMatchedDeclarationCache):

    Don't allow styles with explicitly inherited properties to be cached at all.
        
(WebCore::CSSStyleSelector::applyMatchedDeclarations):
        
    If the parent inherited styles are equal reuse the cache entry fully and return without
    doing anything else.
        
* css/CSSStyleSelector.h:
* rendering/style/RenderStyle.cpp:
(WebCore::RenderStyle::inheritedDataShared):
* rendering/style/RenderStyle.h:
        
    Add fast check for equal inherited properties.

Modified Paths

Diff

Modified: trunk/Source/WebCore/ChangeLog (101523 => 101524)


--- trunk/Source/WebCore/ChangeLog	2011-11-30 17:16:45 UTC (rev 101523)
+++ trunk/Source/WebCore/ChangeLog	2011-11-30 17:25:17 UTC (rev 101524)
@@ -1,3 +1,52 @@
+2011-11-30  Antti Koivisto  <an...@apple.com>
+
+        Reuse cached style fully if the parent inherited styles are equal 
+        https://bugs.webkit.org/show_bug.cgi?id=73421
+
+        Reviewed by Oliver Hunt.
+
+        The matched declaration cache currently restores the non-inherted properties from the cache
+        entry but still applies all inherited properties normally. In case the current parent
+        inherited style is equivalent to the cache entry's, also the inherited style can be reused
+        and no properties need to be applied. This is faster and saves memory (by sharing the
+        style substructures better).
+        
+        The new optimized code path has a pretty good hit rate, >50% of all cases on many pages.
+        
+        Loading the HTML5 spec this reduces style memory consumption by ~20% (5MB, ~2.5% of total) and 
+        speeds up style applying by ~25% for ~0.4s (2-3%) gain in the spec loading benchmark.
+        
+        * css/CSSStyleSelector.cpp:
+        (WebCore::CSSStyleSelector::applyDeclaration):
+        (WebCore::CSSStyleSelector::applyDeclarations):
+        
+            Remove the code that dynamically disables inherited only applying. We now don't allow
+            styles with explicitly inherited properties to be cached in the first place.
+        
+        (WebCore::CSSStyleSelector::findFromMatchedDeclarationCache):
+        
+            Return the full cache item.
+        
+        (WebCore::CSSStyleSelector::addToMatchedDeclarationCache):
+        
+            Also the parent style is now needed for the check for full sharing.
+        
+        (WebCore::isCacheableInMatchedDeclarationCache):
+
+            Don't allow styles with explicitly inherited properties to be cached at all.
+        
+        (WebCore::CSSStyleSelector::applyMatchedDeclarations):
+        
+            If the parent inherited styles are equal reuse the cache entry fully and return without
+            doing anything else.
+        
+        * css/CSSStyleSelector.h:
+        * rendering/style/RenderStyle.cpp:
+        (WebCore::RenderStyle::inheritedDataShared):
+        * rendering/style/RenderStyle.h:
+        
+            Add fast check for equal inherited properties.
+
 2011-11-30  Renata Hodovan  <r...@webkit.org>
 
         CG buildfix after r101517.

Modified: trunk/Source/WebCore/css/CSSStyleSelector.cpp (101523 => 101524)


--- trunk/Source/WebCore/css/CSSStyleSelector.cpp	2011-11-30 17:16:45 UTC (rev 101523)
+++ trunk/Source/WebCore/css/CSSStyleSelector.cpp	2011-11-30 17:25:17 UTC (rev 101524)
@@ -2119,7 +2119,7 @@
 }
 
 template <bool applyFirst>
-void CSSStyleSelector::applyDeclaration(CSSMutableStyleDeclaration* styleDeclaration, bool isImportant, bool& inheritedOnly)
+void CSSStyleSelector::applyDeclaration(CSSMutableStyleDeclaration* styleDeclaration, bool isImportant, bool inheritedOnly)
 {
     CSSMutableStyleDeclaration::const_iterator end = styleDeclaration->end();
     for (CSSMutableStyleDeclaration::const_iterator it = styleDeclaration->begin(); it != end; ++it) {
@@ -2127,12 +2127,11 @@
         if (isImportant != current.isImportant())
             continue;
         if (inheritedOnly && !current.isInherited()) {
-            if (!current.value()->isInheritedValue())
-                continue;
             // If the property value is explicitly inherited, we need to apply further non-inherited properties
-            // as they might override the value inherited here. This is really per-property but that is
-            // probably not worth optimizing for.
-            inheritedOnly = false;
+            // as they might override the value inherited here. For this reason we don't allow declarations with
+            // explicitly inherited properties to be cached.
+            ASSERT(!current.value()->isInheritedValue());
+            continue;
         }
         int property = current.id();
         if (applyFirst) {
@@ -2156,7 +2155,7 @@
 }
 
 template <bool applyFirst>
-void CSSStyleSelector::applyDeclarations(bool isImportant, int startIndex, int endIndex, bool& inheritedOnly)
+void CSSStyleSelector::applyDeclarations(bool isImportant, int startIndex, int endIndex, bool inheritedOnly)
 {
     if (startIndex == -1)
         return;
@@ -2210,7 +2209,7 @@
     return !(a == b);
 }
 
-const RenderStyle* CSSStyleSelector::findFromMatchedDeclarationCache(unsigned hash, const MatchResult& matchResult)
+const CSSStyleSelector::MatchedStyleDeclarationCacheItem* CSSStyleSelector::findFromMatchedDeclarationCache(unsigned hash, const MatchResult& matchResult)
 {
     ASSERT(hash);
 
@@ -2229,18 +2228,19 @@
     }
     if (cacheItem.matchResult != matchResult)
         return 0;
-    return cacheItem.renderStyle.get();
+    return &cacheItem;
 }
 
-void CSSStyleSelector::addToMatchedDeclarationCache(const RenderStyle* style, unsigned hash, const MatchResult& matchResult)
+void CSSStyleSelector::addToMatchedDeclarationCache(const RenderStyle* style, const RenderStyle* parentStyle, unsigned hash, const MatchResult& matchResult)
 {
     ASSERT(hash);
     MatchedStyleDeclarationCacheItem cacheItem;
     cacheItem.matchedStyleDeclarations.append(m_matchedDecls);
     cacheItem.matchResult = matchResult;
     // Note that we don't cache the original RenderStyle instance. It may be further modified.
-    // The RenderStyle in the cache is really just a holder for the non-inherited substructures and never used as-is.
+    // The RenderStyle in the cache is really just a holder for the substructures and never used as-is.
     cacheItem.renderStyle = RenderStyle::clone(style);
+    cacheItem.parentRenderStyle = RenderStyle::clone(parentStyle);
     m_matchStyleDeclarationCache.add(hash, cacheItem);
 }
 
@@ -2252,6 +2252,9 @@
         return false;
     if (style->zoom() != RenderStyle::initialZoom())
         return false;
+    // The cache assumes static knowledge about which properties are inherited.
+    if (parentStyle->hasExplicitlyInheritedProperties())
+        return false;
     return true;
 }
 
@@ -2259,12 +2262,21 @@
 {
     unsigned cacheHash = matchResult.isCacheable ? computeDeclarationHash(m_matchedDecls.data(), m_matchedDecls.size()) : 0;
     bool applyInheritedOnly = false;
-    const RenderStyle* cachedStyle = 0;
-    if (cacheHash && (cachedStyle = findFromMatchedDeclarationCache(cacheHash, matchResult))) {
+    const MatchedStyleDeclarationCacheItem* cacheItem = 0;
+    if (cacheHash && (cacheItem = findFromMatchedDeclarationCache(cacheHash, matchResult))) {
         // We can build up the style by copying non-inherited properties from an earlier style object built using the same exact
         // style declarations. We then only need to apply the inherited properties, if any, as their values can depend on the 
         // element context. This is fast and saves memory by reusing the style data structures.
-        m_style->copyNonInheritedFrom(cachedStyle);
+        m_style->copyNonInheritedFrom(cacheItem->renderStyle.get());
+        if (m_parentStyle->inheritedDataShared(cacheItem->parentRenderStyle.get())) {
+            EInsideLink linkStatus = m_style->insideLink();
+            // If the cache item parent style has identical inherited properties to the current parent style then the
+            // resulting style will be identical too. We copy the inherited properties over from the cache and are done.
+            m_style->inheritFrom(cacheItem->renderStyle.get());
+            // Unfortunately the link status is treated like an inherited property. We need to explicitly restore it.
+            m_style->setInsideLink(linkStatus);
+            return;
+        }
         applyInheritedOnly = true; 
     }
     // Now we have all of the matched rules in the appropriate order. Walk the rules and apply
@@ -2277,7 +2289,7 @@
     applyDeclarations<true>(true, matchResult.firstUserRule, matchResult.lastUserRule, applyInheritedOnly);
     applyDeclarations<true>(true, matchResult.firstUARule, matchResult.lastUARule, applyInheritedOnly);
 
-    if (cachedStyle && cachedStyle->effectiveZoom() != m_style->effectiveZoom()) {
+    if (cacheItem && cacheItem->renderStyle->effectiveZoom() != m_style->effectiveZoom()) {
         m_fontDirty = true;
         applyInheritedOnly = false;
     }
@@ -2290,7 +2302,7 @@
         applyProperty(CSSPropertyLineHeight, m_lineHeightValue);
 
     // Many properties depend on the font. If it changes we just apply all properties.
-    if (cachedStyle && cachedStyle->fontDescription() != m_style->fontDescription())
+    if (cacheItem && cacheItem->renderStyle->fontDescription() != m_style->fontDescription())
         applyInheritedOnly = false;
 
     // Now do the normal priority UA properties.
@@ -2313,11 +2325,11 @@
     
     ASSERT(!m_fontDirty);
     
-    if (cachedStyle || !cacheHash)
+    if (cacheItem || !cacheHash)
         return;
     if (!isCacheableInMatchedDeclarationCache(m_style.get(), m_parentStyle))
         return;
-    addToMatchedDeclarationCache(m_style.get(), cacheHash, matchResult);
+    addToMatchedDeclarationCache(m_style.get(), m_parentStyle, cacheHash, matchResult);
 }
 
 void CSSStyleSelector::matchPageRules(RuleSet* rules, bool isLeftPage, bool isFirstPage, const String& pageName)

Modified: trunk/Source/WebCore/css/CSSStyleSelector.h (101523 => 101524)


--- trunk/Source/WebCore/css/CSSStyleSelector.h	2011-11-30 17:16:45 UTC (rev 101523)
+++ trunk/Source/WebCore/css/CSSStyleSelector.h	2011-11-30 17:25:17 UTC (rev 101524)
@@ -265,9 +265,9 @@
 
     void applyMatchedDeclarations(const MatchResult&);
     template <bool firstPass>
-    void applyDeclarations(bool important, int startIndex, int endIndex, bool& inheritedOnly);
+    void applyDeclarations(bool important, int startIndex, int endIndex, bool inheritedOnly);
     template <bool firstPass>
-    void applyDeclaration(CSSMutableStyleDeclaration*, bool isImportant, bool& inheritedOnly);
+    void applyDeclaration(CSSMutableStyleDeclaration*, bool isImportant, bool inheritedOnly);
 
     void matchPageRules(RuleSet*, bool isLeftPage, bool isFirstPage, const String& pageName);
     void matchPageRulesForList(const Vector<RuleData>*, bool isLeftPage, bool isFirstPage, const String& pageName);
@@ -349,20 +349,21 @@
         unsigned linkMatchType;
     };
     static unsigned computeDeclarationHash(MatchedStyleDeclaration*, unsigned size);
-    const RenderStyle* findFromMatchedDeclarationCache(unsigned hash, const MatchResult&);   
-    void addToMatchedDeclarationCache(const RenderStyle*, unsigned hash, const MatchResult&);
+    struct MatchedStyleDeclarationCacheItem {
+        Vector<MatchedStyleDeclaration> matchedStyleDeclarations;
+        MatchResult matchResult;
+        RefPtr<RenderStyle> renderStyle;
+        RefPtr<RenderStyle> parentRenderStyle;
+    };
+    const MatchedStyleDeclarationCacheItem* findFromMatchedDeclarationCache(unsigned hash, const MatchResult&);
+    void addToMatchedDeclarationCache(const RenderStyle*, const RenderStyle* parentStyle, unsigned hash, const MatchResult&);
 
     // We collect the set of decls that match in |m_matchedDecls|. We then walk the
     // set of matched decls four times, once for those properties that others depend on (like font-size),
     // and then a second time for all the remaining properties. We then do the same two passes
     // for any !important rules.
     Vector<MatchedStyleDeclaration, 64> m_matchedDecls;
-    
-    struct MatchedStyleDeclarationCacheItem {
-        Vector<MatchedStyleDeclaration> matchedStyleDeclarations;
-        MatchResult matchResult;
-        RefPtr<RenderStyle> renderStyle;
-    };
+
     typedef HashMap<unsigned, MatchedStyleDeclarationCacheItem> MatchedStyleDeclarationCache;
     MatchedStyleDeclarationCache m_matchStyleDeclarationCache;
 

Modified: trunk/Source/WebCore/rendering/style/RenderStyle.cpp (101523 => 101524)


--- trunk/Source/WebCore/rendering/style/RenderStyle.cpp	2011-11-30 17:16:45 UTC (rev 101523)
+++ trunk/Source/WebCore/rendering/style/RenderStyle.cpp	2011-11-30 17:25:17 UTC (rev 101524)
@@ -321,6 +321,17 @@
            || rareInheritedData != other->rareInheritedData;
 }
 
+bool RenderStyle::inheritedDataShared(const RenderStyle* other) const
+{
+    // This is a fast check that only looks if the data structures are shared.
+    return inherited_flags == other->inherited_flags
+        && inherited.get() == other->inherited.get()
+#if ENABLE(SVG)
+        && m_svgStyle.get() == other->m_svgStyle.get()
+#endif
+        && rareInheritedData.get() == other->rareInheritedData.get();
+}
+
 static bool positionedObjectMoved(const LengthBox& a, const LengthBox& b)
 {
     // If any unit types are different, then we can't guarantee

Modified: trunk/Source/WebCore/rendering/style/RenderStyle.h (101523 => 101524)


--- trunk/Source/WebCore/rendering/style/RenderStyle.h	2011-11-30 17:16:45 UTC (rev 101523)
+++ trunk/Source/WebCore/rendering/style/RenderStyle.h	2011-11-30 17:25:17 UTC (rev 101524)
@@ -1343,6 +1343,7 @@
     const AtomicString& hyphenString() const;
 
     bool inheritedNotEqual(const RenderStyle*) const;
+    bool inheritedDataShared(const RenderStyle*) const;
 
     StyleDifference diff(const RenderStyle*, unsigned& changedContextSensitiveProperties) const;
 
_______________________________________________
webkit-changes mailing list
webkit-changes@lists.webkit.org
http://lists.webkit.org/mailman/listinfo.cgi/webkit-changes

Reply via email to