Title: [165103] trunk/Source/WebCore
Revision
165103
Author
[email protected]
Date
2014-03-05 02:41:48 -0800 (Wed, 05 Mar 2014)

Log Message

appendChild shouldn't invalidate LiveNodeLists and HTMLCollections if they don't have valid caches
https://bugs.webkit.org/show_bug.cgi?id=129727

Reviewed by Andreas Kling.

Before this patch, invalidateNodeListAndCollectionCachesInAncestors invalidated node lists and HTML
collections on ancestors of a node whenever we're inserting or removing a child node. This patch
makes HTMLCollections and LiveNodeLists register themselves with Document only when they have valid
caches.

Each user of CollectionIndexCache now implements willValidateIndexCache member function that gets
called when CollectionIndexCache caches any state and necessitates the registration with document.

* dom/ChildNodeList.h: Added an empty willValidateIndexCache since child node lists are never
registered with document.

* dom/CollectionIndexCache.h:
(WebCore::CollectionIndexCache::hasValidCache): Added.
(WebCore::CollectionIndexCache::nodeCount): Calls willValidateIndexCache when caching node count.
(WebCore::CollectionIndexCache::nodeAfterCached): Ditto. Also assert that hasValidCache() true in
the cases where we're simply updating our caches or adding more caches.
(WebCore::CollectionIndexCache::nodeAt): Ditto. Also added a code to set the length cache when
we've reached the end of the list. This should be a slight speed up on some cases.

* dom/Document.cpp:
(WebCore::Document::Document): Initializes a variable used by assertions.
(WebCore::Document::unregisterNodeList): Added an early exit for when m_listsInvalidatedAtDocument
is empty since invalidateNodeListAndCollectionCaches swaps out the list.
(WebCore::Document::registerCollection): Removed the boolean hasIdNameMap since we now explicitly
call collectionCachedIdNameMap in HTMLCollection.
(WebCore::Document::unregisterCollection): Ditto. Exit early if m_collectionsInvalidatedAtDocument
is empty since invalidateNodeListAndCollectionCaches swaps out the list.
* dom/Document.h:

* dom/LiveNodeList.cpp:
(WebCore::LiveNodeList::invalidateCache): Unregister the node list with document if we had caches.
* dom/LiveNodeList.h:
(WebCore::LiveNodeList::LiveNodeList):
(WebCore::LiveNodeList::~LiveNodeList): Ditto.
(WebCore::LiveNodeList::invalidateCache): Pass around document. This is necessary since document()
had already moved to the new document inside NodeListsNodeData::invalidateCaches.
(WebCore::LiveNodeList::willValidateIndexCache): Added. Registers itself with document.

* dom/Node.cpp:
(WebCore::Document::invalidateNodeListAndCollectionCaches): Swap the lists since invalidateCache
tries to unregister node lists and HTML collections with document. Since this is the only case in
which node lists and HTML collections being removed may not be in the lists in unregisterNodeList
and unregisterCollection, assert this condition via m_inInvalidateNodeListAndCollectionCaches.
(WebCore::NodeListsNodeData::invalidateCaches):

* dom/NodeRareData.h:
(WebCore::NodeListsNodeData::adoptDocument): Unregister node lists and HTML collections from old
document via invalidateCache. We need to explicitly pass in oldDocument here since owner node's
document had already been changed to newDocument at this point. Since we're invalidating caches,
there is no need to register node lists and HTML collections with newDocument.

* html/HTMLCollection.cpp:
(WebCore::HTMLCollection::HTMLCollection):
(WebCore::HTMLCollection::~HTMLCollection): Unregister the node list with document if we had caches.
(WebCore::HTMLCollection::invalidateCache): Ditto.
(WebCore::HTMLCollection::invalidateNamedElementCache):
* html/HTMLCollection.h:
(WebCore::HTMLCollection::invalidateCache): Pass around document as done in LiveNodeList.
(WebCore::HTMLCollection::willValidateIndexCache): Ditto.

