Move global setup to the Env (Isolate)

Previously, we were doing some global setup in the Snapshot, but this was
always being overwritten when creating a context. This meaningless setup in
the snapshot was removed.

The global setup is now done once per isolate, rather than once per context.
This commit is contained in:
Karl Seguin
2026-01-20 17:21:45 +08:00
parent fbd047599e
commit 2498e12f19
3 changed files with 33 additions and 32 deletions

View File

@@ -29,6 +29,8 @@ const Snapshot = @import("Snapshot.zig");
const Inspector = @import("Inspector.zig");
const ExecutionWorld = @import("ExecutionWorld.zig");
const Window = @import("../webapi/Window.zig");
const JsApis = bridge.JsApis;
const Allocator = std.mem.Allocator;
const ArenaAllocator = std.heap.ArenaAllocator;
@@ -59,6 +61,9 @@ eternal_function_templates: []v8.Eternal,
// Dynamic slice to avoid circular dependency on JsApis.len at comptime
templates: []*const v8.FunctionTemplate,
// Global template created once per isolate and reused across all contexts
global_template: v8.Eternal,
pub fn init(allocator: Allocator, platform: *const Platform, snapshot: *Snapshot) !Env {
var params = try allocator.create(v8.CreateParams);
errdefer allocator.destroy(params);
@@ -91,6 +96,7 @@ pub fn init(allocator: Allocator, platform: *const Platform, snapshot: *Snapshot
const templates = try allocator.alloc(*const v8.FunctionTemplate, JsApis.len);
errdefer allocator.free(templates);
var global_eternal: v8.Eternal = undefined;
{
var temp_scope: js.HandleScope = undefined;
temp_scope.init(isolate);
@@ -107,6 +113,29 @@ pub fn init(allocator: Allocator, platform: *const Platform, snapshot: *Snapshot
const eternal_ptr = v8.v8__Eternal__Get(&eternal_function_templates[i], isolate.handle);
templates[i] = @ptrCast(@alignCast(eternal_ptr.?));
}
// Create global template once per isolate
const js_global = v8.v8__FunctionTemplate__New__DEFAULT(isolate.handle);
const window_name = v8.v8__String__NewFromUtf8(isolate.handle, "Window", v8.kNormal, 6);
v8.v8__FunctionTemplate__SetClassName(js_global, window_name);
// Find Window in JsApis by name (avoids circular import)
const window_index = comptime bridge.JsApiLookup.getId(Window.JsApi);
v8.v8__FunctionTemplate__Inherit(js_global, templates[window_index]);
const global_template_local = v8.v8__FunctionTemplate__InstanceTemplate(js_global).?;
v8.v8__ObjectTemplate__SetNamedHandler(global_template_local, &.{
.getter = bridge.unknownPropertyCallback,
.setter = null,
.query = null,
.deleter = null,
.enumerator = null,
.definer = null,
.descriptor = null,
.data = null,
.flags = v8.kOnlyInterceptStrings | v8.kNonMasking,
});
v8.v8__Eternal__New(isolate.handle, @ptrCast(global_template_local), &global_eternal);
}
return .{
@@ -117,6 +146,7 @@ pub fn init(allocator: Allocator, platform: *const Platform, snapshot: *Snapshot
.templates = templates,
.isolate_params = params,
.eternal_function_templates = eternal_function_templates,
.global_template = global_eternal,
};
}

View File

@@ -80,21 +80,8 @@ pub fn createContext(self: *ExecutionWorld, page: *Page, enter: bool) !*Context
hs.init(isolate);
defer hs.deinit();
// Getting this into the snapshot is tricky (anything involving the
// global is tricky). Easier to do here
const global_template = @import("Snapshot.zig").createGlobalTemplate(isolate.handle, env.templates);
v8.v8__ObjectTemplate__SetNamedHandler(global_template, &.{
.getter = bridge.unknownPropertyCallback,
.setter = null,
.query = null,
.deleter = null,
.enumerator = null,
.definer = null,
.descriptor = null,
.data = null,
.flags = v8.kOnlyInterceptStrings | v8.kNonMasking,
});
// Get the global template that was created once per isolate
const global_template: *const v8.ObjectTemplate = @ptrCast(@alignCast(v8.v8__Eternal__Get(&env.global_template, isolate.handle).?));
const v8_context = v8.v8__Context__New(isolate.handle, global_template, null).?;
// Create the v8::Context and wrap it in a v8::Global

View File

@@ -22,7 +22,6 @@ const bridge = @import("bridge.zig");
const log = @import("../../log.zig");
const IS_DEBUG = @import("builtin").mode == .Debug;
const Window = @import("../webapi/Window.zig");
const v8 = js.v8;
const JsApis = bridge.JsApis;
@@ -114,20 +113,6 @@ fn isValid(self: Snapshot) bool {
return v8.v8__StartupData__IsValid(self.startup_data);
}
pub fn createGlobalTemplate(isolate: *v8.Isolate, templates: anytype) *const v8.ObjectTemplate {
// Set up the global template to inherit from Window's template
// This way the global object gets all Window properties through inheritance
const js_global = v8.v8__FunctionTemplate__New__DEFAULT(isolate);
const window_name = v8.v8__String__NewFromUtf8(isolate, "Window", v8.kNormal, 6);
v8.v8__FunctionTemplate__SetClassName(js_global, window_name);
// Find Window in JsApis by name (avoids circular import)
const window_index = comptime bridge.JsApiLookup.getId(Window.JsApi);
v8.v8__FunctionTemplate__Inherit(js_global, templates[window_index]);
return v8.v8__FunctionTemplate__InstanceTemplate(js_global).?;
}
pub fn create() !Snapshot {
var external_references = collectExternalReferences();
@@ -169,8 +154,7 @@ pub fn create() !Snapshot {
// Set up the global template to inherit from Window's template
// This way the global object gets all Window properties through inheritance
const global_template = createGlobalTemplate(isolate, templates[0..]);
const context = v8.v8__Context__New(isolate, global_template, null);
const context = v8.v8__Context__New(isolate, null, null);
v8.v8__Context__Enter(context);
defer v8.v8__Context__Exit(context);