From 16dfad08957933ce379cf3a1efafd0abfb8300f4 Mon Sep 17 00:00:00 2001 From: Karl Seguin Date: Wed, 11 Mar 2026 21:55:58 +0800 Subject: [PATCH] Use origin.arena for values that are tied to the origin Of note, the TAO and identity map entry has to use the origin arena, not the context arena, as those can outlive the context. --- src/browser/js/Context.zig | 1 + src/browser/js/Env.zig | 2 +- src/browser/js/Local.zig | 8 ++++---- src/browser/js/Origin.zig | 13 +++++++++++++ src/browser/js/String.zig | 2 +- 5 files changed, 20 insertions(+), 6 deletions(-) diff --git a/src/browser/js/Context.zig b/src/browser/js/Context.zig index 787527b6..5c58c5cb 100644 --- a/src/browser/js/Context.zig +++ b/src/browser/js/Context.zig @@ -171,6 +171,7 @@ pub fn setOrigin(self: *Context, key: ?[]const u8) !void { errdefer self.session.releaseOrigin(origin); try self.origin.transferTo(origin); + lp.assert(self.origin.rc == 1, "Ref opaque origin", .{ .rc = self.origin.rc }); self.origin.deinit(env.app); self.origin = origin; diff --git a/src/browser/js/Env.zig b/src/browser/js/Env.zig index e8488541..ba2e3e5a 100644 --- a/src/browser/js/Env.zig +++ b/src/browser/js/Env.zig @@ -326,7 +326,7 @@ pub fn createContext(self: *Env, page: *Page) !*Context { .script_manager = &page._script_manager, .scheduler = .init(context_arena), }; - try context.origin.identity_map.putNoClobber(context_arena, @intFromPtr(page.window), global_global); + try context.origin.identity_map.putNoClobber(origin.arena, @intFromPtr(page.window), global_global); // Store a pointer to our context inside the v8 context so that, given // a v8 context, we can get our context out diff --git a/src/browser/js/Local.zig b/src/browser/js/Local.zig index ee2ca5cd..a45b35df 100644 --- a/src/browser/js/Local.zig +++ b/src/browser/js/Local.zig @@ -202,20 +202,20 @@ pub fn compileAndRun(self: *const Local, src: []const u8, name: ?[]const u8) !js // we can just grab it from the identity_map) pub fn mapZigInstanceToJs(self: *const Local, js_obj_handle: ?*const v8.Object, value: anytype) !js.Object { const ctx = self.ctx; - const arena = ctx.arena; + const origin_arena = ctx.origin.arena; const T = @TypeOf(value); switch (@typeInfo(T)) { .@"struct" => { // Struct, has to be placed on the heap - const heap = try arena.create(T); + const heap = try origin_arena.create(T); heap.* = value; return self.mapZigInstanceToJs(js_obj_handle, heap); }, .pointer => |ptr| { const resolved = resolveValue(value); - const gop = try ctx.origin.identity_map.getOrPut(arena, @intFromPtr(resolved.ptr)); + const gop = try ctx.origin.addIdentity(@intFromPtr(resolved.ptr)); if (gop.found_existing) { // we've seen this instance before, return the same object return (js.Object.Global{ .handle = gop.value_ptr.* }).local(self); @@ -244,7 +244,7 @@ pub fn mapZigInstanceToJs(self: *const Local, js_obj_handle: ?*const v8.Object, // The TAO contains the pointer to our Zig instance as // well as any meta data we'll need to use it later. // See the TaggedOpaque struct for more details. - const tao = try arena.create(TaggedOpaque); + const tao = try origin_arena.create(TaggedOpaque); tao.* = .{ .value = resolved.ptr, .prototype_chain = resolved.prototype_chain.ptr, diff --git a/src/browser/js/Origin.zig b/src/browser/js/Origin.zig index 486888f1..d7e74e4f 100644 --- a/src/browser/js/Origin.zig +++ b/src/browser/js/Origin.zig @@ -129,6 +129,19 @@ pub fn trackGlobal(self: *Origin, global: v8.Global) !void { return self.globals.append(self.arena, global); } +pub const IdentityResult = struct { + value_ptr: *v8.Global, + found_existing: bool, +}; + +pub fn addIdentity(self: *Origin, ptr: usize) !IdentityResult { + const gop = try self.identity_map.getOrPut(self.arena, ptr); + return .{ + .value_ptr = gop.value_ptr, + .found_existing = gop.found_existing, + }; +} + pub fn trackTemp(self: *Origin, global: v8.Global) !void { return self.temps.put(self.arena, global.data_ptr, global); } diff --git a/src/browser/js/String.zig b/src/browser/js/String.zig index 04eda642..47be227a 100644 --- a/src/browser/js/String.zig +++ b/src/browser/js/String.zig @@ -56,7 +56,7 @@ fn _toSlice(self: String, comptime null_terminate: bool, allocator: Allocator) ! pub fn toSSO(self: String, comptime global: bool) !(if (global) SSO.Global else SSO) { if (comptime global) { - return .{ .str = try self.toSSOWithAlloc(self.local.ctx.arena) }; + return .{ .str = try self.toSSOWithAlloc(self.local.ctx.origin.arena) }; } return self.toSSOWithAlloc(self.local.call_arena); }