1 #include <node_buffer.h>
2 #include <node_object_wrap.h>
3 #include <limits.h> // INT_MAX
4 #include <string.h>
5 #include <algorithm>
6 #include <cmath>
7 #include <vector>
8 #define NAPI_EXPERIMENTAL
9 #include "node_api.h"
10 #include "node_internals.h"
11 #include "env.h"
12
13 static
14 napi_status napi_set_last_error(napi_env env, napi_status error_code,
15 uint32_t engine_error_code = 0,
16 void* engine_reserved = nullptr);
17 static
18 napi_status napi_clear_last_error(napi_env env);
19
20 struct napi_env__ {
napi_env__napi_env__21 explicit napi_env__(v8::Local<v8::Context> context)
22 : isolate(context->GetIsolate()),
23 context_persistent(isolate, context) {
24 CHECK_EQ(isolate, context->GetIsolate());
25 CHECK_NOT_NULL(node_env());
26 }
27
~napi_env__napi_env__28 virtual ~napi_env__() {
29 if (instance_data.finalize_cb != nullptr) {
30 CallIntoModuleThrow([&](napi_env env) {
31 instance_data.finalize_cb(env, instance_data.data, instance_data.hint);
32 });
33 }
34 }
35
36 v8::Isolate* const isolate; // Shortcut for context()->GetIsolate()
37 node::Persistent<v8::Context> context_persistent;
38
contextnapi_env__39 inline v8::Local<v8::Context> context() const {
40 return StrongPersistentToLocal(context_persistent);
41 }
42
node_envnapi_env__43 inline node::Environment* node_env() const {
44 return node::Environment::GetCurrent(context());
45 }
46
Refnapi_env__47 inline void Ref() { refs++; }
Unrefnapi_env__48 inline void Unref() { if (--refs == 0) delete this; }
49
50 template <typename T, typename U>
CallIntoModulenapi_env__51 void CallIntoModule(T&& call, U&& handle_exception) {
52 int open_handle_scopes_before = open_handle_scopes;
53 int open_callback_scopes_before = open_callback_scopes;
54 napi_clear_last_error(this);
55 call(this);
56 CHECK_EQ(open_handle_scopes, open_handle_scopes_before);
57 CHECK_EQ(open_callback_scopes, open_callback_scopes_before);
58 if (!last_exception.IsEmpty()) {
59 handle_exception(this, last_exception.Get(this->isolate));
60 last_exception.Reset();
61 }
62 }
63
64 template <typename T>
CallIntoModuleThrownapi_env__65 void CallIntoModuleThrow(T&& call) {
66 CallIntoModule(call, [&](napi_env env, v8::Local<v8::Value> value) {
67 env->isolate->ThrowException(value);
68 });
69 }
70
71 node::Persistent<v8::Value> last_exception;
72 napi_extended_error_info last_error;
73 int open_handle_scopes = 0;
74 int open_callback_scopes = 0;
75 int refs = 1;
76 struct {
77 void* data = nullptr;
78 void* hint = nullptr;
79 napi_finalize finalize_cb = nullptr;
80 } instance_data;
81 };
82
83 #define NAPI_PRIVATE_KEY(context, suffix) \
84 (node::Environment::GetCurrent((context))->napi_ ## suffix())
85
86 #define RETURN_STATUS_IF_FALSE(env, condition, status) \
87 do { \
88 if (!(condition)) { \
89 return napi_set_last_error((env), (status)); \
90 } \
91 } while (0)
92
93 #define CHECK_ENV(env) \
94 do { \
95 if ((env) == nullptr) { \
96 return napi_invalid_arg; \
97 } \
98 } while (0)
99
100 #define CHECK_ARG(env, arg) \
101 RETURN_STATUS_IF_FALSE((env), ((arg) != nullptr), napi_invalid_arg)
102
103 #define CHECK_MAYBE_EMPTY(env, maybe, status) \
104 RETURN_STATUS_IF_FALSE((env), !((maybe).IsEmpty()), (status))
105
106 #define CHECK_MAYBE_NOTHING(env, maybe, status) \
107 RETURN_STATUS_IF_FALSE((env), !((maybe).IsNothing()), (status))
108
109 // NAPI_PREAMBLE is not wrapped in do..while: try_catch must have function scope
110 #define NAPI_PREAMBLE(env) \
111 CHECK_ENV((env)); \
112 RETURN_STATUS_IF_FALSE((env), (env)->last_exception.IsEmpty(), \
113 napi_pending_exception); \
114 napi_clear_last_error((env)); \
115 v8impl::TryCatch try_catch((env))
116
117 #define CHECK_TO_TYPE(env, type, context, result, src, status) \
118 do { \
119 CHECK_ARG((env), (src)); \
120 auto maybe = v8impl::V8LocalValueFromJsValue((src))->To##type((context)); \
121 CHECK_MAYBE_EMPTY((env), maybe, (status)); \
122 (result) = maybe.ToLocalChecked(); \
123 } while (0)
124
125 #define CHECK_TO_FUNCTION(env, result, src) \
126 do { \
127 CHECK_ARG((env), (src)); \
128 v8::Local<v8::Value> v8value = v8impl::V8LocalValueFromJsValue((src)); \
129 RETURN_STATUS_IF_FALSE((env), v8value->IsFunction(), napi_invalid_arg); \
130 (result) = v8value.As<v8::Function>(); \
131 } while (0)
132
133 #define CHECK_TO_OBJECT(env, context, result, src) \
134 CHECK_TO_TYPE((env), Object, (context), (result), (src), napi_object_expected)
135
136 #define CHECK_TO_STRING(env, context, result, src) \
137 CHECK_TO_TYPE((env), String, (context), (result), (src), napi_string_expected)
138
139 #define CHECK_TO_NUMBER(env, context, result, src) \
140 CHECK_TO_TYPE((env), Number, (context), (result), (src), napi_number_expected)
141
142 #define CHECK_TO_BOOL(env, context, result, src) \
143 CHECK_TO_TYPE((env), Boolean, (context), (result), (src), \
144 napi_boolean_expected)
145
146 // n-api defines NAPI_AUTO_LENGHTH as the indicator that a string
147 // is null terminated. For V8 the equivalent is -1. The assert
148 // validates that our cast of NAPI_AUTO_LENGTH results in -1 as
149 // needed by V8.
150 #define CHECK_NEW_FROM_UTF8_LEN(env, result, str, len) \
151 do { \
152 static_assert(static_cast<int>(NAPI_AUTO_LENGTH) == -1, \
153 "Casting NAPI_AUTO_LENGTH to int must result in -1"); \
154 RETURN_STATUS_IF_FALSE((env), \
155 (len == NAPI_AUTO_LENGTH) || len <= INT_MAX, \
156 napi_invalid_arg); \
157 auto str_maybe = v8::String::NewFromUtf8( \
158 (env)->isolate, (str), v8::NewStringType::kInternalized, \
159 static_cast<int>(len)); \
160 CHECK_MAYBE_EMPTY((env), str_maybe, napi_generic_failure); \
161 (result) = str_maybe.ToLocalChecked(); \
162 } while (0)
163
164 #define CHECK_NEW_FROM_UTF8(env, result, str) \
165 CHECK_NEW_FROM_UTF8_LEN((env), (result), (str), NAPI_AUTO_LENGTH)
166
167 #define GET_RETURN_STATUS(env) \
168 (!try_catch.HasCaught() ? napi_ok \
169 : napi_set_last_error((env), napi_pending_exception))
170
171 #define THROW_RANGE_ERROR_IF_FALSE(env, condition, error, message) \
172 do { \
173 if (!(condition)) { \
174 napi_throw_range_error((env), (error), (message)); \
175 return napi_set_last_error((env), napi_generic_failure); \
176 } \
177 } while (0)
178
179 #define CREATE_TYPED_ARRAY( \
180 env, type, size_of_element, buffer, byte_offset, length, out) \
181 do { \
182 if ((size_of_element) > 1) { \
183 THROW_RANGE_ERROR_IF_FALSE( \
184 (env), (byte_offset) % (size_of_element) == 0, \
185 "ERR_NAPI_INVALID_TYPEDARRAY_ALIGNMENT", \
186 "start offset of "#type" should be a multiple of "#size_of_element); \
187 } \
188 THROW_RANGE_ERROR_IF_FALSE((env), (length) * (size_of_element) + \
189 (byte_offset) <= buffer->ByteLength(), \
190 "ERR_NAPI_INVALID_TYPEDARRAY_LENGTH", \
191 "Invalid typed array length"); \
192 (out) = v8::type::New((buffer), (byte_offset), (length)); \
193 } while (0)
194
195 #define RETURN_STATUS_IF_FALSE_WITH_PREAMBLE(env, condition, status) \
196 do { \
197 if (!(condition)) { \
198 return napi_set_last_error( \
199 (env), try_catch.HasCaught() ? napi_pending_exception : (status)); \
200 } \
201 } while (0)
202
203 #define CHECK_MAYBE_EMPTY_WITH_PREAMBLE(env, maybe, status) \
204 RETURN_STATUS_IF_FALSE_WITH_PREAMBLE((env), !((maybe).IsEmpty()), (status))
205
206 namespace {
207 namespace v8impl {
208
209 // convert from n-api property attributes to v8::PropertyAttribute
V8PropertyAttributesFromDescriptor(const napi_property_descriptor * descriptor)210 static inline v8::PropertyAttribute V8PropertyAttributesFromDescriptor(
211 const napi_property_descriptor* descriptor) {
212 unsigned int attribute_flags = v8::PropertyAttribute::None;
213
214 if (descriptor->getter != nullptr || descriptor->setter != nullptr) {
215 // The napi_writable attribute is ignored for accessor descriptors, but
216 // V8 requires the ReadOnly attribute to match nonexistence of a setter.
217 attribute_flags |= (descriptor->setter == nullptr ?
218 v8::PropertyAttribute::ReadOnly : v8::PropertyAttribute::None);
219 } else if ((descriptor->attributes & napi_writable) == 0) {
220 attribute_flags |= v8::PropertyAttribute::ReadOnly;
221 }
222
223 if ((descriptor->attributes & napi_enumerable) == 0) {
224 attribute_flags |= v8::PropertyAttribute::DontEnum;
225 }
226 if ((descriptor->attributes & napi_configurable) == 0) {
227 attribute_flags |= v8::PropertyAttribute::DontDelete;
228 }
229
230 return static_cast<v8::PropertyAttribute>(attribute_flags);
231 }
232
233 class HandleScopeWrapper {
234 public:
HandleScopeWrapper(v8::Isolate * isolate)235 explicit HandleScopeWrapper(v8::Isolate* isolate) : scope(isolate) {}
236
237 private:
238 v8::HandleScope scope;
239 };
240
241 // In node v0.10 version of v8, there is no EscapableHandleScope and the
242 // node v0.10 port use HandleScope::Close(Local<T> v) to mimic the behavior
243 // of a EscapableHandleScope::Escape(Local<T> v), but it is not the same
244 // semantics. This is an example of where the api abstraction fail to work
245 // across different versions.
246 class EscapableHandleScopeWrapper {
247 public:
EscapableHandleScopeWrapper(v8::Isolate * isolate)248 explicit EscapableHandleScopeWrapper(v8::Isolate* isolate)
249 : scope(isolate), escape_called_(false) {}
escape_called() const250 bool escape_called() const {
251 return escape_called_;
252 }
253 template <typename T>
Escape(v8::Local<T> handle)254 v8::Local<T> Escape(v8::Local<T> handle) {
255 escape_called_ = true;
256 return scope.Escape(handle);
257 }
258
259 private:
260 v8::EscapableHandleScope scope;
261 bool escape_called_;
262 };
263
264 static
JsHandleScopeFromV8HandleScope(HandleScopeWrapper * s)265 napi_handle_scope JsHandleScopeFromV8HandleScope(HandleScopeWrapper* s) {
266 return reinterpret_cast<napi_handle_scope>(s);
267 }
268
269 static
V8HandleScopeFromJsHandleScope(napi_handle_scope s)270 HandleScopeWrapper* V8HandleScopeFromJsHandleScope(napi_handle_scope s) {
271 return reinterpret_cast<HandleScopeWrapper*>(s);
272 }
273
274 static
JsEscapableHandleScopeFromV8EscapableHandleScope(EscapableHandleScopeWrapper * s)275 napi_escapable_handle_scope JsEscapableHandleScopeFromV8EscapableHandleScope(
276 EscapableHandleScopeWrapper* s) {
277 return reinterpret_cast<napi_escapable_handle_scope>(s);
278 }
279
280 static
281 EscapableHandleScopeWrapper*
V8EscapableHandleScopeFromJsEscapableHandleScope(napi_escapable_handle_scope s)282 V8EscapableHandleScopeFromJsEscapableHandleScope(
283 napi_escapable_handle_scope s) {
284 return reinterpret_cast<EscapableHandleScopeWrapper*>(s);
285 }
286
287 static
JsCallbackScopeFromV8CallbackScope(node::CallbackScope * s)288 napi_callback_scope JsCallbackScopeFromV8CallbackScope(
289 node::CallbackScope* s) {
290 return reinterpret_cast<napi_callback_scope>(s);
291 }
292
293 static
V8CallbackScopeFromJsCallbackScope(napi_callback_scope s)294 node::CallbackScope* V8CallbackScopeFromJsCallbackScope(
295 napi_callback_scope s) {
296 return reinterpret_cast<node::CallbackScope*>(s);
297 }
298
299 //=== Conversion between V8 Handles and napi_value ========================
300
301 // This asserts v8::Local<> will always be implemented with a single
302 // pointer field so that we can pass it around as a void*.
303 static_assert(sizeof(v8::Local<v8::Value>) == sizeof(napi_value),
304 "Cannot convert between v8::Local<v8::Value> and napi_value");
305
306 static
JsDeferredFromNodePersistent(node::Persistent<v8::Value> * local)307 napi_deferred JsDeferredFromNodePersistent(node::Persistent<v8::Value>* local) {
308 return reinterpret_cast<napi_deferred>(local);
309 }
310
311 static
NodePersistentFromJsDeferred(napi_deferred local)312 node::Persistent<v8::Value>* NodePersistentFromJsDeferred(napi_deferred local) {
313 return reinterpret_cast<node::Persistent<v8::Value>*>(local);
314 }
315
316 static
JsValueFromV8LocalValue(v8::Local<v8::Value> local)317 napi_value JsValueFromV8LocalValue(v8::Local<v8::Value> local) {
318 return reinterpret_cast<napi_value>(*local);
319 }
320
321 static
V8LocalValueFromJsValue(napi_value v)322 v8::Local<v8::Value> V8LocalValueFromJsValue(napi_value v) {
323 v8::Local<v8::Value> local;
324 memcpy(&local, &v, sizeof(v));
325 return local;
326 }
327
trigger_fatal_exception(napi_env env,v8::Local<v8::Value> local_err)328 static inline void trigger_fatal_exception(
329 napi_env env, v8::Local<v8::Value> local_err) {
330 v8::Local<v8::Message> local_msg =
331 v8::Exception::CreateMessage(env->isolate, local_err);
332 node::FatalException(env->isolate, local_err, local_msg);
333 }
334
V8NameFromPropertyDescriptor(napi_env env,const napi_property_descriptor * p,v8::Local<v8::Name> * result)335 static inline napi_status V8NameFromPropertyDescriptor(napi_env env,
336 const napi_property_descriptor* p,
337 v8::Local<v8::Name>* result) {
338 if (p->utf8name != nullptr) {
339 CHECK_NEW_FROM_UTF8(env, *result, p->utf8name);
340 } else {
341 v8::Local<v8::Value> property_value =
342 v8impl::V8LocalValueFromJsValue(p->name);
343
344 RETURN_STATUS_IF_FALSE(env, property_value->IsName(), napi_name_expected);
345 *result = property_value.As<v8::Name>();
346 }
347
348 return napi_ok;
349 }
350
351 // Adapter for napi_finalize callbacks.
352 class Finalizer {
353 protected:
Finalizer(napi_env env,napi_finalize finalize_callback,void * finalize_data,void * finalize_hint)354 Finalizer(napi_env env,
355 napi_finalize finalize_callback,
356 void* finalize_data,
357 void* finalize_hint)
358 : _env(env),
359 _finalize_callback(finalize_callback),
360 _finalize_data(finalize_data),
361 _finalize_hint(finalize_hint) {
362 }
363
~Finalizer()364 ~Finalizer() {
365 }
366
367 public:
New(napi_env env,napi_finalize finalize_callback=nullptr,void * finalize_data=nullptr,void * finalize_hint=nullptr)368 static Finalizer* New(napi_env env,
369 napi_finalize finalize_callback = nullptr,
370 void* finalize_data = nullptr,
371 void* finalize_hint = nullptr) {
372 return new Finalizer(
373 env, finalize_callback, finalize_data, finalize_hint);
374 }
375
Delete(Finalizer * finalizer)376 static void Delete(Finalizer* finalizer) {
377 delete finalizer;
378 }
379
380 // node::Buffer::FreeCallback
FinalizeBufferCallback(char * data,void * hint)381 static void FinalizeBufferCallback(char* data, void* hint) {
382 Finalizer* finalizer = static_cast<Finalizer*>(hint);
383 if (finalizer->_finalize_callback != nullptr) {
384 finalizer->_env->CallIntoModuleThrow([&](napi_env env) {
385 finalizer->_finalize_callback(env, data, finalizer->_finalize_hint);
386 });
387 }
388
389 Delete(finalizer);
390 }
391
392 protected:
393 napi_env _env;
394 napi_finalize _finalize_callback;
395 void* _finalize_data;
396 void* _finalize_hint;
397 bool _finalize_ran = false;
398 };
399
400 // Wrapper around node::Persistent that implements reference counting.
401 class Reference : private Finalizer {
402 private:
Reference(napi_env env,v8::Local<v8::Value> value,uint32_t initial_refcount,bool delete_self,napi_finalize finalize_callback,void * finalize_data,void * finalize_hint)403 Reference(napi_env env,
404 v8::Local<v8::Value> value,
405 uint32_t initial_refcount,
406 bool delete_self,
407 napi_finalize finalize_callback,
408 void* finalize_data,
409 void* finalize_hint)
410 : Finalizer(env, finalize_callback, finalize_data, finalize_hint),
411 _persistent(env->isolate, value),
412 _refcount(initial_refcount),
413 _delete_self(delete_self) {
414 if (initial_refcount == 0) {
415 _persistent.SetWeak(
416 this, FinalizeCallback, v8::WeakCallbackType::kParameter);
417 }
418 }
419
420 public:
Data()421 void* Data() {
422 return _finalize_data;
423 }
424
New(napi_env env,v8::Local<v8::Value> value,uint32_t initial_refcount,bool delete_self,napi_finalize finalize_callback=nullptr,void * finalize_data=nullptr,void * finalize_hint=nullptr)425 static Reference* New(napi_env env,
426 v8::Local<v8::Value> value,
427 uint32_t initial_refcount,
428 bool delete_self,
429 napi_finalize finalize_callback = nullptr,
430 void* finalize_data = nullptr,
431 void* finalize_hint = nullptr) {
432 return new Reference(env,
433 value,
434 initial_refcount,
435 delete_self,
436 finalize_callback,
437 finalize_data,
438 finalize_hint);
439 }
440
441 // Delete is called in 2 ways. Either from the finalizer or
442 // from one of Unwrap or napi_delete_reference.
443 //
444 // When it is called from Unwrap or napi_delete_reference we only
445 // want to do the delete if the finalizer has already run,
446 // otherwise we may crash when the finalizer does run.
447 // If the finalizer has not already run delay the delete until
448 // the finalizer runs by not doing the delete
449 // and setting _delete_self to true so that the finalizer will
450 // delete it when it runs.
451 //
452 // The second way this is called is from
453 // the finalizer and _delete_self is set. In this case we
454 // know we need to do the deletion so just do it.
Delete(Reference * reference)455 static void Delete(Reference* reference) {
456 if ((reference->_delete_self) || (reference->_finalize_ran)) {
457 delete reference;
458 } else {
459 // reduce the reference count to 0 and defer until
460 // finalizer runs
461 reference->_delete_self = true;
462 while (reference->Unref() != 0) {}
463 }
464 }
465
Ref()466 uint32_t Ref() {
467 if (++_refcount == 1) {
468 _persistent.ClearWeak();
469 }
470
471 return _refcount;
472 }
473
Unref()474 uint32_t Unref() {
475 if (_refcount == 0) {
476 return 0;
477 }
478 if (--_refcount == 0) {
479 _persistent.SetWeak(
480 this, FinalizeCallback, v8::WeakCallbackType::kParameter);
481 }
482
483 return _refcount;
484 }
485
RefCount()486 uint32_t RefCount() {
487 return _refcount;
488 }
489
Get()490 v8::Local<v8::Value> Get() {
491 if (_persistent.IsEmpty()) {
492 return v8::Local<v8::Value>();
493 } else {
494 return v8::Local<v8::Value>::New(_env->isolate, _persistent);
495 }
496 }
497
498 private:
499 // The N-API finalizer callback may make calls into the engine. V8's heap is
500 // not in a consistent state during the weak callback, and therefore it does
501 // not support calls back into it. However, it provides a mechanism for adding
502 // a finalizer which may make calls back into the engine by allowing us to
503 // attach such a second-pass finalizer from the first pass finalizer. Thus,
504 // we do that here to ensure that the N-API finalizer callback is free to call
505 // into the engine.
FinalizeCallback(const v8::WeakCallbackInfo<Reference> & data)506 static void FinalizeCallback(const v8::WeakCallbackInfo<Reference>& data) {
507 Reference* reference = data.GetParameter();
508
509 // The reference must be reset during the first pass.
510 reference->_persistent.Reset();
511
512 data.SetSecondPassCallback(SecondPassCallback);
513 }
514
SecondPassCallback(const v8::WeakCallbackInfo<Reference> & data)515 static void SecondPassCallback(const v8::WeakCallbackInfo<Reference>& data) {
516 Reference* reference = data.GetParameter();
517
518 if (reference->_finalize_callback != nullptr) {
519 reference->_env->CallIntoModuleThrow([&](napi_env env) {
520 reference->_finalize_callback(
521 env,
522 reference->_finalize_data,
523 reference->_finalize_hint);
524 });
525 }
526
527 // this is safe because if a request to delete the reference
528 // is made in the finalize_callback it will defer deletion
529 // to this block and set _delete_self to true
530 if (reference->_delete_self) {
531 Delete(reference);
532 } else {
533 reference->_finalize_ran = true;
534 }
535 }
536
537 node::Persistent<v8::Value> _persistent;
538 uint32_t _refcount;
539 bool _delete_self;
540 };
541
542 class TryCatch : public v8::TryCatch {
543 public:
TryCatch(napi_env env)544 explicit TryCatch(napi_env env)
545 : v8::TryCatch(env->isolate), _env(env) {}
546
~TryCatch()547 ~TryCatch() {
548 if (HasCaught()) {
549 _env->last_exception.Reset(_env->isolate, Exception());
550 }
551 }
552
553 private:
554 napi_env _env;
555 };
556
557 //=== Function napi_callback wrapper =================================
558
559 // Use this data structure to associate callback data with each N-API function
560 // exposed to JavaScript. The structure is stored in a v8::External which gets
561 // passed into our callback wrapper. This reduces the performance impact of
562 // calling through N-API.
563 // Ref: benchmark/misc/function_call
564 // Discussion (incl. perf. data): https://github.com/nodejs/node/pull/21072
565 struct CallbackBundle {
566 // Bind the lifecycle of `this` C++ object to a JavaScript object.
567 // We never delete a CallbackBundle C++ object directly.
BindLifecycleTo__anon94cd3a6a0411::v8impl::CallbackBundle568 void BindLifecycleTo(v8::Isolate* isolate, v8::Local<v8::Value> target) {
569 handle.Reset(isolate, target);
570 handle.SetWeak(this, WeakCallback, v8::WeakCallbackType::kParameter);
571 }
572
573 napi_env env; // Necessary to invoke C++ NAPI callback
574 void* cb_data; // The user provided callback data
575 napi_callback function_or_getter;
576 napi_callback setter;
577 node::Persistent<v8::Value> handle; // Die with this JavaScript object
578
579 private:
WeakCallback__anon94cd3a6a0411::v8impl::CallbackBundle580 static void WeakCallback(v8::WeakCallbackInfo<CallbackBundle> const& info) {
581 // Use the "WeakCallback mechanism" to delete the C++ `bundle` object.
582 // This will be called when the v8::External containing `this` pointer
583 // is being GC-ed.
584 CallbackBundle* bundle = info.GetParameter();
585 if (bundle != nullptr) {
586 delete bundle;
587 }
588 }
589 };
590
591 // Base class extended by classes that wrap V8 function and property callback
592 // info.
593 class CallbackWrapper {
594 public:
CallbackWrapper(napi_value this_arg,size_t args_length,void * data)595 CallbackWrapper(napi_value this_arg, size_t args_length, void* data)
596 : _this(this_arg), _args_length(args_length), _data(data) {}
597
598 virtual napi_value GetNewTarget() = 0;
599 virtual void Args(napi_value* buffer, size_t bufferlength) = 0;
600 virtual void SetReturnValue(napi_value value) = 0;
601
This()602 napi_value This() { return _this; }
603
ArgsLength()604 size_t ArgsLength() { return _args_length; }
605
Data()606 void* Data() { return _data; }
607
608 protected:
609 const napi_value _this;
610 const size_t _args_length;
611 void* _data;
612 };
613
614 template <typename Info, napi_callback CallbackBundle::*FunctionField>
615 class CallbackWrapperBase : public CallbackWrapper {
616 public:
CallbackWrapperBase(const Info & cbinfo,const size_t args_length)617 CallbackWrapperBase(const Info& cbinfo, const size_t args_length)
618 : CallbackWrapper(JsValueFromV8LocalValue(cbinfo.This()),
619 args_length,
620 nullptr),
621 _cbinfo(cbinfo) {
622 _bundle = reinterpret_cast<CallbackBundle*>(
623 v8::Local<v8::External>::Cast(cbinfo.Data())->Value());
624 _data = _bundle->cb_data;
625 }
626
GetNewTarget()627 napi_value GetNewTarget() override { return nullptr; }
628
629 protected:
InvokeCallback()630 void InvokeCallback() {
631 napi_callback_info cbinfo_wrapper = reinterpret_cast<napi_callback_info>(
632 static_cast<CallbackWrapper*>(this));
633
634 // All other pointers we need are stored in `_bundle`
635 napi_env env = _bundle->env;
636 napi_callback cb = _bundle->*FunctionField;
637
638 napi_value result;
639 env->CallIntoModuleThrow([&](napi_env env) {
640 result = cb(env, cbinfo_wrapper);
641 });
642
643 if (result != nullptr) {
644 this->SetReturnValue(result);
645 }
646 }
647
648 const Info& _cbinfo;
649 CallbackBundle* _bundle;
650 };
651
652 class FunctionCallbackWrapper
653 : public CallbackWrapperBase<v8::FunctionCallbackInfo<v8::Value>,
654 &CallbackBundle::function_or_getter> {
655 public:
Invoke(const v8::FunctionCallbackInfo<v8::Value> & info)656 static void Invoke(const v8::FunctionCallbackInfo<v8::Value>& info) {
657 FunctionCallbackWrapper cbwrapper(info);
658 cbwrapper.InvokeCallback();
659 }
660
FunctionCallbackWrapper(const v8::FunctionCallbackInfo<v8::Value> & cbinfo)661 explicit FunctionCallbackWrapper(
662 const v8::FunctionCallbackInfo<v8::Value>& cbinfo)
663 : CallbackWrapperBase(cbinfo, cbinfo.Length()) {}
664
GetNewTarget()665 napi_value GetNewTarget() override {
666 if (_cbinfo.IsConstructCall()) {
667 return v8impl::JsValueFromV8LocalValue(_cbinfo.NewTarget());
668 } else {
669 return nullptr;
670 }
671 }
672
673 /*virtual*/
Args(napi_value * buffer,size_t buffer_length)674 void Args(napi_value* buffer, size_t buffer_length) override {
675 size_t i = 0;
676 size_t min = std::min(buffer_length, _args_length);
677
678 for (; i < min; i += 1) {
679 buffer[i] = v8impl::JsValueFromV8LocalValue(_cbinfo[i]);
680 }
681
682 if (i < buffer_length) {
683 napi_value undefined =
684 v8impl::JsValueFromV8LocalValue(v8::Undefined(_cbinfo.GetIsolate()));
685 for (; i < buffer_length; i += 1) {
686 buffer[i] = undefined;
687 }
688 }
689 }
690
691 /*virtual*/
SetReturnValue(napi_value value)692 void SetReturnValue(napi_value value) override {
693 v8::Local<v8::Value> val = v8impl::V8LocalValueFromJsValue(value);
694 _cbinfo.GetReturnValue().Set(val);
695 }
696 };
697
698 class GetterCallbackWrapper
699 : public CallbackWrapperBase<v8::PropertyCallbackInfo<v8::Value>,
700 &CallbackBundle::function_or_getter> {
701 public:
Invoke(v8::Local<v8::Name> property,const v8::PropertyCallbackInfo<v8::Value> & info)702 static void Invoke(v8::Local<v8::Name> property,
703 const v8::PropertyCallbackInfo<v8::Value>& info) {
704 GetterCallbackWrapper cbwrapper(info);
705 cbwrapper.InvokeCallback();
706 }
707
GetterCallbackWrapper(const v8::PropertyCallbackInfo<v8::Value> & cbinfo)708 explicit GetterCallbackWrapper(
709 const v8::PropertyCallbackInfo<v8::Value>& cbinfo)
710 : CallbackWrapperBase(cbinfo, 0) {}
711
712 /*virtual*/
Args(napi_value * buffer,size_t buffer_length)713 void Args(napi_value* buffer, size_t buffer_length) override {
714 if (buffer_length > 0) {
715 napi_value undefined =
716 v8impl::JsValueFromV8LocalValue(v8::Undefined(_cbinfo.GetIsolate()));
717 for (size_t i = 0; i < buffer_length; i += 1) {
718 buffer[i] = undefined;
719 }
720 }
721 }
722
723 /*virtual*/
SetReturnValue(napi_value value)724 void SetReturnValue(napi_value value) override {
725 v8::Local<v8::Value> val = v8impl::V8LocalValueFromJsValue(value);
726 _cbinfo.GetReturnValue().Set(val);
727 }
728 };
729
730 class SetterCallbackWrapper
731 : public CallbackWrapperBase<v8::PropertyCallbackInfo<void>,
732 &CallbackBundle::setter> {
733 public:
Invoke(v8::Local<v8::Name> property,v8::Local<v8::Value> value,const v8::PropertyCallbackInfo<void> & info)734 static void Invoke(v8::Local<v8::Name> property,
735 v8::Local<v8::Value> value,
736 const v8::PropertyCallbackInfo<void>& info) {
737 SetterCallbackWrapper cbwrapper(info, value);
738 cbwrapper.InvokeCallback();
739 }
740
SetterCallbackWrapper(const v8::PropertyCallbackInfo<void> & cbinfo,const v8::Local<v8::Value> & value)741 SetterCallbackWrapper(const v8::PropertyCallbackInfo<void>& cbinfo,
742 const v8::Local<v8::Value>& value)
743 : CallbackWrapperBase(cbinfo, 1), _value(value) {}
744
745 /*virtual*/
Args(napi_value * buffer,size_t buffer_length)746 void Args(napi_value* buffer, size_t buffer_length) override {
747 if (buffer_length > 0) {
748 buffer[0] = v8impl::JsValueFromV8LocalValue(_value);
749
750 if (buffer_length > 1) {
751 napi_value undefined = v8impl::JsValueFromV8LocalValue(
752 v8::Undefined(_cbinfo.GetIsolate()));
753 for (size_t i = 1; i < buffer_length; i += 1) {
754 buffer[i] = undefined;
755 }
756 }
757 }
758 }
759
760 /*virtual*/
SetReturnValue(napi_value value)761 void SetReturnValue(napi_value value) override {
762 // Ignore any value returned from a setter callback.
763 }
764
765 private:
766 const v8::Local<v8::Value>& _value;
767 };
768
769 // Creates an object to be made available to the static function callback
770 // wrapper, used to retrieve the native callback function and data pointer.
771 static
CreateFunctionCallbackData(napi_env env,napi_callback cb,void * data)772 v8::Local<v8::Value> CreateFunctionCallbackData(napi_env env,
773 napi_callback cb,
774 void* data) {
775 CallbackBundle* bundle = new CallbackBundle();
776 bundle->function_or_getter = cb;
777 bundle->cb_data = data;
778 bundle->env = env;
779 v8::Local<v8::Value> cbdata = v8::External::New(env->isolate, bundle);
780 bundle->BindLifecycleTo(env->isolate, cbdata);
781
782 return cbdata;
783 }
784
785 // Creates an object to be made available to the static getter/setter
786 // callback wrapper, used to retrieve the native getter/setter callback
787 // function and data pointer.
788 static
CreateAccessorCallbackData(napi_env env,napi_callback getter,napi_callback setter,void * data)789 v8::Local<v8::Value> CreateAccessorCallbackData(napi_env env,
790 napi_callback getter,
791 napi_callback setter,
792 void* data) {
793 CallbackBundle* bundle = new CallbackBundle();
794 bundle->function_or_getter = getter;
795 bundle->setter = setter;
796 bundle->cb_data = data;
797 bundle->env = env;
798 v8::Local<v8::Value> cbdata = v8::External::New(env->isolate, bundle);
799 bundle->BindLifecycleTo(env->isolate, cbdata);
800
801 return cbdata;
802 }
803
804 static
NewEnv(v8::Local<v8::Context> context)805 napi_env NewEnv(v8::Local<v8::Context> context) {
806 napi_env result;
807
808 result = new napi_env__(context);
809 // TODO(addaleax): There was previously code that tried to delete the
810 // napi_env when its v8::Context was garbage collected;
811 // However, as long as N-API addons using this napi_env are in place,
812 // the Context needs to be accessible and alive.
813 // Ideally, we'd want an on-addon-unload hook that takes care of this
814 // once all N-API addons using this napi_env are unloaded.
815 // For now, a per-Environment cleanup hook is the best we can do.
816 result->node_env()->AddCleanupHook(
817 [](void* arg) {
818 static_cast<napi_env>(arg)->Unref();
819 },
820 static_cast<void*>(result));
821
822 return result;
823 }
824
825 enum UnwrapAction {
826 KeepWrap,
827 RemoveWrap
828 };
829
830 static
Unwrap(napi_env env,napi_value js_object,void ** result,UnwrapAction action)831 napi_status Unwrap(napi_env env,
832 napi_value js_object,
833 void** result,
834 UnwrapAction action) {
835 NAPI_PREAMBLE(env);
836 CHECK_ARG(env, js_object);
837 if (action == KeepWrap) {
838 CHECK_ARG(env, result);
839 }
840
841 v8::Local<v8::Context> context = env->context();
842
843 v8::Local<v8::Value> value = v8impl::V8LocalValueFromJsValue(js_object);
844 RETURN_STATUS_IF_FALSE(env, value->IsObject(), napi_invalid_arg);
845 v8::Local<v8::Object> obj = value.As<v8::Object>();
846
847 auto val = obj->GetPrivate(context, NAPI_PRIVATE_KEY(context, wrapper))
848 .ToLocalChecked();
849 RETURN_STATUS_IF_FALSE(env, val->IsExternal(), napi_invalid_arg);
850 Reference* reference =
851 static_cast<v8impl::Reference*>(val.As<v8::External>()->Value());
852
853 if (result) {
854 *result = reference->Data();
855 }
856
857 if (action == RemoveWrap) {
858 CHECK(obj->DeletePrivate(context, NAPI_PRIVATE_KEY(context, wrapper))
859 .FromJust());
860 Reference::Delete(reference);
861 }
862
863 return GET_RETURN_STATUS(env);
864 }
865
866 static
ConcludeDeferred(napi_env env,napi_deferred deferred,napi_value result,bool is_resolved)867 napi_status ConcludeDeferred(napi_env env,
868 napi_deferred deferred,
869 napi_value result,
870 bool is_resolved) {
871 NAPI_PREAMBLE(env);
872 CHECK_ARG(env, result);
873
874 v8::Local<v8::Context> context = env->context();
875 node::Persistent<v8::Value>* deferred_ref =
876 NodePersistentFromJsDeferred(deferred);
877 v8::Local<v8::Value> v8_deferred =
878 v8::Local<v8::Value>::New(env->isolate, *deferred_ref);
879
880 auto v8_resolver = v8::Local<v8::Promise::Resolver>::Cast(v8_deferred);
881
882 v8::Maybe<bool> success = is_resolved ?
883 v8_resolver->Resolve(context, v8impl::V8LocalValueFromJsValue(result)) :
884 v8_resolver->Reject(context, v8impl::V8LocalValueFromJsValue(result));
885
886 delete deferred_ref;
887
888 RETURN_STATUS_IF_FALSE(env, success.FromMaybe(false), napi_generic_failure);
889
890 return GET_RETURN_STATUS(env);
891 }
892
893 class ThreadSafeFunction : public node::AsyncResource {
894 public:
ThreadSafeFunction(v8::Local<v8::Function> func,v8::Local<v8::Object> resource,v8::Local<v8::String> name,size_t thread_count_,void * context_,size_t max_queue_size_,napi_env env_,void * finalize_data_,napi_finalize finalize_cb_,napi_threadsafe_function_call_js call_js_cb_)895 ThreadSafeFunction(v8::Local<v8::Function> func,
896 v8::Local<v8::Object> resource,
897 v8::Local<v8::String> name,
898 size_t thread_count_,
899 void* context_,
900 size_t max_queue_size_,
901 napi_env env_,
902 void* finalize_data_,
903 napi_finalize finalize_cb_,
904 napi_threadsafe_function_call_js call_js_cb_):
905 AsyncResource(env_->isolate,
906 resource,
907 *v8::String::Utf8Value(env_->isolate, name)),
908 thread_count(thread_count_),
909 is_closing(false),
910 context(context_),
911 max_queue_size(max_queue_size_),
912 env(env_),
913 finalize_data(finalize_data_),
914 finalize_cb(finalize_cb_),
915 call_js_cb(call_js_cb_ == nullptr ? CallJs : call_js_cb_),
916 handles_closing(false) {
917 ref.Reset(env->isolate, func);
918 node::AddEnvironmentCleanupHook(env->isolate, Cleanup, this);
919 env->Ref();
920 }
921
~ThreadSafeFunction()922 ~ThreadSafeFunction() {
923 node::RemoveEnvironmentCleanupHook(env->isolate, Cleanup, this);
924 env->Unref();
925 }
926
927 // These methods can be called from any thread.
928
Push(void * data,napi_threadsafe_function_call_mode mode)929 napi_status Push(void* data, napi_threadsafe_function_call_mode mode) {
930 node::Mutex::ScopedLock lock(this->mutex);
931
932 while (queue.size() >= max_queue_size &&
933 max_queue_size > 0 &&
934 !is_closing) {
935 if (mode == napi_tsfn_nonblocking) {
936 return napi_queue_full;
937 }
938 cond->Wait(lock);
939 }
940
941 if (is_closing) {
942 if (thread_count == 0) {
943 return napi_invalid_arg;
944 } else {
945 thread_count--;
946 return napi_closing;
947 }
948 } else {
949 if (uv_async_send(&async) != 0) {
950 return napi_generic_failure;
951 }
952 queue.push(data);
953 return napi_ok;
954 }
955 }
956
Acquire()957 napi_status Acquire() {
958 node::Mutex::ScopedLock lock(this->mutex);
959
960 if (is_closing) {
961 return napi_closing;
962 }
963
964 thread_count++;
965
966 return napi_ok;
967 }
968
Release(napi_threadsafe_function_release_mode mode)969 napi_status Release(napi_threadsafe_function_release_mode mode) {
970 node::Mutex::ScopedLock lock(this->mutex);
971
972 if (thread_count == 0) {
973 return napi_invalid_arg;
974 }
975
976 thread_count--;
977
978 if (thread_count == 0 || mode == napi_tsfn_abort) {
979 if (!is_closing) {
980 is_closing = (mode == napi_tsfn_abort);
981 if (is_closing && max_queue_size > 0) {
982 cond->Signal(lock);
983 }
984 if (uv_async_send(&async) != 0) {
985 return napi_generic_failure;
986 }
987 }
988 }
989
990 return napi_ok;
991 }
992
EmptyQueueAndDelete()993 void EmptyQueueAndDelete() {
994 for (; !queue.empty() ; queue.pop()) {
995 call_js_cb(nullptr, nullptr, context, queue.front());
996 }
997 delete this;
998 }
999
1000 // These methods must only be called from the loop thread.
1001
Init()1002 napi_status Init() {
1003 uv_loop_t* loop = nullptr;
1004 CHECK_EQ(napi_get_uv_event_loop(env, &loop), napi_ok);
1005
1006 ThreadSafeFunction* ts_fn = this;
1007
1008 if (uv_async_init(loop, &async, AsyncCb) == 0) {
1009 if (max_queue_size > 0) {
1010 cond.reset(new node::ConditionVariable);
1011 }
1012 if ((max_queue_size == 0 || cond.get() != nullptr) &&
1013 uv_idle_init(loop, &idle) == 0) {
1014 return napi_ok;
1015 }
1016
1017 env->node_env()->CloseHandle(
1018 reinterpret_cast<uv_handle_t*>(&async),
1019 [](uv_handle_t* handle) -> void {
1020 ThreadSafeFunction* ts_fn =
1021 node::ContainerOf(&ThreadSafeFunction::async,
1022 reinterpret_cast<uv_async_t*>(handle));
1023 delete ts_fn;
1024 });
1025
1026 // Prevent the thread-safe function from being deleted here, because
1027 // the callback above will delete it.
1028 ts_fn = nullptr;
1029 }
1030
1031 delete ts_fn;
1032
1033 return napi_generic_failure;
1034 }
1035
Unref()1036 napi_status Unref() {
1037 uv_unref(reinterpret_cast<uv_handle_t*>(&async));
1038 uv_unref(reinterpret_cast<uv_handle_t*>(&idle));
1039
1040 return napi_ok;
1041 }
1042
Ref()1043 napi_status Ref() {
1044 uv_ref(reinterpret_cast<uv_handle_t*>(&async));
1045 uv_ref(reinterpret_cast<uv_handle_t*>(&idle));
1046
1047 return napi_ok;
1048 }
1049
DispatchOne()1050 void DispatchOne() {
1051 void* data = nullptr;
1052 bool popped_value = false;
1053 bool idle_stop_failed = false;
1054
1055 {
1056 node::Mutex::ScopedLock lock(this->mutex);
1057 if (is_closing) {
1058 CloseHandlesAndMaybeDelete();
1059 } else {
1060 size_t size = queue.size();
1061 if (size > 0) {
1062 data = queue.front();
1063 queue.pop();
1064 popped_value = true;
1065 if (size == max_queue_size && max_queue_size > 0) {
1066 cond->Signal(lock);
1067 }
1068 size--;
1069 }
1070
1071 if (size == 0) {
1072 if (thread_count == 0) {
1073 is_closing = true;
1074 if (max_queue_size > 0) {
1075 cond->Signal(lock);
1076 }
1077 CloseHandlesAndMaybeDelete();
1078 } else {
1079 if (uv_idle_stop(&idle) != 0) {
1080 idle_stop_failed = true;
1081 }
1082 }
1083 }
1084 }
1085 }
1086
1087 if (popped_value || idle_stop_failed) {
1088 v8::HandleScope scope(env->isolate);
1089 CallbackScope cb_scope(this);
1090
1091 if (idle_stop_failed) {
1092 CHECK(napi_throw_error(env,
1093 "ERR_NAPI_TSFN_STOP_IDLE_LOOP",
1094 "Failed to stop the idle loop") == napi_ok);
1095 } else {
1096 napi_value js_callback = nullptr;
1097 if (!ref.IsEmpty()) {
1098 v8::Local<v8::Function> js_cb =
1099 v8::Local<v8::Function>::New(env->isolate, ref);
1100 js_callback = v8impl::JsValueFromV8LocalValue(js_cb);
1101 }
1102 call_js_cb(env,
1103 js_callback,
1104 context,
1105 data);
1106 }
1107 }
1108 }
1109
MaybeStartIdle()1110 void MaybeStartIdle() {
1111 if (uv_idle_start(&idle, IdleCb) != 0) {
1112 v8::HandleScope scope(env->isolate);
1113 CallbackScope cb_scope(this);
1114 CHECK(napi_throw_error(env,
1115 "ERR_NAPI_TSFN_START_IDLE_LOOP",
1116 "Failed to start the idle loop") == napi_ok);
1117 }
1118 }
1119
Finalize()1120 void Finalize() {
1121 v8::HandleScope scope(env->isolate);
1122 if (finalize_cb) {
1123 CallbackScope cb_scope(this);
1124 finalize_cb(env, finalize_data, context);
1125 }
1126 EmptyQueueAndDelete();
1127 }
1128
Context()1129 inline void* Context() {
1130 return context;
1131 }
1132
CloseHandlesAndMaybeDelete(bool set_closing=false)1133 void CloseHandlesAndMaybeDelete(bool set_closing = false) {
1134 v8::HandleScope scope(env->isolate);
1135 if (set_closing) {
1136 node::Mutex::ScopedLock lock(this->mutex);
1137 is_closing = true;
1138 if (max_queue_size > 0) {
1139 cond->Signal(lock);
1140 }
1141 }
1142 if (handles_closing) {
1143 return;
1144 }
1145 handles_closing = true;
1146 env->node_env()->CloseHandle(
1147 reinterpret_cast<uv_handle_t*>(&async),
1148 [](uv_handle_t* handle) -> void {
1149 ThreadSafeFunction* ts_fn =
1150 node::ContainerOf(&ThreadSafeFunction::async,
1151 reinterpret_cast<uv_async_t*>(handle));
1152 v8::HandleScope scope(ts_fn->env->isolate);
1153 ts_fn->env->node_env()->CloseHandle(
1154 reinterpret_cast<uv_handle_t*>(&ts_fn->idle),
1155 [](uv_handle_t* handle) -> void {
1156 ThreadSafeFunction* ts_fn =
1157 node::ContainerOf(&ThreadSafeFunction::idle,
1158 reinterpret_cast<uv_idle_t*>(handle));
1159 ts_fn->Finalize();
1160 });
1161 });
1162 }
1163
1164 // Default way of calling into JavaScript. Used when ThreadSafeFunction is
1165 // without a call_js_cb_.
CallJs(napi_env env,napi_value cb,void * context,void * data)1166 static void CallJs(napi_env env, napi_value cb, void* context, void* data) {
1167 if (!(env == nullptr || cb == nullptr)) {
1168 napi_value recv;
1169 napi_status status;
1170
1171 status = napi_get_undefined(env, &recv);
1172 if (status != napi_ok) {
1173 napi_throw_error(env, "ERR_NAPI_TSFN_GET_UNDEFINED",
1174 "Failed to retrieve undefined value");
1175 return;
1176 }
1177
1178 status = napi_call_function(env, recv, cb, 0, nullptr, nullptr);
1179 if (status != napi_ok && status != napi_pending_exception) {
1180 napi_throw_error(env, "ERR_NAPI_TSFN_CALL_JS",
1181 "Failed to call JS callback");
1182 return;
1183 }
1184 }
1185 }
1186
IdleCb(uv_idle_t * idle)1187 static void IdleCb(uv_idle_t* idle) {
1188 ThreadSafeFunction* ts_fn =
1189 node::ContainerOf(&ThreadSafeFunction::idle, idle);
1190 ts_fn->DispatchOne();
1191 }
1192
AsyncCb(uv_async_t * async)1193 static void AsyncCb(uv_async_t* async) {
1194 ThreadSafeFunction* ts_fn =
1195 node::ContainerOf(&ThreadSafeFunction::async, async);
1196 ts_fn->MaybeStartIdle();
1197 }
1198
Cleanup(void * data)1199 static void Cleanup(void* data) {
1200 reinterpret_cast<ThreadSafeFunction*>(data)
1201 ->CloseHandlesAndMaybeDelete(true);
1202 }
1203
1204 private:
1205 // These are variables protected by the mutex.
1206 node::Mutex mutex;
1207 std::unique_ptr<node::ConditionVariable> cond;
1208 std::queue<void*> queue;
1209 uv_async_t async;
1210 uv_idle_t idle;
1211 size_t thread_count;
1212 bool is_closing;
1213
1214 // These are variables set once, upon creation, and then never again, which
1215 // means we don't need the mutex to read them.
1216 void* context;
1217 size_t max_queue_size;
1218
1219 // These are variables accessed only from the loop thread.
1220 node::Persistent<v8::Function> ref;
1221 napi_env env;
1222 void* finalize_data;
1223 napi_finalize finalize_cb;
1224 napi_threadsafe_function_call_js call_js_cb;
1225 bool handles_closing;
1226 };
1227
1228 enum WrapType {
1229 retrievable,
1230 anonymous
1231 };
1232
1233 template <WrapType wrap_type> static inline
Wrap(napi_env env,napi_value js_object,void * native_object,napi_finalize finalize_cb,void * finalize_hint,napi_ref * result)1234 napi_status Wrap(napi_env env,
1235 napi_value js_object,
1236 void* native_object,
1237 napi_finalize finalize_cb,
1238 void* finalize_hint,
1239 napi_ref* result) {
1240 NAPI_PREAMBLE(env);
1241 CHECK_ARG(env, js_object);
1242
1243 v8::Local<v8::Context> context = env->context();
1244
1245 v8::Local<v8::Value> value = v8impl::V8LocalValueFromJsValue(js_object);
1246 RETURN_STATUS_IF_FALSE(env, value->IsObject(), napi_invalid_arg);
1247 v8::Local<v8::Object> obj = value.As<v8::Object>();
1248
1249 if (wrap_type == retrievable) {
1250 // If we've already wrapped this object, we error out.
1251 RETURN_STATUS_IF_FALSE(env,
1252 !obj->HasPrivate(context, NAPI_PRIVATE_KEY(context, wrapper))
1253 .FromJust(),
1254 napi_invalid_arg);
1255 } else if (wrap_type == anonymous) {
1256 // If no finalize callback is provided, we error out.
1257 CHECK_ARG(env, finalize_cb);
1258 }
1259
1260 v8impl::Reference* reference = nullptr;
1261 if (result != nullptr) {
1262 // The returned reference should be deleted via napi_delete_reference()
1263 // ONLY in response to the finalize callback invocation. (If it is deleted
1264 // before then, then the finalize callback will never be invoked.)
1265 // Therefore a finalize callback is required when returning a reference.
1266 CHECK_ARG(env, finalize_cb);
1267 reference = v8impl::Reference::New(
1268 env, obj, 0, false, finalize_cb, native_object, finalize_hint);
1269 *result = reinterpret_cast<napi_ref>(reference);
1270 } else {
1271 // Create a self-deleting reference.
1272 reference = v8impl::Reference::New(env, obj, 0, true, finalize_cb,
1273 native_object, finalize_cb == nullptr ? nullptr : finalize_hint);
1274 }
1275
1276 if (wrap_type == retrievable) {
1277 CHECK(obj->SetPrivate(context, NAPI_PRIVATE_KEY(context, wrapper),
1278 v8::External::New(env->isolate, reference)).FromJust());
1279 }
1280
1281 return GET_RETURN_STATUS(env);
1282 }
1283
1284 } // end of namespace v8impl
1285
1286 // Intercepts the Node-V8 module registration callback. Converts parameters
1287 // to NAPI equivalents and then calls the registration callback specified
1288 // by the NAPI module.
napi_module_register_cb(v8::Local<v8::Object> exports,v8::Local<v8::Value> module,v8::Local<v8::Context> context,void * priv)1289 void napi_module_register_cb(v8::Local<v8::Object> exports,
1290 v8::Local<v8::Value> module,
1291 v8::Local<v8::Context> context,
1292 void* priv) {
1293 napi_module_register_by_symbol(exports, module, context,
1294 static_cast<napi_module*>(priv)->nm_register_func);
1295 }
1296
1297 } // end of anonymous namespace
1298
napi_module_register_by_symbol(v8::Local<v8::Object> exports,v8::Local<v8::Value> module,v8::Local<v8::Context> context,napi_addon_register_func init)1299 void napi_module_register_by_symbol(v8::Local<v8::Object> exports,
1300 v8::Local<v8::Value> module,
1301 v8::Local<v8::Context> context,
1302 napi_addon_register_func init) {
1303 if (init == nullptr) {
1304 node::Environment* node_env = node::Environment::GetCurrent(context);
1305 CHECK_NOT_NULL(node_env);
1306 node_env->ThrowError(
1307 "Module has no declared entry point.");
1308 return;
1309 }
1310
1311 // Create a new napi_env for this module or reference one if a pre-existing
1312 // one is found.
1313 napi_env env = v8impl::NewEnv(context);
1314
1315 napi_value _exports;
1316 env->CallIntoModuleThrow([&](napi_env env) {
1317 _exports = init(env, v8impl::JsValueFromV8LocalValue(exports));
1318 });
1319
1320 // If register function returned a non-null exports object different from
1321 // the exports object we passed it, set that as the "exports" property of
1322 // the module.
1323 if (_exports != nullptr &&
1324 _exports != v8impl::JsValueFromV8LocalValue(exports)) {
1325 napi_value _module = v8impl::JsValueFromV8LocalValue(module);
1326 napi_set_named_property(env, _module, "exports", _exports);
1327 }
1328 }
1329
1330 // Registers a NAPI module.
napi_module_register(napi_module * mod)1331 void napi_module_register(napi_module* mod) {
1332 node::node_module* nm = new node::node_module {
1333 -1,
1334 mod->nm_flags,
1335 nullptr,
1336 mod->nm_filename,
1337 nullptr,
1338 napi_module_register_cb,
1339 mod->nm_modname,
1340 mod, // priv
1341 nullptr,
1342 };
1343 node::node_module_register(nm);
1344 }
1345
napi_add_env_cleanup_hook(napi_env env,void (* fun)(void * arg),void * arg)1346 napi_status napi_add_env_cleanup_hook(napi_env env,
1347 void (*fun)(void* arg),
1348 void* arg) {
1349 CHECK_ENV(env);
1350 CHECK_ARG(env, fun);
1351
1352 node::AddEnvironmentCleanupHook(env->isolate, fun, arg);
1353
1354 return napi_ok;
1355 }
1356
napi_remove_env_cleanup_hook(napi_env env,void (* fun)(void * arg),void * arg)1357 napi_status napi_remove_env_cleanup_hook(napi_env env,
1358 void (*fun)(void* arg),
1359 void* arg) {
1360 CHECK_ENV(env);
1361 CHECK_ARG(env, fun);
1362
1363 node::RemoveEnvironmentCleanupHook(env->isolate, fun, arg);
1364
1365 return napi_ok;
1366 }
1367
1368 // Warning: Keep in-sync with napi_status enum
1369 static
1370 const char* error_messages[] = {nullptr,
1371 "Invalid argument",
1372 "An object was expected",
1373 "A string was expected",
1374 "A string or symbol was expected",
1375 "A function was expected",
1376 "A number was expected",
1377 "A boolean was expected",
1378 "An array was expected",
1379 "Unknown failure",
1380 "An exception is pending",
1381 "The async work item was cancelled",
1382 "napi_escape_handle already called on scope",
1383 "Invalid handle scope usage",
1384 "Invalid callback scope usage",
1385 "Thread-safe function queue is full",
1386 "Thread-safe function handle is closing",
1387 "A bigint was expected",
1388 "A date was expected",
1389 "An arraybuffer was expected",
1390 "A detachable arraybuffer was expected",
1391 };
1392
napi_clear_last_error(napi_env env)1393 static inline napi_status napi_clear_last_error(napi_env env) {
1394 env->last_error.error_code = napi_ok;
1395
1396 // TODO(boingoing): Should this be a callback?
1397 env->last_error.engine_error_code = 0;
1398 env->last_error.engine_reserved = nullptr;
1399 return napi_ok;
1400 }
1401
1402 static inline
napi_set_last_error(napi_env env,napi_status error_code,uint32_t engine_error_code,void * engine_reserved)1403 napi_status napi_set_last_error(napi_env env, napi_status error_code,
1404 uint32_t engine_error_code,
1405 void* engine_reserved) {
1406 env->last_error.error_code = error_code;
1407 env->last_error.engine_error_code = engine_error_code;
1408 env->last_error.engine_reserved = engine_reserved;
1409 return error_code;
1410 }
1411
napi_get_last_error_info(napi_env env,const napi_extended_error_info ** result)1412 napi_status napi_get_last_error_info(napi_env env,
1413 const napi_extended_error_info** result) {
1414 CHECK_ENV(env);
1415 CHECK_ARG(env, result);
1416
1417 // The value of the constant below must be updated to reference the last
1418 // message in the `napi_status` enum each time a new error message is added.
1419 // We don't have a napi_status_last as this would result in an ABI
1420 // change each time a message was added.
1421 const int last_status = napi_detachable_arraybuffer_expected;
1422
1423 static_assert(
1424 node::arraysize(error_messages) == last_status + 1,
1425 "Count of error messages must match count of error values");
1426 CHECK_LE(env->last_error.error_code, last_status);
1427
1428 // Wait until someone requests the last error information to fetch the error
1429 // message string
1430 env->last_error.error_message =
1431 error_messages[env->last_error.error_code];
1432
1433 *result = &(env->last_error);
1434 return napi_ok;
1435 }
1436
napi_fatal_exception(napi_env env,napi_value err)1437 napi_status napi_fatal_exception(napi_env env, napi_value err) {
1438 NAPI_PREAMBLE(env);
1439 CHECK_ARG(env, err);
1440
1441 v8::Local<v8::Value> local_err = v8impl::V8LocalValueFromJsValue(err);
1442 v8impl::trigger_fatal_exception(env, local_err);
1443
1444 return napi_clear_last_error(env);
1445 }
1446
napi_fatal_error(const char * location,size_t location_len,const char * message,size_t message_len)1447 NAPI_NO_RETURN void napi_fatal_error(const char* location,
1448 size_t location_len,
1449 const char* message,
1450 size_t message_len) {
1451 std::string location_string;
1452 std::string message_string;
1453
1454 if (location_len != NAPI_AUTO_LENGTH) {
1455 location_string.assign(
1456 const_cast<char*>(location), location_len);
1457 } else {
1458 location_string.assign(
1459 const_cast<char*>(location), strlen(location));
1460 }
1461
1462 if (message_len != NAPI_AUTO_LENGTH) {
1463 message_string.assign(
1464 const_cast<char*>(message), message_len);
1465 } else {
1466 message_string.assign(
1467 const_cast<char*>(message), strlen(message));
1468 }
1469
1470 node::FatalError(location_string.c_str(), message_string.c_str());
1471 }
1472
napi_create_function(napi_env env,const char * utf8name,size_t length,napi_callback cb,void * callback_data,napi_value * result)1473 napi_status napi_create_function(napi_env env,
1474 const char* utf8name,
1475 size_t length,
1476 napi_callback cb,
1477 void* callback_data,
1478 napi_value* result) {
1479 NAPI_PREAMBLE(env);
1480 CHECK_ARG(env, result);
1481 CHECK_ARG(env, cb);
1482
1483 v8::Isolate* isolate = env->isolate;
1484 v8::Local<v8::Function> return_value;
1485 v8::EscapableHandleScope scope(isolate);
1486 v8::Local<v8::Value> cbdata =
1487 v8impl::CreateFunctionCallbackData(env, cb, callback_data);
1488
1489 RETURN_STATUS_IF_FALSE(env, !cbdata.IsEmpty(), napi_generic_failure);
1490
1491 v8::Local<v8::Context> context = env->context();
1492 v8::MaybeLocal<v8::Function> maybe_function =
1493 v8::Function::New(context,
1494 v8impl::FunctionCallbackWrapper::Invoke,
1495 cbdata);
1496 CHECK_MAYBE_EMPTY(env, maybe_function, napi_generic_failure);
1497
1498 return_value = scope.Escape(maybe_function.ToLocalChecked());
1499
1500 if (utf8name != nullptr) {
1501 v8::Local<v8::String> name_string;
1502 CHECK_NEW_FROM_UTF8_LEN(env, name_string, utf8name, length);
1503 return_value->SetName(name_string);
1504 }
1505
1506 *result = v8impl::JsValueFromV8LocalValue(return_value);
1507
1508 return GET_RETURN_STATUS(env);
1509 }
1510
napi_define_class(napi_env env,const char * utf8name,size_t length,napi_callback constructor,void * callback_data,size_t property_count,const napi_property_descriptor * properties,napi_value * result)1511 napi_status napi_define_class(napi_env env,
1512 const char* utf8name,
1513 size_t length,
1514 napi_callback constructor,
1515 void* callback_data,
1516 size_t property_count,
1517 const napi_property_descriptor* properties,
1518 napi_value* result) {
1519 NAPI_PREAMBLE(env);
1520 CHECK_ARG(env, result);
1521 CHECK_ARG(env, constructor);
1522
1523 v8::Isolate* isolate = env->isolate;
1524
1525 v8::EscapableHandleScope scope(isolate);
1526 v8::Local<v8::Value> cbdata =
1527 v8impl::CreateFunctionCallbackData(env, constructor, callback_data);
1528
1529 RETURN_STATUS_IF_FALSE(env, !cbdata.IsEmpty(), napi_generic_failure);
1530
1531 v8::Local<v8::FunctionTemplate> tpl = v8::FunctionTemplate::New(
1532 isolate, v8impl::FunctionCallbackWrapper::Invoke, cbdata);
1533
1534 v8::Local<v8::String> name_string;
1535 CHECK_NEW_FROM_UTF8_LEN(env, name_string, utf8name, length);
1536 tpl->SetClassName(name_string);
1537
1538 size_t static_property_count = 0;
1539 for (size_t i = 0; i < property_count; i++) {
1540 const napi_property_descriptor* p = properties + i;
1541
1542 if ((p->attributes & napi_static) != 0) {
1543 // Static properties are handled separately below.
1544 static_property_count++;
1545 continue;
1546 }
1547
1548 v8::Local<v8::Name> property_name;
1549 napi_status status =
1550 v8impl::V8NameFromPropertyDescriptor(env, p, &property_name);
1551
1552 if (status != napi_ok) {
1553 return napi_set_last_error(env, status);
1554 }
1555
1556 v8::PropertyAttribute attributes =
1557 v8impl::V8PropertyAttributesFromDescriptor(p);
1558
1559 // This code is similar to that in napi_define_properties(); the
1560 // difference is it applies to a template instead of an object.
1561 if (p->getter != nullptr || p->setter != nullptr) {
1562 v8::Local<v8::Value> cbdata = v8impl::CreateAccessorCallbackData(
1563 env, p->getter, p->setter, p->data);
1564
1565 tpl->PrototypeTemplate()->SetAccessor(
1566 property_name,
1567 p->getter ? v8impl::GetterCallbackWrapper::Invoke : nullptr,
1568 p->setter ? v8impl::SetterCallbackWrapper::Invoke : nullptr,
1569 cbdata,
1570 v8::AccessControl::DEFAULT,
1571 attributes);
1572 } else if (p->method != nullptr) {
1573 v8::Local<v8::Value> cbdata =
1574 v8impl::CreateFunctionCallbackData(env, p->method, p->data);
1575
1576 RETURN_STATUS_IF_FALSE(env, !cbdata.IsEmpty(), napi_generic_failure);
1577
1578 v8::Local<v8::FunctionTemplate> t =
1579 v8::FunctionTemplate::New(isolate,
1580 v8impl::FunctionCallbackWrapper::Invoke,
1581 cbdata,
1582 v8::Signature::New(isolate, tpl));
1583
1584 tpl->PrototypeTemplate()->Set(property_name, t, attributes);
1585 } else {
1586 v8::Local<v8::Value> value = v8impl::V8LocalValueFromJsValue(p->value);
1587 tpl->PrototypeTemplate()->Set(property_name, value, attributes);
1588 }
1589 }
1590
1591 v8::Local<v8::Context> context = env->context();
1592 *result = v8impl::JsValueFromV8LocalValue(
1593 scope.Escape(tpl->GetFunction(context).ToLocalChecked()));
1594
1595 if (static_property_count > 0) {
1596 std::vector<napi_property_descriptor> static_descriptors;
1597 static_descriptors.reserve(static_property_count);
1598
1599 for (size_t i = 0; i < property_count; i++) {
1600 const napi_property_descriptor* p = properties + i;
1601 if ((p->attributes & napi_static) != 0) {
1602 static_descriptors.push_back(*p);
1603 }
1604 }
1605
1606 napi_status status =
1607 napi_define_properties(env,
1608 *result,
1609 static_descriptors.size(),
1610 static_descriptors.data());
1611 if (status != napi_ok) return status;
1612 }
1613
1614 return GET_RETURN_STATUS(env);
1615 }
1616
napi_get_property_names(napi_env env,napi_value object,napi_value * result)1617 napi_status napi_get_property_names(napi_env env,
1618 napi_value object,
1619 napi_value* result) {
1620 return napi_get_all_property_names(
1621 env,
1622 object,
1623 napi_key_include_prototypes,
1624 static_cast<napi_key_filter>(napi_key_enumerable |
1625 napi_key_skip_symbols),
1626 napi_key_numbers_to_strings,
1627 result);
1628 }
1629
napi_get_all_property_names(napi_env env,napi_value object,napi_key_collection_mode key_mode,napi_key_filter key_filter,napi_key_conversion key_conversion,napi_value * result)1630 napi_status napi_get_all_property_names(napi_env env,
1631 napi_value object,
1632 napi_key_collection_mode key_mode,
1633 napi_key_filter key_filter,
1634 napi_key_conversion key_conversion,
1635 napi_value* result) {
1636 NAPI_PREAMBLE(env);
1637 CHECK_ARG(env, result);
1638
1639 v8::Local<v8::Context> context = env->context();
1640 v8::Local<v8::Object> obj;
1641 CHECK_TO_OBJECT(env, context, obj, object);
1642
1643 v8::PropertyFilter filter = v8::PropertyFilter::ALL_PROPERTIES;
1644 if (key_filter & napi_key_writable) {
1645 filter =
1646 static_cast<v8::PropertyFilter>(filter |
1647 v8::PropertyFilter::ONLY_WRITABLE);
1648 }
1649 if (key_filter & napi_key_enumerable) {
1650 filter =
1651 static_cast<v8::PropertyFilter>(filter |
1652 v8::PropertyFilter::ONLY_ENUMERABLE);
1653 }
1654 if (key_filter & napi_key_configurable) {
1655 filter =
1656 static_cast<v8::PropertyFilter>(filter |
1657 v8::PropertyFilter::ONLY_WRITABLE);
1658 }
1659 if (key_filter & napi_key_skip_strings) {
1660 filter =
1661 static_cast<v8::PropertyFilter>(filter |
1662 v8::PropertyFilter::SKIP_STRINGS);
1663 }
1664 if (key_filter & napi_key_skip_symbols) {
1665 filter =
1666 static_cast<v8::PropertyFilter>(filter |
1667 v8::PropertyFilter::SKIP_SYMBOLS);
1668 }
1669 v8::KeyCollectionMode collection_mode;
1670 v8::KeyConversionMode conversion_mode;
1671
1672 switch (key_mode) {
1673 case napi_key_include_prototypes:
1674 collection_mode = v8::KeyCollectionMode::kIncludePrototypes;
1675 break;
1676 case napi_key_own_only:
1677 collection_mode = v8::KeyCollectionMode::kOwnOnly;
1678 break;
1679 default:
1680 return napi_set_last_error(env, napi_invalid_arg);
1681 }
1682
1683 switch (key_conversion) {
1684 case napi_key_keep_numbers:
1685 conversion_mode = v8::KeyConversionMode::kKeepNumbers;
1686 break;
1687 case napi_key_numbers_to_strings:
1688 conversion_mode = v8::KeyConversionMode::kConvertToString;
1689 break;
1690 default:
1691 return napi_set_last_error(env, napi_invalid_arg);
1692 }
1693
1694 v8::MaybeLocal<v8::Array> maybe_all_propertynames =
1695 obj->GetPropertyNames(context,
1696 collection_mode,
1697 filter,
1698 v8::IndexFilter::kIncludeIndices,
1699 conversion_mode);
1700
1701 CHECK_MAYBE_EMPTY_WITH_PREAMBLE(
1702 env, maybe_all_propertynames, napi_generic_failure);
1703
1704 *result =
1705 v8impl::JsValueFromV8LocalValue(maybe_all_propertynames.ToLocalChecked());
1706 return GET_RETURN_STATUS(env);
1707 }
1708
napi_set_property(napi_env env,napi_value object,napi_value key,napi_value value)1709 napi_status napi_set_property(napi_env env,
1710 napi_value object,
1711 napi_value key,
1712 napi_value value) {
1713 NAPI_PREAMBLE(env);
1714 CHECK_ARG(env, key);
1715 CHECK_ARG(env, value);
1716
1717 v8::Local<v8::Context> context = env->context();
1718 v8::Local<v8::Object> obj;
1719
1720 CHECK_TO_OBJECT(env, context, obj, object);
1721
1722 v8::Local<v8::Value> k = v8impl::V8LocalValueFromJsValue(key);
1723 v8::Local<v8::Value> val = v8impl::V8LocalValueFromJsValue(value);
1724
1725 v8::Maybe<bool> set_maybe = obj->Set(context, k, val);
1726
1727 RETURN_STATUS_IF_FALSE(env, set_maybe.FromMaybe(false), napi_generic_failure);
1728 return GET_RETURN_STATUS(env);
1729 }
1730
napi_has_property(napi_env env,napi_value object,napi_value key,bool * result)1731 napi_status napi_has_property(napi_env env,
1732 napi_value object,
1733 napi_value key,
1734 bool* result) {
1735 NAPI_PREAMBLE(env);
1736 CHECK_ARG(env, result);
1737 CHECK_ARG(env, key);
1738
1739 v8::Local<v8::Context> context = env->context();
1740 v8::Local<v8::Object> obj;
1741
1742 CHECK_TO_OBJECT(env, context, obj, object);
1743
1744 v8::Local<v8::Value> k = v8impl::V8LocalValueFromJsValue(key);
1745 v8::Maybe<bool> has_maybe = obj->Has(context, k);
1746
1747 CHECK_MAYBE_NOTHING(env, has_maybe, napi_generic_failure);
1748
1749 *result = has_maybe.FromMaybe(false);
1750 return GET_RETURN_STATUS(env);
1751 }
1752
napi_get_property(napi_env env,napi_value object,napi_value key,napi_value * result)1753 napi_status napi_get_property(napi_env env,
1754 napi_value object,
1755 napi_value key,
1756 napi_value* result) {
1757 NAPI_PREAMBLE(env);
1758 CHECK_ARG(env, key);
1759 CHECK_ARG(env, result);
1760
1761 v8::Local<v8::Context> context = env->context();
1762 v8::Local<v8::Value> k = v8impl::V8LocalValueFromJsValue(key);
1763 v8::Local<v8::Object> obj;
1764
1765 CHECK_TO_OBJECT(env, context, obj, object);
1766
1767 auto get_maybe = obj->Get(context, k);
1768
1769 CHECK_MAYBE_EMPTY(env, get_maybe, napi_generic_failure);
1770
1771 v8::Local<v8::Value> val = get_maybe.ToLocalChecked();
1772 *result = v8impl::JsValueFromV8LocalValue(val);
1773 return GET_RETURN_STATUS(env);
1774 }
1775
napi_delete_property(napi_env env,napi_value object,napi_value key,bool * result)1776 napi_status napi_delete_property(napi_env env,
1777 napi_value object,
1778 napi_value key,
1779 bool* result) {
1780 NAPI_PREAMBLE(env);
1781 CHECK_ARG(env, key);
1782
1783 v8::Local<v8::Context> context = env->context();
1784 v8::Local<v8::Value> k = v8impl::V8LocalValueFromJsValue(key);
1785 v8::Local<v8::Object> obj;
1786
1787 CHECK_TO_OBJECT(env, context, obj, object);
1788 v8::Maybe<bool> delete_maybe = obj->Delete(context, k);
1789 CHECK_MAYBE_NOTHING(env, delete_maybe, napi_generic_failure);
1790
1791 if (result != nullptr)
1792 *result = delete_maybe.FromMaybe(false);
1793
1794 return GET_RETURN_STATUS(env);
1795 }
1796
napi_has_own_property(napi_env env,napi_value object,napi_value key,bool * result)1797 napi_status napi_has_own_property(napi_env env,
1798 napi_value object,
1799 napi_value key,
1800 bool* result) {
1801 NAPI_PREAMBLE(env);
1802 CHECK_ARG(env, key);
1803
1804 v8::Local<v8::Context> context = env->context();
1805 v8::Local<v8::Object> obj;
1806
1807 CHECK_TO_OBJECT(env, context, obj, object);
1808 v8::Local<v8::Value> k = v8impl::V8LocalValueFromJsValue(key);
1809 RETURN_STATUS_IF_FALSE(env, k->IsName(), napi_name_expected);
1810 v8::Maybe<bool> has_maybe = obj->HasOwnProperty(context, k.As<v8::Name>());
1811 CHECK_MAYBE_NOTHING(env, has_maybe, napi_generic_failure);
1812 *result = has_maybe.FromMaybe(false);
1813
1814 return GET_RETURN_STATUS(env);
1815 }
1816
napi_set_named_property(napi_env env,napi_value object,const char * utf8name,napi_value value)1817 napi_status napi_set_named_property(napi_env env,
1818 napi_value object,
1819 const char* utf8name,
1820 napi_value value) {
1821 NAPI_PREAMBLE(env);
1822 CHECK_ARG(env, value);
1823
1824 v8::Local<v8::Context> context = env->context();
1825 v8::Local<v8::Object> obj;
1826
1827 CHECK_TO_OBJECT(env, context, obj, object);
1828
1829 v8::Local<v8::Name> key;
1830 CHECK_NEW_FROM_UTF8(env, key, utf8name);
1831
1832 v8::Local<v8::Value> val = v8impl::V8LocalValueFromJsValue(value);
1833
1834 v8::Maybe<bool> set_maybe = obj->Set(context, key, val);
1835
1836 RETURN_STATUS_IF_FALSE(env, set_maybe.FromMaybe(false), napi_generic_failure);
1837 return GET_RETURN_STATUS(env);
1838 }
1839
napi_has_named_property(napi_env env,napi_value object,const char * utf8name,bool * result)1840 napi_status napi_has_named_property(napi_env env,
1841 napi_value object,
1842 const char* utf8name,
1843 bool* result) {
1844 NAPI_PREAMBLE(env);
1845 CHECK_ARG(env, result);
1846
1847 v8::Local<v8::Context> context = env->context();
1848 v8::Local<v8::Object> obj;
1849
1850 CHECK_TO_OBJECT(env, context, obj, object);
1851
1852 v8::Local<v8::Name> key;
1853 CHECK_NEW_FROM_UTF8(env, key, utf8name);
1854
1855 v8::Maybe<bool> has_maybe = obj->Has(context, key);
1856
1857 CHECK_MAYBE_NOTHING(env, has_maybe, napi_generic_failure);
1858
1859 *result = has_maybe.FromMaybe(false);
1860 return GET_RETURN_STATUS(env);
1861 }
1862
napi_get_named_property(napi_env env,napi_value object,const char * utf8name,napi_value * result)1863 napi_status napi_get_named_property(napi_env env,
1864 napi_value object,
1865 const char* utf8name,
1866 napi_value* result) {
1867 NAPI_PREAMBLE(env);
1868 CHECK_ARG(env, result);
1869
1870 v8::Local<v8::Context> context = env->context();
1871
1872 v8::Local<v8::Name> key;
1873 CHECK_NEW_FROM_UTF8(env, key, utf8name);
1874
1875 v8::Local<v8::Object> obj;
1876
1877 CHECK_TO_OBJECT(env, context, obj, object);
1878
1879 auto get_maybe = obj->Get(context, key);
1880
1881 CHECK_MAYBE_EMPTY(env, get_maybe, napi_generic_failure);
1882
1883 v8::Local<v8::Value> val = get_maybe.ToLocalChecked();
1884 *result = v8impl::JsValueFromV8LocalValue(val);
1885 return GET_RETURN_STATUS(env);
1886 }
1887
napi_set_element(napi_env env,napi_value object,uint32_t index,napi_value value)1888 napi_status napi_set_element(napi_env env,
1889 napi_value object,
1890 uint32_t index,
1891 napi_value value) {
1892 NAPI_PREAMBLE(env);
1893 CHECK_ARG(env, value);
1894
1895 v8::Local<v8::Context> context = env->context();
1896 v8::Local<v8::Object> obj;
1897
1898 CHECK_TO_OBJECT(env, context, obj, object);
1899
1900 v8::Local<v8::Value> val = v8impl::V8LocalValueFromJsValue(value);
1901 auto set_maybe = obj->Set(context, index, val);
1902
1903 RETURN_STATUS_IF_FALSE(env, set_maybe.FromMaybe(false), napi_generic_failure);
1904
1905 return GET_RETURN_STATUS(env);
1906 }
1907
napi_has_element(napi_env env,napi_value object,uint32_t index,bool * result)1908 napi_status napi_has_element(napi_env env,
1909 napi_value object,
1910 uint32_t index,
1911 bool* result) {
1912 NAPI_PREAMBLE(env);
1913 CHECK_ARG(env, result);
1914
1915 v8::Local<v8::Context> context = env->context();
1916 v8::Local<v8::Object> obj;
1917
1918 CHECK_TO_OBJECT(env, context, obj, object);
1919
1920 v8::Maybe<bool> has_maybe = obj->Has(context, index);
1921
1922 CHECK_MAYBE_NOTHING(env, has_maybe, napi_generic_failure);
1923
1924 *result = has_maybe.FromMaybe(false);
1925 return GET_RETURN_STATUS(env);
1926 }
1927
napi_get_element(napi_env env,napi_value object,uint32_t index,napi_value * result)1928 napi_status napi_get_element(napi_env env,
1929 napi_value object,
1930 uint32_t index,
1931 napi_value* result) {
1932 NAPI_PREAMBLE(env);
1933 CHECK_ARG(env, result);
1934
1935 v8::Local<v8::Context> context = env->context();
1936 v8::Local<v8::Object> obj;
1937
1938 CHECK_TO_OBJECT(env, context, obj, object);
1939
1940 auto get_maybe = obj->Get(context, index);
1941
1942 CHECK_MAYBE_EMPTY(env, get_maybe, napi_generic_failure);
1943
1944 *result = v8impl::JsValueFromV8LocalValue(get_maybe.ToLocalChecked());
1945 return GET_RETURN_STATUS(env);
1946 }
1947
napi_delete_element(napi_env env,napi_value object,uint32_t index,bool * result)1948 napi_status napi_delete_element(napi_env env,
1949 napi_value object,
1950 uint32_t index,
1951 bool* result) {
1952 NAPI_PREAMBLE(env);
1953
1954 v8::Local<v8::Context> context = env->context();
1955 v8::Local<v8::Object> obj;
1956
1957 CHECK_TO_OBJECT(env, context, obj, object);
1958 v8::Maybe<bool> delete_maybe = obj->Delete(context, index);
1959 CHECK_MAYBE_NOTHING(env, delete_maybe, napi_generic_failure);
1960
1961 if (result != nullptr)
1962 *result = delete_maybe.FromMaybe(false);
1963
1964 return GET_RETURN_STATUS(env);
1965 }
1966
napi_define_properties(napi_env env,napi_value object,size_t property_count,const napi_property_descriptor * properties)1967 napi_status napi_define_properties(napi_env env,
1968 napi_value object,
1969 size_t property_count,
1970 const napi_property_descriptor* properties) {
1971 NAPI_PREAMBLE(env);
1972 if (property_count > 0) {
1973 CHECK_ARG(env, properties);
1974 }
1975
1976 v8::Local<v8::Context> context = env->context();
1977
1978 v8::Local<v8::Object> obj;
1979 CHECK_TO_OBJECT(env, context, obj, object);
1980
1981 for (size_t i = 0; i < property_count; i++) {
1982 const napi_property_descriptor* p = &properties[i];
1983
1984 v8::Local<v8::Name> property_name;
1985 napi_status status =
1986 v8impl::V8NameFromPropertyDescriptor(env, p, &property_name);
1987
1988 if (status != napi_ok) {
1989 return napi_set_last_error(env, status);
1990 }
1991
1992 v8::PropertyAttribute attributes =
1993 v8impl::V8PropertyAttributesFromDescriptor(p);
1994
1995 if (p->getter != nullptr || p->setter != nullptr) {
1996 v8::Local<v8::Value> cbdata = v8impl::CreateAccessorCallbackData(
1997 env,
1998 p->getter,
1999 p->setter,
2000 p->data);
2001
2002 auto set_maybe = obj->SetAccessor(
2003 context,
2004 property_name,
2005 p->getter ? v8impl::GetterCallbackWrapper::Invoke : nullptr,
2006 p->setter ? v8impl::SetterCallbackWrapper::Invoke : nullptr,
2007 cbdata,
2008 v8::AccessControl::DEFAULT,
2009 attributes);
2010
2011 if (!set_maybe.FromMaybe(false)) {
2012 return napi_set_last_error(env, napi_invalid_arg);
2013 }
2014 } else if (p->method != nullptr) {
2015 v8::Local<v8::Value> cbdata =
2016 v8impl::CreateFunctionCallbackData(env, p->method, p->data);
2017
2018 CHECK_MAYBE_EMPTY(env, cbdata, napi_generic_failure);
2019
2020 v8::MaybeLocal<v8::Function> maybe_fn =
2021 v8::Function::New(context,
2022 v8impl::FunctionCallbackWrapper::Invoke,
2023 cbdata);
2024
2025 CHECK_MAYBE_EMPTY(env, maybe_fn, napi_generic_failure);
2026
2027 auto define_maybe = obj->DefineOwnProperty(
2028 context, property_name, maybe_fn.ToLocalChecked(), attributes);
2029
2030 if (!define_maybe.FromMaybe(false)) {
2031 return napi_set_last_error(env, napi_generic_failure);
2032 }
2033 } else {
2034 v8::Local<v8::Value> value = v8impl::V8LocalValueFromJsValue(p->value);
2035
2036 auto define_maybe =
2037 obj->DefineOwnProperty(context, property_name, value, attributes);
2038
2039 if (!define_maybe.FromMaybe(false)) {
2040 return napi_set_last_error(env, napi_invalid_arg);
2041 }
2042 }
2043 }
2044
2045 return GET_RETURN_STATUS(env);
2046 }
2047
napi_is_array(napi_env env,napi_value value,bool * result)2048 napi_status napi_is_array(napi_env env, napi_value value, bool* result) {
2049 CHECK_ENV(env);
2050 CHECK_ARG(env, value);
2051 CHECK_ARG(env, result);
2052
2053 v8::Local<v8::Value> val = v8impl::V8LocalValueFromJsValue(value);
2054
2055 *result = val->IsArray();
2056 return napi_clear_last_error(env);
2057 }
2058
napi_get_array_length(napi_env env,napi_value value,uint32_t * result)2059 napi_status napi_get_array_length(napi_env env,
2060 napi_value value,
2061 uint32_t* result) {
2062 NAPI_PREAMBLE(env);
2063 CHECK_ARG(env, value);
2064 CHECK_ARG(env, result);
2065
2066 v8::Local<v8::Value> val = v8impl::V8LocalValueFromJsValue(value);
2067 RETURN_STATUS_IF_FALSE(env, val->IsArray(), napi_array_expected);
2068
2069 v8::Local<v8::Array> arr = val.As<v8::Array>();
2070 *result = arr->Length();
2071
2072 return GET_RETURN_STATUS(env);
2073 }
2074
napi_strict_equals(napi_env env,napi_value lhs,napi_value rhs,bool * result)2075 napi_status napi_strict_equals(napi_env env,
2076 napi_value lhs,
2077 napi_value rhs,
2078 bool* result) {
2079 NAPI_PREAMBLE(env);
2080 CHECK_ARG(env, lhs);
2081 CHECK_ARG(env, rhs);
2082 CHECK_ARG(env, result);
2083
2084 v8::Local<v8::Value> a = v8impl::V8LocalValueFromJsValue(lhs);
2085 v8::Local<v8::Value> b = v8impl::V8LocalValueFromJsValue(rhs);
2086
2087 *result = a->StrictEquals(b);
2088 return GET_RETURN_STATUS(env);
2089 }
2090
napi_get_prototype(napi_env env,napi_value object,napi_value * result)2091 napi_status napi_get_prototype(napi_env env,
2092 napi_value object,
2093 napi_value* result) {
2094 NAPI_PREAMBLE(env);
2095 CHECK_ARG(env, result);
2096
2097 v8::Local<v8::Context> context = env->context();
2098
2099 v8::Local<v8::Object> obj;
2100 CHECK_TO_OBJECT(env, context, obj, object);
2101
2102 v8::Local<v8::Value> val = obj->GetPrototype();
2103 *result = v8impl::JsValueFromV8LocalValue(val);
2104 return GET_RETURN_STATUS(env);
2105 }
2106
napi_create_object(napi_env env,napi_value * result)2107 napi_status napi_create_object(napi_env env, napi_value* result) {
2108 CHECK_ENV(env);
2109 CHECK_ARG(env, result);
2110
2111 *result = v8impl::JsValueFromV8LocalValue(
2112 v8::Object::New(env->isolate));
2113
2114 return napi_clear_last_error(env);
2115 }
2116
napi_create_array(napi_env env,napi_value * result)2117 napi_status napi_create_array(napi_env env, napi_value* result) {
2118 CHECK_ENV(env);
2119 CHECK_ARG(env, result);
2120
2121 *result = v8impl::JsValueFromV8LocalValue(
2122 v8::Array::New(env->isolate));
2123
2124 return napi_clear_last_error(env);
2125 }
2126
napi_create_array_with_length(napi_env env,size_t length,napi_value * result)2127 napi_status napi_create_array_with_length(napi_env env,
2128 size_t length,
2129 napi_value* result) {
2130 CHECK_ENV(env);
2131 CHECK_ARG(env, result);
2132
2133 *result = v8impl::JsValueFromV8LocalValue(
2134 v8::Array::New(env->isolate, length));
2135
2136 return napi_clear_last_error(env);
2137 }
2138
napi_create_string_latin1(napi_env env,const char * str,size_t length,napi_value * result)2139 napi_status napi_create_string_latin1(napi_env env,
2140 const char* str,
2141 size_t length,
2142 napi_value* result) {
2143 CHECK_ENV(env);
2144 CHECK_ARG(env, result);
2145 RETURN_STATUS_IF_FALSE(env,
2146 (length == NAPI_AUTO_LENGTH) || length <= INT_MAX,
2147 napi_invalid_arg);
2148
2149 auto isolate = env->isolate;
2150 auto str_maybe =
2151 v8::String::NewFromOneByte(isolate,
2152 reinterpret_cast<const uint8_t*>(str),
2153 v8::NewStringType::kNormal,
2154 length);
2155 CHECK_MAYBE_EMPTY(env, str_maybe, napi_generic_failure);
2156
2157 *result = v8impl::JsValueFromV8LocalValue(str_maybe.ToLocalChecked());
2158 return napi_clear_last_error(env);
2159 }
2160
napi_create_string_utf8(napi_env env,const char * str,size_t length,napi_value * result)2161 napi_status napi_create_string_utf8(napi_env env,
2162 const char* str,
2163 size_t length,
2164 napi_value* result) {
2165 CHECK_ENV(env);
2166 CHECK_ARG(env, result);
2167 RETURN_STATUS_IF_FALSE(env,
2168 (length == NAPI_AUTO_LENGTH) || length <= INT_MAX,
2169 napi_invalid_arg);
2170
2171 auto isolate = env->isolate;
2172 auto str_maybe =
2173 v8::String::NewFromUtf8(isolate,
2174 str,
2175 v8::NewStringType::kNormal,
2176 static_cast<int>(length));
2177 CHECK_MAYBE_EMPTY(env, str_maybe, napi_generic_failure);
2178 *result = v8impl::JsValueFromV8LocalValue(str_maybe.ToLocalChecked());
2179 return napi_clear_last_error(env);
2180 }
2181
napi_create_string_utf16(napi_env env,const char16_t * str,size_t length,napi_value * result)2182 napi_status napi_create_string_utf16(napi_env env,
2183 const char16_t* str,
2184 size_t length,
2185 napi_value* result) {
2186 CHECK_ENV(env);
2187 CHECK_ARG(env, result);
2188 RETURN_STATUS_IF_FALSE(env,
2189 (length == NAPI_AUTO_LENGTH) || length <= INT_MAX,
2190 napi_invalid_arg);
2191
2192 auto isolate = env->isolate;
2193 auto str_maybe =
2194 v8::String::NewFromTwoByte(isolate,
2195 reinterpret_cast<const uint16_t*>(str),
2196 v8::NewStringType::kNormal,
2197 length);
2198 CHECK_MAYBE_EMPTY(env, str_maybe, napi_generic_failure);
2199
2200 *result = v8impl::JsValueFromV8LocalValue(str_maybe.ToLocalChecked());
2201 return napi_clear_last_error(env);
2202 }
2203
napi_create_double(napi_env env,double value,napi_value * result)2204 napi_status napi_create_double(napi_env env,
2205 double value,
2206 napi_value* result) {
2207 CHECK_ENV(env);
2208 CHECK_ARG(env, result);
2209
2210 *result = v8impl::JsValueFromV8LocalValue(
2211 v8::Number::New(env->isolate, value));
2212
2213 return napi_clear_last_error(env);
2214 }
2215
napi_create_int32(napi_env env,int32_t value,napi_value * result)2216 napi_status napi_create_int32(napi_env env,
2217 int32_t value,
2218 napi_value* result) {
2219 CHECK_ENV(env);
2220 CHECK_ARG(env, result);
2221
2222 *result = v8impl::JsValueFromV8LocalValue(
2223 v8::Integer::New(env->isolate, value));
2224
2225 return napi_clear_last_error(env);
2226 }
2227
napi_create_uint32(napi_env env,uint32_t value,napi_value * result)2228 napi_status napi_create_uint32(napi_env env,
2229 uint32_t value,
2230 napi_value* result) {
2231 CHECK_ENV(env);
2232 CHECK_ARG(env, result);
2233
2234 *result = v8impl::JsValueFromV8LocalValue(
2235 v8::Integer::NewFromUnsigned(env->isolate, value));
2236
2237 return napi_clear_last_error(env);
2238 }
2239
napi_create_int64(napi_env env,int64_t value,napi_value * result)2240 napi_status napi_create_int64(napi_env env,
2241 int64_t value,
2242 napi_value* result) {
2243 CHECK_ENV(env);
2244 CHECK_ARG(env, result);
2245
2246 *result = v8impl::JsValueFromV8LocalValue(
2247 v8::Number::New(env->isolate, static_cast<double>(value)));
2248
2249 return napi_clear_last_error(env);
2250 }
2251
napi_create_bigint_int64(napi_env env,int64_t value,napi_value * result)2252 napi_status napi_create_bigint_int64(napi_env env,
2253 int64_t value,
2254 napi_value* result) {
2255 CHECK_ENV(env);
2256 CHECK_ARG(env, result);
2257
2258 *result = v8impl::JsValueFromV8LocalValue(
2259 v8::BigInt::New(env->isolate, value));
2260
2261 return napi_clear_last_error(env);
2262 }
2263
napi_create_bigint_uint64(napi_env env,uint64_t value,napi_value * result)2264 napi_status napi_create_bigint_uint64(napi_env env,
2265 uint64_t value,
2266 napi_value* result) {
2267 CHECK_ENV(env);
2268 CHECK_ARG(env, result);
2269
2270 *result = v8impl::JsValueFromV8LocalValue(
2271 v8::BigInt::NewFromUnsigned(env->isolate, value));
2272
2273 return napi_clear_last_error(env);
2274 }
2275
napi_create_bigint_words(napi_env env,int sign_bit,size_t word_count,const uint64_t * words,napi_value * result)2276 napi_status napi_create_bigint_words(napi_env env,
2277 int sign_bit,
2278 size_t word_count,
2279 const uint64_t* words,
2280 napi_value* result) {
2281 NAPI_PREAMBLE(env);
2282 CHECK_ARG(env, words);
2283 CHECK_ARG(env, result);
2284
2285 v8::Local<v8::Context> context = env->context();
2286
2287 if (word_count > INT_MAX) {
2288 napi_throw_range_error(env, nullptr, "Maximum BigInt size exceeded");
2289 return napi_set_last_error(env, napi_pending_exception);
2290 }
2291
2292 v8::MaybeLocal<v8::BigInt> b = v8::BigInt::NewFromWords(
2293 context, sign_bit, word_count, words);
2294
2295 if (try_catch.HasCaught()) {
2296 return napi_set_last_error(env, napi_pending_exception);
2297 } else {
2298 CHECK_MAYBE_EMPTY(env, b, napi_generic_failure);
2299 *result = v8impl::JsValueFromV8LocalValue(b.ToLocalChecked());
2300 return napi_clear_last_error(env);
2301 }
2302 }
2303
napi_get_boolean(napi_env env,bool value,napi_value * result)2304 napi_status napi_get_boolean(napi_env env, bool value, napi_value* result) {
2305 CHECK_ENV(env);
2306 CHECK_ARG(env, result);
2307
2308 v8::Isolate* isolate = env->isolate;
2309
2310 if (value) {
2311 *result = v8impl::JsValueFromV8LocalValue(v8::True(isolate));
2312 } else {
2313 *result = v8impl::JsValueFromV8LocalValue(v8::False(isolate));
2314 }
2315
2316 return napi_clear_last_error(env);
2317 }
2318
napi_create_symbol(napi_env env,napi_value description,napi_value * result)2319 napi_status napi_create_symbol(napi_env env,
2320 napi_value description,
2321 napi_value* result) {
2322 CHECK_ENV(env);
2323 CHECK_ARG(env, result);
2324
2325 v8::Isolate* isolate = env->isolate;
2326
2327 if (description == nullptr) {
2328 *result = v8impl::JsValueFromV8LocalValue(v8::Symbol::New(isolate));
2329 } else {
2330 v8::Local<v8::Value> desc = v8impl::V8LocalValueFromJsValue(description);
2331 RETURN_STATUS_IF_FALSE(env, desc->IsString(), napi_string_expected);
2332
2333 *result = v8impl::JsValueFromV8LocalValue(
2334 v8::Symbol::New(isolate, desc.As<v8::String>()));
2335 }
2336
2337 return napi_clear_last_error(env);
2338 }
2339
set_error_code(napi_env env,v8::Local<v8::Value> error,napi_value code,const char * code_cstring)2340 static napi_status set_error_code(napi_env env,
2341 v8::Local<v8::Value> error,
2342 napi_value code,
2343 const char* code_cstring) {
2344 if ((code != nullptr) || (code_cstring != nullptr)) {
2345 v8::Isolate* isolate = env->isolate;
2346 v8::Local<v8::Context> context = env->context();
2347 v8::Local<v8::Object> err_object = error.As<v8::Object>();
2348
2349 v8::Local<v8::Value> code_value = v8impl::V8LocalValueFromJsValue(code);
2350 if (code != nullptr) {
2351 code_value = v8impl::V8LocalValueFromJsValue(code);
2352 RETURN_STATUS_IF_FALSE(env, code_value->IsString(), napi_string_expected);
2353 } else {
2354 CHECK_NEW_FROM_UTF8(env, code_value, code_cstring);
2355 }
2356
2357 v8::Local<v8::Name> code_key;
2358 CHECK_NEW_FROM_UTF8(env, code_key, "code");
2359
2360 v8::Maybe<bool> set_maybe = err_object->Set(context, code_key, code_value);
2361 RETURN_STATUS_IF_FALSE(env,
2362 set_maybe.FromMaybe(false),
2363 napi_generic_failure);
2364
2365 // now update the name to be "name [code]" where name is the
2366 // original name and code is the code associated with the Error
2367 v8::Local<v8::String> name_string;
2368 CHECK_NEW_FROM_UTF8(env, name_string, "");
2369 v8::Local<v8::Name> name_key;
2370 CHECK_NEW_FROM_UTF8(env, name_key, "name");
2371
2372 auto maybe_name = err_object->Get(context, name_key);
2373 if (!maybe_name.IsEmpty()) {
2374 v8::Local<v8::Value> name = maybe_name.ToLocalChecked();
2375 if (name->IsString()) {
2376 name_string =
2377 v8::String::Concat(isolate, name_string, name.As<v8::String>());
2378 }
2379 }
2380 name_string = v8::String::Concat(
2381 isolate, name_string, node::FIXED_ONE_BYTE_STRING(isolate, " ["));
2382 name_string =
2383 v8::String::Concat(isolate, name_string, code_value.As<v8::String>());
2384 name_string = v8::String::Concat(
2385 isolate, name_string, node::FIXED_ONE_BYTE_STRING(isolate, "]"));
2386
2387 set_maybe = err_object->Set(context, name_key, name_string);
2388 RETURN_STATUS_IF_FALSE(env,
2389 set_maybe.FromMaybe(false),
2390 napi_generic_failure);
2391 }
2392 return napi_ok;
2393 }
2394
napi_create_error(napi_env env,napi_value code,napi_value msg,napi_value * result)2395 napi_status napi_create_error(napi_env env,
2396 napi_value code,
2397 napi_value msg,
2398 napi_value* result) {
2399 CHECK_ENV(env);
2400 CHECK_ARG(env, msg);
2401 CHECK_ARG(env, result);
2402
2403 v8::Local<v8::Value> message_value = v8impl::V8LocalValueFromJsValue(msg);
2404 RETURN_STATUS_IF_FALSE(env, message_value->IsString(), napi_string_expected);
2405
2406 v8::Local<v8::Value> error_obj =
2407 v8::Exception::Error(message_value.As<v8::String>());
2408 napi_status status = set_error_code(env, error_obj, code, nullptr);
2409 if (status != napi_ok) return status;
2410
2411 *result = v8impl::JsValueFromV8LocalValue(error_obj);
2412
2413 return napi_clear_last_error(env);
2414 }
2415
napi_create_type_error(napi_env env,napi_value code,napi_value msg,napi_value * result)2416 napi_status napi_create_type_error(napi_env env,
2417 napi_value code,
2418 napi_value msg,
2419 napi_value* result) {
2420 CHECK_ENV(env);
2421 CHECK_ARG(env, msg);
2422 CHECK_ARG(env, result);
2423
2424 v8::Local<v8::Value> message_value = v8impl::V8LocalValueFromJsValue(msg);
2425 RETURN_STATUS_IF_FALSE(env, message_value->IsString(), napi_string_expected);
2426
2427 v8::Local<v8::Value> error_obj =
2428 v8::Exception::TypeError(message_value.As<v8::String>());
2429 napi_status status = set_error_code(env, error_obj, code, nullptr);
2430 if (status != napi_ok) return status;
2431
2432 *result = v8impl::JsValueFromV8LocalValue(error_obj);
2433
2434 return napi_clear_last_error(env);
2435 }
2436
napi_create_range_error(napi_env env,napi_value code,napi_value msg,napi_value * result)2437 napi_status napi_create_range_error(napi_env env,
2438 napi_value code,
2439 napi_value msg,
2440 napi_value* result) {
2441 CHECK_ENV(env);
2442 CHECK_ARG(env, msg);
2443 CHECK_ARG(env, result);
2444
2445 v8::Local<v8::Value> message_value = v8impl::V8LocalValueFromJsValue(msg);
2446 RETURN_STATUS_IF_FALSE(env, message_value->IsString(), napi_string_expected);
2447
2448 v8::Local<v8::Value> error_obj =
2449 v8::Exception::RangeError(message_value.As<v8::String>());
2450 napi_status status = set_error_code(env, error_obj, code, nullptr);
2451 if (status != napi_ok) return status;
2452
2453 *result = v8impl::JsValueFromV8LocalValue(error_obj);
2454
2455 return napi_clear_last_error(env);
2456 }
2457
napi_typeof(napi_env env,napi_value value,napi_valuetype * result)2458 napi_status napi_typeof(napi_env env,
2459 napi_value value,
2460 napi_valuetype* result) {
2461 // Omit NAPI_PREAMBLE and GET_RETURN_STATUS because V8 calls here cannot throw
2462 // JS exceptions.
2463 CHECK_ENV(env);
2464 CHECK_ARG(env, value);
2465 CHECK_ARG(env, result);
2466
2467 v8::Local<v8::Value> v = v8impl::V8LocalValueFromJsValue(value);
2468
2469 if (v->IsNumber()) {
2470 *result = napi_number;
2471 } else if (v->IsBigInt()) {
2472 *result = napi_bigint;
2473 } else if (v->IsString()) {
2474 *result = napi_string;
2475 } else if (v->IsFunction()) {
2476 // This test has to come before IsObject because IsFunction
2477 // implies IsObject
2478 *result = napi_function;
2479 } else if (v->IsExternal()) {
2480 // This test has to come before IsObject because IsExternal
2481 // implies IsObject
2482 *result = napi_external;
2483 } else if (v->IsObject()) {
2484 *result = napi_object;
2485 } else if (v->IsBoolean()) {
2486 *result = napi_boolean;
2487 } else if (v->IsUndefined()) {
2488 *result = napi_undefined;
2489 } else if (v->IsSymbol()) {
2490 *result = napi_symbol;
2491 } else if (v->IsNull()) {
2492 *result = napi_null;
2493 } else {
2494 // Should not get here unless V8 has added some new kind of value.
2495 return napi_set_last_error(env, napi_invalid_arg);
2496 }
2497
2498 return napi_clear_last_error(env);
2499 }
2500
napi_get_undefined(napi_env env,napi_value * result)2501 napi_status napi_get_undefined(napi_env env, napi_value* result) {
2502 CHECK_ENV(env);
2503 CHECK_ARG(env, result);
2504
2505 *result = v8impl::JsValueFromV8LocalValue(
2506 v8::Undefined(env->isolate));
2507
2508 return napi_clear_last_error(env);
2509 }
2510
napi_get_null(napi_env env,napi_value * result)2511 napi_status napi_get_null(napi_env env, napi_value* result) {
2512 CHECK_ENV(env);
2513 CHECK_ARG(env, result);
2514
2515 *result = v8impl::JsValueFromV8LocalValue(
2516 v8::Null(env->isolate));
2517
2518 return napi_clear_last_error(env);
2519 }
2520
2521 // Gets all callback info in a single call. (Ugly, but faster.)
napi_get_cb_info(napi_env env,napi_callback_info cbinfo,size_t * argc,napi_value * argv,napi_value * this_arg,void ** data)2522 napi_status napi_get_cb_info(
2523 napi_env env, // [in] NAPI environment handle
2524 napi_callback_info cbinfo, // [in] Opaque callback-info handle
2525 size_t* argc, // [in-out] Specifies the size of the provided argv array
2526 // and receives the actual count of args.
2527 napi_value* argv, // [out] Array of values
2528 napi_value* this_arg, // [out] Receives the JS 'this' arg for the call
2529 void** data) { // [out] Receives the data pointer for the callback.
2530 CHECK_ENV(env);
2531 CHECK_ARG(env, cbinfo);
2532
2533 v8impl::CallbackWrapper* info =
2534 reinterpret_cast<v8impl::CallbackWrapper*>(cbinfo);
2535
2536 if (argv != nullptr) {
2537 CHECK_ARG(env, argc);
2538 info->Args(argv, *argc);
2539 }
2540 if (argc != nullptr) {
2541 *argc = info->ArgsLength();
2542 }
2543 if (this_arg != nullptr) {
2544 *this_arg = info->This();
2545 }
2546 if (data != nullptr) {
2547 *data = info->Data();
2548 }
2549
2550 return napi_clear_last_error(env);
2551 }
2552
napi_get_new_target(napi_env env,napi_callback_info cbinfo,napi_value * result)2553 napi_status napi_get_new_target(napi_env env,
2554 napi_callback_info cbinfo,
2555 napi_value* result) {
2556 CHECK_ENV(env);
2557 CHECK_ARG(env, cbinfo);
2558 CHECK_ARG(env, result);
2559
2560 v8impl::CallbackWrapper* info =
2561 reinterpret_cast<v8impl::CallbackWrapper*>(cbinfo);
2562
2563 *result = info->GetNewTarget();
2564 return napi_clear_last_error(env);
2565 }
2566
napi_call_function(napi_env env,napi_value recv,napi_value func,size_t argc,const napi_value * argv,napi_value * result)2567 napi_status napi_call_function(napi_env env,
2568 napi_value recv,
2569 napi_value func,
2570 size_t argc,
2571 const napi_value* argv,
2572 napi_value* result) {
2573 NAPI_PREAMBLE(env);
2574 CHECK_ARG(env, recv);
2575 if (argc > 0) {
2576 CHECK_ARG(env, argv);
2577 }
2578
2579 v8::Local<v8::Context> context = env->context();
2580
2581 v8::Local<v8::Value> v8recv = v8impl::V8LocalValueFromJsValue(recv);
2582
2583 v8::Local<v8::Function> v8func;
2584 CHECK_TO_FUNCTION(env, v8func, func);
2585
2586 auto maybe = v8func->Call(context, v8recv, argc,
2587 reinterpret_cast<v8::Local<v8::Value>*>(const_cast<napi_value*>(argv)));
2588
2589 if (try_catch.HasCaught()) {
2590 return napi_set_last_error(env, napi_pending_exception);
2591 } else {
2592 if (result != nullptr) {
2593 CHECK_MAYBE_EMPTY(env, maybe, napi_generic_failure);
2594 *result = v8impl::JsValueFromV8LocalValue(maybe.ToLocalChecked());
2595 }
2596 return napi_clear_last_error(env);
2597 }
2598 }
2599
napi_get_global(napi_env env,napi_value * result)2600 napi_status napi_get_global(napi_env env, napi_value* result) {
2601 CHECK_ENV(env);
2602 CHECK_ARG(env, result);
2603
2604 v8::Local<v8::Context> context = env->context();
2605 *result = v8impl::JsValueFromV8LocalValue(context->Global());
2606
2607 return napi_clear_last_error(env);
2608 }
2609
napi_throw(napi_env env,napi_value error)2610 napi_status napi_throw(napi_env env, napi_value error) {
2611 NAPI_PREAMBLE(env);
2612 CHECK_ARG(env, error);
2613
2614 v8::Isolate* isolate = env->isolate;
2615
2616 isolate->ThrowException(v8impl::V8LocalValueFromJsValue(error));
2617 // any VM calls after this point and before returning
2618 // to the javascript invoker will fail
2619 return napi_clear_last_error(env);
2620 }
2621
napi_throw_error(napi_env env,const char * code,const char * msg)2622 napi_status napi_throw_error(napi_env env,
2623 const char* code,
2624 const char* msg) {
2625 NAPI_PREAMBLE(env);
2626
2627 v8::Isolate* isolate = env->isolate;
2628 v8::Local<v8::String> str;
2629 CHECK_NEW_FROM_UTF8(env, str, msg);
2630
2631 v8::Local<v8::Value> error_obj = v8::Exception::Error(str);
2632 napi_status status = set_error_code(env, error_obj, nullptr, code);
2633 if (status != napi_ok) return status;
2634
2635 isolate->ThrowException(error_obj);
2636 // any VM calls after this point and before returning
2637 // to the javascript invoker will fail
2638 return napi_clear_last_error(env);
2639 }
2640
napi_throw_type_error(napi_env env,const char * code,const char * msg)2641 napi_status napi_throw_type_error(napi_env env,
2642 const char* code,
2643 const char* msg) {
2644 NAPI_PREAMBLE(env);
2645
2646 v8::Isolate* isolate = env->isolate;
2647 v8::Local<v8::String> str;
2648 CHECK_NEW_FROM_UTF8(env, str, msg);
2649
2650 v8::Local<v8::Value> error_obj = v8::Exception::TypeError(str);
2651 napi_status status = set_error_code(env, error_obj, nullptr, code);
2652 if (status != napi_ok) return status;
2653
2654 isolate->ThrowException(error_obj);
2655 // any VM calls after this point and before returning
2656 // to the javascript invoker will fail
2657 return napi_clear_last_error(env);
2658 }
2659
napi_throw_range_error(napi_env env,const char * code,const char * msg)2660 napi_status napi_throw_range_error(napi_env env,
2661 const char* code,
2662 const char* msg) {
2663 NAPI_PREAMBLE(env);
2664
2665 v8::Isolate* isolate = env->isolate;
2666 v8::Local<v8::String> str;
2667 CHECK_NEW_FROM_UTF8(env, str, msg);
2668
2669 v8::Local<v8::Value> error_obj = v8::Exception::RangeError(str);
2670 napi_status status = set_error_code(env, error_obj, nullptr, code);
2671 if (status != napi_ok) return status;
2672
2673 isolate->ThrowException(error_obj);
2674 // any VM calls after this point and before returning
2675 // to the javascript invoker will fail
2676 return napi_clear_last_error(env);
2677 }
2678
napi_is_error(napi_env env,napi_value value,bool * result)2679 napi_status napi_is_error(napi_env env, napi_value value, bool* result) {
2680 // Omit NAPI_PREAMBLE and GET_RETURN_STATUS because V8 calls here cannot
2681 // throw JS exceptions.
2682 CHECK_ENV(env);
2683 CHECK_ARG(env, value);
2684 CHECK_ARG(env, result);
2685
2686 v8::Local<v8::Value> val = v8impl::V8LocalValueFromJsValue(value);
2687 *result = val->IsNativeError();
2688
2689 return napi_clear_last_error(env);
2690 }
2691
napi_get_value_double(napi_env env,napi_value value,double * result)2692 napi_status napi_get_value_double(napi_env env,
2693 napi_value value,
2694 double* result) {
2695 // Omit NAPI_PREAMBLE and GET_RETURN_STATUS because V8 calls here cannot throw
2696 // JS exceptions.
2697 CHECK_ENV(env);
2698 CHECK_ARG(env, value);
2699 CHECK_ARG(env, result);
2700
2701 v8::Local<v8::Value> val = v8impl::V8LocalValueFromJsValue(value);
2702 RETURN_STATUS_IF_FALSE(env, val->IsNumber(), napi_number_expected);
2703
2704 *result = val.As<v8::Number>()->Value();
2705
2706 return napi_clear_last_error(env);
2707 }
2708
napi_get_value_int32(napi_env env,napi_value value,int32_t * result)2709 napi_status napi_get_value_int32(napi_env env,
2710 napi_value value,
2711 int32_t* result) {
2712 // Omit NAPI_PREAMBLE and GET_RETURN_STATUS because V8 calls here cannot throw
2713 // JS exceptions.
2714 CHECK_ENV(env);
2715 CHECK_ARG(env, value);
2716 CHECK_ARG(env, result);
2717
2718 v8::Local<v8::Value> val = v8impl::V8LocalValueFromJsValue(value);
2719
2720 if (val->IsInt32()) {
2721 *result = val.As<v8::Int32>()->Value();
2722 } else {
2723 RETURN_STATUS_IF_FALSE(env, val->IsNumber(), napi_number_expected);
2724
2725 // Empty context: https://github.com/nodejs/node/issues/14379
2726 v8::Local<v8::Context> context;
2727 *result = val->Int32Value(context).FromJust();
2728 }
2729
2730 return napi_clear_last_error(env);
2731 }
2732
napi_get_value_uint32(napi_env env,napi_value value,uint32_t * result)2733 napi_status napi_get_value_uint32(napi_env env,
2734 napi_value value,
2735 uint32_t* result) {
2736 // Omit NAPI_PREAMBLE and GET_RETURN_STATUS because V8 calls here cannot throw
2737 // JS exceptions.
2738 CHECK_ENV(env);
2739 CHECK_ARG(env, value);
2740 CHECK_ARG(env, result);
2741
2742 v8::Local<v8::Value> val = v8impl::V8LocalValueFromJsValue(value);
2743
2744 if (val->IsUint32()) {
2745 *result = val.As<v8::Uint32>()->Value();
2746 } else {
2747 RETURN_STATUS_IF_FALSE(env, val->IsNumber(), napi_number_expected);
2748
2749 // Empty context: https://github.com/nodejs/node/issues/14379
2750 v8::Local<v8::Context> context;
2751 *result = val->Uint32Value(context).FromJust();
2752 }
2753
2754 return napi_clear_last_error(env);
2755 }
2756
napi_get_value_int64(napi_env env,napi_value value,int64_t * result)2757 napi_status napi_get_value_int64(napi_env env,
2758 napi_value value,
2759 int64_t* result) {
2760 // Omit NAPI_PREAMBLE and GET_RETURN_STATUS because V8 calls here cannot throw
2761 // JS exceptions.
2762 CHECK_ENV(env);
2763 CHECK_ARG(env, value);
2764 CHECK_ARG(env, result);
2765
2766 v8::Local<v8::Value> val = v8impl::V8LocalValueFromJsValue(value);
2767
2768 // This is still a fast path very likely to be taken.
2769 if (val->IsInt32()) {
2770 *result = val.As<v8::Int32>()->Value();
2771 return napi_clear_last_error(env);
2772 }
2773
2774 RETURN_STATUS_IF_FALSE(env, val->IsNumber(), napi_number_expected);
2775
2776 // v8::Value::IntegerValue() converts NaN, +Inf, and -Inf to INT64_MIN,
2777 // inconsistent with v8::Value::Int32Value() which converts those values to 0.
2778 // Special-case all non-finite values to match that behavior.
2779 double doubleValue = val.As<v8::Number>()->Value();
2780 if (std::isfinite(doubleValue)) {
2781 // Empty context: https://github.com/nodejs/node/issues/14379
2782 v8::Local<v8::Context> context;
2783 *result = val->IntegerValue(context).FromJust();
2784 } else {
2785 *result = 0;
2786 }
2787
2788 return napi_clear_last_error(env);
2789 }
2790
napi_get_value_bigint_int64(napi_env env,napi_value value,int64_t * result,bool * lossless)2791 napi_status napi_get_value_bigint_int64(napi_env env,
2792 napi_value value,
2793 int64_t* result,
2794 bool* lossless) {
2795 CHECK_ENV(env);
2796 CHECK_ARG(env, value);
2797 CHECK_ARG(env, result);
2798 CHECK_ARG(env, lossless);
2799
2800 v8::Local<v8::Value> val = v8impl::V8LocalValueFromJsValue(value);
2801
2802 RETURN_STATUS_IF_FALSE(env, val->IsBigInt(), napi_bigint_expected);
2803
2804 *result = val.As<v8::BigInt>()->Int64Value(lossless);
2805
2806 return napi_clear_last_error(env);
2807 }
2808
napi_get_value_bigint_uint64(napi_env env,napi_value value,uint64_t * result,bool * lossless)2809 napi_status napi_get_value_bigint_uint64(napi_env env,
2810 napi_value value,
2811 uint64_t* result,
2812 bool* lossless) {
2813 CHECK_ENV(env);
2814 CHECK_ARG(env, value);
2815 CHECK_ARG(env, result);
2816 CHECK_ARG(env, lossless);
2817
2818 v8::Local<v8::Value> val = v8impl::V8LocalValueFromJsValue(value);
2819
2820 RETURN_STATUS_IF_FALSE(env, val->IsBigInt(), napi_bigint_expected);
2821
2822 *result = val.As<v8::BigInt>()->Uint64Value(lossless);
2823
2824 return napi_clear_last_error(env);
2825 }
2826
napi_get_value_bigint_words(napi_env env,napi_value value,int * sign_bit,size_t * word_count,uint64_t * words)2827 napi_status napi_get_value_bigint_words(napi_env env,
2828 napi_value value,
2829 int* sign_bit,
2830 size_t* word_count,
2831 uint64_t* words) {
2832 CHECK_ENV(env);
2833 CHECK_ARG(env, value);
2834 CHECK_ARG(env, word_count);
2835
2836 v8::Local<v8::Value> val = v8impl::V8LocalValueFromJsValue(value);
2837
2838 RETURN_STATUS_IF_FALSE(env, val->IsBigInt(), napi_bigint_expected);
2839
2840 v8::Local<v8::BigInt> big = val.As<v8::BigInt>();
2841
2842 int word_count_int = *word_count;
2843
2844 if (sign_bit == nullptr && words == nullptr) {
2845 word_count_int = big->WordCount();
2846 } else {
2847 CHECK_ARG(env, sign_bit);
2848 CHECK_ARG(env, words);
2849 big->ToWordsArray(sign_bit, &word_count_int, words);
2850 }
2851
2852 *word_count = word_count_int;
2853
2854 return napi_clear_last_error(env);
2855 }
2856
napi_get_value_bool(napi_env env,napi_value value,bool * result)2857 napi_status napi_get_value_bool(napi_env env, napi_value value, bool* result) {
2858 // Omit NAPI_PREAMBLE and GET_RETURN_STATUS because V8 calls here cannot throw
2859 // JS exceptions.
2860 CHECK_ENV(env);
2861 CHECK_ARG(env, value);
2862 CHECK_ARG(env, result);
2863
2864 v8::Local<v8::Value> val = v8impl::V8LocalValueFromJsValue(value);
2865 RETURN_STATUS_IF_FALSE(env, val->IsBoolean(), napi_boolean_expected);
2866
2867 *result = val.As<v8::Boolean>()->Value();
2868
2869 return napi_clear_last_error(env);
2870 }
2871
2872 // Copies a JavaScript string into a LATIN-1 string buffer. The result is the
2873 // number of bytes (excluding the null terminator) copied into buf.
2874 // A sufficient buffer size should be greater than the length of string,
2875 // reserving space for null terminator.
2876 // If bufsize is insufficient, the string will be truncated and null terminated.
2877 // If buf is NULL, this method returns the length of the string (in bytes)
2878 // via the result parameter.
2879 // The result argument is optional unless buf is NULL.
napi_get_value_string_latin1(napi_env env,napi_value value,char * buf,size_t bufsize,size_t * result)2880 napi_status napi_get_value_string_latin1(napi_env env,
2881 napi_value value,
2882 char* buf,
2883 size_t bufsize,
2884 size_t* result) {
2885 CHECK_ENV(env);
2886 CHECK_ARG(env, value);
2887
2888 v8::Local<v8::Value> val = v8impl::V8LocalValueFromJsValue(value);
2889 RETURN_STATUS_IF_FALSE(env, val->IsString(), napi_string_expected);
2890
2891 if (!buf) {
2892 CHECK_ARG(env, result);
2893 *result = val.As<v8::String>()->Length();
2894 } else if (bufsize != 0) {
2895 int copied =
2896 val.As<v8::String>()->WriteOneByte(env->isolate,
2897 reinterpret_cast<uint8_t*>(buf),
2898 0,
2899 bufsize - 1,
2900 v8::String::NO_NULL_TERMINATION);
2901
2902 buf[copied] = '\0';
2903 if (result != nullptr) {
2904 *result = copied;
2905 }
2906 } else if (result != nullptr) {
2907 *result = 0;
2908 }
2909
2910 return napi_clear_last_error(env);
2911 }
2912
2913 // Copies a JavaScript string into a UTF-8 string buffer. The result is the
2914 // number of bytes (excluding the null terminator) copied into buf.
2915 // A sufficient buffer size should be greater than the length of string,
2916 // reserving space for null terminator.
2917 // If bufsize is insufficient, the string will be truncated and null terminated.
2918 // If buf is NULL, this method returns the length of the string (in bytes)
2919 // via the result parameter.
2920 // The result argument is optional unless buf is NULL.
napi_get_value_string_utf8(napi_env env,napi_value value,char * buf,size_t bufsize,size_t * result)2921 napi_status napi_get_value_string_utf8(napi_env env,
2922 napi_value value,
2923 char* buf,
2924 size_t bufsize,
2925 size_t* result) {
2926 CHECK_ENV(env);
2927 CHECK_ARG(env, value);
2928
2929 v8::Local<v8::Value> val = v8impl::V8LocalValueFromJsValue(value);
2930 RETURN_STATUS_IF_FALSE(env, val->IsString(), napi_string_expected);
2931
2932 if (!buf) {
2933 CHECK_ARG(env, result);
2934 *result = val.As<v8::String>()->Utf8Length(env->isolate);
2935 } else if (bufsize != 0) {
2936 int copied = val.As<v8::String>()->WriteUtf8(
2937 env->isolate,
2938 buf,
2939 bufsize - 1,
2940 nullptr,
2941 v8::String::REPLACE_INVALID_UTF8 | v8::String::NO_NULL_TERMINATION);
2942
2943 buf[copied] = '\0';
2944 if (result != nullptr) {
2945 *result = copied;
2946 }
2947 } else if (result != nullptr) {
2948 *result = 0;
2949 }
2950
2951 return napi_clear_last_error(env);
2952 }
2953
2954 // Copies a JavaScript string into a UTF-16 string buffer. The result is the
2955 // number of 2-byte code units (excluding the null terminator) copied into buf.
2956 // A sufficient buffer size should be greater than the length of string,
2957 // reserving space for null terminator.
2958 // If bufsize is insufficient, the string will be truncated and null terminated.
2959 // If buf is NULL, this method returns the length of the string (in 2-byte
2960 // code units) via the result parameter.
2961 // The result argument is optional unless buf is NULL.
napi_get_value_string_utf16(napi_env env,napi_value value,char16_t * buf,size_t bufsize,size_t * result)2962 napi_status napi_get_value_string_utf16(napi_env env,
2963 napi_value value,
2964 char16_t* buf,
2965 size_t bufsize,
2966 size_t* result) {
2967 CHECK_ENV(env);
2968 CHECK_ARG(env, value);
2969
2970 v8::Local<v8::Value> val = v8impl::V8LocalValueFromJsValue(value);
2971 RETURN_STATUS_IF_FALSE(env, val->IsString(), napi_string_expected);
2972
2973 if (!buf) {
2974 CHECK_ARG(env, result);
2975 // V8 assumes UTF-16 length is the same as the number of characters.
2976 *result = val.As<v8::String>()->Length();
2977 } else if (bufsize != 0) {
2978 int copied = val.As<v8::String>()->Write(env->isolate,
2979 reinterpret_cast<uint16_t*>(buf),
2980 0,
2981 bufsize - 1,
2982 v8::String::NO_NULL_TERMINATION);
2983
2984 buf[copied] = '\0';
2985 if (result != nullptr) {
2986 *result = copied;
2987 }
2988 } else if (result != nullptr) {
2989 *result = 0;
2990 }
2991
2992 return napi_clear_last_error(env);
2993 }
2994
napi_coerce_to_object(napi_env env,napi_value value,napi_value * result)2995 napi_status napi_coerce_to_object(napi_env env,
2996 napi_value value,
2997 napi_value* result) {
2998 NAPI_PREAMBLE(env);
2999 CHECK_ARG(env, value);
3000 CHECK_ARG(env, result);
3001
3002 v8::Local<v8::Context> context = env->context();
3003 v8::Local<v8::Object> obj;
3004 CHECK_TO_OBJECT(env, context, obj, value);
3005
3006 *result = v8impl::JsValueFromV8LocalValue(obj);
3007 return GET_RETURN_STATUS(env);
3008 }
3009
napi_coerce_to_bool(napi_env env,napi_value value,napi_value * result)3010 napi_status napi_coerce_to_bool(napi_env env,
3011 napi_value value,
3012 napi_value* result) {
3013 NAPI_PREAMBLE(env);
3014 CHECK_ARG(env, value);
3015 CHECK_ARG(env, result);
3016
3017 v8::Local<v8::Context> context = env->context();
3018 v8::Local<v8::Boolean> b;
3019
3020 CHECK_TO_BOOL(env, context, b, value);
3021
3022 *result = v8impl::JsValueFromV8LocalValue(b);
3023 return GET_RETURN_STATUS(env);
3024 }
3025
napi_coerce_to_number(napi_env env,napi_value value,napi_value * result)3026 napi_status napi_coerce_to_number(napi_env env,
3027 napi_value value,
3028 napi_value* result) {
3029 NAPI_PREAMBLE(env);
3030 CHECK_ARG(env, value);
3031 CHECK_ARG(env, result);
3032
3033 v8::Local<v8::Context> context = env->context();
3034 v8::Local<v8::Number> num;
3035
3036 CHECK_TO_NUMBER(env, context, num, value);
3037
3038 *result = v8impl::JsValueFromV8LocalValue(num);
3039 return GET_RETURN_STATUS(env);
3040 }
3041
napi_coerce_to_string(napi_env env,napi_value value,napi_value * result)3042 napi_status napi_coerce_to_string(napi_env env,
3043 napi_value value,
3044 napi_value* result) {
3045 NAPI_PREAMBLE(env);
3046 CHECK_ARG(env, value);
3047 CHECK_ARG(env, result);
3048
3049 v8::Local<v8::Context> context = env->context();
3050 v8::Local<v8::String> str;
3051
3052 CHECK_TO_STRING(env, context, str, value);
3053
3054 *result = v8impl::JsValueFromV8LocalValue(str);
3055 return GET_RETURN_STATUS(env);
3056 }
3057
napi_wrap(napi_env env,napi_value js_object,void * native_object,napi_finalize finalize_cb,void * finalize_hint,napi_ref * result)3058 napi_status napi_wrap(napi_env env,
3059 napi_value js_object,
3060 void* native_object,
3061 napi_finalize finalize_cb,
3062 void* finalize_hint,
3063 napi_ref* result) {
3064 return v8impl::Wrap<v8impl::retrievable>(env,
3065 js_object,
3066 native_object,
3067 finalize_cb,
3068 finalize_hint,
3069 result);
3070 }
3071
napi_unwrap(napi_env env,napi_value obj,void ** result)3072 napi_status napi_unwrap(napi_env env, napi_value obj, void** result) {
3073 return v8impl::Unwrap(env, obj, result, v8impl::KeepWrap);
3074 }
3075
napi_remove_wrap(napi_env env,napi_value obj,void ** result)3076 napi_status napi_remove_wrap(napi_env env, napi_value obj, void** result) {
3077 return v8impl::Unwrap(env, obj, result, v8impl::RemoveWrap);
3078 }
3079
napi_create_external(napi_env env,void * data,napi_finalize finalize_cb,void * finalize_hint,napi_value * result)3080 napi_status napi_create_external(napi_env env,
3081 void* data,
3082 napi_finalize finalize_cb,
3083 void* finalize_hint,
3084 napi_value* result) {
3085 NAPI_PREAMBLE(env);
3086 CHECK_ARG(env, result);
3087
3088 v8::Isolate* isolate = env->isolate;
3089
3090 v8::Local<v8::Value> external_value = v8::External::New(isolate, data);
3091
3092 // The Reference object will delete itself after invoking the finalizer
3093 // callback.
3094 v8impl::Reference::New(env,
3095 external_value,
3096 0,
3097 true,
3098 finalize_cb,
3099 data,
3100 finalize_hint);
3101
3102 *result = v8impl::JsValueFromV8LocalValue(external_value);
3103
3104 return napi_clear_last_error(env);
3105 }
3106
napi_get_value_external(napi_env env,napi_value value,void ** result)3107 napi_status napi_get_value_external(napi_env env,
3108 napi_value value,
3109 void** result) {
3110 CHECK_ENV(env);
3111 CHECK_ARG(env, value);
3112 CHECK_ARG(env, result);
3113
3114 v8::Local<v8::Value> val = v8impl::V8LocalValueFromJsValue(value);
3115 RETURN_STATUS_IF_FALSE(env, val->IsExternal(), napi_invalid_arg);
3116
3117 v8::Local<v8::External> external_value = val.As<v8::External>();
3118 *result = external_value->Value();
3119
3120 return napi_clear_last_error(env);
3121 }
3122
3123 // Set initial_refcount to 0 for a weak reference, >0 for a strong reference.
napi_create_reference(napi_env env,napi_value value,uint32_t initial_refcount,napi_ref * result)3124 napi_status napi_create_reference(napi_env env,
3125 napi_value value,
3126 uint32_t initial_refcount,
3127 napi_ref* result) {
3128 // Omit NAPI_PREAMBLE and GET_RETURN_STATUS because V8 calls here cannot throw
3129 // JS exceptions.
3130 CHECK_ENV(env);
3131 CHECK_ARG(env, value);
3132 CHECK_ARG(env, result);
3133
3134 v8::Local<v8::Value> v8_value = v8impl::V8LocalValueFromJsValue(value);
3135
3136 if (!(v8_value->IsObject() || v8_value->IsFunction())) {
3137 return napi_set_last_error(env, napi_object_expected);
3138 }
3139
3140 v8impl::Reference* reference =
3141 v8impl::Reference::New(env, v8_value, initial_refcount, false);
3142
3143 *result = reinterpret_cast<napi_ref>(reference);
3144 return napi_clear_last_error(env);
3145 }
3146
3147 // Deletes a reference. The referenced value is released, and may be GC'd unless
3148 // there are other references to it.
napi_delete_reference(napi_env env,napi_ref ref)3149 napi_status napi_delete_reference(napi_env env, napi_ref ref) {
3150 // Omit NAPI_PREAMBLE and GET_RETURN_STATUS because V8 calls here cannot throw
3151 // JS exceptions.
3152 CHECK_ENV(env);
3153 CHECK_ARG(env, ref);
3154
3155 v8impl::Reference::Delete(reinterpret_cast<v8impl::Reference*>(ref));
3156
3157 return napi_clear_last_error(env);
3158 }
3159
3160 // Increments the reference count, optionally returning the resulting count.
3161 // After this call the reference will be a strong reference because its
3162 // refcount is >0, and the referenced object is effectively "pinned".
3163 // Calling this when the refcount is 0 and the object is unavailable
3164 // results in an error.
napi_reference_ref(napi_env env,napi_ref ref,uint32_t * result)3165 napi_status napi_reference_ref(napi_env env, napi_ref ref, uint32_t* result) {
3166 // Omit NAPI_PREAMBLE and GET_RETURN_STATUS because V8 calls here cannot throw
3167 // JS exceptions.
3168 CHECK_ENV(env);
3169 CHECK_ARG(env, ref);
3170
3171 v8impl::Reference* reference = reinterpret_cast<v8impl::Reference*>(ref);
3172 uint32_t count = reference->Ref();
3173
3174 if (result != nullptr) {
3175 *result = count;
3176 }
3177
3178 return napi_clear_last_error(env);
3179 }
3180
3181 // Decrements the reference count, optionally returning the resulting count. If
3182 // the result is 0 the reference is now weak and the object may be GC'd at any
3183 // time if there are no other references. Calling this when the refcount is
3184 // already 0 results in an error.
napi_reference_unref(napi_env env,napi_ref ref,uint32_t * result)3185 napi_status napi_reference_unref(napi_env env, napi_ref ref, uint32_t* result) {
3186 // Omit NAPI_PREAMBLE and GET_RETURN_STATUS because V8 calls here cannot throw
3187 // JS exceptions.
3188 CHECK_ENV(env);
3189 CHECK_ARG(env, ref);
3190
3191 v8impl::Reference* reference = reinterpret_cast<v8impl::Reference*>(ref);
3192
3193 if (reference->RefCount() == 0) {
3194 return napi_set_last_error(env, napi_generic_failure);
3195 }
3196
3197 uint32_t count = reference->Unref();
3198
3199 if (result != nullptr) {
3200 *result = count;
3201 }
3202
3203 return napi_clear_last_error(env);
3204 }
3205
3206 // Attempts to get a referenced value. If the reference is weak, the value might
3207 // no longer be available, in that case the call is still successful but the
3208 // result is NULL.
napi_get_reference_value(napi_env env,napi_ref ref,napi_value * result)3209 napi_status napi_get_reference_value(napi_env env,
3210 napi_ref ref,
3211 napi_value* result) {
3212 // Omit NAPI_PREAMBLE and GET_RETURN_STATUS because V8 calls here cannot throw
3213 // JS exceptions.
3214 CHECK_ENV(env);
3215 CHECK_ARG(env, ref);
3216 CHECK_ARG(env, result);
3217
3218 v8impl::Reference* reference = reinterpret_cast<v8impl::Reference*>(ref);
3219 *result = v8impl::JsValueFromV8LocalValue(reference->Get());
3220
3221 return napi_clear_last_error(env);
3222 }
3223
napi_open_handle_scope(napi_env env,napi_handle_scope * result)3224 napi_status napi_open_handle_scope(napi_env env, napi_handle_scope* result) {
3225 // Omit NAPI_PREAMBLE and GET_RETURN_STATUS because V8 calls here cannot throw
3226 // JS exceptions.
3227 CHECK_ENV(env);
3228 CHECK_ARG(env, result);
3229
3230 *result = v8impl::JsHandleScopeFromV8HandleScope(
3231 new v8impl::HandleScopeWrapper(env->isolate));
3232 env->open_handle_scopes++;
3233 return napi_clear_last_error(env);
3234 }
3235
napi_close_handle_scope(napi_env env,napi_handle_scope scope)3236 napi_status napi_close_handle_scope(napi_env env, napi_handle_scope scope) {
3237 // Omit NAPI_PREAMBLE and GET_RETURN_STATUS because V8 calls here cannot throw
3238 // JS exceptions.
3239 CHECK_ENV(env);
3240 CHECK_ARG(env, scope);
3241 if (env->open_handle_scopes == 0) {
3242 return napi_handle_scope_mismatch;
3243 }
3244
3245 env->open_handle_scopes--;
3246 delete v8impl::V8HandleScopeFromJsHandleScope(scope);
3247 return napi_clear_last_error(env);
3248 }
3249
napi_open_escapable_handle_scope(napi_env env,napi_escapable_handle_scope * result)3250 napi_status napi_open_escapable_handle_scope(
3251 napi_env env,
3252 napi_escapable_handle_scope* result) {
3253 // Omit NAPI_PREAMBLE and GET_RETURN_STATUS because V8 calls here cannot throw
3254 // JS exceptions.
3255 CHECK_ENV(env);
3256 CHECK_ARG(env, result);
3257
3258 *result = v8impl::JsEscapableHandleScopeFromV8EscapableHandleScope(
3259 new v8impl::EscapableHandleScopeWrapper(env->isolate));
3260 env->open_handle_scopes++;
3261 return napi_clear_last_error(env);
3262 }
3263
napi_close_escapable_handle_scope(napi_env env,napi_escapable_handle_scope scope)3264 napi_status napi_close_escapable_handle_scope(
3265 napi_env env,
3266 napi_escapable_handle_scope scope) {
3267 // Omit NAPI_PREAMBLE and GET_RETURN_STATUS because V8 calls here cannot throw
3268 // JS exceptions.
3269 CHECK_ENV(env);
3270 CHECK_ARG(env, scope);
3271 if (env->open_handle_scopes == 0) {
3272 return napi_handle_scope_mismatch;
3273 }
3274
3275 delete v8impl::V8EscapableHandleScopeFromJsEscapableHandleScope(scope);
3276 env->open_handle_scopes--;
3277 return napi_clear_last_error(env);
3278 }
3279
napi_escape_handle(napi_env env,napi_escapable_handle_scope scope,napi_value escapee,napi_value * result)3280 napi_status napi_escape_handle(napi_env env,
3281 napi_escapable_handle_scope scope,
3282 napi_value escapee,
3283 napi_value* result) {
3284 // Omit NAPI_PREAMBLE and GET_RETURN_STATUS because V8 calls here cannot throw
3285 // JS exceptions.
3286 CHECK_ENV(env);
3287 CHECK_ARG(env, scope);
3288 CHECK_ARG(env, escapee);
3289 CHECK_ARG(env, result);
3290
3291 v8impl::EscapableHandleScopeWrapper* s =
3292 v8impl::V8EscapableHandleScopeFromJsEscapableHandleScope(scope);
3293 if (!s->escape_called()) {
3294 *result = v8impl::JsValueFromV8LocalValue(
3295 s->Escape(v8impl::V8LocalValueFromJsValue(escapee)));
3296 return napi_clear_last_error(env);
3297 }
3298 return napi_set_last_error(env, napi_escape_called_twice);
3299 }
3300
napi_open_callback_scope(napi_env env,napi_value resource_object,napi_async_context async_context_handle,napi_callback_scope * result)3301 napi_status napi_open_callback_scope(napi_env env,
3302 napi_value resource_object,
3303 napi_async_context async_context_handle,
3304 napi_callback_scope* result) {
3305 // Omit NAPI_PREAMBLE and GET_RETURN_STATUS because V8 calls here cannot throw
3306 // JS exceptions.
3307 CHECK_ENV(env);
3308 CHECK_ARG(env, result);
3309
3310 v8::Local<v8::Context> context = env->context();
3311
3312 node::async_context* node_async_context =
3313 reinterpret_cast<node::async_context*>(async_context_handle);
3314
3315 v8::Local<v8::Object> resource;
3316 CHECK_TO_OBJECT(env, context, resource, resource_object);
3317
3318 *result = v8impl::JsCallbackScopeFromV8CallbackScope(
3319 new node::CallbackScope(env->isolate,
3320 resource,
3321 *node_async_context));
3322
3323 env->open_callback_scopes++;
3324 return napi_clear_last_error(env);
3325 }
3326
napi_close_callback_scope(napi_env env,napi_callback_scope scope)3327 napi_status napi_close_callback_scope(napi_env env, napi_callback_scope scope) {
3328 // Omit NAPI_PREAMBLE and GET_RETURN_STATUS because V8 calls here cannot throw
3329 // JS exceptions.
3330 CHECK_ENV(env);
3331 CHECK_ARG(env, scope);
3332 if (env->open_callback_scopes == 0) {
3333 return napi_callback_scope_mismatch;
3334 }
3335
3336 env->open_callback_scopes--;
3337 delete v8impl::V8CallbackScopeFromJsCallbackScope(scope);
3338 return napi_clear_last_error(env);
3339 }
3340
napi_new_instance(napi_env env,napi_value constructor,size_t argc,const napi_value * argv,napi_value * result)3341 napi_status napi_new_instance(napi_env env,
3342 napi_value constructor,
3343 size_t argc,
3344 const napi_value* argv,
3345 napi_value* result) {
3346 NAPI_PREAMBLE(env);
3347 CHECK_ARG(env, constructor);
3348 if (argc > 0) {
3349 CHECK_ARG(env, argv);
3350 }
3351 CHECK_ARG(env, result);
3352
3353 v8::Local<v8::Context> context = env->context();
3354
3355 v8::Local<v8::Function> ctor;
3356 CHECK_TO_FUNCTION(env, ctor, constructor);
3357
3358 auto maybe = ctor->NewInstance(context, argc,
3359 reinterpret_cast<v8::Local<v8::Value>*>(const_cast<napi_value*>(argv)));
3360
3361 CHECK_MAYBE_EMPTY(env, maybe, napi_generic_failure);
3362
3363 *result = v8impl::JsValueFromV8LocalValue(maybe.ToLocalChecked());
3364 return GET_RETURN_STATUS(env);
3365 }
3366
napi_instanceof(napi_env env,napi_value object,napi_value constructor,bool * result)3367 napi_status napi_instanceof(napi_env env,
3368 napi_value object,
3369 napi_value constructor,
3370 bool* result) {
3371 NAPI_PREAMBLE(env);
3372 CHECK_ARG(env, object);
3373 CHECK_ARG(env, result);
3374
3375 *result = false;
3376
3377 v8::Local<v8::Object> ctor;
3378 v8::Local<v8::Context> context = env->context();
3379
3380 CHECK_TO_OBJECT(env, context, ctor, constructor);
3381
3382 if (!ctor->IsFunction()) {
3383 napi_throw_type_error(env,
3384 "ERR_NAPI_CONS_FUNCTION",
3385 "Constructor must be a function");
3386
3387 return napi_set_last_error(env, napi_function_expected);
3388 }
3389
3390 napi_status status = napi_generic_failure;
3391
3392 v8::Local<v8::Value> val = v8impl::V8LocalValueFromJsValue(object);
3393 auto maybe_result = val->InstanceOf(context, ctor);
3394 CHECK_MAYBE_NOTHING(env, maybe_result, status);
3395 *result = maybe_result.FromJust();
3396 return GET_RETURN_STATUS(env);
3397 }
3398
napi_async_init(napi_env env,napi_value async_resource,napi_value async_resource_name,napi_async_context * result)3399 napi_status napi_async_init(napi_env env,
3400 napi_value async_resource,
3401 napi_value async_resource_name,
3402 napi_async_context* result) {
3403 CHECK_ENV(env);
3404 CHECK_ARG(env, async_resource_name);
3405 CHECK_ARG(env, result);
3406
3407 v8::Isolate* isolate = env->isolate;
3408 v8::Local<v8::Context> context = env->context();
3409
3410 v8::Local<v8::Object> v8_resource;
3411 if (async_resource != nullptr) {
3412 CHECK_TO_OBJECT(env, context, v8_resource, async_resource);
3413 } else {
3414 v8_resource = v8::Object::New(isolate);
3415 }
3416
3417 v8::Local<v8::String> v8_resource_name;
3418 CHECK_TO_STRING(env, context, v8_resource_name, async_resource_name);
3419
3420 // TODO(jasongin): Consider avoiding allocation here by using
3421 // a tagged pointer with 2×31 bit fields instead.
3422 node::async_context* async_context = new node::async_context();
3423
3424 *async_context = node::EmitAsyncInit(isolate, v8_resource, v8_resource_name);
3425 *result = reinterpret_cast<napi_async_context>(async_context);
3426
3427 return napi_clear_last_error(env);
3428 }
3429
napi_async_destroy(napi_env env,napi_async_context async_context)3430 napi_status napi_async_destroy(napi_env env,
3431 napi_async_context async_context) {
3432 CHECK_ENV(env);
3433 CHECK_ARG(env, async_context);
3434
3435 v8::Isolate* isolate = env->isolate;
3436 node::async_context* node_async_context =
3437 reinterpret_cast<node::async_context*>(async_context);
3438 node::EmitAsyncDestroy(isolate, *node_async_context);
3439
3440 delete node_async_context;
3441
3442 return napi_clear_last_error(env);
3443 }
3444
napi_make_callback(napi_env env,napi_async_context async_context,napi_value recv,napi_value func,size_t argc,const napi_value * argv,napi_value * result)3445 napi_status napi_make_callback(napi_env env,
3446 napi_async_context async_context,
3447 napi_value recv,
3448 napi_value func,
3449 size_t argc,
3450 const napi_value* argv,
3451 napi_value* result) {
3452 NAPI_PREAMBLE(env);
3453 CHECK_ARG(env, recv);
3454 if (argc > 0) {
3455 CHECK_ARG(env, argv);
3456 }
3457
3458 v8::Local<v8::Context> context = env->context();
3459
3460 v8::Local<v8::Object> v8recv;
3461 CHECK_TO_OBJECT(env, context, v8recv, recv);
3462
3463 v8::Local<v8::Function> v8func;
3464 CHECK_TO_FUNCTION(env, v8func, func);
3465
3466 node::async_context* node_async_context =
3467 reinterpret_cast<node::async_context*>(async_context);
3468 if (node_async_context == nullptr) {
3469 static node::async_context empty_context = { 0, 0 };
3470 node_async_context = &empty_context;
3471 }
3472
3473 v8::MaybeLocal<v8::Value> callback_result = node::MakeCallback(
3474 env->isolate, v8recv, v8func, argc,
3475 reinterpret_cast<v8::Local<v8::Value>*>(const_cast<napi_value*>(argv)),
3476 *node_async_context);
3477
3478 if (try_catch.HasCaught()) {
3479 return napi_set_last_error(env, napi_pending_exception);
3480 } else {
3481 CHECK_MAYBE_EMPTY(env, callback_result, napi_generic_failure);
3482 if (result != nullptr) {
3483 *result = v8impl::JsValueFromV8LocalValue(
3484 callback_result.ToLocalChecked());
3485 }
3486 }
3487
3488 return GET_RETURN_STATUS(env);
3489 }
3490
3491 // Methods to support catching exceptions
napi_is_exception_pending(napi_env env,bool * result)3492 napi_status napi_is_exception_pending(napi_env env, bool* result) {
3493 // NAPI_PREAMBLE is not used here: this function must execute when there is a
3494 // pending exception.
3495 CHECK_ENV(env);
3496 CHECK_ARG(env, result);
3497
3498 *result = !env->last_exception.IsEmpty();
3499 return napi_clear_last_error(env);
3500 }
3501
napi_get_and_clear_last_exception(napi_env env,napi_value * result)3502 napi_status napi_get_and_clear_last_exception(napi_env env,
3503 napi_value* result) {
3504 // NAPI_PREAMBLE is not used here: this function must execute when there is a
3505 // pending exception.
3506 CHECK_ENV(env);
3507 CHECK_ARG(env, result);
3508
3509 if (env->last_exception.IsEmpty()) {
3510 return napi_get_undefined(env, result);
3511 } else {
3512 *result = v8impl::JsValueFromV8LocalValue(
3513 v8::Local<v8::Value>::New(env->isolate, env->last_exception));
3514 env->last_exception.Reset();
3515 }
3516
3517 return napi_clear_last_error(env);
3518 }
3519
napi_create_buffer(napi_env env,size_t length,void ** data,napi_value * result)3520 napi_status napi_create_buffer(napi_env env,
3521 size_t length,
3522 void** data,
3523 napi_value* result) {
3524 NAPI_PREAMBLE(env);
3525 CHECK_ARG(env, result);
3526
3527 auto maybe = node::Buffer::New(env->isolate, length);
3528
3529 CHECK_MAYBE_EMPTY(env, maybe, napi_generic_failure);
3530
3531 v8::Local<v8::Object> buffer = maybe.ToLocalChecked();
3532
3533 *result = v8impl::JsValueFromV8LocalValue(buffer);
3534
3535 if (data != nullptr) {
3536 *data = node::Buffer::Data(buffer);
3537 }
3538
3539 return GET_RETURN_STATUS(env);
3540 }
3541
napi_create_external_buffer(napi_env env,size_t length,void * data,napi_finalize finalize_cb,void * finalize_hint,napi_value * result)3542 napi_status napi_create_external_buffer(napi_env env,
3543 size_t length,
3544 void* data,
3545 napi_finalize finalize_cb,
3546 void* finalize_hint,
3547 napi_value* result) {
3548 NAPI_PREAMBLE(env);
3549 CHECK_ARG(env, result);
3550
3551 v8::Isolate* isolate = env->isolate;
3552
3553 // The finalizer object will delete itself after invoking the callback.
3554 v8impl::Finalizer* finalizer = v8impl::Finalizer::New(
3555 env, finalize_cb, nullptr, finalize_hint);
3556
3557 auto maybe = node::Buffer::New(isolate,
3558 static_cast<char*>(data),
3559 length,
3560 v8impl::Finalizer::FinalizeBufferCallback,
3561 finalizer);
3562
3563 CHECK_MAYBE_EMPTY(env, maybe, napi_generic_failure);
3564
3565 *result = v8impl::JsValueFromV8LocalValue(maybe.ToLocalChecked());
3566 return GET_RETURN_STATUS(env);
3567 // Tell coverity that 'finalizer' should not be freed when we return
3568 // as it will be deleted when the buffer to which it is associated
3569 // is finalized.
3570 // coverity[leaked_storage]
3571 }
3572
napi_create_buffer_copy(napi_env env,size_t length,const void * data,void ** result_data,napi_value * result)3573 napi_status napi_create_buffer_copy(napi_env env,
3574 size_t length,
3575 const void* data,
3576 void** result_data,
3577 napi_value* result) {
3578 NAPI_PREAMBLE(env);
3579 CHECK_ARG(env, result);
3580
3581 auto maybe = node::Buffer::Copy(env->isolate,
3582 static_cast<const char*>(data), length);
3583
3584 CHECK_MAYBE_EMPTY(env, maybe, napi_generic_failure);
3585
3586 v8::Local<v8::Object> buffer = maybe.ToLocalChecked();
3587 *result = v8impl::JsValueFromV8LocalValue(buffer);
3588
3589 if (result_data != nullptr) {
3590 *result_data = node::Buffer::Data(buffer);
3591 }
3592
3593 return GET_RETURN_STATUS(env);
3594 }
3595
napi_is_buffer(napi_env env,napi_value value,bool * result)3596 napi_status napi_is_buffer(napi_env env, napi_value value, bool* result) {
3597 CHECK_ENV(env);
3598 CHECK_ARG(env, value);
3599 CHECK_ARG(env, result);
3600
3601 *result = node::Buffer::HasInstance(v8impl::V8LocalValueFromJsValue(value));
3602 return napi_clear_last_error(env);
3603 }
3604
napi_get_buffer_info(napi_env env,napi_value value,void ** data,size_t * length)3605 napi_status napi_get_buffer_info(napi_env env,
3606 napi_value value,
3607 void** data,
3608 size_t* length) {
3609 CHECK_ENV(env);
3610 CHECK_ARG(env, value);
3611
3612 v8::Local<v8::Value> buffer = v8impl::V8LocalValueFromJsValue(value);
3613
3614 if (data != nullptr) {
3615 *data = node::Buffer::Data(buffer);
3616 }
3617 if (length != nullptr) {
3618 *length = node::Buffer::Length(buffer);
3619 }
3620
3621 return napi_clear_last_error(env);
3622 }
3623
napi_is_arraybuffer(napi_env env,napi_value value,bool * result)3624 napi_status napi_is_arraybuffer(napi_env env, napi_value value, bool* result) {
3625 CHECK_ENV(env);
3626 CHECK_ARG(env, value);
3627 CHECK_ARG(env, result);
3628
3629 v8::Local<v8::Value> val = v8impl::V8LocalValueFromJsValue(value);
3630 *result = val->IsArrayBuffer();
3631
3632 return napi_clear_last_error(env);
3633 }
3634
napi_create_arraybuffer(napi_env env,size_t byte_length,void ** data,napi_value * result)3635 napi_status napi_create_arraybuffer(napi_env env,
3636 size_t byte_length,
3637 void** data,
3638 napi_value* result) {
3639 NAPI_PREAMBLE(env);
3640 CHECK_ARG(env, result);
3641
3642 v8::Isolate* isolate = env->isolate;
3643 v8::Local<v8::ArrayBuffer> buffer =
3644 v8::ArrayBuffer::New(isolate, byte_length);
3645
3646 // Optionally return a pointer to the buffer's data, to avoid another call to
3647 // retrieve it.
3648 if (data != nullptr) {
3649 *data = buffer->GetContents().Data();
3650 }
3651
3652 *result = v8impl::JsValueFromV8LocalValue(buffer);
3653 return GET_RETURN_STATUS(env);
3654 }
3655
napi_create_external_arraybuffer(napi_env env,void * external_data,size_t byte_length,napi_finalize finalize_cb,void * finalize_hint,napi_value * result)3656 napi_status napi_create_external_arraybuffer(napi_env env,
3657 void* external_data,
3658 size_t byte_length,
3659 napi_finalize finalize_cb,
3660 void* finalize_hint,
3661 napi_value* result) {
3662 NAPI_PREAMBLE(env);
3663 CHECK_ARG(env, result);
3664
3665 v8::Isolate* isolate = env->isolate;
3666 v8::Local<v8::ArrayBuffer> buffer =
3667 v8::ArrayBuffer::New(isolate, external_data, byte_length);
3668
3669 if (finalize_cb != nullptr) {
3670 // Create a self-deleting weak reference that invokes the finalizer
3671 // callback.
3672 v8impl::Reference::New(env,
3673 buffer,
3674 0,
3675 true,
3676 finalize_cb,
3677 external_data,
3678 finalize_hint);
3679 }
3680
3681 *result = v8impl::JsValueFromV8LocalValue(buffer);
3682 return GET_RETURN_STATUS(env);
3683 }
3684
napi_get_arraybuffer_info(napi_env env,napi_value arraybuffer,void ** data,size_t * byte_length)3685 napi_status napi_get_arraybuffer_info(napi_env env,
3686 napi_value arraybuffer,
3687 void** data,
3688 size_t* byte_length) {
3689 CHECK_ENV(env);
3690 CHECK_ARG(env, arraybuffer);
3691
3692 v8::Local<v8::Value> value = v8impl::V8LocalValueFromJsValue(arraybuffer);
3693 RETURN_STATUS_IF_FALSE(env, value->IsArrayBuffer(), napi_invalid_arg);
3694
3695 v8::ArrayBuffer::Contents contents =
3696 value.As<v8::ArrayBuffer>()->GetContents();
3697
3698 if (data != nullptr) {
3699 *data = contents.Data();
3700 }
3701
3702 if (byte_length != nullptr) {
3703 *byte_length = contents.ByteLength();
3704 }
3705
3706 return napi_clear_last_error(env);
3707 }
3708
napi_is_typedarray(napi_env env,napi_value value,bool * result)3709 napi_status napi_is_typedarray(napi_env env, napi_value value, bool* result) {
3710 CHECK_ENV(env);
3711 CHECK_ARG(env, value);
3712 CHECK_ARG(env, result);
3713
3714 v8::Local<v8::Value> val = v8impl::V8LocalValueFromJsValue(value);
3715 *result = val->IsTypedArray();
3716
3717 return napi_clear_last_error(env);
3718 }
3719
napi_create_typedarray(napi_env env,napi_typedarray_type type,size_t length,napi_value arraybuffer,size_t byte_offset,napi_value * result)3720 napi_status napi_create_typedarray(napi_env env,
3721 napi_typedarray_type type,
3722 size_t length,
3723 napi_value arraybuffer,
3724 size_t byte_offset,
3725 napi_value* result) {
3726 NAPI_PREAMBLE(env);
3727 CHECK_ARG(env, arraybuffer);
3728 CHECK_ARG(env, result);
3729
3730 v8::Local<v8::Value> value = v8impl::V8LocalValueFromJsValue(arraybuffer);
3731 RETURN_STATUS_IF_FALSE(env, value->IsArrayBuffer(), napi_invalid_arg);
3732
3733 v8::Local<v8::ArrayBuffer> buffer = value.As<v8::ArrayBuffer>();
3734 v8::Local<v8::TypedArray> typedArray;
3735
3736 switch (type) {
3737 case napi_int8_array:
3738 CREATE_TYPED_ARRAY(
3739 env, Int8Array, 1, buffer, byte_offset, length, typedArray);
3740 break;
3741 case napi_uint8_array:
3742 CREATE_TYPED_ARRAY(
3743 env, Uint8Array, 1, buffer, byte_offset, length, typedArray);
3744 break;
3745 case napi_uint8_clamped_array:
3746 CREATE_TYPED_ARRAY(
3747 env, Uint8ClampedArray, 1, buffer, byte_offset, length, typedArray);
3748 break;
3749 case napi_int16_array:
3750 CREATE_TYPED_ARRAY(
3751 env, Int16Array, 2, buffer, byte_offset, length, typedArray);
3752 break;
3753 case napi_uint16_array:
3754 CREATE_TYPED_ARRAY(
3755 env, Uint16Array, 2, buffer, byte_offset, length, typedArray);
3756 break;
3757 case napi_int32_array:
3758 CREATE_TYPED_ARRAY(
3759 env, Int32Array, 4, buffer, byte_offset, length, typedArray);
3760 break;
3761 case napi_uint32_array:
3762 CREATE_TYPED_ARRAY(
3763 env, Uint32Array, 4, buffer, byte_offset, length, typedArray);
3764 break;
3765 case napi_float32_array:
3766 CREATE_TYPED_ARRAY(
3767 env, Float32Array, 4, buffer, byte_offset, length, typedArray);
3768 break;
3769 case napi_float64_array:
3770 CREATE_TYPED_ARRAY(
3771 env, Float64Array, 8, buffer, byte_offset, length, typedArray);
3772 break;
3773 case napi_bigint64_array:
3774 CREATE_TYPED_ARRAY(
3775 env, BigInt64Array, 8, buffer, byte_offset, length, typedArray);
3776 break;
3777 case napi_biguint64_array:
3778 CREATE_TYPED_ARRAY(
3779 env, BigUint64Array, 8, buffer, byte_offset, length, typedArray);
3780 break;
3781 default:
3782 return napi_set_last_error(env, napi_invalid_arg);
3783 }
3784
3785 *result = v8impl::JsValueFromV8LocalValue(typedArray);
3786 return GET_RETURN_STATUS(env);
3787 }
3788
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)3789 napi_status napi_get_typedarray_info(napi_env env,
3790 napi_value typedarray,
3791 napi_typedarray_type* type,
3792 size_t* length,
3793 void** data,
3794 napi_value* arraybuffer,
3795 size_t* byte_offset) {
3796 CHECK_ENV(env);
3797 CHECK_ARG(env, typedarray);
3798
3799 v8::Local<v8::Value> value = v8impl::V8LocalValueFromJsValue(typedarray);
3800 RETURN_STATUS_IF_FALSE(env, value->IsTypedArray(), napi_invalid_arg);
3801
3802 v8::Local<v8::TypedArray> array = value.As<v8::TypedArray>();
3803
3804 if (type != nullptr) {
3805 if (value->IsInt8Array()) {
3806 *type = napi_int8_array;
3807 } else if (value->IsUint8Array()) {
3808 *type = napi_uint8_array;
3809 } else if (value->IsUint8ClampedArray()) {
3810 *type = napi_uint8_clamped_array;
3811 } else if (value->IsInt16Array()) {
3812 *type = napi_int16_array;
3813 } else if (value->IsUint16Array()) {
3814 *type = napi_uint16_array;
3815 } else if (value->IsInt32Array()) {
3816 *type = napi_int32_array;
3817 } else if (value->IsUint32Array()) {
3818 *type = napi_uint32_array;
3819 } else if (value->IsFloat32Array()) {
3820 *type = napi_float32_array;
3821 } else if (value->IsFloat64Array()) {
3822 *type = napi_float64_array;
3823 } else if (value->IsBigInt64Array()) {
3824 *type = napi_bigint64_array;
3825 } else if (value->IsBigUint64Array()) {
3826 *type = napi_biguint64_array;
3827 }
3828 }
3829
3830 if (length != nullptr) {
3831 *length = array->Length();
3832 }
3833
3834 v8::Local<v8::ArrayBuffer> buffer = array->Buffer();
3835 if (data != nullptr) {
3836 *data = static_cast<uint8_t*>(buffer->GetContents().Data()) +
3837 array->ByteOffset();
3838 }
3839
3840 if (arraybuffer != nullptr) {
3841 *arraybuffer = v8impl::JsValueFromV8LocalValue(buffer);
3842 }
3843
3844 if (byte_offset != nullptr) {
3845 *byte_offset = array->ByteOffset();
3846 }
3847
3848 return napi_clear_last_error(env);
3849 }
3850
napi_create_dataview(napi_env env,size_t byte_length,napi_value arraybuffer,size_t byte_offset,napi_value * result)3851 napi_status napi_create_dataview(napi_env env,
3852 size_t byte_length,
3853 napi_value arraybuffer,
3854 size_t byte_offset,
3855 napi_value* result) {
3856 NAPI_PREAMBLE(env);
3857 CHECK_ARG(env, arraybuffer);
3858 CHECK_ARG(env, result);
3859
3860 v8::Local<v8::Value> value = v8impl::V8LocalValueFromJsValue(arraybuffer);
3861 RETURN_STATUS_IF_FALSE(env, value->IsArrayBuffer(), napi_invalid_arg);
3862
3863 v8::Local<v8::ArrayBuffer> buffer = value.As<v8::ArrayBuffer>();
3864 if (byte_length + byte_offset > buffer->ByteLength()) {
3865 napi_throw_range_error(
3866 env,
3867 "ERR_NAPI_INVALID_DATAVIEW_ARGS",
3868 "byte_offset + byte_length should be less than or "
3869 "equal to the size in bytes of the array passed in");
3870 return napi_set_last_error(env, napi_pending_exception);
3871 }
3872 v8::Local<v8::DataView> DataView = v8::DataView::New(buffer, byte_offset,
3873 byte_length);
3874
3875 *result = v8impl::JsValueFromV8LocalValue(DataView);
3876 return GET_RETURN_STATUS(env);
3877 }
3878
napi_is_dataview(napi_env env,napi_value value,bool * result)3879 napi_status napi_is_dataview(napi_env env, napi_value value, bool* result) {
3880 CHECK_ENV(env);
3881 CHECK_ARG(env, value);
3882 CHECK_ARG(env, result);
3883
3884 v8::Local<v8::Value> val = v8impl::V8LocalValueFromJsValue(value);
3885 *result = val->IsDataView();
3886
3887 return napi_clear_last_error(env);
3888 }
3889
napi_get_dataview_info(napi_env env,napi_value dataview,size_t * byte_length,void ** data,napi_value * arraybuffer,size_t * byte_offset)3890 napi_status napi_get_dataview_info(napi_env env,
3891 napi_value dataview,
3892 size_t* byte_length,
3893 void** data,
3894 napi_value* arraybuffer,
3895 size_t* byte_offset) {
3896 CHECK_ENV(env);
3897 CHECK_ARG(env, dataview);
3898
3899 v8::Local<v8::Value> value = v8impl::V8LocalValueFromJsValue(dataview);
3900 RETURN_STATUS_IF_FALSE(env, value->IsDataView(), napi_invalid_arg);
3901
3902 v8::Local<v8::DataView> array = value.As<v8::DataView>();
3903
3904 if (byte_length != nullptr) {
3905 *byte_length = array->ByteLength();
3906 }
3907
3908 v8::Local<v8::ArrayBuffer> buffer = array->Buffer();
3909 if (data != nullptr) {
3910 *data = static_cast<uint8_t*>(buffer->GetContents().Data()) +
3911 array->ByteOffset();
3912 }
3913
3914 if (arraybuffer != nullptr) {
3915 *arraybuffer = v8impl::JsValueFromV8LocalValue(buffer);
3916 }
3917
3918 if (byte_offset != nullptr) {
3919 *byte_offset = array->ByteOffset();
3920 }
3921
3922 return napi_clear_last_error(env);
3923 }
3924
napi_get_version(napi_env env,uint32_t * result)3925 napi_status napi_get_version(napi_env env, uint32_t* result) {
3926 CHECK_ENV(env);
3927 CHECK_ARG(env, result);
3928 *result = NAPI_VERSION;
3929 return napi_clear_last_error(env);
3930 }
3931
napi_get_node_version(napi_env env,const napi_node_version ** result)3932 napi_status napi_get_node_version(napi_env env,
3933 const napi_node_version** result) {
3934 CHECK_ENV(env);
3935 CHECK_ARG(env, result);
3936 static const napi_node_version version = {
3937 NODE_MAJOR_VERSION,
3938 NODE_MINOR_VERSION,
3939 NODE_PATCH_VERSION,
3940 NODE_RELEASE
3941 };
3942 *result = &version;
3943 return napi_clear_last_error(env);
3944 }
3945
napi_adjust_external_memory(napi_env env,int64_t change_in_bytes,int64_t * adjusted_value)3946 napi_status napi_adjust_external_memory(napi_env env,
3947 int64_t change_in_bytes,
3948 int64_t* adjusted_value) {
3949 CHECK_ENV(env);
3950 CHECK_ARG(env, adjusted_value);
3951
3952 *adjusted_value = env->isolate->AdjustAmountOfExternalAllocatedMemory(
3953 change_in_bytes);
3954
3955 return napi_clear_last_error(env);
3956 }
3957
3958 namespace {
3959 namespace uvimpl {
3960
ConvertUVErrorCode(int code)3961 static napi_status ConvertUVErrorCode(int code) {
3962 switch (code) {
3963 case 0:
3964 return napi_ok;
3965 case UV_EINVAL:
3966 return napi_invalid_arg;
3967 case UV_ECANCELED:
3968 return napi_cancelled;
3969 }
3970
3971 return napi_generic_failure;
3972 }
3973
3974 // Wrapper around uv_work_t which calls user-provided callbacks.
3975 class Work : public node::AsyncResource, public node::ThreadPoolWork {
3976 private:
Work(napi_env env,v8::Local<v8::Object> async_resource,v8::Local<v8::String> async_resource_name,napi_async_execute_callback execute,napi_async_complete_callback complete=nullptr,void * data=nullptr)3977 explicit Work(napi_env env,
3978 v8::Local<v8::Object> async_resource,
3979 v8::Local<v8::String> async_resource_name,
3980 napi_async_execute_callback execute,
3981 napi_async_complete_callback complete = nullptr,
3982 void* data = nullptr)
3983 : AsyncResource(env->isolate,
3984 async_resource,
3985 *v8::String::Utf8Value(env->isolate, async_resource_name)),
3986 ThreadPoolWork(env->node_env()),
3987 _env(env),
3988 _data(data),
3989 _execute(execute),
3990 _complete(complete) {
3991 }
3992
~Work()3993 virtual ~Work() { }
3994
3995 public:
New(napi_env env,v8::Local<v8::Object> async_resource,v8::Local<v8::String> async_resource_name,napi_async_execute_callback execute,napi_async_complete_callback complete,void * data)3996 static Work* New(napi_env env,
3997 v8::Local<v8::Object> async_resource,
3998 v8::Local<v8::String> async_resource_name,
3999 napi_async_execute_callback execute,
4000 napi_async_complete_callback complete,
4001 void* data) {
4002 return new Work(env, async_resource, async_resource_name,
4003 execute, complete, data);
4004 }
4005
Delete(Work * work)4006 static void Delete(Work* work) {
4007 delete work;
4008 }
4009
DoThreadPoolWork()4010 void DoThreadPoolWork() override {
4011 _execute(_env, _data);
4012 }
4013
AfterThreadPoolWork(int status)4014 void AfterThreadPoolWork(int status) override {
4015 if (_complete == nullptr)
4016 return;
4017
4018 // Establish a handle scope here so that every callback doesn't have to.
4019 // Also it is needed for the exception-handling below.
4020 v8::HandleScope scope(_env->isolate);
4021
4022 CallbackScope callback_scope(this);
4023
4024 _env->CallIntoModule([&](napi_env env) {
4025 _complete(env, ConvertUVErrorCode(status), _data);
4026 }, [](napi_env env, v8::Local<v8::Value> local_err) {
4027 // If there was an unhandled exception in the complete callback,
4028 // report it as a fatal exception. (There is no JavaScript on the
4029 // callstack that can possibly handle it.)
4030 v8impl::trigger_fatal_exception(env, local_err);
4031 });
4032
4033 // Note: Don't access `work` after this point because it was
4034 // likely deleted by the complete callback.
4035 }
4036
4037 private:
4038 napi_env _env;
4039 void* _data;
4040 napi_async_execute_callback _execute;
4041 napi_async_complete_callback _complete;
4042 };
4043
4044 } // end of namespace uvimpl
4045 } // end of anonymous namespace
4046
4047 #define CALL_UV(env, condition) \
4048 do { \
4049 int result = (condition); \
4050 napi_status status = uvimpl::ConvertUVErrorCode(result); \
4051 if (status != napi_ok) { \
4052 return napi_set_last_error(env, status, result); \
4053 } \
4054 } while (0)
4055
napi_create_async_work(napi_env env,napi_value async_resource,napi_value async_resource_name,napi_async_execute_callback execute,napi_async_complete_callback complete,void * data,napi_async_work * result)4056 napi_status napi_create_async_work(napi_env env,
4057 napi_value async_resource,
4058 napi_value async_resource_name,
4059 napi_async_execute_callback execute,
4060 napi_async_complete_callback complete,
4061 void* data,
4062 napi_async_work* result) {
4063 CHECK_ENV(env);
4064 CHECK_ARG(env, execute);
4065 CHECK_ARG(env, result);
4066
4067 v8::Local<v8::Context> context = env->context();
4068
4069 v8::Local<v8::Object> resource;
4070 if (async_resource != nullptr) {
4071 CHECK_TO_OBJECT(env, context, resource, async_resource);
4072 } else {
4073 resource = v8::Object::New(env->isolate);
4074 }
4075
4076 v8::Local<v8::String> resource_name;
4077 CHECK_TO_STRING(env, context, resource_name, async_resource_name);
4078
4079 uvimpl::Work* work =
4080 uvimpl::Work::New(env, resource, resource_name,
4081 execute, complete, data);
4082
4083 *result = reinterpret_cast<napi_async_work>(work);
4084
4085 return napi_clear_last_error(env);
4086 }
4087
napi_delete_async_work(napi_env env,napi_async_work work)4088 napi_status napi_delete_async_work(napi_env env, napi_async_work work) {
4089 CHECK_ENV(env);
4090 CHECK_ARG(env, work);
4091
4092 uvimpl::Work::Delete(reinterpret_cast<uvimpl::Work*>(work));
4093
4094 return napi_clear_last_error(env);
4095 }
4096
napi_get_uv_event_loop(napi_env env,uv_loop_t ** loop)4097 napi_status napi_get_uv_event_loop(napi_env env, uv_loop_t** loop) {
4098 CHECK_ENV(env);
4099 CHECK_ARG(env, loop);
4100 *loop = env->node_env()->event_loop();
4101 return napi_clear_last_error(env);
4102 }
4103
napi_queue_async_work(napi_env env,napi_async_work work)4104 napi_status napi_queue_async_work(napi_env env, napi_async_work work) {
4105 CHECK_ENV(env);
4106 CHECK_ARG(env, work);
4107
4108 napi_status status;
4109 uv_loop_t* event_loop = nullptr;
4110 status = napi_get_uv_event_loop(env, &event_loop);
4111 if (status != napi_ok)
4112 return napi_set_last_error(env, status);
4113
4114 uvimpl::Work* w = reinterpret_cast<uvimpl::Work*>(work);
4115
4116 w->ScheduleWork();
4117
4118 return napi_clear_last_error(env);
4119 }
4120
napi_cancel_async_work(napi_env env,napi_async_work work)4121 napi_status napi_cancel_async_work(napi_env env, napi_async_work work) {
4122 CHECK_ENV(env);
4123 CHECK_ARG(env, work);
4124
4125 uvimpl::Work* w = reinterpret_cast<uvimpl::Work*>(work);
4126
4127 CALL_UV(env, w->CancelWork());
4128
4129 return napi_clear_last_error(env);
4130 }
4131
napi_create_promise(napi_env env,napi_deferred * deferred,napi_value * promise)4132 napi_status napi_create_promise(napi_env env,
4133 napi_deferred* deferred,
4134 napi_value* promise) {
4135 NAPI_PREAMBLE(env);
4136 CHECK_ARG(env, deferred);
4137 CHECK_ARG(env, promise);
4138
4139 auto maybe = v8::Promise::Resolver::New(env->context());
4140 CHECK_MAYBE_EMPTY(env, maybe, napi_generic_failure);
4141
4142 auto v8_resolver = maybe.ToLocalChecked();
4143 auto v8_deferred = new node::Persistent<v8::Value>();
4144 v8_deferred->Reset(env->isolate, v8_resolver);
4145
4146 *deferred = v8impl::JsDeferredFromNodePersistent(v8_deferred);
4147 *promise = v8impl::JsValueFromV8LocalValue(v8_resolver->GetPromise());
4148 return GET_RETURN_STATUS(env);
4149 }
4150
napi_resolve_deferred(napi_env env,napi_deferred deferred,napi_value resolution)4151 napi_status napi_resolve_deferred(napi_env env,
4152 napi_deferred deferred,
4153 napi_value resolution) {
4154 return v8impl::ConcludeDeferred(env, deferred, resolution, true);
4155 }
4156
napi_reject_deferred(napi_env env,napi_deferred deferred,napi_value resolution)4157 napi_status napi_reject_deferred(napi_env env,
4158 napi_deferred deferred,
4159 napi_value resolution) {
4160 return v8impl::ConcludeDeferred(env, deferred, resolution, false);
4161 }
4162
napi_is_promise(napi_env env,napi_value promise,bool * is_promise)4163 napi_status napi_is_promise(napi_env env,
4164 napi_value promise,
4165 bool* is_promise) {
4166 CHECK_ENV(env);
4167 CHECK_ARG(env, promise);
4168 CHECK_ARG(env, is_promise);
4169
4170 *is_promise = v8impl::V8LocalValueFromJsValue(promise)->IsPromise();
4171
4172 return napi_clear_last_error(env);
4173 }
4174
napi_create_date(napi_env env,double time,napi_value * result)4175 napi_status napi_create_date(napi_env env,
4176 double time,
4177 napi_value* result) {
4178 NAPI_PREAMBLE(env);
4179 CHECK_ARG(env, result);
4180
4181 v8::MaybeLocal<v8::Value> maybe_date = v8::Date::New(env->context(), time);
4182 CHECK_MAYBE_EMPTY(env, maybe_date, napi_generic_failure);
4183
4184 *result = v8impl::JsValueFromV8LocalValue(maybe_date.ToLocalChecked());
4185
4186 return GET_RETURN_STATUS(env);
4187 }
4188
napi_is_date(napi_env env,napi_value value,bool * is_date)4189 napi_status napi_is_date(napi_env env,
4190 napi_value value,
4191 bool* is_date) {
4192 CHECK_ENV(env);
4193 CHECK_ARG(env, value);
4194 CHECK_ARG(env, is_date);
4195
4196 *is_date = v8impl::V8LocalValueFromJsValue(value)->IsDate();
4197
4198 return napi_clear_last_error(env);
4199 }
4200
napi_get_date_value(napi_env env,napi_value value,double * result)4201 napi_status napi_get_date_value(napi_env env,
4202 napi_value value,
4203 double* result) {
4204 NAPI_PREAMBLE(env);
4205 CHECK_ARG(env, value);
4206 CHECK_ARG(env, result);
4207
4208 v8::Local<v8::Value> val = v8impl::V8LocalValueFromJsValue(value);
4209 RETURN_STATUS_IF_FALSE(env, val->IsDate(), napi_date_expected);
4210
4211 v8::Local<v8::Date> date = val.As<v8::Date>();
4212 *result = date->ValueOf();
4213
4214 return GET_RETURN_STATUS(env);
4215 }
4216
napi_run_script(napi_env env,napi_value script,napi_value * result)4217 napi_status napi_run_script(napi_env env,
4218 napi_value script,
4219 napi_value* result) {
4220 NAPI_PREAMBLE(env);
4221 CHECK_ARG(env, script);
4222 CHECK_ARG(env, result);
4223
4224 v8::Local<v8::Value> v8_script = v8impl::V8LocalValueFromJsValue(script);
4225
4226 if (!v8_script->IsString()) {
4227 return napi_set_last_error(env, napi_string_expected);
4228 }
4229
4230 v8::Local<v8::Context> context = env->context();
4231
4232 auto maybe_script = v8::Script::Compile(context,
4233 v8::Local<v8::String>::Cast(v8_script));
4234 CHECK_MAYBE_EMPTY(env, maybe_script, napi_generic_failure);
4235
4236 auto script_result =
4237 maybe_script.ToLocalChecked()->Run(context);
4238 CHECK_MAYBE_EMPTY(env, script_result, napi_generic_failure);
4239
4240 *result = v8impl::JsValueFromV8LocalValue(script_result.ToLocalChecked());
4241 return GET_RETURN_STATUS(env);
4242 }
4243
4244 napi_status
napi_create_threadsafe_function(napi_env env,napi_value func,napi_value async_resource,napi_value async_resource_name,size_t max_queue_size,size_t initial_thread_count,void * thread_finalize_data,napi_finalize thread_finalize_cb,void * context,napi_threadsafe_function_call_js call_js_cb,napi_threadsafe_function * result)4245 napi_create_threadsafe_function(napi_env env,
4246 napi_value func,
4247 napi_value async_resource,
4248 napi_value async_resource_name,
4249 size_t max_queue_size,
4250 size_t initial_thread_count,
4251 void* thread_finalize_data,
4252 napi_finalize thread_finalize_cb,
4253 void* context,
4254 napi_threadsafe_function_call_js call_js_cb,
4255 napi_threadsafe_function* result) {
4256 CHECK_ENV(env);
4257 CHECK_ARG(env, async_resource_name);
4258 RETURN_STATUS_IF_FALSE(env, initial_thread_count > 0, napi_invalid_arg);
4259 CHECK_ARG(env, result);
4260
4261 napi_status status = napi_ok;
4262
4263 v8::Local<v8::Function> v8_func;
4264 if (func == nullptr) {
4265 CHECK_ARG(env, call_js_cb);
4266 } else {
4267 CHECK_TO_FUNCTION(env, v8_func, func);
4268 }
4269
4270 v8::Local<v8::Context> v8_context = env->context();
4271
4272 v8::Local<v8::Object> v8_resource;
4273 if (async_resource == nullptr) {
4274 v8_resource = v8::Object::New(env->isolate);
4275 } else {
4276 CHECK_TO_OBJECT(env, v8_context, v8_resource, async_resource);
4277 }
4278
4279 v8::Local<v8::String> v8_name;
4280 CHECK_TO_STRING(env, v8_context, v8_name, async_resource_name);
4281
4282 v8impl::ThreadSafeFunction* ts_fn =
4283 new v8impl::ThreadSafeFunction(v8_func,
4284 v8_resource,
4285 v8_name,
4286 initial_thread_count,
4287 context,
4288 max_queue_size,
4289 env,
4290 thread_finalize_data,
4291 thread_finalize_cb,
4292 call_js_cb);
4293
4294 if (ts_fn == nullptr) {
4295 status = napi_generic_failure;
4296 } else {
4297 // Init deletes ts_fn upon failure.
4298 status = ts_fn->Init();
4299 if (status == napi_ok) {
4300 *result = reinterpret_cast<napi_threadsafe_function>(ts_fn);
4301 }
4302 }
4303
4304 return napi_set_last_error(env, status);
4305 }
4306
4307 napi_status
napi_get_threadsafe_function_context(napi_threadsafe_function func,void ** result)4308 napi_get_threadsafe_function_context(napi_threadsafe_function func,
4309 void** result) {
4310 CHECK(func != nullptr);
4311 CHECK(result != nullptr);
4312
4313 *result = reinterpret_cast<v8impl::ThreadSafeFunction*>(func)->Context();
4314 return napi_ok;
4315 }
4316
4317 napi_status
napi_call_threadsafe_function(napi_threadsafe_function func,void * data,napi_threadsafe_function_call_mode is_blocking)4318 napi_call_threadsafe_function(napi_threadsafe_function func,
4319 void* data,
4320 napi_threadsafe_function_call_mode is_blocking) {
4321 CHECK(func != nullptr);
4322 return reinterpret_cast<v8impl::ThreadSafeFunction*>(func)->Push(data,
4323 is_blocking);
4324 }
4325
4326 napi_status
napi_acquire_threadsafe_function(napi_threadsafe_function func)4327 napi_acquire_threadsafe_function(napi_threadsafe_function func) {
4328 CHECK(func != nullptr);
4329 return reinterpret_cast<v8impl::ThreadSafeFunction*>(func)->Acquire();
4330 }
4331
4332 napi_status
napi_release_threadsafe_function(napi_threadsafe_function func,napi_threadsafe_function_release_mode mode)4333 napi_release_threadsafe_function(napi_threadsafe_function func,
4334 napi_threadsafe_function_release_mode mode) {
4335 CHECK(func != nullptr);
4336 return reinterpret_cast<v8impl::ThreadSafeFunction*>(func)->Release(mode);
4337 }
4338
4339 napi_status
napi_unref_threadsafe_function(napi_env env,napi_threadsafe_function func)4340 napi_unref_threadsafe_function(napi_env env, napi_threadsafe_function func) {
4341 CHECK(func != nullptr);
4342 return reinterpret_cast<v8impl::ThreadSafeFunction*>(func)->Unref();
4343 }
4344
4345 napi_status
napi_ref_threadsafe_function(napi_env env,napi_threadsafe_function func)4346 napi_ref_threadsafe_function(napi_env env, napi_threadsafe_function func) {
4347 CHECK(func != nullptr);
4348 return reinterpret_cast<v8impl::ThreadSafeFunction*>(func)->Ref();
4349 }
4350
napi_add_finalizer(napi_env env,napi_value js_object,void * native_object,napi_finalize finalize_cb,void * finalize_hint,napi_ref * result)4351 napi_status napi_add_finalizer(napi_env env,
4352 napi_value js_object,
4353 void* native_object,
4354 napi_finalize finalize_cb,
4355 void* finalize_hint,
4356 napi_ref* result) {
4357 return v8impl::Wrap<v8impl::anonymous>(env,
4358 js_object,
4359 native_object,
4360 finalize_cb,
4361 finalize_hint,
4362 result);
4363 }
4364
napi_set_instance_data(napi_env env,void * data,napi_finalize finalize_cb,void * finalize_hint)4365 napi_status napi_set_instance_data(napi_env env,
4366 void* data,
4367 napi_finalize finalize_cb,
4368 void* finalize_hint) {
4369 CHECK_ENV(env);
4370
4371 env->instance_data.data = data;
4372 env->instance_data.finalize_cb = finalize_cb;
4373 env->instance_data.hint = finalize_hint;
4374
4375 return napi_clear_last_error(env);
4376 }
4377
napi_get_instance_data(napi_env env,void ** data)4378 napi_status napi_get_instance_data(napi_env env,
4379 void** data) {
4380 CHECK_ENV(env);
4381 CHECK_ARG(env, data);
4382
4383 *data = env->instance_data.data;
4384
4385 return napi_clear_last_error(env);
4386 }
4387
napi_detach_arraybuffer(napi_env env,napi_value arraybuffer)4388 napi_status napi_detach_arraybuffer(napi_env env, napi_value arraybuffer) {
4389 CHECK_ENV(env);
4390 CHECK_ARG(env, arraybuffer);
4391
4392 v8::Local<v8::Value> value = v8impl::V8LocalValueFromJsValue(arraybuffer);
4393 RETURN_STATUS_IF_FALSE(
4394 env, value->IsArrayBuffer(), napi_arraybuffer_expected);
4395
4396 v8::Local<v8::ArrayBuffer> it = value.As<v8::ArrayBuffer>();
4397 RETURN_STATUS_IF_FALSE(
4398 env, it->IsExternal(), napi_detachable_arraybuffer_expected);
4399 RETURN_STATUS_IF_FALSE(
4400 env, it->IsNeuterable(), napi_detachable_arraybuffer_expected);
4401
4402 it->Neuter();
4403
4404 return napi_clear_last_error(env);
4405 }
4406
napi_is_detached_arraybuffer(napi_env env,napi_value arraybuffer,bool * result)4407 napi_status napi_is_detached_arraybuffer(napi_env env,
4408 napi_value arraybuffer,
4409 bool* result) {
4410 CHECK_ENV(env);
4411 CHECK_ARG(env, arraybuffer);
4412 CHECK_ARG(env, result);
4413
4414 v8::Local<v8::Value> value = v8impl::V8LocalValueFromJsValue(arraybuffer);
4415
4416 *result = value->IsArrayBuffer() &&
4417 value.As<v8::ArrayBuffer>()->GetContents().Data() == nullptr;
4418
4419 return napi_clear_last_error(env);
4420 }
4421