Skip to content

Commit 5c23f1c

Browse files
Merge pull request #294 from karlseguin/remote_object_subtype
Add RemoteObject subtype
2 parents d27f5d2 + c65f7dd commit 5c23f1c

File tree

5 files changed

+82
-22
lines changed

5 files changed

+82
-22
lines changed

build.zig

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -182,7 +182,7 @@ pub fn packages(comptime vendor_path: []const u8) type {
182182
mod.addIncludePath(b.path(vendor ++ "/zig-v8/src"));
183183

184184
const build_opts = b.addOptions();
185-
build_opts.addOption(bool, "inspector_subtype", true);
185+
build_opts.addOption(bool, "inspector_subtype", false);
186186
mod.addOptions("default_exports", build_opts);
187187
return mod;
188188
}

src/engines/v8/generate.zig

Lines changed: 15 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ const jsToObject = @import("types_primitives.zig").jsToObject;
3434
const TPL = @import("v8.zig").TPL;
3535
const JSObject = @import("v8.zig").JSObject;
3636
const JSObjectID = @import("v8.zig").JSObjectID;
37+
const ExternalEntry = @import("v8.zig").ExternalEntry;
3738

3839
// Utils functions
3940
// ---------------
@@ -435,20 +436,17 @@ fn bindObjectNativeToJS(
435436
const pers = PersistentObject.init(isolate, js_obj);
436437
const js_obj_pers = pers.castToObject();
437438

438-
// bind the native object pointer to the JS object
439-
var ext: v8.External = undefined;
440-
if (comptime T_refl.is_mem_guarantied()) {
441-
442-
// store directly the object pointer
443-
ext = v8.External.init(isolate, nat_obj);
444-
} else {
439+
const entry = try alloc.create(ExternalEntry);
440+
entry.* = .{
441+
.ptr = nat_obj,
442+
.sub_type = T_refl.sub_type,
443+
};
445444

446-
// use the refs mechanism
447-
const int_ptr = try alloc.create(usize);
448-
int_ptr.* = @intFromPtr(nat_obj);
449-
ext = v8.External.init(isolate, int_ptr);
450-
try nat_ctx.nat_objs.put(alloc, int_ptr.*, T_refl.index);
445+
// bind the native object pointer to the JS object
446+
if (comptime T_refl.is_mem_guarantied() == false) {
447+
try nat_ctx.nat_objs.put(alloc, @intFromPtr(nat_obj), T_refl.index);
451448
}
449+
const ext = v8.External.init(isolate, entry);
452450
js_obj_pers.setInternalField(0, ext);
453451
return js_obj_pers;
454452
}
@@ -824,12 +822,14 @@ fn getNativeObject(
824822

825823
// TODO ensure the js object corresponds to the expected native type.
826824

827-
const ext = js_obj.getInternalField(0).castTo(v8.External).get().?;
825+
const external_data = js_obj.getInternalField(0).castTo(v8.External).get().?;
826+
const external_entry: *ExternalEntry = @alignCast(@ptrCast(external_data));
827+
const opaque_instance_ptr = external_entry.ptr;
828828
if (comptime T_refl.is_mem_guarantied()) {
829829
// memory is fixed
830830
// ensure the pointer is aligned (no-op at runtime)
831831
// as External is a ?*anyopaque (ie. *void) with alignment 1
832-
const ptr: *align(@alignOf(T_refl.Self())) anyopaque = @alignCast(ext);
832+
const ptr: *align(@alignOf(T_refl.Self())) anyopaque = @alignCast(opaque_instance_ptr);
833833
if (@hasDecl(T_refl.T, "protoCast")) {
834834
// T_refl provides a function to cast the pointer from high level Type
835835
obj_ptr = @call(.auto, @field(T_refl.T, "protoCast"), .{ptr});
@@ -841,7 +841,7 @@ fn getNativeObject(
841841
}
842842
} else {
843843
// use the refs mechanism to retrieve from high level Type
844-
obj_ptr = try refs.getObject(nat_ctx.nat_objs, T, gen.Types, ext);
844+
obj_ptr = try refs.getObject(nat_ctx.nat_objs, T, gen.Types, opaque_instance_ptr);
845845
}
846846
}
847847
return obj_ptr;

src/engines/v8/v8.zig

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -720,3 +720,59 @@ pub const Inspector = struct {
720720
return self.session.dispatchProtocolMessage(env.isolate, msg);
721721
}
722722
};
723+
724+
// When we return a Zig instance to V8, we wrap it in a v8.Object. That wrapping
725+
// happens by:
726+
// - Assigning our instance to a v8.External (which just holds an *anyopaque)
727+
// - Creating a v8.PersistentObject and assigning the external to the
728+
// PersistentObject's internalField #0
729+
// - Casting the v8.PersistentObject to a v8.Object
730+
//
731+
// Now, instead of assigning the instance directly into the v8.External we
732+
// allocate and assign this ExternalEntry, which allows us to hold the ptr to
733+
// the Zig instance, as well as meta data that we'll need.
734+
pub const ExternalEntry = struct {
735+
// Ptr to the Zig instance
736+
ptr: *anyopaque,
737+
738+
// When we're asked to describe an object via the Inspector, we _must_ include
739+
// the proper subtype (and description) fields in the returned JSON.
740+
// V8 will give us a Value and ask us for the subtype. Hence, we store it
741+
// here.
742+
sub_type: ?[*c]const u8,
743+
};
744+
745+
// See above for documentation for the ExternalEntry's sub_type field.
746+
pub export fn v8_inspector__Client__IMPL__valueSubtype(
747+
_: *v8.c.InspectorClientImpl,
748+
c_value: *const v8.C_Value,
749+
) callconv(.C) [*c]const u8 {
750+
const external_entry = getExternalEntry(.{ .handle = c_value }) orelse return null;
751+
return if (external_entry.sub_type) |st| st else null;
752+
}
753+
754+
pub export fn v8_inspector__Client__IMPL__descriptionForValueSubtype(
755+
_: *v8.c.InspectorClientImpl,
756+
context: *const v8.C_Context,
757+
c_value: *const v8.C_Value,
758+
) callconv(.C) [*c]const u8 {
759+
_ = context;
760+
761+
// We _must_ include a non-null description in order for the subtype value
762+
// to be included. Besides that, I don't know if the value has any meaning
763+
const external_entry = getExternalEntry(.{ .handle = c_value }) orelse return null;
764+
return if (external_entry.sub_type == null) null else "";
765+
}
766+
767+
fn getExternalEntry(value: v8.Value) ?*ExternalEntry {
768+
if (value.isObject() == false) {
769+
return null;
770+
}
771+
const obj = value.castTo(Object);
772+
if (obj.internalFieldCount() == 0) {
773+
return null;
774+
}
775+
776+
const external_data = obj.getInternalField(0).castTo(v8.External).get().?;
777+
return @alignCast(@ptrCast(external_data));
778+
}

src/reflect.zig

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -785,6 +785,7 @@ pub const Struct = struct {
785785

786786
// nested types
787787
nested: []const StructNested,
788+
sub_type: ?[*c]const u8,
788789

789790
pub fn Self(comptime self: Struct) type {
790791
comptime {
@@ -1246,6 +1247,11 @@ pub const Struct = struct {
12461247
mem_guarantied = @typeInfo(T).@"struct".layout != .auto;
12471248
}
12481249

1250+
var sub_type: ?[*c]const u8 = null;
1251+
if (@hasDecl(T, "sub_type")) {
1252+
sub_type = @field(T, "sub_type");
1253+
}
1254+
12491255
// nested types
12501256
var nested_nb: usize = 0;
12511257
// first iteration to retrieve the number of nested structs
@@ -1430,6 +1436,7 @@ pub const Struct = struct {
14301436

14311437
// nested types
14321438
.nested = &cnested,
1439+
.sub_type = sub_type,
14331440
};
14341441
}
14351442
};

src/refs.zig

Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -26,11 +26,8 @@ const refl = internal.refl;
2626
pub const Map = std.AutoHashMapUnmanaged(usize, usize);
2727

2828
pub fn getObject(map: Map, comptime T: type, comptime types: []const refl.Struct, ptr: anytype) !*T {
29-
30-
// use the object pointer (key) to retrieve the API index (value) in the map
31-
const ptr_aligned: *align(@alignOf(usize)) anyopaque = @alignCast(ptr);
32-
const key: *usize = @ptrCast(ptr_aligned);
33-
const T_index = map.get(key.*);
29+
const key: usize = @intFromPtr(ptr);
30+
const T_index = map.get(key);
3431
if (T_index == null) {
3532
return error.NullReference;
3633
}
@@ -42,7 +39,7 @@ pub fn getObject(map: Map, comptime T: type, comptime types: []const refl.Struct
4239
if (!T_refl.isEmpty()) { // stage1: condition is needed for empty structs
4340
// go through the "proto" object chain
4441
// to retrieve the good object corresponding to T
45-
const target_ptr: *T_refl.Self() = @ptrFromInt(key.*);
42+
const target_ptr: *T_refl.Self() = @ptrFromInt(key);
4643
return try getRealObject(T, target_ptr);
4744
}
4845
}

0 commit comments

Comments
 (0)