From 10a346edde47c872de9afbcb79aa43095064078b Mon Sep 17 00:00:00 2001 From: legendecas Date: Wed, 29 May 2019 13:25:07 +0800 Subject: n-api: define ECMAScript-compliant accessors on napi_define_class PR-URL: https://github.com/nodejs/node/pull/27851 Fixes: https://github.com/nodejs/node/issues/26551 Fixes: https://github.com/nodejs/node-addon-api/issues/485 Reviewed-By: Anna Henningsen Reviewed-By: Gus Caplan Reviewed-By: Tiancheng "Timothy" Gu Reviewed-By: Michael Dawson --- src/js_native_api_v8.cc | 61 +++++++++++++++++++++++-------------------------- 1 file changed, 28 insertions(+), 33 deletions(-) (limited to 'src/js_native_api_v8.cc') diff --git a/src/js_native_api_v8.cc b/src/js_native_api_v8.cc index b99f08bbea..30f34b474c 100644 --- a/src/js_native_api_v8.cc +++ b/src/js_native_api_v8.cc @@ -79,12 +79,10 @@ inline static v8::PropertyAttribute V8PropertyAttributesFromDescriptor( const napi_property_descriptor* descriptor) { unsigned int attribute_flags = v8::PropertyAttribute::None; - if (descriptor->getter != nullptr || descriptor->setter != nullptr) { - // The napi_writable attribute is ignored for accessor descriptors, but - // V8 requires the ReadOnly attribute to match nonexistence of a setter. - attribute_flags |= (descriptor->setter == nullptr ? - v8::PropertyAttribute::ReadOnly : v8::PropertyAttribute::None); - } else if ((descriptor->attributes & napi_writable) == 0) { + // The napi_writable attribute is ignored for accessor descriptors, but + // V8 would throw `TypeError`s on assignment with nonexistence of a setter. + if ((descriptor->getter == nullptr && descriptor->setter == nullptr) && + (descriptor->attributes & napi_writable) == 0) { attribute_flags |= v8::PropertyAttribute::ReadOnly; } @@ -598,24 +596,6 @@ v8::Local CreateFunctionCallbackData(napi_env env, return cbdata; } -// Creates an object to be made available to the static getter/setter -// callback wrapper, used to retrieve the native getter/setter callback -// function and data pointer. -inline v8::Local CreateAccessorCallbackData(napi_env env, - napi_callback getter, - napi_callback setter, - void* data) { - CallbackBundle* bundle = new CallbackBundle(); - bundle->function_or_getter = getter; - bundle->setter = setter; - bundle->cb_data = data; - bundle->env = env; - v8::Local cbdata = v8::External::New(env->isolate, bundle); - bundle->BindLifecycleTo(env->isolate, cbdata); - - return cbdata; -} - enum WrapType { retrievable, anonymous @@ -812,18 +792,33 @@ napi_status napi_define_class(napi_env env, v8impl::V8PropertyAttributesFromDescriptor(p); // This code is similar to that in napi_define_properties(); the - // difference is it applies to a template instead of an object. + // difference is it applies to a template instead of an object, + // and preferred PropertyAttribute for lack of PropertyDescriptor + // support on ObjectTemplate. if (p->getter != nullptr || p->setter != nullptr) { - v8::Local cbdata = v8impl::CreateAccessorCallbackData( - env, p->getter, p->setter, p->data); + v8::Local getter_tpl; + v8::Local setter_tpl; + if (p->getter != nullptr) { + v8::Local getter_data = + v8impl::CreateFunctionCallbackData(env, p->getter, p->data); + + getter_tpl = v8::FunctionTemplate::New( + isolate, v8impl::FunctionCallbackWrapper::Invoke, getter_data); + } + if (p->setter != nullptr) { + v8::Local setter_data = + v8impl::CreateFunctionCallbackData(env, p->setter, p->data); + + setter_tpl = v8::FunctionTemplate::New( + isolate, v8impl::FunctionCallbackWrapper::Invoke, setter_data); + } - tpl->PrototypeTemplate()->SetAccessor( + tpl->PrototypeTemplate()->SetAccessorProperty( property_name, - p->getter ? v8impl::GetterCallbackWrapper::Invoke : nullptr, - p->setter ? v8impl::SetterCallbackWrapper::Invoke : nullptr, - cbdata, - v8::AccessControl::DEFAULT, - attributes); + getter_tpl, + setter_tpl, + attributes, + v8::AccessControl::DEFAULT); } else if (p->method != nullptr) { v8::Local cbdata = v8impl::CreateFunctionCallbackData(env, p->method, p->data); -- cgit v1.2.3