Макет памяти объектов JavaScript в V8

Я хочу написать некоторые привязки C к V8, и поэтому мне нужно выяснить расположение памяти различных примитивных типов JavaScript. Есть ли какая-либо документация по этим деталям в любом месте?

Ответы

Ответ 1

Вам не нужно знать макеты типов данных для записи привязок C для V8. Объект никогда не открывается напрямую, когда вы работаете с V8, но с помощью API-реализации V8 знает, как они выложены. Например, получение свойства foo из объекта o выглядит так в С++:

v8::Handle<v8::Object> o;
v8::Handle<v8::Object> v =
  o->Get(v8::String::NewFromUtf8(isolate, "foo"));

Теперь, чтобы обернуть это в C, вам нужно только знать, как представлять и передавать v8::Handle<T>, тогда вы можете написать обертку, например:

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 GC точно отслеживать, какие объекты используются в коде С++, и разрешить перемещать эти объекты.

Итак, теоретически вы можете определить 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 s. В С++ 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);
}

Ответ 2

Как ваш вопрос о том, как писать дополнения V8 С++ для Node.js, вы должны просто обратиться к руководству для nodeJs, который имеет достаточно простые руководство для написания дополнений;

Если вы задаетесь вопросом о том, как создавать фоновые потоки, то есть плагины nodejs, которые помогут вам в этом, но также прочитайте это, чтобы как написать его напрямую.

Вы никогда не должны пытаться напрямую обращаться к памяти для V8, так как память и объект могут перемещаться - всегда используйте API