Changeset 225596 in webkit


Ignore:
Timestamp:
Dec 6, 2017 2:24:06 PM (6 years ago)
Author:
Antti Koivisto
Message:

Prefer ids and classes over tag names in selector filter
https://bugs.webkit.org/show_bug.cgi?id=180433
<rdar://problem/35859103>

Reviewed by Zalan Bujtas.

There are only four slots in the filter and currently we just pick whatever identifiers we find traversing the selector
from right to left. More specific selector types are on average more valuable (id > class > tag) so we should prefer them.

This appears to be 4-5% StyleBench progression.

  • css/RuleSet.cpp:

(WebCore::RuleData::RuleData):

  • css/SelectorFilter.cpp:

(WebCore::collectSimpleSelectorHash):
(WebCore::collectSelectorHashes):

This function collects all hashes from the selector.

(WebCore::chooseSelectorHashesForFilter):

This function chooses the most valuable hashes to use with the filter.

(WebCore::SelectorFilter::collectHashes):

Factor into two separate steps.

(WebCore::collectDescendantSelectorIdentifierHashes): Deleted.
(WebCore::SelectorFilter::collectIdentifierHashes): Deleted.

  • css/SelectorFilter.h:

(WebCore::SelectorFilter::fastRejectSelector const):

Location:
trunk/Source/WebCore
Files:
4 edited

Legend:

