我想编写一些与V8相关的C绑定,因此需要弄清各种基本JavaScript类型的内存布局。是否有关于这些细节的文档?
我想编写一些与V8相关的C绑定,因此需要弄清各种基本JavaScript类型的内存布局。是否有关于这些细节的文档?
o
中获取属性foo
在C++中看起来像这样:v8::Handle<v8::Object> o;
v8::Handle<v8::Object> v =
o->Get(v8::String::NewFromUtf8(isolate, "foo"));
template<typename T> Handle<T> FromC(v8_handle_t h) { /* ... */ }
template<typename T> v8_handle_t ToC(Handle<T> h) { /* ... */ }
extern "C" v8_handle_t v8_object_get(v8_handle_t self,
v8_handle_t key) {
return ToC(FromC<Object>(self)->Get(FromC<Value>(key)));
}
那么 v8::Handle<T>
里面是什么呢?实际上,它只是一个指向某个槽的指针,该槽又包含一个底层 V8 对象的实际指针。这种双重间接性存在是为了使 V8 垃圾回收器能够精确跟踪 C++ 代码中正在使用哪些对象,并允许移动这些对象。
因此,你可以理论上将 v8_handle_t
定义为一个不透明指针,并像这样进行编组:
typedef struct v8_object_pointer_t* v8_handle_t; // Opaque pointer
static_assert(sizeof(v8_handle_t) == sizeof(Handle<Object>))
template<typename T> Handle<T> FromC(v8_handle_t h) {
return *(Handle<T>*)&h;
}
template<typename T> v8_handle_t ToC(const Handle<T>& h) {
return *(v8_handle_t*)&h;
}
有一个小的问题需要处理,那就是管理叫做HandleScope
的结构体,这个结构体管理着Handle
。在C++ API中,它依赖于RAII模式来管理一些后备存储。最简单的处理方法可能是:
typedef struct {
void* a[3];
} v8_handle_scope_t;
static_assert(sizeof(v8_handle_scope_t) == sizeof(HandleScope))
void v8_handle_scope_enter(v8_handle_scope_t* scope) {
new(scope) HandleScope;
}
void v8_handle_scope_leave(v8_handle_scope_t* scope) {
delete (HandleScope*)scope;
}
在需要处理作用域的代码中,要注意使用平衡。
for (i = 0; i < N; i++) {
v8_handle_scope_t scope;
v8_handle_scope_enter(&scope);
// action
v8_handle_scope_leave(&scope);
}
由于您的问题涉及如何编写 Node.js 的 V8 C++ 插件,因此您应该参考Node.js 手册中针对编写插件有简单易懂的指南;
如果您的问题是关于如何创建后台线程,则有一些 Node.js 插件可以帮助您完成,但也可以直接阅读此文以了解如何编写。
永远不要尝试直接访问 V8 的内存,因为内存和对象可能会移动 -- 总是使用 API。