LibWeb+WebContent: Don't let PageClient keep documents alive

We were inadvertently keeping all documents alive by installing a
console client for them. This patch fixes the issue by adding a
finalizer to Document, and having that be the way we detach console
clients. This breaks the cycle.

With this change, we can spam set .innerHTML in a loop and memory
usage remains stable.

Fixes #14612
This commit is contained in:
Andreas Kling 2024-04-20 09:19:02 +02:00
commit 44659f2f2a
Notes: sideshowbarker 2024-07-18 02:47:59 +09:00
4 changed files with 9 additions and 4 deletions

View file

@ -408,6 +408,12 @@ WebIDL::ExceptionOr<void> Document::populate_with_html_head_and_body()
return {};
}
void Document::finalize()
{
Base::finalize();
page().client().page_did_destroy_document(*this);
}
void Document::visit_edges(Cell::Visitor& visitor)
{
Base::visit_edges(visitor);
@ -3070,8 +3076,6 @@ void Document::run_unloading_cleanup_steps()
// https://html.spec.whatwg.org/multipage/document-lifecycle.html#destroy-a-document
void Document::destroy()
{
page().client().page_did_destroy_document(*this);
// NOTE: Abort needs to happen before destory. There is currently bug in the spec: https://github.com/whatwg/html/issues/9148
// 4. Abort document.
abort();

View file

@ -658,6 +658,7 @@ public:
protected:
virtual void initialize(JS::Realm&) override;
virtual void visit_edges(Cell::Visitor&) override;
virtual void finalize() override;
Document(JS::Realm&, URL::URL const&);

View file

@ -125,7 +125,6 @@ void PageClient::visit_edges(JS::Cell::Visitor& visitor)
{
Base::visit_edges(visitor);
visitor.visit(m_page);
visitor.visit(m_console_clients);
}
ConnectionFromClient& PageClient::client() const

View file

@ -195,7 +195,8 @@ private:
};
BackingStores m_backing_stores;
HashMap<JS::NonnullGCPtr<Web::DOM::Document>, NonnullOwnPtr<WebContentConsoleClient>> m_console_clients;
// NOTE: These documents are not visited, but manually removed from the map on document finalization.
HashMap<JS::RawGCPtr<Web::DOM::Document>, NonnullOwnPtr<WebContentConsoleClient>> m_console_clients;
WeakPtr<WebContentConsoleClient> m_top_level_document_console_client;
JS::Handle<JS::GlobalObject> m_console_global_object;