Store selectors and combinators inline in a single sequence.

This improves cache locality and reduces allocations during parsing.

Note that this reverses the iteration order within a sequence of simple selectors,
but that shouldn't matter.
This commit is contained in:
Bobby Holley 2017-04-18 23:43:39 -07:00
parent 93fa0ae1e3
commit 6d66ec5e11
10 changed files with 703 additions and 330 deletions

View file

@ -14,7 +14,6 @@ use selectors::visitor::SelectorVisitor;
use std::borrow::Cow;
use std::fmt;
use std::ptr;
use std::sync::Arc;
use string_cache::{Atom, Namespace, WeakAtom, WeakNamespace};
/// A representation of a CSS pseudo-element.
@ -218,7 +217,7 @@ macro_rules! pseudo_class_name {
///
/// TODO(emilio): We disallow combinators and pseudos here, so we
/// should use SimpleSelector instead
MozAny(Vec<Arc<ComplexSelector<SelectorImpl>>>),
MozAny(Vec<ComplexSelector<SelectorImpl>>),
}
}
}
@ -396,10 +395,10 @@ impl<'a> ::selectors::Parser for SelectorParser<'a> {
}, )*
"-moz-any" => {
let selectors = parser.parse_comma_separated(|input| {
ComplexSelector::parse(self, input).map(Arc::new)
ComplexSelector::parse(self, input)
})?;
// Selectors inside `:-moz-any` may not include combinators.
if selectors.iter().any(|s| s.next.is_some()) {
if selectors.iter().flat_map(|x| x.iter_raw()).any(|s| s.is_combinator()) {
return Err(())
}
NonTSPseudoClass::MozAny(selectors)

View file

@ -17,10 +17,10 @@ use selector_parser::{AttrValue, NonTSPseudoClass, Snapshot, SelectorImpl};
use selectors::{Element, MatchAttr};
use selectors::matching::{ElementSelectorFlags, StyleRelations};
use selectors::matching::matches_selector;
use selectors::parser::{AttrSelector, Combinator, ComplexSelector, SelectorInner, SelectorMethods, SimpleSelector};
use selectors::parser::{AttrSelector, Combinator, ComplexSelector, SelectorInner, SelectorIter};
use selectors::parser::{SelectorMethods, SimpleSelector};
use selectors::visitor::SelectorVisitor;
use std::clone::Clone;
use std::sync::Arc;
bitflags! {
/// When the ElementState of an element (like IN_HOVER_STATE) changes,
@ -509,7 +509,7 @@ impl SelectorVisitor for SensitivitiesVisitor {
type Impl = SelectorImpl;
fn visit_complex_selector(&mut self,
_: &ComplexSelector<SelectorImpl>,
_: SelectorIter<SelectorImpl>,
combinator: Option<Combinator>) -> bool {
self.hint |= combinator_to_restyle_hint(combinator);
self.needs_revalidation |= self.hint.contains(RESTYLE_LATER_SIBLINGS);
@ -567,50 +567,47 @@ impl DependencySet {
/// cache revalidation, that is, whether two siblings of the same "shape"
/// may have different style due to this selector.
pub fn note_selector(&mut self,
selector: &Arc<ComplexSelector<SelectorImpl>>)
base: &ComplexSelector<SelectorImpl>)
-> bool
{
let mut next = Some(base.clone());
let mut combinator = None;
let mut current = selector;
let mut needs_revalidation = false;
loop {
let mut sensitivities_visitor = SensitivitiesVisitor {
while let Some(current) = next.take() {
// Set up our visitor.
let mut visitor = SensitivitiesVisitor {
sensitivities: Sensitivities::new(),
hint: RestyleHint::empty(),
hint: combinator_to_restyle_hint(combinator),
needs_revalidation: false,
};
for ss in &current.compound_selector {
ss.visit(&mut sensitivities_visitor);
{
// Visit all the simple selectors.
let mut iter = current.iter();
let mut index = 0usize;
for ss in &mut iter {
ss.visit(&mut visitor);
index += 1;
}
// Prepare the next sequence of simple selectors.
if let Some(next_combinator) = iter.next_sequence() {
next = Some(current.slice_from(index + 1));
combinator = Some(next_combinator);
}
}
needs_revalidation |= sensitivities_visitor.needs_revalidation;
let SensitivitiesVisitor {
sensitivities,
mut hint,
..
} = sensitivities_visitor;
hint |= combinator_to_restyle_hint(combinator);
if !sensitivities.is_empty() {
// Note what we found.
needs_revalidation |= visitor.needs_revalidation;
if !visitor.sensitivities.is_empty() {
self.add_dependency(Dependency {
sensitivities: sensitivities,
hint: hint,
selector: SelectorInner::new(current.clone()),
sensitivities: visitor.sensitivities,
hint: visitor.hint,
selector: SelectorInner::new(current),
})
}
match current.next {
Some((ref next, next_combinator)) => {
current = next;
combinator = Some(next_combinator);
}
None => break,
}
}
needs_revalidation
@ -729,7 +726,7 @@ fn smoke_restyle_hints() {
let mut dependencies = DependencySet::new();
let mut p = Parser::new(":not(:active) ~ label");
let selector = Arc::new(ComplexSelector::parse(&parser, &mut p).unwrap());
let selector = ComplexSelector::parse(&parser, &mut p).unwrap();
dependencies.note_selector(&selector);
assert_eq!(dependencies.len(), 1);
assert_eq!(dependencies.state_deps.len(), 1);

View file

@ -1070,8 +1070,7 @@ impl SelectorMap {
// correct, and also to not trigger rule tree assertions.
let mut important = vec![];
for rule in self.other_rules.iter() {
if rule.selector.complex.compound_selector.is_empty() &&
rule.selector.complex.next.is_none() {
if rule.selector.complex.iter_raw().next().is_none() {
let style_rule = rule.style_rule.read_with(guard);
let block = style_rule.block.read_with(guard);
if block.any_normal() {
@ -1180,7 +1179,7 @@ impl SelectorMap {
/// Retrieve the first ID name in Rule, or None otherwise.
pub fn get_id_name(rule: &Rule) -> Option<Atom> {
for ss in &rule.selector.complex.compound_selector {
for ss in rule.selector.complex.iter() {
// TODO(pradeep): Implement case-sensitivity based on the
// document type and quirks mode.
if let SimpleSelector::ID(ref id) = *ss {
@ -1193,7 +1192,7 @@ impl SelectorMap {
/// Retrieve the FIRST class name in Rule, or None otherwise.
pub fn get_class_name(rule: &Rule) -> Option<Atom> {
for ss in &rule.selector.complex.compound_selector {
for ss in rule.selector.complex.iter() {
// TODO(pradeep): Implement case-sensitivity based on the
// document type and quirks mode.
if let SimpleSelector::Class(ref class) = *ss {
@ -1206,7 +1205,7 @@ impl SelectorMap {
/// Retrieve the name if it is a type selector, or None otherwise.
pub fn get_local_name(rule: &Rule) -> Option<LocalNameSelector<SelectorImpl>> {
for ss in &rule.selector.complex.compound_selector {
for ss in rule.selector.complex.iter() {
if let SimpleSelector::LocalName(ref n) = *ss {
return Some(LocalNameSelector {
name: n.name.clone(),