From 6ba38e8c2b8a9b5fcbbd35dd3f76b3737647fd81 Mon Sep 17 00:00:00 2001 From: Gabriel Schulhof Date: Fri, 30 Jun 2017 13:46:25 +0300 Subject: [PATCH] N-API: Reuse ObjectTemplate instances 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`. https://github.com/nodejs/node-addon-api/pull/70#discussion_r124998408 Backport-PR-URL: https://github.com/nodejs/node/pull/19447 PR-URL: https://github.com/nodejs/node/pull/13999 Reviewed-By: Ben Noordhuis Reviewed-By: Anna Henningsen Reviewed-By: Colin Ihrig Reviewed-By: James M Snell Reviewed-By: Michael Dawson Reviewed-By: Hitesh Kanwathirtha --- src/node_api.cc | 33 +++++++++++++++++++++++++-------- 1 file changed, 25 insertions(+), 8 deletions(-) diff --git a/src/node_api.cc b/src/node_api.cc index 1cd2fad9b9807a..addd63a0f7e6f3 100644 --- a/src/node_api.cc +++ b/src/node_api.cc @@ -36,14 +36,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 last_exception; v8::Persistent has_instance; + v8::Persistent wrap_template; + v8::Persistent function_data_template; + v8::Persistent 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)) { \ @@ -608,8 +626,8 @@ v8::Local CreateFunctionCallbackData(napi_env env, v8::Isolate* isolate = env->isolate; v8::Local context = isolate->GetCurrentContext(); - v8::Local otpl = v8::ObjectTemplate::New(isolate); - otpl->SetInternalFieldCount(v8impl::kFunctionFieldCount); + v8::Local otpl; + ENV_OBJECT_TEMPLATE(env, function_data, otpl, v8impl::kFunctionFieldCount); v8::Local cbdata = otpl->NewInstance(context).ToLocalChecked(); cbdata->SetInternalField( @@ -634,8 +652,8 @@ v8::Local CreateAccessorCallbackData(napi_env env, v8::Isolate* isolate = env->isolate; v8::Local context = isolate->GetCurrentContext(); - v8::Local otpl = v8::ObjectTemplate::New(isolate); - otpl->SetInternalFieldCount(v8impl::kAccessorFieldCount); + v8::Local otpl; + ENV_OBJECT_TEMPLATE(env, accessor_data, otpl, v8impl::kAccessorFieldCount); v8::Local cbdata = otpl->NewInstance(context).ToLocalChecked(); cbdata->SetInternalField( @@ -2011,11 +2029,10 @@ napi_status napi_wrap(napi_env env, v8::Local obj = value.As(); // Create a wrapper object with an internal field to hold the wrapped pointer. - v8::Local wrapperTemplate = - v8::ObjectTemplate::New(isolate); - wrapperTemplate->SetInternalFieldCount(1); + v8::Local wrapper_template; + ENV_OBJECT_TEMPLATE(env, wrap, wrapper_template, 1); v8::Local 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.