diff --git a/src/.gitignore b/src/.gitignore new file mode 100644 index 000000000..b7a17b3df --- /dev/null +++ b/src/.gitignore @@ -0,0 +1,4 @@ +/Debug +/Release +/*.vcxproj* +/*.sln \ No newline at end of file diff --git a/src/node_api.cc b/src/node_api.cc index 5d630e111..551e78eab 100644 --- a/src/node_api.cc +++ b/src/node_api.cc @@ -8,20 +8,123 @@ * ******************************************************************************/ - #include #include #include #include +#include +#include #include -#include "node_api_internal.h" +#include "uv.h" +#include "node_api.h" + +napi_status napi_set_last_error(napi_env env, napi_status error_code, + uint32_t engine_error_code = 0, + void* engine_reserved = nullptr); +void napi_clear_last_error(napi_env env); + +struct napi_env__ { + explicit napi_env__(v8::Isolate* _isolate): isolate(_isolate), + has_instance_available(true), last_error() {} + ~napi_env__() { + last_exception.Reset(); + has_instance.Reset(); + } + v8::Isolate* isolate; + v8::Persistent last_exception; + v8::Persistent has_instance; + bool has_instance_available; + napi_extended_error_info last_error; +}; + +#define RETURN_STATUS_IF_FALSE(env, condition, status) \ + do { \ + if (!(condition)) { \ + return napi_set_last_error((env), (status)); \ + } \ + } while (0) + +#define CHECK_ENV(env) \ + if ((env) == nullptr) { \ + return napi_invalid_arg; \ + } + +#define CHECK_ARG(env, arg) \ + RETURN_STATUS_IF_FALSE((env), ((arg) != nullptr), napi_invalid_arg) + +#define CHECK_MAYBE_EMPTY(env, maybe, status) \ + RETURN_STATUS_IF_FALSE((env), !((maybe).IsEmpty()), (status)) + +#define CHECK_MAYBE_NOTHING(env, maybe, status) \ + RETURN_STATUS_IF_FALSE((env), !((maybe).IsNothing()), (status)) + +// NAPI_PREAMBLE is not wrapped in do..while: try_catch must have function scope +#define NAPI_PREAMBLE(env) \ + CHECK_ENV((env)); \ + RETURN_STATUS_IF_FALSE((env), (env)->last_exception.IsEmpty(), \ + napi_pending_exception); \ + napi_clear_last_error((env)); \ + v8impl::TryCatch try_catch((env)) + +#define CHECK_TO_TYPE(env, type, context, result, src, status) \ + do { \ + auto maybe = v8impl::V8LocalValueFromJsValue((src))->To##type((context)); \ + CHECK_MAYBE_EMPTY((env), maybe, (status)); \ + (result) = maybe.ToLocalChecked(); \ + } while (0) + +#define CHECK_TO_OBJECT(env, context, result, src) \ + CHECK_TO_TYPE((env), Object, (context), (result), (src), napi_object_expected) + +#define CHECK_TO_STRING(env, context, result, src) \ + CHECK_TO_TYPE((env), String, (context), (result), (src), napi_string_expected) + +#define CHECK_TO_NUMBER(env, context, result, src) \ + CHECK_TO_TYPE((env), Number, (context), (result), (src), napi_number_expected) + +#define CHECK_TO_BOOL(env, context, result, src) \ + CHECK_TO_TYPE((env), Boolean, (context), (result), (src), \ + napi_boolean_expected) + +#define CHECK_NEW_FROM_UTF8_LEN(env, result, str, len) \ + do { \ + auto str_maybe = v8::String::NewFromUtf8( \ + (env)->isolate, (str), v8::NewStringType::kInternalized, (len)); \ + CHECK_MAYBE_EMPTY((env), str_maybe, napi_generic_failure); \ + (result) = str_maybe.ToLocalChecked(); \ + } while (0) + +#define CHECK_NEW_FROM_UTF8(env, result, str) \ + CHECK_NEW_FROM_UTF8_LEN((env), (result), (str), -1) + +#define GET_RETURN_STATUS(env) \ + (!try_catch.HasCaught() ? napi_ok \ + : napi_set_last_error((env), napi_pending_exception)) namespace v8impl { -//=== Conversion between V8 Isolate and napi_env ========================== +// convert from n-api property attributes to v8::PropertyAttribute +static inline 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) { + attribute_flags |= v8::PropertyAttribute::ReadOnly; + } -napi_env JsEnvFromV8Isolate(v8::Isolate* isolate) { - return reinterpret_cast(isolate); + if ((descriptor->attributes & napi_enumerable) == 0) { + attribute_flags |= v8::PropertyAttribute::DontEnum; + } + if ((descriptor->attributes & napi_configurable) == 0) { + attribute_flags |= v8::PropertyAttribute::DontDelete; + } + + return static_cast(attribute_flags); } v8::Isolate* V8IsolateFromJsEnv(napi_env e) { @@ -74,61 +177,101 @@ V8EscapableHandleScopeFromJsEscapableHandleScope( //=== Conversion between V8 Handles and napi_value ======================== -// This is assuming v8::Local<> will always be implemented with a single -// pointer field so that we can pass it around as a void* (maybe we should -// use intptr_t instead of void*) +// This asserts v8::Local<> will always be implemented with a single +// pointer field so that we can pass it around as a void*. +static_assert(sizeof(v8::Local) == sizeof(napi_value), + "Cannot convert between v8::Local and napi_value"); napi_value JsValueFromV8LocalValue(v8::Local local) { - // This is awkward, better way? memcpy but don't want that dependency? - union U { - napi_value v; - v8::Local l; - U(v8::Local _l) : l(_l) {} - } u(local); - assert(sizeof(u.v) == sizeof(u.l)); - return u.v; + return reinterpret_cast(*local); } v8::Local V8LocalValueFromJsValue(napi_value v) { - // Likewise awkward - union U { - napi_value v; - v8::Local l; - U(napi_value _v) : v(_v) {} - } u(v); - assert(sizeof(u.v) == sizeof(u.l)); - return u.l; -} - -static v8::Local V8LocalFunctionFromJsValue(napi_value v) { - // Likewise awkward - union U { - napi_value v; - v8::Local f; - U(napi_value _v) : v(_v) {} - } u(v); - assert(sizeof(u.v) == sizeof(u.f)); - return u.f; + v8::Local local; + memcpy(&local, &v, sizeof(v)); + return local; } -// Wrapper around v8::Persistent that implements reference counting. -class Reference { +static inline napi_status V8NameFromPropertyDescriptor(napi_env env, + const napi_property_descriptor* p, + v8::Local* result) { + if (p->utf8name != nullptr) { + CHECK_NEW_FROM_UTF8(env, *result, p->utf8name); + } else { + v8::Local property_value = + v8impl::V8LocalValueFromJsValue(p->name); + + RETURN_STATUS_IF_FALSE(env, property_value->IsName(), napi_name_expected); + *result = property_value.As(); + } + + return napi_ok; +} + +// Adapter for napi_finalize callbacks. +class Finalizer { + protected: + Finalizer(napi_env env, + napi_finalize finalize_callback, + void* finalize_data, + void* finalize_hint) + : _env(env), + _finalize_callback(finalize_callback), + _finalize_data(finalize_data), + _finalize_hint(finalize_hint) { + } + + ~Finalizer() { + } + public: - Reference(v8::Isolate* isolate, + static Finalizer* New(napi_env env, + napi_finalize finalize_callback = nullptr, + void* finalize_data = nullptr, + void* finalize_hint = nullptr) { + return new Finalizer( + env, finalize_callback, finalize_data, finalize_hint); + } + + static void Delete(Finalizer* finalizer) { + delete finalizer; + } + + // node::Buffer::FreeCallback + static void FinalizeBufferCallback(char* data, void* hint) { + Finalizer* finalizer = static_cast(hint); + if (finalizer->_finalize_callback != nullptr) { + finalizer->_finalize_callback( + finalizer->_env, + data, + finalizer->_finalize_hint); + } + + Delete(finalizer); + } + + protected: + napi_env _env; + napi_finalize _finalize_callback; + void* _finalize_data; + void* _finalize_hint; +}; + +// Wrapper around v8::Persistent that implements reference counting. +class Reference : private Finalizer { + private: + Reference(napi_env env, v8::Local value, - int initialRefcount, - bool deleteSelf, - napi_finalize finalizeCallback = nullptr, - void* finalizeData = nullptr, - void* finalizeHint = nullptr) - : _isolate(isolate), - _persistent(isolate, value), - _refcount(initialRefcount), - _deleteSelf(deleteSelf), - _finalizeCallback(finalizeCallback), - _finalizeData(finalizeData), - _finalizeHint(finalizeHint) { - if (initialRefcount == 0) { + uint32_t initial_refcount, + bool delete_self, + napi_finalize finalize_callback, + void* finalize_data, + void* finalize_hint) + : Finalizer(env, finalize_callback, finalize_data, finalize_hint), + _persistent(env->isolate, value), + _refcount(initial_refcount), + _delete_self(delete_self) { + if (initial_refcount == 0) { _persistent.SetWeak( this, FinalizeCallback, v8::WeakCallbackType::kParameter); _persistent.MarkIndependent(); @@ -145,7 +288,28 @@ class Reference { _persistent.Reset(); } - int AddRef() { + public: + static Reference* New(napi_env env, + v8::Local value, + uint32_t initial_refcount, + bool delete_self, + napi_finalize finalize_callback = nullptr, + void* finalize_data = nullptr, + void* finalize_hint = nullptr) { + return new Reference(env, + value, + initial_refcount, + delete_self, + finalize_callback, + finalize_data, + finalize_hint); + } + + static void Delete(Reference* reference) { + delete reference; + } + + uint32_t Ref() { if (++_refcount == 1) { _persistent.ClearWeak(); } @@ -153,7 +317,10 @@ class Reference { return _refcount; } - int Release() { + uint32_t Unref() { + if (_refcount == 0) { + return 0; + } if (--_refcount == 0) { _persistent.SetWeak( this, FinalizeCallback, v8::WeakCallbackType::kParameter); @@ -163,11 +330,15 @@ class Reference { return _refcount; } + uint32_t RefCount() { + return _refcount; + } + v8::Local Get() { if (_persistent.IsEmpty()) { return v8::Local(); } else { - return v8::Local::New(_isolate, _persistent); + return v8::Local::New(_env->isolate, _persistent); } } @@ -178,88 +349,81 @@ class Reference { // Check before calling the finalize callback, because the callback might // delete it. - bool deleteSelf = reference->_deleteSelf; + bool delete_self = reference->_delete_self; - if (reference->_finalizeCallback != nullptr) { - reference->_finalizeCallback(reference->_finalizeData, - reference->_finalizeHint); + if (reference->_finalize_callback != nullptr) { + reference->_finalize_callback( + reference->_env, + reference->_finalize_data, + reference->_finalize_hint); } - if (deleteSelf) { - delete reference; + if (delete_self) { + Delete(reference); } } - v8::Isolate* _isolate; v8::Persistent _persistent; - int _refcount; - bool _deleteSelf; - napi_finalize _finalizeCallback; - void* _finalizeData; - void* _finalizeHint; + uint32_t _refcount; + bool _delete_self; }; class TryCatch : public v8::TryCatch { public: - explicit TryCatch(v8::Isolate* isolate) - : v8::TryCatch(isolate), _isolate(isolate) {} + explicit TryCatch(napi_env env) + : v8::TryCatch(env->isolate), _env(env) {} ~TryCatch() { if (HasCaught()) { - _theException.Reset(_isolate, Exception()); + _env->last_exception.Reset(_env->isolate, Exception()); } } - static v8::Persistent& lastException() { return _theException; } - private: - static v8::Persistent _theException; - v8::Isolate* _isolate; + napi_env _env; }; -v8::Persistent TryCatch::_theException; - //=== Function napi_callback wrapper ================================= static const int kDataIndex = 0; +static const int kEnvIndex = 1; -static const int kFunctionIndex = 1; -static const int kFunctionFieldCount = 2; +static const int kFunctionIndex = 2; +static const int kFunctionFieldCount = 3; -static const int kGetterIndex = 1; -static const int kSetterIndex = 2; -static const int kAccessorFieldCount = 3; +static const int kGetterIndex = 2; +static const int kSetterIndex = 3; +static const int kAccessorFieldCount = 4; // Base class extended by classes that wrap V8 function and property callback // info. class CallbackWrapper { public: - CallbackWrapper(napi_value thisArg, int argsLength, void* data) - : _this(thisArg), _argsLength(argsLength), _data(data) {} + CallbackWrapper(napi_value this_arg, size_t args_length, void* data) + : _this(this_arg), _args_length(args_length), _data(data) {} - virtual napi_value Holder() = 0; virtual bool IsConstructCall() = 0; - virtual void Args(napi_value* buffer, int bufferlength) = 0; - virtual void SetReturnValue(napi_value v) = 0; + virtual void Args(napi_value* buffer, size_t bufferlength) = 0; + virtual void SetReturnValue(napi_value value) = 0; napi_value This() { return _this; } - int ArgsLength() { return _argsLength; } + size_t ArgsLength() { return _args_length; } void* Data() { return _data; } protected: const napi_value _this; - const int _argsLength; + const size_t _args_length; void* _data; }; -template +template class CallbackWrapperBase : public CallbackWrapper { public: - CallbackWrapperBase(const T& cbinfo, const int argsLength) + CallbackWrapperBase(const Info& cbinfo, const size_t args_length) : CallbackWrapper(JsValueFromV8LocalValue(cbinfo.This()), - argsLength, + args_length, nullptr), _cbinfo(cbinfo), _cbdata(v8::Local::Cast(cbinfo.Data())) { @@ -267,11 +431,6 @@ class CallbackWrapperBase : public CallbackWrapper { ->Value(); } - /*virtual*/ - napi_value Holder() override { - return JsValueFromV8LocalValue(_cbinfo.Holder()); - } - /*virtual*/ bool IsConstructCall() override { return false; } @@ -280,18 +439,31 @@ class CallbackWrapperBase : public CallbackWrapper { napi_callback_info cbinfo_wrapper = reinterpret_cast( static_cast(this)); napi_callback cb = reinterpret_cast( - v8::Local::Cast(_cbdata->GetInternalField(I))->Value()); + v8::Local::Cast( + _cbdata->GetInternalField(kInternalFieldIndex))->Value()); v8::Isolate* isolate = _cbinfo.GetIsolate(); - cb(v8impl::JsEnvFromV8Isolate(isolate), cbinfo_wrapper); - if (!TryCatch::lastException().IsEmpty()) { + napi_env env = static_cast( + v8::Local::Cast( + _cbdata->GetInternalField(kEnvIndex))->Value()); + + // Make sure any errors encountered last time we were in N-API are gone. + napi_clear_last_error(env); + + napi_value result = cb(env, cbinfo_wrapper); + + if (result != nullptr) { + this->SetReturnValue(result); + } + + if (!env->last_exception.IsEmpty()) { isolate->ThrowException( - v8::Local::New(isolate, TryCatch::lastException())); - TryCatch::lastException().Reset(); + v8::Local::New(isolate, env->last_exception)); + env->last_exception.Reset(); } } - const T& _cbinfo; + const Info& _cbinfo; const v8::Local _cbdata; }; @@ -312,26 +484,26 @@ class FunctionCallbackWrapper bool IsConstructCall() override { return _cbinfo.IsConstructCall(); } /*virtual*/ - void Args(napi_value* buffer, int bufferlength) override { - int i = 0; - int min = std::min(bufferlength, _argsLength); + void Args(napi_value* buffer, size_t buffer_length) override { + size_t i = 0; + size_t min = std::min(buffer_length, _args_length); for (; i < min; i += 1) { buffer[i] = v8impl::JsValueFromV8LocalValue(_cbinfo[i]); } - if (i < bufferlength) { + if (i < buffer_length) { napi_value undefined = v8impl::JsValueFromV8LocalValue(v8::Undefined(_cbinfo.GetIsolate())); - for (; i < bufferlength; i += 1) { + for (; i < buffer_length; i += 1) { buffer[i] = undefined; } } } /*virtual*/ - void SetReturnValue(napi_value v) override { - v8::Local val = v8impl::V8LocalValueFromJsValue(v); + void SetReturnValue(napi_value value) override { + v8::Local val = v8impl::V8LocalValueFromJsValue(value); _cbinfo.GetReturnValue().Set(val); } }; @@ -351,19 +523,19 @@ class GetterCallbackWrapper : CallbackWrapperBase(cbinfo, 0) {} /*virtual*/ - void Args(napi_value* buffer, int bufferlength) override { - if (bufferlength > 0) { + void Args(napi_value* buffer, size_t buffer_length) override { + if (buffer_length > 0) { napi_value undefined = v8impl::JsValueFromV8LocalValue(v8::Undefined(_cbinfo.GetIsolate())); - for (int i = 0; i < bufferlength; i += 1) { + for (size_t i = 0; i < buffer_length; i += 1) { buffer[i] = undefined; } } } /*virtual*/ - void SetReturnValue(napi_value v) override { - v8::Local val = v8impl::V8LocalValueFromJsValue(v); + void SetReturnValue(napi_value value) override { + v8::Local val = v8impl::V8LocalValueFromJsValue(value); _cbinfo.GetReturnValue().Set(val); } }; @@ -372,9 +544,9 @@ class SetterCallbackWrapper : public CallbackWrapperBase, kSetterIndex> { public: static void Invoke(v8::Local property, - v8::Local v, + v8::Local value, const v8::PropertyCallbackInfo& info) { - SetterCallbackWrapper cbwrapper(info, v); + SetterCallbackWrapper cbwrapper(info, value); cbwrapper.InvokeCallback(); } @@ -383,14 +555,14 @@ class SetterCallbackWrapper : CallbackWrapperBase(cbinfo, 1), _value(value) {} /*virtual*/ - void Args(napi_value* buffer, int bufferlength) override { - if (bufferlength > 0) { + void Args(napi_value* buffer, size_t buffer_length) override { + if (buffer_length > 0) { buffer[0] = v8impl::JsValueFromV8LocalValue(_value); - if (bufferlength > 1) { + if (buffer_length > 1) { napi_value undefined = v8impl::JsValueFromV8LocalValue( v8::Undefined(_cbinfo.GetIsolate())); - for (int i = 1; i < bufferlength; i += 1) { + for (size_t i = 1; i < buffer_length; i += 1) { buffer[i] = undefined; } } @@ -398,9 +570,8 @@ class SetterCallbackWrapper } /*virtual*/ - void SetReturnValue(napi_value v) override { - // Cannot set the return value of a setter. - assert(false); + void SetReturnValue(napi_value value) override { + // Ignore any value returned from a setter callback. } private: @@ -409,61 +580,61 @@ class SetterCallbackWrapper // Creates an object to be made available to the static function callback // wrapper, used to retrieve the native callback function and data pointer. -v8::Local CreateFunctionCallbackData(napi_env e, +v8::Local CreateFunctionCallbackData(napi_env env, napi_callback cb, void* data) { - v8::Isolate* isolate = v8impl::V8IsolateFromJsEnv(e); + v8::Isolate* isolate = env->isolate; v8::Local context = isolate->GetCurrentContext(); v8::Local otpl = v8::ObjectTemplate::New(isolate); otpl->SetInternalFieldCount(v8impl::kFunctionFieldCount); v8::Local cbdata = otpl->NewInstance(context).ToLocalChecked(); + cbdata->SetInternalField( + v8impl::kEnvIndex, + v8::External::New(isolate, static_cast(env))); cbdata->SetInternalField( v8impl::kFunctionIndex, v8::External::New(isolate, reinterpret_cast(cb))); - - if (data) { - cbdata->SetInternalField( - v8impl::kDataIndex, - v8::External::New(isolate, reinterpret_cast(data))); - } - + cbdata->SetInternalField( + v8impl::kDataIndex, + v8::External::New(isolate, data)); 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. -v8::Local CreateAccessorCallbackData(napi_env e, +v8::Local CreateAccessorCallbackData(napi_env env, napi_callback getter, napi_callback setter, void* data) { - v8::Isolate* isolate = v8impl::V8IsolateFromJsEnv(e); + v8::Isolate* isolate = env->isolate; v8::Local context = isolate->GetCurrentContext(); v8::Local otpl = v8::ObjectTemplate::New(isolate); otpl->SetInternalFieldCount(v8impl::kAccessorFieldCount); v8::Local cbdata = otpl->NewInstance(context).ToLocalChecked(); - if (getter) { + cbdata->SetInternalField( + v8impl::kEnvIndex, + v8::External::New(isolate, static_cast(env))); + + if (getter != nullptr) { cbdata->SetInternalField( v8impl::kGetterIndex, v8::External::New(isolate, reinterpret_cast(getter))); } - if (setter) { + if (setter != nullptr) { cbdata->SetInternalField( v8impl::kSetterIndex, v8::External::New(isolate, reinterpret_cast(setter))); } - if (data) { - cbdata->SetInternalField( - v8impl::kDataIndex, - v8::External::New(isolate, reinterpret_cast(data))); - } - + cbdata->SetInternalField( + v8impl::kDataIndex, + v8::External::New(isolate, data)); return cbdata; } @@ -477,8 +648,13 @@ void napi_module_register_cb(v8::Local exports, v8::Local context, void* priv) { napi_module* mod = static_cast(priv); + + // Create a new napi_env for this module. Once module unloading is supported + // we shall have to call delete on this object from there. + napi_env env = new napi_env__(context->GetIsolate()); + mod->nm_register_func( - v8impl::JsEnvFromV8Isolate(context->GetIsolate()), + env, v8impl::JsValueFromV8LocalValue(exports), v8impl::JsValueFromV8LocalValue(module), mod->nm_priv); @@ -494,18 +670,18 @@ namespace node { // Registers a NAPI module. void napi_module_register(napi_module* mod) { // NAPI modules always work with the current node version. - int moduleVersion = NODE_MODULE_VERSION; + int module_version = NODE_MODULE_VERSION; #ifndef EXTERNAL_NAPI if (!node::load_napi_modules) { // NAPI is disabled, so set the module version to -1 to cause the module // to be unloaded. - moduleVersion = -1; + module_version = -1; } #endif // EXTERNAL_NAPI node::node_module* nm = new node::node_module { - moduleVersion, + module_version, mod->nm_flags, nullptr, mod->nm_filename, @@ -518,160 +694,109 @@ void napi_module_register(napi_module* mod) { node::node_module_register(nm); } -#define RETURN_STATUS_IF_FALSE(condition, status) \ - do { \ - if (!(condition)) { \ - return napi_set_last_error((status)); \ - } \ - } while (0) - -#define CHECK_ARG(arg) RETURN_STATUS_IF_FALSE((arg), napi_invalid_arg) - -#define CHECK_MAYBE_EMPTY(maybe, status) \ - RETURN_STATUS_IF_FALSE(!((maybe).IsEmpty()), (status)) - -#define CHECK_MAYBE_NOTHING(maybe, status) \ - RETURN_STATUS_IF_FALSE(!((maybe).IsNothing()), (status)) - -// NAPI_PREAMBLE is not wrapped in do..while: tryCatch must have function scope. -#define NAPI_PREAMBLE(e) \ - CHECK_ARG(e); \ - RETURN_STATUS_IF_FALSE(v8impl::TryCatch::lastException().IsEmpty(), \ - napi_pending_exception); \ - napi_clear_last_error(); \ - v8impl::TryCatch tryCatch(v8impl::V8IsolateFromJsEnv((e))) - -#define CHECK_TO_TYPE(type, context, result, src, status) \ - do { \ - auto maybe = v8impl::V8LocalValueFromJsValue((src))->To##type((context)); \ - CHECK_MAYBE_EMPTY(maybe, (status)); \ - result = maybe.ToLocalChecked(); \ - } while (0) - -#define CHECK_TO_OBJECT(context, result, src) \ - CHECK_TO_TYPE(Object, context, result, src, napi_object_expected) - -#define CHECK_TO_STRING(context, result, src) \ - CHECK_TO_TYPE(String, context, result, src, napi_string_expected) - -#define CHECK_TO_NUMBER(context, result, src) \ - CHECK_TO_TYPE(Number, context, result, src, napi_number_expected) - -#define CHECK_TO_BOOL(context, result, src) \ - CHECK_TO_TYPE(Boolean, context, result, src, napi_boolean_expected) - -#define CHECK_NEW_FROM_UTF8_LEN(isolate, result, str, len) \ - do { \ - auto str_maybe = v8::String::NewFromUtf8( \ - (isolate), (str), v8::NewStringType::kInternalized, (len)); \ - CHECK_MAYBE_EMPTY(str_maybe, napi_generic_failure); \ - result = str_maybe.ToLocalChecked(); \ - } while (0) - -#define CHECK_NEW_FROM_UTF8(isolate, result, str) \ - CHECK_NEW_FROM_UTF8_LEN((isolate), (result), (str), -1) - -#define GET_RETURN_STATUS() \ - (!tryCatch.HasCaught() ? napi_ok \ - : napi_set_last_error(napi_pending_exception)) - -// Static last error returned from napi_get_last_error_info -napi_extended_error_info static_last_error = {}; - // Warning: Keep in-sync with napi_status enum const char* error_messages[] = {nullptr, "Invalid pointer passed as argument", "An object was expected", "A string was expected", + "A string or symbol was expected", "A function was expected", "A number was expected", "A boolean was expected", + "An array was expected", "Unknown failure", - "An exception is pending"}; + "An exception is pending", + "The async work item was cancelled"}; -void napi_clear_last_error() { - static_last_error.error_code = napi_ok; +void napi_clear_last_error(napi_env env) { + env->last_error.error_code = napi_ok; // TODO(boingoing): Should this be a callback? - static_last_error.engine_error_code = 0; - static_last_error.engine_reserved = nullptr; + env->last_error.engine_error_code = 0; + env->last_error.engine_reserved = nullptr; +} + +napi_status napi_set_last_error(napi_env env, napi_status error_code, + uint32_t engine_error_code, + void* engine_reserved) { + env->last_error.error_code = error_code; + env->last_error.engine_error_code = engine_error_code; + env->last_error.engine_reserved = engine_reserved; + + return error_code; } -const napi_extended_error_info* napi_get_last_error_info() { +napi_status napi_get_last_error_info(napi_env env, + const napi_extended_error_info** result) { + CHECK_ENV(env); + static_assert( - sizeof(error_messages) / sizeof(*error_messages) == napi_status_last, + (sizeof (error_messages) / sizeof (*error_messages)) == napi_status_last, "Count of error messages must match count of error values"); - assert(static_last_error.error_code < napi_status_last); + assert(env->last_error.error_code < napi_status_last); // Wait until someone requests the last error information to fetch the error // message string - static_last_error.error_message = - error_messages[static_last_error.error_code]; - - return &static_last_error; -} - -napi_status napi_set_last_error(napi_status error_code, - uint32_t engine_error_code = 0, - void* engine_reserved = nullptr) { - static_last_error.error_code = error_code; - static_last_error.engine_error_code = engine_error_code; - static_last_error.engine_reserved = engine_reserved; + env->last_error.error_message = + error_messages[env->last_error.error_code]; - return error_code; + *result = &(env->last_error); + return napi_ok; } -napi_status napi_create_function(napi_env e, +napi_status napi_create_function(napi_env env, const char* utf8name, napi_callback cb, - void* data, + void* callback_data, napi_value* result) { - NAPI_PREAMBLE(e); - CHECK_ARG(result); - - v8::Isolate *isolate = v8impl::V8IsolateFromJsEnv(e); - v8::Local retval; + NAPI_PREAMBLE(env); + CHECK_ARG(env, result); + v8::Isolate* isolate = env->isolate; + v8::Local return_value; v8::EscapableHandleScope scope(isolate); - v8::Local cbdata = - v8impl::CreateFunctionCallbackData(e, cb, data); + v8impl::CreateFunctionCallbackData(env, cb, callback_data); - RETURN_STATUS_IF_FALSE(!cbdata.IsEmpty(), napi_generic_failure); + RETURN_STATUS_IF_FALSE(env, !cbdata.IsEmpty(), napi_generic_failure); v8::Local tpl = v8::FunctionTemplate::New( isolate, v8impl::FunctionCallbackWrapper::Invoke, cbdata); - retval = scope.Escape(tpl->GetFunction()); + v8::Local context = isolate->GetCurrentContext(); + v8::MaybeLocal maybe_function = tpl->GetFunction(context); + CHECK_MAYBE_EMPTY(env, maybe_function, napi_generic_failure); - if (utf8name) { - v8::Local namestring; - CHECK_NEW_FROM_UTF8(isolate, namestring, utf8name); - retval->SetName(namestring); + return_value = scope.Escape(maybe_function.ToLocalChecked()); + + if (utf8name != nullptr) { + v8::Local name_string; + CHECK_NEW_FROM_UTF8(env, name_string, utf8name); + return_value->SetName(name_string); } - *result = v8impl::JsValueFromV8LocalValue(retval); + *result = v8impl::JsValueFromV8LocalValue(return_value); - return GET_RETURN_STATUS(); + return GET_RETURN_STATUS(env); } -napi_status napi_define_class(napi_env e, +napi_status napi_define_class(napi_env env, const char* utf8name, napi_callback constructor, - void* data, - int property_count, + void* callback_data, + size_t property_count, const napi_property_descriptor* properties, napi_value* result) { - NAPI_PREAMBLE(e); - CHECK_ARG(result); + NAPI_PREAMBLE(env); + CHECK_ARG(env, result); - v8::Isolate* isolate = v8impl::V8IsolateFromJsEnv(e); + v8::Isolate* isolate = env->isolate; v8::EscapableHandleScope scope(isolate); v8::Local cbdata = - v8impl::CreateFunctionCallbackData(e, constructor, data); + v8impl::CreateFunctionCallbackData(env, constructor, callback_data); - RETURN_STATUS_IF_FALSE(!cbdata.IsEmpty(), napi_generic_failure); + RETURN_STATUS_IF_FALSE(env, !cbdata.IsEmpty(), napi_generic_failure); v8::Local tpl = v8::FunctionTemplate::New( isolate, v8impl::FunctionCallbackWrapper::Invoke, cbdata); @@ -679,588 +804,603 @@ napi_status napi_define_class(napi_env e, // we need an internal field to stash the wrapped object tpl->InstanceTemplate()->SetInternalFieldCount(1); - v8::Local namestring; - CHECK_NEW_FROM_UTF8(isolate, namestring, utf8name); - tpl->SetClassName(namestring); + v8::Local name_string; + CHECK_NEW_FROM_UTF8(env, name_string, utf8name); + tpl->SetClassName(name_string); - int staticPropertyCount = 0; - for (int i = 0; i < property_count; i++) { + size_t static_property_count = 0; + for (size_t i = 0; i < property_count; i++) { const napi_property_descriptor* p = properties + i; - if ((p->attributes & napi_static_property) != 0) { + if ((p->attributes & napi_static) != 0) { // Static properties are handled separately below. - staticPropertyCount++; + static_property_count++; continue; } - v8::Local propertyname; - CHECK_NEW_FROM_UTF8(isolate, propertyname, p->utf8name); + v8::Local property_name; + napi_status status = + v8impl::V8NameFromPropertyDescriptor(env, p, &property_name); + + if (status != napi_ok) { + return napi_set_last_error(env, status); + } v8::PropertyAttribute attributes = - static_cast(p->attributes); + v8impl::V8PropertyAttributesFromDescriptor(p); - // This code is similar to that in napi_define_property(); the + // This code is similar to that in napi_define_properties(); the // difference is it applies to a template instead of an object. - if (p->method) { + if (p->getter != nullptr || p->setter != nullptr) { + v8::Local cbdata = v8impl::CreateAccessorCallbackData( + env, p->getter, p->setter, p->data); + + tpl->PrototypeTemplate()->SetAccessor( + property_name, + p->getter ? v8impl::GetterCallbackWrapper::Invoke : nullptr, + p->setter ? v8impl::SetterCallbackWrapper::Invoke : nullptr, + cbdata, + v8::AccessControl::DEFAULT, + attributes); + } else if (p->method != nullptr) { v8::Local cbdata = - v8impl::CreateFunctionCallbackData(e, p->method, p->data); + v8impl::CreateFunctionCallbackData(env, p->method, p->data); - RETURN_STATUS_IF_FALSE(!cbdata.IsEmpty(), napi_generic_failure); + RETURN_STATUS_IF_FALSE(env, !cbdata.IsEmpty(), napi_generic_failure); v8::Local t = - v8::FunctionTemplate::New(isolate, - v8impl::FunctionCallbackWrapper::Invoke, - cbdata, - v8::Signature::New(isolate, tpl)); - t->SetClassName(propertyname); - - tpl->PrototypeTemplate()->Set(propertyname, t, attributes); - } else if (p->getter || p->setter) { - v8::Local cbdata = - v8impl::CreateAccessorCallbackData(e, p->getter, p->setter, p->data); - - tpl->PrototypeTemplate()->SetAccessor( - propertyname, - v8impl::GetterCallbackWrapper::Invoke, - p->setter ? v8impl::SetterCallbackWrapper::Invoke : nullptr, + v8::FunctionTemplate::New(isolate, + v8impl::FunctionCallbackWrapper::Invoke, cbdata, - v8::AccessControl::DEFAULT, - attributes); + v8::Signature::New(isolate, tpl)); + + tpl->PrototypeTemplate()->Set(property_name, t, attributes); } else { v8::Local value = v8impl::V8LocalValueFromJsValue(p->value); - tpl->PrototypeTemplate()->Set(propertyname, value, attributes); + tpl->PrototypeTemplate()->Set(property_name, value, attributes); } } *result = v8impl::JsValueFromV8LocalValue(scope.Escape(tpl->GetFunction())); - if (staticPropertyCount > 0) { - std::vector staticDescriptors; - staticDescriptors.reserve(staticPropertyCount); + if (static_property_count > 0) { + std::vector static_descriptors; + static_descriptors.reserve(static_property_count); - for (int i = 0; i < property_count; i++) { + for (size_t i = 0; i < property_count; i++) { const napi_property_descriptor* p = properties + i; - if ((p->attributes & napi_static_property) != 0) { - staticDescriptors.push_back(*p); + if ((p->attributes & napi_static) != 0) { + static_descriptors.push_back(*p); } } napi_status status = - napi_define_properties(e, + napi_define_properties(env, *result, - static_cast(staticDescriptors.size()), - staticDescriptors.data()); + static_descriptors.size(), + static_descriptors.data()); if (status != napi_ok) return status; } - return GET_RETURN_STATUS(); -} - -napi_status napi_set_return_value(napi_env e, - napi_callback_info cbinfo, - napi_value value) { - NAPI_PREAMBLE(e); - - v8impl::CallbackWrapper* info = - reinterpret_cast(cbinfo); - - info->SetReturnValue(value); - return GET_RETURN_STATUS(); + return GET_RETURN_STATUS(env); } -napi_status napi_get_propertynames(napi_env e, - napi_value object, - napi_value* result) { - NAPI_PREAMBLE(e); - CHECK_ARG(result); +napi_status napi_get_property_names(napi_env env, + napi_value object, + napi_value* result) { + NAPI_PREAMBLE(env); + CHECK_ARG(env, result); - v8::Isolate *isolate = v8impl::V8IsolateFromJsEnv(e); + v8::Isolate* isolate = env->isolate; v8::Local context = isolate->GetCurrentContext(); v8::Local obj; - CHECK_TO_OBJECT(context, obj, object); + CHECK_TO_OBJECT(env, context, obj, object); auto maybe_propertynames = obj->GetPropertyNames(context); - CHECK_MAYBE_EMPTY(maybe_propertynames, napi_generic_failure); + CHECK_MAYBE_EMPTY(env, maybe_propertynames, napi_generic_failure); *result = v8impl::JsValueFromV8LocalValue( maybe_propertynames.ToLocalChecked()); - return GET_RETURN_STATUS(); + return GET_RETURN_STATUS(env); } -napi_status napi_set_property(napi_env e, +napi_status napi_set_property(napi_env env, napi_value object, napi_value key, napi_value value) { - NAPI_PREAMBLE(e); + NAPI_PREAMBLE(env); - v8::Isolate *isolate = v8impl::V8IsolateFromJsEnv(e); + v8::Isolate* isolate = env->isolate; v8::Local context = isolate->GetCurrentContext(); v8::Local obj; - CHECK_TO_OBJECT(context, obj, object); + CHECK_TO_OBJECT(env, context, obj, object); v8::Local k = v8impl::V8LocalValueFromJsValue(key); v8::Local val = v8impl::V8LocalValueFromJsValue(value); v8::Maybe set_maybe = obj->Set(context, k, val); - RETURN_STATUS_IF_FALSE(set_maybe.FromMaybe(false), napi_generic_failure); - return GET_RETURN_STATUS(); + RETURN_STATUS_IF_FALSE(env, set_maybe.FromMaybe(false), napi_generic_failure); + return GET_RETURN_STATUS(env); } -napi_status napi_has_property(napi_env e, +napi_status napi_has_property(napi_env env, napi_value object, napi_value key, bool* result) { - NAPI_PREAMBLE(e); - CHECK_ARG(result); + NAPI_PREAMBLE(env); + CHECK_ARG(env, result); - v8::Isolate* isolate = v8impl::V8IsolateFromJsEnv(e); + v8::Isolate* isolate = env->isolate; v8::Local context = isolate->GetCurrentContext(); v8::Local obj; - CHECK_TO_OBJECT(context, obj, object); + CHECK_TO_OBJECT(env, context, obj, object); v8::Local k = v8impl::V8LocalValueFromJsValue(key); v8::Maybe has_maybe = obj->Has(context, k); - CHECK_MAYBE_NOTHING(has_maybe, napi_generic_failure); + CHECK_MAYBE_NOTHING(env, has_maybe, napi_generic_failure); *result = has_maybe.FromMaybe(false); - return GET_RETURN_STATUS(); + return GET_RETURN_STATUS(env); } -napi_status napi_get_property(napi_env e, +napi_status napi_get_property(napi_env env, napi_value object, napi_value key, napi_value* result) { - NAPI_PREAMBLE(e); - CHECK_ARG(result); + NAPI_PREAMBLE(env); + CHECK_ARG(env, result); - v8::Isolate* isolate = v8impl::V8IsolateFromJsEnv(e); + v8::Isolate* isolate = env->isolate; v8::Local context = isolate->GetCurrentContext(); v8::Local k = v8impl::V8LocalValueFromJsValue(key); v8::Local obj; - CHECK_TO_OBJECT(context, obj, object); + CHECK_TO_OBJECT(env, context, obj, object); auto get_maybe = obj->Get(context, k); - CHECK_MAYBE_EMPTY(get_maybe, napi_generic_failure); + CHECK_MAYBE_EMPTY(env, get_maybe, napi_generic_failure); v8::Local val = get_maybe.ToLocalChecked(); *result = v8impl::JsValueFromV8LocalValue(val); - return GET_RETURN_STATUS(); + return GET_RETURN_STATUS(env); } -napi_status napi_set_named_property(napi_env e, +napi_status napi_set_named_property(napi_env env, napi_value object, const char* utf8name, napi_value value) { - NAPI_PREAMBLE(e); + NAPI_PREAMBLE(env); - v8::Isolate *isolate = v8impl::V8IsolateFromJsEnv(e); + v8::Isolate* isolate = env->isolate; v8::Local context = isolate->GetCurrentContext(); v8::Local obj; - CHECK_TO_OBJECT(context, obj, object); + CHECK_TO_OBJECT(env, context, obj, object); v8::Local key; - CHECK_NEW_FROM_UTF8(isolate, key, utf8name); + CHECK_NEW_FROM_UTF8(env, key, utf8name); v8::Local val = v8impl::V8LocalValueFromJsValue(value); v8::Maybe set_maybe = obj->Set(context, key, val); - RETURN_STATUS_IF_FALSE(set_maybe.FromMaybe(false), napi_generic_failure); - return GET_RETURN_STATUS(); + RETURN_STATUS_IF_FALSE(env, set_maybe.FromMaybe(false), napi_generic_failure); + return GET_RETURN_STATUS(env); } -napi_status napi_has_named_property(napi_env e, +napi_status napi_has_named_property(napi_env env, napi_value object, const char* utf8name, bool* result) { - NAPI_PREAMBLE(e); - CHECK_ARG(result); + NAPI_PREAMBLE(env); + CHECK_ARG(env, result); - v8::Isolate* isolate = v8impl::V8IsolateFromJsEnv(e); + v8::Isolate* isolate = env->isolate; v8::Local context = isolate->GetCurrentContext(); v8::Local obj; - CHECK_TO_OBJECT(context, obj, object); + CHECK_TO_OBJECT(env, context, obj, object); v8::Local key; - CHECK_NEW_FROM_UTF8(isolate, key, utf8name); + CHECK_NEW_FROM_UTF8(env, key, utf8name); v8::Maybe has_maybe = obj->Has(context, key); - CHECK_MAYBE_NOTHING(has_maybe, napi_generic_failure); + CHECK_MAYBE_NOTHING(env, has_maybe, napi_generic_failure); *result = has_maybe.FromMaybe(false); - return GET_RETURN_STATUS(); + return GET_RETURN_STATUS(env); } -napi_status napi_get_named_property(napi_env e, +napi_status napi_get_named_property(napi_env env, napi_value object, const char* utf8name, napi_value* result) { - NAPI_PREAMBLE(e); - CHECK_ARG(result); + NAPI_PREAMBLE(env); + CHECK_ARG(env, result); - v8::Isolate* isolate = v8impl::V8IsolateFromJsEnv(e); + v8::Isolate* isolate = env->isolate; v8::Local context = isolate->GetCurrentContext(); v8::Local key; - CHECK_NEW_FROM_UTF8(isolate, key, utf8name); + CHECK_NEW_FROM_UTF8(env, key, utf8name); v8::Local obj; - CHECK_TO_OBJECT(context, obj, object); + CHECK_TO_OBJECT(env, context, obj, object); auto get_maybe = obj->Get(context, key); - CHECK_MAYBE_EMPTY(get_maybe, napi_generic_failure); + CHECK_MAYBE_EMPTY(env, get_maybe, napi_generic_failure); v8::Local val = get_maybe.ToLocalChecked(); *result = v8impl::JsValueFromV8LocalValue(val); - return GET_RETURN_STATUS(); + return GET_RETURN_STATUS(env); } -napi_status napi_set_element(napi_env e, +napi_status napi_set_element(napi_env env, napi_value object, uint32_t index, napi_value value) { - NAPI_PREAMBLE(e); + NAPI_PREAMBLE(env); - v8::Isolate* isolate = v8impl::V8IsolateFromJsEnv(e); + v8::Isolate* isolate = env->isolate; v8::Local context = isolate->GetCurrentContext(); v8::Local obj; - CHECK_TO_OBJECT(context, obj, object); + CHECK_TO_OBJECT(env, context, obj, object); v8::Local val = v8impl::V8LocalValueFromJsValue(value); auto set_maybe = obj->Set(context, index, val); - RETURN_STATUS_IF_FALSE(set_maybe.FromMaybe(false), napi_generic_failure); + RETURN_STATUS_IF_FALSE(env, set_maybe.FromMaybe(false), napi_generic_failure); - return GET_RETURN_STATUS(); + return GET_RETURN_STATUS(env); } -napi_status napi_has_element(napi_env e, +napi_status napi_has_element(napi_env env, napi_value object, uint32_t index, bool* result) { - NAPI_PREAMBLE(e); - CHECK_ARG(result); + NAPI_PREAMBLE(env); + CHECK_ARG(env, result); - v8::Isolate* isolate = v8impl::V8IsolateFromJsEnv(e); + v8::Isolate* isolate = env->isolate; v8::Local context = isolate->GetCurrentContext(); v8::Local obj; - CHECK_TO_OBJECT(context, obj, object); + CHECK_TO_OBJECT(env, context, obj, object); v8::Maybe has_maybe = obj->Has(context, index); - CHECK_MAYBE_NOTHING(has_maybe, napi_generic_failure); + CHECK_MAYBE_NOTHING(env, has_maybe, napi_generic_failure); *result = has_maybe.FromMaybe(false); - return GET_RETURN_STATUS(); + return GET_RETURN_STATUS(env); } -napi_status napi_get_element(napi_env e, +napi_status napi_get_element(napi_env env, napi_value object, uint32_t index, napi_value* result) { - NAPI_PREAMBLE(e); - CHECK_ARG(result); + NAPI_PREAMBLE(env); + CHECK_ARG(env, result); - v8::Isolate* isolate = v8impl::V8IsolateFromJsEnv(e); + v8::Isolate* isolate = env->isolate; v8::Local context = isolate->GetCurrentContext(); v8::Local obj; - CHECK_TO_OBJECT(context, obj, object); + CHECK_TO_OBJECT(env, context, obj, object); auto get_maybe = obj->Get(context, index); - CHECK_MAYBE_EMPTY(get_maybe, napi_generic_failure); + CHECK_MAYBE_EMPTY(env, get_maybe, napi_generic_failure); *result = v8impl::JsValueFromV8LocalValue(get_maybe.ToLocalChecked()); - return GET_RETURN_STATUS(); + return GET_RETURN_STATUS(env); } -napi_status napi_define_properties(napi_env e, +napi_status napi_define_properties(napi_env env, napi_value object, - int property_count, + size_t property_count, const napi_property_descriptor* properties) { - NAPI_PREAMBLE(e); + NAPI_PREAMBLE(env); - v8::Isolate* isolate = v8impl::V8IsolateFromJsEnv(e); + v8::Isolate* isolate = env->isolate; v8::Local context = isolate->GetCurrentContext(); v8::Local obj = v8impl::V8LocalValueFromJsValue(object).As(); - for (int i = 0; i < property_count; i++) { + for (size_t i = 0; i < property_count; i++) { const napi_property_descriptor* p = &properties[i]; - v8::Local name; - CHECK_NEW_FROM_UTF8(isolate, name, p->utf8name); + v8::Local property_name; + napi_status status = + v8impl::V8NameFromPropertyDescriptor(env, p, &property_name); - v8::PropertyAttribute attributes = static_cast( - p->attributes & ~napi_static_property); + if (status != napi_ok) { + return napi_set_last_error(env, status); + } - if (p->method) { + v8::PropertyAttribute attributes = + v8impl::V8PropertyAttributesFromDescriptor(p); + + if (p->getter != nullptr || p->setter != nullptr) { + v8::Local cbdata = v8impl::CreateAccessorCallbackData( + env, + p->getter, + p->setter, + p->data); + + auto set_maybe = obj->SetAccessor( + context, + property_name, + p->getter ? v8impl::GetterCallbackWrapper::Invoke : nullptr, + p->setter ? v8impl::SetterCallbackWrapper::Invoke : nullptr, + cbdata, + v8::AccessControl::DEFAULT, + attributes); + + if (!set_maybe.FromMaybe(false)) { + return napi_set_last_error(env, napi_invalid_arg); + } + } else if (p->method != nullptr) { v8::Local cbdata = - v8impl::CreateFunctionCallbackData(e, p->method, p->data); + v8impl::CreateFunctionCallbackData(env, p->method, p->data); - RETURN_STATUS_IF_FALSE(!cbdata.IsEmpty(), napi_generic_failure); + RETURN_STATUS_IF_FALSE(env, !cbdata.IsEmpty(), napi_generic_failure); v8::Local t = v8::FunctionTemplate::New( isolate, v8impl::FunctionCallbackWrapper::Invoke, cbdata); - auto define_maybe = - obj->DefineOwnProperty(context, name, t->GetFunction(), attributes); + auto define_maybe = obj->DefineOwnProperty( + context, property_name, t->GetFunction(), attributes); - // IsNothing seems like a serious failure, - // should we return a different error code if the define failed? - if (define_maybe.IsNothing() || !define_maybe.FromMaybe(false)) { - return napi_set_last_error(napi_generic_failure); - } - } else if (p->getter || p->setter) { - v8::Local cbdata = - v8impl::CreateAccessorCallbackData(e, p->getter, p->setter, p->data); - - auto set_maybe = obj->SetAccessor( - context, - name, - v8impl::GetterCallbackWrapper::Invoke, - p->setter ? v8impl::SetterCallbackWrapper::Invoke : nullptr, - cbdata, - v8::AccessControl::DEFAULT, - attributes); - - // IsNothing seems like a serious failure, - // should we return a different error code if the set failed? - if (set_maybe.IsNothing() || !set_maybe.FromMaybe(false)) { - return napi_set_last_error(napi_generic_failure); + if (!define_maybe.FromMaybe(false)) { + return napi_set_last_error(env, napi_generic_failure); } } else { v8::Local value = v8impl::V8LocalValueFromJsValue(p->value); auto define_maybe = - obj->DefineOwnProperty(context, name, value, attributes); + obj->DefineOwnProperty(context, property_name, value, attributes); - // IsNothing seems like a serious failure, - // should we return a different error code if the define failed? - if (define_maybe.IsNothing() || !define_maybe.FromMaybe(false)) { - return napi_set_last_error(napi_generic_failure); + if (!define_maybe.FromMaybe(false)) { + return napi_set_last_error(env, napi_invalid_arg); } } } - return GET_RETURN_STATUS(); + return GET_RETURN_STATUS(env); } -napi_status napi_is_array(napi_env e, napi_value value, bool* result) { - NAPI_PREAMBLE(e); - CHECK_ARG(result); +napi_status napi_is_array(napi_env env, napi_value value, bool* result) { + NAPI_PREAMBLE(env); + CHECK_ARG(env, result); v8::Local val = v8impl::V8LocalValueFromJsValue(value); *result = val->IsArray(); - return GET_RETURN_STATUS(); + return GET_RETURN_STATUS(env); } -napi_status napi_get_array_length(napi_env e, +napi_status napi_get_array_length(napi_env env, napi_value value, uint32_t* result) { - NAPI_PREAMBLE(e); - CHECK_ARG(result); + NAPI_PREAMBLE(env); + CHECK_ARG(env, result); - // TODO(boingoing): Should this also check to see if v is an array before - // blindly casting it? - v8::Local arr = - v8impl::V8LocalValueFromJsValue(value).As(); + v8::Local val = v8impl::V8LocalValueFromJsValue(value); + RETURN_STATUS_IF_FALSE(env, val->IsArray(), napi_array_expected); + v8::Local arr = val.As(); *result = arr->Length(); - return GET_RETURN_STATUS(); + + return GET_RETURN_STATUS(env); } -napi_status napi_strict_equals(napi_env e, +napi_status napi_strict_equals(napi_env env, napi_value lhs, napi_value rhs, bool* result) { - NAPI_PREAMBLE(e); - CHECK_ARG(result); + NAPI_PREAMBLE(env); + CHECK_ARG(env, result); v8::Local a = v8impl::V8LocalValueFromJsValue(lhs); v8::Local b = v8impl::V8LocalValueFromJsValue(rhs); *result = a->StrictEquals(b); - return GET_RETURN_STATUS(); + return GET_RETURN_STATUS(env); } -napi_status napi_get_prototype(napi_env e, +napi_status napi_get_prototype(napi_env env, napi_value object, napi_value* result) { - NAPI_PREAMBLE(e); - CHECK_ARG(result); + NAPI_PREAMBLE(env); + CHECK_ARG(env, result); - v8::Isolate* isolate = v8impl::V8IsolateFromJsEnv(e); + v8::Isolate* isolate = env->isolate; v8::Local context = isolate->GetCurrentContext(); v8::Local obj; - CHECK_TO_OBJECT(context, obj, object); + CHECK_TO_OBJECT(env, context, obj, object); v8::Local val = obj->GetPrototype(); *result = v8impl::JsValueFromV8LocalValue(val); - return GET_RETURN_STATUS(); + return GET_RETURN_STATUS(env); } -napi_status napi_create_object(napi_env e, napi_value* result) { - NAPI_PREAMBLE(e); - CHECK_ARG(result); +napi_status napi_create_object(napi_env env, napi_value* result) { + NAPI_PREAMBLE(env); + CHECK_ARG(env, result); *result = v8impl::JsValueFromV8LocalValue( - v8::Object::New(v8impl::V8IsolateFromJsEnv(e))); + v8::Object::New(env->isolate)); - return GET_RETURN_STATUS(); + return GET_RETURN_STATUS(env); } -napi_status napi_create_array(napi_env e, napi_value* result) { - NAPI_PREAMBLE(e); - CHECK_ARG(result); +napi_status napi_create_array(napi_env env, napi_value* result) { + NAPI_PREAMBLE(env); + CHECK_ARG(env, result); *result = v8impl::JsValueFromV8LocalValue( - v8::Array::New(v8impl::V8IsolateFromJsEnv(e))); + v8::Array::New(env->isolate)); - return GET_RETURN_STATUS(); + return GET_RETURN_STATUS(env); } -napi_status napi_create_array_with_length(napi_env e, - int length, +napi_status napi_create_array_with_length(napi_env env, + size_t length, napi_value* result) { - NAPI_PREAMBLE(e); - CHECK_ARG(result); + NAPI_PREAMBLE(env); + CHECK_ARG(env, result); *result = v8impl::JsValueFromV8LocalValue( - v8::Array::New(v8impl::V8IsolateFromJsEnv(e), length)); + v8::Array::New(env->isolate, length)); - return GET_RETURN_STATUS(); + return GET_RETURN_STATUS(env); } -napi_status napi_create_string_utf8(napi_env e, - const char* s, - int length, +napi_status napi_create_string_utf8(napi_env env, + const char* str, + size_t length, napi_value* result) { - NAPI_PREAMBLE(e); - CHECK_ARG(result); + NAPI_PREAMBLE(env); + CHECK_ARG(env, result); - auto isolate = v8impl::V8IsolateFromJsEnv(e); - v8::Local str; - CHECK_NEW_FROM_UTF8_LEN(isolate, str, s, length); + v8::Local s; + CHECK_NEW_FROM_UTF8_LEN(env, s, str, length); - *result = v8impl::JsValueFromV8LocalValue(str); - return GET_RETURN_STATUS(); + *result = v8impl::JsValueFromV8LocalValue(s); + return GET_RETURN_STATUS(env); } -napi_status napi_create_string_utf16(napi_env e, - const char16_t* s, - int length, +napi_status napi_create_string_utf16(napi_env env, + const char16_t* str, + size_t length, napi_value* result) { - NAPI_PREAMBLE(e); - CHECK_ARG(result); + NAPI_PREAMBLE(env); + CHECK_ARG(env, result); - auto isolate = v8impl::V8IsolateFromJsEnv(e); + auto isolate = env->isolate; auto str_maybe = v8::String::NewFromTwoByte(isolate, - reinterpret_cast(s), + reinterpret_cast(str), v8::NewStringType::kInternalized, length); - CHECK_MAYBE_EMPTY(str_maybe, napi_generic_failure); - v8::Local str = str_maybe.ToLocalChecked(); + CHECK_MAYBE_EMPTY(env, str_maybe, napi_generic_failure); - *result = v8impl::JsValueFromV8LocalValue(str); - return GET_RETURN_STATUS(); + *result = v8impl::JsValueFromV8LocalValue(str_maybe.ToLocalChecked()); + return GET_RETURN_STATUS(env); } -napi_status napi_create_number(napi_env e, double v, napi_value* result) { - NAPI_PREAMBLE(e); - CHECK_ARG(result); +napi_status napi_create_number(napi_env env, + double value, + napi_value* result) { + NAPI_PREAMBLE(env); + CHECK_ARG(env, result); *result = v8impl::JsValueFromV8LocalValue( - v8::Number::New(v8impl::V8IsolateFromJsEnv(e), v)); + v8::Number::New(env->isolate, value)); - return GET_RETURN_STATUS(); + return GET_RETURN_STATUS(env); } -napi_status napi_create_boolean(napi_env e, bool b, napi_value* result) { - NAPI_PREAMBLE(e); - CHECK_ARG(result); +napi_status napi_get_boolean(napi_env env, bool value, napi_value* result) { + CHECK_ENV(env); + CHECK_ARG(env, result); - *result = v8impl::JsValueFromV8LocalValue( - v8::Boolean::New(v8impl::V8IsolateFromJsEnv(e), b)); + v8::Isolate* isolate = env->isolate; + + if (value) { + *result = v8impl::JsValueFromV8LocalValue(v8::True(isolate)); + } else { + *result = v8impl::JsValueFromV8LocalValue(v8::False(isolate)); + } - return GET_RETURN_STATUS(); + return napi_ok; } -napi_status napi_create_symbol(napi_env e, const char* s, napi_value* result) { - NAPI_PREAMBLE(e); - CHECK_ARG(result); +napi_status napi_create_symbol(napi_env env, + napi_value description, + napi_value* result) { + NAPI_PREAMBLE(env); + CHECK_ARG(env, result); + + v8::Isolate* isolate = env->isolate; - v8::Isolate* isolate = v8impl::V8IsolateFromJsEnv(e); - if (s == nullptr) { + if (description == nullptr) { *result = v8impl::JsValueFromV8LocalValue(v8::Symbol::New(isolate)); } else { - v8::Local string; - CHECK_NEW_FROM_UTF8(isolate, string, s); + v8::Local desc = v8impl::V8LocalValueFromJsValue(description); + RETURN_STATUS_IF_FALSE(env, desc->IsString(), napi_string_expected); - *result = v8impl::JsValueFromV8LocalValue(v8::Symbol::New(isolate, string)); + *result = v8impl::JsValueFromV8LocalValue( + v8::Symbol::New(isolate, desc.As())); } - return GET_RETURN_STATUS(); + return GET_RETURN_STATUS(env); } -napi_status napi_create_error(napi_env e, napi_value msg, napi_value* result) { - NAPI_PREAMBLE(e); - CHECK_ARG(result); +napi_status napi_create_error(napi_env env, + napi_value msg, + napi_value* result) { + NAPI_PREAMBLE(env); + CHECK_ARG(env, result); + + v8::Local message_value = v8impl::V8LocalValueFromJsValue(msg); + RETURN_STATUS_IF_FALSE(env, message_value->IsString(), napi_string_expected); *result = v8impl::JsValueFromV8LocalValue(v8::Exception::Error( - v8impl::V8LocalValueFromJsValue(msg).As())); + message_value.As())); - return GET_RETURN_STATUS(); + return GET_RETURN_STATUS(env); } -napi_status napi_create_type_error(napi_env e, +napi_status napi_create_type_error(napi_env env, napi_value msg, napi_value* result) { - NAPI_PREAMBLE(e); - CHECK_ARG(result); + NAPI_PREAMBLE(env); + CHECK_ARG(env, result); + + v8::Local message_value = v8impl::V8LocalValueFromJsValue(msg); + RETURN_STATUS_IF_FALSE(env, message_value->IsString(), napi_string_expected); *result = v8impl::JsValueFromV8LocalValue(v8::Exception::TypeError( - v8impl::V8LocalValueFromJsValue(msg).As())); + message_value.As())); - return GET_RETURN_STATUS(); + return GET_RETURN_STATUS(env); } -napi_status napi_create_range_error(napi_env e, +napi_status napi_create_range_error(napi_env env, napi_value msg, napi_value* result) { - NAPI_PREAMBLE(e); - CHECK_ARG(result); + NAPI_PREAMBLE(env); + CHECK_ARG(env, result); + + v8::Local message_value = v8impl::V8LocalValueFromJsValue(msg); + RETURN_STATUS_IF_FALSE(env, message_value->IsString(), napi_string_expected); *result = v8impl::JsValueFromV8LocalValue(v8::Exception::RangeError( - v8impl::V8LocalValueFromJsValue(msg).As())); + message_value.As())); - return GET_RETURN_STATUS(); + return GET_RETURN_STATUS(env); } -napi_status napi_get_type_of_value(napi_env e, - napi_value value, - napi_valuetype* result) { +napi_status napi_typeof(napi_env env, + napi_value value, + napi_valuetype* result) { // Omit NAPI_PREAMBLE and GET_RETURN_STATUS because V8 calls here cannot throw // JS exceptions. - CHECK_ARG(result); + CHECK_ENV(env); + CHECK_ARG(env, result); v8::Local v = v8impl::V8LocalValueFromJsValue(value); @@ -1285,95 +1425,70 @@ napi_status napi_get_type_of_value(napi_env e, } else if (v->IsExternal()) { *result = napi_external; } else { - *result = napi_object; // Is this correct? + // Should not get here unless V8 has added some new kind of value. + return napi_set_last_error(env, napi_invalid_arg); } return napi_ok; } -napi_status napi_get_undefined(napi_env e, napi_value* result) { - NAPI_PREAMBLE(e); - CHECK_ARG(result); +napi_status napi_get_undefined(napi_env env, napi_value* result) { + CHECK_ENV(env); + CHECK_ARG(env, result); *result = v8impl::JsValueFromV8LocalValue( - v8::Undefined(v8impl::V8IsolateFromJsEnv(e))); - - return GET_RETURN_STATUS(); -} - -napi_status napi_get_null(napi_env e, napi_value* result) { - NAPI_PREAMBLE(e); - CHECK_ARG(result); - - *result = - v8impl::JsValueFromV8LocalValue(v8::Null(v8impl::V8IsolateFromJsEnv(e))); + v8::Undefined(env->isolate)); - return GET_RETURN_STATUS(); -} - -napi_status napi_get_false(napi_env e, napi_value* result) { - NAPI_PREAMBLE(e); - CHECK_ARG(result); - - *result = - v8impl::JsValueFromV8LocalValue(v8::False(v8impl::V8IsolateFromJsEnv(e))); - - return GET_RETURN_STATUS(); + return napi_ok; } -napi_status napi_get_true(napi_env e, napi_value* result) { - NAPI_PREAMBLE(e); - CHECK_ARG(result); +napi_status napi_get_null(napi_env env, napi_value* result) { + CHECK_ENV(env); + CHECK_ARG(env, result); - *result = - v8impl::JsValueFromV8LocalValue(v8::True(v8impl::V8IsolateFromJsEnv(e))); + *result = v8impl::JsValueFromV8LocalValue( + v8::Null(env->isolate)); - return GET_RETURN_STATUS(); + return napi_ok; } // Gets all callback info in a single call. (Ugly, but faster.) napi_status napi_get_cb_info( - napi_env e, // [in] NAPI environment handle + napi_env env, // [in] NAPI environment handle napi_callback_info cbinfo, // [in] Opaque callback-info handle - int* argc, // [in-out] Specifies the size of the provided argv array + size_t* argc, // [in-out] Specifies the size of the provided argv array // and receives the actual count of args. napi_value* argv, // [out] Array of values - napi_value* thisArg, // [out] Receives the JS 'this' arg for the call - void** data) { // [out] Receives the data pointer for the callback. - CHECK_ARG(argc); - CHECK_ARG(argv); - CHECK_ARG(thisArg); - CHECK_ARG(data); + napi_value* this_arg, // [out] Receives the JS 'this' arg for the call + void** data) { // [out] Receives the data pointer for the callback. + CHECK_ENV(env); v8impl::CallbackWrapper* info = reinterpret_cast(cbinfo); - info->Args(argv, std::min(*argc, info->ArgsLength())); - *argc = info->ArgsLength(); - *thisArg = info->This(); - *data = info->Data(); - - return napi_ok; -} - -napi_status napi_get_cb_args_length(napi_env e, - napi_callback_info cbinfo, - int* result) { - // Omit NAPI_PREAMBLE and GET_RETURN_STATUS because no V8 APIs are called. - CHECK_ARG(result); - - v8impl::CallbackWrapper* info = - reinterpret_cast(cbinfo); + if (argv != nullptr) { + CHECK_ARG(env, argc); + info->Args(argv, std::min(*argc, info->ArgsLength())); + } + if (argc != nullptr) { + *argc = info->ArgsLength(); + } + if (this_arg != nullptr) { + *this_arg = info->This(); + } + if (data != nullptr) { + *data = info->Data(); + } - *result = info->ArgsLength(); return napi_ok; } -napi_status napi_is_construct_call(napi_env e, +napi_status napi_is_construct_call(napi_env env, napi_callback_info cbinfo, bool* result) { // Omit NAPI_PREAMBLE and GET_RETURN_STATUS because no V8 APIs are called. - CHECK_ARG(result); + CHECK_ENV(env); + CHECK_ARG(env, result); v8impl::CallbackWrapper* info = reinterpret_cast(cbinfo); @@ -1382,113 +1497,55 @@ napi_status napi_is_construct_call(napi_env e, return napi_ok; } -// copy encoded arguments into provided buffer or return direct pointer to -// encoded arguments array? -napi_status napi_get_cb_args(napi_env e, - napi_callback_info cbinfo, - napi_value* buffer, - int bufferlength) { - // Omit NAPI_PREAMBLE and GET_RETURN_STATUS because no V8 APIs are called. - CHECK_ARG(buffer); - - v8impl::CallbackWrapper* info = - reinterpret_cast(cbinfo); - - info->Args(buffer, bufferlength); - return napi_ok; -} - -napi_status napi_get_cb_this(napi_env e, - napi_callback_info cbinfo, - napi_value* result) { - // Omit NAPI_PREAMBLE and GET_RETURN_STATUS because no V8 APIs are called. - CHECK_ARG(result); - - v8impl::CallbackWrapper* info = - reinterpret_cast(cbinfo); - - *result = info->This(); - return napi_ok; -} - -// Holder is a V8 concept. Is not clear if this can be emulated with other VMs -// AFAIK Holder should be the owner of the JS function, which should be in the -// prototype chain of This, so maybe it is possible to emulate. -napi_status napi_get_cb_holder(napi_env e, - napi_callback_info cbinfo, - napi_value* result) { - // Omit NAPI_PREAMBLE and GET_RETURN_STATUS because no V8 APIs are called. - CHECK_ARG(result); - - v8impl::CallbackWrapper* info = - reinterpret_cast(cbinfo); - - *result = info->Holder(); - return napi_ok; -} - -napi_status napi_get_cb_data(napi_env e, - napi_callback_info cbinfo, - void** result) { - // Omit NAPI_PREAMBLE and GET_RETURN_STATUS because no V8 APIs are called. - CHECK_ARG(result); - - v8impl::CallbackWrapper* info = - reinterpret_cast(cbinfo); - - *result = info->Data(); - return napi_ok; -} - -napi_status napi_call_function(napi_env e, +napi_status napi_call_function(napi_env env, napi_value recv, napi_value func, - int argc, + size_t argc, const napi_value* argv, napi_value* result) { - NAPI_PREAMBLE(e); - CHECK_ARG(result); + NAPI_PREAMBLE(env); - std::vector> args(argc); - v8::Isolate* isolate = v8impl::V8IsolateFromJsEnv(e); + v8::Isolate* isolate = env->isolate; v8::Local context = isolate->GetCurrentContext(); - v8::Handle v8recv = v8impl::V8LocalValueFromJsValue(recv); + v8::Local v8recv = v8impl::V8LocalValueFromJsValue(recv); - for (int i = 0; i < argc; i++) { - args[i] = v8impl::V8LocalValueFromJsValue(argv[i]); - } + v8::Local v8value = v8impl::V8LocalValueFromJsValue(func); + RETURN_STATUS_IF_FALSE(env, v8value->IsFunction(), napi_invalid_arg); - v8::Local v8func = v8impl::V8LocalFunctionFromJsValue(func); - auto maybe = v8func->Call(context, v8recv, argc, args.data()); + v8::Local v8func = v8value.As(); + auto maybe = v8func->Call(context, v8recv, argc, + reinterpret_cast*>(const_cast(argv))); - if (tryCatch.HasCaught()) { - return napi_set_last_error(napi_pending_exception); + if (try_catch.HasCaught()) { + return napi_set_last_error(env, napi_pending_exception); } else { - CHECK_MAYBE_EMPTY(maybe, napi_generic_failure); - *result = v8impl::JsValueFromV8LocalValue(maybe.ToLocalChecked()); + if (result != nullptr) { + CHECK_MAYBE_EMPTY(env, maybe, napi_generic_failure); + *result = v8impl::JsValueFromV8LocalValue(maybe.ToLocalChecked()); + } return napi_ok; } } -napi_status napi_get_global(napi_env e, napi_value* result) { - NAPI_PREAMBLE(e); - CHECK_ARG(result); +napi_status napi_get_global(napi_env env, napi_value* result) { + CHECK_ENV(env); + CHECK_ARG(env, result); - v8::Isolate* isolate = v8impl::V8IsolateFromJsEnv(e); + v8::Isolate* isolate = env->isolate; // TODO(ianhall): what if we need the global object from a different // context in the same isolate? // Should napi_env be the current context rather than the current isolate? v8::Local context = isolate->GetCurrentContext(); *result = v8impl::JsValueFromV8LocalValue(context->Global()); - return GET_RETURN_STATUS(); + return napi_ok; } -napi_status napi_throw(napi_env e, napi_value error) { - NAPI_PREAMBLE(e); +napi_status napi_throw(napi_env env, napi_value error) { + NAPI_PREAMBLE(env); - v8::Isolate* isolate = v8impl::V8IsolateFromJsEnv(e); + v8::Isolate* isolate = env->isolate; isolate->ThrowException(v8impl::V8LocalValueFromJsValue(error)); // any VM calls after this point and before returning @@ -1496,12 +1553,12 @@ napi_status napi_throw(napi_env e, napi_value error) { return napi_ok; } -napi_status napi_throw_error(napi_env e, const char* msg) { - NAPI_PREAMBLE(e); +napi_status napi_throw_error(napi_env env, const char* msg) { + NAPI_PREAMBLE(env); - v8::Isolate* isolate = v8impl::V8IsolateFromJsEnv(e); + v8::Isolate* isolate = env->isolate; v8::Local str; - CHECK_NEW_FROM_UTF8(isolate, str, msg); + CHECK_NEW_FROM_UTF8(env, str, msg); isolate->ThrowException(v8::Exception::Error(str)); // any VM calls after this point and before returning @@ -1509,12 +1566,12 @@ napi_status napi_throw_error(napi_env e, const char* msg) { return napi_ok; } -napi_status napi_throw_type_error(napi_env e, const char* msg) { - NAPI_PREAMBLE(e); +napi_status napi_throw_type_error(napi_env env, const char* msg) { + NAPI_PREAMBLE(env); - v8::Isolate* isolate = v8impl::V8IsolateFromJsEnv(e); + v8::Isolate* isolate = env->isolate; v8::Local str; - CHECK_NEW_FROM_UTF8(isolate, str, msg); + CHECK_NEW_FROM_UTF8(env, str, msg); isolate->ThrowException(v8::Exception::TypeError(str)); // any VM calls after this point and before returning @@ -1522,12 +1579,12 @@ napi_status napi_throw_type_error(napi_env e, const char* msg) { return napi_ok; } -napi_status napi_throw_range_error(napi_env e, const char* msg) { - NAPI_PREAMBLE(e); +napi_status napi_throw_range_error(napi_env env, const char* msg) { + NAPI_PREAMBLE(env); - v8::Isolate* isolate = v8impl::V8IsolateFromJsEnv(e); + v8::Isolate* isolate = env->isolate; v8::Local str; - CHECK_NEW_FROM_UTF8(isolate, str, msg); + CHECK_NEW_FROM_UTF8(env, str, msg); isolate->ThrowException(v8::Exception::RangeError(str)); // any VM calls after this point and before returning @@ -1535,10 +1592,11 @@ napi_status napi_throw_range_error(napi_env e, const char* msg) { return napi_ok; } -napi_status napi_is_error(napi_env e, napi_value value, bool* result) { - // Omit NAPI_PREAMBLE and GET_RETURN_STATUS because V8 calls here cannot throw - // JS exceptions. - CHECK_ARG(result); +napi_status napi_is_error(napi_env env, napi_value value, bool* result) { + // Omit NAPI_PREAMBLE and GET_RETURN_STATUS because V8 calls here cannot + // throw JS exceptions. + CHECK_ENV(env); + CHECK_ARG(env, result); v8::Local val = v8impl::V8LocalValueFromJsValue(value); *result = val->IsNativeError(); @@ -1546,73 +1604,96 @@ napi_status napi_is_error(napi_env e, napi_value value, bool* result) { return napi_ok; } -napi_status napi_get_value_double(napi_env e, +napi_status napi_get_value_double(napi_env env, napi_value value, double* result) { // Omit NAPI_PREAMBLE and GET_RETURN_STATUS because V8 calls here cannot throw // JS exceptions. - CHECK_ARG(result); + CHECK_ENV(env); + CHECK_ARG(env, value); + CHECK_ARG(env, result); v8::Local val = v8impl::V8LocalValueFromJsValue(value); - RETURN_STATUS_IF_FALSE(val->IsNumber(), napi_number_expected); + RETURN_STATUS_IF_FALSE(env, val->IsNumber(), napi_number_expected); *result = val.As()->Value(); return napi_ok; } -napi_status napi_get_value_int32(napi_env e, +napi_status napi_get_value_int32(napi_env env, napi_value value, int32_t* result) { // Omit NAPI_PREAMBLE and GET_RETURN_STATUS because V8 calls here cannot throw // JS exceptions. - CHECK_ARG(result); + CHECK_ENV(env); + CHECK_ARG(env, value); + CHECK_ARG(env, result); v8::Local val = v8impl::V8LocalValueFromJsValue(value); - RETURN_STATUS_IF_FALSE(val->IsNumber(), napi_number_expected); + RETURN_STATUS_IF_FALSE(env, val->IsNumber(), napi_number_expected); - *result = val.As()->Value(); + v8::Isolate* isolate = env->isolate; + v8::Local context = isolate->GetCurrentContext(); + *result = val->Int32Value(context).FromJust(); return napi_ok; } -napi_status napi_get_value_uint32(napi_env e, +napi_status napi_get_value_uint32(napi_env env, napi_value value, uint32_t* result) { // Omit NAPI_PREAMBLE and GET_RETURN_STATUS because V8 calls here cannot throw // JS exceptions. - CHECK_ARG(result); + CHECK_ENV(env); + CHECK_ARG(env, value); + CHECK_ARG(env, result); v8::Local val = v8impl::V8LocalValueFromJsValue(value); - RETURN_STATUS_IF_FALSE(val->IsNumber(), napi_number_expected); + RETURN_STATUS_IF_FALSE(env, val->IsNumber(), napi_number_expected); - *result = val.As()->Value(); + v8::Isolate* isolate = env->isolate; + v8::Local context = isolate->GetCurrentContext(); + *result = val->Uint32Value(context).FromJust(); return napi_ok; } -napi_status napi_get_value_int64(napi_env e, +napi_status napi_get_value_int64(napi_env env, napi_value value, int64_t* result) { // Omit NAPI_PREAMBLE and GET_RETURN_STATUS because V8 calls here cannot throw // JS exceptions. - CHECK_ARG(result); + CHECK_ENV(env); + CHECK_ARG(env, value); + CHECK_ARG(env, result); v8::Local val = v8impl::V8LocalValueFromJsValue(value); - RETURN_STATUS_IF_FALSE(val->IsNumber(), napi_number_expected); + RETURN_STATUS_IF_FALSE(env, val->IsNumber(), napi_number_expected); - *result = val.As()->Value(); + // v8::Value::IntegerValue() converts NaN to INT64_MIN, inconsistent with + // v8::Value::Int32Value() that converts NaN to 0. So special-case NaN here. + double doubleValue = val.As()->Value(); + if (std::isnan(doubleValue)) { + *result = 0; + } else { + v8::Isolate* isolate = env->isolate; + v8::Local context = isolate->GetCurrentContext(); + *result = val->IntegerValue(context).FromJust(); + } return napi_ok; } -napi_status napi_get_value_bool(napi_env e, napi_value value, bool* result) { +napi_status napi_get_value_bool(napi_env env, napi_value value, bool* result) { // Omit NAPI_PREAMBLE and GET_RETURN_STATUS because V8 calls here cannot throw // JS exceptions. - CHECK_ARG(result); + CHECK_ENV(env); + CHECK_ARG(env, value); + CHECK_ARG(env, result); v8::Local val = v8impl::V8LocalValueFromJsValue(value); - RETURN_STATUS_IF_FALSE(val->IsBoolean(), napi_boolean_expected); + RETURN_STATUS_IF_FALSE(env, val->IsBoolean(), napi_boolean_expected); *result = val.As()->Value(); @@ -1620,648 +1701,699 @@ napi_status napi_get_value_bool(napi_env e, napi_value value, bool* result) { } // Gets the number of CHARACTERS in the string. -napi_status napi_get_value_string_length(napi_env e, +napi_status napi_get_value_string_length(napi_env env, napi_value value, - int* result) { - NAPI_PREAMBLE(e); - CHECK_ARG(result); + size_t* result) { + NAPI_PREAMBLE(env); + CHECK_ARG(env, result); v8::Local val = v8impl::V8LocalValueFromJsValue(value); - RETURN_STATUS_IF_FALSE(val->IsString(), napi_string_expected); + RETURN_STATUS_IF_FALSE(env, val->IsString(), napi_string_expected); *result = val.As()->Length(); - return GET_RETURN_STATUS(); -} - -// Gets the number of BYTES in the UTF-8 encoded representation of the string. -napi_status napi_get_value_string_utf8_length(napi_env e, - napi_value value, - int* result) { - NAPI_PREAMBLE(e); - CHECK_ARG(result); - - v8::Local val = v8impl::V8LocalValueFromJsValue(value); - RETURN_STATUS_IF_FALSE(val->IsString(), napi_string_expected); - - *result = val.As()->Utf8Length(); - - return GET_RETURN_STATUS(); + return GET_RETURN_STATUS(env); } // Copies a JavaScript string into a UTF-8 string buffer. The result is the -// number -// of bytes copied into buf, including the null terminator. If the buf size is -// insufficient, the string will be truncated, including a null terminator. -napi_status napi_get_value_string_utf8(napi_env e, +// number of bytes copied into buf, including the null terminator. If bufsize +// is insufficient, the string will be truncated, including a null terminator. +// If buf is NULL, this method returns the length of the string (in bytes) +// via the result parameter. +// The result argument is optional unless buf is NULL. +napi_status napi_get_value_string_utf8(napi_env env, napi_value value, char* buf, - int bufsize, - int* result) { - NAPI_PREAMBLE(e); + size_t bufsize, + size_t* result) { + NAPI_PREAMBLE(env); v8::Local val = v8impl::V8LocalValueFromJsValue(value); - RETURN_STATUS_IF_FALSE(val->IsString(), napi_string_expected); + RETURN_STATUS_IF_FALSE(env, val->IsString(), napi_string_expected); - int copied = val.As()->WriteUtf8( + if (!buf) { + CHECK_ARG(env, result); + *result = val.As()->Utf8Length(); + } else { + int copied = val.As()->WriteUtf8( buf, bufsize, nullptr, v8::String::REPLACE_INVALID_UTF8); - if (result != nullptr) { - *result = copied; + if (result != nullptr) { + *result = copied; + } } - return GET_RETURN_STATUS(); -} - -// Gets the number of 2-byte code units in the UTF-16 encoded representation of -// the string. -napi_status napi_get_value_string_utf16_length(napi_env e, - napi_value value, - int* result) { - NAPI_PREAMBLE(e); - CHECK_ARG(result); - - v8::Local val = v8impl::V8LocalValueFromJsValue(value); - RETURN_STATUS_IF_FALSE(val->IsString(), napi_string_expected); - - // V8 assumes UTF-16 length is the same as the number of characters. - *result = val.As()->Length(); - - return GET_RETURN_STATUS(); + return GET_RETURN_STATUS(env); } // Copies a JavaScript string into a UTF-16 string buffer. The result is the -// number -// of 2-byte code units copied into buf, including the null terminator. If the -// buf -// size is insufficient, the string will be truncated, including a null -// terminator. -napi_status napi_get_value_string_utf16(napi_env e, +// number of 2-byte code units copied into buf, including the null terminator. +// If bufsize is insufficient, the string will be truncated, including a null +// terminator. If buf is NULL, this method returns the length of the string +// (in 2-byte code units) via the result parameter. +// The result argument is optional unless buf is NULL. +napi_status napi_get_value_string_utf16(napi_env env, napi_value value, char16_t* buf, - int bufsize, - int* result) { - NAPI_PREAMBLE(e); - CHECK_ARG(result); + size_t bufsize, + size_t* result) { + NAPI_PREAMBLE(env); v8::Local val = v8impl::V8LocalValueFromJsValue(value); - RETURN_STATUS_IF_FALSE(val->IsString(), napi_string_expected); + RETURN_STATUS_IF_FALSE(env, val->IsString(), napi_string_expected); - int copied = val.As()->Write( + if (!buf) { + CHECK_ARG(env, result); + // V8 assumes UTF-16 length is the same as the number of characters. + *result = val.As()->Length(); + } else { + int copied = val.As()->Write( reinterpret_cast(buf), 0, bufsize, v8::String::NO_OPTIONS); - if (result != nullptr) { - *result = copied; + if (result != nullptr) { + *result = copied; + } } - return GET_RETURN_STATUS(); + return GET_RETURN_STATUS(env); } -napi_status napi_coerce_to_object(napi_env e, +napi_status napi_coerce_to_object(napi_env env, napi_value value, napi_value* result) { - NAPI_PREAMBLE(e); - CHECK_ARG(result); + NAPI_PREAMBLE(env); + CHECK_ARG(env, result); - v8::Isolate* isolate = v8impl::V8IsolateFromJsEnv(e); + v8::Isolate* isolate = env->isolate; v8::Local context = isolate->GetCurrentContext(); v8::Local obj; - CHECK_TO_OBJECT(context, obj, value); + CHECK_TO_OBJECT(env, context, obj, value); *result = v8impl::JsValueFromV8LocalValue(obj); - return GET_RETURN_STATUS(); + return GET_RETURN_STATUS(env); } -napi_status napi_coerce_to_bool(napi_env e, +napi_status napi_coerce_to_bool(napi_env env, napi_value value, napi_value* result) { - NAPI_PREAMBLE(e); - CHECK_ARG(result); + NAPI_PREAMBLE(env); + CHECK_ARG(env, result); - v8::Isolate* isolate = v8impl::V8IsolateFromJsEnv(e); + v8::Isolate* isolate = env->isolate; v8::Local context = isolate->GetCurrentContext(); v8::Local b; - CHECK_TO_BOOL(context, b, value); + CHECK_TO_BOOL(env, context, b, value); *result = v8impl::JsValueFromV8LocalValue(b); - return GET_RETURN_STATUS(); + return GET_RETURN_STATUS(env); } -napi_status napi_coerce_to_number(napi_env e, +napi_status napi_coerce_to_number(napi_env env, napi_value value, napi_value* result) { - NAPI_PREAMBLE(e); - CHECK_ARG(result); + NAPI_PREAMBLE(env); + CHECK_ARG(env, result); - v8::Isolate* isolate = v8impl::V8IsolateFromJsEnv(e); + v8::Isolate* isolate = env->isolate; v8::Local context = isolate->GetCurrentContext(); v8::Local num; - CHECK_TO_NUMBER(context, num, value); + CHECK_TO_NUMBER(env, context, num, value); *result = v8impl::JsValueFromV8LocalValue(num); - return GET_RETURN_STATUS(); + return GET_RETURN_STATUS(env); } -napi_status napi_coerce_to_string(napi_env e, +napi_status napi_coerce_to_string(napi_env env, napi_value value, napi_value* result) { - NAPI_PREAMBLE(e); - CHECK_ARG(result); + NAPI_PREAMBLE(env); + CHECK_ARG(env, result); - v8::Isolate* isolate = v8impl::V8IsolateFromJsEnv(e); + v8::Isolate* isolate = env->isolate; v8::Local context = isolate->GetCurrentContext(); v8::Local str; - CHECK_TO_STRING(context, str, value); + CHECK_TO_STRING(env, context, str, value); *result = v8impl::JsValueFromV8LocalValue(str); - return GET_RETURN_STATUS(); + return GET_RETURN_STATUS(env); } -napi_status napi_wrap(napi_env e, - napi_value jsObject, - void* nativeObj, +napi_status napi_wrap(napi_env env, + napi_value js_object, + void* native_object, napi_finalize finalize_cb, void* finalize_hint, napi_ref* result) { - NAPI_PREAMBLE(e); - CHECK_ARG(jsObject); + NAPI_PREAMBLE(env); + CHECK_ARG(env, js_object); - v8::Isolate* isolate = v8impl::V8IsolateFromJsEnv(e); + v8::Isolate* isolate = env->isolate; v8::Local obj = - v8impl::V8LocalValueFromJsValue(jsObject).As(); + v8impl::V8LocalValueFromJsValue(js_object).As(); // Only objects that were created from a NAPI constructor's prototype // via napi_define_class() can be (un)wrapped. - RETURN_STATUS_IF_FALSE(obj->InternalFieldCount() > 0, napi_invalid_arg); + RETURN_STATUS_IF_FALSE(env, obj->InternalFieldCount() > 0, napi_invalid_arg); - obj->SetAlignedPointerInInternalField(0, nativeObj); + obj->SetInternalField(0, v8::External::New(isolate, native_object)); if (result != nullptr) { // The returned reference should be deleted via napi_delete_reference() // ONLY in response to the finalize callback invocation. (If it is deleted // before then, then the finalize callback will never be invoked.) // Therefore a finalize callback is required when returning a reference. - CHECK_ARG(finalize_cb); - v8impl::Reference* reference = new v8impl::Reference( - isolate, obj, 0, false, finalize_cb, nativeObj, finalize_hint); + CHECK_ARG(env, finalize_cb); + v8impl::Reference* reference = v8impl::Reference::New( + env, obj, 0, false, finalize_cb, native_object, finalize_hint); *result = reinterpret_cast(reference); } else if (finalize_cb != nullptr) { // Create a self-deleting reference just for the finalize callback. - new v8impl::Reference( - isolate, obj, 0, true, finalize_cb, nativeObj, finalize_hint); + v8impl::Reference::New( + env, obj, 0, true, finalize_cb, native_object, finalize_hint); } - return GET_RETURN_STATUS(); + return GET_RETURN_STATUS(env); } -napi_status napi_unwrap(napi_env e, napi_value jsObject, void** result) { +napi_status napi_unwrap(napi_env env, napi_value js_object, void** result) { // Omit NAPI_PREAMBLE and GET_RETURN_STATUS because V8 calls here cannot throw // JS exceptions. - CHECK_ARG(jsObject); - CHECK_ARG(result); + CHECK_ENV(env); + CHECK_ARG(env, js_object); + CHECK_ARG(env, result); - v8::Local obj = - v8impl::V8LocalValueFromJsValue(jsObject).As(); + v8::Local value = v8impl::V8LocalValueFromJsValue(js_object); + RETURN_STATUS_IF_FALSE(env, value->IsObject(), napi_invalid_arg); + v8::Local obj = value.As(); // Only objects that were created from a NAPI constructor's prototype // via napi_define_class() can be (un)wrapped. - RETURN_STATUS_IF_FALSE(obj->InternalFieldCount() > 0, napi_invalid_arg); + RETURN_STATUS_IF_FALSE(env, obj->InternalFieldCount() > 0, napi_invalid_arg); - *result = obj->GetAlignedPointerFromInternalField(0); + v8::Local unwrappedValue = obj->GetInternalField(0); + RETURN_STATUS_IF_FALSE(env, unwrappedValue->IsExternal(), napi_invalid_arg); + + *result = unwrappedValue.As()->Value(); return napi_ok; } -napi_status napi_create_external(napi_env e, +napi_status napi_create_external(napi_env env, void* data, napi_finalize finalize_cb, void* finalize_hint, napi_value* result) { - NAPI_PREAMBLE(e); - CHECK_ARG(result); + NAPI_PREAMBLE(env); + CHECK_ARG(env, result); - v8::Isolate* isolate = v8impl::V8IsolateFromJsEnv(e); + v8::Isolate* isolate = env->isolate; - v8::Local externalValue = v8::External::New(isolate, data); + v8::Local external_value = v8::External::New(isolate, data); // The Reference object will delete itself after invoking the finalizer // callback. - new v8impl::Reference(isolate, - externalValue, + v8impl::Reference::New(env, + external_value, 0, true, finalize_cb, data, finalize_hint); - *result = v8impl::JsValueFromV8LocalValue(externalValue); + *result = v8impl::JsValueFromV8LocalValue(external_value); - return GET_RETURN_STATUS(); + return GET_RETURN_STATUS(env); } -napi_status napi_get_value_external(napi_env e, +napi_status napi_get_value_external(napi_env env, napi_value value, void** result) { - NAPI_PREAMBLE(e); - CHECK_ARG(value); - CHECK_ARG(result); + NAPI_PREAMBLE(env); + CHECK_ARG(env, value); + CHECK_ARG(env, result); v8::Local val = v8impl::V8LocalValueFromJsValue(value); - RETURN_STATUS_IF_FALSE(val->IsExternal(), napi_invalid_arg); + RETURN_STATUS_IF_FALSE(env, val->IsExternal(), napi_invalid_arg); - v8::Local externalValue = val.As(); - *result = externalValue->Value(); + v8::Local external_value = val.As(); + *result = external_value->Value(); - return GET_RETURN_STATUS(); + return GET_RETURN_STATUS(env); } // Set initial_refcount to 0 for a weak reference, >0 for a strong reference. -napi_status napi_create_reference(napi_env e, +napi_status napi_create_reference(napi_env env, napi_value value, - int initial_refcount, + uint32_t initial_refcount, napi_ref* result) { - NAPI_PREAMBLE(e); - CHECK_ARG(result); - RETURN_STATUS_IF_FALSE(initial_refcount >= 0, napi_invalid_arg); - - v8::Isolate* isolate = v8impl::V8IsolateFromJsEnv(e); + NAPI_PREAMBLE(env); + CHECK_ARG(env, result); - v8impl::Reference* reference = new v8impl::Reference( - isolate, v8impl::V8LocalValueFromJsValue(value), initial_refcount, false); + v8impl::Reference* reference = v8impl::Reference::New( + env, v8impl::V8LocalValueFromJsValue(value), initial_refcount, false); *result = reinterpret_cast(reference); - return GET_RETURN_STATUS(); + return GET_RETURN_STATUS(env); } // Deletes a reference. The referenced value is released, and may be GC'd unless -// there -// are other references to it. -napi_status napi_delete_reference(napi_env e, napi_ref ref) { +// there are other references to it. +napi_status napi_delete_reference(napi_env env, napi_ref ref) { // Omit NAPI_PREAMBLE and GET_RETURN_STATUS because V8 calls here cannot throw // JS exceptions. - CHECK_ARG(ref); + CHECK_ENV(env); + CHECK_ARG(env, ref); - v8impl::Reference* reference = reinterpret_cast(ref); - delete reference; + v8impl::Reference::Delete(reinterpret_cast(ref)); return napi_ok; } // Increments the reference count, optionally returning the resulting count. -// After this call the -// reference will be a strong reference because its refcount is >0, and the -// referenced object is -// effectively "pinned". Calling this when the refcount is 0 and the object -// is unavailable +// After this call the reference will be a strong reference because its +// refcount is >0, and the referenced object is effectively "pinned". +// Calling this when the refcount is 0 and the object is unavailable // results in an error. -napi_status napi_reference_addref(napi_env e, napi_ref ref, int* result) { - NAPI_PREAMBLE(e); - CHECK_ARG(ref); +napi_status napi_reference_ref(napi_env env, napi_ref ref, uint32_t* result) { + NAPI_PREAMBLE(env); + CHECK_ARG(env, ref); v8impl::Reference* reference = reinterpret_cast(ref); - int count = reference->AddRef(); + uint32_t count = reference->Ref(); if (result != nullptr) { *result = count; } - return GET_RETURN_STATUS(); + return GET_RETURN_STATUS(env); } // Decrements the reference count, optionally returning the resulting count. If -// the result is -// 0 the reference is now weak and the object may be GC'd at any time if there -// are no other -// references. Calling this when the refcount is already 0 results in an error. -napi_status napi_reference_release(napi_env e, napi_ref ref, int* result) { - NAPI_PREAMBLE(e); - CHECK_ARG(ref); +// the result is 0 the reference is now weak and the object may be GC'd at any +// time if there are no other references. Calling this when the refcount is +// already 0 results in an error. +napi_status napi_reference_unref(napi_env env, napi_ref ref, uint32_t* result) { + NAPI_PREAMBLE(env); + CHECK_ARG(env, ref); v8impl::Reference* reference = reinterpret_cast(ref); - int count = reference->Release(); - if (count < 0) { - return napi_set_last_error(napi_generic_failure); + + if (reference->RefCount() == 0) { + return napi_set_last_error(env, napi_generic_failure); } + uint32_t count = reference->Unref(); + if (result != nullptr) { *result = count; } - return GET_RETURN_STATUS(); + return GET_RETURN_STATUS(env); } // Attempts to get a referenced value. If the reference is weak, the value might -// no longer be -// available, in that case the call is still successful but the result is NULL. -napi_status napi_get_reference_value(napi_env e, +// no longer be available, in that case the call is still successful but the +// result is NULL. +napi_status napi_get_reference_value(napi_env env, napi_ref ref, napi_value* result) { - NAPI_PREAMBLE(e); - CHECK_ARG(ref); - CHECK_ARG(result); + NAPI_PREAMBLE(env); + CHECK_ARG(env, ref); + CHECK_ARG(env, result); v8impl::Reference* reference = reinterpret_cast(ref); *result = v8impl::JsValueFromV8LocalValue(reference->Get()); - return GET_RETURN_STATUS(); + return GET_RETURN_STATUS(env); } -napi_status napi_open_handle_scope(napi_env e, napi_handle_scope* result) { - NAPI_PREAMBLE(e); - CHECK_ARG(result); +napi_status napi_open_handle_scope(napi_env env, napi_handle_scope* result) { + NAPI_PREAMBLE(env); + CHECK_ARG(env, result); *result = v8impl::JsHandleScopeFromV8HandleScope( - new v8impl::HandleScopeWrapper(v8impl::V8IsolateFromJsEnv(e))); - return GET_RETURN_STATUS(); + new v8impl::HandleScopeWrapper(env->isolate)); + return GET_RETURN_STATUS(env); } -napi_status napi_close_handle_scope(napi_env e, napi_handle_scope scope) { - NAPI_PREAMBLE(e); - CHECK_ARG(scope); +napi_status napi_close_handle_scope(napi_env env, napi_handle_scope scope) { + NAPI_PREAMBLE(env); + CHECK_ARG(env, scope); delete v8impl::V8HandleScopeFromJsHandleScope(scope); - return GET_RETURN_STATUS(); + return GET_RETURN_STATUS(env); } napi_status napi_open_escapable_handle_scope( - napi_env e, + napi_env env, napi_escapable_handle_scope* result) { - NAPI_PREAMBLE(e); - CHECK_ARG(result); + NAPI_PREAMBLE(env); + CHECK_ARG(env, result); *result = v8impl::JsEscapableHandleScopeFromV8EscapableHandleScope( - new v8impl::EscapableHandleScopeWrapper(v8impl::V8IsolateFromJsEnv(e))); - return GET_RETURN_STATUS(); + new v8impl::EscapableHandleScopeWrapper(env->isolate)); + return GET_RETURN_STATUS(env); } napi_status napi_close_escapable_handle_scope( - napi_env e, + napi_env env, napi_escapable_handle_scope scope) { - NAPI_PREAMBLE(e); - CHECK_ARG(scope); + NAPI_PREAMBLE(env); + CHECK_ARG(env, scope); delete v8impl::V8EscapableHandleScopeFromJsEscapableHandleScope(scope); - return GET_RETURN_STATUS(); + return GET_RETURN_STATUS(env); } -napi_status napi_escape_handle(napi_env e, +napi_status napi_escape_handle(napi_env env, napi_escapable_handle_scope scope, napi_value escapee, napi_value* result) { - NAPI_PREAMBLE(e); - CHECK_ARG(scope); - CHECK_ARG(result); + NAPI_PREAMBLE(env); + CHECK_ARG(env, scope); + CHECK_ARG(env, result); v8impl::EscapableHandleScopeWrapper* s = v8impl::V8EscapableHandleScopeFromJsEscapableHandleScope(scope); *result = v8impl::JsValueFromV8LocalValue( s->Escape(v8impl::V8LocalValueFromJsValue(escapee))); - return GET_RETURN_STATUS(); + return GET_RETURN_STATUS(env); } -napi_status napi_new_instance(napi_env e, +napi_status napi_new_instance(napi_env env, napi_value constructor, - int argc, + size_t argc, const napi_value* argv, napi_value* result) { - NAPI_PREAMBLE(e); - CHECK_ARG(result); + NAPI_PREAMBLE(env); + CHECK_ARG(env, result); - v8::Isolate* isolate = v8impl::V8IsolateFromJsEnv(e); + v8::Isolate* isolate = env->isolate; v8::Local context = isolate->GetCurrentContext(); - std::vector> args(argc); - for (int i = 0; i < argc; i++) { - args[i] = v8impl::V8LocalValueFromJsValue(argv[i]); - } + v8::Local v8value = v8impl::V8LocalValueFromJsValue(constructor); + RETURN_STATUS_IF_FALSE(env, v8value->IsFunction(), napi_invalid_arg); - v8::Local v8cons = - v8impl::V8LocalFunctionFromJsValue(constructor); + v8::Local ctor = v8value.As(); - auto maybe = v8cons->NewInstance(context, argc, args.data()); - CHECK_MAYBE_EMPTY(maybe, napi_generic_failure); + auto maybe = ctor->NewInstance(context, argc, + reinterpret_cast*>(const_cast(argv))); + + CHECK_MAYBE_EMPTY(env, maybe, napi_generic_failure); *result = v8impl::JsValueFromV8LocalValue(maybe.ToLocalChecked()); - return GET_RETURN_STATUS(); + return GET_RETURN_STATUS(env); } -napi_status napi_instanceof(napi_env e, +napi_status napi_instanceof(napi_env env, napi_value object, napi_value constructor, bool* result) { - NAPI_PREAMBLE(e); - CHECK_ARG(result); + NAPI_PREAMBLE(env); + CHECK_ARG(env, result); *result = false; - v8::Local v8Cons; - v8::Local prototypeString; - v8::Isolate* isolate = v8impl::V8IsolateFromJsEnv(e); + v8::Local ctor; + v8::Isolate* isolate = env->isolate; v8::Local context = isolate->GetCurrentContext(); - CHECK_TO_OBJECT(context, v8Cons, constructor); + CHECK_TO_OBJECT(env, context, ctor, constructor); - if (!v8Cons->IsFunction()) { - napi_throw_type_error(e, "constructor must be a function"); + if (!ctor->IsFunction()) { + napi_throw_type_error(env, "constructor must be a function"); - return napi_set_last_error(napi_function_expected); + return napi_set_last_error(env, napi_function_expected); } - CHECK_NEW_FROM_UTF8(isolate, prototypeString, "prototype"); + if (env->has_instance_available) { + napi_value value, js_result, has_instance = nullptr; + napi_status status = napi_generic_failure; + napi_valuetype value_type; + + // Get "Symbol" from the global object + if (env->has_instance.IsEmpty()) { + status = napi_get_global(env, &value); + if (status != napi_ok) return status; + status = napi_get_named_property(env, value, "Symbol", &value); + if (status != napi_ok) return status; + status = napi_typeof(env, value, &value_type); + if (status != napi_ok) return status; + + // Get "hasInstance" from Symbol + if (value_type == napi_function) { + status = napi_get_named_property(env, value, "hasInstance", &value); + if (status != napi_ok) return status; + status = napi_typeof(env, value, &value_type); + if (status != napi_ok) return status; + + // Store Symbol.hasInstance in a global persistent reference + if (value_type == napi_symbol) { + env->has_instance.Reset(env->isolate, + v8impl::V8LocalValueFromJsValue(value)); + has_instance = value; + } + } + } else { + has_instance = v8impl::JsValueFromV8LocalValue( + v8::Local::New(env->isolate, env->has_instance)); + } - auto maybe = v8Cons->Get(context, prototypeString); + if (has_instance) { + status = napi_get_property(env, constructor, has_instance, &value); + if (status != napi_ok) return status; + status = napi_typeof(env, value, &value_type); + if (status != napi_ok) return status; + + // Call the function to determine whether the object is an instance of the + // constructor + if (value_type == napi_function) { + status = napi_call_function(env, constructor, value, 1, &object, + &js_result); + if (status != napi_ok) return status; + return napi_get_value_bool(env, js_result, result); + } + } - CHECK_MAYBE_EMPTY(maybe, napi_generic_failure); + env->has_instance_available = false; + } - v8::Local prototypeProperty = maybe.ToLocalChecked(); + // If running constructor[Symbol.hasInstance](object) did not work, we perform + // a traditional instanceof (early Node.js 6.x). - if (!prototypeProperty->IsObject()) { - napi_throw_type_error(e, "constructor prototype must be an object"); + v8::Local prototype_string; + CHECK_NEW_FROM_UTF8(env, prototype_string, "prototype"); - return napi_set_last_error(napi_object_expected); - } + auto maybe_prototype = ctor->Get(context, prototype_string); + CHECK_MAYBE_EMPTY(env, maybe_prototype, napi_generic_failure); - v8Cons = prototypeProperty->ToObject(); + v8::Local prototype_property = maybe_prototype.ToLocalChecked(); + if (!prototype_property->IsObject()) { + napi_throw_type_error(env, "constructor.prototype must be an object"); - v8::Local v8Obj = v8impl::V8LocalValueFromJsValue(object); - if (!v8Obj->StrictEquals(v8Cons)) { - for (v8::Local originalObj = v8Obj; - !(v8Obj->IsNull() || v8Obj->IsUndefined());) { - if (v8Obj->StrictEquals(v8Cons)) { - *result = !(originalObj->IsNumber() || originalObj->IsBoolean() || - originalObj->IsString()); + return napi_set_last_error(env, napi_object_expected); + } + + auto maybe_ctor = prototype_property->ToObject(context); + CHECK_MAYBE_EMPTY(env, maybe_ctor, napi_generic_failure); + ctor = maybe_ctor.ToLocalChecked(); + + v8::Local current_obj = v8impl::V8LocalValueFromJsValue(object); + if (!current_obj->StrictEquals(ctor)) { + for (v8::Local original_obj = current_obj; + !(current_obj->IsNull() || current_obj->IsUndefined());) { + if (current_obj->StrictEquals(ctor)) { + *result = !(original_obj->IsNumber() || + original_obj->IsBoolean() || + original_obj->IsString()); break; } v8::Local obj; - CHECK_TO_OBJECT(context, obj, v8impl::JsValueFromV8LocalValue(v8Obj)); - v8Obj = obj->GetPrototype(); + CHECK_TO_OBJECT(env, context, obj, v8impl::JsValueFromV8LocalValue( + current_obj)); + current_obj = obj->GetPrototype(); } } - return GET_RETURN_STATUS(); + return GET_RETURN_STATUS(env); } -napi_status napi_make_callback(napi_env e, +napi_status napi_make_callback(napi_env env, napi_value recv, napi_value func, - int argc, + size_t argc, const napi_value* argv, napi_value* result) { - NAPI_PREAMBLE(e); - CHECK_ARG(result); + NAPI_PREAMBLE(env); - v8::Isolate* isolate = v8impl::V8IsolateFromJsEnv(e); + v8::Isolate* isolate = env->isolate; v8::Local v8recv = v8impl::V8LocalValueFromJsValue(recv).As(); v8::Local v8func = v8impl::V8LocalValueFromJsValue(func).As(); - std::vector> args(argc); - for (int i = 0; i < argc; i++) { - args[i] = v8impl::V8LocalValueFromJsValue(argv[i]); - } - v8::Handle retval = - node::MakeCallback(isolate, v8recv, v8func, argc, args.data()); - *result = v8impl::JsValueFromV8LocalValue(retval); + v8::Local callback_result = node::MakeCallback( + isolate, v8recv, v8func, argc, + reinterpret_cast*>(const_cast(argv))); - return GET_RETURN_STATUS(); + if (result != nullptr) { + *result = v8impl::JsValueFromV8LocalValue(callback_result); + } + + return GET_RETURN_STATUS(env); } // Methods to support catching exceptions -napi_status napi_is_exception_pending(napi_env e, bool* result) { +napi_status napi_is_exception_pending(napi_env env, bool* result) { // NAPI_PREAMBLE is not used here: this function must execute when there is a // pending exception. - CHECK_ARG(e); - CHECK_ARG(result); + CHECK_ENV(env); + CHECK_ARG(env, result); - *result = !v8impl::TryCatch::lastException().IsEmpty(); + *result = !env->last_exception.IsEmpty(); return napi_ok; } -napi_status napi_get_and_clear_last_exception(napi_env e, napi_value* result) { +napi_status napi_get_and_clear_last_exception(napi_env env, + napi_value* result) { // NAPI_PREAMBLE is not used here: this function must execute when there is a // pending exception. - CHECK_ARG(e); - CHECK_ARG(result); + CHECK_ENV(env); + CHECK_ARG(env, result); - // TODO(boingoing): Is there a chance that an exception will be thrown in - // the process of attempting to retrieve the global static exception? - if (v8impl::TryCatch::lastException().IsEmpty()) { - return napi_get_undefined(e, result); + if (env->last_exception.IsEmpty()) { + return napi_get_undefined(env, result); } else { - *result = v8impl::JsValueFromV8LocalValue(v8::Local::New( - v8impl::V8IsolateFromJsEnv(e), v8impl::TryCatch::lastException())); - v8impl::TryCatch::lastException().Reset(); + *result = v8impl::JsValueFromV8LocalValue( + v8::Local::New(env->isolate, env->last_exception)); + env->last_exception.Reset(); } return napi_ok; } -napi_status napi_create_buffer(napi_env e, - size_t size, +napi_status napi_create_buffer(napi_env env, + size_t length, void** data, napi_value* result) { - NAPI_PREAMBLE(e); - CHECK_ARG(data); - CHECK_ARG(result); + NAPI_PREAMBLE(env); + CHECK_ARG(env, data); + CHECK_ARG(env, result); - auto maybe = node::Buffer::New(v8impl::V8IsolateFromJsEnv(e), size); + auto maybe = node::Buffer::New(env->isolate, length); - CHECK_MAYBE_EMPTY(maybe, napi_generic_failure); + CHECK_MAYBE_EMPTY(env, maybe, napi_generic_failure); - v8::Local jsBuffer = maybe.ToLocalChecked(); + v8::Local buffer = maybe.ToLocalChecked(); - *result = v8impl::JsValueFromV8LocalValue(jsBuffer); - *data = node::Buffer::Data(jsBuffer); + *result = v8impl::JsValueFromV8LocalValue(buffer); + *data = node::Buffer::Data(buffer); - return GET_RETURN_STATUS(); + return GET_RETURN_STATUS(env); } -napi_status napi_create_external_buffer(napi_env e, - size_t size, +napi_status napi_create_external_buffer(napi_env env, + size_t length, void* data, napi_finalize finalize_cb, void* finalize_hint, napi_value* result) { - NAPI_PREAMBLE(e); - CHECK_ARG(result); + NAPI_PREAMBLE(env); + CHECK_ARG(env, result); + + v8::Isolate* isolate = env->isolate; - auto maybe = node::Buffer::New(v8impl::V8IsolateFromJsEnv(e), + // The finalizer object will delete itself after invoking the callback. + v8impl::Finalizer* finalizer = v8impl::Finalizer::New( + env, finalize_cb, nullptr, finalize_hint); + + auto maybe = node::Buffer::New(isolate, static_cast(data), - size, - (node::Buffer::FreeCallback)finalize_cb, - finalize_hint); + length, + v8impl::Finalizer::FinalizeBufferCallback, + finalizer); - CHECK_MAYBE_EMPTY(maybe, napi_generic_failure); + CHECK_MAYBE_EMPTY(env, maybe, napi_generic_failure); *result = v8impl::JsValueFromV8LocalValue(maybe.ToLocalChecked()); - return GET_RETURN_STATUS(); + return GET_RETURN_STATUS(env); + // Tell coverity that 'finalizer' should not be freed when we return + // as it will be deleted when the buffer to which it is associated + // is finalized. + // coverity[leaked_storage] } -napi_status napi_create_buffer_copy(napi_env e, +napi_status napi_create_buffer_copy(napi_env env, + size_t length, const void* data, - size_t size, + void** result_data, napi_value* result) { - NAPI_PREAMBLE(e); - CHECK_ARG(result); + NAPI_PREAMBLE(env); + CHECK_ARG(env, result); - auto maybe = node::Buffer::Copy(v8impl::V8IsolateFromJsEnv(e), - static_cast(data), size); + auto maybe = node::Buffer::Copy(env->isolate, + static_cast(data), length); - CHECK_MAYBE_EMPTY(maybe, napi_generic_failure); + CHECK_MAYBE_EMPTY(env, maybe, napi_generic_failure); - *result = v8impl::JsValueFromV8LocalValue(maybe.ToLocalChecked()); - return GET_RETURN_STATUS(); + v8::Local buffer = maybe.ToLocalChecked(); + *result = v8impl::JsValueFromV8LocalValue(buffer); + + if (result_data != nullptr) { + *result_data = node::Buffer::Data(buffer); + } + + return GET_RETURN_STATUS(env); } -napi_status napi_is_buffer(napi_env e, napi_value value, bool* result) { - NAPI_PREAMBLE(e); - CHECK_ARG(result); +napi_status napi_is_buffer(napi_env env, napi_value value, bool* result) { + NAPI_PREAMBLE(env); + CHECK_ARG(env, result); *result = node::Buffer::HasInstance(v8impl::V8LocalValueFromJsValue(value)); - return GET_RETURN_STATUS(); + return GET_RETURN_STATUS(env); } -napi_status napi_get_buffer_info(napi_env e, +napi_status napi_get_buffer_info(napi_env env, napi_value value, void** data, size_t* length) { - NAPI_PREAMBLE(e); + NAPI_PREAMBLE(env); v8::Local buffer = v8impl::V8LocalValueFromJsValue(value).As(); - if (data) { + if (data != nullptr) { *data = node::Buffer::Data(buffer); } - if (length) { + if (length != nullptr) { *length = node::Buffer::Length(buffer); } - return GET_RETURN_STATUS(); + return GET_RETURN_STATUS(env); } -napi_status napi_is_arraybuffer(napi_env e, napi_value value, bool* result) { - NAPI_PREAMBLE(e); - CHECK_ARG(result); +napi_status napi_is_arraybuffer(napi_env env, napi_value value, bool* result) { + NAPI_PREAMBLE(env); + CHECK_ARG(env, result); - v8::Local v8value = v8impl::V8LocalValueFromJsValue(value); - *result = v8value->IsArrayBuffer(); + v8::Local val = v8impl::V8LocalValueFromJsValue(value); + *result = val->IsArrayBuffer(); - return GET_RETURN_STATUS(); + return GET_RETURN_STATUS(env); } -napi_status napi_create_arraybuffer(napi_env e, +napi_status napi_create_arraybuffer(napi_env env, size_t byte_length, void** data, napi_value* result) { - NAPI_PREAMBLE(e); - CHECK_ARG(result); + NAPI_PREAMBLE(env); + CHECK_ARG(env, result); - v8::Isolate* isolate = v8impl::V8IsolateFromJsEnv(e); + v8::Isolate* isolate = env->isolate; v8::Local buffer = v8::ArrayBuffer::New(isolate, byte_length); @@ -2272,26 +2404,26 @@ napi_status napi_create_arraybuffer(napi_env e, } *result = v8impl::JsValueFromV8LocalValue(buffer); - return GET_RETURN_STATUS(); + return GET_RETURN_STATUS(env); } -napi_status napi_create_external_arraybuffer(napi_env e, +napi_status napi_create_external_arraybuffer(napi_env env, void* external_data, size_t byte_length, napi_finalize finalize_cb, void* finalize_hint, napi_value* result) { - NAPI_PREAMBLE(e); - CHECK_ARG(result); + NAPI_PREAMBLE(env); + CHECK_ARG(env, result); - v8::Isolate* isolate = v8impl::V8IsolateFromJsEnv(e); + v8::Isolate* isolate = env->isolate; v8::Local buffer = v8::ArrayBuffer::New(isolate, external_data, byte_length); if (finalize_cb != nullptr) { // Create a self-deleting weak reference that invokes the finalizer // callback. - new v8impl::Reference(isolate, + v8impl::Reference::New(env, buffer, 0, true, @@ -2301,17 +2433,17 @@ napi_status napi_create_external_arraybuffer(napi_env e, } *result = v8impl::JsValueFromV8LocalValue(buffer); - return GET_RETURN_STATUS(); + return GET_RETURN_STATUS(env); } -napi_status napi_get_arraybuffer_info(napi_env e, +napi_status napi_get_arraybuffer_info(napi_env env, napi_value arraybuffer, void** data, size_t* byte_length) { - NAPI_PREAMBLE(e); + NAPI_PREAMBLE(env); v8::Local value = v8impl::V8LocalValueFromJsValue(arraybuffer); - RETURN_STATUS_IF_FALSE(value->IsArrayBuffer(), napi_invalid_arg); + RETURN_STATUS_IF_FALSE(env, value->IsArrayBuffer(), napi_invalid_arg); v8::ArrayBuffer::Contents contents = value.As()->GetContents(); @@ -2324,103 +2456,103 @@ napi_status napi_get_arraybuffer_info(napi_env e, *byte_length = contents.ByteLength(); } - return GET_RETURN_STATUS(); + return GET_RETURN_STATUS(env); } -napi_status napi_is_typedarray(napi_env e, napi_value value, bool* result) { - NAPI_PREAMBLE(e); - CHECK_ARG(result); +napi_status napi_is_typedarray(napi_env env, napi_value value, bool* result) { + NAPI_PREAMBLE(env); + CHECK_ARG(env, result); - v8::Local v8value = v8impl::V8LocalValueFromJsValue(value); - *result = v8value->IsTypedArray(); + v8::Local val = v8impl::V8LocalValueFromJsValue(value); + *result = val->IsTypedArray(); - return GET_RETURN_STATUS(); + return GET_RETURN_STATUS(env); } -napi_status napi_create_typedarray(napi_env e, +napi_status napi_create_typedarray(napi_env env, napi_typedarray_type type, size_t length, napi_value arraybuffer, size_t byte_offset, napi_value* result) { - NAPI_PREAMBLE(e); - CHECK_ARG(result); + NAPI_PREAMBLE(env); + CHECK_ARG(env, result); v8::Local value = v8impl::V8LocalValueFromJsValue(arraybuffer); - RETURN_STATUS_IF_FALSE(value->IsArrayBuffer(), napi_invalid_arg); + RETURN_STATUS_IF_FALSE(env, value->IsArrayBuffer(), napi_invalid_arg); v8::Local buffer = value.As(); v8::Local typedArray; switch (type) { - case napi_int8: + case napi_int8_array: typedArray = v8::Int8Array::New(buffer, byte_offset, length); break; - case napi_uint8: + case napi_uint8_array: typedArray = v8::Uint8Array::New(buffer, byte_offset, length); break; - case napi_uint8_clamped: + case napi_uint8_clamped_array: typedArray = v8::Uint8ClampedArray::New(buffer, byte_offset, length); break; - case napi_int16: + case napi_int16_array: typedArray = v8::Int16Array::New(buffer, byte_offset, length); break; - case napi_uint16: + case napi_uint16_array: typedArray = v8::Uint16Array::New(buffer, byte_offset, length); break; - case napi_int32: + case napi_int32_array: typedArray = v8::Int32Array::New(buffer, byte_offset, length); break; - case napi_uint32: + case napi_uint32_array: typedArray = v8::Uint32Array::New(buffer, byte_offset, length); break; - case napi_float32: + case napi_float32_array: typedArray = v8::Float32Array::New(buffer, byte_offset, length); break; - case napi_float64: + case napi_float64_array: typedArray = v8::Float64Array::New(buffer, byte_offset, length); break; default: - return napi_set_last_error(napi_invalid_arg); + return napi_set_last_error(env, napi_invalid_arg); } *result = v8impl::JsValueFromV8LocalValue(typedArray); - return GET_RETURN_STATUS(); + return GET_RETURN_STATUS(env); } -napi_status napi_get_typedarray_info(napi_env e, +napi_status napi_get_typedarray_info(napi_env env, napi_value typedarray, napi_typedarray_type* type, size_t* length, void** data, napi_value* arraybuffer, size_t* byte_offset) { - NAPI_PREAMBLE(e); + NAPI_PREAMBLE(env); v8::Local value = v8impl::V8LocalValueFromJsValue(typedarray); - RETURN_STATUS_IF_FALSE(value->IsTypedArray(), napi_invalid_arg); + RETURN_STATUS_IF_FALSE(env, value->IsTypedArray(), napi_invalid_arg); v8::Local array = value.As(); if (type != nullptr) { if (value->IsInt8Array()) { - *type = napi_int8; + *type = napi_int8_array; } else if (value->IsUint8Array()) { - *type = napi_uint8; + *type = napi_uint8_array; } else if (value->IsUint8ClampedArray()) { - *type = napi_uint8_clamped; + *type = napi_uint8_clamped_array; } else if (value->IsInt16Array()) { - *type = napi_int16; + *type = napi_int16_array; } else if (value->IsUint16Array()) { - *type = napi_uint16; + *type = napi_uint16_array; } else if (value->IsInt32Array()) { - *type = napi_int32; + *type = napi_int32_array; } else if (value->IsUint32Array()) { - *type = napi_uint32; + *type = napi_uint32_array; } else if (value->IsFloat32Array()) { - *type = napi_float32; + *type = napi_float32_array; } else if (value->IsFloat64Array()) { - *type = napi_float64; + *type = napi_float64_array; } } @@ -2442,5 +2574,140 @@ napi_status napi_get_typedarray_info(napi_env e, *byte_offset = array->ByteOffset(); } - return GET_RETURN_STATUS(); + return GET_RETURN_STATUS(env); +} + +namespace uvimpl { + +napi_status ConvertUVErrorCode(int code) { + switch (code) { + case 0: + return napi_ok; + case UV_EINVAL: + return napi_invalid_arg; + case UV_ECANCELED: + return napi_cancelled; + } + + return napi_generic_failure; +} + +// Wrapper around uv_work_t which calls user-provided callbacks. +class Work { + private: + explicit Work(napi_env env, + napi_async_execute_callback execute = nullptr, + napi_async_complete_callback complete = nullptr, + void* data = nullptr) + : _env(env), + _data(data), + _execute(execute), + _complete(complete) { + _request.data = this; + } + + ~Work() { } + + public: + static Work* New(napi_env env, + napi_async_execute_callback execute, + napi_async_complete_callback complete, + void* data) { + return new Work(env, execute, complete, data); + } + + static void Delete(Work* work) { + delete work; + } + + static void ExecuteCallback(uv_work_t* req) { + Work* work = static_cast(req->data); + work->_execute(work->_env, work->_data); + } + + static void CompleteCallback(uv_work_t* req, int status) { + Work* work = static_cast(req->data); + + if (work->_complete != nullptr) { + work->_complete(work->_env, ConvertUVErrorCode(status), work->_data); + } + } + + uv_work_t* Request() { + return &_request; + } + + private: + napi_env _env; + void* _data; + uv_work_t _request; + napi_async_execute_callback _execute; + napi_async_complete_callback _complete; +}; + +} // end of namespace uvimpl + +#define CALL_UV(env, condition) \ + do { \ + int result = (condition); \ + napi_status status = uvimpl::ConvertUVErrorCode(result); \ + if (status != napi_ok) { \ + return napi_set_last_error(env, status, result); \ + } \ + } while (0) + +napi_status napi_create_async_work(napi_env env, + napi_async_execute_callback execute, + napi_async_complete_callback complete, + void* data, + napi_async_work* result) { + CHECK_ENV(env); + CHECK_ARG(env, execute); + CHECK_ARG(env, result); + + uvimpl::Work* work = uvimpl::Work::New(env, execute, complete, data); + + *result = reinterpret_cast(work); + + return napi_ok; +} + +napi_status napi_delete_async_work(napi_env env, napi_async_work work) { + CHECK_ENV(env); + CHECK_ARG(env, work); + + uvimpl::Work::Delete(reinterpret_cast(work)); + + return napi_ok; +} + +napi_status napi_queue_async_work(napi_env env, napi_async_work work) { + CHECK_ENV(env); + CHECK_ARG(env, work); + + // Consider: Encapsulate the uv_loop_t into an opaque pointer parameter. + // Currently the environment event loop is the same as the UV default loop. + // Someday (if node ever supports multiple isolates), it may be better to get + // the loop from node::Environment::GetCurrent(env->isolate)->event_loop(); + uv_loop_t* event_loop = uv_default_loop(); + + uvimpl::Work* w = reinterpret_cast(work); + + CALL_UV(env, uv_queue_work(event_loop, + w->Request(), + uvimpl::Work::ExecuteCallback, + uvimpl::Work::CompleteCallback)); + + return napi_ok; +} + +napi_status napi_cancel_async_work(napi_env env, napi_async_work work) { + CHECK_ENV(env); + CHECK_ARG(env, work); + + uvimpl::Work* w = reinterpret_cast(work); + + CALL_UV(env, uv_cancel(reinterpret_cast(w->Request()))); + + return napi_ok; } diff --git a/src/node_api.gyp b/src/node_api.gyp index 706eef6f4..a23d9f581 100644 --- a/src/node_api.gyp +++ b/src/node_api.gyp @@ -8,7 +8,6 @@ 'type': 'static_library', 'sources': [ 'node_api.cc', - 'node_api_async.cc', ], 'defines': [ 'EXTERNAL_NAPI', diff --git a/src/node_api.h b/src/node_api.h index 73b85f223..8791954a3 100644 --- a/src/node_api.h +++ b/src/node_api.h @@ -11,6 +11,7 @@ #define SRC_NODE_API_H_ #include +#include #include "node_api_types.h" #ifdef _WIN32 @@ -37,23 +38,20 @@ #endif -namespace node { +typedef void (*napi_addon_register_func)(napi_env env, + napi_value exports, + napi_value module, + void* priv); -NAPI_EXTERN typedef void (*napi_addon_register_func)(napi_env env, - napi_value exports, - napi_value module, - void* priv); -} // namespace node - -struct napi_module { +typedef struct { int nm_version; unsigned int nm_flags; const char* nm_filename; - node::napi_addon_register_func nm_register_func; + napi_addon_register_func nm_register_func; const char* nm_modname; void* nm_priv; void* reserved[4]; -}; +} napi_module; #define NAPI_MODULE_VERSION 1 @@ -70,8 +68,16 @@ struct napi_module { static void fn(void) #endif +#ifdef __cplusplus +#define EXTERN_C_START extern "C" { +#define EXTERN_C_END } +#else +#define EXTERN_C_START +#define EXTERN_C_END +#endif + #define NAPI_MODULE_X(modname, regfunc, priv, flags) \ - extern "C" { \ + EXTERN_C_START \ static napi_module _module = \ { \ NAPI_MODULE_VERSION, \ @@ -85,212 +91,201 @@ struct napi_module { NAPI_C_CTOR(_register_ ## modname) { \ napi_module_register(&_module); \ } \ - } + EXTERN_C_END #define NAPI_MODULE(modname, regfunc) \ NAPI_MODULE_X(modname, regfunc, NULL, 0) -extern "C" { +EXTERN_C_START NAPI_EXTERN void napi_module_register(napi_module* mod); -NAPI_EXTERN const napi_extended_error_info* napi_get_last_error_info(); +NAPI_EXTERN napi_status +napi_get_last_error_info(napi_env env, + const napi_extended_error_info** result); // Getters for defined singletons -NAPI_EXTERN napi_status napi_get_undefined(napi_env e, napi_value* result); -NAPI_EXTERN napi_status napi_get_null(napi_env e, napi_value* result); -NAPI_EXTERN napi_status napi_get_false(napi_env e, napi_value* result); -NAPI_EXTERN napi_status napi_get_true(napi_env e, napi_value* result); -NAPI_EXTERN napi_status napi_get_global(napi_env e, napi_value* result); +NAPI_EXTERN napi_status napi_get_undefined(napi_env env, napi_value* result); +NAPI_EXTERN napi_status napi_get_null(napi_env env, napi_value* result); +NAPI_EXTERN napi_status napi_get_global(napi_env env, napi_value* result); +NAPI_EXTERN napi_status napi_get_boolean(napi_env env, + bool value, + napi_value* result); // Methods to create Primitive types/Objects -NAPI_EXTERN napi_status napi_create_object(napi_env e, napi_value* result); -NAPI_EXTERN napi_status napi_create_array(napi_env e, napi_value* result); -NAPI_EXTERN napi_status napi_create_array_with_length(napi_env e, - int length, +NAPI_EXTERN napi_status napi_create_object(napi_env env, napi_value* result); +NAPI_EXTERN napi_status napi_create_array(napi_env env, napi_value* result); +NAPI_EXTERN napi_status napi_create_array_with_length(napi_env env, + size_t length, napi_value* result); -NAPI_EXTERN napi_status napi_create_number(napi_env e, - double val, +NAPI_EXTERN napi_status napi_create_number(napi_env env, + double value, napi_value* result); -NAPI_EXTERN napi_status napi_create_string_utf8(napi_env e, - const char* s, - int length, +NAPI_EXTERN napi_status napi_create_string_utf8(napi_env env, + const char* str, + size_t length, napi_value* result); -NAPI_EXTERN napi_status napi_create_string_utf16(napi_env e, - const char16_t* s, - int length, +NAPI_EXTERN napi_status napi_create_string_utf16(napi_env env, + const char16_t* str, + size_t length, napi_value* result); -NAPI_EXTERN napi_status napi_create_boolean(napi_env e, - bool b, - napi_value* result); -NAPI_EXTERN napi_status napi_create_symbol(napi_env e, - const char* s, +NAPI_EXTERN napi_status napi_create_symbol(napi_env env, + napi_value description, napi_value* result); -NAPI_EXTERN napi_status napi_create_function(napi_env e, +NAPI_EXTERN napi_status napi_create_function(napi_env env, const char* utf8name, napi_callback cb, void* data, napi_value* result); -NAPI_EXTERN napi_status napi_create_error(napi_env e, +NAPI_EXTERN napi_status napi_create_error(napi_env env, napi_value msg, napi_value* result); -NAPI_EXTERN napi_status napi_create_type_error(napi_env e, +NAPI_EXTERN napi_status napi_create_type_error(napi_env env, napi_value msg, napi_value* result); -NAPI_EXTERN napi_status napi_create_range_error(napi_env e, +NAPI_EXTERN napi_status napi_create_range_error(napi_env env, napi_value msg, napi_value* result); // Methods to get the the native napi_value from Primitive type -NAPI_EXTERN napi_status napi_get_type_of_value(napi_env e, - napi_value value, - napi_valuetype* result); -NAPI_EXTERN napi_status napi_get_value_double(napi_env e, +NAPI_EXTERN napi_status napi_typeof(napi_env env, + napi_value value, + napi_valuetype* result); +NAPI_EXTERN napi_status napi_get_value_double(napi_env env, napi_value value, double* result); -NAPI_EXTERN napi_status napi_get_value_int32(napi_env e, +NAPI_EXTERN napi_status napi_get_value_int32(napi_env env, napi_value value, int32_t* result); -NAPI_EXTERN napi_status napi_get_value_uint32(napi_env e, +NAPI_EXTERN napi_status napi_get_value_uint32(napi_env env, napi_value value, uint32_t* result); -NAPI_EXTERN napi_status napi_get_value_int64(napi_env e, +NAPI_EXTERN napi_status napi_get_value_int64(napi_env env, napi_value value, int64_t* result); -NAPI_EXTERN napi_status napi_get_value_bool(napi_env e, +NAPI_EXTERN napi_status napi_get_value_bool(napi_env env, napi_value value, bool* result); // Gets the number of CHARACTERS in the string. -NAPI_EXTERN napi_status napi_get_value_string_length(napi_env e, +NAPI_EXTERN napi_status napi_get_value_string_length(napi_env env, napi_value value, - int* result); - -// Gets the number of BYTES in the UTF-8 encoded representation of the string. -NAPI_EXTERN napi_status napi_get_value_string_utf8_length(napi_env e, - napi_value value, - int* result); + size_t* result); // Copies UTF-8 encoded bytes from a string into a buffer. -NAPI_EXTERN napi_status napi_get_value_string_utf8(napi_env e, +NAPI_EXTERN napi_status napi_get_value_string_utf8(napi_env env, napi_value value, char* buf, - int bufsize, - int* result); - -// Gets the number of 2-byte code units in the UTF-16 encoded -// representation of the string. -NAPI_EXTERN napi_status napi_get_value_string_utf16_length(napi_env e, - napi_value value, - int* result); + size_t bufsize, + size_t* result); // Copies UTF-16 encoded bytes from a string into a buffer. -NAPI_EXTERN napi_status napi_get_value_string_utf16(napi_env e, +NAPI_EXTERN napi_status napi_get_value_string_utf16(napi_env env, napi_value value, char16_t* buf, - int bufsize, - int* result); + size_t bufsize, + size_t* result); // Methods to coerce values -// These APIs may execute user script -NAPI_EXTERN napi_status napi_coerce_to_bool(napi_env e, +// These APIs may execute user scripts +NAPI_EXTERN napi_status napi_coerce_to_bool(napi_env env, napi_value value, napi_value* result); -NAPI_EXTERN napi_status napi_coerce_to_number(napi_env e, +NAPI_EXTERN napi_status napi_coerce_to_number(napi_env env, napi_value value, napi_value* result); -NAPI_EXTERN napi_status napi_coerce_to_object(napi_env e, +NAPI_EXTERN napi_status napi_coerce_to_object(napi_env env, napi_value value, napi_value* result); -NAPI_EXTERN napi_status napi_coerce_to_string(napi_env e, +NAPI_EXTERN napi_status napi_coerce_to_string(napi_env env, napi_value value, napi_value* result); // Methods to work with Objects -NAPI_EXTERN napi_status napi_get_prototype(napi_env e, +NAPI_EXTERN napi_status napi_get_prototype(napi_env env, napi_value object, napi_value* result); -NAPI_EXTERN napi_status napi_get_propertynames(napi_env e, - napi_value object, - napi_value* result); -NAPI_EXTERN napi_status napi_set_property(napi_env e, +NAPI_EXTERN napi_status napi_get_property_names(napi_env env, + napi_value object, + napi_value* result); +NAPI_EXTERN napi_status napi_set_property(napi_env env, napi_value object, napi_value key, napi_value value); -NAPI_EXTERN napi_status napi_has_property(napi_env e, +NAPI_EXTERN napi_status napi_has_property(napi_env env, napi_value object, napi_value key, bool* result); -NAPI_EXTERN napi_status napi_get_property(napi_env e, +NAPI_EXTERN napi_status napi_get_property(napi_env env, napi_value object, napi_value key, napi_value* result); -NAPI_EXTERN napi_status napi_set_named_property(napi_env e, +NAPI_EXTERN napi_status napi_set_named_property(napi_env env, napi_value object, const char* utf8name, napi_value value); -NAPI_EXTERN napi_status napi_has_named_property(napi_env e, +NAPI_EXTERN napi_status napi_has_named_property(napi_env env, napi_value object, const char* utf8name, bool* result); -NAPI_EXTERN napi_status napi_get_named_property(napi_env e, +NAPI_EXTERN napi_status napi_get_named_property(napi_env env, napi_value object, const char* utf8name, napi_value* result); -NAPI_EXTERN napi_status napi_set_element(napi_env e, +NAPI_EXTERN napi_status napi_set_element(napi_env env, napi_value object, uint32_t index, napi_value value); -NAPI_EXTERN napi_status napi_has_element(napi_env e, +NAPI_EXTERN napi_status napi_has_element(napi_env env, napi_value object, uint32_t index, bool* result); -NAPI_EXTERN napi_status napi_get_element(napi_env e, +NAPI_EXTERN napi_status napi_get_element(napi_env env, napi_value object, uint32_t index, napi_value* result); NAPI_EXTERN napi_status -napi_define_properties(napi_env e, +napi_define_properties(napi_env env, napi_value object, - int property_count, + size_t property_count, const napi_property_descriptor* properties); // Methods to work with Arrays -NAPI_EXTERN napi_status napi_is_array(napi_env e, +NAPI_EXTERN napi_status napi_is_array(napi_env env, napi_value value, bool* result); -NAPI_EXTERN napi_status napi_get_array_length(napi_env e, +NAPI_EXTERN napi_status napi_get_array_length(napi_env env, napi_value value, uint32_t* result); // Methods to compare values -NAPI_EXTERN napi_status napi_strict_equals(napi_env e, +NAPI_EXTERN napi_status napi_strict_equals(napi_env env, napi_value lhs, napi_value rhs, bool* result); // Methods to work with Functions -NAPI_EXTERN napi_status napi_call_function(napi_env e, +NAPI_EXTERN napi_status napi_call_function(napi_env env, napi_value recv, napi_value func, - int argc, + size_t argc, const napi_value* argv, napi_value* result); -NAPI_EXTERN napi_status napi_new_instance(napi_env e, +NAPI_EXTERN napi_status napi_new_instance(napi_env env, napi_value constructor, - int argc, + size_t argc, const napi_value* argv, napi_value* result); -NAPI_EXTERN napi_status napi_instanceof(napi_env e, +NAPI_EXTERN napi_status napi_instanceof(napi_env env, napi_value object, napi_value constructor, bool* result); // Napi version of node::MakeCallback(...) -NAPI_EXTERN napi_status napi_make_callback(napi_env e, +NAPI_EXTERN napi_status napi_make_callback(napi_env env, napi_value recv, napi_value func, - int argc, + size_t argc, const napi_value* argv, napi_value* result); @@ -298,151 +293,131 @@ NAPI_EXTERN napi_status napi_make_callback(napi_env e, // Gets all callback info in a single call. (Ugly, but faster.) NAPI_EXTERN napi_status napi_get_cb_info( - napi_env e, // [in] NAPI environment handle + napi_env env, // [in] NAPI environment handle napi_callback_info cbinfo, // [in] Opaque callback-info handle - int* argc, // [in-out] Specifies the size of the provided argv array + size_t* argc, // [in-out] Specifies the size of the provided argv array // and receives the actual count of args. napi_value* argv, // [out] Array of values - napi_value* thisArg, // [out] Receives the JS 'this' arg for the call - void** data); // [out] Receives the data pointer for the callback. - -NAPI_EXTERN napi_status napi_get_cb_args_length(napi_env e, - napi_callback_info cbinfo, - int* result); -NAPI_EXTERN napi_status napi_get_cb_args(napi_env e, - napi_callback_info cbinfo, - napi_value* buffer, - int bufferlength); -NAPI_EXTERN napi_status napi_get_cb_this(napi_env e, - napi_callback_info cbinfo, - napi_value* result); + napi_value* this_arg, // [out] Receives the JS 'this' arg for the call + void** data); // [out] Receives the data pointer for the callback. -// V8 concept; see note in .cc file -NAPI_EXTERN napi_status napi_get_cb_holder(napi_env e, - napi_callback_info cbinfo, - napi_value* result); -NAPI_EXTERN napi_status napi_get_cb_data(napi_env e, - napi_callback_info cbinfo, - void** result); -NAPI_EXTERN napi_status napi_is_construct_call(napi_env e, +NAPI_EXTERN napi_status napi_is_construct_call(napi_env env, napi_callback_info cbinfo, bool* result); -NAPI_EXTERN napi_status napi_set_return_value(napi_env e, - napi_callback_info cbinfo, - napi_value value); NAPI_EXTERN napi_status -napi_define_class(napi_env e, +napi_define_class(napi_env env, const char* utf8name, napi_callback constructor, void* data, - int property_count, + size_t property_count, const napi_property_descriptor* properties, napi_value* result); // Methods to work with external data objects -NAPI_EXTERN napi_status napi_wrap(napi_env e, - napi_value jsObject, - void* nativeObj, +NAPI_EXTERN napi_status napi_wrap(napi_env env, + napi_value js_object, + void* native_object, napi_finalize finalize_cb, void* finalize_hint, napi_ref* result); -NAPI_EXTERN napi_status napi_unwrap(napi_env e, - napi_value jsObject, +NAPI_EXTERN napi_status napi_unwrap(napi_env env, + napi_value js_object, void** result); -NAPI_EXTERN napi_status napi_create_external(napi_env e, +NAPI_EXTERN napi_status napi_create_external(napi_env env, void* data, napi_finalize finalize_cb, void* finalize_hint, napi_value* result); -NAPI_EXTERN napi_status napi_get_value_external(napi_env e, +NAPI_EXTERN napi_status napi_get_value_external(napi_env env, napi_value value, void** result); // Methods to control object lifespan // Set initial_refcount to 0 for a weak reference, >0 for a strong reference. -NAPI_EXTERN napi_status napi_create_reference(napi_env e, +NAPI_EXTERN napi_status napi_create_reference(napi_env env, napi_value value, - int initial_refcount, + uint32_t initial_refcount, napi_ref* result); // Deletes a reference. The referenced value is released, and may // be GC'd unless there are other references to it. -NAPI_EXTERN napi_status napi_delete_reference(napi_env e, napi_ref ref); +NAPI_EXTERN napi_status napi_delete_reference(napi_env env, napi_ref ref); // Increments the reference count, optionally returning the resulting count. // After this call the reference will be a strong reference because its // refcount is >0, and the referenced object is effectively "pinned". -// Calling this when the refcount is 0 and the object isunavailable +// Calling this when the refcount is 0 and the object is unavailable // results in an error. -NAPI_EXTERN napi_status napi_reference_addref(napi_env e, - napi_ref ref, - int* result); +NAPI_EXTERN napi_status napi_reference_ref(napi_env env, + napi_ref ref, + uint32_t* result); // Decrements the reference count, optionally returning the resulting count. // If the result is 0 the reference is now weak and the object may be GC'd // at any time if there are no other references. Calling this when the -// refcount is already 0 results in an error. -NAPI_EXTERN napi_status napi_reference_release(napi_env e, - napi_ref ref, - int* result); +// refcount is already 0 results in an error. +NAPI_EXTERN napi_status napi_reference_unref(napi_env env, + napi_ref ref, + uint32_t* result); // Attempts to get a referenced value. If the reference is weak, // the value might no longer be available, in that case the call -// is still successful but the result is NULL. -NAPI_EXTERN napi_status napi_get_reference_value(napi_env e, +// is still successful but the result is NULL. +NAPI_EXTERN napi_status napi_get_reference_value(napi_env env, napi_ref ref, napi_value* result); -NAPI_EXTERN napi_status napi_open_handle_scope(napi_env e, +NAPI_EXTERN napi_status napi_open_handle_scope(napi_env env, napi_handle_scope* result); -NAPI_EXTERN napi_status napi_close_handle_scope(napi_env e, +NAPI_EXTERN napi_status napi_close_handle_scope(napi_env env, napi_handle_scope scope); NAPI_EXTERN napi_status -napi_open_escapable_handle_scope(napi_env e, +napi_open_escapable_handle_scope(napi_env env, napi_escapable_handle_scope* result); NAPI_EXTERN napi_status -napi_close_escapable_handle_scope(napi_env e, +napi_close_escapable_handle_scope(napi_env env, napi_escapable_handle_scope scope); -NAPI_EXTERN napi_status napi_escape_handle(napi_env e, +NAPI_EXTERN napi_status napi_escape_handle(napi_env env, napi_escapable_handle_scope scope, napi_value escapee, napi_value* result); // Methods to support error handling -NAPI_EXTERN napi_status napi_throw(napi_env e, napi_value error); -NAPI_EXTERN napi_status napi_throw_error(napi_env e, const char* msg); -NAPI_EXTERN napi_status napi_throw_type_error(napi_env e, const char* msg); -NAPI_EXTERN napi_status napi_throw_range_error(napi_env e, const char* msg); -NAPI_EXTERN napi_status napi_is_error(napi_env e, +NAPI_EXTERN napi_status napi_throw(napi_env env, napi_value error); +NAPI_EXTERN napi_status napi_throw_error(napi_env env, const char* msg); +NAPI_EXTERN napi_status napi_throw_type_error(napi_env env, const char* msg); +NAPI_EXTERN napi_status napi_throw_range_error(napi_env env, const char* msg); +NAPI_EXTERN napi_status napi_is_error(napi_env env, napi_value value, bool* result); // Methods to support catching exceptions -NAPI_EXTERN napi_status napi_is_exception_pending(napi_env e, bool* result); -NAPI_EXTERN napi_status napi_get_and_clear_last_exception(napi_env e, +NAPI_EXTERN napi_status napi_is_exception_pending(napi_env env, bool* result); +NAPI_EXTERN napi_status napi_get_and_clear_last_exception(napi_env env, napi_value* result); // Methods to provide node::Buffer functionality with napi types -NAPI_EXTERN napi_status napi_create_buffer(napi_env e, - size_t size, +NAPI_EXTERN napi_status napi_create_buffer(napi_env env, + size_t length, void** data, napi_value* result); -NAPI_EXTERN napi_status napi_create_external_buffer(napi_env e, - size_t size, +NAPI_EXTERN napi_status napi_create_external_buffer(napi_env env, + size_t length, void* data, napi_finalize finalize_cb, void* finalize_hint, napi_value* result); -NAPI_EXTERN napi_status napi_create_buffer_copy(napi_env e, +NAPI_EXTERN napi_status napi_create_buffer_copy(napi_env env, + size_t length, const void* data, - size_t size, + void** result_data, napi_value* result); -NAPI_EXTERN napi_status napi_is_buffer(napi_env e, +NAPI_EXTERN napi_status napi_is_buffer(napi_env env, napi_value value, bool* result); -NAPI_EXTERN napi_status napi_get_buffer_info(napi_env e, +NAPI_EXTERN napi_status napi_get_buffer_info(napi_env env, napi_value value, void** data, size_t* length); @@ -482,6 +457,21 @@ NAPI_EXTERN napi_status napi_get_typedarray_info(napi_env env, void** data, napi_value* arraybuffer, size_t* byte_offset); -} // extern "C" + +// Methods to manage simple async operations +NAPI_EXTERN +napi_status napi_create_async_work(napi_env env, + napi_async_execute_callback execute, + napi_async_complete_callback complete, + void* data, + napi_async_work* result); +NAPI_EXTERN napi_status napi_delete_async_work(napi_env env, + napi_async_work work); +NAPI_EXTERN napi_status napi_queue_async_work(napi_env env, + napi_async_work work); +NAPI_EXTERN napi_status napi_cancel_async_work(napi_env env, + napi_async_work work); + +EXTERN_C_END #endif // SRC_NODE_API_H__ diff --git a/src/node_api_async.cc b/src/node_api_async.cc deleted file mode 100644 index baef75358..000000000 --- a/src/node_api_async.cc +++ /dev/null @@ -1,60 +0,0 @@ -#include "node_api_async_internal.h" - -napi_work napi_create_async_work() { - napi_work_impl* worker = - reinterpret_cast(malloc(sizeof(napi_work_impl))); - uv_work_t* req = reinterpret_cast(malloc(sizeof(uv_work_t))); - req->data = worker; - worker->work = req; - return reinterpret_cast(worker); -} - -void napi_delete_async_work(napi_work w) { - napi_work_impl* worker = reinterpret_cast(w); - if (worker != NULL) { - if (worker->work != NULL) { - delete reinterpret_cast(worker->work); - } - delete worker; - worker = NULL; - } -} - -void napi_async_set_data(napi_work w, void* data) { - napi_work_impl* worker = reinterpret_cast(w); - worker->data = data; -} - -void napi_async_set_execute(napi_work w, void (*execute)(void* data)) { - napi_work_impl* worker = reinterpret_cast(w); - worker->execute = execute; -} - -void napi_async_set_complete(napi_work w, void (*complete)(void* data)) { - napi_work_impl* worker = reinterpret_cast(w); - worker->complete = complete; -} - -void napi_async_set_destroy(napi_work w, void (*destroy)(void* data)) { - napi_work_impl* worker = reinterpret_cast(w); - worker->destroy = destroy; -} - -void napi_async_execute(uv_work_t* req) { - napi_work_impl* worker = static_cast(req->data); - worker->execute(worker->data); -} - -void napi_async_complete(uv_work_t* req) { - napi_work_impl* worker = static_cast(req->data); - worker->complete(worker->data); - worker->destroy(worker->data); -} - -void napi_async_queue_worker(napi_work w) { - napi_work_impl* worker = reinterpret_cast(w); - uv_queue_work(uv_default_loop(), - worker->work, - napi_async_execute, - reinterpret_cast(napi_async_complete)); -} diff --git a/src/node_api_async.h b/src/node_api_async.h deleted file mode 100644 index c754d348c..000000000 --- a/src/node_api_async.h +++ /dev/null @@ -1,18 +0,0 @@ -#ifndef SRC_NODE_API_ASYNC_H_ -#define SRC_NODE_API_ASYNC_H_ - -#include -#include "node_api.h" -#include "node_api_async_types.h" - -extern "C" { -NAPI_EXTERN napi_work napi_create_async_work(); -NAPI_EXTERN void napi_delete_async_work(napi_work w); -NAPI_EXTERN void napi_async_set_data(napi_work w, void* data); -NAPI_EXTERN void napi_async_set_execute(napi_work w, void (*execute)(void*)); -NAPI_EXTERN void napi_async_set_complete(napi_work w, void (*complete)(void*)); -NAPI_EXTERN void napi_async_set_destroy(napi_work w, void (*destroy)(void*)); -NAPI_EXTERN void napi_async_queue_worker(napi_work w); -} // extern "C" - -#endif // SRC_NODE_API_ASYNC_H_ diff --git a/src/node_api_async_internal.h b/src/node_api_async_internal.h deleted file mode 100644 index 3022a311e..000000000 --- a/src/node_api_async_internal.h +++ /dev/null @@ -1,20 +0,0 @@ -#ifndef SRC_NODE_API_ASYNC_INTERNAL_H_ -#define SRC_NODE_API_ASYNC_INTERNAL_H_ - -#include "node_api_async.h" -#include "uv.h" - -typedef struct napi_work_impl__ { - uv_work_t* work; - void* data; - void (*execute)(void* data); - void (*complete)(void* data); - void (*destroy)(void* data); -} napi_work_impl; - - -void napi_async_execute(uv_work_t* req); -void napi_async_complete(uv_work_t* req); - - -#endif // SRC_NODE_API_ASYNC_INTERNAL_H_ diff --git a/src/node_api_async_types.h b/src/node_api_async_types.h deleted file mode 100644 index 44e0671c3..000000000 --- a/src/node_api_async_types.h +++ /dev/null @@ -1,8 +0,0 @@ -#ifndef SRC_NODE_API_ASYNC_TYPES_H_ -#define SRC_NODE_API_ASYNC_TYPES_H_ - -// LIBUV API types are all opaque pointers for ABI stability -// typedef undefined structs instead of void* for compile time type safety -typedef struct napi_uv_work_t__ *napi_work; - -#endif // SRC_NODE_API_ASYNC_TYPES_H_ diff --git a/src/node_api_internal.h b/src/node_api_internal.h deleted file mode 100644 index fa6d808c8..000000000 --- a/src/node_api_internal.h +++ /dev/null @@ -1,16 +0,0 @@ -#ifndef SRC_NODE_API_INTERNAL_H_ -#define SRC_NODE_API_INTERNAL_H_ - -#include "node_api.h" -#include "node.h" - -namespace v8impl { - napi_env JsEnvFromV8Isolate(v8::Isolate* isolate); - v8::Isolate* V8IsolateFromJsEnv(napi_env e); - - napi_value JsValueFromV8LocalValue(v8::Local local); - v8::Local V8LocalValueFromJsValue(napi_value v); -} - - -#endif // SRC_NODE_API_INTERNAL_H_ diff --git a/src/node_api_types.h b/src/node_api_types.h index 0607bc145..4bf1b8263 100644 --- a/src/node_api_types.h +++ b/src/node_api_types.h @@ -4,6 +4,10 @@ #include #include +#if !defined __cplusplus || (defined(_MSC_VER) && _MSC_VER < 1900) + typedef uint16_t char16_t; +#endif + // JSVM API types are all opaque pointers for ABI stability // typedef undefined structs instead of void* for compile time type safety typedef struct napi_env__ *napi_env; @@ -12,36 +16,20 @@ typedef struct napi_ref__ *napi_ref; typedef struct napi_handle_scope__ *napi_handle_scope; typedef struct napi_escapable_handle_scope__ *napi_escapable_handle_scope; typedef struct napi_callback_info__ *napi_callback_info; +typedef struct napi_async_work__ *napi_async_work; -typedef void (*napi_callback)(napi_env, napi_callback_info); -typedef void (*napi_finalize)(void* finalize_data, void* finalize_hint); - -enum napi_property_attributes { +typedef enum { napi_default = 0, - napi_read_only = 1 << 0, - napi_dont_enum = 1 << 1, - napi_dont_delete = 1 << 2, + napi_writable = 1 << 0, + napi_enumerable = 1 << 1, + napi_configurable = 1 << 2, // Used with napi_define_class to distinguish static properties // from instance properties. Ignored by napi_define_properties. - napi_static_property = 1 << 10, -}; - -struct napi_property_descriptor { - const char* utf8name; - - napi_callback method; - napi_callback getter; - napi_callback setter; - napi_value value; - - napi_property_attributes attributes; - void* data; -}; + napi_static = 1 << 10, +} napi_property_attributes; -#define DEFAULT_ATTR 0, 0, 0, napi_default, 0 - -enum napi_valuetype { +typedef enum { // ES6 types (corresponds to typeof) napi_undefined, napi_null, @@ -52,38 +40,66 @@ enum napi_valuetype { napi_object, napi_function, napi_external, -}; +} napi_valuetype; -enum napi_typedarray_type { - napi_int8, - napi_uint8, - napi_uint8_clamped, - napi_int16, - napi_uint16, - napi_int32, - napi_uint32, - napi_float32, - napi_float64, -}; +typedef enum { + napi_int8_array, + napi_uint8_array, + napi_uint8_clamped_array, + napi_int16_array, + napi_uint16_array, + napi_int32_array, + napi_uint32_array, + napi_float32_array, + napi_float64_array, +} napi_typedarray_type; -enum napi_status { +typedef enum { napi_ok, napi_invalid_arg, napi_object_expected, napi_string_expected, + napi_name_expected, napi_function_expected, napi_number_expected, napi_boolean_expected, + napi_array_expected, napi_generic_failure, napi_pending_exception, + napi_cancelled, napi_status_last -}; +} napi_status; + +typedef napi_value (*napi_callback)(napi_env env, + napi_callback_info info); +typedef void (*napi_finalize)(napi_env env, + void* finalize_data, + void* finalize_hint); +typedef void (*napi_async_execute_callback)(napi_env env, + void* data); +typedef void (*napi_async_complete_callback)(napi_env env, + napi_status status, + void* data); + +typedef struct { + // One of utf8name or name should be NULL. + const char* utf8name; + napi_value name; + + napi_callback method; + napi_callback getter; + napi_callback setter; + napi_value value; + + napi_property_attributes attributes; + void* data; +} napi_property_descriptor; -struct napi_extended_error_info { +typedef struct { const char* error_message; void* engine_reserved; uint32_t engine_error_code; napi_status error_code; -}; +} napi_extended_error_info; #endif // SRC_NODE_API_TYPES_H_