Diff
Modified: trunk/Source/WebCore/ChangeLog (175771 => 175772)
--- trunk/Source/WebCore/ChangeLog 2014-11-08 00:40:54 UTC (rev 175771)
+++ trunk/Source/WebCore/ChangeLog 2014-11-08 02:05:36 UTC (rev 175772)
@@ -1,3 +1,76 @@
+2014-11-07 Benjamin Poulain <[email protected]>
+
+ Make the Selector's specificity part of Selector matching
+ https://bugs.webkit.org/show_bug.cgi?id=138486
+
+ Reviewed by Andreas Kling.
+
+ In CSS Selectors Level 4, the specificity of selectors is computed dynamically
+ based on which element is being matched.
+
+ For example, a selector:
+ :matches(#foo, .bar, baz)
+ has a specificity of
+ (1, 0, 0) on <baz id=foo class=bar>
+ (0, 1, 0) on <baz class=bar>
+ (0, 0, 1) on <baz>
+
+ Previously, the specificity of each selector was computed statically when populating
+ RuleSet. With more recent CSS, this gives us the wrong specificity because we do not know
+ how the selectors applies to the target.
+
+ This patch moves one tiny step in the direction of dynamic specificity. The specificity
+ is removed from RuleSet and is moved inside Selector Matching.
+
+ There is one bit worth keeping static: matching based on rule hash. This path is important
+ to avoid spending time compiling trivial selectors.
+ In order to keep rule hash matching working, the RuleData store which specificity class
+ the rule has in addition to the information about matching/not-matching. When going through
+ the fast path in ElementCollector, we compute the right specificity based on the type
+ of rule-hash matching.
+
+ * css/CSSSelector.cpp:
+ (WebCore::CSSSelector::specificityForOneSelector):
+ * css/CSSSelector.h:
+ * css/ElementRuleCollector.cpp:
+ (WebCore::ElementRuleCollector::addMatchedRule):
+ (WebCore::ElementRuleCollector::sortAndTransferMatchedRules):
+ (WebCore::ElementRuleCollector::ruleMatches):
+ (WebCore::ElementRuleCollector::collectMatchingRulesForList):
+ (WebCore::compareRules):
+ * css/ElementRuleCollector.h:
+ * css/RuleSet.cpp:
+ (WebCore::computeMatchBasedOnRuleHash):
+ (WebCore::RuleData::RuleData):
+ (WebCore::isSelectorMatchingHTMLBasedOnRuleHash): Deleted.
+ * css/RuleSet.h:
+ (WebCore::RuleData::matchBasedOnRuleHash):
+ (WebCore::RuleData::hasRightmostSelectorMatchingHTMLBasedOnRuleHash): Deleted.
+ (WebCore::RuleData::specificity): Deleted.
+ * css/SelectorChecker.cpp:
+ (WebCore::SelectorChecker::match):
+ * css/SelectorChecker.h:
+ * css/StyleResolver.h:
+ (WebCore::checkRegionSelector):
+ * cssjit/SelectorCompiler.cpp:
+ (WebCore::SelectorCompiler::SelectorCodeGenerator::SelectorCodeGenerator):
+ (WebCore::SelectorCompiler::SelectorCodeGenerator::generateSelectorChecker):
+ * cssjit/SelectorCompiler.h:
+ (WebCore::SelectorCompiler::ruleCollectorSimpleSelectorCheckerFunction):
+ (WebCore::SelectorCompiler::querySelectorSimpleSelectorCheckerFunction):
+ (WebCore::SelectorCompiler::ruleCollectorSelectorCheckerFunctionWithCheckingContext):
+ (WebCore::SelectorCompiler::querySelectorSelectorCheckerFunctionWithCheckingContext):
+ (WebCore::SelectorCompiler::simpleSelectorCheckerFunction): Deleted.
+ (WebCore::SelectorCompiler::selectorCheckerFunctionWithCheckingContext): Deleted.
+ * dom/SelectorQuery.cpp:
+ (WebCore::SelectorDataList::selectorMatches):
+ (WebCore::SelectorDataList::selectorClosest):
+ (WebCore::SelectorDataList::executeCompiledSimpleSelectorChecker):
+ (WebCore::SelectorDataList::executeCompiledSelectorCheckerWithCheckingContext):
+ (WebCore::SelectorDataList::executeCompiledSingleMultiSelectorData):
+ (WebCore::SelectorDataList::execute):
+ * dom/SelectorQuery.h:
+
2014-11-07 Alexey Proskuryakov <[email protected]>
CSP is enforced for eval in report-only mode on first page load
Modified: trunk/Source/WebCore/css/CSSSelector.cpp (175771 => 175772)
--- trunk/Source/WebCore/css/CSSSelector.cpp 2014-11-08 00:40:54 UTC (rev 175771)
+++ trunk/Source/WebCore/css/CSSSelector.cpp 2014-11-08 02:05:36 UTC (rev 175772)
@@ -94,7 +94,7 @@
{
switch (match()) {
case Id:
- return 0x10000;
+ return static_cast<unsigned>(SelectorSpecificityIncrement::ClassA);
case PagePseudoClass:
break;
@@ -125,11 +125,11 @@
case Contain:
case Begin:
case End:
- return 0x100;
+ return static_cast<unsigned>(SelectorSpecificityIncrement::ClassB);
case Tag:
- return (tagQName().localName() != starAtom) ? 1 : 0;
+ return (tagQName().localName() != starAtom) ? static_cast<unsigned>(SelectorSpecificityIncrement::ClassC) : 0;
case PseudoElement:
- return 1;
+ return static_cast<unsigned>(SelectorSpecificityIncrement::ClassC);
case Unknown:
return 0;
}
Modified: trunk/Source/WebCore/css/CSSSelector.h (175771 => 175772)
--- trunk/Source/WebCore/css/CSSSelector.h 2014-11-08 00:40:54 UTC (rev 175771)
+++ trunk/Source/WebCore/css/CSSSelector.h 2014-11-08 02:05:36 UTC (rev 175772)
@@ -29,6 +29,12 @@
namespace WebCore {
class CSSSelectorList;
+ enum class SelectorSpecificityIncrement {
+ ClassA = 0x10000,
+ ClassB = 0x100,
+ ClassC = 1
+ };
+
// this class represents a selector for a StyleRule
class CSSSelector {
WTF_MAKE_FAST_ALLOCATED;
Modified: trunk/Source/WebCore/css/ElementRuleCollector.cpp (175771 => 175772)
--- trunk/Source/WebCore/css/ElementRuleCollector.cpp 2014-11-08 00:40:54 UTC (rev 175771)
+++ trunk/Source/WebCore/css/ElementRuleCollector.cpp 2014-11-08 02:05:36 UTC (rev 175772)
@@ -86,11 +86,11 @@
return m_matchedRuleList;
}
-inline void ElementRuleCollector::addMatchedRule(const RuleData* rule)
+inline void ElementRuleCollector::addMatchedRule(const MatchedRule& matchedRule)
{
if (!m_matchedRules)
- m_matchedRules = std::make_unique<Vector<const RuleData*, 32>>();
- m_matchedRules->append(rule);
+ m_matchedRules = std::make_unique<Vector<MatchedRule, 32>>();
+ m_matchedRules->append(matchedRule);
}
void ElementRuleCollector::clearMatchedRules()
@@ -202,18 +202,18 @@
sortMatchedRules();
- Vector<const RuleData*, 32>& matchedRules = *m_matchedRules;
+ Vector<MatchedRule, 32>& matchedRules = *m_matchedRules;
if (m_mode == SelectorChecker::Mode::CollectingRules) {
- for (unsigned i = 0; i < matchedRules.size(); ++i)
- m_matchedRuleList.append(matchedRules[i]->rule());
+ for (const MatchedRule& matchedRule : matchedRules)
+ m_matchedRuleList.append(matchedRule.ruleData->rule());
return;
}
// Now transfer the set of matched rules over to our list of declarations.
- for (unsigned i = 0; i < matchedRules.size(); i++) {
- if (m_style && matchedRules[i]->containsUncommonAttributeSelector())
+ for (const MatchedRule& matchedRule : matchedRules) {
+ if (m_style && matchedRule.ruleData->containsUncommonAttributeSelector())
m_style->setUnique();
- m_result.addMatchedProperties(matchedRules[i]->rule()->properties(), matchedRules[i]->rule(), matchedRules[i]->linkMatchType(), matchedRules[i]->propertyWhitelistType(MatchingUARulesScope::isMatchingUARules()));
+ m_result.addMatchedProperties(matchedRule.ruleData->rule()->properties(), matchedRule.ruleData->rule(), matchedRule.ruleData->linkMatchType(), matchedRule.ruleData->propertyWhitelistType(MatchingUARulesScope::isMatchingUARules()));
}
}
@@ -274,12 +274,31 @@
sortAndTransferMatchedRules();
}
-inline bool ElementRuleCollector::ruleMatches(const RuleData& ruleData)
+inline bool ElementRuleCollector::ruleMatches(const RuleData& ruleData, unsigned& specificity)
{
// We know a sufficiently simple single part selector matches simply because we found it from the rule hash when filtering the RuleSet.
// This is limited to HTML only so we don't need to check the namespace (because of tag name match).
- if (ruleData.hasRightmostSelectorMatchingHTMLBasedOnRuleHash() && m_element.isHTMLElement()) {
+ MatchBasedOnRuleHash matchBasedOnRuleHash = ruleData.matchBasedOnRuleHash();
+ if (matchBasedOnRuleHash != MatchBasedOnRuleHash::None && m_element.isHTMLElement()) {
ASSERT_WITH_MESSAGE(m_pseudoStyleRequest.pseudoId == NOPSEUDO, "If we match based on the rule hash while collecting for a particular pseudo element ID, we would add incorrect rules for that pseudo element ID. We should never end in ruleMatches() with a pseudo element if the ruleData cannot match any pseudo element.");
+
+ switch (matchBasedOnRuleHash) {
+ case MatchBasedOnRuleHash::None:
+ ASSERT_NOT_REACHED();
+ break;
+ case MatchBasedOnRuleHash::Universal:
+ specificity = 0;
+ break;
+ case MatchBasedOnRuleHash::ClassA:
+ specificity = static_cast<unsigned>(SelectorSpecificityIncrement::ClassA);
+ break;
+ case MatchBasedOnRuleHash::ClassB:
+ specificity = static_cast<unsigned>(SelectorSpecificityIncrement::ClassB);
+ break;
+ case MatchBasedOnRuleHash::ClassC:
+ specificity = static_cast<unsigned>(SelectorSpecificityIncrement::ClassC);
+ break;
+ }
return true;
}
@@ -296,12 +315,15 @@
}
if (compiledSelectorChecker && ruleData.compilationStatus() == SelectorCompilationStatus::SimpleSelectorChecker) {
- SelectorCompiler::SimpleSelectorChecker selectorChecker = SelectorCompiler::simpleSelectorCheckerFunction(compiledSelectorChecker, ruleData.compilationStatus());
- ASSERT_WITH_MESSAGE(!selectorChecker(&m_element) || m_pseudoStyleRequest.pseudoId == NOPSEUDO, "When matching pseudo elements, we should never compile a selector checker without context unless it cannot match anything.");
+ SelectorCompiler::RuleCollectorSimpleSelectorChecker selectorChecker = SelectorCompiler::ruleCollectorSimpleSelectorCheckerFunction(compiledSelectorChecker, ruleData.compilationStatus());
+#if !ASSERT_MSG_DISABLED
+ unsigned ignoreSpecificity;
+ ASSERT_WITH_MESSAGE(!selectorChecker(&m_element, &ignoreSpecificity) || m_pseudoStyleRequest.pseudoId == NOPSEUDO, "When matching pseudo elements, we should never compile a selector checker without context unless it cannot match anything.");
+#endif
#if CSS_SELECTOR_JIT_PROFILING
ruleData.compiledSelectorUsed();
#endif
- return selectorChecker(&m_element);
+ return selectorChecker(&m_element, &specificity);
}
#endif // ENABLE(CSS_SELECTOR_JIT)
@@ -315,18 +337,18 @@
if (compiledSelectorChecker) {
ASSERT(ruleData.compilationStatus() == SelectorCompilationStatus::SelectorCheckerWithCheckingContext);
- SelectorCompiler::SelectorCheckerWithCheckingContext selectorChecker = SelectorCompiler::selectorCheckerFunctionWithCheckingContext(compiledSelectorChecker, ruleData.compilationStatus());
+ SelectorCompiler::RuleCollectorSelectorCheckerWithCheckingContext selectorChecker = SelectorCompiler::ruleCollectorSelectorCheckerFunctionWithCheckingContext(compiledSelectorChecker, ruleData.compilationStatus());
#if CSS_SELECTOR_JIT_PROFILING
ruleData.compiledSelectorUsed();
#endif
- return selectorChecker(&m_element, &context);
+ return selectorChecker(&m_element, &context, &specificity);
}
#endif // ENABLE(CSS_SELECTOR_JIT)
// Slow path.
SelectorChecker selectorChecker(m_element.document());
- return selectorChecker.match(ruleData.selector(), &m_element, context);
+ return selectorChecker.match(ruleData.selector(), &m_element, context, specificity);
}
void ElementRuleCollector::collectMatchingRulesForList(const Vector<RuleData>* rules, const MatchRequest& matchRequest, StyleResolver::RuleRange& ruleRange)
@@ -354,23 +376,24 @@
if (m_sameOriginOnly && !ruleData.hasDocumentSecurityOrigin())
continue;
- if (ruleMatches(ruleData)) {
+ unsigned specificity;
+ if (ruleMatches(ruleData, specificity)) {
// Update our first/last rule indices in the matched rules array.
++ruleRange.lastRuleIndex;
if (ruleRange.firstRuleIndex == -1)
ruleRange.firstRuleIndex = ruleRange.lastRuleIndex;
// Add this rule to our list of matched rules.
- addMatchedRule(&ruleData);
+ addMatchedRule({&ruleData, specificity});
}
}
}
-static inline bool compareRules(const RuleData* r1, const RuleData* r2)
+static inline bool compareRules(MatchedRule r1, MatchedRule r2)
{
- unsigned specificity1 = r1->specificity();
- unsigned specificity2 = r2->specificity();
- return (specificity1 == specificity2) ? r1->position() < r2->position() : specificity1 < specificity2;
+ unsigned specificity1 = r1.specificity;
+ unsigned specificity2 = r2.specificity;
+ return (specificity1 == specificity2) ? r1.ruleData->position() < r2.ruleData->position() : specificity1 < specificity2;
}
void ElementRuleCollector::sortMatchedRules()
Modified: trunk/Source/WebCore/css/ElementRuleCollector.h (175771 => 175772)
--- trunk/Source/WebCore/css/ElementRuleCollector.h 2014-11-08 00:40:54 UTC (rev 175771)
+++ trunk/Source/WebCore/css/ElementRuleCollector.h 2014-11-08 02:05:36 UTC (rev 175772)
@@ -38,6 +38,11 @@
class RuleSet;
class SelectorFilter;
+struct MatchedRule {
+ const RuleData* ruleData;
+ unsigned specificity;
+};
+
class ElementRuleCollector {
public:
ElementRuleCollector(Element& element, RenderStyle* style, const DocumentRuleSets& ruleSets, const SelectorFilter& selectorFilter)
@@ -81,12 +86,12 @@
void collectMatchingRules(const MatchRequest&, StyleResolver::RuleRange&);
void collectMatchingRulesForRegion(const MatchRequest&, StyleResolver::RuleRange&);
void collectMatchingRulesForList(const Vector<RuleData>*, const MatchRequest&, StyleResolver::RuleRange&);
- bool ruleMatches(const RuleData&);
+ bool ruleMatches(const RuleData&, unsigned &specificity);
void sortMatchedRules();
void sortAndTransferMatchedRules();
- void addMatchedRule(const RuleData*);
+ void addMatchedRule(const MatchedRule&);
Element& m_element;
RenderStyle* m_style;
@@ -100,7 +105,7 @@
SelectorChecker::Mode m_mode;
bool m_canUseFastReject;
- std::unique_ptr<Vector<const RuleData*, 32>> m_matchedRules;
+ std::unique_ptr<Vector<MatchedRule, 32>> m_matchedRules;
// Output.
Vector<RefPtr<StyleRule>> m_matchedRuleList;
Modified: trunk/Source/WebCore/css/RuleSet.cpp (175771 => 175772)
--- trunk/Source/WebCore/css/RuleSet.cpp 2014-11-08 00:40:54 UTC (rev 175771)
+++ trunk/Source/WebCore/css/RuleSet.cpp 2014-11-08 02:05:36 UTC (rev 175772)
@@ -53,18 +53,28 @@
// -----------------------------------------------------------------
-static inline bool isSelectorMatchingHTMLBasedOnRuleHash(const CSSSelector& selector)
+static inline MatchBasedOnRuleHash computeMatchBasedOnRuleHash(const CSSSelector& selector)
{
if (selector.tagHistory())
- return false;
+ return MatchBasedOnRuleHash::None;
if (selector.match() == CSSSelector::Tag) {
- const AtomicString& selectorNamespace = selector.tagQName().namespaceURI();
- return selectorNamespace == starAtom || selectorNamespace == xhtmlNamespaceURI;
+ const QualifiedName& tagQualifiedName = selector.tagQName();
+ const AtomicString& selectorNamespace = tagQualifiedName.namespaceURI();
+ if (selectorNamespace == starAtom || selectorNamespace == xhtmlNamespaceURI) {
+ if (tagQualifiedName == anyQName())
+ return MatchBasedOnRuleHash::Universal;
+ return MatchBasedOnRuleHash::ClassC;
+ }
+ return MatchBasedOnRuleHash::None;
}
if (SelectorChecker::isCommonPseudoClassSelector(&selector))
- return true;
- return selector.match() == CSSSelector::Id || selector.match() == CSSSelector::Class;
+ return MatchBasedOnRuleHash::ClassB;
+ if (selector.match() == CSSSelector::Id)
+ return MatchBasedOnRuleHash::ClassA;
+ if (selector.match() == CSSSelector::Class)
+ return MatchBasedOnRuleHash::ClassB;
+ return MatchBasedOnRuleHash::None;
}
static bool selectorCanMatchPseudoElement(const CSSSelector& rootSelector)
@@ -149,8 +159,7 @@
, m_selectorIndex(selectorIndex)
, m_hasDocumentSecurityOrigin(addRuleFlags & RuleHasDocumentSecurityOrigin)
, m_position(position)
- , m_specificity(selector()->specificity())
- , m_hasRightmostSelectorMatchingHTMLBasedOnRuleHash(isSelectorMatchingHTMLBasedOnRuleHash(*selector()))
+ , m_matchBasedOnRuleHash(static_cast<unsigned>(computeMatchBasedOnRuleHash(*selector())))
, m_canMatchPseudoElement(selectorCanMatchPseudoElement(*selector()))
, m_containsUncommonAttributeSelector(WebCore::containsUncommonAttributeSelector(selector()))
, m_linkMatchType(SelectorChecker::determineLinkMatchType(selector()))
Modified: trunk/Source/WebCore/css/RuleSet.h (175771 => 175772)
--- trunk/Source/WebCore/css/RuleSet.h 2014-11-08 00:40:54 UTC (rev 175771)
+++ trunk/Source/WebCore/css/RuleSet.h 2014-11-08 02:05:36 UTC (rev 175772)
@@ -54,6 +54,14 @@
class StyleRuleRegion;
class StyleSheetContents;
+enum class MatchBasedOnRuleHash : unsigned {
+ None,
+ Universal,
+ ClassA,
+ ClassB,
+ ClassC
+};
+
class RuleData {
public:
static const unsigned maximumSelectorComponentCount = 8192;
@@ -66,9 +74,8 @@
unsigned selectorIndex() const { return m_selectorIndex; }
bool canMatchPseudoElement() const { return m_canMatchPseudoElement; }
- bool hasRightmostSelectorMatchingHTMLBasedOnRuleHash() const { return m_hasRightmostSelectorMatchingHTMLBasedOnRuleHash; }
+ MatchBasedOnRuleHash matchBasedOnRuleHash() const { return static_cast<MatchBasedOnRuleHash>(m_matchBasedOnRuleHash); }
bool containsUncommonAttributeSelector() const { return m_containsUncommonAttributeSelector; }
- unsigned specificity() const { return m_specificity; }
unsigned linkMatchType() const { return m_linkMatchType; }
bool hasDocumentSecurityOrigin() const { return m_hasDocumentSecurityOrigin; }
PropertyWhitelistType propertyWhitelistType(bool isMatchingUARules = false) const { return isMatchingUARules ? PropertyWhitelistNone : static_cast<PropertyWhitelistType>(m_propertyWhitelistType); }
@@ -101,8 +108,7 @@
// This number was picked fairly arbitrarily. We can probably lower it if we need to.
// Some simple testing showed <100,000 RuleData's on large sites.
unsigned m_position : 18;
- unsigned m_specificity : 24;
- unsigned m_hasRightmostSelectorMatchingHTMLBasedOnRuleHash : 1;
+ unsigned m_matchBasedOnRuleHash : 3;
unsigned m_canMatchPseudoElement : 1;
unsigned m_containsUncommonAttributeSelector : 1;
unsigned m_linkMatchType : 2; // SelectorChecker::LinkMatchMask
Modified: trunk/Source/WebCore/css/SelectorChecker.cpp (175771 => 175772)
--- trunk/Source/WebCore/css/SelectorChecker.cpp 2014-11-08 00:40:54 UTC (rev 175771)
+++ trunk/Source/WebCore/css/SelectorChecker.cpp 2014-11-08 02:05:36 UTC (rev 175772)
@@ -168,7 +168,7 @@
{
}
-bool SelectorChecker::match(const CSSSelector* selector, Element* element, const CheckingContext& providedContext) const
+bool SelectorChecker::match(const CSSSelector* selector, Element* element, const CheckingContext& providedContext, unsigned& specificity) const
{
CheckingContextWithStatus context(providedContext, selector, element);
PseudoId pseudoId = NOPSEUDO;
@@ -176,6 +176,8 @@
return false;
if (context.pseudoId != NOPSEUDO && context.pseudoId != pseudoId)
return false;
+
+ specificity = selector->specificity();
if (context.pseudoId == NOPSEUDO && pseudoId != NOPSEUDO) {
if (context.resolvingMode == Mode::ResolvingStyle && pseudoId < FIRST_INTERNAL_PSEUDOID)
context.elementStyle->setHasPseudoStyle(pseudoId);
Modified: trunk/Source/WebCore/css/SelectorChecker.h (175771 => 175772)
--- trunk/Source/WebCore/css/SelectorChecker.h 2014-11-08 00:40:54 UTC (rev 175771)
+++ trunk/Source/WebCore/css/SelectorChecker.h 2014-11-08 02:05:36 UTC (rev 175772)
@@ -72,7 +72,7 @@
struct CheckingContextWithStatus;
- bool match(const CSSSelector*, Element*, const CheckingContext&) const;
+ bool match(const CSSSelector*, Element*, const CheckingContext&, unsigned& specificity) const;
static bool tagMatches(const Element*, const QualifiedName&);
static bool isCommonPseudoClassSelector(const CSSSelector*);
Modified: trunk/Source/WebCore/css/StyleResolver.h (175771 => 175772)
--- trunk/Source/WebCore/css/StyleResolver.h 2014-11-08 00:40:54 UTC (rev 175771)
+++ trunk/Source/WebCore/css/StyleResolver.h 2014-11-08 02:05:36 UTC (rev 175772)
@@ -572,7 +572,8 @@
SelectorChecker selectorChecker(regionElement->document());
for (const CSSSelector* s = regionSelector; s; s = CSSSelectorList::next(s)) {
SelectorChecker::CheckingContext selectorCheckingContext(SelectorChecker::Mode::QueryingRules);
- if (selectorChecker.match(s, regionElement, selectorCheckingContext))
+ unsigned ignoredSpecificity;
+ if (selectorChecker.match(s, regionElement, selectorCheckingContext, ignoredSpecificity))
return true;
}
return false;
Modified: trunk/Source/WebCore/cssjit/SelectorCompiler.cpp (175771 => 175772)
--- trunk/Source/WebCore/cssjit/SelectorCompiler.cpp 2014-11-08 00:40:54 UTC (rev 175771)
+++ trunk/Source/WebCore/cssjit/SelectorCompiler.cpp 2014-11-08 02:05:36 UTC (rev 175772)
@@ -357,9 +357,7 @@
StackAllocator::StackReference m_lastVisitedElement;
StackAllocator::StackReference m_startElement;
-#if CSS_SELECTOR_JIT_DEBUGGING
const CSSSelector* m_originalSelector;
-#endif
};
const Assembler::RegisterID SelectorCodeGenerator::returnRegister = JSC::GPRInfo::returnValueGPR;
@@ -798,9 +796,7 @@
, m_functionType(FunctionType::SimpleSelectorChecker)
, m_visitedMode(VisitedMode::None)
, m_descendantBacktrackingStartInUse(false)
-#if CSS_SELECTOR_JIT_DEBUGGING
, m_originalSelector(rootSelector)
-#endif
{
#if CSS_SELECTOR_JIT_DEBUGGING
dataLogF("Compiling \"%s\"\n", m_originalSelector->selectorText().utf8().data());
@@ -1609,6 +1605,14 @@
generateRequestedPseudoElementEqualsToSelectorPseudoElement(failureOnFunctionEntry, m_selectorFragments.first(), checkingContextRegister);
}
+ if (m_selectorContext == SelectorContext::RuleCollector) {
+ unsigned specificity = m_originalSelector->specificity();
+ if (m_functionType == FunctionType::SelectorCheckerWithCheckingContext)
+ m_assembler.store32(Assembler::TrustedImm32(specificity), JSC::GPRInfo::argumentGPR2);
+ else
+ m_assembler.store32(Assembler::TrustedImm32(specificity), JSC::GPRInfo::argumentGPR1);
+ }
+
computeBacktrackingMemoryRequirements(m_selectorFragments);
unsigned availableRegisterCount = m_registerAllocator.reserveCallerSavedRegisters(m_selectorFragments.registerRequirements);
Modified: trunk/Source/WebCore/cssjit/SelectorCompiler.h (175771 => 175772)
--- trunk/Source/WebCore/cssjit/SelectorCompiler.h 2014-11-08 00:40:54 UTC (rev 175771)
+++ trunk/Source/WebCore/cssjit/SelectorCompiler.h 2014-11-08 02:05:36 UTC (rev 175772)
@@ -77,22 +77,37 @@
QuerySelector
};
-typedef unsigned (*SimpleSelectorChecker)(Element*);
-typedef unsigned (*SelectorCheckerWithCheckingContext)(Element*, const SelectorChecker::CheckingContext*);
+typedef unsigned (*RuleCollectorSimpleSelectorChecker)(Element*, unsigned*);
+typedef unsigned (*QuerySelectorSimpleSelectorChecker)(Element*);
+
+typedef unsigned (*RuleCollectorSelectorCheckerWithCheckingContext)(Element*, const SelectorChecker::CheckingContext*, unsigned*);
+typedef unsigned (*QuerySelectorSelectorCheckerWithCheckingContext)(Element*, const SelectorChecker::CheckingContext*);
+
SelectorCompilationStatus compileSelector(const CSSSelector*, JSC::VM*, SelectorContext, JSC::MacroAssemblerCodeRef& outputCodeRef);
-inline SimpleSelectorChecker simpleSelectorCheckerFunction(void* executableAddress, SelectorCompilationStatus compilationStatus)
+inline RuleCollectorSimpleSelectorChecker ruleCollectorSimpleSelectorCheckerFunction(void* executableAddress, SelectorCompilationStatus compilationStatus)
{
ASSERT_UNUSED(compilationStatus, compilationStatus == SelectorCompilationStatus::SimpleSelectorChecker);
- return reinterpret_cast<SimpleSelectorChecker>(executableAddress);
+ return reinterpret_cast<RuleCollectorSimpleSelectorChecker>(executableAddress);
}
-inline SelectorCheckerWithCheckingContext selectorCheckerFunctionWithCheckingContext(void* executableAddress, SelectorCompilationStatus compilationStatus)
+inline QuerySelectorSimpleSelectorChecker querySelectorSimpleSelectorCheckerFunction(void* executableAddress, SelectorCompilationStatus compilationStatus)
{
+ ASSERT_UNUSED(compilationStatus, compilationStatus == SelectorCompilationStatus::SimpleSelectorChecker);
+ return reinterpret_cast<QuerySelectorSimpleSelectorChecker>(executableAddress);
+}
+
+inline RuleCollectorSelectorCheckerWithCheckingContext ruleCollectorSelectorCheckerFunctionWithCheckingContext(void* executableAddress, SelectorCompilationStatus compilationStatus)
+{
ASSERT_UNUSED(compilationStatus, compilationStatus == SelectorCompilationStatus::SelectorCheckerWithCheckingContext);
- return reinterpret_cast<SelectorCheckerWithCheckingContext>(executableAddress);
+ return reinterpret_cast<RuleCollectorSelectorCheckerWithCheckingContext>(executableAddress);
}
+inline QuerySelectorSelectorCheckerWithCheckingContext querySelectorSelectorCheckerFunctionWithCheckingContext(void* executableAddress, SelectorCompilationStatus compilationStatus)
+{
+ ASSERT_UNUSED(compilationStatus, compilationStatus == SelectorCompilationStatus::SelectorCheckerWithCheckingContext);
+ return reinterpret_cast<QuerySelectorSelectorCheckerWithCheckingContext>(executableAddress);
+}
} // namespace SelectorCompiler
} // namespace WebCore
Modified: trunk/Source/WebCore/dom/SelectorQuery.cpp (175771 => 175772)
--- trunk/Source/WebCore/dom/SelectorQuery.cpp 2014-11-08 00:40:54 UTC (rev 175771)
+++ trunk/Source/WebCore/dom/SelectorQuery.cpp 2014-11-08 02:05:36 UTC (rev 175772)
@@ -117,7 +117,8 @@
SelectorChecker selectorChecker(element.document());
SelectorChecker::CheckingContext selectorCheckingContext(SelectorChecker::Mode::QueryingRules);
selectorCheckingContext.scope = rootNode.isDocumentNode() ? nullptr : &rootNode;
- return selectorChecker.match(selectorData.selector, &element, selectorCheckingContext);
+ unsigned ignoredSpecificity;
+ return selectorChecker.match(selectorData.selector, &element, selectorCheckingContext, ignoredSpecificity);
}
inline Element* SelectorDataList::selectorClosest(const SelectorData& selectorData, Element& element, const ContainerNode& rootNode) const
@@ -126,7 +127,8 @@
SelectorChecker::CheckingContext selectorCheckingContext(SelectorChecker::Mode::QueryingRules);
selectorCheckingContext.scope = rootNode.isDocumentNode() ? nullptr : &rootNode;
Element* currentNode = &element;
- if (!selectorChecker.match(selectorData.selector, currentNode, selectorCheckingContext))
+ unsigned ignoredSpecificity;
+ if (!selectorChecker.match(selectorData.selector, currentNode, selectorCheckingContext, ignoredSpecificity))
return nullptr;
return currentNode;
}
@@ -381,7 +383,7 @@
#if ENABLE(CSS_SELECTOR_JIT)
template <typename SelectorQueryTrait>
-ALWAYS_INLINE void SelectorDataList::executeCompiledSimpleSelectorChecker(const ContainerNode& searchRootNode, SelectorCompiler::SimpleSelectorChecker selectorChecker, typename SelectorQueryTrait::OutputType& output, const SelectorData& selectorData) const
+ALWAYS_INLINE void SelectorDataList::executeCompiledSimpleSelectorChecker(const ContainerNode& searchRootNode, SelectorCompiler::QuerySelectorSimpleSelectorChecker selectorChecker, typename SelectorQueryTrait::OutputType& output, const SelectorData& selectorData) const
{
for (auto& element : elementDescendants(const_cast<ContainerNode&>(searchRootNode))) {
#if CSS_SELECTOR_JIT_PROFILING
@@ -398,7 +400,7 @@
}
template <typename SelectorQueryTrait>
-ALWAYS_INLINE void SelectorDataList::executeCompiledSelectorCheckerWithCheckingContext(const ContainerNode& rootNode, const ContainerNode& searchRootNode, SelectorCompiler::SelectorCheckerWithCheckingContext selectorChecker, typename SelectorQueryTrait::OutputType& output, const SelectorData& selectorData) const
+ALWAYS_INLINE void SelectorDataList::executeCompiledSelectorCheckerWithCheckingContext(const ContainerNode& rootNode, const ContainerNode& searchRootNode, SelectorCompiler::QuerySelectorSelectorCheckerWithCheckingContext selectorChecker, typename SelectorQueryTrait::OutputType& output, const SelectorData& selectorData) const
{
SelectorChecker::CheckingContext checkingContext(SelectorChecker::Mode::QueryingRules);
checkingContext.scope = rootNode.isDocumentNode() ? nullptr : &rootNode;
@@ -431,11 +433,11 @@
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);
+ SelectorCompiler::QuerySelectorSimpleSelectorChecker selectorChecker = SelectorCompiler::querySelectorSimpleSelectorCheckerFunction(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);
+ SelectorCompiler::QuerySelectorSelectorCheckerWithCheckingContext selectorChecker = SelectorCompiler::querySelectorSelectorCheckerFunctionWithCheckingContext(compiledSelectorChecker, m_selectors[i].compilationStatus);
matched = selectorChecker(&element, &checkingContext);
}
if (matched) {
@@ -524,11 +526,11 @@
const SelectorData& selectorData = m_selectors.first();
void* compiledSelectorChecker = selectorData.compiledSelectorCodeRef.code().executableAddress();
if (selectorData.compilationStatus == SelectorCompilationStatus::SimpleSelectorChecker) {
- SelectorCompiler::SimpleSelectorChecker selectorChecker = SelectorCompiler::simpleSelectorCheckerFunction(compiledSelectorChecker, selectorData.compilationStatus);
+ SelectorCompiler::QuerySelectorSimpleSelectorChecker selectorChecker = SelectorCompiler::querySelectorSimpleSelectorCheckerFunction(compiledSelectorChecker, selectorData.compilationStatus);
executeCompiledSimpleSelectorChecker<SelectorQueryTrait>(*searchRootNode, selectorChecker, output, selectorData);
} else {
ASSERT(selectorData.compilationStatus == SelectorCompilationStatus::SelectorCheckerWithCheckingContext);
- SelectorCompiler::SelectorCheckerWithCheckingContext selectorChecker = SelectorCompiler::selectorCheckerFunctionWithCheckingContext(compiledSelectorChecker, selectorData.compilationStatus);
+ SelectorCompiler::QuerySelectorSelectorCheckerWithCheckingContext selectorChecker = SelectorCompiler::querySelectorSelectorCheckerFunctionWithCheckingContext(compiledSelectorChecker, selectorData.compilationStatus);
executeCompiledSelectorCheckerWithCheckingContext<SelectorQueryTrait>(rootNode, *searchRootNode, selectorChecker, output, selectorData);
}
break;
Modified: trunk/Source/WebCore/dom/SelectorQuery.h (175771 => 175772)
--- trunk/Source/WebCore/dom/SelectorQuery.h 2014-11-08 00:40:54 UTC (rev 175771)
+++ trunk/Source/WebCore/dom/SelectorQuery.h 2014-11-08 02:05:36 UTC (rev 175772)
@@ -89,8 +89,8 @@
template <typename SelectorQueryTrait> void executeSingleSelectorData(const ContainerNode& rootNode, const SelectorData&, typename SelectorQueryTrait::OutputType&) const;
template <typename SelectorQueryTrait> void executeSingleMultiSelectorData(const ContainerNode& rootNode, typename SelectorQueryTrait::OutputType&) const;
#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 executeCompiledSimpleSelectorChecker(const ContainerNode& searchRootNode, SelectorCompiler::QuerySelectorSimpleSelectorChecker, typename SelectorQueryTrait::OutputType&, const SelectorData&) const;
+ template <typename SelectorQueryTrait> void executeCompiledSelectorCheckerWithCheckingContext(const ContainerNode& rootNode, const ContainerNode& searchRootNode, SelectorCompiler::QuerySelectorSelectorCheckerWithCheckingContext, 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)