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.
This commit is contained in:
Karl Seguin committed 2026-04-28 08:54:48 +08:00
1 parent ae8013f967
commit f3ab1dcf78
3 files changed
+51 -18

No files matched your search

+6 -1
View File
@@ -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) {
+39 -17
View File
@@ -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;
}
@@ -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);
}
</script>