* html/HTMLFormControlsCollection.cpp:
(WebCore::HTMLFormControlsCollection::invalidateCache): Ditto.
* html/HTMLFormControlsCollection.h:

* html/HTMLSelectElement.cpp:
(WebCore::HTMLSelectElement::invalidateSelectedItems): Ditto.
(WebCore::HTMLSelectElement::setRecalcListItems): Ditto.

Modified Paths

Diff

Modified: trunk/Source/WebCore/ChangeLog (165102 => 165103)


--- trunk/Source/WebCore/ChangeLog	2014-03-05 10:35:14 UTC (rev 165102)
+++ trunk/Source/WebCore/ChangeLog	2014-03-05 10:41:48 UTC (rev 165103)
@@ -1,3 +1,78 @@
+2014-03-05  Ryosuke Niwa  <[email protected]>
+
+        appendChild shouldn't invalidate LiveNodeLists and HTMLCollections if they don't have valid caches
+        https://bugs.webkit.org/show_bug.cgi?id=129727
+
+        Reviewed by Andreas Kling.
+
+        Before this patch, invalidateNodeListAndCollectionCachesInAncestors invalidated node lists and HTML
+        collections on ancestors of a node whenever we're inserting or removing a child node. This patch
+        makes HTMLCollections and LiveNodeLists register themselves with Document only when they have valid
+        caches.
+
+        Each user of CollectionIndexCache now implements willValidateIndexCache member function that gets
+        called when CollectionIndexCache caches any state and necessitates the registration with document.
+
+        * dom/ChildNodeList.h: Added an empty willValidateIndexCache since child node lists are never
+        registered with document.
+
+        * dom/CollectionIndexCache.h:
+        (WebCore::CollectionIndexCache::hasValidCache): Added.
+        (WebCore::CollectionIndexCache::nodeCount): Calls willValidateIndexCache when caching node count.
+        (WebCore::CollectionIndexCache::nodeAfterCached): Ditto. Also assert that hasValidCache() true in
+        the cases where we're simply updating our caches or adding more caches.
+        (WebCore::CollectionIndexCache::nodeAt): Ditto. Also added a code to set the length cache when
+        we've reached the end of the list. This should be a slight speed up on some cases.
+
+        * dom/Document.cpp:
+        (WebCore::Document::Document): Initializes a variable used by assertions.
+        (WebCore::Document::unregisterNodeList): Added an early exit for when m_listsInvalidatedAtDocument
+        is empty since invalidateNodeListAndCollectionCaches swaps out the list.
+        (WebCore::Document::registerCollection): Removed the boolean hasIdNameMap since we now explicitly
+        call collectionCachedIdNameMap in HTMLCollection.
+        (WebCore::Document::unregisterCollection): Ditto. Exit early if m_collectionsInvalidatedAtDocument
+        is empty since invalidateNodeListAndCollectionCaches swaps out the list.
+        * dom/Document.h:
+
+        * dom/LiveNodeList.cpp:
+        (WebCore::LiveNodeList::invalidateCache): Unregister the node list with document if we had caches.
+        * dom/LiveNodeList.h:
+        (WebCore::LiveNodeList::LiveNodeList):
+        (WebCore::LiveNodeList::~LiveNodeList): Ditto.
+        (WebCore::LiveNodeList::invalidateCache): Pass around document. This is necessary since document()
+        had already moved to the new document inside NodeListsNodeData::invalidateCaches.
+        (WebCore::LiveNodeList::willValidateIndexCache): Added. Registers itself with document.
+
+        * dom/Node.cpp:
+        (WebCore::Document::invalidateNodeListAndCollectionCaches): Swap the lists since invalidateCache
+        tries to unregister node lists and HTML collections with document. Since this is the only case in
+        which node lists and HTML collections being removed may not be in the lists in unregisterNodeList
+        and unregisterCollection, assert this condition via m_inInvalidateNodeListAndCollectionCaches.
+        (WebCore::NodeListsNodeData::invalidateCaches):
+
+        * dom/NodeRareData.h:
+        (WebCore::NodeListsNodeData::adoptDocument): Unregister node lists and HTML collections from old
+        document via invalidateCache. We need to explicitly pass in oldDocument here since owner node's
+        document had already been changed to newDocument at this point. Since we're invalidating caches,
+        there is no need to register node lists and HTML collections with newDocument.
+
+        * html/HTMLCollection.cpp:
+        (WebCore::HTMLCollection::HTMLCollection):
+        (WebCore::HTMLCollection::~HTMLCollection): Unregister the node list with document if we had caches.
+        (WebCore::HTMLCollection::invalidateCache): Ditto.
+        (WebCore::HTMLCollection::invalidateNamedElementCache):
+        * html/HTMLCollection.h:
+        (WebCore::HTMLCollection::invalidateCache): Pass around document as done in LiveNodeList.
+        (WebCore::HTMLCollection::willValidateIndexCache): Ditto.
+
+        * html/HTMLFormControlsCollection.cpp:
+        (WebCore::HTMLFormControlsCollection::invalidateCache): Ditto.
+        * html/HTMLFormControlsCollection.h:
+
+        * html/HTMLSelectElement.cpp:
+        (WebCore::HTMLSelectElement::invalidateSelectedItems): Ditto.
+        (WebCore::HTMLSelectElement::setRecalcListItems): Ditto.
+
 2014-03-05  Jon Lee  <[email protected]>
 
         Fix linker error after r165087

