script: Don't traverse O(the whole DOM tree) nodes when inserting elements into Vec in tree order (#44120)

Previously the code was computing a prefix sum over the number of
preceding elements in tree order to get the index that the node should
be inserted in.

That's not great if the DOM tree is big. Instead, we can compare two
nodes individually by looking at their ancestor chain and then find the
correct position with binary search.

On https://262.ecma-international.org/16.0/index.html, this reduces the
time it takes for content to appear from around 33s to 16s.

Part of https://github.com/servo/servo/issues/44113

---------

Signed-off-by: Simon Wülker <simon.wuelker@arcor.de>
This commit is contained in:
Simon Wülker
2026-04-14 15:16:55 +02:00
committed by GitHub
parent 38e3397237
commit 2930beb4d1
6 changed files with 99 additions and 35 deletions

View File

@@ -1407,7 +1407,18 @@ impl HTMLFormElement {
let root = self.upcast::<Element>().root_element();
let root = root.upcast::<Node>();
let mut controls = self.controls.borrow_mut();
controls.insert_pre_order(control.to_element(), root);
// https://html.spec.whatwg.org/multipage/#create-an-element-for-the-token
// associates form control elements with a form before they are bound to the tree.
//
// In that case we can't use insert_pre_order, because the position of a element not in
// the tree can't be compared to anything in the DOM tree.
let control_element = control.to_element();
if control_element.upcast::<Node>().has_parent() {
controls.insert_pre_order(control_element, root);
} else {
controls.push(Dom::from_ref(control_element));
}
}
self.update_validity(can_gc);
}