diff --git a/src/App.zig b/src/App.zig index 8e3fe0c9..9e8741ba 100644 --- a/src/App.zig +++ b/src/App.zig @@ -69,7 +69,7 @@ pub fn init(allocator: Allocator, config: *const Config) !*App { app.telemetry = try Telemetry.init(app, config.mode); errdefer app.telemetry.deinit(allocator); - app.arena_pool = ArenaPool.init(allocator, 512, 1024 * 16); + app.arena_pool = ArenaPool.init(allocator, .{}); errdefer app.arena_pool.deinit(); return app; diff --git a/src/ArenaPool.zig b/src/ArenaPool.zig index 96fb694f..2b501438 100644 --- a/src/ArenaPool.zig +++ b/src/ArenaPool.zig @@ -27,33 +27,52 @@ const ArenaPool = @This(); const IS_DEBUG = builtin.mode == .Debug; -allocator: Allocator, -retain_bytes: usize, -free_list_len: u16 = 0, -free_list: ?*Entry = null, -free_list_max: u16, -entry_pool: std.heap.MemoryPool(Entry), -mutex: std.Thread.Mutex = .{}, -// Debug mode: track acquire/release counts per debug name to detect leaks and double-frees -_leak_track: if (IS_DEBUG) std.StringHashMapUnmanaged(isize) else void = if (IS_DEBUG) .empty else {}, +pub const BucketSize = enum { tiny, small, medium, large }; + +const Bucket = struct { + free_list: ?*Entry = null, + free_list_len: u16 = 0, + free_list_max: u16, + retain_bytes: usize, +}; const Entry = struct { next: ?*Entry, arena: ArenaAllocator, + bucket: *Bucket, debug: if (IS_DEBUG) []const u8 else void = if (IS_DEBUG) "" else {}, }; -pub const DebugInfo = struct { - debug: []const u8 = "", +pub const Config = struct { + tiny: Config.Bucket = .{ .max = 512, .retain = 1024 }, + small: Config.Bucket = .{ .max = 128, .retain = 4 * 1024 }, + medium: Config.Bucket = .{ .max = 64, .retain = 16 * 1024 }, + large: Config.Bucket = .{ .max = 32, .retain = 128 * 1024 }, + + const Bucket = struct { + max: u16, + retain: usize, + }; }; -pub fn init(allocator: Allocator, free_list_max: u16, retain_bytes: usize) ArenaPool { +tiny: Bucket, +small: Bucket, +medium: Bucket, +large: Bucket, +allocator: Allocator, +mutex: std.Thread.Mutex = .{}, +entry_pool: std.heap.MemoryPool(Entry), + +_leak_track: if (IS_DEBUG) std.StringHashMapUnmanaged(isize) else void = if (IS_DEBUG) .empty else {}, + +pub fn init(allocator: Allocator, config: Config) ArenaPool { return .{ .allocator = allocator, - .free_list_max = free_list_max, - .retain_bytes = retain_bytes, .entry_pool = .init(allocator), - ._leak_track = if (IS_DEBUG) .empty else {}, + .tiny = .{ .free_list_max = config.tiny.max, .retain_bytes = config.tiny.retain }, + .small = .{ .free_list_max = config.small.max, .retain_bytes = config.small.retain }, + .medium = .{ .free_list_max = config.medium.max, .retain_bytes = config.medium.retain }, + .large = .{ .free_list_max = config.large.max, .retain_bytes = config.large.retain }, }; } @@ -73,24 +92,49 @@ pub fn deinit(self: *ArenaPool) void { self._leak_track.deinit(self.allocator); } - var entry = self.free_list; - while (entry) |e| { - entry = e.next; - e.arena.deinit(); + // Free all arenas in all buckets + inline for (&[_]*Bucket{ &self.tiny, &self.small, &self.medium, &self.large }) |bucket| { + var entry = bucket.free_list; + while (entry) |e| { + entry = e.next; + e.arena.deinit(); + } } self.entry_pool.deinit(); } -pub fn acquire(self: *ArenaPool, dbg: DebugInfo) !Allocator { +// Acquire an arena from the pool. +// - Pass a BucketSize (.tiny, .small, .medium, .large) for explicit bucket selection +// - Pass a usize for automatic bucket selection based on expected size +pub fn acquire(self: *ArenaPool, size_or_bucket: anytype, debug: []const u8) !Allocator { + const bucket = blk: { + const T = @TypeOf(size_or_bucket); + if (T == BucketSize or T == @TypeOf(.enum_literal)) { + break :blk switch (@as(BucketSize, size_or_bucket)) { + .tiny => &self.tiny, + .small => &self.small, + .medium => &self.medium, + .large => &self.large, + }; + } + if (T == usize or T == comptime_int) { + if (size_or_bucket <= self.tiny.retain_bytes) break :blk &self.tiny; + if (size_or_bucket <= self.small.retain_bytes) break :blk &self.small; + if (size_or_bucket <= self.medium.retain_bytes) break :blk &self.medium; + break :blk &self.large; + } + @compileError("acquire expects BucketSize or usize, got " ++ @typeName(T)); + }; + self.mutex.lock(); defer self.mutex.unlock(); - if (self.free_list) |entry| { - self.free_list = entry.next; - self.free_list_len -= 1; + if (bucket.free_list) |entry| { + bucket.free_list = entry.next; + bucket.free_list_len -= 1; if (IS_DEBUG) { - entry.debug = dbg.debug; - const gop = try self._leak_track.getOrPut(self.allocator, dbg.debug); + entry.debug = debug; + const gop = try self._leak_track.getOrPut(self.allocator, debug); if (!gop.found_existing) { gop.value_ptr.* = 0; } @@ -102,12 +146,13 @@ pub fn acquire(self: *ArenaPool, dbg: DebugInfo) !Allocator { const entry = try self.entry_pool.create(); entry.* = .{ .next = null, + .bucket = bucket, + .debug = if (IS_DEBUG) debug else {}, .arena = ArenaAllocator.init(self.allocator), - .debug = if (IS_DEBUG) dbg.debug else {}, }; if (IS_DEBUG) { - const gop = try self._leak_track.getOrPut(self.allocator, dbg.debug); + const gop = try self._leak_track.getOrPut(self.allocator, debug); if (!gop.found_existing) { gop.value_ptr.* = 0; } @@ -116,12 +161,14 @@ pub fn acquire(self: *ArenaPool, dbg: DebugInfo) !Allocator { return entry.arena.allocator(); } +// Universal release - determines bucket from the Entry automatically pub fn release(self: *ArenaPool, allocator: Allocator) void { - const arena: *std.heap.ArenaAllocator = @ptrCast(@alignCast(allocator.ptr)); + const arena: *ArenaAllocator = @ptrCast(@alignCast(allocator.ptr)); const entry: *Entry = @fieldParentPtr("arena", arena); + const bucket = entry.bucket; // Reset the arena before acquiring the lock to minimize lock hold time - _ = arena.reset(.{ .retain_with_limit = self.retain_bytes }); + _ = arena.reset(.{ .retain_with_limit = bucket.retain_bytes }); self.mutex.lock(); defer self.mutex.unlock(); @@ -139,105 +186,113 @@ pub fn release(self: *ArenaPool, allocator: Allocator) void { } } - const free_list_len = self.free_list_len; - if (free_list_len == self.free_list_max) { + if (bucket.free_list_len >= bucket.free_list_max) { arena.deinit(); self.entry_pool.destroy(entry); return; } - entry.next = self.free_list; - self.free_list_len = free_list_len + 1; - self.free_list = entry; + entry.next = bucket.free_list; + bucket.free_list = entry; + bucket.free_list_len += 1; } pub fn reset(_: *const ArenaPool, allocator: Allocator, retain: usize) void { - const arena: *std.heap.ArenaAllocator = @ptrCast(@alignCast(allocator.ptr)); + const arena: *ArenaAllocator = @ptrCast(@alignCast(allocator.ptr)); _ = arena.reset(.{ .retain_with_limit = retain }); } pub fn resetRetain(_: *const ArenaPool, allocator: Allocator) void { - const arena: *std.heap.ArenaAllocator = @ptrCast(@alignCast(allocator.ptr)); + const arena: *ArenaAllocator = @ptrCast(@alignCast(allocator.ptr)); _ = arena.reset(.retain_capacity); } const testing = std.testing; - -test "arena pool - basic acquire and use" { - var pool = ArenaPool.init(testing.allocator, 512, 1024 * 16); +test "ArenaPool: basic acquire and release" { + var pool = ArenaPool.init(testing.allocator, .{}); defer pool.deinit(); - const alloc = try pool.acquire(.{ .debug = "test" }); - const buf = try alloc.alloc(u8, 64); - @memset(buf, 0xAB); - try testing.expectEqual(@as(u8, 0xAB), buf[0]); + const tiny = try pool.acquire(.tiny, "test-tiny"); + const medium = try pool.acquire(.medium, "test-medium"); + const large = try pool.acquire(.large, "test-large"); - pool.release(alloc); + // All three must be distinct arenas + try testing.expect(tiny.ptr != medium.ptr); + try testing.expect(medium.ptr != large.ptr); + + _ = try tiny.alloc(u8, 64); + _ = try medium.alloc(u8, 1024); + _ = try large.alloc(u8, 4096); + + // Universal release works for all buckets + pool.release(tiny); + pool.release(medium); + pool.release(large); + + try testing.expectEqual(1, pool.tiny.free_list_len); + try testing.expectEqual(1, pool.medium.free_list_len); + try testing.expectEqual(1, pool.large.free_list_len); } -test "arena pool - reuse entry after release" { - var pool = ArenaPool.init(testing.allocator, 512, 1024 * 16); +test "ArenaPool: reuse from correct bucket" { + var pool = ArenaPool.init(testing.allocator, .{}); defer pool.deinit(); - const alloc1 = try pool.acquire(.{ .debug = "test" }); - try testing.expectEqual(@as(u16, 0), pool.free_list_len); + const tiny1 = try pool.acquire(.tiny, "test"); + pool.release(tiny1); + try testing.expectEqual(1, pool.tiny.free_list_len); - pool.release(alloc1); - try testing.expectEqual(@as(u16, 1), pool.free_list_len); + // Next acquire with .tiny should reuse from tiny bucket + const tiny2 = try pool.acquire(.tiny, "test"); + try testing.expectEqual(0, pool.tiny.free_list_len); + try testing.expectEqual(tiny1.ptr, tiny2.ptr); - // The same entry should be returned from the free list. - const alloc2 = try pool.acquire(.{ .debug = "test" }); - try testing.expectEqual(@as(u16, 0), pool.free_list_len); - try testing.expectEqual(alloc1.ptr, alloc2.ptr); + // acquire with .medium should NOT get the tiny arena + const medium = try pool.acquire(.medium, "test-medium"); + try testing.expect(medium.ptr != tiny2.ptr); - pool.release(alloc2); + pool.release(tiny2); + pool.release(medium); } -test "arena pool - multiple concurrent arenas" { - var pool = ArenaPool.init(testing.allocator, 512, 1024 * 16); +test "ArenaPool: respects per-bucket max limits" { + var pool = ArenaPool.init(testing.allocator, .{ + .tiny = .{ .max = 1, .retain = 1024 }, + .medium = .{ .max = 2, .retain = 1024 }, + .large = .{ .max = 1, .retain = 1024 }, + }); defer pool.deinit(); - const a1 = try pool.acquire(.{ .debug = "test1" }); - const a2 = try pool.acquire(.{ .debug = "test2" }); - const a3 = try pool.acquire(.{ .debug = "test3" }); + // Acquire 3 tiny arenas + const t1 = try pool.acquire(.tiny, "t1"); + const t2 = try pool.acquire(.tiny, "t2"); + const t3 = try pool.acquire(.tiny, "t3"); - // All three must be distinct arenas. - try testing.expect(a1.ptr != a2.ptr); - try testing.expect(a2.ptr != a3.ptr); - try testing.expect(a1.ptr != a3.ptr); + // Release all 3, but only 1 should be kept (tiny_max = 1) + pool.release(t1); + try testing.expectEqual(1, pool.tiny.free_list_len); + pool.release(t2); + try testing.expectEqual(1, pool.tiny.free_list_len); // still 1, t2 discarded + pool.release(t3); + try testing.expectEqual(1, pool.tiny.free_list_len); // still 1, t3 discarded - _ = try a1.alloc(u8, 16); - _ = try a2.alloc(u8, 32); - _ = try a3.alloc(u8, 48); + // Acquire 3 medium arenas + const m1 = try pool.acquire(.medium, "m1"); + const m2 = try pool.acquire(.medium, "m2"); + const m3 = try pool.acquire(.medium, "m3"); - pool.release(a1); - pool.release(a2); - pool.release(a3); - - try testing.expectEqual(@as(u16, 3), pool.free_list_len); + // Release all 3, but only 2 should be kept (medium_max = 2) + pool.release(m1); + pool.release(m2); + pool.release(m3); + try testing.expectEqual(2, pool.medium.free_list_len); } -test "arena pool - free list respects max limit" { - // Cap the free list at 1 so the second release discards its arena. - var pool = ArenaPool.init(testing.allocator, 1, 1024 * 16); +test "ArenaPool: reset clears memory without releasing" { + var pool = ArenaPool.init(testing.allocator, .{}); defer pool.deinit(); - const a1 = try pool.acquire(.{ .debug = "test1" }); - const a2 = try pool.acquire(.{ .debug = "test2" }); - - pool.release(a1); - try testing.expectEqual(@as(u16, 1), pool.free_list_len); - - // The free list is full; a2's arena should be destroyed, not queued. - pool.release(a2); - try testing.expectEqual(@as(u16, 1), pool.free_list_len); -} - -test "arena pool - reset clears memory without releasing" { - var pool = ArenaPool.init(testing.allocator, 512, 1024 * 16); - defer pool.deinit(); - - const alloc = try pool.acquire(.{ .debug = "test" }); + const alloc = try pool.acquire(.medium, "test"); const buf = try alloc.alloc(u8, 128); @memset(buf, 0xFF); @@ -246,7 +301,7 @@ test "arena pool - reset clears memory without releasing" { pool.reset(alloc, 0); // The free list must stay empty; the allocator was not released. - try testing.expectEqual(@as(u16, 0), pool.free_list_len); + try testing.expectEqual(0, pool.medium.free_list_len); // Allocating again through the same arena must still work. const buf2 = try alloc.alloc(u8, 64); @@ -256,18 +311,60 @@ test "arena pool - reset clears memory without releasing" { pool.release(alloc); } -test "arena pool - deinit with entries in free list" { +test "ArenaPool: deinit with entries in free list" { // Verifies that deinit properly cleans up free-listed arenas (no leaks // detected by the test allocator). - var pool = ArenaPool.init(testing.allocator, 512, 1024 * 16); + var pool = ArenaPool.init(testing.allocator, .{}); - const a1 = try pool.acquire(.{ .debug = "test1" }); - const a2 = try pool.acquire(.{ .debug = "test2" }); + const a1 = try pool.acquire(.tiny, "test1"); + const a2 = try pool.acquire(.medium, "test2"); _ = try a1.alloc(u8, 256); _ = try a2.alloc(u8, 512); pool.release(a1); pool.release(a2); - try testing.expectEqual(@as(u16, 2), pool.free_list_len); + try testing.expectEqual(1, pool.tiny.free_list_len); + try testing.expectEqual(1, pool.medium.free_list_len); pool.deinit(); } + +test "ArenaPool: small bucket" { + var pool = ArenaPool.init(testing.allocator, .{ + .small = .{ .max = 2, .retain = 4 * 1024 }, + }); + defer pool.deinit(); + + const s1 = try pool.acquire(.small, "s1"); + const s2 = try pool.acquire(.small, "s2"); + const s3 = try pool.acquire(.small, "s3"); + + pool.release(s1); + pool.release(s2); + pool.release(s3); + + try testing.expectEqual(2, pool.small.free_list_len); +} + +test "ArenaPool: size-based acquire" { + var pool = ArenaPool.init(testing.allocator, .{}); + defer pool.deinit(); + + // <= 1KB -> tiny + const a = try pool.acquire(500, "fits-tiny"); + // <= 4KB -> small + const b = try pool.acquire(2000, "fits-small"); + // <= 16KB -> medium + const c = try pool.acquire(8000, "fits-medium"); + // > 16KB -> large + const d = try pool.acquire(20000, "fits-large"); + + pool.release(a); + pool.release(b); + pool.release(c); + pool.release(d); + + try testing.expectEqual(1, pool.tiny.free_list_len); + try testing.expectEqual(1, pool.small.free_list_len); + try testing.expectEqual(1, pool.medium.free_list_len); + try testing.expectEqual(1, pool.large.free_list_len); +} diff --git a/src/browser/HttpClient.zig b/src/browser/HttpClient.zig index b90029ac..a2da34d5 100644 --- a/src/browser/HttpClient.zig +++ b/src/browser/HttpClient.zig @@ -374,7 +374,8 @@ fn serveFromCache(req: Request, cached: *const CachedResponse) !void { fn processRequest(self: *Client, req: Request) !void { if (self.network.cache) |*cache| { if (req.method == .GET) { - const arena = try self.network.app.arena_pool.acquire(.{ .debug = "HttpClient.processRequest.cache" }); + // cache is only used to read the meta data + const arena = try self.network.app.arena_pool.acquire(.small, "HttpClient.cache"); defer self.network.app.arena_pool.release(arena); var iter = req.headers.iterator(); diff --git a/src/browser/Page.zig b/src/browser/Page.zig index f12b606b..8ddd29ee 100644 --- a/src/browser/Page.zig +++ b/src/browser/Page.zig @@ -248,7 +248,7 @@ pub fn init(self: *Page, frame_id: u32, session: *Session, parent: ?*Page) !void log.debug(.page, "page.init", .{}); } - const call_arena = try session.getArena(.{ .debug = "call_arena" }); + const call_arena = try session.getArena(.medium, "call_arena"); errdefer session.releaseArena(call_arena); const factory = &session.factory; @@ -429,8 +429,8 @@ pub fn headersForRequest(self: *Page, headers: *HttpClient.Headers) !void { } } -pub fn getArena(self: *Page, comptime opts: Session.GetArenaOpts) !Allocator { - return self._session.getArena(opts); +pub fn getArena(self: *Page, size_or_bucket: anytype, debug: []const u8) !Allocator { + return self._session.getArena(size_or_bucket, debug); } pub fn releaseArena(self: *Page, allocator: Allocator) void { @@ -510,7 +510,7 @@ pub fn navigate(self: *Page, request_url: [:0]const u8, opts: NavigateOpts) !voi log.warn(.js, "invalid blob", .{ .url = request_url }); return error.BlobNotFound; }; - const parse_arena = try self.getArena(.{ .debug = "Page.parseBlob" }); + const parse_arena = try self.getArena(.medium, "Page.parseBlob"); defer self.releaseArena(parse_arena); var parser = Parser.init(parse_arena, self.document.asNode(), self); parser.parse(blob._slice); @@ -619,7 +619,7 @@ pub fn scheduleNavigation(self: *Page, request_url: []const u8, opts: NavigateOp if (self.canScheduleNavigation(std.meta.activeTag(nt)) == false) { return; } - const arena = try self._session.getArena(.{ .debug = "scheduleNavigation" }); + const arena = try self._session.getArena(.small, "scheduleNavigation"); errdefer self._session.releaseArena(arena); return self.scheduleNavigationWithArena(arena, request_url, opts, nt); } @@ -1022,7 +1022,7 @@ fn pageDoneCallback(ctx: *anyopaque) !void { }); }; - const parse_arena = try self.getArena(.{ .debug = "Page.parse" }); + const parse_arena = try self.getArena(.medium, "Page.parse"); defer self.releaseArena(parse_arena); var parser = Parser.init(parse_arena, self.document.asNode(), self); @@ -3568,7 +3568,7 @@ pub fn submitForm(self: *Page, submitter_: ?*Element, form_: ?*Element.Html.Form // I don't think this is technically correct, but FormData handles it ok const form_data = try FormData.init(form, submitter_, self); - const arena = try self._session.getArena(.{ .debug = "submitForm" }); + const arena = try self._session.getArena(.medium, "submitForm"); errdefer self._session.releaseArena(arena); const encoding = form_element.getAttributeSafe(comptime .wrap("enctype")); diff --git a/src/browser/Runner.zig b/src/browser/Runner.zig index 4ee753ea..fd3889e6 100644 --- a/src/browser/Runner.zig +++ b/src/browser/Runner.zig @@ -249,7 +249,7 @@ fn _tick(self: *Runner, comptime is_cdp: bool, opts: TickOpts) !CDPTickResult { } pub fn waitForSelector(self: *Runner, selector: [:0]const u8, timeout_ms: u32) !*Node.Element { - const arena = try self.session.getArena(.{ .debug = "Runner.waitForSelector" }); + const arena = try self.session.getArena(.small, "Runner.waitForSelector"); defer self.session.releaseArena(arena); var timer = try std.time.Timer.start(); diff --git a/src/browser/ScriptManager.zig b/src/browser/ScriptManager.zig index 984ecccc..95b7f839 100644 --- a/src/browser/ScriptManager.zig +++ b/src/browser/ScriptManager.zig @@ -188,7 +188,7 @@ pub fn addFromElement(self: *ScriptManager, comptime from_parser: bool, script_e var handover = false; const page = self.page; - const arena = try page.getArena(.{ .debug = "addFromElement" }); + const arena = try page.getArena(.large, "SM.addFromElement"); errdefer if (!handover) { page.releaseArena(arena); }; @@ -369,7 +369,7 @@ pub fn preloadImport(self: *ScriptManager, url: [:0]const u8, referrer: []const errdefer _ = self.imported_modules.remove(url); const page = self.page; - const arena = try page.getArena(.{ .debug = "preloadImport" }); + const arena = try page.getArena(.large, "SM.preloadImport"); errdefer page.releaseArena(arena); const script = try arena.create(Script); @@ -469,7 +469,7 @@ pub fn waitForImport(self: *ScriptManager, url: [:0]const u8) !ModuleSource { pub fn getAsyncImport(self: *ScriptManager, url: [:0]const u8, cb: ImportAsync.Callback, cb_data: *anyopaque, referrer: []const u8) !void { const page = self.page; - const arena = try page.getArena(.{ .debug = "getAsyncImport" }); + const arena = try page.getArena(.large, "SM.getAsyncImport"); errdefer page.releaseArena(arena); const script = try arena.create(Script); diff --git a/src/browser/Session.zig b/src/browser/Session.zig index 8ec3e217..baea1590 100644 --- a/src/browser/Session.zig +++ b/src/browser/Session.zig @@ -110,10 +110,10 @@ pub fn init(self: *Session, browser: *Browser, notification: *Notification) !voi const allocator = browser.app.allocator; const arena_pool = browser.arena_pool; - const arena = try arena_pool.acquire(.{ .debug = "Session" }); + const arena = try arena_pool.acquire(.small, "Session"); errdefer arena_pool.release(arena); - const page_arena = try arena_pool.acquire(.{ .debug = "Session.page_arena" }); + const page_arena = try arena_pool.acquire(.large, "Session.page_arena"); errdefer arena_pool.release(page_arena); self.* = .{ @@ -186,12 +186,8 @@ pub fn removePage(self: *Session) void { } } -pub const GetArenaOpts = struct { - debug: []const u8, -}; - -pub fn getArena(self: *Session, opts: GetArenaOpts) !Allocator { - return self.arena_pool.acquire(.{ .debug = opts.debug }); +pub fn getArena(self: *Session, size_or_bucket: anytype, debug: []const u8) !Allocator { + return self.arena_pool.acquire(size_or_bucket, debug); } pub fn releaseArena(self: *Session, allocator: Allocator) void { diff --git a/src/browser/StyleManager.zig b/src/browser/StyleManager.zig index 161ebca0..404a11ed 100644 --- a/src/browser/StyleManager.zig +++ b/src/browser/StyleManager.zig @@ -66,7 +66,7 @@ dirty: bool = false, pub fn init(page: *Page) !StyleManager { return .{ .page = page, - .arena = try page.getArena(.{ .debug = "StyleManager" }), + .arena = try page.getArena(.medium, "StyleManager"), }; } diff --git a/src/browser/js/Env.zig b/src/browser/js/Env.zig index 2c1ebf38..03eadac3 100644 --- a/src/browser/js/Env.zig +++ b/src/browser/js/Env.zig @@ -261,7 +261,7 @@ pub const ContextParams = struct { }; pub fn createContext(self: *Env, page: *Page, params: ContextParams) !*Context { - const context_arena = try self.app.arena_pool.acquire(.{ .debug = params.debug_name }); + const context_arena = try self.app.arena_pool.acquire(.large, params.debug_name); errdefer self.app.arena_pool.release(context_arena); const isolate = self.isolate; diff --git a/src/browser/js/Local.zig b/src/browser/js/Local.zig index 4d91ed2e..170e5c0c 100644 --- a/src/browser/js/Local.zig +++ b/src/browser/js/Local.zig @@ -1479,7 +1479,7 @@ fn createFinalizerCallback( ) !*Session.FinalizerCallback { const session = self.ctx.session; - const arena = try session.getArena(.{ .debug = "FinalizerCallback" }); + const arena = try session.getArena(.tiny, "FinalizerCallback"); errdefer session.releaseArena(arena); const fc = try arena.create(Session.FinalizerCallback); diff --git a/src/browser/js/Origin.zig b/src/browser/js/Origin.zig index c6c6bf81..fce37ce0 100644 --- a/src/browser/js/Origin.zig +++ b/src/browser/js/Origin.zig @@ -45,7 +45,7 @@ key: []const u8, security_token: v8.Global, pub fn init(app: *App, isolate: js.Isolate, key: []const u8) !*Origin { - const arena = try app.arena_pool.acquire(.{ .debug = "Origin" }); + const arena = try app.arena_pool.acquire(.tiny, "Origin"); errdefer app.arena_pool.release(arena); var hs: js.HandleScope = undefined; diff --git a/src/browser/js/String.zig b/src/browser/js/String.zig index 2cbe6a17..8d29d838 100644 --- a/src/browser/js/String.zig +++ b/src/browser/js/String.zig @@ -44,11 +44,11 @@ fn _toSlice(self: String, comptime null_terminate: bool, allocator: Allocator) ! const handle = self.handle; const isolate = local.isolate.handle; - const len = v8.v8__String__Utf8Length(handle, isolate); - const buf = try (if (comptime null_terminate) allocator.allocSentinel(u8, @intCast(len), 0) else allocator.alloc(u8, @intCast(len))); + const l = v8.v8__String__Utf8Length(handle, isolate); + const buf = try (if (comptime null_terminate) allocator.allocSentinel(u8, @intCast(l), 0) else allocator.alloc(u8, @intCast(l))); const n = v8.v8__String__WriteUtf8(handle, isolate, buf.ptr, buf.len, v8.NO_NULL_TERMINATION | v8.REPLACE_INVALID_UTF8); if (comptime IS_DEBUG) { - std.debug.assert(n == len); + std.debug.assert(n == l); } return buf; @@ -64,32 +64,32 @@ pub fn toSSOWithAlloc(self: String, allocator: Allocator) !SSO { const handle = self.handle; const isolate = self.local.isolate.handle; - const len: usize = @intCast(v8.v8__String__Utf8Length(handle, isolate)); + const l: usize = @intCast(v8.v8__String__Utf8Length(handle, isolate)); - if (len <= 12) { + if (l <= 12) { var content: [12]u8 = undefined; const n = v8.v8__String__WriteUtf8(handle, isolate, &content[0], content.len, v8.NO_NULL_TERMINATION | v8.REPLACE_INVALID_UTF8); if (comptime IS_DEBUG) { - std.debug.assert(n == len); + std.debug.assert(n == l); } // Weird that we do this _after_, but we have to..I've seen weird issues // in ReleaseMode where v8 won't write to content if it starts off zero // initiated - @memset(content[len..], 0); - return .{ .len = @intCast(len), .payload = .{ .content = content } }; + @memset(content[l..], 0); + return .{ .len = @intCast(l), .payload = .{ .content = content } }; } - const buf = try allocator.alloc(u8, len); + const buf = try allocator.alloc(u8, l); const n = v8.v8__String__WriteUtf8(handle, isolate, buf.ptr, buf.len, v8.NO_NULL_TERMINATION | v8.REPLACE_INVALID_UTF8); if (comptime IS_DEBUG) { - std.debug.assert(n == len); + std.debug.assert(n == l); } var prefix: [4]u8 = @splat(0); @memcpy(&prefix, buf[0..4]); return .{ - .len = @intCast(len), + .len = @intCast(l), .payload = .{ .heap = .{ .prefix = prefix, .ptr = buf.ptr, @@ -103,9 +103,13 @@ pub fn format(self: String, writer: *std.Io.Writer) !void { const isolate = local.isolate.handle; var small: [1024]u8 = undefined; - const len = v8.v8__String__Utf8Length(handle, isolate); - var buf = if (len < 1024) &small else local.call_arena.alloc(u8, @intCast(len)) catch return error.WriteFailed; + const l = v8.v8__String__Utf8Length(handle, isolate); + var buf = if (l < 1024) &small else local.call_arena.alloc(u8, @intCast(l)) catch return error.WriteFailed; const n = v8.v8__String__WriteUtf8(handle, isolate, buf.ptr, buf.len, v8.NO_NULL_TERMINATION | v8.REPLACE_INVALID_UTF8); return writer.writeAll(buf[0..n]); } + +pub fn len(self: String) usize { + return @intCast(v8.v8__String__Utf8Length(self.handle, self.local.isolate.handle)); +} diff --git a/src/browser/webapi/Blob.zig b/src/browser/webapi/Blob.zig index bf0c1118..0598d7fc 100644 --- a/src/browser/webapi/Blob.zig +++ b/src/browser/webapi/Blob.zig @@ -77,7 +77,15 @@ pub fn initWithMimeValidation( validate_mime: bool, page: *Page, ) !*Blob { - const arena = try page.getArena(.{ .debug = "Blob" }); + const data_len = blk: { + const parts = maybe_blob_parts orelse break :blk 0; + var size: usize = 0; + for (parts) |p| { + size += p.len; + } + break :blk size; + }; + const arena = try page.getArena(256 + data_len, "Blob"); errdefer page.releaseArena(arena); const options: InitOptions = maybe_options orelse .{}; diff --git a/src/browser/webapi/DOMParser.zig b/src/browser/webapi/DOMParser.zig index 10a94bca..7bd5b600 100644 --- a/src/browser/webapi/DOMParser.zig +++ b/src/browser/webapi/DOMParser.zig @@ -50,7 +50,7 @@ pub fn parseFromString( @"image/svg+xml", }, mime_type) orelse return error.NotSupported; - const arena = try page.getArena(.{ .debug = "DOMParser.parseFromString" }); + const arena = try page.getArena(.medium, "DOMParser.parseFromString"); defer page.releaseArena(arena); return switch (target_mime) { diff --git a/src/browser/webapi/Document.zig b/src/browser/webapi/Document.zig index cf15c49b..5b6c0a4a 100644 --- a/src/browser/webapi/Document.zig +++ b/src/browser/webapi/Document.zig @@ -666,7 +666,7 @@ pub fn write(self: *Document, text: []const []const u8, page: *Page) !void { page._parse_mode = .document_write; defer page._parse_mode = previous_parse_mode; - const arena = try page.getArena(.{ .debug = "Document.write" }); + const arena = try page.getArena(.medium, "Document.write"); defer page.releaseArena(arena); var parser = Parser.init(arena, fragment_node, page); diff --git a/src/browser/webapi/Event.zig b/src/browser/webapi/Event.zig index b573bfc7..50895866 100644 --- a/src/browser/webapi/Event.zig +++ b/src/browser/webapi/Event.zig @@ -90,14 +90,14 @@ pub const Options = struct { }; pub fn init(typ: []const u8, opts_: ?Options, page: *Page) !*Event { - const arena = try page.getArena(.{ .debug = "Event" }); + const arena = try page.getArena(.tiny, "Event"); errdefer page.releaseArena(arena); const str = try String.init(arena, typ, .{}); return initWithTrusted(arena, str, opts_, false); } pub fn initTrusted(typ: String, opts_: ?Options, page: *Page) !*Event { - const arena = try page.getArena(.{ .debug = "Event.trusted" }); + const arena = try page.getArena(.tiny, "Event.trusted"); errdefer page.releaseArena(arena); return initWithTrusted(arena, typ, opts_, true); } diff --git a/src/browser/webapi/File.zig b/src/browser/webapi/File.zig index fb27359a..e4c70662 100644 --- a/src/browser/webapi/File.zig +++ b/src/browser/webapi/File.zig @@ -31,7 +31,7 @@ _proto: *Blob, // TODO: Implement File API. pub fn init(page: *Page) !*File { - const arena = try page.getArena(.{ .debug = "File" }); + const arena = try page.getArena(.tiny, "File"); errdefer page.releaseArena(arena); return page._factory.blob(arena, File{ ._proto = undefined }); } diff --git a/src/browser/webapi/FileReader.zig b/src/browser/webapi/FileReader.zig index 109fdc7b..33f0e209 100644 --- a/src/browser/webapi/FileReader.zig +++ b/src/browser/webapi/FileReader.zig @@ -63,7 +63,7 @@ const Result = union(enum) { }; pub fn init(page: *Page) !*FileReader { - const arena = try page.getArena(.{ .debug = "FileReader" }); + const arena = try page.getArena(.tiny, "FileReader"); errdefer page.releaseArena(arena); return page._factory.eventTargetWithAllocator(arena, FileReader{ diff --git a/src/browser/webapi/IntersectionObserver.zig b/src/browser/webapi/IntersectionObserver.zig index cbc9278f..990c45ee 100644 --- a/src/browser/webapi/IntersectionObserver.zig +++ b/src/browser/webapi/IntersectionObserver.zig @@ -71,7 +71,7 @@ pub const ObserverInit = struct { }; pub fn init(callback: js.Function.Temp, options: ?ObserverInit, page: *Page) !*IntersectionObserver { - const arena = try page.getArena(.{ .debug = "IntersectionObserver" }); + const arena = try page.getArena(.medium, "IntersectionObserver"); errdefer page.releaseArena(arena); const opts = options orelse ObserverInit{}; @@ -266,7 +266,7 @@ fn checkIntersection(self: *IntersectionObserver, target: *Element, page: *Page) (was_intersecting_opt != null and was_intersecting_opt.? != is_now_intersecting); if (should_report) { - const arena = try page.getArena(.{ .debug = "IntersectionObserverEntry" }); + const arena = try page.getArena(.tiny, "IntersectionObserverEntry"); errdefer page.releaseArena(arena); const entry = try arena.create(IntersectionObserverEntry); diff --git a/src/browser/webapi/MutationObserver.zig b/src/browser/webapi/MutationObserver.zig index 5453e797..6a99fcb5 100644 --- a/src/browser/webapi/MutationObserver.zig +++ b/src/browser/webapi/MutationObserver.zig @@ -76,7 +76,7 @@ pub const ObserveOptions = struct { }; pub fn init(callback: js.Function.Temp, page: *Page) !*MutationObserver { - const arena = try page.getArena(.{ .debug = "MutationObserver" }); + const arena = try page.getArena(.medium, "MutationObserver"); errdefer page.releaseArena(arena); const self = try arena.create(MutationObserver); @@ -227,7 +227,7 @@ pub fn notifyAttributeChange( } } - const arena = try page.getArena(.{ .debug = "MutationRecord" }); + const arena = try page.getArena(.tiny, "MutationRecord"); const record = try arena.create(MutationRecord); record.* = .{ ._arena = arena, @@ -271,7 +271,7 @@ pub fn notifyCharacterDataChange( continue; } - const arena = try page.getArena(.{ .debug = "MutationRecord" }); + const arena = try page.getArena(.tiny, "MutationRecord"); const record = try arena.create(MutationRecord); record.* = .{ ._arena = arena, @@ -318,7 +318,7 @@ pub fn notifyChildListChange( continue; } - const arena = try page.getArena(.{ .debug = "MutationRecord" }); + const arena = try page.getArena(.tiny, "MutationRecord"); const record = try arena.create(MutationRecord); record.* = .{ ._arena = arena, diff --git a/src/browser/webapi/Permissions.zig b/src/browser/webapi/Permissions.zig index 8a06b4f4..84ff810f 100644 --- a/src/browser/webapi/Permissions.zig +++ b/src/browser/webapi/Permissions.zig @@ -38,7 +38,7 @@ const QueryDescriptor = struct { }; // We always report 'prompt' (the default safe value — neither granted nor denied). pub fn query(_: *const Permissions, qd: QueryDescriptor, page: *Page) !js.Promise { - const arena = try page.getArena(.{ .debug = "PermissionStatus" }); + const arena = try page.getArena(.tiny, "PermissionStatus"); errdefer page.releaseArena(arena); const status = try arena.create(PermissionStatus); diff --git a/src/browser/webapi/Range.zig b/src/browser/webapi/Range.zig index 720fc5ff..dab3db89 100644 --- a/src/browser/webapi/Range.zig +++ b/src/browser/webapi/Range.zig @@ -33,7 +33,7 @@ const Range = @This(); _proto: *AbstractRange, pub fn init(page: *Page) !*Range { - const arena = try page.getArena(.{ .debug = "Range" }); + const arena = try page.getArena(.medium, "Range"); errdefer page.releaseArena(arena); return page._factory.abstractRange(arena, Range{ ._proto = undefined }, page); } @@ -312,7 +312,7 @@ pub fn intersectsNode(self: *const Range, node: *Node) bool { } pub fn cloneRange(self: *const Range, page: *Page) !*Range { - const arena = try page.getArena(.{ .debug = "Range.clone" }); + const arena = try page.getArena(.medium, "Range.clone"); errdefer page.releaseArena(arena); const clone = try page._factory.abstractRange(arena, Range{ ._proto = undefined }, page); diff --git a/src/browser/webapi/Window.zig b/src/browser/webapi/Window.zig index 418037fd..ef076663 100644 --- a/src/browser/webapi/Window.zig +++ b/src/browser/webapi/Window.zig @@ -407,7 +407,7 @@ pub fn postMessage(self: *Window, message: js.Value.Temp, target_origin: ?[]cons const target_page = self._page; const source_window = target_page.js.getIncumbent().window; - const arena = try target_page.getArena(.{ .debug = "Window.postMessage" }); + const arena = try target_page.getArena(.medium, "Window.postMessage"); errdefer target_page.releaseArena(arena); // Origin should be the source window's origin (where the message came from) @@ -645,7 +645,7 @@ fn scheduleCallback(self: *Window, cb: js.Function.Temp, delay_ms: u32, opts: Sc return error.TooManyTimeout; } - const arena = try page.getArena(.{ .debug = "Window.schedule" }); + const arena = try page.getArena(.tiny, "Window.schedule"); errdefer page.releaseArena(arena); const timer_id = self._timer_id +% 1; diff --git a/src/browser/webapi/animation/Animation.zig b/src/browser/webapi/animation/Animation.zig index 08eb21c2..4bddfd1d 100644 --- a/src/browser/webapi/animation/Animation.zig +++ b/src/browser/webapi/animation/Animation.zig @@ -52,7 +52,7 @@ _playState: PlayState = .idle, // // TODO add support for effect and timeline pub fn init(page: *Page) !*Animation { - const arena = try page.getArena(.{ .debug = "Animation" }); + const arena = try page.getArena(.tiny, "Animation"); errdefer page.releaseArena(arena); const self = try arena.create(Animation); diff --git a/src/browser/webapi/collections/ChildNodes.zig b/src/browser/webapi/collections/ChildNodes.zig index df3e7ee1..410c12b7 100644 --- a/src/browser/webapi/collections/ChildNodes.zig +++ b/src/browser/webapi/collections/ChildNodes.zig @@ -39,7 +39,7 @@ pub const ValueIterator = GenericIterator(Iterator, "1"); pub const EntryIterator = GenericIterator(Iterator, null); pub fn init(node: *Node, page: *Page) !*ChildNodes { - const arena = try page.getArena(.{ .debug = "ChildNodes" }); + const arena = try page.getArena(.small, "ChildNodes"); errdefer page.releaseArena(arena); const self = try arena.create(ChildNodes); diff --git a/src/browser/webapi/css/FontFace.zig b/src/browser/webapi/css/FontFace.zig index 075d9135..9ccb0c4c 100644 --- a/src/browser/webapi/css/FontFace.zig +++ b/src/browser/webapi/css/FontFace.zig @@ -33,7 +33,7 @@ _family: []const u8, pub fn init(family: []const u8, source: []const u8, page: *Page) !*FontFace { _ = source; - const arena = try page.getArena(.{ .debug = "FontFace" }); + const arena = try page.getArena(.tiny, "FontFace"); errdefer page.releaseArena(arena); const self = try arena.create(FontFace); diff --git a/src/browser/webapi/css/FontFaceSet.zig b/src/browser/webapi/css/FontFaceSet.zig index b20017ca..f43dc405 100644 --- a/src/browser/webapi/css/FontFaceSet.zig +++ b/src/browser/webapi/css/FontFaceSet.zig @@ -34,7 +34,7 @@ _proto: *EventTarget, _arena: Allocator, pub fn init(page: *Page) !*FontFaceSet { - const arena = try page.getArena(.{ .debug = "FontFaceSet" }); + const arena = try page.getArena(.tiny, "FontFaceSet"); errdefer page.releaseArena(arena); return page._factory.eventTargetWithAllocator(arena, FontFaceSet{ diff --git a/src/browser/webapi/element/Html.zig b/src/browser/webapi/element/Html.zig index d72b4fa8..7a33d25a 100644 --- a/src/browser/webapi/element/Html.zig +++ b/src/browser/webapi/element/Html.zig @@ -292,7 +292,7 @@ pub fn insertAdjacentHTML( }); const doc_node = doc.asNode(); - const arena = try page.getArena(.{ .debug = "HTML.insertAdjacentHTML" }); + const arena = try page.getArena(.medium, "HTML.insertAdjacentHTML"); defer page.releaseArena(arena); const Parser = @import("../../parser/Parser.zig"); diff --git a/src/browser/webapi/encoding/TextDecoder.zig b/src/browser/webapi/encoding/TextDecoder.zig index c117df09..7da889e4 100644 --- a/src/browser/webapi/encoding/TextDecoder.zig +++ b/src/browser/webapi/encoding/TextDecoder.zig @@ -48,7 +48,7 @@ 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" }); + const arena = try page.getArena(.large, "TextDecoder"); errdefer page.releaseArena(arena); const opts = opts_ orelse InitOpts{}; diff --git a/src/browser/webapi/event/CloseEvent.zig b/src/browser/webapi/event/CloseEvent.zig index aa9f1d2b..dbe5f21a 100644 --- a/src/browser/webapi/event/CloseEvent.zig +++ b/src/browser/webapi/event/CloseEvent.zig @@ -39,14 +39,14 @@ const CloseEventOptions = struct { const Options = Event.inheritOptions(CloseEvent, CloseEventOptions); pub fn init(typ: []const u8, _opts: ?Options, page: *Page) !*CloseEvent { - const arena = try page.getArena(.{ .debug = "CloseEvent" }); + const arena = try page.getArena(.tiny, "CloseEvent"); errdefer page.releaseArena(arena); const type_string = try String.init(arena, typ, .{}); return initWithTrusted(arena, type_string, _opts, false, page); } pub fn initTrusted(typ: String, _opts: ?Options, page: *Page) !*CloseEvent { - const arena = try page.getArena(.{ .debug = "CloseEvent.trusted" }); + const arena = try page.getArena(.tiny, "CloseEvent.trusted"); errdefer page.releaseArena(arena); return initWithTrusted(arena, typ, _opts, true, page); } diff --git a/src/browser/webapi/event/CompositionEvent.zig b/src/browser/webapi/event/CompositionEvent.zig index 7f3fd1d2..04077994 100644 --- a/src/browser/webapi/event/CompositionEvent.zig +++ b/src/browser/webapi/event/CompositionEvent.zig @@ -35,7 +35,7 @@ const CompositionEventOptions = struct { const Options = Event.inheritOptions(CompositionEvent, CompositionEventOptions); pub fn init(typ: []const u8, opts_: ?Options, page: *Page) !*CompositionEvent { - const arena = try page.getArena(.{ .debug = "CompositionEvent" }); + const arena = try page.getArena(.tiny, "CompositionEvent"); errdefer page.releaseArena(arena); const type_string = try String.init(arena, typ, .{}); diff --git a/src/browser/webapi/event/CustomEvent.zig b/src/browser/webapi/event/CustomEvent.zig index 9013bb4a..51efa36c 100644 --- a/src/browser/webapi/event/CustomEvent.zig +++ b/src/browser/webapi/event/CustomEvent.zig @@ -38,7 +38,7 @@ const CustomEventOptions = struct { const Options = Event.inheritOptions(CustomEvent, CustomEventOptions); pub fn init(typ: []const u8, opts_: ?Options, page: *Page) !*CustomEvent { - const arena = try page.getArena(.{ .debug = "CustomEvent" }); + const arena = try page.getArena(.tiny, "CustomEvent"); errdefer page.releaseArena(arena); const type_string = try String.init(arena, typ, .{}); diff --git a/src/browser/webapi/event/ErrorEvent.zig b/src/browser/webapi/event/ErrorEvent.zig index aef63a0e..4bb68573 100644 --- a/src/browser/webapi/event/ErrorEvent.zig +++ b/src/browser/webapi/event/ErrorEvent.zig @@ -47,14 +47,14 @@ pub const ErrorEventOptions = struct { const Options = Event.inheritOptions(ErrorEvent, ErrorEventOptions); pub fn init(typ: []const u8, opts_: ?Options, page: *Page) !*ErrorEvent { - const arena = try page.getArena(.{ .debug = "ErrorEvent" }); + const arena = try page.getArena(.small, "ErrorEvent"); errdefer page.releaseArena(arena); const type_string = try String.init(arena, typ, .{}); return initWithTrusted(arena, type_string, opts_, false, page); } pub fn initTrusted(typ: String, opts_: ?Options, page: *Page) !*ErrorEvent { - const arena = try page.getArena(.{ .debug = "ErrorEvent.trusted" }); + const arena = try page.getArena(.small, "ErrorEvent.trusted"); errdefer page.releaseArena(arena); return initWithTrusted(arena, typ, opts_, true, page); } diff --git a/src/browser/webapi/event/FocusEvent.zig b/src/browser/webapi/event/FocusEvent.zig index 776605db..59e88e36 100644 --- a/src/browser/webapi/event/FocusEvent.zig +++ b/src/browser/webapi/event/FocusEvent.zig @@ -42,13 +42,13 @@ pub const Options = Event.inheritOptions( ); pub fn initTrusted(typ: String, _opts: ?Options, page: *Page) !*FocusEvent { - const arena = try page.getArena(.{ .debug = "FocusEvent.trusted" }); + const arena = try page.getArena(.tiny, "FocusEvent.trusted"); errdefer page.releaseArena(arena); return initWithTrusted(arena, typ, _opts, true, page); } pub fn init(typ: []const u8, _opts: ?Options, page: *Page) !*FocusEvent { - const arena = try page.getArena(.{ .debug = "FocusEvent" }); + const arena = try page.getArena(.tiny, "FocusEvent"); errdefer page.releaseArena(arena); const type_string = try String.init(arena, typ, .{}); return initWithTrusted(arena, type_string, _opts, false, page); diff --git a/src/browser/webapi/event/FormDataEvent.zig b/src/browser/webapi/event/FormDataEvent.zig index 93eadfa3..ce45a9d0 100644 --- a/src/browser/webapi/event/FormDataEvent.zig +++ b/src/browser/webapi/event/FormDataEvent.zig @@ -38,14 +38,14 @@ const Options = Event.inheritOptions(FormDataEvent, struct { }); pub fn init(typ: []const u8, maybe_options: Options, page: *Page) !*FormDataEvent { - const arena = try page.getArena(.{ .debug = "FormDataEvent" }); + const arena = try page.getArena(.tiny, "FormDataEvent"); errdefer page.releaseArena(arena); const type_string = try String.init(arena, typ, .{}); return initWithTrusted(arena, type_string, maybe_options, false, page); } pub fn initTrusted(typ: String, _opts: ?Options, page: *Page) !*FormDataEvent { - const arena = try page.getArena(.{ .debug = "FormDataEvent.trusted" }); + const arena = try page.getArena(.tiny, "FormDataEvent.trusted"); errdefer page.releaseArena(arena); return initWithTrusted(arena, typ, _opts, true, page); } diff --git a/src/browser/webapi/event/InputEvent.zig b/src/browser/webapi/event/InputEvent.zig index 3b01b900..3c00debd 100644 --- a/src/browser/webapi/event/InputEvent.zig +++ b/src/browser/webapi/event/InputEvent.zig @@ -46,13 +46,13 @@ const Options = Event.inheritOptions( ); pub fn initTrusted(typ: String, _opts: ?Options, page: *Page) !*InputEvent { - const arena = try page.getArena(.{ .debug = "InputEvent.trusted" }); + const arena = try page.getArena(.tiny, "InputEvent.trusted"); errdefer page.releaseArena(arena); return initWithTrusted(arena, typ, _opts, true, page); } pub fn init(typ: []const u8, _opts: ?Options, page: *Page) !*InputEvent { - const arena = try page.getArena(.{ .debug = "InputEvent" }); + const arena = try page.getArena(.tiny, "InputEvent"); errdefer page.releaseArena(arena); const type_string = try String.init(arena, typ, .{}); return initWithTrusted(arena, type_string, _opts, false, page); diff --git a/src/browser/webapi/event/KeyboardEvent.zig b/src/browser/webapi/event/KeyboardEvent.zig index ddc7548d..f8056cc3 100644 --- a/src/browser/webapi/event/KeyboardEvent.zig +++ b/src/browser/webapi/event/KeyboardEvent.zig @@ -186,13 +186,13 @@ const Options = Event.inheritOptions( ); pub fn initTrusted(typ: String, _opts: ?Options, page: *Page) !*KeyboardEvent { - const arena = try page.getArena(.{ .debug = "KeyboardEvent.trusted" }); + const arena = try page.getArena(.tiny, "KeyboardEvent.trusted"); errdefer page.releaseArena(arena); return initWithTrusted(arena, typ, _opts, true, page); } pub fn init(typ: []const u8, _opts: ?Options, page: *Page) !*KeyboardEvent { - const arena = try page.getArena(.{ .debug = "KeyboardEvent" }); + const arena = try page.getArena(.tiny, "KeyboardEvent"); errdefer page.releaseArena(arena); const type_string = try String.init(arena, typ, .{}); return initWithTrusted(arena, type_string, _opts, false, page); diff --git a/src/browser/webapi/event/MessageEvent.zig b/src/browser/webapi/event/MessageEvent.zig index dfd813d5..27fdfb23 100644 --- a/src/browser/webapi/event/MessageEvent.zig +++ b/src/browser/webapi/event/MessageEvent.zig @@ -50,14 +50,14 @@ pub const Data = union(enum) { const Options = Event.inheritOptions(MessageEvent, MessageEventOptions); pub fn init(typ: []const u8, opts_: ?Options, page: *Page) !*MessageEvent { - const arena = try page.getArena(.{ .debug = "MessageEvent" }); + const arena = try page.getArena(.small, "MessageEvent"); errdefer page.releaseArena(arena); const type_string = try String.init(arena, typ, .{}); return initWithTrusted(arena, type_string, opts_, false, page); } pub fn initTrusted(typ: String, opts_: ?Options, page: *Page) !*MessageEvent { - const arena = try page.getArena(.{ .debug = "MessageEvent.trusted" }); + const arena = try page.getArena(.small, "MessageEvent.trusted"); errdefer page.releaseArena(arena); return initWithTrusted(arena, typ, opts_, true, page); } diff --git a/src/browser/webapi/event/MouseEvent.zig b/src/browser/webapi/event/MouseEvent.zig index 999bd010..ff2b1118 100644 --- a/src/browser/webapi/event/MouseEvent.zig +++ b/src/browser/webapi/event/MouseEvent.zig @@ -82,14 +82,14 @@ pub const Options = Event.inheritOptions( ); pub fn init(typ: []const u8, _opts: ?Options, page: *Page) !*MouseEvent { - const arena = try page.getArena(.{ .debug = "MouseEvent" }); + const arena = try page.getArena(.tiny, "MouseEvent"); errdefer page.releaseArena(arena); const type_string = try String.init(arena, typ, .{}); return initWithTrusted(arena, type_string, _opts, false, page); } pub fn initTrusted(typ: String, _opts: ?Options, page: *Page) !*MouseEvent { - const arena = try page.getArena(.{ .debug = "MouseEvent.trusted" }); + const arena = try page.getArena(.tiny, "MouseEvent.trusted"); errdefer page.releaseArena(arena); return initWithTrusted(arena, typ, _opts, true, page); } diff --git a/src/browser/webapi/event/NavigationCurrentEntryChangeEvent.zig b/src/browser/webapi/event/NavigationCurrentEntryChangeEvent.zig index 816fa1c8..d791cb39 100644 --- a/src/browser/webapi/event/NavigationCurrentEntryChangeEvent.zig +++ b/src/browser/webapi/event/NavigationCurrentEntryChangeEvent.zig @@ -45,14 +45,14 @@ const Options = Event.inheritOptions( ); pub fn init(typ: []const u8, opts: Options, page: *Page) !*NavigationCurrentEntryChangeEvent { - const arena = try page.getArena(.{ .debug = "NavigationCurrentEntryChangeEvent" }); + const arena = try page.getArena(.tiny, "NavigationCurrentEntryChangeEvent"); errdefer page.releaseArena(arena); const type_string = try String.init(arena, typ, .{}); return initWithTrusted(arena, type_string, opts, false, page); } pub fn initTrusted(typ: String, opts: Options, page: *Page) !*NavigationCurrentEntryChangeEvent { - const arena = try page.getArena(.{ .debug = "NavigationCurrentEntryChangeEvent.trusted" }); + const arena = try page.getArena(.tiny, "NavigationCurrentEntryChangeEvent.trusted"); errdefer page.releaseArena(arena); return initWithTrusted(arena, typ, opts, true, page); } diff --git a/src/browser/webapi/event/PageTransitionEvent.zig b/src/browser/webapi/event/PageTransitionEvent.zig index e11be386..335a665a 100644 --- a/src/browser/webapi/event/PageTransitionEvent.zig +++ b/src/browser/webapi/event/PageTransitionEvent.zig @@ -38,14 +38,14 @@ const PageTransitionEventOptions = struct { const Options = Event.inheritOptions(PageTransitionEvent, PageTransitionEventOptions); pub fn init(typ: []const u8, _opts: ?Options, page: *Page) !*PageTransitionEvent { - const arena = try page.getArena(.{ .debug = "PageTransitionEvent" }); + const arena = try page.getArena(.tiny, "PageTransitionEvent"); errdefer page.releaseArena(arena); const type_string = try String.init(arena, typ, .{}); return initWithTrusted(arena, type_string, _opts, false, page); } pub fn initTrusted(typ: String, _opts: ?Options, page: *Page) !*PageTransitionEvent { - const arena = try page.getArena(.{ .debug = "PageTransitionEvent.trusted" }); + const arena = try page.getArena(.tiny, "PageTransitionEvent.trusted"); errdefer page.releaseArena(arena); return initWithTrusted(arena, typ, _opts, true, page); } diff --git a/src/browser/webapi/event/PointerEvent.zig b/src/browser/webapi/event/PointerEvent.zig index c5440d45..4eb1e250 100644 --- a/src/browser/webapi/event/PointerEvent.zig +++ b/src/browser/webapi/event/PointerEvent.zig @@ -84,7 +84,7 @@ const Options = Event.inheritOptions( ); pub fn init(typ: []const u8, _opts: ?Options, page: *Page) !*PointerEvent { - const arena = try page.getArena(.{ .debug = "UIEvent" }); + const arena = try page.getArena(.tiny, "PointerEvent"); errdefer page.releaseArena(arena); const type_string = try String.init(arena, typ, .{}); diff --git a/src/browser/webapi/event/PopStateEvent.zig b/src/browser/webapi/event/PopStateEvent.zig index cd430cf8..3b0fe4e4 100644 --- a/src/browser/webapi/event/PopStateEvent.zig +++ b/src/browser/webapi/event/PopStateEvent.zig @@ -39,14 +39,14 @@ const PopStateEventOptions = struct { const Options = Event.inheritOptions(PopStateEvent, PopStateEventOptions); pub fn init(typ: []const u8, _opts: ?Options, page: *Page) !*PopStateEvent { - const arena = try page.getArena(.{ .debug = "PopStateEvent" }); + const arena = try page.getArena(.tiny, "PopStateEvent"); errdefer page.releaseArena(arena); const type_string = try String.init(arena, typ, .{}); return initWithTrusted(arena, type_string, _opts, false, page); } pub fn initTrusted(typ: String, _opts: ?Options, page: *Page) !*PopStateEvent { - const arena = try page.getArena(.{ .debug = "PopStateEvent.trusted" }); + const arena = try page.getArena(.tiny, "PopStateEvent.trusted"); errdefer page.releaseArena(arena); return initWithTrusted(arena, typ, _opts, true, page); } diff --git a/src/browser/webapi/event/ProgressEvent.zig b/src/browser/webapi/event/ProgressEvent.zig index 6498da48..895bff09 100644 --- a/src/browser/webapi/event/ProgressEvent.zig +++ b/src/browser/webapi/event/ProgressEvent.zig @@ -39,14 +39,14 @@ const ProgressEventOptions = struct { const Options = Event.inheritOptions(ProgressEvent, ProgressEventOptions); pub fn init(typ: []const u8, _opts: ?Options, page: *Page) !*ProgressEvent { - const arena = try page.getArena(.{ .debug = "ProgressEvent" }); + const arena = try page.getArena(.tiny, "ProgressEvent"); errdefer page.releaseArena(arena); const type_string = try String.init(arena, typ, .{}); return initWithTrusted(arena, type_string, _opts, false, page); } pub fn initTrusted(typ: String, _opts: ?Options, page: *Page) !*ProgressEvent { - const arena = try page.getArena(.{ .debug = "ProgressEvent.trusted" }); + const arena = try page.getArena(.tiny, "ProgressEvent.trusted"); errdefer page.releaseArena(arena); return initWithTrusted(arena, typ, _opts, true, page); } diff --git a/src/browser/webapi/event/PromiseRejectionEvent.zig b/src/browser/webapi/event/PromiseRejectionEvent.zig index cc014b39..44af3904 100644 --- a/src/browser/webapi/event/PromiseRejectionEvent.zig +++ b/src/browser/webapi/event/PromiseRejectionEvent.zig @@ -37,7 +37,7 @@ const PromiseRejectionEventOptions = struct { const Options = Event.inheritOptions(PromiseRejectionEvent, PromiseRejectionEventOptions); pub fn init(typ: []const u8, opts_: ?Options, page: *Page) !*PromiseRejectionEvent { - const arena = try page.getArena(.{ .debug = "PromiseRejectionEvent" }); + const arena = try page.getArena(.tiny, "PromiseRejectionEvent"); errdefer page.releaseArena(arena); const type_string = try String.init(arena, typ, .{}); diff --git a/src/browser/webapi/event/SubmitEvent.zig b/src/browser/webapi/event/SubmitEvent.zig index f48365dc..3400cbcd 100644 --- a/src/browser/webapi/event/SubmitEvent.zig +++ b/src/browser/webapi/event/SubmitEvent.zig @@ -39,14 +39,14 @@ const SubmitEventOptions = struct { const Options = Event.inheritOptions(SubmitEvent, SubmitEventOptions); pub fn init(typ: []const u8, opts_: ?Options, page: *Page) !*SubmitEvent { - const arena = try page.getArena(.{ .debug = "SubmitEvent" }); + const arena = try page.getArena(.tiny, "SubmitEvent"); errdefer page.releaseArena(arena); const type_string = try String.init(arena, typ, .{}); return initWithTrusted(arena, type_string, opts_, false, page); } pub fn initTrusted(typ: String, _opts: ?Options, page: *Page) !*SubmitEvent { - const arena = try page.getArena(.{ .debug = "SubmitEvent.trusted" }); + const arena = try page.getArena(.tiny, "SubmitEvent.trusted"); errdefer page.releaseArena(arena); return initWithTrusted(arena, typ, _opts, true, page); } diff --git a/src/browser/webapi/event/TextEvent.zig b/src/browser/webapi/event/TextEvent.zig index 3ddb2636..dcc5e478 100644 --- a/src/browser/webapi/event/TextEvent.zig +++ b/src/browser/webapi/event/TextEvent.zig @@ -40,7 +40,7 @@ pub const Options = Event.inheritOptions( ); pub fn init(typ: []const u8, _opts: ?Options, page: *Page) !*TextEvent { - const arena = try page.getArena(.{ .debug = "TextEvent" }); + const arena = try page.getArena(.tiny, "TextEvent"); errdefer page.releaseArena(arena); const type_string = try String.init(arena, typ, .{}); diff --git a/src/browser/webapi/event/UIEvent.zig b/src/browser/webapi/event/UIEvent.zig index 6874d6d5..2b456738 100644 --- a/src/browser/webapi/event/UIEvent.zig +++ b/src/browser/webapi/event/UIEvent.zig @@ -51,7 +51,7 @@ pub const Options = Event.inheritOptions( ); pub fn init(typ: []const u8, _opts: ?Options, page: *Page) !*UIEvent { - const arena = try page.getArena(.{ .debug = "UIEvent" }); + const arena = try page.getArena(.tiny, "UIEvent"); errdefer page.releaseArena(arena); const type_string = try String.init(arena, typ, .{}); diff --git a/src/browser/webapi/event/WheelEvent.zig b/src/browser/webapi/event/WheelEvent.zig index 4711ac25..8f79ab8a 100644 --- a/src/browser/webapi/event/WheelEvent.zig +++ b/src/browser/webapi/event/WheelEvent.zig @@ -50,7 +50,7 @@ pub const Options = Event.inheritOptions( ); pub fn init(typ: []const u8, _opts: ?Options, page: *Page) !*WheelEvent { - const arena = try page.getArena(.{ .debug = "WheelEvent" }); + const arena = try page.getArena(.medium, "WheelEvent"); errdefer page.releaseArena(arena); const type_string = try String.init(arena, typ, .{}); diff --git a/src/browser/webapi/net/Response.zig b/src/browser/webapi/net/Response.zig index e4fbd46d..7ed7ba4d 100644 --- a/src/browser/webapi/net/Response.zig +++ b/src/browser/webapi/net/Response.zig @@ -57,7 +57,7 @@ const InitOpts = struct { }; pub fn init(body_: ?[]const u8, opts_: ?InitOpts, page: *Page) !*Response { - const arena = try page.getArena(.{ .debug = "Response" }); + const arena = try page.getArena(.large, "Response"); errdefer page.releaseArena(arena); const opts = opts_ orelse InitOpts{}; @@ -174,7 +174,7 @@ pub fn bytes(self: *const Response, page: *Page) !js.Promise { } pub fn clone(self: *const Response, page: *Page) !*Response { - const arena = try page.getArena(.{ .debug = "Response.clone" }); + const arena = try page.getArena((self._body orelse "").len + self._url.len + 256, "Response.clone"); errdefer page.releaseArena(arena); const body = if (self._body) |b| try arena.dupe(u8, b) else null; diff --git a/src/browser/webapi/net/WebSocket.zig b/src/browser/webapi/net/WebSocket.zig index 1244a61e..20a622c6 100644 --- a/src/browser/webapi/net/WebSocket.zig +++ b/src/browser/webapi/net/WebSocket.zig @@ -105,7 +105,7 @@ pub fn init(url: []const u8, protocols_: ?[]const u8, page: *Page) !*WebSocket { } } - const arena = try page.getArena(.{ .debug = "WebSocket" }); + const arena = try page.getArena(.medium, "WebSocket"); errdefer page.releaseArena(arena); const resolved_url = try URL.resolve(arena, page.base(), url, .{ .always_dupe = true, .encode = true }); @@ -272,12 +272,10 @@ pub fn send(self: *WebSocket, data: SendData) !void { return error.InvalidStateError; } - // Get a dedicated arena for this message - const arena = try self._page._session.getArena(.{ .debug = "WebSocket message" }); - errdefer self._page._session.releaseArena(arena); - switch (data) { .blob => |blob| { + const arena = try self._page._session.getArena(blob._slice.len, "WebSocket.message"); + errdefer self._page._session.releaseArena(arena); try self.queueMessage(.{ .binary = .{ .arena = arena, .data = try arena.dupe(u8, blob._slice), @@ -285,15 +283,21 @@ pub fn send(self: *WebSocket, data: SendData) !void { }, .js_val => |js_val| { if (js_val.isString()) |str| { + const arena = try self._page._session.getArena(str.len(), "WebSocket.message"); + errdefer self._page._session.releaseArena(arena); try self.queueMessage(.{ .text = .{ .arena = arena, .data = try str.toSliceWithAlloc(arena), } }); } else { const binary = try js_val.toZig(BinaryData); + const buffer = binary.asBuffer(); + + const arena = try self._page._session.getArena(buffer.len, "WebSocket.message"); + errdefer self._page._session.releaseArena(arena); try self.queueMessage(.{ .binary = .{ .arena = arena, - .data = try arena.dupe(u8, binary.asBuffer()), + .data = try arena.dupe(u8, buffer), } }); } }, diff --git a/src/browser/webapi/net/XMLHttpRequest.zig b/src/browser/webapi/net/XMLHttpRequest.zig index 62e05a17..1024e1e7 100644 --- a/src/browser/webapi/net/XMLHttpRequest.zig +++ b/src/browser/webapi/net/XMLHttpRequest.zig @@ -89,7 +89,7 @@ const ResponseType = enum { }; pub fn init(page: *Page) !*XMLHttpRequest { - const arena = try page.getArena(.{ .debug = "XMLHttpRequest" }); + const arena = try page.getArena(.large, "XMLHttpRequest"); errdefer page.releaseArena(arena); const self = try page._factory.xhrEventTarget(arena, XMLHttpRequest{ ._page = page, diff --git a/src/browser/webapi/selector/Selector.zig b/src/browser/webapi/selector/Selector.zig index a3d5d894..838cecfd 100644 --- a/src/browser/webapi/selector/Selector.zig +++ b/src/browser/webapi/selector/Selector.zig @@ -45,7 +45,7 @@ pub fn querySelectorAll(root: *Node, input: []const u8, page: *Page) !*List { return error.SyntaxError; } - const arena = try page.getArena(.{ .debug = "querySelectorAll" }); + const arena = try page.getArena(.small, "querySelectorAll"); errdefer page.releaseArena(arena); var nodes: std.AutoArrayHashMapUnmanaged(*Node, void) = .empty; diff --git a/src/cdp/CDP.zig b/src/cdp/CDP.zig index 024954db..222098c8 100644 --- a/src/cdp/CDP.zig +++ b/src/cdp/CDP.zig @@ -487,10 +487,10 @@ pub const BrowserContext = struct { pub fn createIsolatedWorld(self: *BrowserContext, world_name: []const u8, grant_universal_access: bool) !*IsolatedWorld { const browser = &self.cdp.browser; - const arena = try browser.arena_pool.acquire(.{ .debug = "IsolatedWorld" }); + const arena = try browser.arena_pool.acquire(.small, "IsolatedWorld"); errdefer browser.arena_pool.release(arena); - const call_arena = try browser.arena_pool.acquire(.{ .debug = "IsolatedWorld.call_arena" }); + const call_arena = try browser.arena_pool.acquire(.tiny, "IsolatedWorld.call_arena"); errdefer browser.arena_pool.release(call_arena); const world = try arena.create(IsolatedWorld);