Skip to content

Commit 0a120e5

Browse files
v8 Inspector support
Signed-off-by: Francis Bouvier <[email protected]>
1 parent 0c61a85 commit 0a120e5

File tree

4 files changed

+568
-0
lines changed

4 files changed

+568
-0
lines changed

src/binding.cpp

Lines changed: 217 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,12 @@
22

33
#include <cassert>
44
#include "include/libplatform/libplatform.h"
5+
#include "include/v8-inspector.h"
56
#include "include/v8.h"
67
#include "src/api/api.h"
78

9+
#include "inspector.h"
10+
811
template <class T, class... Args>
912
class Wrapper {
1013
public:
@@ -1501,4 +1504,218 @@ void v8__base__SetDcheckFunction(void (*func)(const char*, int, const char*)) {
15011504
v8::base::SetDcheckFunction(func);
15021505
}
15031506

1507+
// Inspector
1508+
// ---------
1509+
1510+
// v8 inspector is not really documented and not easy.
1511+
// Sources:
1512+
// - https://v8.dev/docs/inspector
1513+
// - C++ doc https://v8.github.io/api/head/namespacev8__inspector.html
1514+
// - Rusty (Deno) bindings https://github.com/denoland/rusty_v8/blob/main/src/binding.cc
1515+
// - https://github.com/ahmadov/v8_inspector_example
1516+
// - https://web.archive.org/web/20210918052901/http://hyperandroid.com/2020/02/12/v8-inspector-from-an-embedder-standpoint
1517+
1518+
// Utils
1519+
1520+
static inline v8_inspector::StringView toStringView(const std::string &str) {
1521+
auto* stringView = reinterpret_cast<const uint8_t*>(str.c_str());
1522+
return { stringView, str.length() };
1523+
}
1524+
1525+
static inline std::string fromStringView(v8::Isolate* isolate, const v8_inspector::StringView stringView) {
1526+
int length = static_cast<int>(stringView.length());
1527+
v8::Local<v8::String> message = (
1528+
stringView.is8Bit()
1529+
? v8::String::NewFromOneByte(isolate, reinterpret_cast<const uint8_t*>(stringView.characters8()), v8::NewStringType::kNormal, length)
1530+
: v8::String::NewFromTwoByte(isolate, reinterpret_cast<const uint16_t*>(stringView.characters16()), v8::NewStringType::kNormal, length)
1531+
).ToLocalChecked();
1532+
v8::String::Utf8Value result(isolate, message);
1533+
return *result;
1534+
}
1535+
1536+
// Inspector
1537+
1538+
v8_inspector::V8Inspector *v8_inspector__Inspector__Create(
1539+
v8::Isolate* isolate, v8_inspector__Client__IMPL *client) {
1540+
std::unique_ptr<v8_inspector::V8Inspector> u =
1541+
v8_inspector::V8Inspector::create(isolate, client);
1542+
return u.release();
1543+
}
1544+
void v8_inspector__Inspector__DELETE(v8_inspector::V8Inspector* self) {
1545+
delete self;
1546+
}
1547+
v8_inspector::V8InspectorSession *v8_inspector__Inspector__Connect(
1548+
v8_inspector::V8Inspector *self, int contextGroupId,
1549+
v8_inspector__Channel__IMPL *channel,
1550+
v8_inspector::V8Inspector::ClientTrustLevel client_trust_level) {
1551+
auto state = v8_inspector::StringView();
1552+
std::unique_ptr<v8_inspector::V8InspectorSession> u =
1553+
self->connect(contextGroupId, channel, state, client_trust_level);
1554+
return u.release();
1555+
}
1556+
void v8_inspector__Inspector__ContextCreated(v8_inspector::V8Inspector *self,
1557+
int contextGroupId,
1558+
const v8::Context &ctx) {
1559+
v8_inspector::StringView ctxView(toStringView("inspector"));
1560+
auto context = ptr_to_local(&ctx);
1561+
v8_inspector::V8ContextInfo info(context, contextGroupId, ctxView);
1562+
self->contextCreated(info);
1563+
}
1564+
1565+
// InspectorSession
1566+
1567+
void v8_inspector__Session__dispatchProtocolMessage(
1568+
v8_inspector::V8InspectorSession *session, v8::Isolate *isolate,
1569+
const char *msg, int msg_len) {
1570+
std::string message;
1571+
message.assign(msg, msg_len);
1572+
auto str_view = toStringView(message);
1573+
session->dispatchProtocolMessage(str_view);
1574+
}
1575+
1576+
// InspectorChannel
1577+
1578+
v8_inspector__Channel__IMPL * v8_inspector__Channel__IMPL__CREATE(v8::Isolate *isolate) {
1579+
auto channel = new v8_inspector__Channel__IMPL();
1580+
channel->isolate = isolate;
1581+
return channel;
1582+
}
1583+
void v8_inspector__Channel__IMPL__DELETE(v8_inspector__Channel__IMPL *self) {
1584+
delete self;
15041585
}
1586+
void v8_inspector__Channel__IMPL__SET_DATA(v8_inspector__Channel__IMPL *self, void *data) {
1587+
self->data = data;
1588+
}
1589+
1590+
// declaration of functions implementations
1591+
// NOTE: zig project should provide those implementations with C-ABI functions
1592+
void v8_inspector__Channel__IMPL__sendResponse(
1593+
v8_inspector__Channel__IMPL* self, void* data,
1594+
int callId, const char* message, size_t length);
1595+
void v8_inspector__Channel__IMPL__sendNotification(
1596+
v8_inspector__Channel__IMPL* self, void *data,
1597+
const char* msg, size_t length);
1598+
void v8_inspector__Channel__IMPL__flushProtocolNotifications(
1599+
v8_inspector__Channel__IMPL* self, void *data);
1600+
1601+
// c++ implementation (just wrappers around the C/zig functions)
1602+
} // extern "C"
1603+
void v8_inspector__Channel__IMPL::sendResponse(
1604+
int callId, std::unique_ptr<v8_inspector::StringBuffer> message) {
1605+
const std::string resp = fromStringView(this->isolate, message->string());
1606+
return v8_inspector__Channel__IMPL__sendResponse(this, this->data, callId, resp.c_str(), resp.length());
1607+
}
1608+
void v8_inspector__Channel__IMPL::sendNotification(
1609+
std::unique_ptr<v8_inspector::StringBuffer> message) {
1610+
const std::string notif = fromStringView(this->isolate, message->string());
1611+
return v8_inspector__Channel__IMPL__sendNotification(this, this->data, notif.c_str(), notif.length());
1612+
}
1613+
void v8_inspector__Channel__IMPL::flushProtocolNotifications() {
1614+
return v8_inspector__Channel__IMPL__flushProtocolNotifications(this, this->data);
1615+
}
1616+
1617+
extern "C" {
1618+
1619+
// wrappers for the public API Interface
1620+
// NOTE: not sure it's useful to expose those
1621+
void v8_inspector__Channel__sendResponse(
1622+
v8_inspector::V8Inspector::Channel* self, int callId,
1623+
v8_inspector::StringBuffer* message) {
1624+
self->sendResponse(
1625+
callId,
1626+
static_cast<std::unique_ptr<v8_inspector::StringBuffer>>(message));
1627+
}
1628+
void v8_inspector__Channel__sendNotification(
1629+
v8_inspector::V8Inspector::Channel* self,
1630+
v8_inspector::StringBuffer* message) {
1631+
self->sendNotification(
1632+
static_cast<std::unique_ptr<v8_inspector::StringBuffer>>(message));
1633+
}
1634+
void v8_inspector__Channel__flushProtocolNotifications(
1635+
v8_inspector::V8Inspector::Channel* self) {
1636+
self->flushProtocolNotifications();
1637+
}
1638+
1639+
// InspectorClient
1640+
1641+
v8_inspector__Client__IMPL *v8_inspector__Client__IMPL__CREATE() {
1642+
return new v8_inspector__Client__IMPL();
1643+
}
1644+
void v8_inspector__Client__IMPL__DELETE(v8_inspector__Client__IMPL *self) {
1645+
delete self;
1646+
}
1647+
void v8_inspector__Client__IMPL__SET_DATA(v8_inspector__Client__IMPL *self, void *data) {
1648+
self->data = data;
1649+
}
1650+
1651+
// declaration of functions implementations
1652+
// NOTE: zig project should provide those implementations with C-like functions
1653+
int64_t v8_inspector__Client__IMPL__generateUniqueId(v8_inspector__Client__IMPL* self, void* data);
1654+
void v8_inspector__Client__IMPL__runMessageLoopOnPause(
1655+
v8_inspector__Client__IMPL *self,
1656+
void* data, int contextGroupId);
1657+
void v8_inspector__Client__IMPL__quitMessageLoopOnPause(v8_inspector__Client__IMPL* self, void* data);
1658+
void v8_inspector__Client__IMPL__runIfWaitingForDebugger(
1659+
v8_inspector__Client__IMPL* self, void* data, int contextGroupId);
1660+
void v8_inspector__Client__IMPL__consoleAPIMessage(
1661+
v8_inspector__Client__IMPL* self, void* data, int contextGroupId,
1662+
v8::Isolate::MessageErrorLevel level,
1663+
const v8_inspector::StringView &message,
1664+
const v8_inspector::StringView &url, unsigned lineNumber,
1665+
unsigned columnNumber, v8_inspector::V8StackTrace *stackTrace);
1666+
1667+
// c++ implementation (just wrappers around the c/zig functions)
1668+
} // extern "C"
1669+
int64_t v8_inspector__Client__IMPL::generateUniqueId() {
1670+
return v8_inspector__Client__IMPL__generateUniqueId(this, this->data);
1671+
}
1672+
void v8_inspector__Client__IMPL::runMessageLoopOnPause(int contextGroupId) {
1673+
return v8_inspector__Client__IMPL__runMessageLoopOnPause(this, this->data, contextGroupId);
1674+
}
1675+
void v8_inspector__Client__IMPL::quitMessageLoopOnPause() {
1676+
return v8_inspector__Client__IMPL__quitMessageLoopOnPause(this, this->data);
1677+
}
1678+
void v8_inspector__Client__IMPL::runIfWaitingForDebugger(int contextGroupId) {
1679+
return v8_inspector__Client__IMPL__runIfWaitingForDebugger(this, this->data, contextGroupId);
1680+
}
1681+
void v8_inspector__Client__IMPL::consoleAPIMessage(
1682+
int contextGroupId, v8::Isolate::MessageErrorLevel level,
1683+
const v8_inspector::StringView &message,
1684+
const v8_inspector::StringView &url, unsigned lineNumber,
1685+
unsigned columnNumber, v8_inspector::V8StackTrace *stackTrace) {
1686+
return v8_inspector__Client__IMPL__consoleAPIMessage(
1687+
this, this->data, contextGroupId, level, message, url, lineNumber,
1688+
columnNumber, stackTrace);
1689+
}
1690+
1691+
extern "C" {
1692+
1693+
// wrappers for the public API Interface
1694+
// NOTE: not sure it's useful to expose those
1695+
int64_t v8_inspector__Client__generateUniqueId(
1696+
v8_inspector::V8InspectorClient *self) {
1697+
return self->generateUniqueId();
1698+
}
1699+
void v8_inspector__Client__runMessageLoopOnPause(
1700+
v8_inspector::V8InspectorClient* self, int contextGroupId) {
1701+
self->runMessageLoopOnPause(contextGroupId);
1702+
}
1703+
void v8_inspector__Client__quitMessageLoopOnPause(
1704+
v8_inspector::V8InspectorClient* self) {
1705+
self->quitMessageLoopOnPause();
1706+
}
1707+
void v8_inspector__Client__runIfWaitingForDebugger(
1708+
v8_inspector::V8InspectorClient* self, int contextGroupId) {
1709+
self->runIfWaitingForDebugger(contextGroupId);
1710+
}
1711+
void v8_inspector__Client__consoleAPIMessage(
1712+
v8_inspector::V8InspectorClient* self, int contextGroupId,
1713+
v8::Isolate::MessageErrorLevel level,
1714+
const v8_inspector::StringView& message,
1715+
const v8_inspector::StringView& url, unsigned lineNumber,
1716+
unsigned columnNumber, v8_inspector::V8StackTrace* stackTrace) {
1717+
self->consoleAPIMessage(contextGroupId, level, message, url, lineNumber,
1718+
columnNumber, stackTrace);
1719+
}
1720+
1721+
} // extern "C"

