Changeset 122637 in webkit


Ignore:
Timestamp:
Jul 13, 2012 3:44:46 PM (12 years ago)
Author:
rniwa@webkit.org
Message:

NodeLists should not invalidate on irreleavnt attribute changes
https://bugs.webkit.org/show_bug.cgi?id=91277

Reviewed by Ojan Vafai.

Explicitely check the invalidation type and the changed attribute in NodeListNodeData::invalidateCaches
and ElementRareData::clearHTMLCollectionCaches to only invalidate node lists affected by the change.

Also merged invalidateNodeListsCacheAfterAttributeChanged and invalidateNodeListsCacheAfterChildrenChanged
as invalidateNodeListCachesInAncestors since they're almost identical after r122498.

In addition, moved shouldInvalidateNodeListForType from Document.cpp to DynamicNodeList.h and renamed it to
shouldInvalidateTypeOnAttributeChange since it needs to called in Node.cpp and ElementRareData.h.

  • dom/Attr.cpp:

(WebCore::Attr::setValue):
(WebCore::Attr::childrenChanged):

  • dom/ContainerNode.cpp:

(WebCore::ContainerNode::childrenChanged):

  • dom/Document.cpp:

(WebCore::Document::registerNodeListCache): Calls isRootedAtDocument() instead of directly comparing
the value of NodeListRootType in order to prepare for the bug 80269.
(WebCore::Document::unregisterNodeListCache): Ditto.
(WebCore): shouldInvalidateNodeListForType is moved to DynamicNodeList.h
(WebCore::Document::shouldInvalidateNodeListCaches):

  • dom/DynamicNodeList.h:

(DynamicNodeListCacheBase):
(WebCore::DynamicNodeListCacheBase::shouldInvalidateTypeOnAttributeChange): Moved from Document.cpp.

  • dom/Element.cpp:

(WebCore::Element::attributeChanged):

  • dom/ElementRareData.h:

(WebCore::ElementRareData::clearHTMLCollectionCaches): Takes const QualifiedName* to compare against
the invalidation type of HTML collections via shouldInvalidateTypeOnAttributeChange.

  • dom/Node.cpp:

(WebCore::Node::invalidateNodeListCachesInAncestors): Merged invalidateNodeListCachesInAncestors and
invalidateNodeListsCacheAfterChildrenChanged. Also pass attrName to clearHTMLCollectionCaches.
(WebCore::NodeListsNodeData::invalidateCaches): Compares attrName against the invalidation type of
node lists via shouldInvalidateTypeOnAttributeChange.
(WebCore):

  • dom/Node.h:

(Node):

  • dom/NodeRareData.h:

(WebCore::NodeRareData::ensureNodeLists): Merged NodeRareData::createNodeLists.
(WebCore::NodeRareData::clearChildNodeListCache): Moved from Node.cpp.
(NodeRareData):

  • html/HTMLCollection.h:

(HTMLCollectionCacheBase):

Location:
trunk/Source/WebCore
Files:
11 edited

Legend:

