Changeset 30667 in webkit


Ignore:
Timestamp:
Feb 29, 2008 10:58:06 AM (16 years ago)
Author:
hyatt@apple.com
Message:

<rdar://problem/5755916> REGRESSION: Loading HTML5 spec is 5x slower on TOT than in 3.0.4

Improve the performance of dynamic sibling and CSS3 selectors so that there is no slowdown any more.
Be more precise in terms of what nodes we mark dirty.

Reviewed by Beth

  • css/CSSStyleSelector.cpp: (WebCore::CSSStyleSelector::checkSelector):
  • dom/Element.cpp: (WebCore::Element::recalcStyle): (WebCore::checkForSiblingStyleChanges): (WebCore::Element::childrenChanged): (WebCore::Element::finishParsingChildren):
  • rendering/RenderStyle.cpp: (WebCore::RenderStyle::RenderStyle):
  • rendering/RenderStyle.h: (WebCore::RenderStyle::childrenAffectedByPositionalRules): (WebCore::RenderStyle::childrenAffectedByDirectAdjacentRules): (WebCore::RenderStyle::setChildrenAffectedByDirectAdjacentRules):
Location:
trunk/WebCore
Files:
5 edited

Legend:

Unmodified
Added
Removed
  • trunk/WebCore/ChangeLog

    r30665 r30667  
     12008-02-29  David Hyatt  <hyatt@apple.com>
     2
     3        <rdar://problem/5755916> REGRESSION: Loading HTML5 spec is 5x slower on TOT than in 3.0.4
     4
     5        Improve the performance of dynamic sibling and CSS3 selectors so that there is no slowdown any more.
     6        Be more precise in terms of what nodes we mark dirty.
     7
     8        Reviewed by Beth
     9
     10        * css/CSSStyleSelector.cpp:
     11        (WebCore::CSSStyleSelector::checkSelector):
     12        * dom/Element.cpp:
     13        (WebCore::Element::recalcStyle):
     14        (WebCore::checkForSiblingStyleChanges):
     15        (WebCore::Element::childrenChanged):
     16        (WebCore::Element::finishParsingChildren):
     17        * rendering/RenderStyle.cpp:
     18        (WebCore::RenderStyle::RenderStyle):
     19        * rendering/RenderStyle.h:
     20        (WebCore::RenderStyle::childrenAffectedByPositionalRules):
     21        (WebCore::RenderStyle::childrenAffectedByDirectAdjacentRules):
     22        (WebCore::RenderStyle::setChildrenAffectedByDirectAdjacentRules):
     23
    1242008-02-29  Alexey Proskuryakov  <ap@webkit.org>
    225
  • trunk/WebCore/css/CSSStyleSelector.cpp

    r30593 r30667  
    14301430                RenderStyle* parentStyle = (m_element == e) ? m_parentStyle : e->parentNode()->renderStyle();
    14311431                if (parentStyle)
    1432                     parentStyle->setChildrenAffectedByForwardPositionalRules();
     1432                    parentStyle->setChildrenAffectedByDirectAdjacentRules();
    14331433            }
    14341434            Node* n = e->previousSibling();
  • trunk/WebCore/dom/Element.cpp

    r30633 r30667  
    707707    RenderStyle* currentStyle = renderStyle();
    708708    bool hasParentStyle = parentNode() ? parentNode()->renderStyle() : false;
    709     bool hasPositionalChildren = currentStyle && (currentStyle->childrenAffectedByFirstChildRules() || currentStyle->childrenAffectedByLastChildRules() ||
    710                                                   currentStyle->childrenAffectedByForwardPositionalRules() || currentStyle->childrenAffectedByBackwardPositionalRules());
     709    bool hasPositionalRules = changed() && currentStyle && currentStyle->childrenAffectedByPositionalRules();
    711710
    712711#if ENABLE(SVG)
     
    751750            if (currentStyle->childrenAffectedByLastChildRules())
    752751                newStyle->setChildrenAffectedByLastChildRules();
     752            if (currentStyle->childrenAffectedByDirectAdjacentRules())
     753                newStyle->setChildrenAffectedByDirectAdjacentRules();
    753754        }
    754755
     
    769770
    770771        if (change != Force) {
    771             if ((document()->usesDescendantRules() || hasPositionalChildren) && styleChangeType() == FullStyleChange)
     772            if ((document()->usesDescendantRules() || hasPositionalRules) && styleChangeType() == FullStyleChange)
    772773                change = Force;
    773774            else
     
    801802}
    802803
    803 static void checkFirstChildRules(Element* e, RenderStyle* style)
    804 {
    805     if (style->childrenAffectedByFirstChildRules()) {
    806         // Check our first two children.  They need to be true and false respectively.
    807         bool checkingFirstChild = true;
    808         for (Node* n = e->firstChild(); n; n = n->nextSibling()) {
    809             if (n->isElementNode()) {
    810                 if (checkingFirstChild) {
    811                     if (n->attached() && n->renderStyle() && !n->renderStyle()->firstChildState())
    812                         n->setChanged();
    813                     checkingFirstChild = false;
    814                 } else {
    815                     if (n->attached() && n->renderStyle() && n->renderStyle()->firstChildState())
    816                         n->setChanged();
    817                     break;
    818                 }
    819             }
    820         }
    821     }
    822 }
    823 
    824 static void checkLastChildRules(Element* e, RenderStyle* style)
    825 {
    826     if (style->childrenAffectedByLastChildRules()) {
    827         // Check our last two children.  They need to be true and false respectively.
    828         bool checkingLastChild = true;
    829         for (Node* n = e->lastChild(); n; n = n->previousSibling()) {
    830             if (n->isElementNode()) {
    831                 if (checkingLastChild) {
    832                     if (n->attached() && n->renderStyle() && !n->renderStyle()->lastChildState())
    833                         n->setChanged();
    834                     checkingLastChild = false;
    835                 } else {
    836                     if (n->attached() && n->renderStyle() && n->renderStyle()->lastChildState())
    837                         n->setChanged();
    838                     break;
    839                 }
    840             }
    841         }
    842     }
    843 }
    844 
    845 static bool checkEmptyRules(Element* e, RenderStyle* style)
    846 {
    847     return style->affectedByEmpty() && (!style->emptyState() || e->hasChildNodes());
    848 }
    849 
    850 static void checkStyleRules(Element* e, RenderStyle* style, bool changedByParser)
    851 {
    852     if (e->changed() || !style)
    853         return;
    854 
    855     if (style->childrenAffectedByBackwardPositionalRules() ||
    856         (!changedByParser && style->childrenAffectedByForwardPositionalRules()) ||
    857         checkEmptyRules(e, style)) {
     804static void checkForSiblingStyleChanges(Element* e, RenderStyle* style, bool finishedParsingCallback,
     805                                        Node* beforeChange, Node* afterChange, int childCountDelta)
     806{
     807    if (!style || (e->changed() && style->childrenAffectedByPositionalRules()))
     808        return;
     809
     810    // :first-child.  In the parser callback case, we don't have to check anything, since we were right the first time.
     811    // In the DOM case, we only need to do something if |afterChange| is not 0.
     812    // |afterChange| is 0 in the parser case, so it works out that we'll skip this block.
     813    if (style->childrenAffectedByFirstChildRules() && afterChange) {
     814        // Find our new first child.
     815        Node* newFirstChild = 0;
     816        for (newFirstChild = e->firstChild(); newFirstChild && !newFirstChild->isElementNode(); newFirstChild = newFirstChild->nextSibling()) {};
     817       
     818        // Find the first element node following |afterChange|
     819        Node* firstElementAfterInsertion = 0;
     820        for (firstElementAfterInsertion = afterChange;
     821             firstElementAfterInsertion && !firstElementAfterInsertion->isElementNode();
     822             firstElementAfterInsertion = firstElementAfterInsertion->nextSibling()) {};
     823       
     824        // This is the insert/append case.
     825        if (newFirstChild != firstElementAfterInsertion && firstElementAfterInsertion && firstElementAfterInsertion->attached() &&
     826            firstElementAfterInsertion->renderStyle() && firstElementAfterInsertion->renderStyle()->firstChildState())
     827            firstElementAfterInsertion->setChanged();
     828           
     829        // We also have to handle node removal.
     830        if (childCountDelta < 0 && newFirstChild == firstElementAfterInsertion && newFirstChild && newFirstChild->renderStyle() && !newFirstChild->renderStyle()->firstChildState())
     831            newFirstChild->setChanged();
     832    }
     833
     834    // :last-child.  In the parser callback case, we don't have to check anything, since we were right the first time.
     835    // In the DOM case, we only need to do something if |afterChange| is not 0.
     836    if (style->childrenAffectedByLastChildRules() && beforeChange) {
     837        // Find our new last child.
     838        Node* newLastChild = 0;
     839        for (newLastChild = e->lastChild(); newLastChild && !newLastChild->isElementNode(); newLastChild = newLastChild->previousSibling()) {};
     840       
     841        // Find the last element node going backwards from |beforeChange|
     842        Node* lastElementBeforeInsertion = 0;
     843        for (lastElementBeforeInsertion = beforeChange;
     844             lastElementBeforeInsertion && !lastElementBeforeInsertion->isElementNode();
     845             lastElementBeforeInsertion = lastElementBeforeInsertion->previousSibling()) {};
     846       
     847        if (newLastChild != lastElementBeforeInsertion && lastElementBeforeInsertion && lastElementBeforeInsertion->attached() &&
     848            lastElementBeforeInsertion->renderStyle() && lastElementBeforeInsertion->renderStyle()->lastChildState())
     849            lastElementBeforeInsertion->setChanged();
     850           
     851        // We also have to handle node removal.  The parser callback case is similar to node removal as well in that we need to change the last child
     852        // to match now.
     853        if ((childCountDelta < 0 || finishedParsingCallback) && newLastChild == lastElementBeforeInsertion && newLastChild && newLastChild->renderStyle() && !newLastChild->renderStyle()->lastChildState())
     854            newLastChild->setChanged();
     855    }
     856
     857    // The + selector.  We need to invalidate the first element following the insertion point.  It is the only possible element
     858    // that could be affected by this DOM change.
     859    if (style->childrenAffectedByDirectAdjacentRules() && afterChange) {
     860        Node* firstElementAfterInsertion = 0;
     861        for (firstElementAfterInsertion = afterChange;
     862             firstElementAfterInsertion && !firstElementAfterInsertion->isElementNode();
     863             firstElementAfterInsertion = firstElementAfterInsertion->nextSibling()) {};
     864        if (firstElementAfterInsertion && firstElementAfterInsertion->attached())
     865            firstElementAfterInsertion->setChanged();
     866    }
     867
     868    // Forward positional selectors include the ~ selector, nth-child, nth-of-type, first-of-type and only-of-type.
     869    // Backward positional selectors include nth-last-child, nth-last-of-type, last-of-type and only-of-type.
     870    // We have to invalidate everything following the insertion point in the forward case, and everything before the insertion point in the
     871    // backward case.
     872    // |afterChange| is 0 in the parser callback case, so we won't do any work for the forward case if we don't have to.
     873    // For performance reasons we just mark the parent node as changed, since we don't want to make childrenChanged O(n^2) by crawling all our kids
     874    // here.  recalcStyle will then force a walk of the children when it sees that this has happened.
     875    if ((style->childrenAffectedByForwardPositionalRules() && afterChange) ||
     876        (style->childrenAffectedByBackwardPositionalRules() && beforeChange))
    858877        e->setChanged();
    859         return;
    860     }
    861 
    862     checkFirstChildRules(e, style);
    863     checkLastChildRules(e, style);
     878   
     879    // :empty selector.
     880    if (style->affectedByEmpty() && (!style->emptyState() || e->hasChildNodes()))
     881        e->setChanged();
    864882}
    865883
     
    868886    ContainerNode::childrenChanged(changedByParser, beforeChange, afterChange, childCountDelta);
    869887    if (!changedByParser)
    870         checkStyleRules(this, renderStyle(), false);
     888        checkForSiblingStyleChanges(this, renderStyle(), false, beforeChange, afterChange, childCountDelta);
    871889}
    872890
     
    875893    ContainerNode::finishParsingChildren();
    876894    m_parsingChildrenFinished = true;
    877     checkStyleRules(this, renderStyle(), true);
     895    checkForSiblingStyleChanges(this, renderStyle(), true, lastChild(), 0, 0);
    878896}
    879897
  • trunk/WebCore/rendering/RenderStyle.cpp

    r30573 r30667  
    951951    , m_childrenAffectedByFirstChildRules(false)
    952952    , m_childrenAffectedByLastChildRules(false)
     953    , m_childrenAffectedByDirectAdjacentRules(false)
    953954    , m_childrenAffectedByForwardPositionalRules(false)
    954955    , m_childrenAffectedByBackwardPositionalRules(false)
     
    973974    , m_childrenAffectedByFirstChildRules(false)
    974975    , m_childrenAffectedByLastChildRules(false)
     976    , m_childrenAffectedByDirectAdjacentRules(false)
    975977    , m_childrenAffectedByForwardPositionalRules(false)
    976978    , m_childrenAffectedByBackwardPositionalRules(false)
     
    10171019    , m_childrenAffectedByFirstChildRules(false)
    10181020    , m_childrenAffectedByLastChildRules(false)
     1021    , m_childrenAffectedByDirectAdjacentRules(false)
    10191022    , m_childrenAffectedByForwardPositionalRules(false)
    10201023    , m_childrenAffectedByBackwardPositionalRules(false)
  • trunk/WebCore/rendering/RenderStyle.h

    r30577 r30667  
    15151515    bool m_childrenAffectedByFirstChildRules : 1;
    15161516    bool m_childrenAffectedByLastChildRules  : 1;
     1517    bool m_childrenAffectedByDirectAdjacentRules : 1;
    15171518    bool m_childrenAffectedByForwardPositionalRules : 1;
    15181519    bool m_childrenAffectedByBackwardPositionalRules : 1;
    15191520    bool m_firstChildState : 1;
    15201521    bool m_lastChildState : 1;
    1521     unsigned m_childIndex : 19; // Plenty of bits to cache an index.
     1522    unsigned m_childIndex : 18; // Plenty of bits to cache an index.
    15221523
    15231524    int m_ref;
     
    21662167    bool emptyState() const { return m_emptyState; }
    21672168    void setEmptyState(bool b) { m_affectedByEmpty = true; m_unique = true; m_emptyState = b; }
     2169    bool childrenAffectedByPositionalRules() const { return childrenAffectedByForwardPositionalRules() || childrenAffectedByBackwardPositionalRules(); }
    21682170    bool childrenAffectedByFirstChildRules() const { return m_childrenAffectedByFirstChildRules; }
    21692171    void setChildrenAffectedByFirstChildRules() { m_childrenAffectedByFirstChildRules = true; }
    21702172    bool childrenAffectedByLastChildRules() const { return m_childrenAffectedByLastChildRules; }
    21712173    void setChildrenAffectedByLastChildRules() { m_childrenAffectedByLastChildRules = true; }
     2174    bool childrenAffectedByDirectAdjacentRules() const { return m_childrenAffectedByDirectAdjacentRules; }
     2175    void setChildrenAffectedByDirectAdjacentRules() { m_childrenAffectedByDirectAdjacentRules = true; }
    21722176    bool childrenAffectedByForwardPositionalRules() const { return m_childrenAffectedByForwardPositionalRules; }
    21732177    void setChildrenAffectedByForwardPositionalRules() { m_childrenAffectedByForwardPositionalRules = true; }
Note: See TracChangeset for help on using the changeset viewer.