src/binding.h

Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -895,3 +895,73 @@ const String* v8__JSON__Stringify(
895895

896896
// Misc.
897897
void v8__base__SetDcheckFunction(void (*func)(const char*, int, const char*));
898+
899+
// Inspector
900+
// ---------
901+
902+
typedef enum ClientTrustLevel {
903+
kUntrusted,
904+
kFullyTrusted,
905+
} ClientTrustLevel;
906+
907+
typedef struct StringView StringView;
908+
909+
// InspectorChannel
910+
911+
typedef struct InspectorChannel InspectorChannel;
912+
typedef struct InspectorChannelImpl {
913+
void* data;
914+
} InspectorChannelImpl;
915+
InspectorChannelImpl *v8_inspector__Channel__IMPL__CREATE(Isolate *isolate);
916+
void v8_inspector__Channel__IMPL__DELETE(InspectorChannelImpl *self);
917+
void v8_inspector__Channel__IMPL__SET_DATA(InspectorChannelImpl* self, void *data);
918+
919+
void v8_inspector__Channel__IMPL__sendResponse(
920+
InspectorChannelImpl *self, void *data,
921+
int callId, char *message, size_t length);
922+
void v8_inspector__Channel__IMPL__sendNotification(
923+
InspectorChannelImpl *self, void *data,
924+
char *message, size_t length);
925+
void v8_inspector__Channel__IMPL__flushProtocolNotifications(
926+
InspectorChannelImpl *self, void *data);
927+
928+
// InspectorClient
929+
930+
typedef struct InspectorClient InspectorClient;
931+
typedef struct InspectorClientImpl {
932+
void* data;
933+
} InspectorClientImpl;
934+
InspectorClientImpl *v8_inspector__Client__IMPL__CREATE();
935+
void v8_inspector__Client__IMPL__DELETE(InspectorClientImpl *self);
936+
void v8_inspector__Client__IMPL__SET_DATA(InspectorClientImpl* self, void *data);
937+
938+
int64_t v8_inspector__Client__IMPL__generateUniqueId(InspectorClientImpl *self);
939+
void v8_inspector__Client__IMPL__runMessageLoopOnPause(
940+
InspectorClientImpl *self, int contextGroupId);
941+
void v8_inspector__Client__IMPL__quitMessageLoopOnPause(
942+
InspectorClientImpl *self);
943+
void v8_inspector__Client__IMPL__runIfWaitingForDebugger(
944+
InspectorClientImpl *self, int contextGroupId);
945+
void v8_inspector__Client__IMPL__consoleAPIMessage(
946+
InspectorClientImpl *self, int contextGroupId, MessageErrorLevel level,
947+
StringView *message, StringView *url, unsigned lineNumber,
948+
unsigned columnNumber, StackTrace *StackTrace);
949+
950+
// InspectorSession
951+
952+
typedef struct InspectorSession InspectorSession;
953+
void v8_inspector__Session__dispatchProtocolMessage(InspectorSession *session, Isolate *isolate, const char* msg, usize msg_len);
954+
955+
// Inspector
956+
typedef struct Inspector Inspector;
957+
Inspector* v8_inspector__Inspector__Create(Isolate* isolate, InspectorClientImpl* client);
958+
void v8_inspector__Inspector__DELETE(Inspector *self);
959+
960+
InspectorSession* v8_inspector__Inspector__Connect(
961+
Inspector *self, int contextGroupId,
962+
InspectorChannelImpl *channel,
963+
ClientTrustLevel level);
964+
void v8_inspector__Inspector__ContextCreated(
965+
Inspector *self,
966+
int contextGroupId,
967+
const Context* context);

src/inspector.h

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
#include "include/v8-inspector.h"
2+
3+
#ifndef V8INSPECTORIMPL_H
4+
#define V8INSPECTORIMPLH
5+
6+
// InspectorChannel Implementation
7+
struct v8_inspector__Channel__IMPL
8+
: public v8_inspector::V8Inspector::Channel {
9+
using v8_inspector::V8Inspector::Channel::Channel;
10+
11+
public:
12+
v8::Isolate *isolate;
13+
void *data;
14+
15+
private:
16+
void sendResponse(int callId,
17+
std::unique_ptr<v8_inspector::StringBuffer> message) override;
18+
void sendNotification(std::unique_ptr<v8_inspector::StringBuffer> message) override;
19+
void flushProtocolNotifications() override;
20+
};
21+
22+
// InspectorClient Implementation
23+
class v8_inspector__Client__IMPL
24+
: public v8_inspector::V8InspectorClient {
25+
using v8_inspector::V8InspectorClient::V8InspectorClient;
26+
27+
public:
28+
void *data;
29+
30+
private:
31+
int64_t generateUniqueId() override;
32+
void runMessageLoopOnPause(int contextGroupId) override;
33+
void quitMessageLoopOnPause() override;
34+
void runIfWaitingForDebugger(int contextGroupId) override;
35+
void consoleAPIMessage(int contextGroupId,
36+
v8::Isolate::MessageErrorLevel level,
37+
const v8_inspector::StringView& message,
38+
const v8_inspector::StringView& url,
39+
unsigned lineNumber, unsigned columnNumber,
40+
v8_inspector::V8StackTrace* stackTrace) override;
41+
};
42+
43+
#endif // V8INSPECTORIMPL_H

0 commit comments

Comments
 (0)