mirror of
https://github.com/servo/servo.git
synced 2025-08-05 13:40:08 +01:00
Auto merge of #18798 - emilio:faster-custom-props, r=SimonSapin
style: Optimize custom properties cycle removal. After #18791, this is the major custom_properties perf bottleneck in the testcase from bug 1405411. I'm looking into how to efficiently merge this into `substitute_all`, but meanwhile this is worth landing, and makes most of the overhead go away. <!-- Reviewable:start --> --- This change is [<img src="https://reviewable.io/review_button.svg" height="34" align="absmiddle" alt="Reviewable"/>](https://reviewable.io/reviews/servo/servo/18798) <!-- Reviewable:end -->
This commit is contained in:
commit
27cb13314e
1 changed files with 25 additions and 17 deletions
|
@ -13,6 +13,7 @@ use properties::{CSSWideKeyword, DeclaredValue};
|
||||||
use selector_map::{PrecomputedHashSet, PrecomputedHashMap, PrecomputedDiagnosticHashMap};
|
use selector_map::{PrecomputedHashSet, PrecomputedHashMap, PrecomputedDiagnosticHashMap};
|
||||||
use selectors::parser::SelectorParseError;
|
use selectors::parser::SelectorParseError;
|
||||||
use servo_arc::Arc;
|
use servo_arc::Arc;
|
||||||
|
use smallvec::SmallVec;
|
||||||
use std::ascii::AsciiExt;
|
use std::ascii::AsciiExt;
|
||||||
use std::borrow::{Borrow, Cow};
|
use std::borrow::{Borrow, Cow};
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
|
@ -546,41 +547,48 @@ impl<'a> CustomPropertiesBuilder<'a> {
|
||||||
fn remove_cycles(map: &mut CustomPropertiesMap) {
|
fn remove_cycles(map: &mut CustomPropertiesMap) {
|
||||||
let mut to_remove = PrecomputedHashSet::default();
|
let mut to_remove = PrecomputedHashSet::default();
|
||||||
{
|
{
|
||||||
|
type VisitedNamesStack<'a> = SmallVec<[&'a Name; 10]>;
|
||||||
|
|
||||||
let mut visited = PrecomputedHashSet::default();
|
let mut visited = PrecomputedHashSet::default();
|
||||||
let mut stack = Vec::new();
|
let mut stack = VisitedNamesStack::new();
|
||||||
for name in &map.index {
|
for (name, value) in map.iter() {
|
||||||
walk(map, name, &mut stack, &mut visited, &mut to_remove);
|
walk(map, name, value, &mut stack, &mut visited, &mut to_remove);
|
||||||
|
|
||||||
fn walk<'a>(
|
fn walk<'a>(
|
||||||
map: &'a CustomPropertiesMap,
|
map: &'a CustomPropertiesMap,
|
||||||
name: &'a Name,
|
name: &'a Name,
|
||||||
stack: &mut Vec<&'a Name>,
|
value: &'a Arc<VariableValue>,
|
||||||
|
stack: &mut VisitedNamesStack<'a>,
|
||||||
visited: &mut PrecomputedHashSet<&'a Name>,
|
visited: &mut PrecomputedHashSet<&'a Name>,
|
||||||
to_remove: &mut PrecomputedHashSet<Name>,
|
to_remove: &mut PrecomputedHashSet<Name>,
|
||||||
) {
|
) {
|
||||||
|
if value.references.is_empty() {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
let already_visited_before = !visited.insert(name);
|
let already_visited_before = !visited.insert(name);
|
||||||
if already_visited_before {
|
if already_visited_before {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if let Some(ref value) = map.get(name) {
|
|
||||||
if !value.references.is_empty() {
|
stack.push(name);
|
||||||
stack.push(name);
|
for next in value.references.iter() {
|
||||||
for next in value.references.iter() {
|
if let Some(position) = stack.iter().position(|x| *x == next) {
|
||||||
if let Some(position) = stack.iter().position(|x| *x == next) {
|
// Found a cycle
|
||||||
// Found a cycle
|
for &in_cycle in &stack[position..] {
|
||||||
for &in_cycle in &stack[position..] {
|
to_remove.insert(in_cycle.clone());
|
||||||
to_remove.insert(in_cycle.clone());
|
}
|
||||||
}
|
} else {
|
||||||
} else {
|
if let Some(value) = map.get(next) {
|
||||||
walk(map, next, stack, visited, to_remove);
|
walk(map, next, value, stack, visited, to_remove);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
stack.pop();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
stack.pop();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for name in to_remove {
|
for name in to_remove {
|
||||||
map.remove(&name);
|
map.remove(&name);
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue