mirror of
https://github.com/lightpanda-io/browser.git
synced 2026-02-04 14:33:47 +00:00
Make js.Array and js.Value directly contain their v8 handles.
This commit is contained in:
@@ -6,8 +6,8 @@
|
|||||||
.minimum_zig_version = "0.15.2",
|
.minimum_zig_version = "0.15.2",
|
||||||
.dependencies = .{
|
.dependencies = .{
|
||||||
.v8 = .{
|
.v8 = .{
|
||||||
.url = "https://github.com/lightpanda-io/zig-v8-fork/archive/d6b5f89cfc7feece29359e8c848bb916e8ecfab6.tar.gz",
|
.url = "https://github.com/lightpanda-io/zig-v8-fork/archive/direct_v8.tar.gz",
|
||||||
.hash = "v8-0.0.0-xddH6_0gBABrJc5cL6-P2wGvvweTTCgWdpmClr9r-C-s",
|
.hash = "v8-0.0.0-xddH69smBABCCW8Q-9pislHtX8OolAmcuHk8QoTPx78F",
|
||||||
},
|
},
|
||||||
//.v8 = .{ .path = "../zig-v8-fork" },
|
//.v8 = .{ .path = "../zig-v8-fork" },
|
||||||
.@"boringssl-zig" = .{
|
.@"boringssl-zig" = .{
|
||||||
|
|||||||
@@ -21,18 +21,24 @@ const js = @import("js.zig");
|
|||||||
const v8 = js.v8;
|
const v8 = js.v8;
|
||||||
|
|
||||||
const Array = @This();
|
const Array = @This();
|
||||||
js_arr: v8.Array,
|
|
||||||
context: *js.Context,
|
ctx: *js.Context,
|
||||||
|
handle: *const v8.c.Array,
|
||||||
|
|
||||||
pub fn len(self: Array) usize {
|
pub fn len(self: Array) usize {
|
||||||
return @intCast(self.js_arr.length());
|
return v8.c.v8__Array__Length(self.handle);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get(self: Array, index: usize) !js.Value {
|
pub fn get(self: Array, index: u32) !js.Value {
|
||||||
const idx_key = v8.Integer.initU32(self.context.isolate, @intCast(index));
|
const ctx = self.ctx;
|
||||||
const js_obj = self.js_arr.castTo(v8.Object);
|
|
||||||
|
const idx = js.Integer.init(ctx.isolate.handle, index);
|
||||||
|
const handle = v8.c.v8__Object__Get(@ptrCast(self.handle), ctx.v8_context.handle, idx.handle) orelse {
|
||||||
|
return error.JsException;
|
||||||
|
};
|
||||||
|
|
||||||
return .{
|
return .{
|
||||||
.context = self.context,
|
.ctx = self.ctx,
|
||||||
.js_val = try js_obj.getValue(self.context.v8_context, idx_key.toValue()),
|
.handle = handle,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -86,8 +86,8 @@ identity_map: std.AutoHashMapUnmanaged(usize, PersistentObject) = .empty,
|
|||||||
// we now simply persist every time persist() is called.
|
// we now simply persist every time persist() is called.
|
||||||
js_object_list: std.ArrayListUnmanaged(PersistentObject) = .empty,
|
js_object_list: std.ArrayListUnmanaged(PersistentObject) = .empty,
|
||||||
|
|
||||||
// js_value_list tracks persisted js values.
|
// tracks Global(v8.c.Value).
|
||||||
js_value_list: std.ArrayListUnmanaged(PersistentValue) = .empty,
|
global_values: std.ArrayList(js.Global(js.Value)) = .empty,
|
||||||
|
|
||||||
// Various web APIs depend on having a persistent promise resolver. They
|
// Various web APIs depend on having a persistent promise resolver. They
|
||||||
// require for this PromiseResolver to be valid for a lifetime longer than
|
// require for this PromiseResolver to be valid for a lifetime longer than
|
||||||
@@ -165,8 +165,8 @@ pub fn deinit(self: *Context) void {
|
|||||||
p.deinit();
|
p.deinit();
|
||||||
}
|
}
|
||||||
|
|
||||||
for (self.js_value_list.items) |*p| {
|
for (self.global_values.items) |*global| {
|
||||||
p.deinit();
|
global.deinit();
|
||||||
}
|
}
|
||||||
|
|
||||||
for (self.persisted_promise_resolvers.items) |*p| {
|
for (self.persisted_promise_resolvers.items) |*p| {
|
||||||
@@ -374,12 +374,10 @@ pub fn createException(self: *const Context, e: v8.Value) js.Exception {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
// Wrap a v8.Value, largely so that we can provide a convenient
|
|
||||||
// toString function
|
|
||||||
pub fn createValue(self: *Context, value: v8.Value) js.Value {
|
pub fn createValue(self: *Context, value: v8.Value) js.Value {
|
||||||
return .{
|
return .{
|
||||||
.js_val = value,
|
.ctx = self,
|
||||||
.context = self,
|
.handle = value.handle,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -499,7 +497,7 @@ pub fn zigValueToJs(self: *Context, value: anytype, comptime opts: Caller.CallOp
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (T == js.Value) {
|
if (T == js.Value) {
|
||||||
return value.js_val;
|
return .{ .handle = value.handle };
|
||||||
}
|
}
|
||||||
|
|
||||||
if (T == js.Promise) {
|
if (T == js.Promise) {
|
||||||
@@ -837,8 +835,8 @@ fn jsValueToStruct(self: *Context, comptime T: type, js_value: v8.Value) !?T {
|
|||||||
// Caller wants an opaque js.Object. Probably a parameter
|
// Caller wants an opaque js.Object. Probably a parameter
|
||||||
// that it needs to pass back into a callback.
|
// that it needs to pass back into a callback.
|
||||||
js.Value => js.Value{
|
js.Value => js.Value{
|
||||||
.js_val = js_value,
|
.ctx = self,
|
||||||
.context = self,
|
.handle = js_value.handle,
|
||||||
},
|
},
|
||||||
// Caller wants an opaque js.Object. Probably a parameter
|
// Caller wants an opaque js.Object. Probably a parameter
|
||||||
// that it needs to pass back into a callback.
|
// that it needs to pass back into a callback.
|
||||||
|
|||||||
35
src/browser/js/Integer.zig
Normal file
35
src/browser/js/Integer.zig
Normal file
@@ -0,0 +1,35 @@
|
|||||||
|
// Copyright (C) 2023-2025 Lightpanda (Selecy SAS)
|
||||||
|
//
|
||||||
|
// Francis Bouvier <francis@lightpanda.io>
|
||||||
|
// Pierre Tachoire <pierre@lightpanda.io>
|
||||||
|
//
|
||||||
|
// This program is free software: you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU Affero General Public License as
|
||||||
|
// published by the Free Software Foundation, either version 3 of the
|
||||||
|
// License, or (at your option) any later version.
|
||||||
|
//
|
||||||
|
// This program is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
// GNU Affero General Public License for more details.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the GNU Affero General Public License
|
||||||
|
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
const std = @import("std");
|
||||||
|
const js = @import("js.zig");
|
||||||
|
|
||||||
|
const v8 = js.v8;
|
||||||
|
|
||||||
|
const Integer = @This();
|
||||||
|
|
||||||
|
handle: *const v8.c.Integer,
|
||||||
|
|
||||||
|
pub fn init(isolate: *v8.c.Isolate, value: anytype) Integer {
|
||||||
|
const handle = switch (@TypeOf(value)) {
|
||||||
|
i8, i16, i32 => v8.c.v8__Integer__New(isolate, value).?,
|
||||||
|
u8, u16, u32 => v8.c.v8__Integer__NewFromUnsigned(isolate, value).?,
|
||||||
|
else => |T| @compileError("cannot create v8::Integer from: " ++ @typeName(T)),
|
||||||
|
};
|
||||||
|
return .{ .handle = handle };
|
||||||
|
}
|
||||||
@@ -21,24 +21,25 @@ const js = @import("js.zig");
|
|||||||
|
|
||||||
const v8 = js.v8;
|
const v8 = js.v8;
|
||||||
|
|
||||||
|
const IS_DEBUG = @import("builtin").mode == .Debug;
|
||||||
|
|
||||||
const Allocator = std.mem.Allocator;
|
const Allocator = std.mem.Allocator;
|
||||||
|
|
||||||
const PersistentValue = v8.Persistent(v8.Value);
|
|
||||||
|
|
||||||
const Value = @This();
|
const Value = @This();
|
||||||
js_val: v8.Value,
|
|
||||||
context: *js.Context,
|
ctx: *js.Context,
|
||||||
|
handle: *const v8.c.Value,
|
||||||
|
|
||||||
pub fn isObject(self: Value) bool {
|
pub fn isObject(self: Value) bool {
|
||||||
return self.js_val.isObject();
|
return v8.c.v8__Value__IsObject(self.handle);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn isString(self: Value) bool {
|
pub fn isString(self: Value) bool {
|
||||||
return self.js_val.isString();
|
return v8.c.v8__Value__IsString(self.handle);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn isArray(self: Value) bool {
|
pub fn isArray(self: Value) bool {
|
||||||
return self.js_val.isArray();
|
return v8.c.v8__Value__IsArray(self.handle);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn isNull(self: Value) bool {
|
pub fn isNull(self: Value) bool {
|
||||||
@@ -50,7 +51,7 @@ pub fn isUndefined(self: Value) bool {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn toString(self: Value, allocator: Allocator) ![]const u8 {
|
pub fn toString(self: Value, allocator: Allocator) ![]const u8 {
|
||||||
return self.context.valueToString(self.js_val, .{ .allocator = allocator });
|
return self.ctx.valueToString(.{ .handle = self.handle }, .{ .allocator = allocator });
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn toBool(self: Value) bool {
|
pub fn toBool(self: Value) bool {
|
||||||
@@ -60,17 +61,19 @@ pub fn toBool(self: Value) bool {
|
|||||||
pub fn fromJson(ctx: *js.Context, json: []const u8) !Value {
|
pub fn fromJson(ctx: *js.Context, json: []const u8) !Value {
|
||||||
const json_string = v8.String.initUtf8(ctx.isolate, json);
|
const json_string = v8.String.initUtf8(ctx.isolate, json);
|
||||||
const value = try v8.Json.parse(ctx.v8_context, json_string);
|
const value = try v8.Json.parse(ctx.v8_context, json_string);
|
||||||
return Value{ .context = ctx, .js_val = value };
|
return .{ .ctx = ctx, .handle = value.handle };
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn persist(self: Value) !Value {
|
pub fn persist(self: Value) !Value {
|
||||||
const js_val = self.js_val;
|
var ctx = self.ctx;
|
||||||
var context = self.context;
|
|
||||||
|
|
||||||
const persisted = PersistentValue.init(context.isolate, js_val);
|
const global = js.Global(Value).init(ctx.isolate.handle, self);
|
||||||
try context.js_value_list.append(context.arena, persisted);
|
try ctx.global_values.append(ctx.arena, global);
|
||||||
|
|
||||||
return Value{ .context = context, .js_val = persisted.toValue() };
|
return .{
|
||||||
|
.ctx = ctx,
|
||||||
|
.handle = global.local(),
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn toZig(self: Value, comptime T: type) !T {
|
pub fn toZig(self: Value, comptime T: type) !T {
|
||||||
@@ -78,15 +81,23 @@ pub fn toZig(self: Value, comptime T: type) !T {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn toObject(self: Value) js.Object {
|
pub fn toObject(self: Value) js.Object {
|
||||||
|
if (comptime IS_DEBUG) {
|
||||||
|
std.debug.assert(self.isObject());
|
||||||
|
}
|
||||||
|
|
||||||
return .{
|
return .{
|
||||||
.context = self.context,
|
.context = self.ctx,
|
||||||
.js_obj = self.js_val.castTo(v8.Object),
|
.js_obj = .{ .handle = self.handle },
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn toArray(self: Value) js.Array {
|
pub fn toArray(self: Value) js.Array {
|
||||||
|
if (comptime IS_DEBUG) {
|
||||||
|
std.debug.assert(self.isArray());
|
||||||
|
}
|
||||||
|
|
||||||
return .{
|
return .{
|
||||||
.context = self.context,
|
.ctx = self.ctx,
|
||||||
.js_arr = self.js_val.castTo(v8.Array),
|
.handle = self.handle,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
48
src/browser/js/global.zig
Normal file
48
src/browser/js/global.zig
Normal file
@@ -0,0 +1,48 @@
|
|||||||
|
// Copyright (C) 2023-2025 Lightpanda (Selecy SAS)
|
||||||
|
//
|
||||||
|
// Francis Bouvier <francis@lightpanda.io>
|
||||||
|
// Pierre Tachoire <pierre@lightpanda.io>
|
||||||
|
//
|
||||||
|
// This program is free software: you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU Affero General Public License as
|
||||||
|
// published by the Free Software Foundation, either version 3 of the
|
||||||
|
// License, or (at your option) any later version.
|
||||||
|
//
|
||||||
|
// This program is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
// GNU Affero General Public License for more details.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the GNU Affero General Public License
|
||||||
|
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
const std = @import("std");
|
||||||
|
const js = @import("js.zig");
|
||||||
|
|
||||||
|
const v8 = js.v8;
|
||||||
|
|
||||||
|
pub fn Global(comptime T: type) type {
|
||||||
|
const H = @FieldType(T, "handle");
|
||||||
|
|
||||||
|
return struct {
|
||||||
|
global: v8.c.Global,
|
||||||
|
|
||||||
|
const Self = @This();
|
||||||
|
|
||||||
|
pub fn init(isolate: *v8.c.Isolate, data: T) Self {
|
||||||
|
var global: v8.c.Global = undefined;
|
||||||
|
v8.c.v8__Global__New(isolate, data.handle, &global);
|
||||||
|
return .{
|
||||||
|
.global = global,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn deinit(self: *Self) void {
|
||||||
|
v8.c.v8__Global__Reset(&self.global);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn local(self: *const Self) H {
|
||||||
|
return @ptrCast(@alignCast(@as(*const anyopaque, @ptrFromInt(self.global.data_ptr))));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
@@ -37,6 +37,9 @@ pub const Object = @import("Object.zig");
|
|||||||
pub const TryCatch = @import("TryCatch.zig");
|
pub const TryCatch = @import("TryCatch.zig");
|
||||||
pub const Function = @import("Function.zig");
|
pub const Function = @import("Function.zig");
|
||||||
|
|
||||||
|
pub const Integer = @import("Integer.zig");
|
||||||
|
pub const Global = @import("global.zig").Global;
|
||||||
|
|
||||||
const Allocator = std.mem.Allocator;
|
const Allocator = std.mem.Allocator;
|
||||||
|
|
||||||
pub fn Bridge(comptime T: type) type {
|
pub fn Bridge(comptime T: type) type {
|
||||||
|
|||||||
@@ -72,7 +72,7 @@ pub fn define(self: *CustomElementRegistry, name: []const u8, constructor: js.Fu
|
|||||||
if (observed_attrs.isArray()) {
|
if (observed_attrs.isArray()) {
|
||||||
var js_arr = observed_attrs.toArray();
|
var js_arr = observed_attrs.toArray();
|
||||||
for (0..js_arr.len()) |i| {
|
for (0..js_arr.len()) |i| {
|
||||||
const attr_val = js_arr.get(i) catch continue;
|
const attr_val = js_arr.get(@intCast(i)) catch continue;
|
||||||
const attr_name = attr_val.toString(page.arena) catch continue;
|
const attr_name = attr_val.toString(page.arena) catch continue;
|
||||||
const owned_attr = page.dupeString(attr_name) catch continue;
|
const owned_attr = page.dupeString(attr_name) catch continue;
|
||||||
definition.observed_attributes.put(page.arena, owned_attr, {}) catch continue;
|
definition.observed_attributes.put(page.arena, owned_attr, {}) catch continue;
|
||||||
|
|||||||
Reference in New Issue
Block a user