Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 6 additions & 9 deletions src/browser/js/Context.zig
Original file line number Diff line number Diff line change
Expand Up @@ -457,8 +457,7 @@ pub fn zigValueToJs(self: *Context, value: anytype, comptime opts: Caller.CallOp
.pointer => |ptr| switch (ptr.size) {
.one => {
if (@typeInfo(ptr.child) == .@"struct" and @hasDecl(ptr.child, "JsApi")) {
const type_name = @typeName(ptr.child.JsApi);
if (@hasField(bridge.JsApiLookup, type_name)) {
if (bridge.JsApiLookup.has(ptr.child.JsApi)) {
const js_obj = try self.mapZigInstanceToJs(null, value);
return js_obj.toValue();
}
Expand Down Expand Up @@ -499,8 +498,7 @@ pub fn zigValueToJs(self: *Context, value: anytype, comptime opts: Caller.CallOp
},
.@"struct" => |s| {
if (@hasDecl(T, "JsApi")) {
const type_name = @typeName(T.JsApi);
if (@hasField(bridge.JsApiLookup, type_name)) {
if (bridge.JsApiLookup.has(T.JsApi)) {
const js_obj = try self.mapZigInstanceToJs(null, value);
return js_obj.toValue();
}
Expand Down Expand Up @@ -707,7 +705,7 @@ pub fn jsValueToZig(self: *Context, comptime T: type, js_value: v8.Value) !T {
return error.InvalidArgument;
}
if (@hasDecl(ptr.child, "JsApi")) {
std.debug.assert(@hasField(bridge.JsApiLookup, @typeName(ptr.child.JsApi)));
std.debug.assert(bridge.JsApiLookup.has(ptr.child.JsApi));
const js_obj = js_value.castTo(v8.Object);
return typeTaggedAnyOpaque(*ptr.child, js_obj);
}
Expand Down Expand Up @@ -1537,14 +1535,13 @@ pub fn typeTaggedAnyOpaque(comptime R: type, js_obj: v8.Object) !R {
return error.InvalidArgument;
}

const type_name = @typeName(JsApi);
if (@hasField(bridge.JsApiLookup, type_name) == false) {
if (!bridge.JsApiLookup.has(JsApi)) {
@compileError("unknown Zig type: " ++ @typeName(R));
}

const op = js_obj.getInternalField(0).castTo(v8.External).get();
const tao: *TaggedAnyOpaque = @ptrCast(@alignCast(op));
const expected_type_index = @field(bridge.JS_API_LOOKUP, type_name);
const expected_type_index = bridge.JsApiLookup.getId(JsApi);

const prototype_chain = tao.prototype_chain[0..tao.prototype_len];
if (prototype_chain[0].index == expected_type_index) {
Expand Down Expand Up @@ -1643,7 +1640,7 @@ fn probeJsValueToZig(self: *Context, comptime T: type, js_value: v8.Value) !Prob
if (!js_value.isObject()) {
return .{ .invalid = {} };
}
if (@hasField(bridge.JsApiLookup, @typeName(ptr.child.JsApi))) {
if (bridge.JsApiLookup.has(ptr.child.JsApi)) {
const js_obj = js_value.castTo(v8.Object);
// There's a bit of overhead in doing this, so instead
// of having a version of typeTaggedAnyOpaque which
Expand Down
4 changes: 2 additions & 2 deletions src/browser/js/Env.zig
Original file line number Diff line number Diff line change
Expand Up @@ -335,7 +335,7 @@ fn generateConstructor(comptime JsApi: type, isolate: v8.Isolate) v8.FunctionTem
// }
// }

pub fn protoIndexLookup(comptime JsApi: type) ?u16 {
pub fn protoIndexLookup(comptime JsApi: type) ?bridge.JsApiLookup.BackingInt {
@setEvalBranchQuota(2000);
comptime {
const T = JsApi.bridge.type;
Expand All @@ -344,6 +344,6 @@ pub fn protoIndexLookup(comptime JsApi: type) ?u16 {
}
const Ptr = std.meta.fieldInfo(T, ._proto).type;
const F = @typeInfo(Ptr).pointer.child;
return @field(bridge.JS_API_LOOKUP, @typeName(F.JsApi));
return bridge.JsApiLookup.getId(F.JsApi);
}
}
2 changes: 1 addition & 1 deletion src/browser/js/ExecutionWorld.zig
Original file line number Diff line number Diff line change
Expand Up @@ -128,7 +128,7 @@ pub fn createContext(self: *ExecutionWorld, page: *Page, enter: bool, global_cal
// specific instance of the the Window.
{
const proto_type = @typeInfo(@TypeOf(page.window._proto)).pointer.child;
const proto_index = @field(bridge.JS_API_LOOKUP, @typeName(proto_type.JsApi));
const proto_index = bridge.JsApiLookup.getId(proto_type.JsApi);
js_global.inherit(templates[proto_index]);
}

Expand Down
120 changes: 67 additions & 53 deletions src/browser/js/bridge.zig
Original file line number Diff line number Diff line change
Expand Up @@ -64,20 +64,17 @@ pub fn Builder(comptime T: type) type {
pub fn prototypeChain() [prototypeChainLength(T)]js.PrototypeChainEntry {
var entries: [prototypeChainLength(T)]js.PrototypeChainEntry = undefined;

entries[0] = .{
.offset = 0,
.index = @field(JS_API_LOOKUP, @typeName(T.JsApi)),
};
entries[0] = .{ .offset = 0, .index = JsApiLookup.getId(T.JsApi) };

if (entries.len == 1) {
return entries;
}

var Prototype = T;
for (entries[1..]) |*entry| {
inline for (entries[1..]) |*entry| {
const Next = PrototypeType(Prototype).?;
entry.* = .{
.index = @field(JS_API_LOOKUP, @typeName(Next.JsApi)),
.index = JsApiLookup.getId(Next.JsApi),
.offset = @offsetOf(Prototype, "_proto"),
};
Prototype = Next;
Expand Down Expand Up @@ -394,55 +391,72 @@ pub fn Struct(comptime T: type) type {
};
}

// Imagine we have a type Cat which has a getter:
//
// fn getOwner(self: *Cat) *Owner {
// return self.owner;
// }
//
// When we execute caller.getter, we'll end up doing something like:
// const res = @call(.auto, Cat.getOwner, .{cat_instance});
//
// How do we turn `res`, which is an *Owner, into something we can return
// to v8? We need the ObjectTemplate associated with Owner. How do we
// get that? Well, we store all the ObjectTemplates in an array that's
// tied to env. So we do something like:
//
// env.templates[index_of_owner].initInstance(...);
//
// But how do we get that `index_of_owner`? `Lookup` is a struct
// that looks like:
//
// const Lookup = struct {
// comptime cat: usize = 0,
// comptime owner: usize = 1,
// ...
// }
//
// So to get the template index of `owner`, we can do:
//
// const index_id = @field(type_lookup, @typeName(@TypeOf(res));
//
pub const JsApiLookup = blk: {
var fields: [JsApis.len]std.builtin.Type.StructField = undefined;
for (JsApis, 0..) |JsApi, i| {
fields[i] = .{
.name = @typeName(JsApi),
.type = u16,
.is_comptime = true,
.alignment = @alignOf(u16),
.default_value_ptr = @ptrCast(&i),
};
pub const JsApiLookup = struct {
/// Integer type we use for `JsApiLookup` enum. Can be u8 at min.
pub const BackingInt = std.math.IntFittingRange(0, @max(std.math.maxInt(u8), JsApis.len));

/// Imagine we have a type `Cat` which has a getter:
///
/// fn get_owner(self: *Cat) *Owner {
/// return self.owner;
/// }
///
/// When we execute `caller.getter`, we'll end up doing something like:
///
/// const res = @call(.auto, Cat.get_owner, .{cat_instance});
///
/// How do we turn `res`, which is an *Owner, into something we can return
/// to v8? We need the ObjectTemplate associated with Owner. How do we
/// get that? Well, we store all the ObjectTemplates in an array that's
/// tied to env. So we do something like:
///
/// env.templates[index_of_owner].initInstance(...);
///
/// But how do we get that `index_of_owner`? `Index` is an enum
/// that looks like:
///
/// pub const Enum = enum(BackingInt) {
/// cat = 0,
/// owner = 1,
/// ...
/// }
///
/// (`BackingInt` is calculated at comptime regarding to interfaces we have)
/// So to get the template index of `owner`, simply do:
///
/// const index_id = types.getId(@TypeOf(res));
///
pub const Enum = blk: {
var fields: [JsApis.len]std.builtin.Type.EnumField = undefined;
for (JsApis, 0..) |JsApi, i| {
fields[i] = .{ .name = @typeName(JsApi), .value = i };
}

break :blk @Type(.{
.@"enum" = .{
.fields = &fields,
.tag_type = BackingInt,
.is_exhaustive = true,
.decls = &.{},
},
});
};

/// Returns a boolean indicating if a type exist in the lookup.
pub inline fn has(t: type) bool {
return @hasField(Enum, @typeName(t));
}
break :blk @Type(.{ .@"struct" = .{
.layout = .auto,
.decls = &.{},
.is_tuple = false,
.fields = &fields,
} });
};

pub const JS_API_LOOKUP = JsApiLookup{};
/// Returns the `Enum` for the given type.
pub inline fn getIndex(t: type) Enum {
return @field(Enum, @typeName(t));
}

/// Returns the ID for the given type.
pub inline fn getId(t: type) BackingInt {
return @intFromEnum(getIndex(t));
}
};

pub const SubType = enum {
@"error",
Expand Down
2 changes: 1 addition & 1 deletion src/browser/js/js.zig
Original file line number Diff line number Diff line change
Expand Up @@ -478,7 +478,7 @@ pub const TaggedAnyOpaque = struct {
};

pub const PrototypeChainEntry = struct {
index: u16,
index: bridge.JsApiLookup.BackingInt,
offset: u16, // offset to the _proto field
};

Expand Down
Loading