From f3ab1dcf78124345db1e6affbfa9053931ec9439 Mon Sep 17 00:00:00 2001 From: Karl Seguin Date: Mon, 27 Apr 2026 17:17:50 +0800 Subject: [PATCH] Add constructor arity Depends on https://github.com/lightpanda-io/zig-v8-fork/pull/174 Builds ontop of https://github.com/lightpanda-io/browser/pull/2272 largely because it's driven by the same uievents WPT tests. https://github.com/lightpanda-io/browser/pull/1498 added the length to functions, and this does it for constructors. --- src/browser/js/Snapshot.zig | 7 ++- src/browser/js/bridge.zig | 56 +++++++++++++------ .../tests/element/html/script/script.html | 6 ++ 3 files changed, 51 insertions(+), 18 deletions(-) diff --git a/src/browser/js/Snapshot.zig b/src/browser/js/Snapshot.zig index 533d479c2..93bf9f6bf 100644 --- a/src/browser/js/Snapshot.zig +++ b/src/browser/js/Snapshot.zig @@ -569,7 +569,12 @@ pub fn generateConstructor(comptime JsApi: type, isolate: *v8.Isolate) *const v8 break :blk illegalConstructorCallback; }; - const template = v8.v8__FunctionTemplate__New__DEFAULT2(isolate, callback).?; + const arity: c_int = if (@hasDecl(JsApi, "constructor")) JsApi.constructor.arity else 0; + const template = v8.v8__FunctionTemplate__New__Config(isolate, &.{ + .length = arity, + .callback = callback, + .behavior = v8.kConstructorBehavior_Allow, + }).?; { const internal_field_count = comptime countInternalFields(JsApi); if (internal_field_count > 0) { diff --git a/src/browser/js/bridge.zig b/src/browser/js/bridge.zig index 73ddccab3..ebe96a1f2 100644 --- a/src/browser/js/bridge.zig +++ b/src/browser/js/bridge.zig @@ -107,6 +107,7 @@ pub fn Builder(comptime T: type) type { } pub const Constructor = struct { + arity: c_int, func: *const fn (?*const v8.FunctionCallbackInfo) callconv(.c) void, const Opts = struct { @@ -118,21 +119,24 @@ pub const Constructor = struct { }; fn init(comptime T: type, comptime func: anytype, comptime opts: Opts) Constructor { - return .{ .func = struct { - fn wrap(handle: ?*const v8.FunctionCallbackInfo) callconv(.c) void { - const v8_isolate = v8.v8__FunctionCallbackInfo__GetIsolate(handle).?; - var caller: Caller = undefined; - if (!caller.init(v8_isolate)) { - return; - } - defer caller.deinit(); + return .{ + .arity = comptime Function.getArity(@TypeOf(func), if (opts.new_target) 1 else 0), + .func = struct { + fn wrap(handle: ?*const v8.FunctionCallbackInfo) callconv(.c) void { + const v8_isolate = v8.v8__FunctionCallbackInfo__GetIsolate(handle).?; + var caller: Caller = undefined; + if (!caller.init(v8_isolate)) { + return; + } + defer caller.deinit(); - caller.constructor(T, func, handle.?, .{ - .dom_exception = opts.dom_exception, - .new_target = opts.new_target, - }); - } - }.wrap }; + caller.constructor(T, func, handle.?, .{ + .dom_exception = opts.dom_exception, + .new_target = opts.new_target, + }); + } + }.wrap, + }; } }; @@ -149,7 +153,7 @@ pub const Function = struct { .cache = opts.cache, .static = opts.static, .wpt_only = opts.wpt_only, - .arity = getArity(@TypeOf(func)), + .arity = getArity(@TypeOf(func), 1), .func = if (opts.noop) noopFunction else struct { fn wrap(handle: ?*const v8.FunctionCallbackInfo) callconv(.c) void { Caller.Function.call(T, handle.?, func, opts); @@ -160,14 +164,32 @@ pub const Function = struct { pub fn noopFunction(_: ?*const v8.FunctionCallbackInfo) callconv(.c) void {} - fn getArity(comptime T: type) usize { + fn getArity(comptime T: type, comptime start: usize) usize { + const Execution = js.Execution; + + const Page = @import("../Page.zig"); + const Session = @import("../Session.zig"); + var count: usize = 0; var params = @typeInfo(T).@"fn".params; - for (params[1..]) |p| { // start at 1, skip self + for (params[start..]) |p| { // start at 1, skip self const PT = p.type.?; if (PT == *Frame or PT == *const Frame) { break; } + + if (PT == *Page or PT == *const Page) { + break; + } + + if (PT == *Execution or PT == *const Execution) { + break; + } + + if (PT == *Session or PT == *const Session) { + break; + } + if (@typeInfo(PT) == .optional) { break; } diff --git a/src/browser/tests/element/html/script/script.html b/src/browser/tests/element/html/script/script.html index d49d025ac..0b7fc0f8d 100644 --- a/src/browser/tests/element/html/script/script.html +++ b/src/browser/tests/element/html/script/script.html @@ -35,5 +35,11 @@ const append = Object.getOwnPropertyDescriptor(Element.prototype, 'append'); testing.expectEqual('append', append.value.name); + + // Constructor.length should equal the number of required arguments (1 for + // events: the type). Sentinel for the New__Config wiring in Snapshot.zig. + testing.expectEqual(1, MouseEvent.length); + testing.expectEqual(1, KeyboardEvent.length); + testing.expectEqual(1, Event.length); }