Add RC support to NodeList

Most importantly, this allows the Selector.List to be self-contained with
an arena from the ArenaPool. Selector.List can be both relatively large
and relatively common, so moving it off the page.arena is a nice win.

Also applied this to ChildNodes, which is much smaller but could also be
called often.

I was initially going to hook into the v8::Object's internal fields to store
the referencing v8::Object. So the v8::Object representing the Iterator
would store the v8::Object representing the NodeList inside of its internal
field - which the GC would trace/detect/respect. And that is probably the
fastest and most v8-ish solution, but I couldn't come up with an elegant
solution. The best I had was having a "afterCreate" callback which passed
the v8 object (this is similar to the old postAttach callback we had, but
used for a different purpose). However, since "acquireRef" was recently
added to events, re-using that was much simpler and worked well.
This commit is contained in:
Karl Seguin
2026-02-27 10:17:30 +08:00
parent a14ad6f700
commit 315c9a2d92
10 changed files with 131 additions and 31 deletions

View File

@@ -98,6 +98,8 @@ fn performSearch(cmd: anytype) !void {
const bc = cmd.browser_context orelse return error.BrowserContextNotLoaded;
const page = bc.session.currentPage() orelse return error.PageNotLoaded;
const list = try Selector.querySelectorAll(page.window._document.asNode(), params.query, page);
defer list.deinit(page);
const search = try bc.node_search_list.create(list._nodes);
// dispatch setChildNodesEvents to inform the client of the subpart of node
@@ -247,6 +249,8 @@ fn querySelectorAll(cmd: anytype) !void {
};
const selected_nodes = try Selector.querySelectorAll(node.dom, params.selector, page);
defer selected_nodes.deinit(page);
const nodes = selected_nodes._nodes;
const node_ids = try cmd.arena.alloc(Node.Id, nodes.len);