Search code examples
c++v8

V8 object wrapper is not adding properties correctly


I have a C++ class called TransformComponent and it has three properties of type glm::vec3*. I am trying to expose and instance of this class to my JS code, but I'm having difficulty wrapping it.

This is my wrapper code:

v8::Local<v8::Object> TransformComponent::WrapObject(TransformComponent* object)
{
    v8::Isolate* isolate = v8::Isolate::GetCurrent();
    v8::Isolate::Scope isolate_scope(isolate);
    v8::HandleScope handle_scope(isolate);

    v8::Local<v8::Context> context = isolate->GetCurrentContext();
    v8::Context::Scope context_scope(context);

    v8::Local<v8::ObjectTemplate> class_template = v8::ObjectTemplate::New(isolate);
    class_template->SetInternalFieldCount(1);
    // class_template->SetAccessor(v8::String::NewFromUtf8(isolate, "position"), V8_GetPosition);
    // class_template->SetAccessor(v8::String::NewFromUtf8(isolate, "rotation"), V8_GetRotation);
    class_template->SetAccessor(v8::String::NewFromUtf8(isolate, "scale"), V8_GetScale);

    v8::Local<v8::Object> obj = class_template->NewInstance(context).ToLocalChecked();
    obj->SetInternalField(0, v8::External::New(isolate, object));

    return obj;
}

This is my getter method:

void TransformComponent::V8_GetScale(v8::Local<v8::Name> property, const v8::PropertyCallbackInfo<v8::Value>& info)
{
    printf("S: Getter called!\n");
    TransformComponent* component = V8Helper::UnwrapObject<TransformComponent>(info);
    info.GetReturnValue().Set(Vec3Wrapper::WrapObject(component->scale));
}

And finally this is how I inject the wrapped object in the global js object:

v8::Local<v8::Object> transform_obj = TransformComponent::WrapObject(actor->GetComponent<TransformComponent>());
global->Set(V8_STR("transform"), transform_obj);

With this code, a global object called transform becomes available in the JS code, but for some reason, its properties are undefined (console.log(transform.scale); prints 'undefined') even though I am calling SetAccessor and passing the correct functions. The getter function isn't even being called, because the printf doesn't print anything to the console.

Am I missing something here? I have tried wrapping nested objects in a separate project (where I usually test V8 stuff before implementing them in the main project), and it works there. Here you can look at the working test program where I wrap a Line object with a Point* property.


Solution

  • V8 developer here. The first thing I would try is to drop the HandleScope from the WrapObject function. When a HandleScope goes out of scope, it makes all handles created in it invalid -- in this case, in particular obj. So I'm actually surprised that this code doesn't just crash ;-)

    If you do need a local HandleScope, you can use an EscapableHandleScope, which has a special slot inside to let one handle outlive it.