Optimize toa storage in v8 object.

We're currently using Get/SetInternalField to store our toa instance in v8. This
appears to be meant for v8 data itself, as it participates in the GC's
referencing counting. This is a bit obvious by the fact that it expects a
v8::Data, we we're able to do by wrapping our toa into a v8::External.

The Get/SetAlignedPointerFromInternalField seem specifically designed for toa,
as it takes a (void *) (thus, not requiring the external wrapper) and, from what
I understand is more efficient (presumably because the GC ignores it).

Depends on: https://github.com/lightpanda-io/zig-v8-fork/pull/149
This commit is contained in:
Karl Seguin
2026-02-13 14:12:43 +08:00
parent 5c37f04d64
commit 309f254c2c
4 changed files with 13 additions and 10 deletions

View File

@@ -78,6 +78,14 @@ pub const InitOpts = struct {
};
pub fn init(app: *App, opts: InitOpts) !Env {
if (comptime IS_DEBUG) {
comptime {
// V8 requirement for any data using SetAlignedPointerInInternalField
const a = @alignOf(@import("TaggedOpaque.zig"));
std.debug.assert(a >= 2 and a % 2 == 0);
}
}
const allocator = app.allocator;
const snapshot = &app.snapshot;

View File

@@ -364,9 +364,8 @@ pub fn getTaggedOpaque(value: *const v8.Value) ?*TaggedOpaque {
return null;
}
const external_value = v8.v8__Object__GetInternalField(value, 0).?;
const external_data = v8.v8__External__Value(external_value).?;
return @ptrCast(@alignCast(external_data));
const tao_ptr = v8.v8__Object__GetAlignedPointerFromInternalField(value, 0).?;
return @ptrCast(@alignCast(tao_ptr));
}
fn cZigStringToString(s: v8.CZigString) ?[]const u8 {

View File

@@ -181,11 +181,7 @@ pub fn mapZigInstanceToJs(self: *const Local, js_obj_handle: ?*const v8.Object,
.subtype = if (@hasDecl(JsApi.Meta, "subtype")) JsApi.Meta.subype else .node,
};
// Skip setting internal field for the global object (Window)
// Window accessors get the instance from context.page.window instead
// if (resolved.class_id != @import("../webapi/Window.zig").JsApi.Meta.class_id) {
v8.v8__Object__SetInternalField(js_obj.handle, 0, isolate.createExternal(tao));
// }
v8.v8__Object__SetAlignedPointerInInternalField(js_obj.handle, 0, tao);
} else {
// If the struct is empty, we don't need to do all
// the TOA stuff and setting the internal data.

View File

@@ -133,8 +133,8 @@ pub fn fromJS(comptime R: type, js_obj_handle: *const v8.Object) !R {
@compileError("unknown Zig type: " ++ @typeName(R));
}
const internal_field_handle = v8.v8__Object__GetInternalField(js_obj_handle, 0).?;
const tao: *TaggedOpaque = @ptrCast(@alignCast(v8.v8__External__Value(internal_field_handle)));
const tao_ptr = v8.v8__Object__GetAlignedPointerFromInternalField(js_obj_handle, 0).?;
const tao: *TaggedOpaque = @ptrCast(@alignCast(tao_ptr));
const expected_type_index = bridge.JsApiLookup.getId(JsApi);
const prototype_chain = tao.prototype_chain[0..tao.prototype_len];