Created
September 12, 2014 18:28
-
-
Save Constellation/b3ad0e9158c5b265232a to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| diff --git a/LayoutTests/ChangeLog b/LayoutTests/ChangeLog | |
| index 1948fa9..392decf 100644 | |
| --- a/LayoutTests/ChangeLog | |
| +++ b/LayoutTests/ChangeLog | |
| @@ -1,3 +1,13 @@ | |
| +2014-09-12 Yusuke Suzuki <utatane.tea@gmail.com> | |
| + | |
| + CSS JIT: Apply CSS JIT to SelectorQuery with multiple selectors | |
| + https://bugs.webkit.org/show_bug.cgi?id=135255 | |
| + | |
| + Reviewed by NOBODY (OOPS!). | |
| + | |
| + * fast/selectors/querySelector-multiple-selectors-expected.txt: Added. | |
| + * fast/selectors/querySelector-multiple-selectors.html: Added. | |
| + | |
| 2014-09-11 Alexey Proskuryakov <ap@apple.com> | |
| fast/forms/submit-to-blank-multiple-times.html crashes with JSC_slowPathAllocsBetweenGCs | |
| diff --git a/LayoutTests/fast/selectors/querySelector-multiple-selectors-expected.txt b/LayoutTests/fast/selectors/querySelector-multiple-selectors-expected.txt | |
| new file mode 100644 | |
| index 0000000..c1d6ed7 | |
| --- /dev/null | |
| +++ b/LayoutTests/fast/selectors/querySelector-multiple-selectors-expected.txt | |
| @@ -0,0 +1,17 @@ | |
| +Test cases when the multiple selectors are provided | |
| + | |
| +On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE". | |
| + | |
| + | |
| +PASS document.body.querySelectorAll("t0, t1").length is 4 | |
| +PASS document.body.querySelectorAll("#t2, t3").length is 1 | |
| +PASS document.body.querySelectorAll("t4> #t5, t6 t7.ok").length is 2 | |
| +PASS document.body.querySelectorAll("t8 + t9, t10 t11.ok").length is 1 | |
| +PASS document.body.querySelectorAll("t8 + t9, t10 t11.ok").length is 1 | |
| +PASS document.body.querySelectorAll(".t12, .t13, .t14, .t15").length is 2 | |
| +CSS JIT compile may fail, fallback to the slow path. | |
| +PASS document.body.querySelectorAll(".t16, .t17>t18:nth-last-child(1)").length is 3 | |
| +PASS successfullyParsed is true | |
| + | |
| +TEST COMPLETE | |
| + | |
| diff --git a/LayoutTests/fast/selectors/querySelector-multiple-selectors.html b/LayoutTests/fast/selectors/querySelector-multiple-selectors.html | |
| new file mode 100644 | |
| index 0000000..c5ff97e | |
| --- /dev/null | |
| +++ b/LayoutTests/fast/selectors/querySelector-multiple-selectors.html | |
| @@ -0,0 +1,69 @@ | |
| +<!doctype html> | |
| +<html id=htmlDocument> | |
| +<head> | |
| +<script src="../../resources/js-test-pre.js"></script> | |
| +</head> | |
| +<body> | |
| +<div style="display:none"> | |
| +<t0> | |
| + <t0></t0> | |
| +</t0> | |
| +<t1> | |
| + <t0></t0> | |
| +</t1> | |
| + | |
| + | |
| +<t3></t3> | |
| + | |
| +<t4> | |
| + <t5 id="t5"></t5> | |
| +</t4> | |
| +<t6> | |
| + <ng> | |
| + <t7 class="ok"></t7> | |
| + </ng> | |
| +</t6> | |
| + | |
| +<t8></t8> | |
| +<t9></t9> | |
| +<t9></t9> | |
| +<t10> | |
| + <t11 class="ng"></t11> | |
| +</t10> | |
| + | |
| +<ok class="t12"></ok> | |
| +<ok class="t13 t14 t15"></ok> | |
| + | |
| +<ok class="t16"></ok> | |
| +<ok class="t17"> | |
| + <t18></t18> | |
| + <t18></t18> | |
| + <t18></t18> | |
| + <t18></t18> | |
| + <t18></t18> | |
| +</ok> | |
| +<ok class="t17"> | |
| + <t18></t18> | |
| + <t18></t18> | |
| + <t18></t18> | |
| + <t18></t18> | |
| + <t18></t18> | |
| +</ok> | |
| + | |
| +</div> | |
| +</body> | |
| +<script> | |
| +description('Test cases when the multiple selectors are provided'); | |
| + | |
| +shouldBe('document.body.querySelectorAll("t0, t1").length', '4'); | |
| +shouldBe('document.body.querySelectorAll("#t2, t3").length', '1'); | |
| +shouldBe('document.body.querySelectorAll("t4> #t5, t6 t7.ok").length', '2'); | |
| +shouldBe('document.body.querySelectorAll("t8 + t9, t10 t11.ok").length', '1'); | |
| +shouldBe('document.body.querySelectorAll("t8 + t9, t10 t11.ok").length', '1'); | |
| +shouldBe('document.body.querySelectorAll(".t12, .t13, .t14, .t15").length', '2'); | |
| + | |
| +debug('CSS JIT compile may fail, fallback to the slow path.') | |
| +shouldBe('document.body.querySelectorAll(".t16, .t17>t18:nth-last-child(1)").length', '3'); | |
| +</script> | |
| +<script src="../../resources/js-test-post.js"></script> | |
| +</html> | |
| diff --git a/Source/WebCore/ChangeLog b/Source/WebCore/ChangeLog | |
| index b744640..a9770cd 100644 | |
| --- a/Source/WebCore/ChangeLog | |
| +++ b/Source/WebCore/ChangeLog | |
| @@ -1,3 +1,33 @@ | |
| +2014-09-12 Yusuke Suzuki <utatane.tea@gmail.com> | |
| + | |
| + CSS JIT: Apply CSS JIT to SelectorQuery with multiple selectors | |
| + https://bugs.webkit.org/show_bug.cgi?id=135255 | |
| + | |
| + Reviewed by NOBODY (OOPS!). | |
| + | |
| + After dropping SelectorCheckerFastPath, Dromaeo cssquery-jquery test | |
| + result becomes significantly worse. 400.26/s to 348.16/s, 13% | |
| + performance regression. | |
| + | |
| + Investigated the cause of it and we found that the test results for | |
| + querySelector with multiple selectors causes performance regressions. | |
| + | |
| + To solve this, we attempt to JIT compile all selectors in multiple | |
| + selectors. And if compiling some selectors is failed, SelectorQuery | |
| + fallbacks to the slower implementation. | |
| + | |
| + This change improves the performance. After applying this patch, | |
| + cssquery-jquery test result becomes 418.71/s, 4.61% better than the | |
| + previous good performance case. | |
| + | |
| + Test: fast/selectors/querySelector-multiple-selectors.html | |
| + | |
| + * dom/SelectorQuery.cpp: | |
| + (WebCore::SelectorDataList::SelectorDataList): | |
| + (WebCore::SelectorDataList::executeCompiledSingleMultiSelectorData): | |
| + (WebCore::SelectorDataList::execute): | |
| + * dom/SelectorQuery.h: | |
| + | |
| 2014-09-11 Ryuan Choi <ryuan.choi@gmail.com> | |
| Unreviewed build fix attempt on windows port since r173553. | |
| diff --git a/Source/WebCore/dom/SelectorQuery.cpp b/Source/WebCore/dom/SelectorQuery.cpp | |
| index c9dd60e..03aa542 100644 | |
| --- a/Source/WebCore/dom/SelectorQuery.cpp | |
| +++ b/Source/WebCore/dom/SelectorQuery.cpp | |
| @@ -108,7 +108,7 @@ static IdMatchingType findIdMatchingType(const CSSSelector& firstSelector) | |
| } | |
| } | |
| } else | |
| - m_matchType = MultipleSelectorMatch; | |
| + m_matchType = CompilableMultipleSelectorMatch; | |
| } | |
| inline bool SelectorDataList::selectorMatches(const SelectorData& selectorData, Element& element, const ContainerNode& rootNode) const | |
| @@ -389,6 +389,37 @@ ALWAYS_INLINE void SelectorDataList::executeCompiledSelectorCheckerWithCheckingC | |
| } | |
| } | |
| +template <typename SelectorQueryTrait> | |
| +ALWAYS_INLINE void SelectorDataList::executeCompiledSingleMultiSelectorData(const ContainerNode& rootNode, typename SelectorQueryTrait::OutputType& output) const | |
| +{ | |
| + SelectorChecker::CheckingContext checkingContext(SelectorChecker::Mode::QueryingRules); | |
| + checkingContext.scope = rootNode.isDocumentNode() ? nullptr : &rootNode; | |
| + unsigned selectorCount = m_selectors.size(); | |
| + for (auto& element : elementDescendants(const_cast<ContainerNode&>(rootNode))) { | |
| + for (unsigned i = 0; i < selectorCount; ++i) { | |
| +#if CSS_SELECTOR_JIT_PROFILING | |
| + m_selectors[i].compiledSelectorUsed(); | |
| +#endif | |
| + bool matched = false; | |
| + void* compiledSelectorChecker = m_selectors[i].compiledSelectorCodeRef.code().executableAddress(); | |
| + if (m_selectors[i].compilationStatus == SelectorCompilationStatus::SimpleSelectorChecker) { | |
| + SelectorCompiler::SimpleSelectorChecker selectorChecker = SelectorCompiler::simpleSelectorCheckerFunction(compiledSelectorChecker, m_selectors[i].compilationStatus); | |
| + matched = selectorChecker(&element); | |
| + } else { | |
| + ASSERT(m_selectors[i].compilationStatus == SelectorCompilationStatus::SelectorCheckerWithCheckingContext); | |
| + SelectorCompiler::SelectorCheckerWithCheckingContext selectorChecker = SelectorCompiler::selectorCheckerFunctionWithCheckingContext(compiledSelectorChecker, m_selectors[i].compilationStatus); | |
| + matched = selectorChecker(&element, &checkingContext); | |
| + } | |
| + if (matched) { | |
| + SelectorQueryTrait::appendOutputForElement(output, &element); | |
| + if (SelectorQueryTrait::shouldOnlyMatchFirstElement) | |
| + return; | |
| + break; | |
| + } | |
| + } | |
| + } | |
| +} | |
| + | |
| static bool isCompiledSelector(SelectorCompilationStatus compilationStatus) | |
| { | |
| return compilationStatus == SelectorCompilationStatus::SimpleSelectorChecker || compilationStatus == SelectorCompilationStatus::SelectorCheckerWithCheckingContext; | |
| @@ -489,7 +520,34 @@ ALWAYS_INLINE void SelectorDataList::execute(ContainerNode& rootNode, typename S | |
| case ClassNameMatch: | |
| executeSingleClassNameSelectorData<SelectorQueryTrait>(*searchRootNode, m_selectors.first(), output); | |
| break; | |
| + case CompilableMultipleSelectorMatch: | |
| +#if ENABLE(CSS_SELECTOR_JIT) | |
| + { | |
| + unsigned selectorCount = m_selectors.size(); | |
| + for (unsigned i = 0; i < selectorCount; ++i) { | |
| + if (!compileSelector(m_selectors[i], *searchRootNode)) { | |
| + m_matchType = MultipleSelectorMatch; | |
| + goto MultipleSelectorMatch; | |
| + } | |
| + } | |
| + m_matchType = CompiledMultipleSelectorMatch; | |
| + goto CompiledMultipleSelectorMatch; | |
| +#else | |
| + FALLTHROUGH; | |
| +#endif // ENABLE(CSS_SELECTOR_JIT) | |
| + } | |
| + case CompiledMultipleSelectorMatch: | |
| +#if ENABLE(CSS_SELECTOR_JIT) | |
| + CompiledMultipleSelectorMatch: | |
| + executeCompiledSingleMultiSelectorData<SelectorQueryTrait>(*searchRootNode, output); | |
| + break; | |
| +#else | |
| + FALLTHROUGH; | |
| +#endif // ENABLE(CSS_SELECTOR_JIT) | |
| case MultipleSelectorMatch: | |
| +#if ENABLE(CSS_SELECTOR_JIT) | |
| + MultipleSelectorMatch: | |
| +#endif | |
| executeSingleMultiSelectorData<SelectorQueryTrait>(*searchRootNode, output); | |
| break; | |
| } | |
| diff --git a/Source/WebCore/dom/SelectorQuery.h b/Source/WebCore/dom/SelectorQuery.h | |
| index c075be3..a0f4bbc 100644 | |
| --- a/Source/WebCore/dom/SelectorQuery.h | |
| +++ b/Source/WebCore/dom/SelectorQuery.h | |
| @@ -89,6 +89,7 @@ class SelectorDataList { | |
| #if ENABLE(CSS_SELECTOR_JIT) | |
| template <typename SelectorQueryTrait> void executeCompiledSimpleSelectorChecker(const ContainerNode& searchRootNode, SelectorCompiler::SimpleSelectorChecker, typename SelectorQueryTrait::OutputType&, const SelectorData&) const; | |
| template <typename SelectorQueryTrait> void executeCompiledSelectorCheckerWithCheckingContext(const ContainerNode& rootNode, const ContainerNode& searchRootNode, SelectorCompiler::SelectorCheckerWithCheckingContext, typename SelectorQueryTrait::OutputType&, const SelectorData&) const; | |
| + template <typename SelectorQueryTrait> void executeCompiledSingleMultiSelectorData(const ContainerNode& rootNode, typename SelectorQueryTrait::OutputType&) const; | |
| static bool compileSelector(const SelectorData&, const ContainerNode& rootNode); | |
| #endif // ENABLE(CSS_SELECTOR_JIT) | |
| @@ -96,8 +97,10 @@ class SelectorDataList { | |
| mutable enum MatchType { | |
| CompilableSingle, | |
| CompilableSingleWithRootFilter, | |
| + CompilableMultipleSelectorMatch, | |
| CompiledSingle, | |
| CompiledSingleWithRootFilter, | |
| + CompiledMultipleSelectorMatch, | |
| SingleSelector, | |
| RightMostWithIdMatch, | |
| TagNameMatch, |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment