perf(style): narrow conservative invalidation fallback

This commit is contained in:
ldm0
2026-08-28 15:18:42 +08:00
committed by Donough Liu
parent 4ec96e6771
commit 9720a46768
4 changed files with 229 additions and 30 deletions
Generated
+12 -12
View File
@@ -4247,7 +4247,7 @@ dependencies = [
[[package]]
name = "selectors"
version = "0.40.0"
source = "git+https://github.com/ldm0/stylo?rev=713ba89c8e23dd76fd350c5bee68590bfdb885ae#713ba89c8e23dd76fd350c5bee68590bfdb885ae"
source = "git+https://github.com/ldm0/stylo?rev=32c3de3f2aab3340c51f03f2a0878d1e4eed7fd6#32c3de3f2aab3340c51f03f2a0878d1e4eed7fd6"
dependencies = [
"bitflags",
"cssparser",
@@ -4379,7 +4379,7 @@ dependencies = [
[[package]]
name = "servo_arc"
version = "0.4.3"
source = "git+https://github.com/ldm0/stylo?rev=713ba89c8e23dd76fd350c5bee68590bfdb885ae#713ba89c8e23dd76fd350c5bee68590bfdb885ae"
source = "git+https://github.com/ldm0/stylo?rev=32c3de3f2aab3340c51f03f2a0878d1e4eed7fd6#32c3de3f2aab3340c51f03f2a0878d1e4eed7fd6"
dependencies = [
"serde",
"stable_deref_trait",
@@ -4626,7 +4626,7 @@ dependencies = [
[[package]]
name = "stylo"
version = "0.20.0"
source = "git+https://github.com/ldm0/stylo?rev=713ba89c8e23dd76fd350c5bee68590bfdb885ae#713ba89c8e23dd76fd350c5bee68590bfdb885ae"
source = "git+https://github.com/ldm0/stylo?rev=32c3de3f2aab3340c51f03f2a0878d1e4eed7fd6#32c3de3f2aab3340c51f03f2a0878d1e4eed7fd6"
dependencies = [
"app_units",
"arrayvec",
@@ -4682,7 +4682,7 @@ dependencies = [
[[package]]
name = "stylo_atoms"
version = "0.20.0"
source = "git+https://github.com/ldm0/stylo?rev=713ba89c8e23dd76fd350c5bee68590bfdb885ae#713ba89c8e23dd76fd350c5bee68590bfdb885ae"
source = "git+https://github.com/ldm0/stylo?rev=32c3de3f2aab3340c51f03f2a0878d1e4eed7fd6#32c3de3f2aab3340c51f03f2a0878d1e4eed7fd6"
dependencies = [
"string_cache",
"string_cache_codegen",
@@ -4691,7 +4691,7 @@ dependencies = [
[[package]]
name = "stylo_derive"
version = "0.20.0"
source = "git+https://github.com/ldm0/stylo?rev=713ba89c8e23dd76fd350c5bee68590bfdb885ae#713ba89c8e23dd76fd350c5bee68590bfdb885ae"
source = "git+https://github.com/ldm0/stylo?rev=32c3de3f2aab3340c51f03f2a0878d1e4eed7fd6#32c3de3f2aab3340c51f03f2a0878d1e4eed7fd6"
dependencies = [
"darling",
"proc-macro2",
@@ -4703,7 +4703,7 @@ dependencies = [
[[package]]
name = "stylo_dom"
version = "0.20.0"
source = "git+https://github.com/ldm0/stylo?rev=713ba89c8e23dd76fd350c5bee68590bfdb885ae#713ba89c8e23dd76fd350c5bee68590bfdb885ae"
source = "git+https://github.com/ldm0/stylo?rev=32c3de3f2aab3340c51f03f2a0878d1e4eed7fd6#32c3de3f2aab3340c51f03f2a0878d1e4eed7fd6"
dependencies = [
"bitflags",
"stylo_malloc_size_of",
@@ -4712,7 +4712,7 @@ dependencies = [
[[package]]
name = "stylo_malloc_size_of"
version = "0.20.0"
source = "git+https://github.com/ldm0/stylo?rev=713ba89c8e23dd76fd350c5bee68590bfdb885ae#713ba89c8e23dd76fd350c5bee68590bfdb885ae"
source = "git+https://github.com/ldm0/stylo?rev=32c3de3f2aab3340c51f03f2a0878d1e4eed7fd6#32c3de3f2aab3340c51f03f2a0878d1e4eed7fd6"
dependencies = [
"app_units",
"cssparser",
@@ -4729,7 +4729,7 @@ dependencies = [
[[package]]
name = "stylo_static_prefs"
version = "0.20.0"
source = "git+https://github.com/ldm0/stylo?rev=713ba89c8e23dd76fd350c5bee68590bfdb885ae#713ba89c8e23dd76fd350c5bee68590bfdb885ae"
source = "git+https://github.com/ldm0/stylo?rev=32c3de3f2aab3340c51f03f2a0878d1e4eed7fd6#32c3de3f2aab3340c51f03f2a0878d1e4eed7fd6"
dependencies = [
"toml",
]
@@ -4747,7 +4747,7 @@ dependencies = [
[[package]]
name = "stylo_traits"
version = "0.20.0"
source = "git+https://github.com/ldm0/stylo?rev=713ba89c8e23dd76fd350c5bee68590bfdb885ae#713ba89c8e23dd76fd350c5bee68590bfdb885ae"
source = "git+https://github.com/ldm0/stylo?rev=32c3de3f2aab3340c51f03f2a0878d1e4eed7fd6#32c3de3f2aab3340c51f03f2a0878d1e4eed7fd6"
dependencies = [
"app_units",
"bitflags",
@@ -5033,7 +5033,7 @@ checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20"
[[package]]
name = "to_shmem"
version = "0.5.0"
source = "git+https://github.com/ldm0/stylo?rev=713ba89c8e23dd76fd350c5bee68590bfdb885ae#713ba89c8e23dd76fd350c5bee68590bfdb885ae"
source = "git+https://github.com/ldm0/stylo?rev=32c3de3f2aab3340c51f03f2a0878d1e4eed7fd6#32c3de3f2aab3340c51f03f2a0878d1e4eed7fd6"
dependencies = [
"cssparser",
"servo_arc",
@@ -5046,7 +5046,7 @@ dependencies = [
[[package]]
name = "to_shmem_derive"
version = "0.1.0"
source = "git+https://github.com/ldm0/stylo?rev=713ba89c8e23dd76fd350c5bee68590bfdb885ae#713ba89c8e23dd76fd350c5bee68590bfdb885ae"
source = "git+https://github.com/ldm0/stylo?rev=32c3de3f2aab3340c51f03f2a0878d1e4eed7fd6#32c3de3f2aab3340c51f03f2a0878d1e4eed7fd6"
dependencies = [
"darling",
"proc-macro2",
@@ -5653,7 +5653,7 @@ version = "0.1.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c2a7b1c03c876122aa43f3020e6c3c3ee5c05081c9a00739faf7503aeba10d22"
dependencies = [
"windows-sys 0.61.2",
"windows-sys 0.59.0",
]
[[package]]
+6 -6
View File
@@ -92,12 +92,12 @@ curl = { git = "https://github.com/ldm0/curl-rust", branch = "moli" }
curl-sys = { git = "https://github.com/ldm0/curl-rust", branch = "moli" }
cookie = { git = "https://github.com/ldm0/cookie-rs", branch = "priority" }
v8 = { path = "vendor/v8-146.9.0" }
selectors = { git = "https://github.com/ldm0/stylo", rev = "713ba89c8e23dd76fd350c5bee68590bfdb885ae" }
stylo = { git = "https://github.com/ldm0/stylo", rev = "713ba89c8e23dd76fd350c5bee68590bfdb885ae" }
stylo_atoms = { git = "https://github.com/ldm0/stylo", rev = "713ba89c8e23dd76fd350c5bee68590bfdb885ae" }
stylo_dom = { git = "https://github.com/ldm0/stylo", rev = "713ba89c8e23dd76fd350c5bee68590bfdb885ae" }
stylo_static_prefs = { git = "https://github.com/ldm0/stylo", rev = "713ba89c8e23dd76fd350c5bee68590bfdb885ae" }
stylo_traits = { git = "https://github.com/ldm0/stylo", rev = "713ba89c8e23dd76fd350c5bee68590bfdb885ae" }
selectors = { git = "https://github.com/ldm0/stylo", rev = "32c3de3f2aab3340c51f03f2a0878d1e4eed7fd6" }
stylo = { git = "https://github.com/ldm0/stylo", rev = "32c3de3f2aab3340c51f03f2a0878d1e4eed7fd6" }
stylo_atoms = { git = "https://github.com/ldm0/stylo", rev = "32c3de3f2aab3340c51f03f2a0878d1e4eed7fd6" }
stylo_dom = { git = "https://github.com/ldm0/stylo", rev = "32c3de3f2aab3340c51f03f2a0878d1e4eed7fd6" }
stylo_static_prefs = { git = "https://github.com/ldm0/stylo", rev = "32c3de3f2aab3340c51f03f2a0878d1e4eed7fd6" }
stylo_traits = { git = "https://github.com/ldm0/stylo", rev = "32c3de3f2aab3340c51f03f2a0878d1e4eed7fd6" }
taffy = { git = "https://github.com/ldm0/taffy", rev = "3305c7b51c4c88d698d5d3039cd6c8e828ff2086" }
[workspace.lints.clippy]
@@ -1218,7 +1218,7 @@ fn source_dependency_request_translation_uses_context_roots_for_nth_of_dependenc
}
#[test]
fn source_dependency_request_translation_uses_context_roots_for_nested_relative_dependency() {
fn source_dependency_request_translation_tries_nested_relative_with_context_safety_roots() {
let mut host = test_host();
let document = host.document_handle();
let parent = host.create_element("section");
@@ -1270,27 +1270,33 @@ fn source_dependency_request_translation_uses_context_roots_for_nested_relative_
assert_eq!(target_queries.len(), 1);
assert_eq!(
target_queries[0].kind(),
StyloRetainedSourceStyleInvalidationKind::ContextFallback
StyloRetainedSourceStyleInvalidationKind::RetainedQueries
);
assert!(
target_queries[0]
.fallback_reasons_for_test()
.contains(&StyloSourceInvalidationFallbackReason::NestedRelativeSelectorDependency)
.retained_queries_for_test()
.is_some_and(|queries| queries.contains(&query))
);
assert!(target_queries[0].fallback_reasons_for_test().is_empty());
assert!(
target_queries[0]
.reasoned_fallback_root_set_for_test()
.is_empty()
);
assert!(
target_queries[0]
.exact_safety_fallback_root_set_for_test()
.contains(&target)
);
assert!(
!target_queries[0]
.reasoned_fallback_root_set_for_test()
.exact_safety_fallback_root_set_for_test()
.contains(&document)
);
}
#[test]
fn source_dependency_request_translation_preserves_multiple_context_fallback_reasons() {
fn source_dependency_request_translation_keeps_nth_fallback_while_trying_nested_relative_exactly() {
let mut host = test_host();
let document = host.document_handle();
let parent = host.create_element("section");
@@ -1337,18 +1343,28 @@ fn source_dependency_request_translation_preserves_multiple_context_fallback_rea
assert_eq!(target_queries.len(), 1);
assert_eq!(
target_queries[0].kind(),
StyloRetainedSourceStyleInvalidationKind::ContextFallback
StyloRetainedSourceStyleInvalidationKind::RetainedQueries
);
assert!(
target_queries[0]
.retained_queries_for_test()
.is_some_and(|queries| !queries.contains(&nth_query) && queries.contains(&nested_query))
);
let reasons = target_queries[0].fallback_reasons_for_test();
assert!(reasons.contains(&StyloSourceInvalidationFallbackReason::NthOfDependency));
assert!(
reasons.contains(&StyloSourceInvalidationFallbackReason::NestedRelativeSelectorDependency)
!reasons.contains(&StyloSourceInvalidationFallbackReason::NestedRelativeSelectorDependency)
);
assert!(
!target_queries[0]
.reasoned_fallback_root_set_for_test()
.contains(&document)
);
assert!(
!target_queries[0]
.exact_safety_fallback_root_set_for_test()
.contains(&document)
);
}
#[test]
@@ -4928,6 +4928,155 @@ fn retained_stylo_invalidator_refreshes_nth_child_of_selector_list_on_class_chan
);
}
#[test]
fn retained_stylo_invalidator_refreshes_nth_child_of_custom_state_with_context_fallback() {
let mut host = test_host();
let document = host.document_handle();
let body = host.create_element("body");
let container = host.create_element("section");
let first = host.create_element("x-stateful");
let middle = host.create_element("x-stateful");
let target = host.create_element("x-stateful");
let unrelated = host.create_element("aside");
assert!(host.set_attribute(unrelated, "id", "unrelated"));
assert!(host.insert_custom_state(first, "--active"));
assert!(host.insert_custom_state(target, "--active"));
assert!(host.append_child(document, body));
assert!(host.append_child(body, container));
assert!(host.append_child(container, first));
assert!(host.append_child(container, middle));
assert!(host.append_child(container, target));
assert!(host.append_child(body, unrelated));
let mut engine = MoliStyleEngine::new();
let style_text = "section > x-stateful:nth-child(odd of :state(--active)) {
background-color: rgb(192, 192, 192);
}
#unrelated { color: rgb(1, 2, 3); }";
let document_url = url::Url::parse("https://example.test/").unwrap();
let source = StyloStylesheetSource::new(style_text.into(), document_url.clone())
.with_source_id(Some(StyleSourceId::document_adopted_style_sheet(
document, 0,
)));
engine.set_document_adopted_style_sheet_sources(document, vec![source.clone()]);
let mut inputs = FullStyleWorldSnapshot::default();
inputs.document_stylesheet_sources.push(source);
assert_eq!(
engine.computed_style_property_value(
&host,
&document_url,
target,
"background-color",
None,
&inputs,
None,
),
Some("rgba(0, 0, 0, 0)".into())
);
assert_eq!(
engine.computed_style_property_value(
&host,
&document_url,
unrelated,
"color",
None,
&inputs,
None,
),
Some("rgb(1, 2, 3)".into())
);
let media = crate::protocol_types::EmulatedMediaOverrides::default();
let old_custom_states = host.custom_state_names(middle);
assert!(host.insert_custom_state(middle, "--active"));
let source_scope = crate::style_engine::scope::source_scope_for_custom_state_change(
&host,
middle,
&["--active".to_owned()],
)
.expect("custom state scope");
let target_queries = {
let world = engine.world_for_document(document);
let linked_sources = world.linked_stylesheet_sources.borrow();
let document_adopted_sources = world.adopted_style_sheet_sources.borrow();
super::planner::target_queries_for_pending_cause_with_document_adopted_sources(
&host,
&linked_sources,
&document_adopted_sources,
&engine.dom_adapter,
&media,
StyleViewport::default(),
document,
&PendingStyleInvalidationCause::CustomStateChange {
element: middle,
state_names: vec!["--active".to_owned()],
old_custom_states: old_custom_states.clone(),
},
&source_scope,
)
};
assert_eq!(target_queries.len(), 1, "{target_queries:#?}");
assert_eq!(
target_queries[0].kind(),
StyloRetainedSourceStyleInvalidationKind::ContextFallback,
"{target_queries:#?}"
);
let application = engine
.with_retained_style_system_for_document_for_test(document, |retained| {
retained_source_invalidation_outcome_for_document_for_test(
&engine,
&host,
document,
StyleSourceDocumentContext::for_root_document(document),
Some(retained),
&target_queries,
false,
)
})
.finalize(&host);
assert_eq!(
application.cleanup_target_kind(),
StyleInvalidationCleanupTargetKind::SourceFallbackSubtreeRoots
);
assert!(matches!(
application.cleanup_target(),
StyleInvalidationCleanupTarget::SourceFallbackSubtreeRoots(roots)
if roots.contains(&target) && !roots.contains(&unrelated)
));
assert_eq!(application.diagnostic_target_results().len(), 1);
assert!(!application.diagnostic_target_results()[0].exact());
assert!(
application.diagnostic_target_results()[0]
.fallback_reasons()
.contains(&StyloSourceInvalidationFallbackReason::NthOfDependency)
);
engine.invalidate_for_custom_state_change(
&host,
middle,
vec!["--active".to_owned()],
old_custom_states,
&media,
);
engine.drain_pending_style_invalidations_for_document_for_test(&host, document);
assert!(!engine.computed_style_cache_contains_handle_for_document_for_test(document, target));
assert!(engine.computed_style_cache_contains_handle_for_document_for_test(document, unrelated));
assert_eq!(
engine.computed_style_property_value(
&host,
&document_url,
target,
"background-color",
None,
&inputs,
None,
),
Some("rgb(192, 192, 192)".into())
);
}
#[test]
fn retained_stylo_invalidator_custom_state_snapshot_avoids_source_fallback() {
let mut host = test_host();
@@ -5217,8 +5366,10 @@ fn retained_stylo_invalidator_refreshes_nested_is_sibling_has_on_child_removal()
let first_child = host.create_element("span");
let second_child = host.create_element("span");
let third_child = host.create_element("span");
let unrelated = host.create_element("aside");
assert!(host.set_attribute(target, "id", "target"));
assert!(host.set_attribute(unrelated, "id", "unrelated"));
for item in [first_item, second_item, third_item] {
assert!(host.set_attribute(item, "class", "item"));
}
@@ -5233,12 +5384,14 @@ fn retained_stylo_invalidator_refreshes_nested_is_sibling_has_on_child_removal()
assert!(host.append_child(third_item, first_child));
assert!(host.append_child(third_item, second_child));
assert!(host.append_child(third_item, third_child));
assert!(host.append_child(document, unrelated));
let mut engine = MoliStyleEngine::new();
let style_text = "#target { color: rgb(0, 128, 0); }
#target:has(:is(.item + .item + .item > .child + .child + .child)) {
color: rgb(192, 192, 192);
}";
}
#unrelated { color: rgb(1, 2, 3); }";
let document_url = url::Url::parse("https://example.test/").unwrap();
let metadata = stylo_source_metadata_for_css_text(style_text, &document_url);
assert!(
@@ -5266,9 +5419,21 @@ fn retained_stylo_invalidator_refreshes_nested_is_sibling_has_on_child_removal()
),
Some("rgb(192, 192, 192)".into())
);
assert_eq!(
engine.computed_style_property_value(
&host,
&document_url,
unrelated,
"color",
None,
&inputs,
None,
),
Some("rgb(1, 2, 3)".into())
);
assert_eq!(
engine.computed_style_cache_entry_count_for_document_for_test(document),
1
2
);
let removed_snapshots = removed_element_dependency_snapshots(&host, &[first_item]);
@@ -5289,6 +5454,7 @@ fn retained_stylo_invalidator_refreshes_nested_is_sibling_has_on_child_removal()
engine.drain_pending_style_invalidations_for_document_for_test(&host, document);
assert!(!engine.computed_style_cache_contains_handle_for_document_for_test(document, target));
assert!(engine.computed_style_cache_contains_handle_for_document_for_test(document, unrelated));
assert_eq!(
engine.computed_style_property_value(
&host,
@@ -5315,6 +5481,7 @@ fn retained_stylo_invalidator_refreshes_nested_is_sibling_has_on_middle_insertio
let target = host.create_element("section");
let child = host.create_element("div");
let descendant = host.create_element("div");
let unrelated = host.create_element("aside");
assert!(host.set_attribute(first, "class", "p"));
assert!(host.set_attribute(previous, "id", "parent_previous"));
@@ -5325,6 +5492,7 @@ fn retained_stylo_invalidator_refreshes_nested_is_sibling_has_on_middle_insertio
assert!(host.set_attribute(child, "class", "d"));
assert!(host.set_attribute(descendant, "id", "descendant"));
assert!(host.set_attribute(descendant, "class", "e"));
assert!(host.set_attribute(unrelated, "id", "unrelated"));
assert!(host.append_child(document, body));
assert!(host.append_child(body, outer));
assert!(host.append_child(outer, first));
@@ -5333,12 +5501,14 @@ fn retained_stylo_invalidator_refreshes_nested_is_sibling_has_on_middle_insertio
assert!(host.append_child(parent, target));
assert!(host.append_child(target, child));
assert!(host.append_child(child, descendant));
assert!(host.append_child(body, unrelated));
let mut engine = MoliStyleEngine::new();
let style_text = "#has_scope { color: rgb(128, 128, 128); }
.green:has(#descendant:is(.p + .c_has_scope ~ .d .e)) {
color: rgb(0, 128, 0);
}";
}
#unrelated { color: rgb(1, 2, 3); }";
let document_url = url::Url::parse("https://example.test/").unwrap();
let metadata = stylo_source_metadata_for_css_text(style_text, &document_url);
assert!(
@@ -5366,9 +5536,21 @@ fn retained_stylo_invalidator_refreshes_nested_is_sibling_has_on_middle_insertio
),
Some("rgb(0, 128, 0)".into())
);
assert_eq!(
engine.computed_style_property_value(
&host,
&document_url,
unrelated,
"color",
None,
&inputs,
None,
),
Some("rgb(1, 2, 3)".into())
);
assert_eq!(
engine.computed_style_cache_entry_count_for_document_for_test(document),
1
2
);
let inserted = host.create_element("div");
@@ -5390,6 +5572,7 @@ fn retained_stylo_invalidator_refreshes_nested_is_sibling_has_on_middle_insertio
engine.drain_pending_style_invalidations_for_document_for_test(&host, document);
assert!(!engine.computed_style_cache_contains_handle_for_document_for_test(document, target));
assert!(engine.computed_style_cache_contains_handle_for_document_for_test(document, unrelated));
assert_eq!(
engine.computed_style_property_value(
&host,