Skip to content

Commit

Permalink
N-API: Reuse ObjectTemplate instances
Browse files Browse the repository at this point in the history
V8 caches and does not subsequently release `ObjectTemplate` instances.
Thus, we need to store the `ObjectTemplate` from which we derive object
instances we use for `napi_wrap()` and function/accessor context in a
persistent in the `napi_env`.

nodejs/node-addon-api#70 (comment)
  • Loading branch information
Gabriel Schulhof committed Jun 30, 2017
1 parent 08109a3 commit 4ec417d
Showing 1 changed file with 25 additions and 8 deletions.
33 changes: 25 additions & 8 deletions src/node_api.cc
Original file line number Diff line number Diff line change
Expand Up @@ -34,14 +34,32 @@ struct napi_env__ {
~napi_env__() {
last_exception.Reset();
has_instance.Reset();
wrap_template.Reset();
function_data_template.Reset();
accessor_data_template.Reset();
}
v8::Isolate* isolate;
v8::Persistent<v8::Value> last_exception;
v8::Persistent<v8::Value> has_instance;
v8::Persistent<v8::ObjectTemplate> wrap_template;
v8::Persistent<v8::ObjectTemplate> function_data_template;
v8::Persistent<v8::ObjectTemplate> accessor_data_template;
bool has_instance_available;
napi_extended_error_info last_error;
};

#define ENV_OBJECT_TEMPLATE(env, prefix, destination, field_count) \
do { \
if ((env)->prefix ## _template.IsEmpty()) { \
(destination) = v8::ObjectTemplate::New(isolate); \
(destination)->SetInternalFieldCount((field_count)); \
(env)->prefix ## _template.Reset(isolate, (destination)); \
} else { \
(destination) = env->prefix ## _template.Get(isolate); \
} \
} while (0)


#define RETURN_STATUS_IF_FALSE(env, condition, status) \
do { \
if (!(condition)) { \
Expand Down Expand Up @@ -603,8 +621,8 @@ v8::Local<v8::Object> CreateFunctionCallbackData(napi_env env,
v8::Isolate* isolate = env->isolate;
v8::Local<v8::Context> context = isolate->GetCurrentContext();

v8::Local<v8::ObjectTemplate> otpl = v8::ObjectTemplate::New(isolate);
otpl->SetInternalFieldCount(v8impl::kFunctionFieldCount);
v8::Local<v8::ObjectTemplate> otpl;
ENV_OBJECT_TEMPLATE(env, function_data, otpl, v8impl::kFunctionFieldCount);
v8::Local<v8::Object> cbdata = otpl->NewInstance(context).ToLocalChecked();

cbdata->SetInternalField(
Expand All @@ -629,8 +647,8 @@ v8::Local<v8::Object> CreateAccessorCallbackData(napi_env env,
v8::Isolate* isolate = env->isolate;
v8::Local<v8::Context> context = isolate->GetCurrentContext();

v8::Local<v8::ObjectTemplate> otpl = v8::ObjectTemplate::New(isolate);
otpl->SetInternalFieldCount(v8impl::kAccessorFieldCount);
v8::Local<v8::ObjectTemplate> otpl;
ENV_OBJECT_TEMPLATE(env, accessor_data, otpl, v8impl::kAccessorFieldCount);
v8::Local<v8::Object> cbdata = otpl->NewInstance(context).ToLocalChecked();

cbdata->SetInternalField(
Expand Down Expand Up @@ -1966,11 +1984,10 @@ napi_status napi_wrap(napi_env env,
v8::Local<v8::Object> obj = value.As<v8::Object>();

// Create a wrapper object with an internal field to hold the wrapped pointer.
v8::Local<v8::ObjectTemplate> wrapperTemplate =
v8::ObjectTemplate::New(isolate);
wrapperTemplate->SetInternalFieldCount(1);
v8::Local<v8::ObjectTemplate> wrapper_template;
ENV_OBJECT_TEMPLATE(env, wrap, wrapper_template, 1);
v8::Local<v8::Object> wrapper =
wrapperTemplate->NewInstance(context).ToLocalChecked();
wrapper_template->NewInstance(context).ToLocalChecked();
wrapper->SetInternalField(0, v8::External::New(isolate, native_object));

// Insert the wrapper into the object's prototype chain.
Expand Down

0 comments on commit 4ec417d

Please sign in to comment.