1
Fork 0
mirror of https://github.com/RGBCube/serenity synced 2025-07-26 03:37:43 +00:00

LibWeb: Only allocate DOM::Node registered observer list on demand

Most DOM nodes don't have registered mutation observers, so let's put
the metadata about them behind an OwnPtr to save space in the common
case.

Saves 16 bytes per DOM node that doesn't have registered observers.
This commit is contained in:
Andreas Kling 2023-11-18 11:22:51 +01:00
parent c1fd55ce94
commit 9edfd5e360
4 changed files with 53 additions and 32 deletions

View file

@ -608,9 +608,11 @@ void queue_mutation_observer_microtask(DOM::Document const& document)
if (node.is_null()) if (node.is_null())
continue; continue;
node->registered_observers_list().remove_all_matching([&mutation_observer](DOM::RegisteredObserver& registered_observer) { if (node->registered_observer_list()) {
return is<DOM::TransientRegisteredObserver>(registered_observer) && static_cast<DOM::TransientRegisteredObserver&>(registered_observer).observer().ptr() == mutation_observer.ptr(); node->registered_observer_list()->remove_all_matching([&mutation_observer](DOM::RegisteredObserver& registered_observer) {
}); return is<DOM::TransientRegisteredObserver>(registered_observer) && static_cast<DOM::TransientRegisteredObserver&>(registered_observer).observer().ptr() == mutation_observer.ptr();
});
}
} }
// 4. If records is not empty, then invoke mos callback with « records, mo », and mo. If this throws an exception, catch it, and report the exception. // 4. If records is not empty, then invoke mos callback with « records, mo », and mo. If this throws an exception, catch it, and report the exception.

View file

@ -85,26 +85,30 @@ WebIDL::ExceptionOr<void> MutationObserver::observe(Node& target, MutationObserv
// 7. For each registered of targets registered observer list, if registereds observer is this: // 7. For each registered of targets registered observer list, if registereds observer is this:
bool updated_existing_observer = false; bool updated_existing_observer = false;
for (auto& registered_observer : target.registered_observers_list()) { if (target.registered_observer_list()) {
if (registered_observer->observer().ptr() != this) for (auto& registered_observer : *target.registered_observer_list()) {
continue; if (registered_observer->observer().ptr() != this)
updated_existing_observer = true;
// 1. For each node of thiss node list, remove all transient registered observers whose source is registered from nodes registered observer list.
for (auto& node : m_node_list) {
// FIXME: Is this correct?
if (node.is_null())
continue; continue;
node->registered_observers_list().remove_all_matching([&registered_observer](RegisteredObserver& observer) { updated_existing_observer = true;
return is<TransientRegisteredObserver>(observer) && verify_cast<TransientRegisteredObserver>(observer).source().ptr() == registered_observer;
});
}
// 2. Set registereds options to options. // 1. For each node of thiss node list, remove all transient registered observers whose source is registered from nodes registered observer list.
registered_observer->set_options(options); for (auto& node : m_node_list) {
break; // FIXME: Is this correct?
if (node.is_null())
continue;
if (node->registered_observer_list()) {
node->registered_observer_list()->remove_all_matching([&registered_observer](RegisteredObserver& observer) {
return is<TransientRegisteredObserver>(observer) && verify_cast<TransientRegisteredObserver>(observer).source().ptr() == registered_observer;
});
}
}
// 2. Set registereds options to options.
registered_observer->set_options(options);
break;
}
} }
// 8. Otherwise: // 8. Otherwise:
@ -129,9 +133,11 @@ void MutationObserver::disconnect()
if (node.is_null()) if (node.is_null())
continue; continue;
node->registered_observers_list().remove_all_matching([this](RegisteredObserver& registered_observer) { if (node->registered_observer_list()) {
return registered_observer.observer().ptr() == this; node->registered_observer_list()->remove_all_matching([this](RegisteredObserver& registered_observer) {
}); return registered_observer.observer().ptr() == this;
});
}
} }
// 2. Empty thiss record queue. // 2. Empty thiss record queue.

View file

