mirror of
https://github.com/lightpanda-io/browser.git
synced 2025-10-29 07:03:29 +00:00
Change TypeLookup values from simple index (usize) to a TypeMeta
TypeMeta constains the index and the subtype. This allows retrieving the subtype based on the actual value being bound, as opposed to the struct type. (I.e. it returns the correct subtype when a Zig class is a proxy for another using the Self declaration). Internally store the subtype as an enum. Reduces @sizeOf(TaggedAnyOpaque) from 32 to 16. Finally, sub_type renamed to subtype for consistency with v8.
This commit is contained in:
@@ -36,7 +36,7 @@ pub const HTMLDocument = struct {
|
||||
pub const Self = parser.DocumentHTML;
|
||||
pub const prototype = *Document;
|
||||
|
||||
pub const sub_type = "node";
|
||||
pub const subtype = "node";
|
||||
|
||||
// JS funcs
|
||||
// --------
|
||||
|
||||
@@ -20,6 +20,8 @@ const std = @import("std");
|
||||
const builtin = @import("builtin");
|
||||
const v8 = @import("v8");
|
||||
|
||||
const SubType = @import("subtype.zig").SubType;
|
||||
|
||||
const Allocator = std.mem.Allocator;
|
||||
const ArenaAllocator = std.heap.ArenaAllocator;
|
||||
|
||||
@@ -72,14 +74,14 @@ pub fn Env(comptime S: type, comptime types: anytype) type {
|
||||
// that looks like:
|
||||
//
|
||||
// const TypeLookup = struct {
|
||||
// comptime cat: usize = 0,
|
||||
// comptime owner: usize = 1,
|
||||
// comptime cat: usize = TypeMeta{.index = 0, ...},
|
||||
// comptime owner: usize = TypeMeta{.index = 1, ...},
|
||||
// ...
|
||||
// }
|
||||
//
|
||||
// So to get the template index of `owner`, we can do:
|
||||
//
|
||||
// const index_id = @field(type_lookup, @typeName(@TypeOf(res));
|
||||
// const index_id = @field(type_lookup, @typeName(@TypeOf(res)).index;
|
||||
//
|
||||
const TypeLookup = comptime blk: {
|
||||
var fields: [Types.len]std.builtin.Type.StructField = undefined;
|
||||
@@ -94,13 +96,16 @@ pub fn Env(comptime S: type, comptime types: anytype) type {
|
||||
@compileError(std.fmt.comptimePrint("Prototype '{s}' for type '{s} must be a pointer", .{ @typeName(Struct.prototype), @typeName(Struct) }));
|
||||
}
|
||||
|
||||
const subtype: ?SubType =
|
||||
if (@hasDecl(Struct, "subtype")) std.meta.stringToEnum(SubType, Struct.subtype) else null;
|
||||
|
||||
const R = Receiver(@field(types, s.name));
|
||||
fields[i] = .{
|
||||
.name = @typeName(R),
|
||||
.type = usize,
|
||||
.type = TypeMeta,
|
||||
.is_comptime = true,
|
||||
.alignment = @alignOf(usize),
|
||||
.default_value_ptr = @ptrCast(&i),
|
||||
.default_value_ptr = &TypeMeta{ .index = i, .subtype = subtype },
|
||||
};
|
||||
}
|
||||
break :blk @Type(.{ .@"struct" = .{
|
||||
@@ -135,7 +140,7 @@ pub fn Env(comptime S: type, comptime types: anytype) type {
|
||||
if (@hasDecl(Struct, "prototype")) {
|
||||
const TI = @typeInfo(Struct.prototype);
|
||||
const proto_name = @typeName(Receiver(TI.pointer.child));
|
||||
prototype_index = @field(TYPE_LOOKUP, proto_name);
|
||||
prototype_index = @field(TYPE_LOOKUP, proto_name).index;
|
||||
}
|
||||
table[i] = prototype_index;
|
||||
}
|
||||
@@ -158,7 +163,7 @@ pub fn Env(comptime S: type, comptime types: anytype) type {
|
||||
// access to its TunctionTemplate (the thing we need to create an instance
|
||||
// of it)
|
||||
// I.e.:
|
||||
// const index = @field(TYPE_LOOKUP, @typeName(type_name))
|
||||
// const index = @field(TYPE_LOOKUP, @typeName(type_name)).index
|
||||
// const template = templates[index];
|
||||
templates: [Types.len]v8.FunctionTemplate,
|
||||
|
||||
@@ -214,7 +219,7 @@ pub fn Env(comptime S: type, comptime types: anytype) type {
|
||||
// Populate our templates lookup. generateClass creates the
|
||||
// v8.FunctionTemplate, which we store in our env.templates.
|
||||
// The ordering doesn't matter. What matters is that, given a type
|
||||
// we can get its index via: @field(TYPE_LOOKUP, type_name)
|
||||
// we can get its index via: @field(TYPE_LOOKUP, type_name).index
|
||||
const templates = &env.templates;
|
||||
inline for (Types, 0..) |s, i| {
|
||||
templates[i] = env.generateClass(@field(types, s.name));
|
||||
@@ -234,7 +239,7 @@ pub fn Env(comptime S: type, comptime types: anytype) type {
|
||||
// Just like we said above, given a type, we can get its
|
||||
// template index.
|
||||
|
||||
const proto_index = @field(TYPE_LOOKUP, proto_name);
|
||||
const proto_index = @field(TYPE_LOOKUP, proto_name).index;
|
||||
templates[i].inherit(templates[proto_index]);
|
||||
}
|
||||
}
|
||||
@@ -288,7 +293,7 @@ pub fn Env(comptime S: type, comptime types: anytype) type {
|
||||
if (@hasDecl(Global, "prototype")) {
|
||||
const proto_type = Receiver(@typeInfo(Global.prototype).pointer.child);
|
||||
const proto_name = @typeName(proto_type);
|
||||
const proto_index = @field(TYPE_LOOKUP, proto_name);
|
||||
const proto_index = @field(TYPE_LOOKUP, proto_name).index;
|
||||
globals.inherit(templates[proto_index]);
|
||||
}
|
||||
|
||||
@@ -309,7 +314,7 @@ pub fn Env(comptime S: type, comptime types: anytype) type {
|
||||
@compileError("Type '" ++ @typeName(Struct) ++ "' defines an unknown prototype: " ++ proto_name);
|
||||
}
|
||||
|
||||
const proto_index = @field(TYPE_LOOKUP, proto_name);
|
||||
const proto_index = @field(TYPE_LOOKUP, proto_name).index;
|
||||
const proto_obj = templates[proto_index].getFunction(context).toObject();
|
||||
|
||||
const self_obj = templates[i].getFunction(context).toObject();
|
||||
@@ -640,7 +645,7 @@ pub fn Env(comptime S: type, comptime types: anytype) type {
|
||||
.one => {
|
||||
const type_name = @typeName(ptr.child);
|
||||
if (@hasField(TypeLookup, type_name)) {
|
||||
const template = templates[@field(TYPE_LOOKUP, type_name)];
|
||||
const template = templates[@field(TYPE_LOOKUP, type_name).index];
|
||||
const js_obj = try Executor.mapZigInstanceToJs(context, template, value);
|
||||
return js_obj.toValue();
|
||||
}
|
||||
@@ -676,7 +681,7 @@ pub fn Env(comptime S: type, comptime types: anytype) type {
|
||||
.@"struct" => |s| {
|
||||
const type_name = @typeName(T);
|
||||
if (@hasField(TypeLookup, type_name)) {
|
||||
const template = templates[@field(TYPE_LOOKUP, type_name)];
|
||||
const template = templates[@field(TYPE_LOOKUP, type_name).index];
|
||||
const js_obj = try Executor.mapZigInstanceToJs(context, template, value);
|
||||
return js_obj.toValue();
|
||||
}
|
||||
@@ -960,10 +965,11 @@ pub fn Env(comptime S: type, comptime types: anytype) type {
|
||||
// well as any meta data we'll need to use it later.
|
||||
// See the TaggedAnyOpaque struct for more details.
|
||||
const tao = try scope_arena.create(TaggedAnyOpaque);
|
||||
const meta = @field(TYPE_LOOKUP, @typeName(ptr.child));
|
||||
tao.* = .{
|
||||
.ptr = value,
|
||||
.index = @field(TYPE_LOOKUP, @typeName(ptr.child)),
|
||||
.sub_type = if (@hasDecl(ptr.child, "sub_type")) ptr.child.sub_type else null,
|
||||
.index = meta.index,
|
||||
.subtype = meta.subtype,
|
||||
.offset = if (@typeInfo(ptr.child) != .@"opaque" and @hasField(ptr.child, "proto")) @offsetOf(ptr.child, "proto") else -1,
|
||||
};
|
||||
|
||||
@@ -1345,7 +1351,7 @@ pub fn Env(comptime S: type, comptime types: anytype) type {
|
||||
|
||||
const op = js_obj.getInternalField(0).castTo(v8.External).get();
|
||||
const toa: *TaggedAnyOpaque = @alignCast(@ptrCast(op));
|
||||
const expected_type_index = @field(TYPE_LOOKUP, type_name);
|
||||
const expected_type_index = @field(TYPE_LOOKUP, type_name).index;
|
||||
|
||||
var type_index = toa.index;
|
||||
if (type_index == expected_type_index) {
|
||||
@@ -1379,6 +1385,26 @@ pub fn Env(comptime S: type, comptime types: anytype) type {
|
||||
};
|
||||
}
|
||||
|
||||
// We'll create a struct with all the types we want to bind to JavaScript. The
|
||||
// fields for this struct will be the type names. The values, will be an
|
||||
// instance of this struct.
|
||||
// const TypeLookup = struct {
|
||||
// comptime cat: usize = TypeMeta{.index = 0, subtype = null},
|
||||
// comptime owner: usize = TypeMeta{.index = 1, subtype = .array}.
|
||||
// ...
|
||||
// }
|
||||
// This is essentially meta data for each type.
|
||||
const TypeMeta = struct {
|
||||
// Every type is given a unique index. That index is used to lookup various
|
||||
// things, i.e. the prototype chain.
|
||||
index: usize,
|
||||
|
||||
// We store the type's subtype here, so that when we create an instance of
|
||||
// the type, and bind it to JavaScript, we can store the subtype along with
|
||||
// the created TaggedAnyOpaque.s
|
||||
subtype: ?SubType,
|
||||
};
|
||||
|
||||
fn isEmpty(comptime T: type) bool {
|
||||
return @typeInfo(T) != .@"opaque" and @sizeOf(T) == 0;
|
||||
}
|
||||
@@ -2204,7 +2230,7 @@ const TaggedAnyOpaque = struct {
|
||||
// V8 will give us a Value and ask us for the subtype. From the v8.Value we
|
||||
// can get a v8.Object, and from the v8.Object, we can get out TaggedAnyOpaque
|
||||
// which is where we store the subtype.
|
||||
sub_type: ?[*c]const u8,
|
||||
subtype: ?SubType,
|
||||
};
|
||||
|
||||
fn valueToString(allocator: Allocator, value: v8.Value, isolate: v8.Isolate, context: v8.Context) ![]u8 {
|
||||
@@ -2263,7 +2289,7 @@ pub export fn v8_inspector__Client__IMPL__valueSubtype(
|
||||
c_value: *const v8.C_Value,
|
||||
) callconv(.C) [*c]const u8 {
|
||||
const external_entry = getTaggedAnyOpaque(.{ .handle = c_value }) orelse return null;
|
||||
return if (external_entry.sub_type) |st| st else null;
|
||||
return if (external_entry.subtype) |st| @tagName(st) else null;
|
||||
}
|
||||
|
||||
// Same as valueSubType above, but for the optional description field.
|
||||
@@ -2280,7 +2306,7 @@ pub export fn v8_inspector__Client__IMPL__descriptionForValueSubtype(
|
||||
// We _must_ include a non-null description in order for the subtype value
|
||||
// to be included. Besides that, I don't know if the value has any meaning
|
||||
const external_entry = getTaggedAnyOpaque(.{ .handle = c_value }) orelse return null;
|
||||
return if (external_entry.sub_type == null) null else "";
|
||||
return if (external_entry.subtype == null) null else "";
|
||||
}
|
||||
|
||||
fn getTaggedAnyOpaque(value: v8.Value) ?*TaggedAnyOpaque {
|
||||
|
||||
20
src/runtime/subtype.zig
Normal file
20
src/runtime/subtype.zig
Normal file
@@ -0,0 +1,20 @@
|
||||
pub const SubType = enum {
|
||||
@"error",
|
||||
array,
|
||||
arraybuffer,
|
||||
dataview,
|
||||
date,
|
||||
generator,
|
||||
iterator,
|
||||
map,
|
||||
node,
|
||||
promise,
|
||||
proxy,
|
||||
regexp,
|
||||
set,
|
||||
typedarray,
|
||||
wasmvalue,
|
||||
weakmap,
|
||||
weakset,
|
||||
webassemblymemory,
|
||||
};
|
||||
Reference in New Issue
Block a user