Skip to content

Commit b6b5ed5

Browse files
Merge pull request #49 from lightpanda-io/remote_object
Remote object
2 parents a732711 + 7f0adcc commit b6b5ed5

File tree

3 files changed

+272
-10
lines changed

3 files changed

+272
-10
lines changed

src/binding.cpp

Lines changed: 143 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1556,6 +1556,13 @@ void v8__base__SetDcheckFunction(void (*func)(const char*, int, const char*)) {
15561556

15571557
// Utils
15581558

1559+
/// Header for Zig
1560+
/// Allocates `bytes` bytes of memory using the allocator.
1561+
/// @param allocator: A Zig std.mem.Allocator
1562+
/// @param bytes: The number of bytes to allocate
1563+
/// @returns A pointer to the allocated memory, null if allocation failed
1564+
char* zigAlloc(const void* allocator, uint64_t bytes);
1565+
15591566
static inline v8_inspector::StringView toStringView(const char *str, size_t length) {
15601567
auto* stringView = reinterpret_cast<const uint8_t*>(str);
15611568
return { stringView, length };
@@ -1575,6 +1582,21 @@ static inline std::string fromStringView(v8::Isolate* isolate, const v8_inspecto
15751582
return *result;
15761583
}
15771584

1585+
/// Allocates a string as utf8 on the heap, such that it can be returned to Zig.
1586+
/// @param str: The string to return
1587+
/// @param allocator: A Zig std.mem.Allocator
1588+
/// @returns string pointer with null terminator, null if allocation failed
1589+
const char* toHeapCharPtr(const v8_inspector::String16& str, const void* allocator) {
1590+
std::string utf8_str = str.utf8(); // Note the data*'s lifetime is tied to utf8_str and this may hold the string data on the stack as an SSO, so we need to copy it onto the heap.
1591+
char* heap_str = zigAlloc(allocator, utf8_str.length() + 1); // +1 for null terminator, needed to communicate the length to Zig
1592+
if (heap_str == nullptr) {
1593+
return nullptr;
1594+
}
1595+
strcpy(heap_str, utf8_str.c_str());
1596+
return heap_str;
1597+
}
1598+
1599+
15781600
// Inspector
15791601

15801602
v8_inspector::V8Inspector *v8_inspector__Inspector__Create(
@@ -1635,21 +1657,139 @@ void v8_inspector__Session__dispatchProtocolMessage(
16351657
session->dispatchProtocolMessage(str_view);
16361658
}
16371659

1638-
v8_inspector::protocol::Runtime::API::RemoteObject* v8_inspector__Session__wrapObject(
1660+
v8_inspector::protocol::Runtime::RemoteObject* v8_inspector__Session__wrapObject(
16391661
v8_inspector::V8InspectorSession *session, v8::Isolate *isolate,
16401662
const v8::Context* ctx, const v8::Value* val,
16411663
const char *grpname, int grpname_len, bool generatepreview) {
16421664
auto sv_grpname = toStringView(grpname, grpname_len);
16431665
auto remote_object = session->wrapObject(ptr_to_local(ctx), ptr_to_local(val), sv_grpname, generatepreview);
1644-
return remote_object.release();
1666+
return static_cast<v8_inspector::protocol::Runtime::RemoteObject*>(remote_object.release());
16451667
}
16461668

16471669
// RemoteObject
16481670

1649-
void v8_inspector__RemoteObject__DELETE(v8_inspector::protocol::Runtime::API::RemoteObject* self) {
1671+
// To prevent extra allocations on every call a single default value is reused everytime.
1672+
// It is expected that the precense of a value is checked before calling get* methods.
1673+
const v8_inspector::String16 DEFAULT_STRING = {"default"};
1674+
1675+
void v8_inspector__RemoteObject__DELETE(v8_inspector::protocol::Runtime::RemoteObject* self) {
16501676
delete self;
16511677
}
16521678

1679+
// RemoteObject - Type
1680+
const char* v8_inspector__RemoteObject__getType(v8_inspector::protocol::Runtime::RemoteObject* self, const void* allocator) {
1681+
auto str = self->getType();
1682+
return toHeapCharPtr(str, allocator);
1683+
}
1684+
void v8_inspector__RemoteObject__setType(v8_inspector::protocol::Runtime::RemoteObject* self, const char* type, int type_len) {
1685+
self->setType(v8_inspector::String16::fromUTF8(type, type_len));
1686+
}
1687+
1688+
// RemoteObject - Subtype
1689+
bool v8_inspector__RemoteObject__hasSubtype(v8_inspector::protocol::Runtime::RemoteObject* self) {
1690+
return self->hasSubtype();
1691+
}
1692+
const char* v8_inspector__RemoteObject__getSubtype(v8_inspector::protocol::Runtime::RemoteObject* self, const void* allocator) {
1693+
auto str = self->getSubtype(DEFAULT_STRING);
1694+
return toHeapCharPtr(str, allocator);
1695+
}
1696+
void v8_inspector__RemoteObject__setSubtype(v8_inspector::protocol::Runtime::RemoteObject* self, const char* subtype, int subtype_len) {
1697+
self->setSubtype(v8_inspector::String16::fromUTF8(subtype, subtype_len));
1698+
}
1699+
1700+
// RemoteObject - ClassName
1701+
bool v8_inspector__RemoteObject__hasClassName(v8_inspector::protocol::Runtime::RemoteObject* self) {
1702+
return self->hasClassName();
1703+
}
1704+
const char* v8_inspector__RemoteObject__getClassName(v8_inspector::protocol::Runtime::RemoteObject* self, const void* allocator) {
1705+
auto str = self->getClassName(DEFAULT_STRING);
1706+
return toHeapCharPtr(str, allocator);
1707+
}
1708+
void v8_inspector__RemoteObject__setClassName(v8_inspector::protocol::Runtime::RemoteObject* self, const char* className, int className_len) {
1709+
self->setClassName(v8_inspector::String16::fromUTF8(className, className_len));
1710+
}
1711+
1712+
// RemoteObject - Value
1713+
bool v8_inspector__RemoteObject__hasValue(v8_inspector::protocol::Runtime::RemoteObject* self) {
1714+
return self->hasValue();
1715+
}
1716+
v8_inspector::protocol::Value* v8_inspector__RemoteObject__getValue(v8_inspector::protocol::Runtime::RemoteObject* self) {
1717+
return self->getValue(nullptr);
1718+
}
1719+
void v8_inspector__RemoteObject__setValue(v8_inspector::protocol::Runtime::RemoteObject* self, v8_inspector::protocol::Value* value) {
1720+
self->setValue(std::unique_ptr<v8_inspector::protocol::Value>(value));
1721+
}
1722+
1723+
//RemoteObject - UnserializableValue
1724+
bool v8_inspector__RemoteObject__hasUnserializableValue(v8_inspector::protocol::Runtime::RemoteObject* self) {
1725+
return self->hasUnserializableValue();
1726+
}
1727+
const char* v8_inspector__RemoteObject__getUnserializableValue(v8_inspector::protocol::Runtime::RemoteObject* self, const void* allocator) {
1728+
auto str = self->getUnserializableValue(DEFAULT_STRING);
1729+
return toHeapCharPtr(str, allocator);
1730+
}
1731+
void v8_inspector__RemoteObject__setUnserializableValue(v8_inspector::protocol::Runtime::RemoteObject* self, const char* unserializableValue, int unserializableValue_len) {
1732+
self->setUnserializableValue(v8_inspector::String16::fromUTF8(unserializableValue, unserializableValue_len));
1733+
}
1734+
1735+
// RemoteObject - Description
1736+
bool v8_inspector__RemoteObject__hasDescription(v8_inspector::protocol::Runtime::RemoteObject* self) {
1737+
return self->hasDescription();
1738+
}
1739+
const char* v8_inspector__RemoteObject__getDescription(v8_inspector::protocol::Runtime::RemoteObject* self, const void* allocator) {
1740+
auto str = self->getDescription(DEFAULT_STRING);
1741+
return toHeapCharPtr(str, allocator);
1742+
}
1743+
void v8_inspector__RemoteObject__setDescription(v8_inspector::protocol::Runtime::RemoteObject* self, const char* description, int description_len) {
1744+
self->setDescription(v8_inspector::String16::fromUTF8(description, description_len));
1745+
}
1746+
1747+
// RemoteObject - WebDriverValue
1748+
bool v8_inspector__RemoteObject__hasWebDriverValue(v8_inspector::protocol::Runtime::RemoteObject* self) {
1749+
return self->hasWebDriverValue();
1750+
}
1751+
v8_inspector::protocol::Runtime::WebDriverValue* v8_inspector__RemoteObject__getWebDriverValue(v8_inspector::protocol::Runtime::RemoteObject* self) {
1752+
return self->getWebDriverValue(nullptr);
1753+
}
1754+
void v8_inspector__RemoteObject__setWebDriverValue(v8_inspector::protocol::Runtime::RemoteObject* self, v8_inspector::protocol::Runtime::WebDriverValue* webDriverValue) {
1755+
self->setWebDriverValue(std::unique_ptr<v8_inspector::protocol::Runtime::WebDriverValue>(webDriverValue));
1756+
}
1757+
1758+
// RemoteObject - ObjectId
1759+
bool v8_inspector__RemoteObject__hasObjectId(v8_inspector::protocol::Runtime::RemoteObject* self) {
1760+
return self->hasObjectId();
1761+
}
1762+
1763+
const char* v8_inspector__RemoteObject__getObjectId(v8_inspector::protocol::Runtime::RemoteObject* self, const void* allocator) {
1764+
auto str = self->getObjectId(DEFAULT_STRING);
1765+
return toHeapCharPtr(str, allocator);
1766+
}
1767+
void v8_inspector__RemoteObject__setObjectId(v8_inspector::protocol::Runtime::RemoteObject* self, const char* objectId, int objectId_len) {
1768+
self->setObjectId(v8_inspector::String16::fromUTF8(objectId, objectId_len));
1769+
}
1770+
1771+
// RemoteObject - Preview
1772+
bool v8_inspector__RemoteObject__hasPreview(v8_inspector::protocol::Runtime::RemoteObject* self) {
1773+
return self->hasPreview();
1774+
}
1775+
const v8_inspector::protocol::Runtime::ObjectPreview* v8_inspector__RemoteObject__getPreview(v8_inspector::protocol::Runtime::RemoteObject* self) {
1776+
return self->getPreview(nullptr);
1777+
}
1778+
void v8_inspector__RemoteObject__setPreview(v8_inspector::protocol::Runtime::RemoteObject* self, v8_inspector::protocol::Runtime::ObjectPreview* preview) {
1779+
self->setPreview(std::unique_ptr<v8_inspector::protocol::Runtime::ObjectPreview>(preview));
1780+
}
1781+
1782+
// RemoteObject - CustomPreview
1783+
bool v8_inspector__RemoteObject__hasCustomPreview(v8_inspector::protocol::Runtime::RemoteObject* self) {
1784+
return self->hasCustomPreview();
1785+
}
1786+
const v8_inspector::protocol::Runtime::CustomPreview* v8_inspector__RemoteObject__getCustomPreview(v8_inspector::protocol::Runtime::RemoteObject* self) {
1787+
return self->getCustomPreview(nullptr);
1788+
}
1789+
void v8_inspector__RemoteObject__setCustomPreview(v8_inspector::protocol::Runtime::RemoteObject* self, v8_inspector::protocol::Runtime::CustomPreview* customPreview) {
1790+
self->setCustomPreview(std::unique_ptr<v8_inspector::protocol::Runtime::CustomPreview>(customPreview));
1791+
}
1792+
16531793
// InspectorChannel
16541794

16551795
v8_inspector__Channel__IMPL * v8_inspector__Channel__IMPL__CREATE(v8::Isolate *isolate) {

src/binding.h

Lines changed: 57 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1018,6 +1018,9 @@ char* v8_inspector__Client__IMPL__descriptionForValueSubtype(
10181018

10191019
// RemoteObject
10201020
typedef struct RemoteObject RemoteObject;
1021+
typedef struct WebDriverValue WebDriverValue;
1022+
typedef struct ObjectPreview ObjectPreview;
1023+
typedef struct CustomPreview CustomPreview;
10211024

10221025
// InspectorSession
10231026

@@ -1027,7 +1030,7 @@ void v8_inspector__Session__dispatchProtocolMessage(InspectorSession *session, I
10271030
RemoteObject* v8_inspector__Session__wrapObject(
10281031
InspectorSession *session, Isolate *isolate,
10291032
const Context* ctx, const Value* val,
1030-
const char *grpname, int grpname_len, bool generatepreview);
1033+
const char *grpname, usize grpname_len, bool generatepreview);
10311034

10321035
// Inspector
10331036
typedef struct Inspector Inspector;
@@ -1044,3 +1047,56 @@ void v8_inspector__Inspector__ContextCreated(Inspector *self, const char *name,
10441047
const char *auxData, const usize auxData_len,
10451048
int contextGroupId,
10461049
const Context* context);
1050+
1051+
// RemoteObject
1052+
void v8_inspector__RemoteObject__DELETE(RemoteObject *self);
1053+
1054+
// RemoteObject - Type
1055+
const char* v8_inspector__RemoteObject__getType(RemoteObject* self, const void* allocator);
1056+
void v8_inspector__RemoteObject__setType(RemoteObject* self, const char* type, int type_len);
1057+
1058+
// RemoteObject - Subtype
1059+
bool v8_inspector__RemoteObject__hasSubtype(RemoteObject* self);
1060+
const char* v8_inspector__RemoteObject__getSubtype(RemoteObject* self, const void* allocator);
1061+
void v8_inspector__RemoteObject__setSubtype(RemoteObject* self, const char* subtype, int subtype_len);
1062+
1063+
// RemoteObject - ClassName
1064+
bool v8_inspector__RemoteObject__hasClassName(RemoteObject* self);
1065+
const char* v8_inspector__RemoteObject__getClassName(RemoteObject* self, const void* allocator);
1066+
void v8_inspector__RemoteObject__setClassName(RemoteObject* self, const char* className, int className_len);
1067+
1068+
// RemoteObject - Value
1069+
bool v8_inspector__RemoteObject__hasValue(RemoteObject* self);
1070+
// Commented as these for now as the type should likely be the existing Value TBD
1071+
// v8_inspector::protocol::Value* v8_inspector__RemoteObject__getValue(Rem;eObject* self);
1072+
// void v8_inspector__RemoteObject__setValue(RemoteObject* self, v8_inspector::protocol::Value* value);
1073+
1074+
//RemoteObject - UnserializableValue
1075+
bool v8_inspector__RemoteObject__hasUnserializableValue(RemoteObject* self);
1076+
const char* v8_inspector__RemoteObject__getUnserializableValue(RemoteObject* self, const void* allocator);
1077+
void v8_inspector__RemoteObject__setUnserializableValue(RemoteObject* self, const char* unserializableValue, int unserializableValue_len);
1078+
1079+
// RemoteObject - Description
1080+
bool v8_inspector__RemoteObject__hasDescription(RemoteObject* self);
1081+
const char* v8_inspector__RemoteObject__getDescription(RemoteObject* self, const void* allocator);
1082+
void v8_inspector__RemoteObject__setDescription(RemoteObject* self, const char* description, int description_len);
1083+
1084+
// RemoteObject - WebDriverValue
1085+
bool v8_inspector__RemoteObject__hasWebDriverValue(RemoteObject* self);
1086+
WebDriverValue* v8_inspector__RemoteObject__getWebDriverValue(RemoteObject* self);
1087+
void v8_inspector__RemoteObject__setWebDriverValue(RemoteObject* self, WebDriverValue* webDriverValue);
1088+
1089+
// RemoteObject - ObjectId
1090+
bool v8_inspector__RemoteObject__hasObjectId(RemoteObject* self);
1091+
const char* v8_inspector__RemoteObject__getObjectId(RemoteObject* self, const void* allocator);
1092+
void v8_inspector__RemoteObject__setObjectId(RemoteObject* self, const char* objectId, int objectId_len);
1093+
1094+
// RemoteObject - Preview
1095+
bool v8_inspector__RemoteObject__hasPreview(RemoteObject* self);
1096+
const ObjectPreview* v8_inspector__RemoteObject__getPreview(RemoteObject* self);
1097+
void v8_inspector__RemoteObject__setPreview(RemoteObject* self, ObjectPreview* preview);
1098+
1099+
// RemoteObject - CustomPreview
1100+
bool v8_inspector__RemoteObject__hasCustomPreview(RemoteObject* self);
1101+
const CustomPreview* v8_inspector__RemoteObject__getCustomPreview(RemoteObject* self);
1102+
void v8_inspector__RemoteObject__setCustomPreview(RemoteObject* self, CustomPreview* customPreview);

src/v8.zig

Lines changed: 72 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2704,25 +2704,91 @@ pub const InspectorSession = struct {
27042704
}
27052705

27062706
pub fn wrapObject(self: InspectorSession, isolate: Isolate, ctx: Context, val: Value, grpname: []const u8, generatepreview: bool) !RemoteObject {
2707-
const remote_obj = c.v8_inspector__Session__wrapObject(
2707+
const remote_object = c.v8_inspector__Session__wrapObject(
27082708
self.handle,
27092709
isolate.handle,
27102710
ctx.handle,
27112711
val.handle,
27122712
grpname.ptr,
27132713
grpname.len,
27142714
generatepreview,
2715-
);
2716-
if (remote_obj) {
2717-
return RemoteObject{ .handle = remote_obj };
2718-
} else return error.JsException;
2715+
).?;
2716+
return RemoteObject{ .handle = remote_object };
27192717
}
27202718
};
27212719

2720+
/// Note: Some getters return owned memory (strings), while others return memory owned by V8 (objects).
2721+
/// The getters short-circuit if the default values is not available as converting the defaults to V8 causes unnecessary overhead.
2722+
///
2723+
/// https://chromedevtools.github.io/devtools-protocol/tot/Runtime/#type-RemoteObject
27222724
pub const RemoteObject = struct {
27232725
handle: *c.RemoteObject,
27242726

2725-
pub fn deinit(self: *RemoteObject) void {
2727+
pub fn deinit(self: RemoteObject) void {
27262728
c.v8_inspector__RemoteObject__DELETE(self.handle);
27272729
}
2730+
2731+
pub fn getType(self: RemoteObject, allocator: std.mem.Allocator) ![:0]const u8 {
2732+
const type_ = c.v8_inspector__RemoteObject__getType(self.handle, &allocator);
2733+
if (type_ == null) {
2734+
return error.V8AllocFailed;
2735+
}
2736+
const idx = std.mem.indexOfSentinel(u8, 0, type_);
2737+
return type_[0..idx :0];
2738+
}
2739+
pub fn getSubtype(self: RemoteObject, allocator: std.mem.Allocator) !?[:0]const u8 {
2740+
if (!c.v8_inspector__RemoteObject__hasSubtype(self.handle)) {
2741+
return null;
2742+
}
2743+
2744+
const subtype = c.v8_inspector__RemoteObject__getSubtype(self.handle, &allocator);
2745+
if (subtype == null) {
2746+
return error.V8AllocFailed;
2747+
}
2748+
const idx = std.mem.indexOfSentinel(u8, 0, subtype);
2749+
return subtype[0..idx :0];
2750+
}
2751+
pub fn getClassName(self: RemoteObject, allocator: std.mem.Allocator) !?[:0]const u8 {
2752+
if (!c.v8_inspector__RemoteObject__hasClassName(self.handle)) {
2753+
return null;
2754+
}
2755+
2756+
const class_name = c.v8_inspector__RemoteObject__getClassName(self.handle, &allocator);
2757+
if (class_name == null) {
2758+
return error.V8AllocFailed;
2759+
}
2760+
const idx = std.mem.indexOfSentinel(u8, 0, class_name);
2761+
return class_name[0..idx :0];
2762+
}
2763+
pub fn getDescription(self: RemoteObject, allocator: std.mem.Allocator) !?[:0]const u8 {
2764+
if (!c.v8_inspector__RemoteObject__hasDescription(self.handle)) {
2765+
return null;
2766+
}
2767+
2768+
const description = c.v8_inspector__RemoteObject__getDescription(self.handle, &allocator);
2769+
if (description == null) {
2770+
return error.V8AllocFailed;
2771+
}
2772+
const idx = std.mem.indexOfSentinel(u8, 0, description);
2773+
return description[0..idx :0];
2774+
}
2775+
pub fn getObjectId(self: RemoteObject, allocator: std.mem.Allocator) !?[:0]const u8 {
2776+
if (!c.v8_inspector__RemoteObject__hasObjectId(self.handle)) {
2777+
return null;
2778+
}
2779+
2780+
const object_id = c.v8_inspector__RemoteObject__getObjectId(self.handle, &allocator);
2781+
if (object_id == null) {
2782+
return error.V8AllocFailed;
2783+
}
2784+
const idx = std.mem.indexOfSentinel(u8, 0, object_id);
2785+
return object_id[0..idx :0];
2786+
}
27282787
};
2788+
2789+
/// Enables C to allocate using the given Zig allocator
2790+
pub export fn zigAlloc(self: *anyopaque, bytes: usize) callconv(.C) ?[*]u8 {
2791+
const allocator: *std.mem.Allocator = @ptrCast(@alignCast(self));
2792+
const allocated_bytes = allocator.alloc(u8, bytes) catch return null;
2793+
return allocated_bytes.ptr;
2794+
}

0 commit comments

Comments
 (0)