Changeset 104084 in webkit
- Timestamp:
- Jan 4, 2012 3:08:50 PM (12 years ago)
- Location:
- trunk/Source/WebCore
- Files:
-
- 11 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/Source/WebCore/ChangeLog
r104081 r104084 1 2011-12-30 Ryosuke Niwa <rniwa@webkit.org> 2 3 Inserting nodes is slow due to Node::notifyNodeListsAttributeChanged (20%+) 4 https://bugs.webkit.org/show_bug.cgi?id=73853 5 6 Reviewed by Antti Koivisto. 7 8 Lazily invalidate the node list caches instead of invaliding them at the time of modification. We use 9 the DOM tree version to detect whether caches need to be invalidated or not. We now invalidate caches more 10 frequently after this patch (in particular, invalidates caches that are stored on nodes not present in 11 the ancestry of the modified nodes); however, our study on major Web sites such as Gmail, Facebook, Twitter, 12 etc... indicate that about 1% of real-world usage benefits from keeping the caches alive across different 13 DOM tree versions. 14 15 In order to invalidate caches lazily, this patch adds replaces the type of m_caches in DynamicSubtreeNodeList 16 by DynamicSubtreeNodeList::SubtreeCaches which encapsulates member variables in DynamicNodeList::Caches and 17 invalidates values as needed. Also this change allows m_caches to be allocated as a part of 18 DynamicSubtreeNodeList instead of a separate ref-counted object. 19 20 * dom/Attr.cpp: 21 (WebCore::Attr::setValue): 22 (WebCore::Attr::childrenChanged): 23 * dom/DynamicNodeList.cpp: 24 (WebCore::DynamicSubtreeNodeList::DynamicSubtreeNodeList): 25 (WebCore::DynamicSubtreeNodeList::length): 26 (WebCore::DynamicSubtreeNodeList::itemForwardsFromCurrent): 27 (WebCore::DynamicSubtreeNodeList::itemBackwardsFromCurrent): 28 (WebCore::DynamicSubtreeNodeList::item): 29 (WebCore::DynamicSubtreeNodeList::invalidateCache): 30 (WebCore::DynamicNodeList::Caches::create): 31 (WebCore::DynamicNodeList::Caches::reset): 32 * dom/DynamicNodeList.h: 33 (WebCore::DynamicSubtreeNodeList::SubtreeCaches::SubtreeCaches): Added. 34 (WebCore::DynamicSubtreeNodeList::SubtreeCaches::isLengthCacheValid): Added. 35 (WebCore::DynamicSubtreeNodeList::SubtreeCaches::isItemCacheValid): Added. 36 (WebCore::DynamicSubtreeNodeList::SubtreeCaches::cachedLength): Added. 37 (WebCore::DynamicSubtreeNodeList::SubtreeCaches::cachedItem): Added. 38 (WebCore::DynamicSubtreeNodeList::SubtreeCaches::cachedItemOffset): Added. 39 (WebCore::DynamicSubtreeNodeList::SubtreeCaches::setLengthCache): Added. 40 (WebCore::DynamicSubtreeNodeList::SubtreeCaches::setItemCache): Added. 41 (WebCore::DynamicSubtreeNodeList::SubtreeCaches::reset): Added. 42 (WebCore::DynamicSubtreeNodeList::SubtreeCaches::domVersionIsConsistent): Added. 43 * dom/Element.cpp: 44 (WebCore::Element::updateAfterAttributeChanged): 45 * dom/Node.cpp: 46 (WebCore::Node::setTreeScopeRecursively): Clear caches when a node moves from one document to another. 47 (WebCore::Node::invalidateNodeListsCacheAfterAttributeChanged): Only clears child node list of Attr. 48 (WebCore::Node::invalidateNodeListsCacheAfterChildrenChanged): Only clears child node list. 49 (WebCore::NodeListsNodeData::invalidateCaches): Merged with invalidateCachesThatDependOnAttributes. 50 * dom/Node.h: 51 * dom/NodeRareData.h: 52 * html/HTMLElement.cpp: 53 (WebCore::HTMLElement::parseMappedAttribute): 54 * html/HTMLLabelElement.cpp: 55 * html/HTMLLabelElement.h: 56 1 57 2012-01-04 Ryosuke Niwa <rniwa@webkit.org> 2 58 -
trunk/Source/WebCore/dom/Attr.cpp
r103611 r104084 130 130 m_ignoreChildrenChanged--; 131 131 132 invalidateNodeListsCacheAfterAttributeChanged( m_attribute->name());132 invalidateNodeListsCacheAfterAttributeChanged(); 133 133 } 134 134 … … 175 175 Node::childrenChanged(changedByParser, beforeChange, afterChange, childCountDelta); 176 176 177 invalidateNodeListsCacheAfterAttributeChanged( m_attribute->name());177 invalidateNodeListsCacheAfterAttributeChanged(); 178 178 179 179 // FIXME: We should include entity references in the value -
trunk/Source/WebCore/dom/DynamicNodeList.cpp
r102834 r104084 29 29 namespace WebCore { 30 30 31 DynamicSubtreeNodeList::SubtreeCaches::SubtreeCaches() 32 : m_cachedItem(0) 33 , m_isLengthCacheValid(false) 34 , m_isItemCacheValid(false) 35 , m_DOMVersionAtTimeOfCaching(0) 36 { 37 } 38 39 inline void DynamicSubtreeNodeList::SubtreeCaches::setLengthCache(Node* node, unsigned length) 40 { 41 if (m_isItemCacheValid && !domVersionIsConsistent()) { 42 m_cachedItem = node; 43 m_isItemCacheValid = false; 44 } 45 m_cachedLength = length; 46 m_isLengthCacheValid = true; 47 } 48 49 inline void DynamicSubtreeNodeList::SubtreeCaches::setItemCache(Node* item, unsigned offset) 50 { 51 if (m_isLengthCacheValid && !domVersionIsConsistent()) 52 m_isLengthCacheValid = false; 53 m_cachedItem = item; 54 m_cachedItemOffset = offset; 55 m_isLengthCacheValid = true; 56 } 57 58 inline void DynamicSubtreeNodeList::SubtreeCaches::reset() 59 { 60 m_cachedItem = 0; 61 m_isLengthCacheValid = false; 62 m_isItemCacheValid = false; 63 } 64 31 65 DynamicSubtreeNodeList::DynamicSubtreeNodeList(PassRefPtr<Node> node) 32 66 : DynamicNodeList(node) 33 , m_caches(Caches::create())34 67 { 35 68 rootNode()->registerDynamicSubtreeNodeList(this); … … 43 76 unsigned DynamicSubtreeNodeList::length() const 44 77 { 45 if (m_caches ->isLengthCacheValid)46 return m_caches ->cachedLength;78 if (m_caches.isLengthCacheValid()) 79 return m_caches.cachedLength(); 47 80 48 81 unsigned length = 0; … … 51 84 length += n->isElementNode() && nodeMatches(static_cast<Element*>(n)); 52 85 53 m_caches->cachedLength = length; 54 m_caches->isLengthCacheValid = true; 86 m_caches.setLengthCache(node(), length); 55 87 56 88 return length; … … 63 95 if (n->isElementNode() && nodeMatches(static_cast<Element*>(n))) { 64 96 if (!remainingOffset) { 65 m_caches->lastItem = n; 66 m_caches->lastItemOffset = offset; 67 m_caches->isItemCacheValid = true; 97 m_caches.setItemCache(n, offset); 68 98 return n; 69 99 } … … 81 111 if (n->isElementNode() && nodeMatches(static_cast<Element*>(n))) { 82 112 if (!remainingOffset) { 83 m_caches->lastItem = n; 84 m_caches->lastItemOffset = offset; 85 m_caches->isItemCacheValid = true; 113 m_caches.setItemCache(n, offset); 86 114 return n; 87 115 } … … 97 125 int remainingOffset = offset; 98 126 Node* start = node()->firstChild(); 99 if (m_caches ->isItemCacheValid) {100 if (offset == m_caches ->lastItemOffset)101 return m_caches ->lastItem;102 else if (offset > m_caches->lastItemOffset || m_caches->lastItemOffset- offset < offset) {103 start = m_caches ->lastItem;104 remainingOffset -= m_caches ->lastItemOffset;127 if (m_caches.isItemCacheValid()) { 128 if (offset == m_caches.cachedItemOffset()) 129 return m_caches.cachedItem(); 130 if (offset > m_caches.cachedItemOffset() || m_caches.cachedItemOffset() - offset < offset) { 131 start = m_caches.cachedItem(); 132 remainingOffset -= m_caches.cachedItemOffset(); 105 133 } 106 134 } … … 140 168 void DynamicSubtreeNodeList::invalidateCache() 141 169 { 142 m_caches ->reset();170 m_caches.reset(); 143 171 } 144 172 … … 150 178 } 151 179 152 PassRefPtr<Dynamic SubtreeNodeList::Caches> DynamicSubtreeNodeList::Caches::create()180 PassRefPtr<DynamicNodeList::Caches> DynamicNodeList::Caches::create() 153 181 { 154 182 return adoptRef(new Caches()); 155 183 } 156 184 157 void Dynamic SubtreeNodeList::Caches::reset()185 void DynamicNodeList::Caches::reset() 158 186 { 159 187 lastItem = 0; -
trunk/Source/WebCore/dom/DynamicNodeList.h
r102834 r104084 25 25 #define DynamicNodeList_h 26 26 27 #include "Document.h" 27 28 #include "NodeList.h" 28 29 #include <wtf/RefCounted.h> … … 46 47 bool isLengthCacheValid : 1; 47 48 bool isItemCacheValid : 1; 49 48 50 protected: 49 51 Caches(); 50 52 }; 53 51 54 DynamicNodeList(PassRefPtr<Node> node) 52 55 : m_node(node) … … 77 80 protected: 78 81 DynamicSubtreeNodeList(PassRefPtr<Node> rootNode); 79 mutable RefPtr<Caches> m_caches;80 82 81 83 private: 84 85 class SubtreeCaches { 86 public: 87 SubtreeCaches(); 88 89 bool isLengthCacheValid() const { return m_isLengthCacheValid && domVersionIsConsistent(); } 90 bool isItemCacheValid() const { return m_isItemCacheValid && domVersionIsConsistent(); } 91 92 unsigned cachedLength() const { return m_cachedLength; } 93 Node* cachedItem() const { return m_cachedItem; } 94 unsigned cachedItemOffset() const { return m_cachedItemOffset; } 95 96 void setLengthCache(Node* node, unsigned length); 97 void setItemCache(Node* item, unsigned offset); 98 void reset(); 99 100 private: 101 Node* m_cachedItem; 102 unsigned m_cachedItemOffset; 103 unsigned m_cachedLength : 30; 104 unsigned m_isLengthCacheValid : 1; 105 unsigned m_isItemCacheValid : 1; 106 107 bool domVersionIsConsistent() const 108 { 109 return m_cachedItem && m_cachedItem->document()->domTreeVersion() == m_DOMVersionAtTimeOfCaching; 110 } 111 uint64_t m_DOMVersionAtTimeOfCaching; 112 }; 113 114 mutable SubtreeCaches m_caches; 115 82 116 virtual bool isDynamicNodeList() const; 83 117 Node* itemForwardsFromCurrent(Node* start, unsigned offset, int remainingOffset) const; -
trunk/Source/WebCore/dom/Element.cpp
r104081 r104084 675 675 void Element::updateAfterAttributeChanged(Attribute* attr) 676 676 { 677 invalidateNodeListsCacheAfterAttributeChanged( attr->name());677 invalidateNodeListsCacheAfterAttributeChanged(); 678 678 679 679 if (!AXObjectCache::accessibilityEnabled()) -
trunk/Source/WebCore/dom/Node.cpp
r103701 r104084 490 490 491 491 if (node->hasRareData() && node->rareData()->nodeLists()) { 492 node->rareData()->nodeLists()->invalidateCaches(); 492 493 if (currentTreeScope) 493 494 currentTreeScope->removeNodeListCache(); … … 1003 1004 } 1004 1005 1005 void Node::invalidateNodeListsCacheAfterAttributeChanged( const QualifiedName& attrName)1006 void Node::invalidateNodeListsCacheAfterAttributeChanged() 1006 1007 { 1007 1008 if (hasRareData() && isAttributeNode()) { … … 1010 1011 data->clearChildNodeListCache(); 1011 1012 } 1012 1013 // This list should be sync'ed with NodeListsNodeData.1014 if (attrName != classAttr1015 #if ENABLE(MICRODATA)1016 && attrName != itemscopeAttr1017 && attrName != itempropAttr1018 #endif1019 && attrName != nameAttr)1020 return;1021 1022 if (!treeScope()->hasNodeListCaches())1023 return;1024 1025 for (Node* node = this; node; node = node->parentNode()) {1026 ASSERT(this == node || !node->isAttributeNode());1027 if (!node->hasRareData())1028 continue;1029 NodeRareData* data = node->rareData();1030 if (!data->nodeLists())1031 continue;1032 1033 data->nodeLists()->invalidateCachesThatDependOnAttributes();1034 removeNodeListCacheIfPossible(node, data);1035 }1036 1013 } 1037 1014 … … 1040 1017 if (hasRareData()) 1041 1018 rareData()->clearChildNodeListCache(); 1042 1043 if (!treeScope()->hasNodeListCaches())1044 return;1045 for (Node* node = this; node; node = node->parentNode()) {1046 if (!node->hasRareData())1047 continue;1048 NodeRareData* data = node->rareData();1049 if (!data->nodeLists())1050 continue;1051 1052 data->nodeLists()->invalidateCaches();1053 1054 NodeListsNodeData::NodeListSet::iterator end = data->nodeLists()->m_listsWithCaches.end();1055 for (NodeListsNodeData::NodeListSet::iterator it = data->nodeLists()->m_listsWithCaches.begin(); it != end; ++it)1056 (*it)->invalidateCache();1057 1058 removeNodeListCacheIfPossible(node, data);1059 }1060 }1061 1062 void Node::notifyLocalNodeListsLabelChanged()1063 {1064 if (!hasRareData())1065 return;1066 NodeRareData* data = rareData();1067 if (!data->nodeLists())1068 return;1069 1070 if (data->nodeLists()->m_labelsNodeListCache)1071 data->nodeLists()->m_labelsNodeListCache->invalidateCache();1072 1019 } 1073 1020 … … 2244 2191 } 2245 2192 2246 #if ENABLE(MICRODATA)2247 void Node::itemTypeAttributeChanged()2248 {2249 Node * rootNode = document();2250 2251 if (!rootNode->hasRareData())2252 return;2253 2254 NodeRareData* data = rootNode->rareData();2255 2256 if (!data->nodeLists())2257 return;2258 2259 data->nodeLists()->invalidateMicrodataItemListCaches();2260 }2261 #endif2262 2263 2193 #ifndef NDEBUG 2264 2194 … … 2389 2319 for (TagNodeListCacheNS::const_iterator it = m_tagNodeListCacheNS.begin(); it != tagCacheNSEnd; ++it) 2390 2320 it->second->invalidateCache(); 2391 invalidateCachesThatDependOnAttributes(); 2392 } 2393 2394 void NodeListsNodeData::invalidateCachesThatDependOnAttributes() 2395 { 2321 2396 2322 ClassNodeListCache::iterator classCacheEnd = m_classNodeListCache.end(); 2397 2323 for (ClassNodeListCache::iterator it = m_classNodeListCache.begin(); it != classCacheEnd; ++it) … … 2407 2333 invalidateMicrodataItemListCaches(); 2408 2334 #endif 2335 2409 2336 } 2410 2337 -
trunk/Source/WebCore/dom/Node.h
r103701 r104084 522 522 void registerDynamicSubtreeNodeList(DynamicSubtreeNodeList*); 523 523 void unregisterDynamicSubtreeNodeList(DynamicSubtreeNodeList*); 524 void invalidateNodeListsCacheAfterAttributeChanged( const QualifiedName&);524 void invalidateNodeListsCacheAfterAttributeChanged(); 525 525 void invalidateNodeListsCacheAfterChildrenChanged(); 526 void notifyLocalNodeListsLabelChanged();527 526 void removeCachedClassNodeList(ClassNodeList*, const String&); 528 527 … … 592 591 593 592 #if ENABLE(MICRODATA) 594 void itemTypeAttributeChanged();595 596 593 DOMSettableTokenList* itemProp(); 597 594 DOMSettableTokenList* itemRef(); -
trunk/Source/WebCore/dom/NodeRareData.h
r102834 r104084 79 79 80 80 void invalidateCaches(); 81 void invalidateCachesThatDependOnAttributes();82 81 83 82 #if ENABLE(MICRODATA) -
trunk/Source/WebCore/html/HTMLElement.cpp
r103883 r104084 238 238 } else if (attr->name() == itemtypeAttr) { 239 239 setItemType(attr->value()); 240 itemTypeAttributeChanged();241 240 #endif 242 241 } -
trunk/Source/WebCore/html/HTMLLabelElement.cpp
r100805 r104084 155 155 } 156 156 157 void HTMLLabelElement::parseMappedAttribute(Attribute* attribute)158 {159 if (attribute->name() == forAttr) {160 // htmlFor attribute change affects other nodes than this.161 // Clear the caches to ensure that the labels caches are cleared.162 if (document())163 document()->notifyLocalNodeListsLabelChanged();164 } else165 HTMLElement::parseMappedAttribute(attribute);166 }167 168 157 } // namespace -
trunk/Source/WebCore/html/HTMLLabelElement.h
r100805 r104084 51 51 52 52 void focus(bool restorePreviousSelection = true); 53 54 virtual void parseMappedAttribute(Attribute*);55 53 }; 56 54
Note: See TracChangeset
for help on using the changeset viewer.