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