From d4a6234ca02616cb968181cb3bfa8efbbc2f2c78 Mon Sep 17 00:00:00 2001 From: ldm0 Date: Tue, 6 Oct 2026 01:49:24 +0800 Subject: [PATCH] perf(runtime): skip empty style mutation followups Handle empty CSP input in a small inline entry and delegate nonempty batches to a separate function. The mutation finisher only checks whether the DOM changed before invoking CSP followups. Skip processing empty stylesheet owner changes at the mutation finisher. Continue applying pending stylesheet CSS projections and slotchange events. A/B against the previous caller-side CSP guard on the resulting branch (fixed local WeChat HTML; release; JS/CSS/subframes disabled; 200 balanced randomized pairs) measured 142.39 -> 141.29 ms. Paired saving: 0.34 ms; 95% bootstrap CI: [-0.87, 1.57] ms. The confidence interval includes zero; no resolved performance gain. All 400 measured Markdown outputs were identical. Validation: - cargo fmt --all - cargo clippy --workspace --all-targets --all-features -- -D warnings - cargo nextest run --no-fail-fast (19,490 passed, 16 skipped) --- .../src/document_runtime/mutation_commands.rs | 2 +- .../src/document_runtime/security_policy.rs | 24 +++++++++++++++++++ 2 files changed, 25 insertions(+), 1 deletion(-) diff --git a/moli-renderer-v8/src/document_runtime/mutation_commands.rs b/moli-renderer-v8/src/document_runtime/mutation_commands.rs index dc6ab755ed..077ef4b340 100644 --- a/moli-renderer-v8/src/document_runtime/mutation_commands.rs +++ b/moli-renderer-v8/src/document_runtime/mutation_commands.rs @@ -1809,7 +1809,7 @@ pub(super) fn finish_runtime_mutation_effects( ); } runtime.apply_pending_stylesheet_source_css_projections(scope, host_ptr); - if changed { + if changed && !stylesheet_owner_changes.is_empty() { let mut prime_result = ConnectedStyleLoadPrimeResult::default(); let prepared_owner_changes = runtime.prepare_stylesheet_owner_runtime_changes(&stylesheet_owner_changes); diff --git a/moli-renderer-v8/src/document_runtime/security_policy.rs b/moli-renderer-v8/src/document_runtime/security_policy.rs index 699568ac4d..d1457a7e7f 100644 --- a/moli-renderer-v8/src/document_runtime/security_policy.rs +++ b/moli-renderer-v8/src/document_runtime/security_policy.rs @@ -225,6 +225,7 @@ impl DocumentPolicyContainer { } impl DocumentRuntime { + #[inline] pub(super) fn apply_style_csp_mutation_followups<'s>( &mut self, scope: &mut v8::PinScope<'s, '_>, @@ -232,6 +233,29 @@ impl DocumentRuntime { attribute_mutations: &[super::mutation_commands::InlineStyleAttributeCspMutation], connected_roots: &[DomHandle], stylesheet_owner_changes: &[crate::dom::native::DomStylesheetOwnerChange], + ) { + if attribute_mutations.is_empty() + && connected_roots.is_empty() + && stylesheet_owner_changes.is_empty() + { + return; + } + self.apply_nonempty_style_csp_mutation_followups( + scope, + host_ptr, + attribute_mutations, + connected_roots, + stylesheet_owner_changes, + ); + } + + fn apply_nonempty_style_csp_mutation_followups<'s>( + &mut self, + scope: &mut v8::PinScope<'s, '_>, + host_ptr: *mut JsContextHost, + attribute_mutations: &[super::mutation_commands::InlineStyleAttributeCspMutation], + connected_roots: &[DomHandle], + stylesheet_owner_changes: &[crate::dom::native::DomStylesheetOwnerChange], ) { let mut checked_attributes = HashSet::new(); for mutation in attribute_mutations {