Modified: trunk/Source/WebCore/dom/ChildNodeList.h (165102 => 165103)


--- trunk/Source/WebCore/dom/ChildNodeList.h	2014-03-05 10:35:14 UTC (rev 165102)
+++ trunk/Source/WebCore/dom/ChildNodeList.h	2014-03-05 10:41:48 UTC (rev 165103)
@@ -75,6 +75,7 @@
     Node* collectionTraverseForward(Node&, unsigned count, unsigned& traversedCount) const;
     Node* collectionTraverseBackward(Node&, unsigned count) const;
     bool collectionCanTraverseBackward() const { return true; }
+    void willValidateIndexCache() const { }
 
 private:
     explicit ChildNodeList(ContainerNode& parent);

Modified: trunk/Source/WebCore/dom/CollectionIndexCache.h (165102 => 165103)


--- trunk/Source/WebCore/dom/CollectionIndexCache.h	2014-03-05 10:35:14 UTC (rev 165102)
+++ trunk/Source/WebCore/dom/CollectionIndexCache.h	2014-03-05 10:41:48 UTC (rev 165103)
@@ -40,10 +40,12 @@
     unsigned nodeCount(const Collection&);
     NodeType* nodeAt(const Collection&, unsigned index);
 
+    bool hasValidCache() const { return m_currentNode || m_nodeCountValid || m_listValid; }
     void invalidate();
     size_t memoryCost() { return m_cachedList.capacity() * sizeof(NodeType*); }
 
 private:
+
     unsigned computeNodeCountUpdatingListCache(const Collection&);
     NodeType* nodeBeforeCached(const Collection&, unsigned);
     NodeType* nodeAfterCached(const Collection&, unsigned);
