Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(104)

Side by Side Diff: third_party/WebKit/Source/core/dom/SelectorQuery.cpp

Issue 2797083002: Test cases for querySelector fast paths. (Closed)
Patch Set: Working tests. Created 3 years, 8 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 /* 1 /*
2 * Copyright (C) 2011, 2013 Apple Inc. All rights reserved. 2 * Copyright (C) 2011, 2013 Apple Inc. All rights reserved.
3 * Copyright (C) 2014 Samsung Electronics. All rights reserved. 3 * Copyright (C) 2014 Samsung Electronics. All rights reserved.
4 * 4 *
5 * Redistribution and use in source and binary forms, with or without 5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions 6 * modification, are permitted provided that the following conditions
7 * are met: 7 * are met:
8 * 8 *
9 * 1. Redistributions of source code must retain the above copyright 9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer. 10 * notice, this list of conditions and the following disclaimer.
(...skipping 27 matching lines...) Expand all
38 #include "core/dom/NthIndexCache.h" 38 #include "core/dom/NthIndexCache.h"
39 #include "core/dom/StaticNodeList.h" 39 #include "core/dom/StaticNodeList.h"
40 #include "core/dom/shadow/ElementShadow.h" 40 #include "core/dom/shadow/ElementShadow.h"
41 #include "core/dom/shadow/ShadowRoot.h" 41 #include "core/dom/shadow/ShadowRoot.h"
42 #include "wtf/PtrUtil.h" 42 #include "wtf/PtrUtil.h"
43 43
44 namespace blink { 44 namespace blink {
45 45
46 using namespace HTMLNames; 46 using namespace HTMLNames;
47 47
48 #if DCHECK_IS_ON()
49 static SelectorQuery::QueryStats& currentQueryStats() {
50 DEFINE_STATIC_LOCAL(SelectorQuery::QueryStats, stats, ());
51 return stats;
52 }
53
54 SelectorQuery::QueryStats SelectorQuery::lastQueryStats() {
55 return currentQueryStats();
56 }
57
58 #define QUERY_STATS_INCREMENT(name) \
59 (void)(currentQueryStats().totalCount++, currentQueryStats().name++);
60 #define QUERY_STATS_RESET() (void)(currentQueryStats() = {});
61
62 #else
63
64 #define QUERY_STATS_INCREMENT(name)
65 #define QUERY_STATS_RESET()
66
67 #endif
68
48 struct SingleElementSelectorQueryTrait { 69 struct SingleElementSelectorQueryTrait {
49 typedef Element* OutputType; 70 typedef Element* OutputType;
50 static const bool shouldOnlyMatchFirstElement = true; 71 static const bool shouldOnlyMatchFirstElement = true;
51 ALWAYS_INLINE static void appendElement(OutputType& output, 72 ALWAYS_INLINE static void appendElement(OutputType& output,
52 Element& element) { 73 Element& element) {
53 DCHECK(!output); 74 DCHECK(!output);
54 output = &element; 75 output = &element;
55 } 76 }
56 }; 77 };
57 78
(...skipping 19 matching lines...) Expand all
77 init.mode = SelectorChecker::QueryingRules; 98 init.mode = SelectorChecker::QueryingRules;
78 SelectorChecker checker(init); 99 SelectorChecker checker(init);
79 SelectorChecker::SelectorCheckingContext context( 100 SelectorChecker::SelectorCheckingContext context(
80 &element, SelectorChecker::VisitedMatchDisabled); 101 &element, SelectorChecker::VisitedMatchDisabled);
81 context.selector = &selector; 102 context.selector = &selector;
82 context.scope = &rootNode; 103 context.scope = &rootNode;
83 return checker.match(context); 104 return checker.match(context);
84 } 105 }
85 106
86 bool SelectorQuery::matches(Element& targetElement) const { 107 bool SelectorQuery::matches(Element& targetElement) const {
108 QUERY_STATS_RESET();
87 if (m_needsUpdatedDistribution) 109 if (m_needsUpdatedDistribution)
88 targetElement.updateDistribution(); 110 targetElement.updateDistribution();
89 return selectorListMatches(targetElement, targetElement); 111 return selectorListMatches(targetElement, targetElement);
90 } 112 }
91 113
92 Element* SelectorQuery::closest(Element& targetElement) const { 114 Element* SelectorQuery::closest(Element& targetElement) const {
115 QUERY_STATS_RESET();
93 if (m_selectors.isEmpty()) 116 if (m_selectors.isEmpty())
94 return nullptr; 117 return nullptr;
95 if (m_needsUpdatedDistribution) 118 if (m_needsUpdatedDistribution)
96 targetElement.updateDistribution(); 119 targetElement.updateDistribution();
97 120
98 for (Element* currentElement = &targetElement; currentElement; 121 for (Element* currentElement = &targetElement; currentElement;
99 currentElement = currentElement->parentElement()) { 122 currentElement = currentElement->parentElement()) {
100 if (selectorListMatches(targetElement, *currentElement)) 123 if (selectorListMatches(targetElement, *currentElement))
101 return currentElement; 124 return currentElement;
102 } 125 }
103 return nullptr; 126 return nullptr;
104 } 127 }
105 128
106 StaticElementList* SelectorQuery::queryAll(ContainerNode& rootNode) const { 129 StaticElementList* SelectorQuery::queryAll(ContainerNode& rootNode) const {
130 QUERY_STATS_RESET();
107 NthIndexCache nthIndexCache(rootNode.document()); 131 NthIndexCache nthIndexCache(rootNode.document());
108 HeapVector<Member<Element>> result; 132 HeapVector<Member<Element>> result;
109 execute<AllElementsSelectorQueryTrait>(rootNode, result); 133 execute<AllElementsSelectorQueryTrait>(rootNode, result);
110 return StaticElementList::adopt(result); 134 return StaticElementList::adopt(result);
111 } 135 }
112 136
113 Element* SelectorQuery::queryFirst(ContainerNode& rootNode) const { 137 Element* SelectorQuery::queryFirst(ContainerNode& rootNode) const {
138 QUERY_STATS_RESET();
114 NthIndexCache nthIndexCache(rootNode.document()); 139 NthIndexCache nthIndexCache(rootNode.document());
115 Element* matchedElement = nullptr; 140 Element* matchedElement = nullptr;
116 execute<SingleElementSelectorQueryTrait>(rootNode, matchedElement); 141 execute<SingleElementSelectorQueryTrait>(rootNode, matchedElement);
117 return matchedElement; 142 return matchedElement;
118 } 143 }
119 144
120 template <typename SelectorQueryTrait> 145 template <typename SelectorQueryTrait>
121 static void collectElementsByClassName( 146 static void collectElementsByClassName(
122 ContainerNode& rootNode, 147 ContainerNode& rootNode,
123 const AtomicString& className, 148 const AtomicString& className,
124 const CSSSelector* selector, 149 const CSSSelector* selector,
125 typename SelectorQueryTrait::OutputType& output) { 150 typename SelectorQueryTrait::OutputType& output) {
126 for (Element& element : ElementTraversal::descendantsOf(rootNode)) { 151 for (Element& element : ElementTraversal::descendantsOf(rootNode)) {
152 QUERY_STATS_INCREMENT(fastClass);
127 if (!hasClassName(element, className)) 153 if (!hasClassName(element, className))
128 continue; 154 continue;
129 if (selector && !selectorMatches(*selector, element, rootNode)) 155 if (selector && !selectorMatches(*selector, element, rootNode))
130 continue; 156 continue;
131 SelectorQueryTrait::appendElement(output, element); 157 SelectorQueryTrait::appendElement(output, element);
132 if (SelectorQueryTrait::shouldOnlyMatchFirstElement) 158 if (SelectorQueryTrait::shouldOnlyMatchFirstElement)
133 return; 159 return;
134 } 160 }
135 } 161 }
136 162
(...skipping 12 matching lines...) Expand all
149 return false; 175 return false;
150 } 176 }
151 177
152 template <typename SelectorQueryTrait> 178 template <typename SelectorQueryTrait>
153 static void collectElementsByTagName( 179 static void collectElementsByTagName(
154 ContainerNode& rootNode, 180 ContainerNode& rootNode,
155 const QualifiedName& tagName, 181 const QualifiedName& tagName,
156 typename SelectorQueryTrait::OutputType& output) { 182 typename SelectorQueryTrait::OutputType& output) {
157 DCHECK_EQ(tagName.namespaceURI(), starAtom); 183 DCHECK_EQ(tagName.namespaceURI(), starAtom);
158 for (Element& element : ElementTraversal::descendantsOf(rootNode)) { 184 for (Element& element : ElementTraversal::descendantsOf(rootNode)) {
185 QUERY_STATS_INCREMENT(fastTagName);
159 if (matchesTagName(tagName, element)) { 186 if (matchesTagName(tagName, element)) {
160 SelectorQueryTrait::appendElement(output, element); 187 SelectorQueryTrait::appendElement(output, element);
161 if (SelectorQueryTrait::shouldOnlyMatchFirstElement) 188 if (SelectorQueryTrait::shouldOnlyMatchFirstElement)
162 return; 189 return;
163 } 190 }
164 } 191 }
165 } 192 }
166 193
167 inline bool SelectorQuery::canUseFastQuery( 194 inline bool SelectorQuery::canUseFastQuery(
168 const ContainerNode& rootNode) const { 195 const ContainerNode& rootNode) const {
(...skipping 100 matching lines...) Expand 10 before | Expand all | Expand 10 after
269 template <typename SelectorQueryTrait> 296 template <typename SelectorQueryTrait>
270 void SelectorQuery::executeForTraverseRoot( 297 void SelectorQuery::executeForTraverseRoot(
271 ContainerNode& traverseRoot, 298 ContainerNode& traverseRoot,
272 ContainerNode& rootNode, 299 ContainerNode& rootNode,
273 typename SelectorQueryTrait::OutputType& output) const { 300 typename SelectorQueryTrait::OutputType& output) const {
274 DCHECK_EQ(m_selectors.size(), 1u); 301 DCHECK_EQ(m_selectors.size(), 1u);
275 302
276 const CSSSelector& selector = *m_selectors[0]; 303 const CSSSelector& selector = *m_selectors[0];
277 304
278 for (Element& element : ElementTraversal::descendantsOf(traverseRoot)) { 305 for (Element& element : ElementTraversal::descendantsOf(traverseRoot)) {
306 QUERY_STATS_INCREMENT(fastScan);
279 if (selectorMatches(selector, element, rootNode)) { 307 if (selectorMatches(selector, element, rootNode)) {
280 SelectorQueryTrait::appendElement(output, element); 308 SelectorQueryTrait::appendElement(output, element);
281 if (SelectorQueryTrait::shouldOnlyMatchFirstElement) 309 if (SelectorQueryTrait::shouldOnlyMatchFirstElement)
282 return; 310 return;
283 } 311 }
284 } 312 }
285 } 313 }
286 314
287 bool SelectorQuery::selectorListMatches(ContainerNode& rootNode, 315 bool SelectorQuery::selectorListMatches(ContainerNode& rootNode,
288 Element& element) const { 316 Element& element) const {
289 for (const auto& selector : m_selectors) { 317 for (const auto& selector : m_selectors) {
290 if (selectorMatches(*selector, element, rootNode)) 318 if (selectorMatches(*selector, element, rootNode))
291 return true; 319 return true;
292 } 320 }
293 return false; 321 return false;
294 } 322 }
295 323
296 template <typename SelectorQueryTrait> 324 template <typename SelectorQueryTrait>
297 void SelectorQuery::executeSlow( 325 void SelectorQuery::executeSlow(
298 ContainerNode& rootNode, 326 ContainerNode& rootNode,
299 typename SelectorQueryTrait::OutputType& output) const { 327 typename SelectorQueryTrait::OutputType& output) const {
300 for (Element& element : ElementTraversal::descendantsOf(rootNode)) { 328 for (Element& element : ElementTraversal::descendantsOf(rootNode)) {
329 QUERY_STATS_INCREMENT(slowScan);
301 if (!selectorListMatches(rootNode, element)) 330 if (!selectorListMatches(rootNode, element))
302 continue; 331 continue;
303 SelectorQueryTrait::appendElement(output, element); 332 SelectorQueryTrait::appendElement(output, element);
304 if (SelectorQueryTrait::shouldOnlyMatchFirstElement) 333 if (SelectorQueryTrait::shouldOnlyMatchFirstElement)
305 return; 334 return;
306 } 335 }
307 } 336 }
308 337
309 // FIXME: Move the following helper functions, authorShadowRootOf, 338 // FIXME: Move the following helper functions, authorShadowRootOf,
310 // firstWithinTraversingShadowTree, nextTraversingShadowTree to the best place, 339 // firstWithinTraversingShadowTree, nextTraversingShadowTree to the best place,
(...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after
351 } 380 }
352 381
353 template <typename SelectorQueryTrait> 382 template <typename SelectorQueryTrait>
354 void SelectorQuery::executeSlowTraversingShadowTree( 383 void SelectorQuery::executeSlowTraversingShadowTree(
355 ContainerNode& rootNode, 384 ContainerNode& rootNode,
356 typename SelectorQueryTrait::OutputType& output) const { 385 typename SelectorQueryTrait::OutputType& output) const {
357 for (ContainerNode* node = nextTraversingShadowTree(rootNode, &rootNode); 386 for (ContainerNode* node = nextTraversingShadowTree(rootNode, &rootNode);
358 node; node = nextTraversingShadowTree(*node, &rootNode)) { 387 node; node = nextTraversingShadowTree(*node, &rootNode)) {
359 if (!node->isElementNode()) 388 if (!node->isElementNode())
360 continue; 389 continue;
390 QUERY_STATS_INCREMENT(slowTraversingShadowTreeScan);
361 Element* element = toElement(node); 391 Element* element = toElement(node);
362 if (!selectorListMatches(rootNode, *element)) 392 if (!selectorListMatches(rootNode, *element))
363 continue; 393 continue;
364 SelectorQueryTrait::appendElement(output, *element); 394 SelectorQueryTrait::appendElement(output, *element);
365 if (SelectorQueryTrait::shouldOnlyMatchFirstElement) 395 if (SelectorQueryTrait::shouldOnlyMatchFirstElement)
366 return; 396 return;
367 } 397 }
368 } 398 }
369 399
370 static const CSSSelector* selectorForIdLookup( 400 static const CSSSelector* selectorForIdLookup(
(...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after
412 // Fast path for querySelector*('#id'), querySelector*('tag#id'), 442 // Fast path for querySelector*('#id'), querySelector*('tag#id'),
413 // querySelector*('tag[id=example]'). 443 // querySelector*('tag[id=example]').
414 if (const CSSSelector* idSelector = selectorForIdLookup(firstSelector)) { 444 if (const CSSSelector* idSelector = selectorForIdLookup(firstSelector)) {
415 const AtomicString& idToMatch = idSelector->value(); 445 const AtomicString& idToMatch = idSelector->value();
416 if (rootNode.treeScope().containsMultipleElementsWithId(idToMatch)) { 446 if (rootNode.treeScope().containsMultipleElementsWithId(idToMatch)) {
417 const HeapVector<Member<Element>>& elements = 447 const HeapVector<Member<Element>>& elements =
418 rootNode.treeScope().getAllElementsById(idToMatch); 448 rootNode.treeScope().getAllElementsById(idToMatch);
419 for (const auto& element : elements) { 449 for (const auto& element : elements) {
420 if (!element->isDescendantOf(&rootNode)) 450 if (!element->isDescendantOf(&rootNode))
421 continue; 451 continue;
452 QUERY_STATS_INCREMENT(fastId);
422 if (selectorMatches(selector, *element, rootNode)) { 453 if (selectorMatches(selector, *element, rootNode)) {
423 SelectorQueryTrait::appendElement(output, *element); 454 SelectorQueryTrait::appendElement(output, *element);
424 if (SelectorQueryTrait::shouldOnlyMatchFirstElement) 455 if (SelectorQueryTrait::shouldOnlyMatchFirstElement)
425 return; 456 return;
426 } 457 }
427 } 458 }
428 return; 459 return;
429 } 460 }
430 Element* element = rootNode.treeScope().getElementById(idToMatch); 461 Element* element = rootNode.treeScope().getElementById(idToMatch);
431 if (!element) 462 if (!element)
432 return; 463 return;
433 if (!element->isDescendantOf(&rootNode)) 464 if (!element->isDescendantOf(&rootNode))
434 return; 465 return;
466 QUERY_STATS_INCREMENT(fastId);
435 if (selectorMatches(selector, *element, rootNode)) 467 if (selectorMatches(selector, *element, rootNode))
436 SelectorQueryTrait::appendElement(output, *element); 468 SelectorQueryTrait::appendElement(output, *element);
437 return; 469 return;
438 } 470 }
439 471
440 if (!firstSelector.tagHistory()) { 472 if (!firstSelector.tagHistory()) {
441 // Fast path for querySelector*('.foo'), and querySelector*('div'). 473 // Fast path for querySelector*('.foo'), and querySelector*('div').
442 switch (firstSelector.match()) { 474 switch (firstSelector.match()) {
443 case CSSSelector::Class: 475 case CSSSelector::Class:
444 collectElementsByClassName<SelectorQueryTrait>( 476 collectElementsByClassName<SelectorQueryTrait>(
(...skipping 72 matching lines...) Expand 10 before | Expand all | Expand 10 after
517 return m_entries 549 return m_entries
518 .insert(selectors, SelectorQuery::adopt(std::move(selectorList))) 550 .insert(selectors, SelectorQuery::adopt(std::move(selectorList)))
519 .storedValue->value.get(); 551 .storedValue->value.get();
520 } 552 }
521 553
522 void SelectorQueryCache::invalidate() { 554 void SelectorQueryCache::invalidate() {
523 m_entries.clear(); 555 m_entries.clear();
524 } 556 }
525 557
526 } // namespace blink 558 } // namespace blink
OLDNEW
« no previous file with comments | « third_party/WebKit/Source/core/dom/SelectorQuery.h ('k') | third_party/WebKit/Source/core/dom/SelectorQueryTest.cpp » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698