From 3c1bc1a92d2560b7991e4ee0aac6bd4b976acfb5 Mon Sep 17 00:00:00 2001 From: webbeef Date: Fri, 11 Jul 2025 00:46:23 -0700 Subject: [PATCH] Avoid rooting/unrooting in Node::rev_version (#37885) The iterator produced by Node::inclusive_ancestors roots the items but rev_version just drop and unroot them right away. This patch makes it possible to work on the Node references instead to avoid rooting. *Describe the changes that this pull request makes here. This will be the commit message.* Testing: *Describe how this pull request is tested or why it doesn't require tests* Fixes: *Link to an issue this pull requests fixes or remove this line if there is no issue* Signed-off-by: webbeef --- components/script/dom/bindings/root.rs | 14 ++++++++++++++ components/script/dom/node.rs | 11 +++++++++-- 2 files changed, 23 insertions(+), 2 deletions(-) diff --git a/components/script/dom/bindings/root.rs b/components/script/dom/bindings/root.rs index ab999cab6ba..daa1de2f1fe 100644 --- a/components/script/dom/bindings/root.rs +++ b/components/script/dom/bindings/root.rs @@ -291,6 +291,20 @@ impl MutNullableDom { self.set(None); value } + + /// Runs the given callback on the object if it's not null. + pub(crate) fn if_is_some(&self, cb: F) -> Option<&R> + where + F: FnOnce(&T) -> &R, + { + unsafe { + if let Some(ref value) = *self.ptr.get() { + Some(cb(value)) + } else { + None + } + } + } } impl PartialEq for MutNullableDom { diff --git a/components/script/dom/node.rs b/components/script/dom/node.rs index db946f6a8e6..067b8f0b4c9 100644 --- a/components/script/dom/node.rs +++ b/components/script/dom/node.rs @@ -796,8 +796,15 @@ impl Node { self.inclusive_descendants_version(), doc.inclusive_descendants_version(), ) + 1; - for ancestor in self.inclusive_ancestors(ShadowIncluding::No) { - ancestor.inclusive_descendants_version.set(version); + + // This `while` loop is equivalent to iterating over the non-shadow-inclusive ancestors + // without creating intermediate rooted DOM objects. + let mut node = &MutNullableDom::new(Some(self)); + while let Some(p) = node.if_is_some(|p| { + p.inclusive_descendants_version.set(version); + &p.parent_node + }) { + node = p } doc.inclusive_descendants_version.set(version); }