@@ -70,6 +72,8 @@
 inline unsigned CollectionIndexCache<Collection, NodeType>::nodeCount(const Collection& collection)
 {
     if (!m_nodeCountValid) {
+        if (!hasValidCache())
+            collection.willValidateIndexCache();
         m_nodeCount = computeNodeCountUpdatingListCache(collection);
         m_nodeCountValid = true;
     }
@@ -132,6 +136,7 @@
 
     bool lastIsCloser = m_nodeCountValid && m_nodeCount - index < index - m_currentIndex;
     if (lastIsCloser && collection.collectionCanTraverseBackward()) {
+        ASSERT(hasValidCache());
         m_currentNode = collection.collectionLast();
         if (index < m_nodeCount - 1)
             m_currentNode = collection.collectionTraverseBackward(*m_currentNode, m_nodeCount - index - 1);
@@ -140,6 +145,9 @@
         return m_currentNode;
     }
 
+    if (!hasValidCache())
+        collection.willValidateIndexCache();
+
     unsigned traversedCount;
     m_currentNode = collection.collectionTraverseForward(*m_currentNode, index - m_currentIndex, traversedCount);
     m_currentIndex = m_currentIndex + traversedCount;
@@ -151,6 +159,7 @@
         m_nodeCount = m_currentIndex + 1;
         m_nodeCountValid = true;
     }
+    ASSERT(hasValidCache());
     return m_currentNode;
 }
 
@@ -173,6 +182,7 @@
 
     bool lastIsCloser = m_nodeCountValid && m_nodeCount - index < index;
     if (lastIsCloser && collection.collectionCanTraverseBackward()) {
+        ASSERT(hasValidCache());
         m_currentNode = collection.collectionLast();
         if (index < m_nodeCount - 1)
             m_currentNode = collection.collectionTraverseBackward(*m_currentNode, m_nodeCount - index - 1);
@@ -181,12 +191,21 @@
         return m_currentNode;
     }
 
+    if (!hasValidCache())
+        collection.willValidateIndexCache();
+
     m_currentNode = collection.collectionFirst();
     m_currentIndex = 0;
     if (index && m_currentNode) {
         m_currentNode = collection.collectionTraverseForward(*m_currentNode, index, m_currentIndex);
         ASSERT(m_currentNode || m_currentIndex < index);
     }
+    if (!m_currentNode && !m_nodeCountValid) {
+        // Failed to find the index but at least we now know the size.
+        m_nodeCount = m_currentIndex + 1;
+        m_nodeCountValid = true;
+    }
+    ASSERT(hasValidCache());
     return m_currentNode;
 }
 

Modified: trunk/Source/WebCore/dom/Document.cpp (165102 => 165103)


--- trunk/Source/WebCore/dom/Document.cpp	2014-03-05 10:35:14 UTC (rev 165102)
+++ trunk/Source/WebCore/dom/Document.cpp	2014-03-05 10:41:48 UTC (rev 165103)
@@ -454,6 +454,9 @@
     , m_xmlStandalone(StandaloneUnspecified)
     , m_hasXMLDeclaration(false)
     , m_designMode(inherit)
+#if !ASSERT_DISABLED
+    , m_inInvalidateNodeListAndCollectionCaches(false)
+#endif
 #if ENABLE(DASHBOARD_SUPPORT)
     , m_hasAnnotatedRegions(false)
     , m_annotatedRegionsDirty(false)
@@ -3459,27 +3462,31 @@
 {
     m_nodeListAndCollectionCounts[list.invalidationType()]--;
     if (list.isRootedAtDocument()) {
+        if (!m_listsInvalidatedAtDocument.size()) {
+            ASSERT(m_inInvalidateNodeListAndCollectionCaches);
+            return;
+        }
         ASSERT(m_listsInvalidatedAtDocument.contains(&list));
         m_listsInvalidatedAtDocument.remove(&list);
     }
 }
 
-void Document::registerCollection(HTMLCollection& collection, bool hasIdNameMap)
+void Document::registerCollection(HTMLCollection& collection)
 {
-    if (hasIdNameMap)
-        collectionCachedIdNameMap(collection);
     m_nodeListAndCollectionCounts[collection.invalidationType()]++;
     if (collection.isRootedAtDocument())
         m_collectionsInvalidatedAtDocument.add(&collection);
 }
 
