mirror of
https://github.com/lightpanda-io/browser.git
synced 2026-06-11 09:35:59 -04:00
xpath: cache attribute axis nodes via frame lookup
The attribute axis was calling Entry.toAttribute on every visit, materializing fresh *Attribute structs (plus duped name/value strings) into page-lifetime storage. Repeated XPath queries — the Capybara/ Selenium polling pattern this PR targets — accumulated unbounded copies for the same DOM entries. Route through frame._attribute_lookup so each Entry resolves to a single cached *Attribute, matching List.getAttribute and NamedNodeMap.getAtIndex.
This commit is contained in:
@@ -277,11 +277,15 @@ fn appendAttributes(self: *Evaluator, node: *Node, out: *std.ArrayList(*Node)) E
|
||||
const el = node.is(Element) orelse return;
|
||||
var it = el.attributeIterator();
|
||||
while (it.next()) |entry| {
|
||||
// Materialize as full Attribute so the result is *Node-uniform.
|
||||
// Allocates from frame.arena (long-lived); attribute axis is
|
||||
// typically leaf, so churn is bounded.
|
||||
const attr = try entry.toAttribute(el, self.frame);
|
||||
try out.append(self.arena, attr._proto);
|
||||
// Memoize via frame._attribute_lookup so repeated XPath queries
|
||||
// (Capybara/Selenium polling) reuse the same *Attribute instead
|
||||
// of leaking fresh ones into page-lifetime storage on every call.
|
||||
// Same pattern as Attribute.List.getAttribute / NamedNodeMap.getAtIndex.
|
||||
const gop = try self.frame._attribute_lookup.getOrPut(self.frame.arena, @intFromPtr(entry));
|
||||
if (!gop.found_existing) {
|
||||
gop.value_ptr.* = try entry.toAttribute(el, self.frame);
|
||||
}
|
||||
try out.append(self.arena, gop.value_ptr.*._proto);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user