Unmodified
Added
Removed
  • trunk/Source/WebCore/ChangeLog

    r225594 r225596  
     12017-12-06  Antti Koivisto  <antti@apple.com>
     2
     3        Prefer ids and classes over tag names in selector filter
     4        https://bugs.webkit.org/show_bug.cgi?id=180433
     5        <rdar://problem/35859103>
     6
     7        Reviewed by Zalan Bujtas.
     8
     9        There are only four slots in the filter and currently we just pick whatever identifiers we find traversing the selector
     10        from right to left. More specific selector types are on average more valuable (id > class > tag) so we should prefer them.
     11
     12        This appears to be 4-5% StyleBench progression.
     13
     14        * css/RuleSet.cpp:
     15        (WebCore::RuleData::RuleData):
     16        * css/SelectorFilter.cpp:
     17        (WebCore::collectSimpleSelectorHash):
     18        (WebCore::collectSelectorHashes):
     19
     20            This function collects all hashes from the selector.
     21
     22        (WebCore::chooseSelectorHashesForFilter):
     23
     24            This function chooses the most valuable hashes to use with the filter.
     25
     26        (WebCore::SelectorFilter::collectHashes):
     27
     28            Factor into two separate steps.
     29
     30        (WebCore::collectDescendantSelectorIdentifierHashes): Deleted.
     31        (WebCore::SelectorFilter::collectIdentifierHashes): Deleted.
     32        * css/SelectorFilter.h:
     33        (WebCore::SelectorFilter::fastRejectSelector const):
     34
    1352017-12-06  Jer Noble  <jer.noble@apple.com>
    236
  • trunk/Source/WebCore/css/RuleSet.cpp

    r225482 r225596  
    159159    , m_linkMatchType(SelectorChecker::determineLinkMatchType(selector()))
    160160    , m_propertyWhitelistType(determinePropertyWhitelistType(selector()))
     161    , m_descendantSelectorIdentifierHashes(SelectorFilter::collectHashes(*selector()))
    161162#if ENABLE(CSS_SELECTOR_JIT) && CSS_SELECTOR_JIT_PROFILING
    162163    , m_compiledSelectorUseCount(0)
     
    165166    ASSERT(m_position == position);
    166167    ASSERT(m_selectorIndex == selectorIndex);
    167     SelectorFilter::collectIdentifierHashes(*selector(), m_descendantSelectorIdentifierHashes);
    168168}
    169169
  • trunk/Source/WebCore/css/SelectorFilter.cpp

    r225482 r225596  
    9797}
    9898
    99 static inline void collectDescendantSelectorIdentifierHashes(const CSSSelector& selector, const SelectorFilter::Hashes& hashes, SelectorFilter::Hashes::iterator& hashIt)
    100 {
    101     auto addIfNew = [&] (unsigned hash) {
    102         for (auto it = hashes.begin(); it != hashIt; ++it) {
    103             if (*it == hash)
    104                 return;
    105         }
    106         *hashIt = hash;
    107         hashIt++;
    108     };
    109 
     99struct CollectedSelectorHashes {
     100    using HashVector = Vector<unsigned, 8>;
     101    HashVector ids;
     102    HashVector classes;
     103    HashVector tags;
     104};
     105
     106static inline void collectSimpleSelectorHash(CollectedSelectorHashes& collectedHashes, const CSSSelector& selector)
     107{
    110108    switch (selector.match()) {
    111109    case CSSSelector::Id:
    112110        if (!selector.value().isEmpty())
    113             addIfNew(selector.value().impl()->existingHash() * IdAttributeSalt);
     111            collectedHashes.ids.append(selector.value().impl()->existingHash() * IdAttributeSalt);
    114112        break;
    115113    case CSSSelector::Class:
    116114        if (!selector.value().isEmpty())
    117             addIfNew(selector.value().impl()->existingHash() * ClassAttributeSalt);
     115            collectedHashes.classes.append(selector.value().impl()->existingHash() * ClassAttributeSalt);
    118116        break;
    119117    case CSSSelector::Tag: {
    120118        auto& tagLowercaseLocalName = selector.tagLowercaseLocalName();
    121119        if (tagLowercaseLocalName != starAtom())
    122             addIfNew(tagLowercaseLocalName.impl()->existingHash() * TagNameSalt);
     120            collectedHashes.tags.append(tagLowercaseLocalName.impl()->existingHash() * TagNameSalt);
    123121        break;
    124122    }
     
    128126}
    129127
    130 void SelectorFilter::collectIdentifierHashes(const CSSSelector& rightmostSelector, Hashes& hashes)
    131 {
     128static CollectedSelectorHashes collectSelectorHashes(const CSSSelector& rightmostSelector)
     129{
     130    CollectedSelectorHashes collectedHashes;
     131
    132132    auto* selector = &rightmostSelector;
    133133    auto relation = selector->relation();
    134 
    135     auto hashIt = hashes.begin();
    136134
    137135    // Skip the topmost selector. It is handled quickly by the rule hashes.
     
    142140        case CSSSelector::Subselector:
    143141            if (!skipOverSubselectors)
    144                 collectDescendantSelectorIdentifierHashes(*selector, hashes, hashIt);
     142                collectSimpleSelectorHash(collectedHashes, *selector);
    145143            break;
    146144        case CSSSelector::DirectAdjacent:
     
    152150        case CSSSelector::Child:
    153151            skipOverSubselectors = false;
    154             collectDescendantSelectorIdentifierHashes(*selector, hashes, hashIt);
     152            collectSimpleSelectorHash(collectedHashes, *selector);
    155153            break;
    156154        }
    157         if (hashIt == hashes.end())
    158             return;
    159155        relation = selector->relation();
    160156    }
    161 
    162     *hashIt = 0;
    163 }
    164 
    165 }
    166 
     157    return collectedHashes;
     158}
     159
     160static SelectorFilter::Hashes chooseSelectorHashesForFilter(const CollectedSelectorHashes& collectedSelectorHashes)
     161{
     162    SelectorFilter::Hashes resultHashes;
     163    unsigned index = 0;
     164
     165    auto addIfNew = [&] (unsigned hash) {
     166        for (unsigned i = 0; i < index; ++i) {
     167            if (resultHashes[i] == hash)
     168                return;
     169        }
     170        resultHashes[index++] = hash;
     171    };
     172
     173    auto copyHashes = [&] (auto& hashes) {
     174        for (auto& hash : hashes) {
     175            addIfNew(hash);
     176            if (index == resultHashes.size())
     177                return true;
     178        }
     179        return false;
     180    };
     181
     182    // There is a limited number of slots. Prefer more specific selector types.
     183    if (copyHashes(collectedSelectorHashes.ids))
     184        return resultHashes;
     185    if (copyHashes(collectedSelectorHashes.classes))
     186        return resultHashes;
     187    if (copyHashes(collectedSelectorHashes.tags))
     188        return resultHashes;
     189
     190    // Null-terminate if not full.
     191    resultHashes[index] = 0;
     192    return resultHashes;
     193}
     194
     195SelectorFilter::Hashes SelectorFilter::collectHashes(const CSSSelector& selector)
     196{
     197    auto hashes = collectSelectorHashes(selector);
     198    return chooseSelectorHashesForFilter(hashes);
     199}
     200
     201}
     202
  • trunk/Source/WebCore/css/SelectorFilter.h

    r225482 r225596  
    5050    using Hashes = std::array<unsigned, 4>;
    5151    bool fastRejectSelector(const Hashes&) const;
    52     static void collectIdentifierHashes(const CSSSelector&, Hashes&);
     52    static Hashes collectHashes(const CSSSelector&);
    5353
    5454private:
     
    6868inline bool SelectorFilter::fastRejectSelector(const Hashes& hashes) const
    6969{
    70     for (unsigned n = 0; n < hashes.size() && hashes[n]; ++n) {
    71         if (!m_ancestorIdentifierFilter.mayContain(hashes[n]))
     70    for (auto& hash : hashes) {
     71        if (!hash)
     72            return false;
     73        if (!m_ancestorIdentifierFilter.mayContain(hash))
    7274            return true;
    7375    }
Note: See TracChangeset for help on using the changeset viewer.