-void Document::unregisterCollection(HTMLCollection& collection, bool hasIdNameMap)
+void Document::unregisterCollection(HTMLCollection& collection)
 {
-    if (hasIdNameMap)
-        collectionWillClearIdNameMap(collection);
     ASSERT(m_nodeListAndCollectionCounts[collection.invalidationType()]);
     m_nodeListAndCollectionCounts[collection.invalidationType()]--;
     if (collection.isRootedAtDocument()) {
+        if (!m_collectionsInvalidatedAtDocument.size()) {
+            ASSERT(m_inInvalidateNodeListAndCollectionCaches);
+            return;
+        }
         ASSERT(m_collectionsInvalidatedAtDocument.contains(&collection));
         m_collectionsInvalidatedAtDocument.remove(&collection);
     }

Modified: trunk/Source/WebCore/dom/Document.h (165102 => 165103)


--- trunk/Source/WebCore/dom/Document.h	2014-03-05 10:35:14 UTC (rev 165102)
+++ trunk/Source/WebCore/dom/Document.h	2014-03-05 10:41:48 UTC (rev 165103)
@@ -766,8 +766,8 @@
 
     void registerNodeList(LiveNodeList&);
     void unregisterNodeList(LiveNodeList&);
-    void registerCollection(HTMLCollection&, bool hasNamedElementCache);
-    void unregisterCollection(HTMLCollection&, bool hasNamedElementCache);
+    void registerCollection(HTMLCollection&);
+    void unregisterCollection(HTMLCollection&);
     void collectionCachedIdNameMap(const HTMLCollection&);
     void collectionWillClearIdNameMap(const HTMLCollection&);
     bool shouldInvalidateNodeListAndCollectionCaches(const QualifiedName* attrName = nullptr) const;
@@ -1506,6 +1506,9 @@
 
     HashSet<LiveNodeList*> m_listsInvalidatedAtDocument;
     HashSet<HTMLCollection*> m_collectionsInvalidatedAtDocument;
+#if !ASSERT_DISABLED
+    bool m_inInvalidateNodeListAndCollectionCaches;
+#endif
 
     unsigned m_nodeListAndCollectionCounts[numNodeListInvalidationTypes];
 

Modified: trunk/Source/WebCore/dom/LiveNodeList.cpp (165102 => 165103)


--- trunk/Source/WebCore/dom/LiveNodeList.cpp	2014-03-05 10:35:14 UTC (rev 165102)
+++ trunk/Source/WebCore/dom/LiveNodeList.cpp	2014-03-05 10:41:48 UTC (rev 165103)
@@ -148,8 +148,11 @@
     return m_indexCache.memoryCost();
 }
 
-void LiveNodeList::invalidateCache() const
+void LiveNodeList::invalidateCache(Document& document) const
 {
+    if (!m_indexCache.hasValidCache())
+        return;
+    document.unregisterNodeList(const_cast<LiveNodeList&>(*this));
     m_indexCache.invalidate();
 }
 

Modified: trunk/Source/WebCore/dom/LiveNodeList.h (165102 => 165103)


--- trunk/Source/WebCore/dom/LiveNodeList.h	2014-03-05 10:35:14 UTC (rev 165102)
+++ trunk/Source/WebCore/dom/LiveNodeList.h	2014-03-05 10:41:48 UTC (rev 165103)
@@ -63,15 +63,14 @@
         ASSERT(m_rootType == static_cast<unsigned>(rootType));
         ASSERT(m_invalidationType == static_cast<unsigned>(invalidationType));
         ASSERT(m_type == static_cast<unsigned>(type));
-
-        document().registerNodeList(*this);
     }
     virtual Node* namedItem(const AtomicString&) const override final;
     virtual bool nodeMatches(Element*) const = 0;
 
     virtual ~LiveNodeList()
     {
-        document().unregisterNodeList(*this);
+        if (m_indexCache.hasValidCache())
+            document().unregisterNodeList(*this);
     }
 
     // DOM API
