LibWeb: Add a fast (iterative) selector matcher for trivial selectors

If we determine that a selector is simple enough, we now run it using a
special matching loop that traverses up the DOM ancestor chain without
recursion.

The criteria for this fast path are:

- All combinators involved must be either descendant or child.
- Only tag name, class, ID and attribute selectors allowed.

It's definitely possible to increase the coverage of this fast path,
but this first version already provides a substantial reduction in time
spent evaluating selectors.

48% of the selectors evaluated when loading our GitHub repo are now
using this fast path.

18% speed-up on the "Descendant and child combinators" subtest of
StyleBench. :^)
This commit is contained in:
Andreas Kling 2024-03-19 10:36:08 +01:00
commit 3c3e591f03
Notes: sideshowbarker 2024-07-16 17:12:03 +09:00
4 changed files with 128 additions and 4 deletions

View file

@ -358,8 +358,14 @@ Vector<MatchingRule> StyleComputer::collect_matching_rules(DOM::Element const& e
continue;
auto const& selector = rule_to_run.rule->selectors()[rule_to_run.selector_index];
if (SelectorEngine::matches(selector, *rule_to_run.sheet, element, pseudo_element))
matching_rules.append(rule_to_run);
if (rule_to_run.can_use_fast_matches) {
if (!SelectorEngine::fast_matches(selector, *rule_to_run.sheet, element))
continue;
} else {
if (!SelectorEngine::matches(selector, *rule_to_run.sheet, element, pseudo_element))
continue;
}
matching_rules.append(rule_to_run);
}
return matching_rules;
}
@ -2331,6 +2337,9 @@ NonnullOwnPtr<StyleComputer::RuleCache> StyleComputer::make_rule_cache_for_casca
selector_index,
selector.specificity(),
cascade_origin,
false,
false,
SelectorEngine::can_use_fast_matches(selector),
};
for (auto const& simple_selector : selector.compound_selectors().last().simple_selectors) {