diff --git a/.github/actions/install/action.yml b/.github/actions/install/action.yml index c59bc9a9..d0f0bb55 100644 --- a/.github/actions/install/action.yml +++ b/.github/actions/install/action.yml @@ -13,7 +13,7 @@ inputs: zig-v8: description: 'zig v8 version to install' required: false - default: 'v0.2.7' + default: 'v0.2.8' v8: description: 'v8 version to install' required: false diff --git a/Dockerfile b/Dockerfile index 48df995c..33282309 100644 --- a/Dockerfile +++ b/Dockerfile @@ -3,7 +3,7 @@ FROM debian:stable-slim ARG MINISIG=0.12 ARG ZIG_MINISIG=RWSGOq2NVecA2UPNdBUZykf1CCb147pkmdtYxgb3Ti+JO/wCYvhbAb/U ARG V8=14.0.365.4 -ARG ZIG_V8=v0.2.7 +ARG ZIG_V8=v0.2.8 ARG TARGETPLATFORM RUN apt-get update -yq && \ diff --git a/build.zig.zon b/build.zig.zon index 26ac5346..c7fbd917 100644 --- a/build.zig.zon +++ b/build.zig.zon @@ -6,8 +6,8 @@ .minimum_zig_version = "0.15.2", .dependencies = .{ .v8 = .{ - .url = "https://github.com/lightpanda-io/zig-v8-fork/archive/refs/tags/0.2.7.tar.gz", - .hash = "v8-0.0.0-xddH62VUBADeNHR3Go37RmFrODPARC-f5vjxkpJtxQsZ", + .url = "https://github.com/lightpanda-io/zig-v8-fork/archive/refs/tags/v0.2.8.tar.gz", + .hash = "v8-0.0.0-xddH63lfBADJ7UE2zAJ8nJIBnxoSiimXSaX6Q_M_7DS3", }, //.v8 = .{ .path = "../zig-v8-fork" }, .@"boringssl-zig" = .{ diff --git a/src/browser/js/Snapshot.zig b/src/browser/js/Snapshot.zig index add5e334..e38f30a2 100644 --- a/src/browser/js/Snapshot.zig +++ b/src/browser/js/Snapshot.zig @@ -455,7 +455,7 @@ fn attachClass(comptime JsApi: type, isolate: *v8.Isolate, template: *v8.Functio switch (definition) { bridge.Accessor => { const js_name = v8.v8__String__NewFromUtf8(isolate, name.ptr, v8.kNormal, @intCast(name.len)); - const getter_callback = @constCast(v8.v8__FunctionTemplate__New__DEFAULT2(isolate, value.getter).?); + const getter_callback = @constCast(v8.v8__FunctionTemplate__New__Config(isolate, &.{ .callback = value.getter }).?); if (value.setter == null) { if (value.static) { v8.v8__Template__SetAccessorProperty__DEFAULT(@ptrCast(template), js_name, getter_callback); @@ -466,12 +466,12 @@ fn attachClass(comptime JsApi: type, isolate: *v8.Isolate, template: *v8.Functio if (comptime IS_DEBUG) { std.debug.assert(value.static == false); } - const setter_callback = @constCast(v8.v8__FunctionTemplate__New__DEFAULT2(isolate, value.setter.?).?); + const setter_callback = @constCast(v8.v8__FunctionTemplate__New__Config(isolate, &.{ .callback = value.setter.? }).?); v8.v8__ObjectTemplate__SetAccessorProperty__DEFAULT2(target, js_name, getter_callback, setter_callback); } }, bridge.Function => { - const function_template = @constCast(v8.v8__FunctionTemplate__New__DEFAULT2(isolate, value.func).?); + const function_template = @constCast(v8.v8__FunctionTemplate__New__Config(isolate, &.{ .callback = value.func, .length = value.arity }).?); const js_name = v8.v8__String__NewFromUtf8(isolate, name.ptr, v8.kNormal, @intCast(name.len)); if (value.static) { v8.v8__Template__Set(@ptrCast(template), js_name, @ptrCast(function_template), v8.None); @@ -509,7 +509,7 @@ fn attachClass(comptime JsApi: type, isolate: *v8.Isolate, template: *v8.Functio has_named_index_getter = true; }, bridge.Iterator => { - const function_template = @constCast(v8.v8__FunctionTemplate__New__DEFAULT2(isolate, value.func).?); + const function_template = @constCast(v8.v8__FunctionTemplate__New__Config(isolate, &.{ .callback = value.func }).?); const js_name = if (value.async) v8.v8__Symbol__GetAsyncIterator(isolate) else @@ -518,7 +518,8 @@ fn attachClass(comptime JsApi: type, isolate: *v8.Isolate, template: *v8.Functio }, bridge.Property => { const js_value = switch (value.value) { - inline .bool, .int => |v| js.simpleZigValueToJs(.{ .handle = isolate }, v, true, false), + .null => js.simpleZigValueToJs(.{ .handle = isolate }, null, true, false), + inline .bool, .int, .float, .string => |v| js.simpleZigValueToJs(.{ .handle = isolate }, v, true, false), }; const js_name = v8.v8__String__NewFromUtf8(isolate, name.ptr, v8.kNormal, @intCast(name.len)); @@ -527,7 +528,11 @@ fn attachClass(comptime JsApi: type, isolate: *v8.Isolate, template: *v8.Functio // is like an Accessor, but because the value is known at // compile time, we skip _a lot_ of code and quickly return // the hard-coded value - const getter_callback = @constCast(v8.v8__FunctionTemplate__New__DEFAULT3(isolate, bridge.Property.getter, js_value)); + const getter_callback = @constCast(v8.v8__FunctionTemplate__New__Config(isolate, &.{ + .callback = bridge.Property.getter, + .data = js_value, + .side_effect_type = v8.kSideEffectType_HasSideEffectToReceiver, + })); v8.v8__ObjectTemplate__SetAccessorProperty__DEFAULT(target, js_name, getter_callback); } else { // apply it both to the type itself diff --git a/src/browser/js/bridge.zig b/src/browser/js/bridge.zig index a9956e8f..2b12d9a8 100644 --- a/src/browser/js/bridge.zig +++ b/src/browser/js/bridge.zig @@ -63,12 +63,23 @@ pub fn Builder(comptime T: type) type { } pub fn property(value: anytype, opts: Property.Opts) Property { - // If you add strings to this, they might need to be internalized! - return switch (@typeInfo(@TypeOf(value))) { - .bool => Property.init(.{ .bool = value }, opts), - .comptime_int, .int => Property.init(.{ .int = value }, opts), - else => @compileError("Property for " ++ @typeName(@TypeOf(value)) ++ " hasn't been defined yet"), - }; + switch (@typeInfo(@TypeOf(value))) { + .bool => return Property.init(.{ .bool = value }, opts), + .null => return Property.init(.null, opts), + .comptime_int, .int => return Property.init(.{ .int = value }, opts), + .comptime_float, .float => return Property.init(.{ .float = value }, opts), + .pointer => |ptr| switch (ptr.size) { + .one => { + const one_info = @typeInfo(ptr.child); + if (one_info == .array and one_info.array.child == u8) { + return Property.init(.{ .string = value }, opts); + } + }, + else => {}, + }, + else => {}, + } + @compileError("Property for " ++ @typeName(@TypeOf(value)) ++ " hasn't been defined yet"); } const PrototypeChainEntry = @import("TaggedOpaque.zig").PrototypeChainEntry; @@ -150,6 +161,7 @@ pub const Constructor = struct { pub const Function = struct { static: bool, + arity: usize, func: *const fn (?*const v8.FunctionCallbackInfo) callconv(.c) void, const Opts = struct { @@ -162,6 +174,7 @@ pub const Function = struct { fn init(comptime T: type, comptime func: anytype, comptime opts: Opts) Function { return .{ .static = opts.static, + .arity = getArity(@TypeOf(func)), .func = struct { fn wrap(handle: ?*const v8.FunctionCallbackInfo) callconv(.c) void { const v8_isolate = v8.v8__FunctionCallbackInfo__GetIsolate(handle).?; @@ -186,6 +199,22 @@ pub const Function = struct { }.wrap, }; } + + fn getArity(comptime T: type) usize { + var count: usize = 0; + var params = @typeInfo(T).@"fn".params; + for (params[1..]) |p| { // start at 1, skip self + const PT = p.type.?; + if (PT == *Page or PT == *const Page) { + break; + } + if (@typeInfo(PT) == .optional) { + break; + } + count += 1; + } + return count; + } }; pub const Accessor = struct { @@ -403,10 +432,12 @@ pub const Property = struct { value: Value, template: bool, - // If you add strings to this, they might need to be internalized! const Value = union(enum) { + null, int: i64, + float: f64, bool: bool, + string: []const u8, }; const Opts = struct { diff --git a/src/browser/tests/document/create_element.html b/src/browser/tests/document/create_element.html index 00f84b70..53ad7c3b 100644 --- a/src/browser/tests/document/create_element.html +++ b/src/browser/tests/document/create_element.html @@ -2,6 +2,8 @@