@@ -86,9 +85,9 @@
     ALWAYS_INLINE void invalidateCache(const QualifiedName* attrName) const
     {
         if (!attrName || shouldInvalidateTypeOnAttributeChange(invalidationType(), *attrName))
-            invalidateCache();
+            invalidateCache(document());
     }
-    void invalidateCache() const;
+    void invalidateCache(Document&) const;
 
     // For CollectionIndexCache
     Element* collectionFirst() const;
@@ -96,6 +95,7 @@
     Element* collectionTraverseForward(Element&, unsigned count, unsigned& traversedCount) const;
     Element* collectionTraverseBackward(Element&, unsigned count) const;
     bool collectionCanTraverseBackward() const { return true; }
+    void willValidateIndexCache() const { document().registerNodeList(const_cast<LiveNodeList&>(*this)); }
 
 protected:
     Document& document() const { return m_ownerNode->document(); }

Modified: trunk/Source/WebCore/dom/Node.cpp (165102 => 165103)


--- trunk/Source/WebCore/dom/Node.cpp	2014-03-05 10:35:14 UTC (rev 165102)
+++ trunk/Source/WebCore/dom/Node.cpp	2014-03-05 10:41:48 UTC (rev 165103)
@@ -721,10 +721,19 @@
 
 void Document::invalidateNodeListAndCollectionCaches(const QualifiedName* attrName)
 {
-    for (HashSet<LiveNodeList*>::iterator it = m_listsInvalidatedAtDocument.begin(), end = m_listsInvalidatedAtDocument.end(); it != end; ++it)
-        (*it)->invalidateCache(attrName);
-    for (HashSet<HTMLCollection*>::iterator it = m_collectionsInvalidatedAtDocument.begin(), end = m_collectionsInvalidatedAtDocument.end(); it != end; ++it)
-        (*it)->invalidateCache(attrName);
+#if !ASSERT_DISABLED
+    m_inInvalidateNodeListAndCollectionCaches = true;
+#endif
+    HashSet<LiveNodeList*> liveNodeLists = std::move(m_listsInvalidatedAtDocument);
+    for (auto it : liveNodeLists)
+        it->invalidateCache(attrName);
+
+    HashSet<HTMLCollection*> collectionLists = std::move(m_collectionsInvalidatedAtDocument);
+    for (auto it : collectionLists)
+        it->invalidateCache(attrName);
+#if !ASSERT_DISABLED
+    m_inInvalidateNodeListAndCollectionCaches = false;
+#endif
 }
 
 void Node::invalidateNodeListAndCollectionCachesInAncestors(const QualifiedName* attrName, Element* attributeOwnerElement)
@@ -1689,7 +1698,7 @@
         return;
 
     for (auto& tagNodeList : m_tagNodeListCacheNS)
-        tagNodeList.value->invalidateCache();
+        tagNodeList.value->invalidateCache(nullptr);
 }
 
 void Node::getSubresourceURLs(ListHashSet<URL>& urls) const

Modified: trunk/Source/WebCore/dom/NodeRareData.h (165102 => 165103)


