LibWeb: Let HTMLCollection cache its element list

Use the new DOM tree version mechanism to allow HTMLCollection to
remember its internal list of elements instead of rebuilding it on
every access.

This avoids thousands of full DOM walks while loading our GitHub repo.

~15% speed-up on jQuery subtests in Speedometer 3.0 :^)
This commit is contained in:
Andreas Kling 2024-03-19 15:41:02 +01:00
parent cf60f52a78
commit 6bb4a2bfaa
Notes: sideshowbarker 2024-07-17 00:49:59 +09:00
2 changed files with 26 additions and 13 deletions

View File

@ -6,6 +6,7 @@
*/
#include <LibWeb/Bindings/Intrinsics.h>
#include <LibWeb/DOM/Document.h>
#include <LibWeb/DOM/Element.h>
#include <LibWeb/DOM/HTMLCollection.h>
#include <LibWeb/DOM/ParentNode.h>
@ -45,24 +46,33 @@ void HTMLCollection::visit_edges(Cell::Visitor& visitor)
{
Base::visit_edges(visitor);
visitor.visit(m_root);
for (auto& element : m_cached_elements)
visitor.visit(element);
}
JS::MarkedVector<Element*> HTMLCollection::collect_matching_elements() const
{
JS::MarkedVector<Element*> elements(m_root->heap());
if (m_scope == Scope::Descendants) {
m_root->for_each_in_subtree_of_type<Element>([&](auto& element) {
if (m_filter(element))
elements.append(const_cast<Element*>(&element));
return IterationDecision::Continue;
});
} else {
m_root->for_each_child_of_type<Element>([&](auto& element) {
if (m_filter(element))
elements.append(const_cast<Element*>(&element));
return IterationDecision::Continue;
});
if (m_cached_dom_tree_version != root()->document().dom_tree_version()) {
m_cached_elements.clear();
if (m_scope == Scope::Descendants) {
m_root->for_each_in_subtree_of_type<Element>([&](auto& element) {
if (m_filter(element))
m_cached_elements.append(element);
return IterationDecision::Continue;
});
} else {
m_root->for_each_child_of_type<Element>([&](auto& element) {
if (m_filter(element))
m_cached_elements.append(element);
return IterationDecision::Continue;
});
}
m_cached_dom_tree_version = root()->document().dom_tree_version();
}
JS::MarkedVector<Element*> elements(heap());
for (auto& element : m_cached_elements)
elements.append(element);
return elements;
}

View File

@ -60,6 +60,9 @@ protected:
private:
virtual void visit_edges(Cell::Visitor&) override;
mutable u64 m_cached_dom_tree_version { 0 };
mutable Vector<JS::NonnullGCPtr<Element>> m_cached_elements;
JS::NonnullGCPtr<ParentNode> m_root;
Function<bool(Element const&)> m_filter;