Unmodified
Added
Removed
  • trunk/Source/WebCore/ChangeLog

    r122636 r122637  
     12012-07-13  Ryosuke Niwa  <rniwa@webkit.org>
     2
     3        NodeLists should not invalidate on irreleavnt attribute changes
     4        https://bugs.webkit.org/show_bug.cgi?id=91277
     5
     6        Reviewed by Ojan Vafai.
     7
     8        Explicitely check the invalidation type and the changed attribute in NodeListNodeData::invalidateCaches
     9        and ElementRareData::clearHTMLCollectionCaches to only invalidate node lists affected by the change.
     10
     11        Also merged invalidateNodeListsCacheAfterAttributeChanged and invalidateNodeListsCacheAfterChildrenChanged
     12        as invalidateNodeListCachesInAncestors since they're almost identical after r122498.
     13
     14        In addition, moved shouldInvalidateNodeListForType from Document.cpp to DynamicNodeList.h and renamed it to
     15        shouldInvalidateTypeOnAttributeChange since it needs to called in Node.cpp and ElementRareData.h.
     16
     17        * dom/Attr.cpp:
     18        (WebCore::Attr::setValue):
     19        (WebCore::Attr::childrenChanged):
     20        * dom/ContainerNode.cpp:
     21        (WebCore::ContainerNode::childrenChanged):
     22        * dom/Document.cpp:
     23        (WebCore::Document::registerNodeListCache): Calls isRootedAtDocument() instead of directly comparing
     24        the value of NodeListRootType in order to prepare for the bug 80269.
     25        (WebCore::Document::unregisterNodeListCache): Ditto.
     26        (WebCore): shouldInvalidateNodeListForType is moved to DynamicNodeList.h
     27        (WebCore::Document::shouldInvalidateNodeListCaches):
     28        * dom/DynamicNodeList.h:
     29        (DynamicNodeListCacheBase):
     30        (WebCore::DynamicNodeListCacheBase::shouldInvalidateTypeOnAttributeChange): Moved from Document.cpp.
     31        * dom/Element.cpp:
     32        (WebCore::Element::attributeChanged):
     33        * dom/ElementRareData.h:
     34        (WebCore::ElementRareData::clearHTMLCollectionCaches): Takes const QualifiedName* to compare against
     35        the invalidation type of HTML collections via shouldInvalidateTypeOnAttributeChange.
     36        * dom/Node.cpp:
     37        (WebCore::Node::invalidateNodeListCachesInAncestors): Merged invalidateNodeListCachesInAncestors and
     38        invalidateNodeListsCacheAfterChildrenChanged. Also pass attrName to clearHTMLCollectionCaches.
     39        (WebCore::NodeListsNodeData::invalidateCaches): Compares attrName against the invalidation type of
     40        node lists via shouldInvalidateTypeOnAttributeChange.
     41        (WebCore):
     42        * dom/Node.h:
     43        (Node):
     44        * dom/NodeRareData.h:
     45        (WebCore::NodeRareData::ensureNodeLists): Merged NodeRareData::createNodeLists.
     46        (WebCore::NodeRareData::clearChildNodeListCache): Moved from Node.cpp.
     47        (NodeRareData):
     48        * html/HTMLCollection.h:
     49        (HTMLCollectionCacheBase):
     50
    1512012-07-13  Arpita Bahuguna  <arpitabahuguna@gmail.com>
    252
  • trunk/Source/WebCore/dom/Attr.cpp

    r117956 r122637  
    120120    m_ignoreChildrenChanged--;
    121121
    122     invalidateNodeListsCacheAfterAttributeChanged(m_name, m_element);
     122    invalidateNodeListCachesInAncestors(&m_name, m_element);
    123123}
    124124
     
    163163        return;
    164164
    165     invalidateNodeListsCacheAfterAttributeChanged(qualifiedName(), m_element);
     165    invalidateNodeListCachesInAncestors(&qualifiedName(), m_element);
    166166
    167167    // FIXME: We should include entity references in the value
  • trunk/Source/WebCore/dom/ContainerNode.cpp

    r119937 r122637  
    681681    if (!changedByParser && childCountDelta)
    682682        document()->updateRangesAfterChildrenChanged(this);
    683     invalidateNodeListsCacheAfterChildrenChanged();
     683    invalidateNodeListCachesInAncestors();
    684684}
    685685
  • trunk/Source/WebCore/dom/Document.cpp

    r122626 r122637  
    38723872        m_nodeListCounts[InvalidateOnIdNameAttrChange]++;
    38733873    m_nodeListCounts[list->invalidationType()]++;
    3874     if (list->rootType() == NodeListIsRootedAtDocument)
     3874    if (list->isRootedAtDocument())
    38753875        m_listsInvalidatedAtDocument.add(list);
    38763876}
     
    38813881        m_nodeListCounts[InvalidateOnIdNameAttrChange]--;
    38823882    m_nodeListCounts[list->invalidationType()]--;
    3883     if (list->rootType() == NodeListIsRootedAtDocument) {
     3883    if (list->isRootedAtDocument()) {
    38843884        ASSERT(m_listsInvalidatedAtDocument.contains(list));
    38853885        m_listsInvalidatedAtDocument.remove(list);
     
    38873887}
    38883888
    3889 static ALWAYS_INLINE bool shouldInvalidateNodeListForType(NodeListInvalidationType type, const QualifiedName& attrName)
    3890 {
    3891     switch (type) {
    3892     case InvalidateOnClassAttrChange:
    3893         return attrName == classAttr;
    3894     case InvalidateOnNameAttrChange:
    3895         return attrName == nameAttr;
    3896     case InvalidateOnIdNameAttrChange:
    3897         return attrName == idAttr || attrName == nameAttr;
    3898     case InvalidateOnForAttrChange:
    3899         return attrName == forAttr;
    3900     case InvalidateForFormControls:
    3901         return attrName == nameAttr || attrName == idAttr || attrName == forAttr || attrName == typeAttr;
    3902     case InvalidateOnHRefAttrChange:
    3903         return attrName == hrefAttr;
    3904     case InvalidateOnItemAttrChange:
    3905 #if ENABLE(MICRODATA)
    3906         return attrName == itemscopeAttr || attrName == itempropAttr || attrName == itemtypeAttr;
    3907 #endif // Intentionally fall through
    3908     case DoNotInvalidateOnAttributeChanges:
    3909         ASSERT_NOT_REACHED();
    3910         return false;
    3911     case InvalidateOnAnyAttrChange:
    3912         return true;
    3913     }
    3914     return false;
    3915 }
    3916 
    39173889bool Document::shouldInvalidateNodeListCaches(const QualifiedName* attrName) const
    39183890{
    39193891    if (attrName) {
    39203892        for (int type = DoNotInvalidateOnAttributeChanges + 1; type < numNodeListInvalidationTypes; type++) {
    3921             if (m_nodeListCounts[type] && shouldInvalidateNodeListForType(static_cast<NodeListInvalidationType>(type), *attrName))
     3893            if (m_nodeListCounts[type] && DynamicNodeListCacheBase::shouldInvalidateTypeOnAttributeChange(static_cast<NodeListInvalidationType>(type), *attrName))
    39223894                return true;
    39233895        }
  • trunk/Source/WebCore/dom/DynamicNodeList.h

    r122621 r122637  
    2727#include "CollectionType.h"
    2828#include "Document.h"
     29#include "HTMLNames.h"
    2930#include "NodeList.h"
    3031#include <wtf/Forward.h>
     
    5859public:
    5960    ALWAYS_INLINE bool isRootedAtDocument() const { return m_rootedAtDocument; }
    60     ALWAYS_INLINE bool shouldInvalidateOnAttributeChange() const { return m_invalidationType != DoNotInvalidateOnAttributeChanges; }
    61     ALWAYS_INLINE NodeListRootType rootType() { return m_rootedAtDocument ? NodeListIsRootedAtDocument : NodeListIsRootedAtNode; }
    6261    ALWAYS_INLINE NodeListInvalidationType invalidationType() const { return static_cast<NodeListInvalidationType>(m_invalidationType); }
    6362    ALWAYS_INLINE CollectionType type() const { return static_cast<CollectionType>(m_collectionType); }
    6463
    6564    void invalidateCache() const;
     65
     66    static bool shouldInvalidateTypeOnAttributeChange(NodeListInvalidationType, const QualifiedName&);
    6667
    6768protected:
     
    101102    const unsigned m_collectionType : 5;
    102103};
     104
     105ALWAYS_INLINE bool DynamicNodeListCacheBase::shouldInvalidateTypeOnAttributeChange(NodeListInvalidationType type, const QualifiedName& attrName)
     106{
     107    switch (type) {
     108    case InvalidateOnClassAttrChange:
     109        return attrName == HTMLNames::classAttr;
     110    case InvalidateOnNameAttrChange:
     111        return attrName == HTMLNames::nameAttr;
     112    case InvalidateOnIdNameAttrChange:
     113        return attrName == HTMLNames::idAttr || attrName == HTMLNames::nameAttr;
     114    case InvalidateOnForAttrChange:
     115        return attrName == HTMLNames::forAttr;
     116    case InvalidateForFormControls:
     117        return attrName == HTMLNames::nameAttr || attrName == HTMLNames::idAttr || attrName == HTMLNames::forAttr || attrName == HTMLNames::typeAttr;
     118    case InvalidateOnHRefAttrChange:
     119        return attrName == HTMLNames::hrefAttr;
     120    case InvalidateOnItemAttrChange:
     121#if ENABLE(MICRODATA)
     122        return attrName == HTMLNames::itemscopeAttr || attrName == HTMLNames::itempropAttr || attrName == HTMLNames::itemtypeAttr;
     123#endif // Intentionally fall through
     124    case DoNotInvalidateOnAttributeChanges:
     125        ASSERT_NOT_REACHED();
     126        return false;
     127    case InvalidateOnAnyAttrChange:
     128        return true;
     129    }
     130    return false;
     131}
    103132
    104133class DynamicNodeList : public NodeList, public DynamicNodeListCacheBase {
  • trunk/Source/WebCore/dom/Element.cpp

    r122626 r122637  
    706706    }
    707707
    708     invalidateNodeListsCacheAfterAttributeChanged(attribute.name(), this);
     708    invalidateNodeListCachesInAncestors(&attribute.name(), this);
    709709
    710710    if (!AXObjectCache::accessibilityEnabled())
  • trunk/Source/WebCore/dom/ElementRareData.h

    r122621 r122637  
    6767    }
    6868
    69     void clearHTMLCollectionCaches()
     69    void clearHTMLCollectionCaches(const QualifiedName* attrName)
    7070    {
    7171        if (!m_cachedCollections)
    7272            return;
    7373
     74        bool shouldIgnoreType = !attrName || *attrName == HTMLNames::idAttr || *attrName == HTMLNames::nameAttr;
     75
    7476        for (unsigned i = 0; i < (*m_cachedCollections).size(); i++) {
    75             if ((*m_cachedCollections)[i])
    76                 (*m_cachedCollections)[i]->invalidateCache();
     77            if (HTMLCollection* collection = (*m_cachedCollections)[i]) {
     78                if (shouldIgnoreType || DynamicNodeListCacheBase::shouldInvalidateTypeOnAttributeChange(collection->invalidationType(), *attrName))
     79                    collection->invalidateCache();
     80            }
    7781        }
    7882    }
  • trunk/Source/WebCore/dom/Node.cpp

    r122621 r122637  
    963963}
    964964
    965 void Node::invalidateNodeListsCacheAfterAttributeChanged(const QualifiedName& attrName, Element* attributeOwnerElement)
    966 {
    967     if (hasRareData() && isAttributeNode()) {
    968         NodeRareData* data = rareData();
    969         ASSERT(!data->nodeLists());
    970         data->clearChildNodeListCache();
    971     }
     965void Node::invalidateNodeListCachesInAncestors(const QualifiedName* attrName, Element* attributeOwnerElement)
     966{
     967    if (hasRareData() && (!attrName || isAttributeNode()))
     968        rareData()->clearChildNodeListCache();
    972969
    973970    // Modifications to attributes that are not associated with an Element can't invalidate NodeList caches.
    974     if (!attributeOwnerElement)
    975         return;
    976 
    977     if (!document()->shouldInvalidateNodeListCaches(&attrName))
    978         return;
    979 
    980     document()->clearNodeListCaches();
    981 
    982     for (Node* node = this; node; node = node->parentNode()) {
    983         ASSERT(this == node || !node->isAttributeNode());
    984         if (!node->hasRareData())
    985             continue;
    986         NodeRareData* data = node->rareData();
    987         if (data->nodeLists())
    988             data->nodeLists()->invalidateCaches(&attrName);
    989         if (node->isElementNode())
    990             static_cast<ElementRareData*>(data)->clearHTMLCollectionCaches();
    991     }
    992 }
    993 
    994 void Node::invalidateNodeListsCacheAfterChildrenChanged()
    995 {
    996     if (hasRareData())
    997         rareData()->clearChildNodeListCache();
     971    if (attrName && !attributeOwnerElement)
     972        return;
    998973
    999974    if (!document()->shouldInvalidateNodeListCaches())
     
    1007982        NodeRareData* data = node->rareData();
    1008983        if (data->nodeLists())
    1009             data->nodeLists()->invalidateCaches();
     984            data->nodeLists()->invalidateCaches(attrName);
    1010985        if (node->isElementNode())
    1011             static_cast<ElementRareData*>(data)->clearHTMLCollectionCaches();
     986            static_cast<ElementRareData*>(data)->clearHTMLCollectionCaches(attrName);
    1012987    }
    1013988}
     
    22502225    NodeListAtomicNameCacheMap::const_iterator atomicNameCacheEnd = m_atomicNameCaches.end();
    22512226    for (NodeListAtomicNameCacheMap::const_iterator it = m_atomicNameCaches.begin(); it != atomicNameCacheEnd; ++it) {
    2252         if (!attrName || it->second->shouldInvalidateOnAttributeChange())
    2253             it->second->invalidateCache();
     2227        DynamicNodeList* list = it->second;
     2228        if (!attrName || DynamicNodeListCacheBase::shouldInvalidateTypeOnAttributeChange(list->invalidationType(), *attrName))
     2229            list->invalidateCache();
    22542230    }
    22552231
    22562232    NodeListNameCacheMap::const_iterator nameCacheEnd = m_nameCaches.end();
    22572233    for (NodeListNameCacheMap::const_iterator it = m_nameCaches.begin(); it != nameCacheEnd; ++it) {
    2258         if (!attrName || it->second->shouldInvalidateOnAttributeChange())
    2259             it->second->invalidateCache();
     2234        DynamicNodeList* list = it->second;
     2235        if (!attrName || DynamicNodeListCacheBase::shouldInvalidateTypeOnAttributeChange(list->invalidationType(), *attrName))
     2236            list->invalidateCache();
    22602237    }
    22612238
     
    27732750#endif
    27742751
    2775 void NodeRareData::createNodeLists()
    2776 {
    2777     setNodeLists(NodeListsNodeData::create());
    2778 }
    2779 
    2780 void NodeRareData::clearChildNodeListCache()
    2781 {
    2782     if (m_childNodeList)
    2783         m_childNodeList->invalidateCache();
    2784 }
    2785 
    27862752// It's important not to inline removedLastRef, because we don't want to inline the code to
    27872753// delete a Node at each deref call site.
  • trunk/Source/WebCore/dom/Node.h

    r122159 r122637  
    559559#endif
    560560
    561     void invalidateNodeListsCacheAfterAttributeChanged(const QualifiedName&, Element* attributeOwnerElement);
    562     void invalidateNodeListsCacheAfterChildrenChanged();
     561    void invalidateNodeListCachesInAncestors(const QualifiedName* attrName = 0, Element* attributeOwnerElement = 0);
    563562    NodeListsNodeData* nodeLists();
    564563    void removeCachedChildNodeList();
  • trunk/Source/WebCore/dom/NodeRareData.h

    r122621 r122637  
    223223    {
    224224        if (!m_nodeLists)
    225             createNodeLists();
     225            setNodeLists(NodeListsNodeData::create());
    226226        return m_nodeLists.get();
    227227    }
    228     void clearChildNodeListCache();
     228    void clearChildNodeListCache()
     229    {
     230        if (m_childNodeList)
     231            m_childNodeList->invalidateCache();
     232    }
    229233
    230234    ChildNodeList* childNodeList() const { return m_childNodeList; }
     
    345349
    346350private:
    347     void createNodeLists();
    348351
    349352    TreeScope* m_treeScope;
  • trunk/Source/WebCore/html/HTMLCollection.h

    r122621 r122637  
    6464private:
    6565    using DynamicNodeListCacheBase::isRootedAtDocument;
    66     using DynamicNodeListCacheBase::shouldInvalidateOnAttributeChange;
    6766    using DynamicNodeListCacheBase::setItemCache;
    6867
Note: See TracChangeset for help on using the changeset viewer.