diff --git a/src/browser/js/Env.zig b/src/browser/js/Env.zig index 2b1f6945..7863b99b 100644 --- a/src/browser/js/Env.zig +++ b/src/browser/js/Env.zig @@ -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, }; } diff --git a/src/browser/js/ExecutionWorld.zig b/src/browser/js/ExecutionWorld.zig index efcca59f..8fe7a8dc 100644 --- a/src/browser/js/ExecutionWorld.zig +++ b/src/browser/js/ExecutionWorld.zig @@ -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 diff --git a/src/browser/js/Snapshot.zig b/src/browser/js/Snapshot.zig index 814fbf68..445e80aa 100644 --- a/src/browser/js/Snapshot.zig +++ b/src/browser/js/Snapshot.zig @@ -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);