Merge pull request #1428 from lightpanda-io/parser_arena_pool

Use ArenaPool when parsing HTML and for TextDecoder (with finalizer)
This commit is contained in:
Karl Seguin
2026-01-29 06:49:14 +08:00
committed by GitHub
5 changed files with 40 additions and 11 deletions

View File

@@ -737,7 +737,10 @@ fn pageDoneCallback(ctx: *anyopaque) !void {
switch (self._parse_state) {
.html => |buf| {
var parser = Parser.init(self.arena, self.document.asNode(), self);
const parse_arena = try self.getArena(.{ .debug = "Page.parse" });
defer self.releaseArena(parse_arena);
var parser = Parser.init(parse_arena, self.document.asNode(), self);
parser.parse(buf.items);
self._script_manager.staticScriptsDone();
if (self._script_manager.isDone()) {
@@ -749,7 +752,11 @@ fn pageDoneCallback(ctx: *anyopaque) !void {
},
.text => |*buf| {
try buf.appendSlice(self.arena, "</pre></body></html>");
var parser = Parser.init(self.arena, self.document.asNode(), self);
const parse_arena = try self.getArena(.{ .debug = "Page.parse" });
defer self.releaseArena(parse_arena);
var parser = Parser.init(parse_arena, self.document.asNode(), self);
parser.parse(buf.items);
self.documentIsComplete();
},

View File

@@ -48,6 +48,9 @@ pub fn parseFromString(
@"image/svg+xml",
}, mime_type) orelse return error.NotSupported;
const arena = try page.getArena(.{ .debug = "DOMParser.parseFromString" });
defer page.releaseArena(arena);
return switch (target_mime) {
.@"text/html" => {
// Create a new HTMLDocument
@@ -61,7 +64,7 @@ pub fn parseFromString(
}
// Parse HTML into the document
var parser = Parser.init(page.arena, doc.asNode(), page);
var parser = Parser.init(arena, doc.asNode(), page);
parser.parse(normalized);
if (parser.err) |pe| {
@@ -78,7 +81,7 @@ pub fn parseFromString(
// Parse XML into XMLDocument.
const doc_node = doc.asNode();
var parser = Parser.init(page.arena, doc_node, page);
var parser = Parser.init(arena, doc_node, page);
parser.parseXML(html);
if (parser.err) |pe| {

View File

@@ -648,7 +648,10 @@ pub fn write(self: *Document, text: []const []const u8, page: *Page) !void {
page._parse_mode = .document_write;
defer page._parse_mode = previous_parse_mode;
var parser = Parser.init(page.call_arena, fragment_node, page);
const arena = try page.getArena(.{ .debug = "Document.write" });
defer page.releaseArena(arena);
var parser = Parser.init(arena, fragment_node, page);
parser.parseFragment(html);
// Extract children from wrapper HTML element (html5ever wraps fragments)
@@ -661,7 +664,7 @@ pub fn write(self: *Document, text: []const []const u8, page: *Page) !void {
var it = if (first.is(Element.Html.Html) == null) fragment_node.childrenIterator() else first.childrenIterator();
while (it.next()) |child| {
try children_to_insert.append(page.call_arena, child);
try children_to_insert.append(arena, child);
}
if (children_to_insert.items.len == 0) {

View File

@@ -281,8 +281,11 @@ pub fn insertAdjacentHTML(
});
const doc_node = doc.asNode();
const arena = try page.getArena(.{ .debug = "HTML.insertAdjacentHTML" });
defer page.releaseArena(arena);
const Parser = @import("../../parser/Parser.zig");
var parser = Parser.init(page.call_arena, doc_node, page);
var parser = Parser.init(arena, doc_node, page);
parser.parse(html);
// Check if there's parsing error.

View File

@@ -25,8 +25,9 @@ const Allocator = std.mem.Allocator;
const TextDecoder = @This();
_fatal: bool,
_ignore_bom: bool,
_page: *Page,
_arena: Allocator,
_ignore_bom: bool,
_stream: std.ArrayListUnmanaged(u8),
const Label = enum {
@@ -45,13 +46,23 @@ pub fn init(label_: ?[]const u8, opts_: ?InitOpts, page: *Page) !*TextDecoder {
_ = std.meta.stringToEnum(Label, label) orelse return error.RangeError;
}
const arena = try page.getArena(.{ .debug = "TextDecoder" });
errdefer page.releaseArena(arena);
const opts = opts_ orelse InitOpts{};
return page._factory.create(TextDecoder{
._arena = page.arena,
const self = try arena.create(TextDecoder);
self.* = .{
._page = page,
._arena = arena,
._stream = .empty,
._fatal = opts.fatal,
._ignore_bom = opts.ignoreBOM,
});
};
return self;
}
pub fn deinit(self: *TextDecoder, _: bool) void {
self._page.releaseArena(self._arena);
}
pub fn getEncoding(_: *const TextDecoder) []const u8 {
@@ -103,6 +114,8 @@ pub const JsApi = struct {
pub const name = "TextDecoder";
pub const prototype_chain = bridge.prototypeChain();
pub var class_id: bridge.ClassId = undefined;
pub const weak = true;
pub const finalizer = bridge.finalizer(TextDecoder.deinit);
};
pub const constructor = bridge.constructor(TextDecoder.init, .{});