--- trunk/Source/WebCore/dom/NodeRareData.h	2014-03-05 10:35:14 UTC (rev 165102)
+++ trunk/Source/WebCore/dom/NodeRareData.h	2014-03-05 10:41:48 UTC (rev 165103)
@@ -225,39 +225,26 @@
 
     void adoptDocument(Document* oldDocument, Document* newDocument)
     {
+        ASSERT(oldDocument);
         if (oldDocument == newDocument) {
             invalidateCaches();
             return;
         }
 
-        for (auto it : m_atomicNameCaches) {
-            LiveNodeList& list = *it.value;
-            oldDocument->unregisterNodeList(list);
-            newDocument->registerNodeList(list);
-            list.invalidateCache();
-        }
+        for (auto it : m_atomicNameCaches)
+            it.value->invalidateCache(*oldDocument);
 
-        for (auto it : m_nameCaches) {
-            LiveNodeList& list = *it.value;
-            oldDocument->unregisterNodeList(list);
-            newDocument->registerNodeList(list);
-            list.invalidateCache();
-        }
+        for (auto it : m_nameCaches)
+            it.value->invalidateCache(*oldDocument);
 
         for (auto it : m_tagNodeListCacheNS) {
             LiveNodeList& list = *it.value;
             ASSERT(!list.isRootedAtDocument());
-            oldDocument->unregisterNodeList(list);
-            newDocument->registerNodeList(list);
-            list.invalidateCache();
+            list.invalidateCache(*oldDocument);
         }
 
-        for (auto it : m_cachedCollections) {
-            HTMLCollection& collection = *it.value;
-            oldDocument->unregisterCollection(collection, collection.hasNamedElementCache());
-            newDocument->registerCollection(collection, collection.hasNamedElementCache());
-            collection.invalidateCache();
-        }
+        for (auto it : m_cachedCollections)
+            it.value->invalidateCache(*oldDocument);
     }
 
 private:

Modified: trunk/Source/WebCore/html/HTMLCollection.cpp (165102 => 165103)


--- trunk/Source/WebCore/html/HTMLCollection.cpp	2014-03-05 10:35:14 UTC (rev 165102)
+++ trunk/Source/WebCore/html/HTMLCollection.cpp	2014-03-05 10:41:48 UTC (rev 165103)
@@ -142,8 +142,6 @@
     ASSERT(m_rootType == static_cast<unsigned>(rootTypeFromCollectionType(type)));
     ASSERT(m_invalidationType == static_cast<unsigned>(invalidationTypeExcludingIdAndNameAttributes(type)));
     ASSERT(m_collectionType == static_cast<unsigned>(type));
-
-    document().registerCollection(*this, hasNamedElementCache());
 }
 
 PassRefPtr<HTMLCollection> HTMLCollection::create(ContainerNode& base, CollectionType type)
@@ -153,7 +151,10 @@
 
 HTMLCollection::~HTMLCollection()
 {
-    document().unregisterCollection(*this, hasNamedElementCache());
+    if (m_indexCache.hasValidCache())
+        document().unregisterCollection(*this);
+    if (hasNamedElementCache())
+        document().collectionWillClearIdNameMap(*this);
     // HTMLNameCollection removes cache by itself.
     if (type() != WindowNamedItems && type() != DocumentNamedItems)
         ownerNode().nodeLists()->removeCachedCollection(this);
@@ -362,17 +363,20 @@
     return element;
 }
 
-void HTMLCollection::invalidateCache() const
+void HTMLCollection::invalidateCache(Document& document) const
 {
-    m_indexCache.invalidate();
+    if (m_indexCache.hasValidCache()) {
+        document.unregisterCollection(const_cast<HTMLCollection&>(*this));
+        m_indexCache.invalidate();
+    }
     if (hasNamedElementCache())
-        invalidateNamedElementCache();
+        invalidateNamedElementCache(document);
 }
 
-void HTMLCollection::invalidateNamedElementCache() const
+void HTMLCollection::invalidateNamedElementCache(Document& document) const
 {
     ASSERT(hasNamedElementCache());
-    document().collectionWillClearIdNameMap(*this);
+    document.collectionWillClearIdNameMap(*this);
     m_namedElementCache = nullptr;
 }
 

Modified: trunk/Source/WebCore/html/HTMLCollection.h (165102 => 165103)


--- trunk/Source/WebCore/html/HTMLCollection.h	2014-03-05 10:35:14 UTC (rev 165102)
+++ trunk/Source/WebCore/html/HTMLCollection.h	2014-03-05 10:41:48 UTC (rev 165103)
@@ -107,11 +107,11 @@
     void invalidateCache(const QualifiedName* attrName) const
     {
         if (!attrName || shouldInvalidateTypeOnAttributeChange(invalidationType(), *attrName))
-            invalidateCache();
+            invalidateCache(document());
         else if (hasNamedElementCache() && (*attrName == HTMLNames::idAttr || *attrName == HTMLNames::nameAttr))
-            invalidateNamedElementCache();
+            invalidateNamedElementCache(document());
     }