@ -103,8 +103,10 @@ void Node::visit_edges(Cell::Visitor& visitor)
visitor.visit(m_layout_node); visitor.visit(m_layout_node);
visitor.visit(m_paintable); visitor.visit(m_paintable);
for (auto& registered_observer : m_registered_observer_list) if (m_registered_observer_list) {
visitor.visit(registered_observer); for (auto& registered_observer : *m_registered_observer_list)
visitor.visit(registered_observer);
}
} }
// https://dom.spec.whatwg.org/#dom-node-baseuri // https://dom.spec.whatwg.org/#dom-node-baseuri
@ -686,10 +688,12 @@ void Node::remove(bool suppress_observers)
// if registereds options["subtree"] is true, then append a new transient registered observer // if registereds options["subtree"] is true, then append a new transient registered observer
// whose observer is registereds observer, options is registereds options, and source is registered to nodes registered observer list. // whose observer is registereds observer, options is registereds options, and source is registered to nodes registered observer list.
for (auto* inclusive_ancestor = parent; inclusive_ancestor; inclusive_ancestor = inclusive_ancestor->parent()) { for (auto* inclusive_ancestor = parent; inclusive_ancestor; inclusive_ancestor = inclusive_ancestor->parent()) {
for (auto& registered : inclusive_ancestor->m_registered_observer_list) { if (!inclusive_ancestor->m_registered_observer_list)
continue;
for (auto& registered : *inclusive_ancestor->m_registered_observer_list) {
if (registered->options().subtree) { if (registered->options().subtree) {
auto transient_observer = TransientRegisteredObserver::create(registered->observer(), registered->options(), registered); auto transient_observer = TransientRegisteredObserver::create(registered->observer(), registered->options(), registered);
m_registered_observer_list.append(move(transient_observer)); m_registered_observer_list->append(move(transient_observer));
} }
} }
} }
@ -1546,7 +1550,9 @@ void Node::queue_mutation_record(FlyString const& type, Optional<FlyString> cons
// 2. Let nodes be the inclusive ancestors of target. // 2. Let nodes be the inclusive ancestors of target.
// 3. For each node in nodes, and then for each registered of nodes registered observer list: // 3. For each node in nodes, and then for each registered of nodes registered observer list:
for (auto* node = this; node; node = node->parent()) { for (auto* node = this; node; node = node->parent()) {
for (auto& registered_observer : node->m_registered_observer_list) { if (!node->m_registered_observer_list)
continue;
for (auto& registered_observer : *node->m_registered_observer_list) {
// 1. Let options be registereds options. // 1. Let options be registereds options.
auto& options = registered_observer->options(); auto& options = registered_observer->options();
@ -1995,4 +2001,11 @@ ErrorOr<void> Node::prepend_with_space(StringBuilder x, StringView const& result
return {}; return {};
} }
void Node::add_registered_observer(RegisteredObserver& registered_observer)
{
if (!m_registered_observer_list)
m_registered_observer_list = make<Vector<JS::NonnullGCPtr<RegisteredObserver>>>();
m_registered_observer_list->append(registered_observer);
}
} }

View file

@ -254,10 +254,10 @@ public:
size_t length() const; size_t length() const;
auto& registered_observers_list() { return m_registered_observer_list; } auto& registered_observer_list() { return m_registered_observer_list; }
auto const& registered_observers_list() const { return m_registered_observer_list; } auto const& registered_observer_list() const { return m_registered_observer_list; }
void add_registered_observer(RegisteredObserver& registered_observer) { m_registered_observer_list.append(registered_observer); } void add_registered_observer(RegisteredObserver&);
void queue_mutation_record(FlyString const& type, Optional<FlyString> const& attribute_name, Optional<FlyString> const& attribute_namespace, Optional<String> const& old_value, Vector<JS::Handle<Node>> added_nodes, Vector<JS::Handle<Node>> removed_nodes, Node* previous_sibling, Node* next_sibling) const; void queue_mutation_record(FlyString const& type, Optional<FlyString> const& attribute_name, Optional<FlyString> const& attribute_namespace, Optional<String> const& old_value, Vector<JS::Handle<Node>> added_nodes, Vector<JS::Handle<Node>> removed_nodes, Node* previous_sibling, Node* next_sibling) const;
@ -693,7 +693,7 @@ protected:
// https://dom.spec.whatwg.org/#registered-observer-list // https://dom.spec.whatwg.org/#registered-observer-list
// "Nodes have a strong reference to registered observers in their registered observer list." https://dom.spec.whatwg.org/#garbage-collection // "Nodes have a strong reference to registered observers in their registered observer list." https://dom.spec.whatwg.org/#garbage-collection
Vector<JS::NonnullGCPtr<RegisteredObserver>> m_registered_observer_list; OwnPtr<Vector<JS::NonnullGCPtr<RegisteredObserver>>> m_registered_observer_list;
void build_accessibility_tree(AccessibilityTreeNode& parent); void build_accessibility_tree(AccessibilityTreeNode& parent);