Replace WTF::move with WTFMove
[WebKit-https.git] / Source / WebCore / dom / SelectorQuery.cpp
1 /*
2  * Copyright (C) 2011, 2013, 2014 Apple Inc. All rights reserved.
3  * Copyright (C) 2014 Yusuke Suzuki <utatane.tea@gmail.com>
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  *
9  * 1.  Redistributions of source code must retain the above copyright
10  *     notice, this list of conditions and the following disclaimer.
11  * 2.  Redistributions in binary form must reproduce the above copyright
12  *     notice, this list of conditions and the following disclaimer in the
13  *     documentation and/or other materials provided with the distribution.
14  *
15  * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
16  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
17  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
18  * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
19  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
20  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
21  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
22  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
24  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25  */
26
27 #include "config.h"
28 #include "SelectorQuery.h"
29
30 #include "CSSParser.h"
31 #include "ElementDescendantIterator.h"
32 #include "SelectorChecker.h"
33 #include "StaticNodeList.h"
34 #include "StyledElement.h"
35
36 namespace WebCore {
37
38 #if !ASSERT_DISABLED
39 static bool isSingleTagNameSelector(const CSSSelector& selector)
40 {
41     return selector.isLastInTagHistory() && selector.match() == CSSSelector::Tag;
42 }
43
44 static bool isSingleClassNameSelector(const CSSSelector& selector)
45 {
46     return selector.isLastInTagHistory() && selector.match() == CSSSelector::Class;
47 }
48 #endif
49
50 enum class IdMatchingType : uint8_t {
51     None,
52     Rightmost,
53     Filter
54 };
55
56 static IdMatchingType findIdMatchingType(const CSSSelector& firstSelector)
57 {
58     bool inRightmost = true;
59     for (const CSSSelector* selector = &firstSelector; selector; selector = selector->tagHistory()) {
60         if (selector->match() == CSSSelector::Id) {
61             if (inRightmost)
62                 return IdMatchingType::Rightmost;
63             return IdMatchingType::Filter;
64         }
65         if (selector->relation() != CSSSelector::SubSelector)
66             inRightmost = false;
67     }
68     return IdMatchingType::None;
69 }
70
71 SelectorDataList::SelectorDataList(const CSSSelectorList& selectorList)
72 {
73     unsigned selectorCount = 0;
74     for (const CSSSelector* selector = selectorList.first(); selector; selector = CSSSelectorList::next(selector))
75         selectorCount++;
76
77     m_selectors.reserveInitialCapacity(selectorCount);
78     for (const CSSSelector* selector = selectorList.first(); selector; selector = CSSSelectorList::next(selector))
79         m_selectors.uncheckedAppend(SelectorData(selector));
80
81     if (selectorCount == 1) {
82         const CSSSelector& selector = *m_selectors.first().selector;
83         if (selector.isLastInTagHistory()) {
84             switch (selector.match()) {
85             case CSSSelector::Tag:
86                 m_matchType = TagNameMatch;
87                 break;
88             case CSSSelector::Class:
89                 m_matchType = ClassNameMatch;
90                 break;
91             case CSSSelector::Id:
92                 m_matchType = RightMostWithIdMatch;
93                 break;
94             default:
95                 m_matchType = CompilableSingle;
96                 break;
97             }
98         } else {
99             switch (findIdMatchingType(selector)) {
100             case IdMatchingType::None:
101                 m_matchType = CompilableSingle;
102                 break;
103             case IdMatchingType::Rightmost:
104                 m_matchType = RightMostWithIdMatch;
105                 break;
106             case IdMatchingType::Filter:
107                 m_matchType = CompilableSingleWithRootFilter;
108                 break;
109             }
110         }
111     } else
112         m_matchType = CompilableMultipleSelectorMatch;
113 }
114
115 inline bool SelectorDataList::selectorMatches(const SelectorData& selectorData, Element& element, const ContainerNode& rootNode) const
116 {
117     SelectorChecker selectorChecker(element.document());
118     SelectorChecker::CheckingContext selectorCheckingContext(SelectorChecker::Mode::QueryingRules);
119     selectorCheckingContext.scope = rootNode.isDocumentNode() ? nullptr : &rootNode;
120     unsigned ignoredSpecificity;
121     return selectorChecker.match(selectorData.selector, &element, selectorCheckingContext, ignoredSpecificity);
122 }
123
124 inline Element* SelectorDataList::selectorClosest(const SelectorData& selectorData, Element& element, const ContainerNode& rootNode) const
125 {
126     SelectorChecker selectorChecker(element.document());
127     SelectorChecker::CheckingContext selectorCheckingContext(SelectorChecker::Mode::QueryingRules);
128     selectorCheckingContext.scope = rootNode.isDocumentNode() ? nullptr : &rootNode;
129     Element* currentNode = &element;
130     unsigned ignoredSpecificity;
131     if (!selectorChecker.match(selectorData.selector, currentNode, selectorCheckingContext, ignoredSpecificity))
132         return nullptr;
133     return currentNode;
134 }
135
136 bool SelectorDataList::matches(Element& targetElement) const
137 {
138     for (auto& selctor : m_selectors) {
139         if (selectorMatches(selctor, targetElement, targetElement))
140             return true;
141     }
142     return false;
143 }
144
145 Element* SelectorDataList::closest(Element& targetElement) const
146 {
147     Element* currentNode = &targetElement;
148     do {
149         for (auto& selector : m_selectors) {
150             Element* candidateElement = selectorClosest(selector, *currentNode, targetElement);
151             if (candidateElement)
152                 return candidateElement;
153         }
154         currentNode = currentNode->parentElement();
155     } while (currentNode);
156     return nullptr;
157 }
158
159 struct AllElementExtractorSelectorQueryTrait {
160     typedef Vector<Ref<Element>> OutputType;
161     static const bool shouldOnlyMatchFirstElement = false;
162     ALWAYS_INLINE static void appendOutputForElement(OutputType& output, Element* element) { ASSERT(element); output.append(*element); }
163 };
164
165 RefPtr<NodeList> SelectorDataList::queryAll(ContainerNode& rootNode) const
166 {
167     Vector<Ref<Element>> result;
168     execute<AllElementExtractorSelectorQueryTrait>(rootNode, result);
169     return StaticElementList::adopt(result);
170 }
171
172 struct SingleElementExtractorSelectorQueryTrait {
173     typedef Element* OutputType;
174     static const bool shouldOnlyMatchFirstElement = true;
175     ALWAYS_INLINE static void appendOutputForElement(OutputType& output, Element* element)
176     {
177         ASSERT(element);
178         ASSERT(!output);
179         output = element;
180     }
181 };
182
183 Element* SelectorDataList::queryFirst(ContainerNode& rootNode) const
184 {
185     Element* result = nullptr;
186     execute<SingleElementExtractorSelectorQueryTrait>(rootNode, result);
187     return result;
188 }
189
190 static const CSSSelector* selectorForIdLookup(const ContainerNode& rootNode, const CSSSelector& firstSelector)
191 {
192     if (!rootNode.inDocument())
193         return nullptr;
194     if (rootNode.document().inQuirksMode())
195         return nullptr;
196
197     for (const CSSSelector* selector = &firstSelector; selector; selector = selector->tagHistory()) {
198         if (selector->match() == CSSSelector::Id)
199             return selector;
200         if (selector->relation() != CSSSelector::SubSelector)
201             break;
202     }
203
204     return nullptr;
205 }
206
207 static inline bool isTreeScopeRoot(const ContainerNode& node)
208 {
209     return node.isDocumentNode() || node.isShadowRoot();
210 }
211
212 template <typename SelectorQueryTrait>
213 ALWAYS_INLINE void SelectorDataList::executeFastPathForIdSelector(const ContainerNode& rootNode, const SelectorData& selectorData, const CSSSelector* idSelector, typename SelectorQueryTrait::OutputType& output) const
214 {
215     ASSERT(m_selectors.size() == 1);
216     ASSERT(idSelector);
217
218     const AtomicString& idToMatch = idSelector->value();
219     if (UNLIKELY(rootNode.treeScope().containsMultipleElementsWithId(idToMatch))) {
220         const Vector<Element*>* elements = rootNode.treeScope().getAllElementsById(idToMatch);
221         ASSERT(elements);
222         bool rootNodeIsTreeScopeRoot = isTreeScopeRoot(rootNode);
223         for (auto& element : *elements) {
224             if ((rootNodeIsTreeScopeRoot || element->isDescendantOf(&rootNode)) && selectorMatches(selectorData, *element, rootNode)) {
225                 SelectorQueryTrait::appendOutputForElement(output, element);
226                 if (SelectorQueryTrait::shouldOnlyMatchFirstElement)
227                     return;
228             }
229         }
230         return;
231     }
232
233     Element* element = rootNode.treeScope().getElementById(idToMatch);
234     if (!element || !(isTreeScopeRoot(rootNode) || element->isDescendantOf(&rootNode)))
235         return;
236     if (selectorMatches(selectorData, *element, rootNode))
237         SelectorQueryTrait::appendOutputForElement(output, element);
238 }
239
240 static ContainerNode& filterRootById(ContainerNode& rootNode, const CSSSelector& firstSelector)
241 {
242     if (!rootNode.inDocument())
243         return rootNode;
244     if (rootNode.document().inQuirksMode())
245         return rootNode;
246
247     // If there was an Id match in the rightmost Simple Selector, we should be in a RightMostWithIdMatch, not in filter.
248     // Thus we can skip the rightmost match.
249     const CSSSelector* selector = &firstSelector;
250     do {
251         ASSERT(selector->match() != CSSSelector::Id);
252         if (selector->relation() != CSSSelector::SubSelector)
253             break;
254         selector = selector->tagHistory();
255     } while (selector);
256
257     bool inAdjacentChain = false;
258     for (; selector; selector = selector->tagHistory()) {
259         if (selector->match() == CSSSelector::Id) {
260             const AtomicString& idToMatch = selector->value();
261             if (ContainerNode* searchRoot = rootNode.treeScope().getElementById(idToMatch)) {
262                 if (LIKELY(!rootNode.treeScope().containsMultipleElementsWithId(idToMatch))) {
263                     if (inAdjacentChain)
264                         searchRoot = searchRoot->parentNode();
265                     if (searchRoot && (isTreeScopeRoot(rootNode) || searchRoot == &rootNode || searchRoot->isDescendantOf(&rootNode)))
266                         return *searchRoot;
267                 }
268             }
269         }
270         if (selector->relation() == CSSSelector::SubSelector)
271             continue;
272         if (selector->relation() == CSSSelector::DirectAdjacent || selector->relation() == CSSSelector::IndirectAdjacent)
273             inAdjacentChain = true;
274         else
275             inAdjacentChain = false;
276     }
277     return rootNode;
278 }
279
280 static ALWAYS_INLINE bool localNameMatches(const Element& element, const AtomicString& localName, const AtomicString& lowercaseLocalName)
281 {
282     if (element.isHTMLElement() && element.document().isHTMLDocument())
283         return element.localName() == lowercaseLocalName;
284     return element.localName() == localName;
285
286 }
287
288 template <typename SelectorQueryTrait>
289 static inline void elementsForLocalName(const ContainerNode& rootNode, const AtomicString& localName, const AtomicString& lowercaseLocalName, typename SelectorQueryTrait::OutputType& output)
290 {
291     if (localName == lowercaseLocalName) {
292         for (auto& element : elementDescendants(const_cast<ContainerNode&>(rootNode))) {
293             if (element.tagQName().localName() == localName) {
294                 SelectorQueryTrait::appendOutputForElement(output, &element);
295                 if (SelectorQueryTrait::shouldOnlyMatchFirstElement)
296                 return;
297             }
298         }
299     } else {
300         for (auto& element : elementDescendants(const_cast<ContainerNode&>(rootNode))) {
301             if (localNameMatches(element, localName, lowercaseLocalName)) {
302                 SelectorQueryTrait::appendOutputForElement(output, &element);
303                 if (SelectorQueryTrait::shouldOnlyMatchFirstElement)
304                 return;
305             }
306         }
307     }
308 }
309
310 template <typename SelectorQueryTrait>
311 static inline void anyElement(const ContainerNode& rootNode, typename SelectorQueryTrait::OutputType& output)
312 {
313     for (auto& element : elementDescendants(const_cast<ContainerNode&>(rootNode))) {
314         SelectorQueryTrait::appendOutputForElement(output, &element);
315         if (SelectorQueryTrait::shouldOnlyMatchFirstElement)
316             return;
317     }
318 }
319
320
321 template <typename SelectorQueryTrait>
322 ALWAYS_INLINE void SelectorDataList::executeSingleTagNameSelectorData(const ContainerNode& rootNode, const SelectorData& selectorData, typename SelectorQueryTrait::OutputType& output) const
323 {
324     ASSERT(m_selectors.size() == 1);
325     ASSERT(isSingleTagNameSelector(*selectorData.selector));
326
327     const QualifiedName& tagQualifiedName = selectorData.selector->tagQName();
328     const AtomicString& selectorLocalName = tagQualifiedName.localName();
329     const AtomicString& selectorLowercaseLocalName = selectorData.selector->tagLowercaseLocalName();
330     const AtomicString& selectorNamespaceURI = tagQualifiedName.namespaceURI();
331
332     if (selectorNamespaceURI == starAtom) {
333         if (selectorLocalName != starAtom) {
334             // Common case: name defined, selectorNamespaceURI is a wildcard.
335             elementsForLocalName<SelectorQueryTrait>(rootNode, selectorLocalName, selectorLowercaseLocalName, output);
336         } else {
337             // Other fairly common case: both are wildcards.
338             anyElement<SelectorQueryTrait>(rootNode, output);
339         }
340     } else {
341         // Fallback: NamespaceURI is set, selectorLocalName may be starAtom.
342         for (auto& element : elementDescendants(const_cast<ContainerNode&>(rootNode))) {
343             if (element.namespaceURI() == selectorNamespaceURI && localNameMatches(element, selectorLocalName, selectorLowercaseLocalName)) {
344                 SelectorQueryTrait::appendOutputForElement(output, &element);
345                 if (SelectorQueryTrait::shouldOnlyMatchFirstElement)
346                     return;
347             }
348         }
349     }
350 }
351
352 template <typename SelectorQueryTrait>
353 ALWAYS_INLINE void SelectorDataList::executeSingleClassNameSelectorData(const ContainerNode& rootNode, const SelectorData& selectorData, typename SelectorQueryTrait::OutputType& output) const
354 {
355     ASSERT(m_selectors.size() == 1);
356     ASSERT(isSingleClassNameSelector(*selectorData.selector));
357
358     const AtomicString& className = selectorData.selector->value();
359     for (auto& element : elementDescendants(const_cast<ContainerNode&>(rootNode))) {
360         if (element.hasClass() && element.classNames().contains(className)) {
361             SelectorQueryTrait::appendOutputForElement(output, &element);
362             if (SelectorQueryTrait::shouldOnlyMatchFirstElement)
363                 return;
364         }
365     }
366 }
367
368 template <typename SelectorQueryTrait>
369 ALWAYS_INLINE void SelectorDataList::executeSingleSelectorData(const ContainerNode& rootNode, const ContainerNode& searchRootNode, const SelectorData& selectorData, typename SelectorQueryTrait::OutputType& output) const
370 {
371     ASSERT(m_selectors.size() == 1);
372
373     for (auto& element : elementDescendants(const_cast<ContainerNode&>(searchRootNode))) {
374         if (selectorMatches(selectorData, element, rootNode)) {
375             SelectorQueryTrait::appendOutputForElement(output, &element);
376             if (SelectorQueryTrait::shouldOnlyMatchFirstElement)
377                 return;
378         }
379     }
380 }
381
382 template <typename SelectorQueryTrait>
383 ALWAYS_INLINE void SelectorDataList::executeSingleMultiSelectorData(const ContainerNode& rootNode, typename SelectorQueryTrait::OutputType& output) const
384 {
385     for (auto& element : elementDescendants(const_cast<ContainerNode&>(rootNode))) {
386         for (auto& selector : m_selectors) {
387             if (selectorMatches(selector, element, rootNode)) {
388                 SelectorQueryTrait::appendOutputForElement(output, &element);
389                 if (SelectorQueryTrait::shouldOnlyMatchFirstElement)
390                     return;
391                 break;
392             }
393         }
394     }
395 }
396
397 #if ENABLE(CSS_SELECTOR_JIT)
398 template <typename SelectorQueryTrait>
399 ALWAYS_INLINE void SelectorDataList::executeCompiledSimpleSelectorChecker(const ContainerNode& searchRootNode, SelectorCompiler::QuerySelectorSimpleSelectorChecker selectorChecker, typename SelectorQueryTrait::OutputType& output, const SelectorData& selectorData) const
400 {
401     for (auto& element : elementDescendants(const_cast<ContainerNode&>(searchRootNode))) {
402 #if CSS_SELECTOR_JIT_PROFILING
403         selectorData.compiledSelectorUsed();
404 #else
405         UNUSED_PARAM(selectorData);
406 #endif
407         if (selectorChecker(&element)) {
408             SelectorQueryTrait::appendOutputForElement(output, &element);
409             if (SelectorQueryTrait::shouldOnlyMatchFirstElement)
410                 return;
411         }
412     }
413 }
414
415 template <typename SelectorQueryTrait>
416 ALWAYS_INLINE void SelectorDataList::executeCompiledSelectorCheckerWithCheckingContext(const ContainerNode& rootNode, const ContainerNode& searchRootNode, SelectorCompiler::QuerySelectorSelectorCheckerWithCheckingContext selectorChecker, typename SelectorQueryTrait::OutputType& output, const SelectorData& selectorData) const
417 {
418     SelectorChecker::CheckingContext checkingContext(SelectorChecker::Mode::QueryingRules);
419     checkingContext.scope = rootNode.isDocumentNode() ? nullptr : &rootNode;
420
421     for (auto& element : elementDescendants(const_cast<ContainerNode&>(searchRootNode))) {
422 #if CSS_SELECTOR_JIT_PROFILING
423         selectorData.compiledSelectorUsed();
424 #else
425         UNUSED_PARAM(selectorData);
426 #endif
427         if (selectorChecker(&element, &checkingContext)) {
428             SelectorQueryTrait::appendOutputForElement(output, &element);
429             if (SelectorQueryTrait::shouldOnlyMatchFirstElement)
430                 return;
431         }
432     }
433 }
434
435 template <typename SelectorQueryTrait>
436 ALWAYS_INLINE void SelectorDataList::executeCompiledSingleMultiSelectorData(const ContainerNode& rootNode, typename SelectorQueryTrait::OutputType& output) const
437 {
438     SelectorChecker::CheckingContext checkingContext(SelectorChecker::Mode::QueryingRules);
439     checkingContext.scope = rootNode.isDocumentNode() ? nullptr : &rootNode;
440     for (auto& element : elementDescendants(const_cast<ContainerNode&>(rootNode))) {
441         for (auto& selector : m_selectors) {
442 #if CSS_SELECTOR_JIT_PROFILING
443             selector.compiledSelectorUsed();
444 #endif
445             bool matched = false;
446             void* compiledSelectorChecker = selector.compiledSelectorCodeRef.code().executableAddress();
447             if (selector.compilationStatus == SelectorCompilationStatus::SimpleSelectorChecker) {
448                 auto selectorChecker = SelectorCompiler::querySelectorSimpleSelectorCheckerFunction(compiledSelectorChecker, selector.compilationStatus);
449                 matched = selectorChecker(&element);
450             } else {
451                 ASSERT(selector.compilationStatus == SelectorCompilationStatus::SelectorCheckerWithCheckingContext);
452                 auto selectorChecker = SelectorCompiler::querySelectorSelectorCheckerFunctionWithCheckingContext(compiledSelectorChecker, selector.compilationStatus);
453                 matched = selectorChecker(&element, &checkingContext);
454             }
455             if (matched) {
456                 SelectorQueryTrait::appendOutputForElement(output, &element);
457                 if (SelectorQueryTrait::shouldOnlyMatchFirstElement)
458                     return;
459                 break;
460             }
461         }
462     }
463 }
464
465 static bool isCompiledSelector(SelectorCompilationStatus compilationStatus)
466 {
467     return compilationStatus == SelectorCompilationStatus::SimpleSelectorChecker || compilationStatus == SelectorCompilationStatus::SelectorCheckerWithCheckingContext;
468 }
469
470 bool SelectorDataList::compileSelector(const SelectorData& selectorData, const ContainerNode& rootNode)
471 {
472     if (selectorData.compilationStatus != SelectorCompilationStatus::NotCompiled)
473         return isCompiledSelector(selectorData.compilationStatus);
474
475     JSC::VM& vm = rootNode.document().scriptExecutionContext()->vm();
476     selectorData.compilationStatus = SelectorCompiler::compileSelector(selectorData.selector, &vm, SelectorCompiler::SelectorContext::QuerySelector, selectorData.compiledSelectorCodeRef);
477     return isCompiledSelector(selectorData.compilationStatus);
478 }
479
480
481 #endif // ENABLE(CSS_SELECTOR_JIT)
482
483 template <typename SelectorQueryTrait>
484 ALWAYS_INLINE void SelectorDataList::execute(ContainerNode& rootNode, typename SelectorQueryTrait::OutputType& output) const
485 {
486     ContainerNode* searchRootNode = &rootNode;
487     switch (m_matchType) {
488     case RightMostWithIdMatch:
489         {
490         const SelectorData& selectorData = m_selectors.first();
491         if (const CSSSelector* idSelector = selectorForIdLookup(*searchRootNode, *selectorData.selector)) {
492             executeFastPathForIdSelector<SelectorQueryTrait>(*searchRootNode, m_selectors.first(), idSelector, output);
493             break;
494         }
495 #if ENABLE(CSS_SELECTOR_JIT)
496         if (compileSelector(selectorData, *searchRootNode))
497             goto CompiledSingleCase;
498 #endif // ENABLE(CSS_SELECTOR_JIT)
499         goto SingleSelectorCase;
500         ASSERT_NOT_REACHED();
501         }
502
503     case CompilableSingleWithRootFilter:
504     case CompilableSingle:
505         {
506 #if ENABLE(CSS_SELECTOR_JIT)
507         const SelectorData& selectorData = m_selectors.first();
508         ASSERT(selectorData.compilationStatus == SelectorCompilationStatus::NotCompiled);
509         ASSERT(m_matchType == CompilableSingle || m_matchType == CompilableSingleWithRootFilter);
510         if (compileSelector(selectorData, *searchRootNode)) {
511             if (m_matchType == CompilableSingle) {
512                 m_matchType = CompiledSingle;
513                 goto CompiledSingleCase;
514             }
515             ASSERT(m_matchType == CompilableSingleWithRootFilter);
516             m_matchType = CompiledSingleWithRootFilter;
517             goto CompiledSingleWithRootFilterCase;
518         }
519 #endif // ENABLE(CSS_SELECTOR_JIT)
520         if (m_matchType == CompilableSingle) {
521             m_matchType = SingleSelector;
522             goto SingleSelectorCase;
523         }
524         ASSERT(m_matchType == CompilableSingleWithRootFilter);
525         m_matchType = SingleSelectorWithRootFilter;
526         goto SingleSelectorWithRootFilterCase;
527         ASSERT_NOT_REACHED();
528         }
529
530 #if ENABLE(CSS_SELECTOR_JIT)
531     case CompiledSingleWithRootFilter:
532         CompiledSingleWithRootFilterCase:
533         searchRootNode = &filterRootById(*searchRootNode, *m_selectors.first().selector);
534         FALLTHROUGH;
535     case CompiledSingle:
536         {
537         CompiledSingleCase:
538         const SelectorData& selectorData = m_selectors.first();
539         void* compiledSelectorChecker = selectorData.compiledSelectorCodeRef.code().executableAddress();
540         if (selectorData.compilationStatus == SelectorCompilationStatus::SimpleSelectorChecker) {
541             SelectorCompiler::QuerySelectorSimpleSelectorChecker selectorChecker = SelectorCompiler::querySelectorSimpleSelectorCheckerFunction(compiledSelectorChecker, selectorData.compilationStatus);
542             executeCompiledSimpleSelectorChecker<SelectorQueryTrait>(*searchRootNode, selectorChecker, output, selectorData);
543         } else {
544             ASSERT(selectorData.compilationStatus == SelectorCompilationStatus::SelectorCheckerWithCheckingContext);
545             SelectorCompiler::QuerySelectorSelectorCheckerWithCheckingContext selectorChecker = SelectorCompiler::querySelectorSelectorCheckerFunctionWithCheckingContext(compiledSelectorChecker, selectorData.compilationStatus);
546             executeCompiledSelectorCheckerWithCheckingContext<SelectorQueryTrait>(rootNode, *searchRootNode, selectorChecker, output, selectorData);
547         }
548         break;
549         }
550 #else
551     case CompiledSingleWithRootFilter:
552     case CompiledSingle:
553         ASSERT_NOT_REACHED();
554 #if ASSERT_DISABLED
555         FALLTHROUGH;
556 #endif
557 #endif // ENABLE(CSS_SELECTOR_JIT)
558
559     case SingleSelectorWithRootFilter:
560         SingleSelectorWithRootFilterCase:
561         searchRootNode = &filterRootById(*searchRootNode, *m_selectors.first().selector);
562         FALLTHROUGH;
563     case SingleSelector:
564         SingleSelectorCase:
565         executeSingleSelectorData<SelectorQueryTrait>(rootNode, *searchRootNode, m_selectors.first(), output);
566         break;
567
568     case TagNameMatch:
569         executeSingleTagNameSelectorData<SelectorQueryTrait>(*searchRootNode, m_selectors.first(), output);
570         break;
571     case ClassNameMatch:
572         executeSingleClassNameSelectorData<SelectorQueryTrait>(*searchRootNode, m_selectors.first(), output);
573         break;
574     case CompilableMultipleSelectorMatch:
575 #if ENABLE(CSS_SELECTOR_JIT)
576         {
577         for (auto& selector : m_selectors) {
578             if (!compileSelector(selector, *searchRootNode)) {
579                 m_matchType = MultipleSelectorMatch;
580                 goto MultipleSelectorMatch;
581             }
582         }
583         m_matchType = CompiledMultipleSelectorMatch;
584         goto CompiledMultipleSelectorMatch;
585         }
586 #else
587         FALLTHROUGH;
588 #endif // ENABLE(CSS_SELECTOR_JIT)
589     case CompiledMultipleSelectorMatch:
590 #if ENABLE(CSS_SELECTOR_JIT)
591         CompiledMultipleSelectorMatch:
592         executeCompiledSingleMultiSelectorData<SelectorQueryTrait>(*searchRootNode, output);
593         break;
594 #else
595         FALLTHROUGH;
596 #endif // ENABLE(CSS_SELECTOR_JIT)
597     case MultipleSelectorMatch:
598 #if ENABLE(CSS_SELECTOR_JIT)
599         MultipleSelectorMatch:
600 #endif
601         executeSingleMultiSelectorData<SelectorQueryTrait>(*searchRootNode, output);
602         break;
603     }
604 }
605
606 SelectorQuery::SelectorQuery(CSSSelectorList&& selectorList)
607     : m_selectorList(WTFMove(selectorList))
608     , m_selectors(m_selectorList)
609 {
610 }
611
612 SelectorQuery* SelectorQueryCache::add(const String& selectors, Document& document, ExceptionCode& ec)
613 {
614     auto it = m_entries.find(selectors);
615     if (it != m_entries.end())
616         return it->value.get();
617
618     CSSParser parser(document);
619     CSSSelectorList selectorList;
620     parser.parseSelector(selectors, selectorList);
621
622     if (!selectorList.first() || selectorList.hasInvalidSelector()) {
623         ec = SYNTAX_ERR;
624         return nullptr;
625     }
626
627     // Throw a NAMESPACE_ERR if the selector includes any namespace prefixes.
628     if (selectorList.selectorsNeedNamespaceResolution()) {
629         ec = NAMESPACE_ERR;
630         return nullptr;
631     }
632
633     const int maximumSelectorQueryCacheSize = 256;
634     if (m_entries.size() == maximumSelectorQueryCacheSize)
635         m_entries.remove(m_entries.begin());
636
637     return m_entries.add(selectors, std::make_unique<SelectorQuery>(WTFMove(selectorList))).iterator->value.get();
638 }
639
640 }