-    virtual void invalidateCache() const;
+    virtual void invalidateCache(Document&) const;
 
     // For CollectionIndexCache
     Element* collectionFirst() const;
@@ -119,6 +119,7 @@
     Element* collectionTraverseForward(Element&, unsigned count, unsigned& traversedCount) const;
     Element* collectionTraverseBackward(Element&, unsigned count) const;
     bool collectionCanTraverseBackward() const { return !m_usesCustomForwardOnlyTraversal; }
+    void willValidateIndexCache() const { document().registerCollection(const_cast<HTMLCollection&>(*this)); }
 
     bool hasNamedElementCache() const { return !!m_namedElementCache; }
 
@@ -155,7 +156,7 @@
 
     virtual Element* customElementAfter(Element*) const { ASSERT_NOT_REACHED(); return nullptr; }
     
-    void invalidateNamedElementCache() const;
+    void invalidateNamedElementCache(Document&) const;
 
     Ref<ContainerNode> m_ownerNode;
 

Modified: trunk/Source/WebCore/html/HTMLFormControlsCollection.cpp (165102 => 165103)


--- trunk/Source/WebCore/html/HTMLFormControlsCollection.cpp	2014-03-05 10:35:14 UTC (rev 165102)
+++ trunk/Source/WebCore/html/HTMLFormControlsCollection.cpp	2014-03-05 10:41:48 UTC (rev 165103)
@@ -177,9 +177,9 @@
     cache.didPopulate();
 }
 
-void HTMLFormControlsCollection::invalidateCache() const
+void HTMLFormControlsCollection::invalidateCache(Document& document) const
 {
-    HTMLCollection::invalidateCache();
+    HTMLCollection::invalidateCache(document);
     m_cachedElement = nullptr;
     m_cachedElementOffsetInArray = 0;
 }

Modified: trunk/Source/WebCore/html/HTMLFormControlsCollection.h (165102 => 165103)


--- trunk/Source/WebCore/html/HTMLFormControlsCollection.h	2014-03-05 10:35:14 UTC (rev 165102)
+++ trunk/Source/WebCore/html/HTMLFormControlsCollection.h	2014-03-05 10:41:48 UTC (rev 165103)
@@ -46,7 +46,7 @@
 private:
     explicit HTMLFormControlsCollection(ContainerNode&);
 
-    virtual void invalidateCache() const override;
+    virtual void invalidateCache(Document&) const override;
     virtual void updateNamedElementCache() const override;
 
     const Vector<FormAssociatedElement*>& formControlElements() const;

Modified: trunk/Source/WebCore/html/HTMLSelectElement.cpp (165102 => 165103)


--- trunk/Source/WebCore/html/HTMLSelectElement.cpp	2014-03-05 10:35:14 UTC (rev 165102)
+++ trunk/Source/WebCore/html/HTMLSelectElement.cpp	2014-03-05 10:41:48 UTC (rev 165103)
@@ -750,7 +750,7 @@
 void HTMLSelectElement::invalidateSelectedItems()
 {
     if (HTMLCollection* collection = cachedHTMLCollection(SelectedOptions))
-        collection->invalidateCache();
+        collection->invalidateCache(document());
 }
 
 void HTMLSelectElement::setRecalcListItems()
@@ -762,7 +762,7 @@
     setNeedsStyleRecalc();
     if (!inDocument()) {
         if (HTMLCollection* collection = cachedHTMLCollection(SelectOptions))
-            collection->invalidateCache();
+            collection->invalidateCache(document());
     }
     if (!inDocument())
         invalidateSelectedItems();
_______________________________________________
webkit-changes mailing list
[email protected]
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to