• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 #include <climits>  // INT_MAX
2 #include <cmath>
3 #include <algorithm>
4 #define NAPI_EXPERIMENTAL
5 #include "env-inl.h"
6 #include "js_native_api_v8.h"
7 #include "js_native_api.h"
8 #include "util-inl.h"
9 
10 #define CHECK_MAYBE_NOTHING(env, maybe, status) \
11   RETURN_STATUS_IF_FALSE((env), !((maybe).IsNothing()), (status))
12 
13 #define CHECK_MAYBE_NOTHING_WITH_PREAMBLE(env, maybe, status) \
14   RETURN_STATUS_IF_FALSE_WITH_PREAMBLE((env), !((maybe).IsNothing()), (status))
15 
16 #define CHECK_TO_NUMBER(env, context, result, src) \
17   CHECK_TO_TYPE((env), Number, (context), (result), (src), napi_number_expected)
18 
19 // n-api defines NAPI_AUTO_LENGHTH as the indicator that a string
20 // is null terminated. For V8 the equivalent is -1. The assert
21 // validates that our cast of NAPI_AUTO_LENGTH results in -1 as
22 // needed by V8.
23 #define CHECK_NEW_FROM_UTF8_LEN(env, result, str, len)                   \
24   do {                                                                   \
25     static_assert(static_cast<int>(NAPI_AUTO_LENGTH) == -1,              \
26                   "Casting NAPI_AUTO_LENGTH to int must result in -1");  \
27     RETURN_STATUS_IF_FALSE((env),                                        \
28         (len == NAPI_AUTO_LENGTH) || len <= INT_MAX,                     \
29         napi_invalid_arg);                                               \
30     RETURN_STATUS_IF_FALSE((env),                                        \
31         (str) != nullptr,                                                \
32         napi_invalid_arg);                                               \
33     auto str_maybe = v8::String::NewFromUtf8(                            \
34         (env)->isolate, (str), v8::NewStringType::kInternalized,         \
35         static_cast<int>(len));                                          \
36     CHECK_MAYBE_EMPTY((env), str_maybe, napi_generic_failure);           \
37     (result) = str_maybe.ToLocalChecked();                               \
38   } while (0)
39 
40 #define CHECK_NEW_FROM_UTF8(env, result, str) \
41   CHECK_NEW_FROM_UTF8_LEN((env), (result), (str), NAPI_AUTO_LENGTH)
42 
43 #define CREATE_TYPED_ARRAY(                                                    \
44     env, type, size_of_element, buffer, byte_offset, length, out)              \
45   do {                                                                         \
46     if ((size_of_element) > 1) {                                               \
47       THROW_RANGE_ERROR_IF_FALSE(                                              \
48           (env), (byte_offset) % (size_of_element) == 0,                       \
49           "ERR_NAPI_INVALID_TYPEDARRAY_ALIGNMENT",                             \
50           "start offset of "#type" should be a multiple of "#size_of_element); \
51     }                                                                          \
52     THROW_RANGE_ERROR_IF_FALSE((env), (length) * (size_of_element) +           \
53         (byte_offset) <= buffer->ByteLength(),                                 \
54         "ERR_NAPI_INVALID_TYPEDARRAY_LENGTH",                                  \
55         "Invalid typed array length");                                         \
56     (out) = v8::type::New((buffer), (byte_offset), (length));                  \
57   } while (0)
58 
59 namespace v8impl {
60 
61 namespace {
62 
63 inline static napi_status
V8NameFromPropertyDescriptor(napi_env env,const napi_property_descriptor * p,v8::Local<v8::Name> * result)64 V8NameFromPropertyDescriptor(napi_env env,
65                              const napi_property_descriptor* p,
66                              v8::Local<v8::Name>* result) {
67   if (p->utf8name != nullptr) {
68     CHECK_NEW_FROM_UTF8(env, *result, p->utf8name);
69   } else {
70     v8::Local<v8::Value> property_value =
71       v8impl::V8LocalValueFromJsValue(p->name);
72 
73     RETURN_STATUS_IF_FALSE(env, property_value->IsName(), napi_name_expected);
74     *result = property_value.As<v8::Name>();
75   }
76 
77   return napi_ok;
78 }
79 
80 // convert from n-api property attributes to v8::PropertyAttribute
V8PropertyAttributesFromDescriptor(const napi_property_descriptor * descriptor)81 inline static v8::PropertyAttribute V8PropertyAttributesFromDescriptor(
82     const napi_property_descriptor* descriptor) {
83   unsigned int attribute_flags = v8::PropertyAttribute::None;
84 
85   // The napi_writable attribute is ignored for accessor descriptors, but
86   // V8 would throw `TypeError`s on assignment with nonexistence of a setter.
87   if ((descriptor->getter == nullptr && descriptor->setter == nullptr) &&
88     (descriptor->attributes & napi_writable) == 0) {
89     attribute_flags |= v8::PropertyAttribute::ReadOnly;
90   }
91 
92   if ((descriptor->attributes & napi_enumerable) == 0) {
93     attribute_flags |= v8::PropertyAttribute::DontEnum;
94   }
95   if ((descriptor->attributes & napi_configurable) == 0) {
96     attribute_flags |= v8::PropertyAttribute::DontDelete;
97   }
98 
99   return static_cast<v8::PropertyAttribute>(attribute_flags);
100 }
101 
102 inline static napi_deferred
JsDeferredFromNodePersistent(v8impl::Persistent<v8::Value> * local)103 JsDeferredFromNodePersistent(v8impl::Persistent<v8::Value>* local) {
104   return reinterpret_cast<napi_deferred>(local);
105 }
106 
107 inline static v8impl::Persistent<v8::Value>*
NodePersistentFromJsDeferred(napi_deferred local)108 NodePersistentFromJsDeferred(napi_deferred local) {
109   return reinterpret_cast<v8impl::Persistent<v8::Value>*>(local);
110 }
111 
112 class HandleScopeWrapper {
113  public:
HandleScopeWrapper(v8::Isolate * isolate)114   explicit HandleScopeWrapper(v8::Isolate* isolate) : scope(isolate) {}
115 
116  private:
117   v8::HandleScope scope;
118 };
119 
120 // In node v0.10 version of v8, there is no EscapableHandleScope and the
121 // node v0.10 port use HandleScope::Close(Local<T> v) to mimic the behavior
122 // of a EscapableHandleScope::Escape(Local<T> v), but it is not the same
123 // semantics. This is an example of where the api abstraction fail to work
124 // across different versions.
125 class EscapableHandleScopeWrapper {
126  public:
EscapableHandleScopeWrapper(v8::Isolate * isolate)127   explicit EscapableHandleScopeWrapper(v8::Isolate* isolate)
128       : scope(isolate), escape_called_(false) {}
escape_called() const129   bool escape_called() const {
130     return escape_called_;
131   }
132   template <typename T>
Escape(v8::Local<T> handle)133   v8::Local<T> Escape(v8::Local<T> handle) {
134     escape_called_ = true;
135     return scope.Escape(handle);
136   }
137 
138  private:
139   v8::EscapableHandleScope scope;
140   bool escape_called_;
141 };
142 
143 inline static napi_handle_scope
JsHandleScopeFromV8HandleScope(HandleScopeWrapper * s)144 JsHandleScopeFromV8HandleScope(HandleScopeWrapper* s) {
145   return reinterpret_cast<napi_handle_scope>(s);
146 }
147 
148 inline static HandleScopeWrapper*
V8HandleScopeFromJsHandleScope(napi_handle_scope s)149 V8HandleScopeFromJsHandleScope(napi_handle_scope s) {
150   return reinterpret_cast<HandleScopeWrapper*>(s);
151 }
152 
153 inline static napi_escapable_handle_scope
JsEscapableHandleScopeFromV8EscapableHandleScope(EscapableHandleScopeWrapper * s)154 JsEscapableHandleScopeFromV8EscapableHandleScope(
155     EscapableHandleScopeWrapper* s) {
156   return reinterpret_cast<napi_escapable_handle_scope>(s);
157 }
158 
159 inline static EscapableHandleScopeWrapper*
V8EscapableHandleScopeFromJsEscapableHandleScope(napi_escapable_handle_scope s)160 V8EscapableHandleScopeFromJsEscapableHandleScope(
161     napi_escapable_handle_scope s) {
162   return reinterpret_cast<EscapableHandleScopeWrapper*>(s);
163 }
164 
ConcludeDeferred(napi_env env,napi_deferred deferred,napi_value result,bool is_resolved)165 inline static napi_status ConcludeDeferred(napi_env env,
166                                            napi_deferred deferred,
167                                            napi_value result,
168                                            bool is_resolved) {
169   NAPI_PREAMBLE(env);
170   CHECK_ARG(env, result);
171 
172   v8::Local<v8::Context> context = env->context();
173   v8impl::Persistent<v8::Value>* deferred_ref =
174       NodePersistentFromJsDeferred(deferred);
175   v8::Local<v8::Value> v8_deferred =
176       v8::Local<v8::Value>::New(env->isolate, *deferred_ref);
177 
178   auto v8_resolver = v8::Local<v8::Promise::Resolver>::Cast(v8_deferred);
179 
180   v8::Maybe<bool> success = is_resolved ?
181       v8_resolver->Resolve(context, v8impl::V8LocalValueFromJsValue(result)) :
182       v8_resolver->Reject(context, v8impl::V8LocalValueFromJsValue(result));
183 
184   delete deferred_ref;
185 
186   RETURN_STATUS_IF_FALSE(env, success.FromMaybe(false), napi_generic_failure);
187 
188   return GET_RETURN_STATUS(env);
189 }
190 
191 enum UnwrapAction {
192   KeepWrap,
193   RemoveWrap
194 };
195 
Unwrap(napi_env env,napi_value js_object,void ** result,UnwrapAction action)196 inline static napi_status Unwrap(napi_env env,
197                                  napi_value js_object,
198                                  void** result,
199                                  UnwrapAction action) {
200   NAPI_PREAMBLE(env);
201   CHECK_ARG(env, js_object);
202   if (action == KeepWrap) {
203     CHECK_ARG(env, result);
204   }
205 
206   v8::Local<v8::Context> context = env->context();
207 
208   v8::Local<v8::Value> value = v8impl::V8LocalValueFromJsValue(js_object);
209   RETURN_STATUS_IF_FALSE(env, value->IsObject(), napi_invalid_arg);
210   v8::Local<v8::Object> obj = value.As<v8::Object>();
211 
212   auto val = obj->GetPrivate(context, NAPI_PRIVATE_KEY(context, wrapper))
213       .ToLocalChecked();
214   RETURN_STATUS_IF_FALSE(env, val->IsExternal(), napi_invalid_arg);
215   Reference* reference =
216       static_cast<v8impl::Reference*>(val.As<v8::External>()->Value());
217 
218   if (result) {
219     *result = reference->Data();
220   }
221 
222   if (action == RemoveWrap) {
223     CHECK(obj->DeletePrivate(context, NAPI_PRIVATE_KEY(context, wrapper))
224         .FromJust());
225     Reference::Delete(reference);
226   }
227 
228   return GET_RETURN_STATUS(env);
229 }
230 
231 //=== Function napi_callback wrapper =================================
232 
233 // Use this data structure to associate callback data with each N-API function
234 // exposed to JavaScript. The structure is stored in a v8::External which gets
235 // passed into our callback wrapper. This reduces the performance impact of
236 // calling through N-API.
237 // Ref: benchmark/misc/function_call
238 // Discussion (incl. perf. data): https://github.com/nodejs/node/pull/21072
239 class CallbackBundle {
240  public:
241   // Creates an object to be made available to the static function callback
242   // wrapper, used to retrieve the native callback function and data pointer.
243   static inline v8::Local<v8::Value>
New(napi_env env,napi_callback cb,void * data)244   New(napi_env env, napi_callback cb, void* data) {
245     CallbackBundle* bundle = new CallbackBundle();
246     bundle->cb = cb;
247     bundle->cb_data = data;
248     bundle->env = env;
249 
250     v8::Local<v8::Value> cbdata = v8::External::New(env->isolate, bundle);
251     Reference::New(env, cbdata, 0, true, Delete, bundle, nullptr);
252     return cbdata;
253   }
254   napi_env       env;      // Necessary to invoke C++ NAPI callback
255   void*          cb_data;  // The user provided callback data
256   napi_callback  cb;
257  private:
Delete(napi_env env,void * data,void * hint)258   static void Delete(napi_env env, void* data, void* hint) {
259     CallbackBundle* bundle = static_cast<CallbackBundle*>(data);
260     delete bundle;
261   }
262 };
263 
264 // Base class extended by classes that wrap V8 function and property callback
265 // info.
266 class CallbackWrapper {
267  public:
CallbackWrapper(napi_value this_arg,size_t args_length,void * data)268   inline CallbackWrapper(napi_value this_arg, size_t args_length, void* data)
269       : _this(this_arg), _args_length(args_length), _data(data) {}
270 
271   virtual napi_value GetNewTarget() = 0;
272   virtual void Args(napi_value* buffer, size_t bufferlength) = 0;
273   virtual void SetReturnValue(napi_value value) = 0;
274 
This()275   napi_value This() { return _this; }
276 
ArgsLength()277   size_t ArgsLength() { return _args_length; }
278 
Data()279   void* Data() { return _data; }
280 
281  protected:
282   const napi_value _this;
283   const size_t _args_length;
284   void* _data;
285 };
286 
287 class CallbackWrapperBase : public CallbackWrapper {
288  public:
CallbackWrapperBase(const v8::FunctionCallbackInfo<v8::Value> & cbinfo,const size_t args_length)289   inline CallbackWrapperBase(const v8::FunctionCallbackInfo<v8::Value>& cbinfo,
290                              const size_t args_length)
291       : CallbackWrapper(JsValueFromV8LocalValue(cbinfo.This()),
292                         args_length,
293                         nullptr),
294         _cbinfo(cbinfo) {
295     _bundle = reinterpret_cast<CallbackBundle*>(
296         v8::Local<v8::External>::Cast(cbinfo.Data())->Value());
297     _data = _bundle->cb_data;
298   }
299 
300  protected:
InvokeCallback()301   inline void InvokeCallback() {
302     napi_callback_info cbinfo_wrapper = reinterpret_cast<napi_callback_info>(
303         static_cast<CallbackWrapper*>(this));
304 
305     // All other pointers we need are stored in `_bundle`
306     napi_env env = _bundle->env;
307     napi_callback cb = _bundle->cb;
308 
309     napi_value result = nullptr;
310     bool exceptionOccurred = false;
311     env->CallIntoModule([&](napi_env env) {
312       result = cb(env, cbinfo_wrapper);
313     }, [&](napi_env env, v8::Local<v8::Value> value) {
314       exceptionOccurred = true;
315       env->isolate->ThrowException(value);
316     });
317 
318     if (!exceptionOccurred && (result != nullptr)) {
319       this->SetReturnValue(result);
320     }
321   }
322 
323   const v8::FunctionCallbackInfo<v8::Value>& _cbinfo;
324   CallbackBundle* _bundle;
325 };
326 
327 class FunctionCallbackWrapper
328     : public CallbackWrapperBase {
329  public:
Invoke(const v8::FunctionCallbackInfo<v8::Value> & info)330   static void Invoke(const v8::FunctionCallbackInfo<v8::Value>& info) {
331     FunctionCallbackWrapper cbwrapper(info);
332     cbwrapper.InvokeCallback();
333   }
334 
NewFunction(napi_env env,napi_callback cb,void * cb_data,v8::Local<v8::Function> * result)335   static inline napi_status NewFunction(napi_env env,
336                                         napi_callback cb,
337                                         void* cb_data,
338                                         v8::Local<v8::Function>* result) {
339     v8::Local<v8::Value> cbdata = v8impl::CallbackBundle::New(env, cb, cb_data);
340     RETURN_STATUS_IF_FALSE(env, !cbdata.IsEmpty(), napi_generic_failure);
341 
342     v8::MaybeLocal<v8::Function> maybe_function =
343         v8::Function::New(env->context(), Invoke, cbdata);
344     CHECK_MAYBE_EMPTY(env, maybe_function, napi_generic_failure);
345 
346     *result = maybe_function.ToLocalChecked();
347     return napi_clear_last_error(env);
348   }
349 
NewTemplate(napi_env env,napi_callback cb,void * cb_data,v8::Local<v8::FunctionTemplate> * result,v8::Local<v8::Signature> sig=v8::Local<v8::Signature> ())350   static inline napi_status NewTemplate(napi_env env,
351                     napi_callback cb,
352                     void* cb_data,
353                     v8::Local<v8::FunctionTemplate>* result,
354                     v8::Local<v8::Signature> sig = v8::Local<v8::Signature>()) {
355     v8::Local<v8::Value> cbdata = v8impl::CallbackBundle::New(env, cb, cb_data);
356     RETURN_STATUS_IF_FALSE(env, !cbdata.IsEmpty(), napi_generic_failure);
357 
358     *result = v8::FunctionTemplate::New(env->isolate, Invoke, cbdata, sig);
359     return napi_clear_last_error(env);
360   }
361 
FunctionCallbackWrapper(const v8::FunctionCallbackInfo<v8::Value> & cbinfo)362   explicit FunctionCallbackWrapper(
363       const v8::FunctionCallbackInfo<v8::Value>& cbinfo)
364       : CallbackWrapperBase(cbinfo, cbinfo.Length()) {}
365 
GetNewTarget()366   napi_value GetNewTarget() override {
367     if (_cbinfo.IsConstructCall()) {
368       return v8impl::JsValueFromV8LocalValue(_cbinfo.NewTarget());
369     } else {
370       return nullptr;
371     }
372   }
373 
374   /*virtual*/
Args(napi_value * buffer,size_t buffer_length)375   void Args(napi_value* buffer, size_t buffer_length) override {
376     size_t i = 0;
377     size_t min = std::min(buffer_length, _args_length);
378 
379     for (; i < min; i += 1) {
380       buffer[i] = v8impl::JsValueFromV8LocalValue(_cbinfo[i]);
381     }
382 
383     if (i < buffer_length) {
384       napi_value undefined =
385           v8impl::JsValueFromV8LocalValue(v8::Undefined(_cbinfo.GetIsolate()));
386       for (; i < buffer_length; i += 1) {
387         buffer[i] = undefined;
388       }
389     }
390   }
391 
392   /*virtual*/
SetReturnValue(napi_value value)393   void SetReturnValue(napi_value value) override {
394     v8::Local<v8::Value> val = v8impl::V8LocalValueFromJsValue(value);
395     _cbinfo.GetReturnValue().Set(val);
396   }
397 };
398 
399 enum WrapType {
400   retrievable,
401   anonymous
402 };
403 
404 template <WrapType wrap_type>
Wrap(napi_env env,napi_value js_object,void * native_object,napi_finalize finalize_cb,void * finalize_hint,napi_ref * result)405 inline napi_status Wrap(napi_env env,
406                         napi_value js_object,
407                         void* native_object,
408                         napi_finalize finalize_cb,
409                         void* finalize_hint,
410                         napi_ref* result) {
411   NAPI_PREAMBLE(env);
412   CHECK_ARG(env, js_object);
413 
414   v8::Local<v8::Context> context = env->context();
415 
416   v8::Local<v8::Value> value = v8impl::V8LocalValueFromJsValue(js_object);
417   RETURN_STATUS_IF_FALSE(env, value->IsObject(), napi_invalid_arg);
418   v8::Local<v8::Object> obj = value.As<v8::Object>();
419 
420   if (wrap_type == retrievable) {
421     // If we've already wrapped this object, we error out.
422     RETURN_STATUS_IF_FALSE(env,
423         !obj->HasPrivate(context, NAPI_PRIVATE_KEY(context, wrapper))
424             .FromJust(),
425         napi_invalid_arg);
426   } else if (wrap_type == anonymous) {
427     // If no finalize callback is provided, we error out.
428     CHECK_ARG(env, finalize_cb);
429   }
430 
431   v8impl::Reference* reference = nullptr;
432   if (result != nullptr) {
433     // The returned reference should be deleted via napi_delete_reference()
434     // ONLY in response to the finalize callback invocation. (If it is deleted
435     // before then, then the finalize callback will never be invoked.)
436     // Therefore a finalize callback is required when returning a reference.
437     CHECK_ARG(env, finalize_cb);
438     reference = v8impl::Reference::New(
439         env, obj, 0, false, finalize_cb, native_object, finalize_hint);
440     *result = reinterpret_cast<napi_ref>(reference);
441   } else {
442     // Create a self-deleting reference.
443     reference = v8impl::Reference::New(env, obj, 0, true, finalize_cb,
444         native_object, finalize_cb == nullptr ? nullptr : finalize_hint);
445   }
446 
447   if (wrap_type == retrievable) {
448     CHECK(obj->SetPrivate(context, NAPI_PRIVATE_KEY(context, wrapper),
449           v8::External::New(env->isolate, reference)).FromJust());
450   }
451 
452   return GET_RETURN_STATUS(env);
453 }
454 
455 }  // end of anonymous namespace
456 
457 // Wrapper around v8impl::Persistent that implements reference counting.
RefBase(napi_env env,uint32_t initial_refcount,bool delete_self,napi_finalize finalize_callback,void * finalize_data,void * finalize_hint)458 RefBase::RefBase(napi_env env,
459                  uint32_t initial_refcount,
460                  bool delete_self,
461                  napi_finalize finalize_callback,
462                  void* finalize_data,
463                  void* finalize_hint)
464     : Finalizer(env, finalize_callback, finalize_data, finalize_hint),
465       _refcount(initial_refcount),
466       _delete_self(delete_self) {
467   Link(finalize_callback == nullptr ? &env->reflist : &env->finalizing_reflist);
468 }
469 
New(napi_env env,uint32_t initial_refcount,bool delete_self,napi_finalize finalize_callback,void * finalize_data,void * finalize_hint)470 RefBase* RefBase::New(napi_env env,
471                       uint32_t initial_refcount,
472                       bool delete_self,
473                       napi_finalize finalize_callback,
474                       void* finalize_data,
475                       void* finalize_hint) {
476   return new RefBase(env,
477                      initial_refcount,
478                      delete_self,
479                      finalize_callback,
480                      finalize_data,
481                      finalize_hint);
482 }
483 
~RefBase()484 RefBase::~RefBase() {
485   Unlink();
486 }
487 
Data()488 void* RefBase::Data() {
489   return _finalize_data;
490 }
491 
492 // Delete is called in 2 ways. Either from the finalizer or
493 // from one of Unwrap or napi_delete_reference.
494 //
495 // When it is called from Unwrap or napi_delete_reference we only
496 // want to do the delete if the finalizer has already run or
497 // cannot have been queued to run (ie the reference count is > 0),
498 // otherwise we may crash when the finalizer does run.
499 // If the finalizer may have been queued and has not already run
500 // delay the delete until the finalizer runs by not doing the delete
501 // and setting _delete_self to true so that the finalizer will
502 // delete it when it runs.
503 //
504 // The second way this is called is from
505 // the finalizer and _delete_self is set. In this case we
506 // know we need to do the deletion so just do it.
Delete(RefBase * reference)507 void RefBase::Delete(RefBase* reference) {
508   if ((reference->RefCount() != 0) || (reference->_delete_self) ||
509       (reference->_finalize_ran)) {
510     delete reference;
511   } else {
512     // defer until finalizer runs as
513     // it may already be queued
514     reference->_delete_self = true;
515   }
516 }
517 
Ref()518 uint32_t RefBase::Ref() {
519   return ++_refcount;
520 }
521 
Unref()522 uint32_t RefBase::Unref() {
523   if (_refcount == 0) {
524     return 0;
525   }
526   return --_refcount;
527 }
528 
RefCount()529 uint32_t RefBase::RefCount() {
530   return _refcount;
531 }
532 
Finalize(bool is_env_teardown)533 void RefBase::Finalize(bool is_env_teardown) {
534   // In addition to being called during environment teardown, this method is
535   // also the entry point for the garbage collector. During environment
536   // teardown we have to remove the garbage collector's reference to this
537   // method so that, if, as part of the user's callback, JS gets executed,
538   // resulting in a garbage collection pass, this method is not re-entered as
539   // part of that pass, because that'll cause a double free (as seen in
540   // https://github.com/nodejs/node/issues/37236).
541   //
542   // Since this class does not have access to the V8 persistent reference,
543   // this method is overridden in the `Reference` class below. Therein the
544   // weak callback is removed, ensuring that the garbage collector does not
545   // re-enter this method, and the method chains up to continue the process of
546   // environment-teardown-induced finalization.
547 
548   // During environment teardown we have to convert a strong reference to
549   // a weak reference to force the deferring behavior if the user's finalizer
550   // happens to delete this reference so that the code in this function that
551   // follows the call to the user's finalizer may safely access variables from
552   // this instance.
553   if (is_env_teardown && RefCount() > 0) _refcount = 0;
554 
555   if (_finalize_callback != nullptr) {
556     // This ensures that we never call the finalizer twice.
557     napi_finalize fini = _finalize_callback;
558     _finalize_callback = nullptr;
559     _env->CallFinalizer(fini, _finalize_data, _finalize_hint);
560   }
561 
562   // this is safe because if a request to delete the reference
563   // is made in the finalize_callback it will defer deletion
564   // to this block and set _delete_self to true
565   if (_delete_self || is_env_teardown) {
566     Delete(this);
567   } else {
568     _finalize_ran = true;
569   }
570 }
571 
572 template <typename... Args>
Reference(napi_env env,v8::Local<v8::Value> value,Args &&...args)573 Reference::Reference(napi_env env, v8::Local<v8::Value> value, Args&&... args)
574     : RefBase(env, std::forward<Args>(args)...),
575       _persistent(env->isolate, value),
576       _secondPassParameter(new SecondPassCallParameterRef(this)),
577       _secondPassScheduled(false) {
578   if (RefCount() == 0) {
579     SetWeak();
580   }
581 }
582 
New(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)583 Reference* Reference::New(napi_env env,
584                           v8::Local<v8::Value> value,
585                           uint32_t initial_refcount,
586                           bool delete_self,
587                           napi_finalize finalize_callback,
588                           void* finalize_data,
589                           void* finalize_hint) {
590   return new Reference(env,
591                        value,
592                        initial_refcount,
593                        delete_self,
594                        finalize_callback,
595                        finalize_data,
596                        finalize_hint);
597 }
598 
~Reference()599 Reference::~Reference() {
600   // If the second pass callback is scheduled, it will delete the
601   // parameter passed to it, otherwise it will never be scheduled
602   // and we need to delete it here.
603   if (!_secondPassScheduled) {
604     delete _secondPassParameter;
605   }
606 }
607 
Ref()608 uint32_t Reference::Ref() {
609   uint32_t refcount = RefBase::Ref();
610   if (refcount == 1) {
611     ClearWeak();
612   }
613   return refcount;
614 }
615 
Unref()616 uint32_t Reference::Unref() {
617   uint32_t old_refcount = RefCount();
618   uint32_t refcount = RefBase::Unref();
619   if (old_refcount == 1 && refcount == 0) {
620     SetWeak();
621   }
622   return refcount;
623 }
624 
Get()625 v8::Local<v8::Value> Reference::Get() {
626   if (_persistent.IsEmpty()) {
627     return v8::Local<v8::Value>();
628   } else {
629     return v8::Local<v8::Value>::New(_env->isolate, _persistent);
630   }
631 }
632 
Finalize(bool is_env_teardown)633 void Reference::Finalize(bool is_env_teardown) {
634   // During env teardown, `~napi_env()` alone is responsible for finalizing.
635   // Thus, we don't want any stray gc passes to trigger a second call to
636   // `RefBase::Finalize()`. ClearWeak will ensure that even if the
637   // gc is in progress no Finalization will be run for this Reference
638   // by the gc.
639   if (is_env_teardown) {
640     ClearWeak();
641   }
642 
643   // Chain up to perform the rest of the finalization.
644   RefBase::Finalize(is_env_teardown);
645 }
646 
647 // ClearWeak is marking the Reference so that the gc should not
648 // collect it, but it is possible that a second pass callback
649 // may have been scheduled already if we are in shutdown. We clear
650 // the secondPassParameter so that even if it has been
651 // scheduled no Finalization will be run.
ClearWeak()652 void Reference::ClearWeak() {
653   if (!_persistent.IsEmpty()) {
654     _persistent.ClearWeak();
655   }
656   if (_secondPassParameter != nullptr) {
657     *_secondPassParameter = nullptr;
658   }
659 }
660 
661 // Mark the reference as weak and eligible for collection
662 // by the gc.
SetWeak()663 void Reference::SetWeak() {
664   if (_secondPassParameter == nullptr) {
665     // This means that the Reference has already been processed
666     // by the second pass callback, so its already been Finalized, do
667     // nothing
668     return;
669   }
670   _persistent.SetWeak(
671       _secondPassParameter, FinalizeCallback, v8::WeakCallbackType::kParameter);
672   *_secondPassParameter = this;
673 }
674 
675 // The N-API finalizer callback may make calls into the engine. V8's heap is
676 // not in a consistent state during the weak callback, and therefore it does
677 // not support calls back into it. However, it provides a mechanism for adding
678 // a finalizer which may make calls back into the engine by allowing us to
679 // attach such a second-pass finalizer from the first pass finalizer. Thus,
680 // we do that here to ensure that the N-API finalizer callback is free to call
681 // into the engine.
FinalizeCallback(const v8::WeakCallbackInfo<SecondPassCallParameterRef> & data)682 void Reference::FinalizeCallback(
683     const v8::WeakCallbackInfo<SecondPassCallParameterRef>& data) {
684   SecondPassCallParameterRef* parameter = data.GetParameter();
685   Reference* reference = *parameter;
686   if (reference == nullptr) {
687     return;
688   }
689 
690   // The reference must be reset during the first pass.
691   reference->_persistent.Reset();
692   // Mark the parameter not delete-able until the second pass callback is
693   // invoked.
694   reference->_secondPassScheduled = true;
695 
696   data.SetSecondPassCallback(SecondPassCallback);
697 }
698 
699 // Second pass callbacks are scheduled with platform tasks. At env teardown,
700 // the tasks may have already be scheduled and we are unable to cancel the
701 // second pass callback task. We have to make sure that parameter is kept
702 // alive until the second pass callback is been invoked. In order to do
703 // this and still allow our code to Finalize/delete the Reference during
704 // shutdown we have to use a separately allocated parameter instead
705 // of a parameter within the Reference object itself. This is what
706 // is stored in _secondPassParameter and it is allocated in the
707 // constructor for the Reference.
SecondPassCallback(const v8::WeakCallbackInfo<SecondPassCallParameterRef> & data)708 void Reference::SecondPassCallback(
709     const v8::WeakCallbackInfo<SecondPassCallParameterRef>& data) {
710   SecondPassCallParameterRef* parameter = data.GetParameter();
711   Reference* reference = *parameter;
712   delete parameter;
713   if (reference == nullptr) {
714     // the reference itself has already been deleted so nothing to do
715     return;
716   }
717   reference->_secondPassParameter = nullptr;
718   reference->Finalize();
719 }
720 
721 }  // end of namespace v8impl
722 
723 // Warning: Keep in-sync with napi_status enum
724 static
725 const char* error_messages[] = {nullptr,
726                                 "Invalid argument",
727                                 "An object was expected",
728                                 "A string was expected",
729                                 "A string or symbol was expected",
730                                 "A function was expected",
731                                 "A number was expected",
732                                 "A boolean was expected",
733                                 "An array was expected",
734                                 "Unknown failure",
735                                 "An exception is pending",
736                                 "The async work item was cancelled",
737                                 "napi_escape_handle already called on scope",
738                                 "Invalid handle scope usage",
739                                 "Invalid callback scope usage",
740                                 "Thread-safe function queue is full",
741                                 "Thread-safe function handle is closing",
742                                 "A bigint was expected",
743                                 "A date was expected",
744                                 "An arraybuffer was expected",
745                                 "A detachable arraybuffer was expected",
746                                 "Main thread would deadlock",
747 };
748 
napi_get_last_error_info(napi_env env,const napi_extended_error_info ** result)749 napi_status napi_get_last_error_info(napi_env env,
750                                      const napi_extended_error_info** result) {
751   CHECK_ENV(env);
752   CHECK_ARG(env, result);
753 
754   // The value of the constant below must be updated to reference the last
755   // message in the `napi_status` enum each time a new error message is added.
756   // We don't have a napi_status_last as this would result in an ABI
757   // change each time a message was added.
758   const int last_status = napi_would_deadlock;
759 
760   static_assert(
761       NAPI_ARRAYSIZE(error_messages) == last_status + 1,
762       "Count of error messages must match count of error values");
763   CHECK_LE(env->last_error.error_code, last_status);
764 
765   // Wait until someone requests the last error information to fetch the error
766   // message string
767   env->last_error.error_message =
768       error_messages[env->last_error.error_code];
769 
770   *result = &(env->last_error);
771   return napi_ok;
772 }
773 
napi_create_function(napi_env env,const char * utf8name,size_t length,napi_callback cb,void * callback_data,napi_value * result)774 napi_status napi_create_function(napi_env env,
775                                  const char* utf8name,
776                                  size_t length,
777                                  napi_callback cb,
778                                  void* callback_data,
779                                  napi_value* result) {
780   NAPI_PREAMBLE(env);
781   CHECK_ARG(env, result);
782   CHECK_ARG(env, cb);
783 
784   v8::Local<v8::Function> return_value;
785   v8::EscapableHandleScope scope(env->isolate);
786   v8::Local<v8::Function> fn;
787   STATUS_CALL(v8impl::FunctionCallbackWrapper::NewFunction(
788       env, cb, callback_data, &fn));
789   return_value = scope.Escape(fn);
790 
791   if (utf8name != nullptr) {
792     v8::Local<v8::String> name_string;
793     CHECK_NEW_FROM_UTF8_LEN(env, name_string, utf8name, length);
794     return_value->SetName(name_string);
795   }
796 
797   *result = v8impl::JsValueFromV8LocalValue(return_value);
798 
799   return GET_RETURN_STATUS(env);
800 }
801 
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)802 napi_status napi_define_class(napi_env env,
803                               const char* utf8name,
804                               size_t length,
805                               napi_callback constructor,
806                               void* callback_data,
807                               size_t property_count,
808                               const napi_property_descriptor* properties,
809                               napi_value* result) {
810   NAPI_PREAMBLE(env);
811   CHECK_ARG(env, result);
812   CHECK_ARG(env, constructor);
813 
814   if (property_count > 0) {
815     CHECK_ARG(env, properties);
816   }
817 
818   v8::Isolate* isolate = env->isolate;
819 
820   v8::EscapableHandleScope scope(isolate);
821   v8::Local<v8::FunctionTemplate> tpl;
822   STATUS_CALL(v8impl::FunctionCallbackWrapper::NewTemplate(
823       env, constructor, callback_data, &tpl));
824 
825   v8::Local<v8::String> name_string;
826   CHECK_NEW_FROM_UTF8_LEN(env, name_string, utf8name, length);
827   tpl->SetClassName(name_string);
828 
829   size_t static_property_count = 0;
830   for (size_t i = 0; i < property_count; i++) {
831     const napi_property_descriptor* p = properties + i;
832 
833     if ((p->attributes & napi_static) != 0) {
834       // Static properties are handled separately below.
835       static_property_count++;
836       continue;
837     }
838 
839     v8::Local<v8::Name> property_name;
840     STATUS_CALL(v8impl::V8NameFromPropertyDescriptor(env, p, &property_name));
841 
842     v8::PropertyAttribute attributes =
843         v8impl::V8PropertyAttributesFromDescriptor(p);
844 
845     // This code is similar to that in napi_define_properties(); the
846     // difference is it applies to a template instead of an object,
847     // and preferred PropertyAttribute for lack of PropertyDescriptor
848     // support on ObjectTemplate.
849     if (p->getter != nullptr || p->setter != nullptr) {
850       v8::Local<v8::FunctionTemplate> getter_tpl;
851       v8::Local<v8::FunctionTemplate> setter_tpl;
852       if (p->getter != nullptr) {
853         STATUS_CALL(v8impl::FunctionCallbackWrapper::NewTemplate(
854             env, p->getter, p->data, &getter_tpl));
855       }
856       if (p->setter != nullptr) {
857         STATUS_CALL(v8impl::FunctionCallbackWrapper::NewTemplate(
858             env, p->setter, p->data, &setter_tpl));
859       }
860 
861       tpl->PrototypeTemplate()->SetAccessorProperty(
862         property_name,
863         getter_tpl,
864         setter_tpl,
865         attributes,
866         v8::AccessControl::DEFAULT);
867     } else if (p->method != nullptr) {
868       v8::Local<v8::FunctionTemplate> t;
869       STATUS_CALL(v8impl::FunctionCallbackWrapper::NewTemplate(
870           env, p->method, p->data, &t, v8::Signature::New(isolate, tpl)));
871 
872       tpl->PrototypeTemplate()->Set(property_name, t, attributes);
873     } else {
874       v8::Local<v8::Value> value = v8impl::V8LocalValueFromJsValue(p->value);
875       tpl->PrototypeTemplate()->Set(property_name, value, attributes);
876     }
877   }
878 
879   v8::Local<v8::Context> context = env->context();
880   *result = v8impl::JsValueFromV8LocalValue(
881       scope.Escape(tpl->GetFunction(context).ToLocalChecked()));
882 
883   if (static_property_count > 0) {
884     std::vector<napi_property_descriptor> static_descriptors;
885     static_descriptors.reserve(static_property_count);
886 
887     for (size_t i = 0; i < property_count; i++) {
888       const napi_property_descriptor* p = properties + i;
889       if ((p->attributes & napi_static) != 0) {
890         static_descriptors.push_back(*p);
891       }
892     }
893 
894     STATUS_CALL(napi_define_properties(env,
895                                        *result,
896                                        static_descriptors.size(),
897                                        static_descriptors.data()));
898   }
899 
900   return GET_RETURN_STATUS(env);
901 }
902 
napi_get_property_names(napi_env env,napi_value object,napi_value * result)903 napi_status napi_get_property_names(napi_env env,
904                                     napi_value object,
905                                     napi_value* result) {
906   return napi_get_all_property_names(
907       env,
908       object,
909       napi_key_include_prototypes,
910       static_cast<napi_key_filter>(napi_key_enumerable |
911                                    napi_key_skip_symbols),
912       napi_key_numbers_to_strings,
913       result);
914 }
915 
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)916 napi_status napi_get_all_property_names(napi_env env,
917                                         napi_value object,
918                                         napi_key_collection_mode key_mode,
919                                         napi_key_filter key_filter,
920                                         napi_key_conversion key_conversion,
921                                         napi_value* result) {
922   NAPI_PREAMBLE(env);
923   CHECK_ARG(env, result);
924 
925   v8::Local<v8::Context> context = env->context();
926   v8::Local<v8::Object> obj;
927   CHECK_TO_OBJECT(env, context, obj, object);
928 
929   v8::PropertyFilter filter = v8::PropertyFilter::ALL_PROPERTIES;
930   if (key_filter & napi_key_writable) {
931     filter =
932         static_cast<v8::PropertyFilter>(filter |
933                                         v8::PropertyFilter::ONLY_WRITABLE);
934   }
935   if (key_filter & napi_key_enumerable) {
936     filter =
937         static_cast<v8::PropertyFilter>(filter |
938                                         v8::PropertyFilter::ONLY_ENUMERABLE);
939   }
940   if (key_filter & napi_key_configurable) {
941     filter =
942         static_cast<v8::PropertyFilter>(filter |
943                                         v8::PropertyFilter::ONLY_WRITABLE);
944   }
945   if (key_filter & napi_key_skip_strings) {
946     filter =
947         static_cast<v8::PropertyFilter>(filter |
948                                         v8::PropertyFilter::SKIP_STRINGS);
949   }
950   if (key_filter & napi_key_skip_symbols) {
951     filter =
952         static_cast<v8::PropertyFilter>(filter |
953                                         v8::PropertyFilter::SKIP_SYMBOLS);
954   }
955   v8::KeyCollectionMode collection_mode;
956   v8::KeyConversionMode conversion_mode;
957 
958   switch (key_mode) {
959     case napi_key_include_prototypes:
960       collection_mode = v8::KeyCollectionMode::kIncludePrototypes;
961       break;
962     case napi_key_own_only:
963       collection_mode = v8::KeyCollectionMode::kOwnOnly;
964       break;
965     default:
966       return napi_set_last_error(env, napi_invalid_arg);
967   }
968 
969   switch (key_conversion) {
970     case napi_key_keep_numbers:
971       conversion_mode = v8::KeyConversionMode::kKeepNumbers;
972       break;
973     case napi_key_numbers_to_strings:
974       conversion_mode = v8::KeyConversionMode::kConvertToString;
975       break;
976     default:
977       return napi_set_last_error(env, napi_invalid_arg);
978   }
979 
980   v8::MaybeLocal<v8::Array> maybe_all_propertynames =
981       obj->GetPropertyNames(context,
982                             collection_mode,
983                             filter,
984                             v8::IndexFilter::kIncludeIndices,
985                             conversion_mode);
986 
987   CHECK_MAYBE_EMPTY_WITH_PREAMBLE(
988       env, maybe_all_propertynames, napi_generic_failure);
989 
990   *result =
991       v8impl::JsValueFromV8LocalValue(maybe_all_propertynames.ToLocalChecked());
992   return GET_RETURN_STATUS(env);
993 }
994 
napi_set_property(napi_env env,napi_value object,napi_value key,napi_value value)995 napi_status napi_set_property(napi_env env,
996                               napi_value object,
997                               napi_value key,
998                               napi_value value) {
999   NAPI_PREAMBLE(env);
1000   CHECK_ARG(env, key);
1001   CHECK_ARG(env, value);
1002 
1003   v8::Local<v8::Context> context = env->context();
1004   v8::Local<v8::Object> obj;
1005 
1006   CHECK_TO_OBJECT(env, context, obj, object);
1007 
1008   v8::Local<v8::Value> k = v8impl::V8LocalValueFromJsValue(key);
1009   v8::Local<v8::Value> val = v8impl::V8LocalValueFromJsValue(value);
1010 
1011   v8::Maybe<bool> set_maybe = obj->Set(context, k, val);
1012 
1013   RETURN_STATUS_IF_FALSE(env, set_maybe.FromMaybe(false), napi_generic_failure);
1014   return GET_RETURN_STATUS(env);
1015 }
1016 
napi_has_property(napi_env env,napi_value object,napi_value key,bool * result)1017 napi_status napi_has_property(napi_env env,
1018                               napi_value object,
1019                               napi_value key,
1020                               bool* result) {
1021   NAPI_PREAMBLE(env);
1022   CHECK_ARG(env, result);
1023   CHECK_ARG(env, key);
1024 
1025   v8::Local<v8::Context> context = env->context();
1026   v8::Local<v8::Object> obj;
1027 
1028   CHECK_TO_OBJECT(env, context, obj, object);
1029 
1030   v8::Local<v8::Value> k = v8impl::V8LocalValueFromJsValue(key);
1031   v8::Maybe<bool> has_maybe = obj->Has(context, k);
1032 
1033   CHECK_MAYBE_NOTHING(env, has_maybe, napi_generic_failure);
1034 
1035   *result = has_maybe.FromMaybe(false);
1036   return GET_RETURN_STATUS(env);
1037 }
1038 
napi_get_property(napi_env env,napi_value object,napi_value key,napi_value * result)1039 napi_status napi_get_property(napi_env env,
1040                               napi_value object,
1041                               napi_value key,
1042                               napi_value* result) {
1043   NAPI_PREAMBLE(env);
1044   CHECK_ARG(env, key);
1045   CHECK_ARG(env, result);
1046 
1047   v8::Local<v8::Context> context = env->context();
1048   v8::Local<v8::Value> k = v8impl::V8LocalValueFromJsValue(key);
1049   v8::Local<v8::Object> obj;
1050 
1051   CHECK_TO_OBJECT(env, context, obj, object);
1052 
1053   auto get_maybe = obj->Get(context, k);
1054 
1055   CHECK_MAYBE_EMPTY(env, get_maybe, napi_generic_failure);
1056 
1057   v8::Local<v8::Value> val = get_maybe.ToLocalChecked();
1058   *result = v8impl::JsValueFromV8LocalValue(val);
1059   return GET_RETURN_STATUS(env);
1060 }
1061 
napi_delete_property(napi_env env,napi_value object,napi_value key,bool * result)1062 napi_status napi_delete_property(napi_env env,
1063                                  napi_value object,
1064                                  napi_value key,
1065                                  bool* result) {
1066   NAPI_PREAMBLE(env);
1067   CHECK_ARG(env, key);
1068 
1069   v8::Local<v8::Context> context = env->context();
1070   v8::Local<v8::Value> k = v8impl::V8LocalValueFromJsValue(key);
1071   v8::Local<v8::Object> obj;
1072 
1073   CHECK_TO_OBJECT(env, context, obj, object);
1074   v8::Maybe<bool> delete_maybe = obj->Delete(context, k);
1075   CHECK_MAYBE_NOTHING(env, delete_maybe, napi_generic_failure);
1076 
1077   if (result != nullptr)
1078     *result = delete_maybe.FromMaybe(false);
1079 
1080   return GET_RETURN_STATUS(env);
1081 }
1082 
napi_has_own_property(napi_env env,napi_value object,napi_value key,bool * result)1083 napi_status napi_has_own_property(napi_env env,
1084                                   napi_value object,
1085                                   napi_value key,
1086                                   bool* result) {
1087   NAPI_PREAMBLE(env);
1088   CHECK_ARG(env, key);
1089   CHECK_ARG(env, result);
1090 
1091   v8::Local<v8::Context> context = env->context();
1092   v8::Local<v8::Object> obj;
1093 
1094   CHECK_TO_OBJECT(env, context, obj, object);
1095   v8::Local<v8::Value> k = v8impl::V8LocalValueFromJsValue(key);
1096   RETURN_STATUS_IF_FALSE(env, k->IsName(), napi_name_expected);
1097   v8::Maybe<bool> has_maybe = obj->HasOwnProperty(context, k.As<v8::Name>());
1098   CHECK_MAYBE_NOTHING(env, has_maybe, napi_generic_failure);
1099   *result = has_maybe.FromMaybe(false);
1100 
1101   return GET_RETURN_STATUS(env);
1102 }
1103 
napi_set_named_property(napi_env env,napi_value object,const char * utf8name,napi_value value)1104 napi_status napi_set_named_property(napi_env env,
1105                                     napi_value object,
1106                                     const char* utf8name,
1107                                     napi_value value) {
1108   NAPI_PREAMBLE(env);
1109   CHECK_ARG(env, value);
1110 
1111   v8::Local<v8::Context> context = env->context();
1112   v8::Local<v8::Object> obj;
1113 
1114   CHECK_TO_OBJECT(env, context, obj, object);
1115 
1116   v8::Local<v8::Name> key;
1117   CHECK_NEW_FROM_UTF8(env, key, utf8name);
1118 
1119   v8::Local<v8::Value> val = v8impl::V8LocalValueFromJsValue(value);
1120 
1121   v8::Maybe<bool> set_maybe = obj->Set(context, key, val);
1122 
1123   RETURN_STATUS_IF_FALSE(env, set_maybe.FromMaybe(false), napi_generic_failure);
1124   return GET_RETURN_STATUS(env);
1125 }
1126 
napi_has_named_property(napi_env env,napi_value object,const char * utf8name,bool * result)1127 napi_status napi_has_named_property(napi_env env,
1128                                     napi_value object,
1129                                     const char* utf8name,
1130                                     bool* result) {
1131   NAPI_PREAMBLE(env);
1132   CHECK_ARG(env, result);
1133 
1134   v8::Local<v8::Context> context = env->context();
1135   v8::Local<v8::Object> obj;
1136 
1137   CHECK_TO_OBJECT(env, context, obj, object);
1138 
1139   v8::Local<v8::Name> key;
1140   CHECK_NEW_FROM_UTF8(env, key, utf8name);
1141 
1142   v8::Maybe<bool> has_maybe = obj->Has(context, key);
1143 
1144   CHECK_MAYBE_NOTHING(env, has_maybe, napi_generic_failure);
1145 
1146   *result = has_maybe.FromMaybe(false);
1147   return GET_RETURN_STATUS(env);
1148 }
1149 
napi_get_named_property(napi_env env,napi_value object,const char * utf8name,napi_value * result)1150 napi_status napi_get_named_property(napi_env env,
1151                                     napi_value object,
1152                                     const char* utf8name,
1153                                     napi_value* result) {
1154   NAPI_PREAMBLE(env);
1155   CHECK_ARG(env, result);
1156 
1157   v8::Local<v8::Context> context = env->context();
1158 
1159   v8::Local<v8::Name> key;
1160   CHECK_NEW_FROM_UTF8(env, key, utf8name);
1161 
1162   v8::Local<v8::Object> obj;
1163 
1164   CHECK_TO_OBJECT(env, context, obj, object);
1165 
1166   auto get_maybe = obj->Get(context, key);
1167 
1168   CHECK_MAYBE_EMPTY(env, get_maybe, napi_generic_failure);
1169 
1170   v8::Local<v8::Value> val = get_maybe.ToLocalChecked();
1171   *result = v8impl::JsValueFromV8LocalValue(val);
1172   return GET_RETURN_STATUS(env);
1173 }
1174 
napi_set_element(napi_env env,napi_value object,uint32_t index,napi_value value)1175 napi_status napi_set_element(napi_env env,
1176                              napi_value object,
1177                              uint32_t index,
1178                              napi_value value) {
1179   NAPI_PREAMBLE(env);
1180   CHECK_ARG(env, value);
1181 
1182   v8::Local<v8::Context> context = env->context();
1183   v8::Local<v8::Object> obj;
1184 
1185   CHECK_TO_OBJECT(env, context, obj, object);
1186 
1187   v8::Local<v8::Value> val = v8impl::V8LocalValueFromJsValue(value);
1188   auto set_maybe = obj->Set(context, index, val);
1189 
1190   RETURN_STATUS_IF_FALSE(env, set_maybe.FromMaybe(false), napi_generic_failure);
1191 
1192   return GET_RETURN_STATUS(env);
1193 }
1194 
napi_has_element(napi_env env,napi_value object,uint32_t index,bool * result)1195 napi_status napi_has_element(napi_env env,
1196                              napi_value object,
1197                              uint32_t index,
1198                              bool* result) {
1199   NAPI_PREAMBLE(env);
1200   CHECK_ARG(env, result);
1201 
1202   v8::Local<v8::Context> context = env->context();
1203   v8::Local<v8::Object> obj;
1204 
1205   CHECK_TO_OBJECT(env, context, obj, object);
1206 
1207   v8::Maybe<bool> has_maybe = obj->Has(context, index);
1208 
1209   CHECK_MAYBE_NOTHING(env, has_maybe, napi_generic_failure);
1210 
1211   *result = has_maybe.FromMaybe(false);
1212   return GET_RETURN_STATUS(env);
1213 }
1214 
napi_get_element(napi_env env,napi_value object,uint32_t index,napi_value * result)1215 napi_status napi_get_element(napi_env env,
1216                              napi_value object,
1217                              uint32_t index,
1218                              napi_value* result) {
1219   NAPI_PREAMBLE(env);
1220   CHECK_ARG(env, result);
1221 
1222   v8::Local<v8::Context> context = env->context();
1223   v8::Local<v8::Object> obj;
1224 
1225   CHECK_TO_OBJECT(env, context, obj, object);
1226 
1227   auto get_maybe = obj->Get(context, index);
1228 
1229   CHECK_MAYBE_EMPTY(env, get_maybe, napi_generic_failure);
1230 
1231   *result = v8impl::JsValueFromV8LocalValue(get_maybe.ToLocalChecked());
1232   return GET_RETURN_STATUS(env);
1233 }
1234 
napi_delete_element(napi_env env,napi_value object,uint32_t index,bool * result)1235 napi_status napi_delete_element(napi_env env,
1236                                 napi_value object,
1237                                 uint32_t index,
1238                                 bool* result) {
1239   NAPI_PREAMBLE(env);
1240 
1241   v8::Local<v8::Context> context = env->context();
1242   v8::Local<v8::Object> obj;
1243 
1244   CHECK_TO_OBJECT(env, context, obj, object);
1245   v8::Maybe<bool> delete_maybe = obj->Delete(context, index);
1246   CHECK_MAYBE_NOTHING(env, delete_maybe, napi_generic_failure);
1247 
1248   if (result != nullptr)
1249     *result = delete_maybe.FromMaybe(false);
1250 
1251   return GET_RETURN_STATUS(env);
1252 }
1253 
napi_define_properties(napi_env env,napi_value object,size_t property_count,const napi_property_descriptor * properties)1254 napi_status napi_define_properties(napi_env env,
1255                                    napi_value object,
1256                                    size_t property_count,
1257                                    const napi_property_descriptor* properties) {
1258   NAPI_PREAMBLE(env);
1259   if (property_count > 0) {
1260     CHECK_ARG(env, properties);
1261   }
1262 
1263   v8::Local<v8::Context> context = env->context();
1264 
1265   v8::Local<v8::Object> obj;
1266   CHECK_TO_OBJECT(env, context, obj, object);
1267 
1268   for (size_t i = 0; i < property_count; i++) {
1269     const napi_property_descriptor* p = &properties[i];
1270 
1271     v8::Local<v8::Name> property_name;
1272     STATUS_CALL(v8impl::V8NameFromPropertyDescriptor(env, p, &property_name));
1273 
1274     if (p->getter != nullptr || p->setter != nullptr) {
1275       v8::Local<v8::Function> local_getter;
1276       v8::Local<v8::Function> local_setter;
1277 
1278       if (p->getter != nullptr) {
1279         STATUS_CALL(v8impl::FunctionCallbackWrapper::NewFunction(
1280             env, p->getter, p->data, &local_getter));
1281       }
1282       if (p->setter != nullptr) {
1283         STATUS_CALL(v8impl::FunctionCallbackWrapper::NewFunction(
1284             env, p->setter, p->data, &local_setter));
1285       }
1286 
1287       v8::PropertyDescriptor descriptor(local_getter, local_setter);
1288       descriptor.set_enumerable((p->attributes & napi_enumerable) != 0);
1289       descriptor.set_configurable((p->attributes & napi_configurable) != 0);
1290 
1291       auto define_maybe = obj->DefineProperty(context,
1292                                               property_name,
1293                                               descriptor);
1294 
1295       if (!define_maybe.FromMaybe(false)) {
1296         return napi_set_last_error(env, napi_invalid_arg);
1297       }
1298     } else if (p->method != nullptr) {
1299       v8::Local<v8::Function> method;
1300       STATUS_CALL(v8impl::FunctionCallbackWrapper::NewFunction(
1301           env, p->method, p->data, &method));
1302       v8::PropertyDescriptor descriptor(method,
1303                                         (p->attributes & napi_writable) != 0);
1304       descriptor.set_enumerable((p->attributes & napi_enumerable) != 0);
1305       descriptor.set_configurable((p->attributes & napi_configurable) != 0);
1306 
1307       auto define_maybe = obj->DefineProperty(context,
1308                                               property_name,
1309                                               descriptor);
1310 
1311       if (!define_maybe.FromMaybe(false)) {
1312         return napi_set_last_error(env, napi_generic_failure);
1313       }
1314     } else {
1315       v8::Local<v8::Value> value = v8impl::V8LocalValueFromJsValue(p->value);
1316 
1317       v8::PropertyDescriptor descriptor(value,
1318                                         (p->attributes & napi_writable) != 0);
1319       descriptor.set_enumerable((p->attributes & napi_enumerable) != 0);
1320       descriptor.set_configurable((p->attributes & napi_configurable) != 0);
1321 
1322       auto define_maybe =
1323           obj->DefineProperty(context, property_name, descriptor);
1324 
1325       if (!define_maybe.FromMaybe(false)) {
1326         return napi_set_last_error(env, napi_invalid_arg);
1327       }
1328     }
1329   }
1330 
1331   return GET_RETURN_STATUS(env);
1332 }
1333 
napi_object_freeze(napi_env env,napi_value object)1334 napi_status napi_object_freeze(napi_env env,
1335                                napi_value object) {
1336   NAPI_PREAMBLE(env);
1337 
1338   v8::Local<v8::Context> context = env->context();
1339   v8::Local<v8::Object> obj;
1340 
1341   CHECK_TO_OBJECT(env, context, obj, object);
1342 
1343   v8::Maybe<bool> set_frozen =
1344     obj->SetIntegrityLevel(context, v8::IntegrityLevel::kFrozen);
1345 
1346   RETURN_STATUS_IF_FALSE_WITH_PREAMBLE(env,
1347     set_frozen.FromMaybe(false), napi_generic_failure);
1348 
1349   return GET_RETURN_STATUS(env);
1350 }
1351 
napi_object_seal(napi_env env,napi_value object)1352 napi_status napi_object_seal(napi_env env,
1353                              napi_value object) {
1354   NAPI_PREAMBLE(env);
1355 
1356   v8::Local<v8::Context> context = env->context();
1357   v8::Local<v8::Object> obj;
1358 
1359   CHECK_TO_OBJECT(env, context, obj, object);
1360 
1361   v8::Maybe<bool> set_sealed =
1362     obj->SetIntegrityLevel(context, v8::IntegrityLevel::kSealed);
1363 
1364   RETURN_STATUS_IF_FALSE_WITH_PREAMBLE(env,
1365     set_sealed.FromMaybe(false), napi_generic_failure);
1366 
1367   return GET_RETURN_STATUS(env);
1368 }
1369 
napi_is_array(napi_env env,napi_value value,bool * result)1370 napi_status napi_is_array(napi_env env, napi_value value, bool* result) {
1371   CHECK_ENV(env);
1372   CHECK_ARG(env, value);
1373   CHECK_ARG(env, result);
1374 
1375   v8::Local<v8::Value> val = v8impl::V8LocalValueFromJsValue(value);
1376 
1377   *result = val->IsArray();
1378   return napi_clear_last_error(env);
1379 }
1380 
napi_get_array_length(napi_env env,napi_value value,uint32_t * result)1381 napi_status napi_get_array_length(napi_env env,
1382                                   napi_value value,
1383                                   uint32_t* result) {
1384   NAPI_PREAMBLE(env);
1385   CHECK_ARG(env, value);
1386   CHECK_ARG(env, result);
1387 
1388   v8::Local<v8::Value> val = v8impl::V8LocalValueFromJsValue(value);
1389   RETURN_STATUS_IF_FALSE(env, val->IsArray(), napi_array_expected);
1390 
1391   v8::Local<v8::Array> arr = val.As<v8::Array>();
1392   *result = arr->Length();
1393 
1394   return GET_RETURN_STATUS(env);
1395 }
1396 
napi_strict_equals(napi_env env,napi_value lhs,napi_value rhs,bool * result)1397 napi_status napi_strict_equals(napi_env env,
1398                                napi_value lhs,
1399                                napi_value rhs,
1400                                bool* result) {
1401   NAPI_PREAMBLE(env);
1402   CHECK_ARG(env, lhs);
1403   CHECK_ARG(env, rhs);
1404   CHECK_ARG(env, result);
1405 
1406   v8::Local<v8::Value> a = v8impl::V8LocalValueFromJsValue(lhs);
1407   v8::Local<v8::Value> b = v8impl::V8LocalValueFromJsValue(rhs);
1408 
1409   *result = a->StrictEquals(b);
1410   return GET_RETURN_STATUS(env);
1411 }
1412 
napi_get_prototype(napi_env env,napi_value object,napi_value * result)1413 napi_status napi_get_prototype(napi_env env,
1414                                napi_value object,
1415                                napi_value* result) {
1416   NAPI_PREAMBLE(env);
1417   CHECK_ARG(env, result);
1418 
1419   v8::Local<v8::Context> context = env->context();
1420 
1421   v8::Local<v8::Object> obj;
1422   CHECK_TO_OBJECT(env, context, obj, object);
1423 
1424   v8::Local<v8::Value> val = obj->GetPrototype();
1425   *result = v8impl::JsValueFromV8LocalValue(val);
1426   return GET_RETURN_STATUS(env);
1427 }
1428 
napi_create_object(napi_env env,napi_value * result)1429 napi_status napi_create_object(napi_env env, napi_value* result) {
1430   CHECK_ENV(env);
1431   CHECK_ARG(env, result);
1432 
1433   *result = v8impl::JsValueFromV8LocalValue(
1434       v8::Object::New(env->isolate));
1435 
1436   return napi_clear_last_error(env);
1437 }
1438 
napi_create_array(napi_env env,napi_value * result)1439 napi_status napi_create_array(napi_env env, napi_value* result) {
1440   CHECK_ENV(env);
1441   CHECK_ARG(env, result);
1442 
1443   *result = v8impl::JsValueFromV8LocalValue(
1444       v8::Array::New(env->isolate));
1445 
1446   return napi_clear_last_error(env);
1447 }
1448 
napi_create_array_with_length(napi_env env,size_t length,napi_value * result)1449 napi_status napi_create_array_with_length(napi_env env,
1450                                           size_t length,
1451                                           napi_value* result) {
1452   CHECK_ENV(env);
1453   CHECK_ARG(env, result);
1454 
1455   *result = v8impl::JsValueFromV8LocalValue(
1456       v8::Array::New(env->isolate, length));
1457 
1458   return napi_clear_last_error(env);
1459 }
1460 
napi_create_string_latin1(napi_env env,const char * str,size_t length,napi_value * result)1461 napi_status napi_create_string_latin1(napi_env env,
1462                                       const char* str,
1463                                       size_t length,
1464                                       napi_value* result) {
1465   CHECK_ENV(env);
1466   CHECK_ARG(env, result);
1467   RETURN_STATUS_IF_FALSE(env,
1468       (length == NAPI_AUTO_LENGTH) || length <= INT_MAX,
1469       napi_invalid_arg);
1470 
1471   auto isolate = env->isolate;
1472   auto str_maybe =
1473       v8::String::NewFromOneByte(isolate,
1474                                  reinterpret_cast<const uint8_t*>(str),
1475                                  v8::NewStringType::kNormal,
1476                                  length);
1477   CHECK_MAYBE_EMPTY(env, str_maybe, napi_generic_failure);
1478 
1479   *result = v8impl::JsValueFromV8LocalValue(str_maybe.ToLocalChecked());
1480   return napi_clear_last_error(env);
1481 }
1482 
napi_create_string_utf8(napi_env env,const char * str,size_t length,napi_value * result)1483 napi_status napi_create_string_utf8(napi_env env,
1484                                     const char* str,
1485                                     size_t length,
1486                                     napi_value* result) {
1487   CHECK_ENV(env);
1488   CHECK_ARG(env, result);
1489   RETURN_STATUS_IF_FALSE(env,
1490       (length == NAPI_AUTO_LENGTH) || length <= INT_MAX,
1491       napi_invalid_arg);
1492 
1493   auto isolate = env->isolate;
1494   auto str_maybe =
1495       v8::String::NewFromUtf8(isolate,
1496                               str,
1497                               v8::NewStringType::kNormal,
1498                               static_cast<int>(length));
1499   CHECK_MAYBE_EMPTY(env, str_maybe, napi_generic_failure);
1500   *result = v8impl::JsValueFromV8LocalValue(str_maybe.ToLocalChecked());
1501   return napi_clear_last_error(env);
1502 }
1503 
napi_create_string_utf16(napi_env env,const char16_t * str,size_t length,napi_value * result)1504 napi_status napi_create_string_utf16(napi_env env,
1505                                      const char16_t* str,
1506                                      size_t length,
1507                                      napi_value* result) {
1508   CHECK_ENV(env);
1509   CHECK_ARG(env, result);
1510   RETURN_STATUS_IF_FALSE(env,
1511       (length == NAPI_AUTO_LENGTH) || length <= INT_MAX,
1512       napi_invalid_arg);
1513 
1514   auto isolate = env->isolate;
1515   auto str_maybe =
1516       v8::String::NewFromTwoByte(isolate,
1517                                  reinterpret_cast<const uint16_t*>(str),
1518                                  v8::NewStringType::kNormal,
1519                                  length);
1520   CHECK_MAYBE_EMPTY(env, str_maybe, napi_generic_failure);
1521 
1522   *result = v8impl::JsValueFromV8LocalValue(str_maybe.ToLocalChecked());
1523   return napi_clear_last_error(env);
1524 }
1525 
napi_create_double(napi_env env,double value,napi_value * result)1526 napi_status napi_create_double(napi_env env,
1527                                double value,
1528                                napi_value* result) {
1529   CHECK_ENV(env);
1530   CHECK_ARG(env, result);
1531 
1532   *result = v8impl::JsValueFromV8LocalValue(
1533       v8::Number::New(env->isolate, value));
1534 
1535   return napi_clear_last_error(env);
1536 }
1537 
napi_create_int32(napi_env env,int32_t value,napi_value * result)1538 napi_status napi_create_int32(napi_env env,
1539                               int32_t value,
1540                               napi_value* result) {
1541   CHECK_ENV(env);
1542   CHECK_ARG(env, result);
1543 
1544   *result = v8impl::JsValueFromV8LocalValue(
1545       v8::Integer::New(env->isolate, value));
1546 
1547   return napi_clear_last_error(env);
1548 }
1549 
napi_create_uint32(napi_env env,uint32_t value,napi_value * result)1550 napi_status napi_create_uint32(napi_env env,
1551                                uint32_t value,
1552                                napi_value* result) {
1553   CHECK_ENV(env);
1554   CHECK_ARG(env, result);
1555 
1556   *result = v8impl::JsValueFromV8LocalValue(
1557       v8::Integer::NewFromUnsigned(env->isolate, value));
1558 
1559   return napi_clear_last_error(env);
1560 }
1561 
napi_create_int64(napi_env env,int64_t value,napi_value * result)1562 napi_status napi_create_int64(napi_env env,
1563                               int64_t value,
1564                               napi_value* result) {
1565   CHECK_ENV(env);
1566   CHECK_ARG(env, result);
1567 
1568   *result = v8impl::JsValueFromV8LocalValue(
1569       v8::Number::New(env->isolate, static_cast<double>(value)));
1570 
1571   return napi_clear_last_error(env);
1572 }
1573 
napi_create_bigint_int64(napi_env env,int64_t value,napi_value * result)1574 napi_status napi_create_bigint_int64(napi_env env,
1575                                      int64_t value,
1576                                      napi_value* result) {
1577   CHECK_ENV(env);
1578   CHECK_ARG(env, result);
1579 
1580   *result = v8impl::JsValueFromV8LocalValue(
1581       v8::BigInt::New(env->isolate, value));
1582 
1583   return napi_clear_last_error(env);
1584 }
1585 
napi_create_bigint_uint64(napi_env env,uint64_t value,napi_value * result)1586 napi_status napi_create_bigint_uint64(napi_env env,
1587                                       uint64_t value,
1588                                       napi_value* result) {
1589   CHECK_ENV(env);
1590   CHECK_ARG(env, result);
1591 
1592   *result = v8impl::JsValueFromV8LocalValue(
1593       v8::BigInt::NewFromUnsigned(env->isolate, value));
1594 
1595   return napi_clear_last_error(env);
1596 }
1597 
napi_create_bigint_words(napi_env env,int sign_bit,size_t word_count,const uint64_t * words,napi_value * result)1598 napi_status napi_create_bigint_words(napi_env env,
1599                                      int sign_bit,
1600                                      size_t word_count,
1601                                      const uint64_t* words,
1602                                      napi_value* result) {
1603   NAPI_PREAMBLE(env);
1604   CHECK_ARG(env, words);
1605   CHECK_ARG(env, result);
1606 
1607   v8::Local<v8::Context> context = env->context();
1608 
1609   RETURN_STATUS_IF_FALSE(
1610       env, word_count <= INT_MAX, napi_invalid_arg);
1611 
1612   v8::MaybeLocal<v8::BigInt> b = v8::BigInt::NewFromWords(
1613       context, sign_bit, word_count, words);
1614 
1615   CHECK_MAYBE_EMPTY_WITH_PREAMBLE(env, b, napi_generic_failure);
1616 
1617   *result = v8impl::JsValueFromV8LocalValue(b.ToLocalChecked());
1618   return GET_RETURN_STATUS(env);
1619 }
1620 
napi_get_boolean(napi_env env,bool value,napi_value * result)1621 napi_status napi_get_boolean(napi_env env, bool value, napi_value* result) {
1622   CHECK_ENV(env);
1623   CHECK_ARG(env, result);
1624 
1625   v8::Isolate* isolate = env->isolate;
1626 
1627   if (value) {
1628     *result = v8impl::JsValueFromV8LocalValue(v8::True(isolate));
1629   } else {
1630     *result = v8impl::JsValueFromV8LocalValue(v8::False(isolate));
1631   }
1632 
1633   return napi_clear_last_error(env);
1634 }
1635 
napi_create_symbol(napi_env env,napi_value description,napi_value * result)1636 napi_status napi_create_symbol(napi_env env,
1637                                napi_value description,
1638                                napi_value* result) {
1639   CHECK_ENV(env);
1640   CHECK_ARG(env, result);
1641 
1642   v8::Isolate* isolate = env->isolate;
1643 
1644   if (description == nullptr) {
1645     *result = v8impl::JsValueFromV8LocalValue(v8::Symbol::New(isolate));
1646   } else {
1647     v8::Local<v8::Value> desc = v8impl::V8LocalValueFromJsValue(description);
1648     RETURN_STATUS_IF_FALSE(env, desc->IsString(), napi_string_expected);
1649 
1650     *result = v8impl::JsValueFromV8LocalValue(
1651       v8::Symbol::New(isolate, desc.As<v8::String>()));
1652   }
1653 
1654   return napi_clear_last_error(env);
1655 }
1656 
set_error_code(napi_env env,v8::Local<v8::Value> error,napi_value code,const char * code_cstring)1657 static inline napi_status set_error_code(napi_env env,
1658                                          v8::Local<v8::Value> error,
1659                                          napi_value code,
1660                                          const char* code_cstring) {
1661   if ((code != nullptr) || (code_cstring != nullptr)) {
1662     v8::Local<v8::Context> context = env->context();
1663     v8::Local<v8::Object> err_object = error.As<v8::Object>();
1664 
1665     v8::Local<v8::Value> code_value = v8impl::V8LocalValueFromJsValue(code);
1666     if (code != nullptr) {
1667       code_value = v8impl::V8LocalValueFromJsValue(code);
1668       RETURN_STATUS_IF_FALSE(env, code_value->IsString(), napi_string_expected);
1669     } else {
1670       CHECK_NEW_FROM_UTF8(env, code_value, code_cstring);
1671     }
1672 
1673     v8::Local<v8::Name> code_key;
1674     CHECK_NEW_FROM_UTF8(env, code_key, "code");
1675 
1676     v8::Maybe<bool> set_maybe = err_object->Set(context, code_key, code_value);
1677     RETURN_STATUS_IF_FALSE(env,
1678                            set_maybe.FromMaybe(false),
1679                            napi_generic_failure);
1680   }
1681   return napi_ok;
1682 }
1683 
napi_create_error(napi_env env,napi_value code,napi_value msg,napi_value * result)1684 napi_status napi_create_error(napi_env env,
1685                               napi_value code,
1686                               napi_value msg,
1687                               napi_value* result) {
1688   CHECK_ENV(env);
1689   CHECK_ARG(env, msg);
1690   CHECK_ARG(env, result);
1691 
1692   v8::Local<v8::Value> message_value = v8impl::V8LocalValueFromJsValue(msg);
1693   RETURN_STATUS_IF_FALSE(env, message_value->IsString(), napi_string_expected);
1694 
1695   v8::Local<v8::Value> error_obj =
1696       v8::Exception::Error(message_value.As<v8::String>());
1697   STATUS_CALL(set_error_code(env, error_obj, code, nullptr));
1698 
1699   *result = v8impl::JsValueFromV8LocalValue(error_obj);
1700 
1701   return napi_clear_last_error(env);
1702 }
1703 
napi_create_type_error(napi_env env,napi_value code,napi_value msg,napi_value * result)1704 napi_status napi_create_type_error(napi_env env,
1705                                    napi_value code,
1706                                    napi_value msg,
1707                                    napi_value* result) {
1708   CHECK_ENV(env);
1709   CHECK_ARG(env, msg);
1710   CHECK_ARG(env, result);
1711 
1712   v8::Local<v8::Value> message_value = v8impl::V8LocalValueFromJsValue(msg);
1713   RETURN_STATUS_IF_FALSE(env, message_value->IsString(), napi_string_expected);
1714 
1715   v8::Local<v8::Value> error_obj =
1716       v8::Exception::TypeError(message_value.As<v8::String>());
1717   STATUS_CALL(set_error_code(env, error_obj, code, nullptr));
1718 
1719   *result = v8impl::JsValueFromV8LocalValue(error_obj);
1720 
1721   return napi_clear_last_error(env);
1722 }
1723 
napi_create_range_error(napi_env env,napi_value code,napi_value msg,napi_value * result)1724 napi_status napi_create_range_error(napi_env env,
1725                                     napi_value code,
1726                                     napi_value msg,
1727                                     napi_value* result) {
1728   CHECK_ENV(env);
1729   CHECK_ARG(env, msg);
1730   CHECK_ARG(env, result);
1731 
1732   v8::Local<v8::Value> message_value = v8impl::V8LocalValueFromJsValue(msg);
1733   RETURN_STATUS_IF_FALSE(env, message_value->IsString(), napi_string_expected);
1734 
1735   v8::Local<v8::Value> error_obj =
1736       v8::Exception::RangeError(message_value.As<v8::String>());
1737   STATUS_CALL(set_error_code(env, error_obj, code, nullptr));
1738 
1739   *result = v8impl::JsValueFromV8LocalValue(error_obj);
1740 
1741   return napi_clear_last_error(env);
1742 }
1743 
napi_typeof(napi_env env,napi_value value,napi_valuetype * result)1744 napi_status napi_typeof(napi_env env,
1745                         napi_value value,
1746                         napi_valuetype* result) {
1747   // Omit NAPI_PREAMBLE and GET_RETURN_STATUS because V8 calls here cannot throw
1748   // JS exceptions.
1749   CHECK_ENV(env);
1750   CHECK_ARG(env, value);
1751   CHECK_ARG(env, result);
1752 
1753   v8::Local<v8::Value> v = v8impl::V8LocalValueFromJsValue(value);
1754 
1755   if (v->IsNumber()) {
1756     *result = napi_number;
1757   } else if (v->IsBigInt()) {
1758     *result = napi_bigint;
1759   } else if (v->IsString()) {
1760     *result = napi_string;
1761   } else if (v->IsFunction()) {
1762     // This test has to come before IsObject because IsFunction
1763     // implies IsObject
1764     *result = napi_function;
1765   } else if (v->IsExternal()) {
1766     // This test has to come before IsObject because IsExternal
1767     // implies IsObject
1768     *result = napi_external;
1769   } else if (v->IsObject()) {
1770     *result = napi_object;
1771   } else if (v->IsBoolean()) {
1772     *result = napi_boolean;
1773   } else if (v->IsUndefined()) {
1774     *result = napi_undefined;
1775   } else if (v->IsSymbol()) {
1776     *result = napi_symbol;
1777   } else if (v->IsNull()) {
1778     *result = napi_null;
1779   } else {
1780     // Should not get here unless V8 has added some new kind of value.
1781     return napi_set_last_error(env, napi_invalid_arg);
1782   }
1783 
1784   return napi_clear_last_error(env);
1785 }
1786 
napi_get_undefined(napi_env env,napi_value * result)1787 napi_status napi_get_undefined(napi_env env, napi_value* result) {
1788   CHECK_ENV(env);
1789   CHECK_ARG(env, result);
1790 
1791   *result = v8impl::JsValueFromV8LocalValue(
1792       v8::Undefined(env->isolate));
1793 
1794   return napi_clear_last_error(env);
1795 }
1796 
napi_get_null(napi_env env,napi_value * result)1797 napi_status napi_get_null(napi_env env, napi_value* result) {
1798   CHECK_ENV(env);
1799   CHECK_ARG(env, result);
1800 
1801   *result = v8impl::JsValueFromV8LocalValue(
1802         v8::Null(env->isolate));
1803 
1804   return napi_clear_last_error(env);
1805 }
1806 
1807 // 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)1808 napi_status napi_get_cb_info(
1809     napi_env env,               // [in] NAPI environment handle
1810     napi_callback_info cbinfo,  // [in] Opaque callback-info handle
1811     size_t* argc,      // [in-out] Specifies the size of the provided argv array
1812                        // and receives the actual count of args.
1813     napi_value* argv,  // [out] Array of values
1814     napi_value* this_arg,  // [out] Receives the JS 'this' arg for the call
1815     void** data) {         // [out] Receives the data pointer for the callback.
1816   CHECK_ENV(env);
1817   CHECK_ARG(env, cbinfo);
1818 
1819   v8impl::CallbackWrapper* info =
1820       reinterpret_cast<v8impl::CallbackWrapper*>(cbinfo);
1821 
1822   if (argv != nullptr) {
1823     CHECK_ARG(env, argc);
1824     info->Args(argv, *argc);
1825   }
1826   if (argc != nullptr) {
1827     *argc = info->ArgsLength();
1828   }
1829   if (this_arg != nullptr) {
1830     *this_arg = info->This();
1831   }
1832   if (data != nullptr) {
1833     *data = info->Data();
1834   }
1835 
1836   return napi_clear_last_error(env);
1837 }
1838 
napi_get_new_target(napi_env env,napi_callback_info cbinfo,napi_value * result)1839 napi_status napi_get_new_target(napi_env env,
1840                                 napi_callback_info cbinfo,
1841                                 napi_value* result) {
1842   CHECK_ENV(env);
1843   CHECK_ARG(env, cbinfo);
1844   CHECK_ARG(env, result);
1845 
1846   v8impl::CallbackWrapper* info =
1847       reinterpret_cast<v8impl::CallbackWrapper*>(cbinfo);
1848 
1849   *result = info->GetNewTarget();
1850   return napi_clear_last_error(env);
1851 }
1852 
napi_call_function(napi_env env,napi_value recv,napi_value func,size_t argc,const napi_value * argv,napi_value * result)1853 napi_status napi_call_function(napi_env env,
1854                                napi_value recv,
1855                                napi_value func,
1856                                size_t argc,
1857                                const napi_value* argv,
1858                                napi_value* result) {
1859   NAPI_PREAMBLE(env);
1860   CHECK_ARG(env, recv);
1861   if (argc > 0) {
1862     CHECK_ARG(env, argv);
1863   }
1864 
1865   v8::Local<v8::Context> context = env->context();
1866 
1867   v8::Local<v8::Value> v8recv = v8impl::V8LocalValueFromJsValue(recv);
1868 
1869   v8::Local<v8::Function> v8func;
1870   CHECK_TO_FUNCTION(env, v8func, func);
1871 
1872   auto maybe = v8func->Call(context, v8recv, argc,
1873     reinterpret_cast<v8::Local<v8::Value>*>(const_cast<napi_value*>(argv)));
1874 
1875   if (try_catch.HasCaught()) {
1876     return napi_set_last_error(env, napi_pending_exception);
1877   } else {
1878     if (result != nullptr) {
1879       CHECK_MAYBE_EMPTY(env, maybe, napi_generic_failure);
1880       *result = v8impl::JsValueFromV8LocalValue(maybe.ToLocalChecked());
1881     }
1882     return napi_clear_last_error(env);
1883   }
1884 }
1885 
napi_get_global(napi_env env,napi_value * result)1886 napi_status napi_get_global(napi_env env, napi_value* result) {
1887   CHECK_ENV(env);
1888   CHECK_ARG(env, result);
1889 
1890   *result = v8impl::JsValueFromV8LocalValue(env->context()->Global());
1891 
1892   return napi_clear_last_error(env);
1893 }
1894 
napi_throw(napi_env env,napi_value error)1895 napi_status napi_throw(napi_env env, napi_value error) {
1896   NAPI_PREAMBLE(env);
1897   CHECK_ARG(env, error);
1898 
1899   v8::Isolate* isolate = env->isolate;
1900 
1901   isolate->ThrowException(v8impl::V8LocalValueFromJsValue(error));
1902   // any VM calls after this point and before returning
1903   // to the javascript invoker will fail
1904   return napi_clear_last_error(env);
1905 }
1906 
napi_throw_error(napi_env env,const char * code,const char * msg)1907 napi_status napi_throw_error(napi_env env,
1908                              const char* code,
1909                              const char* msg) {
1910   NAPI_PREAMBLE(env);
1911 
1912   v8::Isolate* isolate = env->isolate;
1913   v8::Local<v8::String> str;
1914   CHECK_NEW_FROM_UTF8(env, str, msg);
1915 
1916   v8::Local<v8::Value> error_obj = v8::Exception::Error(str);
1917   STATUS_CALL(set_error_code(env, error_obj, nullptr, code));
1918 
1919   isolate->ThrowException(error_obj);
1920   // any VM calls after this point and before returning
1921   // to the javascript invoker will fail
1922   return napi_clear_last_error(env);
1923 }
1924 
napi_throw_type_error(napi_env env,const char * code,const char * msg)1925 napi_status napi_throw_type_error(napi_env env,
1926                                   const char* code,
1927                                   const char* msg) {
1928   NAPI_PREAMBLE(env);
1929 
1930   v8::Isolate* isolate = env->isolate;
1931   v8::Local<v8::String> str;
1932   CHECK_NEW_FROM_UTF8(env, str, msg);
1933 
1934   v8::Local<v8::Value> error_obj = v8::Exception::TypeError(str);
1935   STATUS_CALL(set_error_code(env, error_obj, nullptr, code));
1936 
1937   isolate->ThrowException(error_obj);
1938   // any VM calls after this point and before returning
1939   // to the javascript invoker will fail
1940   return napi_clear_last_error(env);
1941 }
1942 
napi_throw_range_error(napi_env env,const char * code,const char * msg)1943 napi_status napi_throw_range_error(napi_env env,
1944                                    const char* code,
1945                                    const char* msg) {
1946   NAPI_PREAMBLE(env);
1947 
1948   v8::Isolate* isolate = env->isolate;
1949   v8::Local<v8::String> str;
1950   CHECK_NEW_FROM_UTF8(env, str, msg);
1951 
1952   v8::Local<v8::Value> error_obj = v8::Exception::RangeError(str);
1953   STATUS_CALL(set_error_code(env, error_obj, nullptr, code));
1954 
1955   isolate->ThrowException(error_obj);
1956   // any VM calls after this point and before returning
1957   // to the javascript invoker will fail
1958   return napi_clear_last_error(env);
1959 }
1960 
napi_is_error(napi_env env,napi_value value,bool * result)1961 napi_status napi_is_error(napi_env env, napi_value value, bool* result) {
1962   // Omit NAPI_PREAMBLE and GET_RETURN_STATUS because V8 calls here cannot
1963   // throw JS exceptions.
1964   CHECK_ENV(env);
1965   CHECK_ARG(env, value);
1966   CHECK_ARG(env, result);
1967 
1968   v8::Local<v8::Value> val = v8impl::V8LocalValueFromJsValue(value);
1969   *result = val->IsNativeError();
1970 
1971   return napi_clear_last_error(env);
1972 }
1973 
napi_get_value_double(napi_env env,napi_value value,double * result)1974 napi_status napi_get_value_double(napi_env env,
1975                                   napi_value value,
1976                                   double* result) {
1977   // Omit NAPI_PREAMBLE and GET_RETURN_STATUS because V8 calls here cannot throw
1978   // JS exceptions.
1979   CHECK_ENV(env);
1980   CHECK_ARG(env, value);
1981   CHECK_ARG(env, result);
1982 
1983   v8::Local<v8::Value> val = v8impl::V8LocalValueFromJsValue(value);
1984   RETURN_STATUS_IF_FALSE(env, val->IsNumber(), napi_number_expected);
1985 
1986   *result = val.As<v8::Number>()->Value();
1987 
1988   return napi_clear_last_error(env);
1989 }
1990 
napi_get_value_int32(napi_env env,napi_value value,int32_t * result)1991 napi_status napi_get_value_int32(napi_env env,
1992                                  napi_value value,
1993                                  int32_t* result) {
1994   // Omit NAPI_PREAMBLE and GET_RETURN_STATUS because V8 calls here cannot throw
1995   // JS exceptions.
1996   CHECK_ENV(env);
1997   CHECK_ARG(env, value);
1998   CHECK_ARG(env, result);
1999 
2000   v8::Local<v8::Value> val = v8impl::V8LocalValueFromJsValue(value);
2001 
2002   if (val->IsInt32()) {
2003     *result = val.As<v8::Int32>()->Value();
2004   } else {
2005     RETURN_STATUS_IF_FALSE(env, val->IsNumber(), napi_number_expected);
2006 
2007     // Empty context: https://github.com/nodejs/node/issues/14379
2008     v8::Local<v8::Context> context;
2009     *result = val->Int32Value(context).FromJust();
2010   }
2011 
2012   return napi_clear_last_error(env);
2013 }
2014 
napi_get_value_uint32(napi_env env,napi_value value,uint32_t * result)2015 napi_status napi_get_value_uint32(napi_env env,
2016                                   napi_value value,
2017                                   uint32_t* result) {
2018   // Omit NAPI_PREAMBLE and GET_RETURN_STATUS because V8 calls here cannot throw
2019   // JS exceptions.
2020   CHECK_ENV(env);
2021   CHECK_ARG(env, value);
2022   CHECK_ARG(env, result);
2023 
2024   v8::Local<v8::Value> val = v8impl::V8LocalValueFromJsValue(value);
2025 
2026   if (val->IsUint32()) {
2027     *result = val.As<v8::Uint32>()->Value();
2028   } else {
2029     RETURN_STATUS_IF_FALSE(env, val->IsNumber(), napi_number_expected);
2030 
2031     // Empty context: https://github.com/nodejs/node/issues/14379
2032     v8::Local<v8::Context> context;
2033     *result = val->Uint32Value(context).FromJust();
2034   }
2035 
2036   return napi_clear_last_error(env);
2037 }
2038 
napi_get_value_int64(napi_env env,napi_value value,int64_t * result)2039 napi_status napi_get_value_int64(napi_env env,
2040                                  napi_value value,
2041                                  int64_t* result) {
2042   // Omit NAPI_PREAMBLE and GET_RETURN_STATUS because V8 calls here cannot throw
2043   // JS exceptions.
2044   CHECK_ENV(env);
2045   CHECK_ARG(env, value);
2046   CHECK_ARG(env, result);
2047 
2048   v8::Local<v8::Value> val = v8impl::V8LocalValueFromJsValue(value);
2049 
2050   // This is still a fast path very likely to be taken.
2051   if (val->IsInt32()) {
2052     *result = val.As<v8::Int32>()->Value();
2053     return napi_clear_last_error(env);
2054   }
2055 
2056   RETURN_STATUS_IF_FALSE(env, val->IsNumber(), napi_number_expected);
2057 
2058   // v8::Value::IntegerValue() converts NaN, +Inf, and -Inf to INT64_MIN,
2059   // inconsistent with v8::Value::Int32Value() which converts those values to 0.
2060   // Special-case all non-finite values to match that behavior.
2061   double doubleValue = val.As<v8::Number>()->Value();
2062   if (std::isfinite(doubleValue)) {
2063     // Empty context: https://github.com/nodejs/node/issues/14379
2064     v8::Local<v8::Context> context;
2065     *result = val->IntegerValue(context).FromJust();
2066   } else {
2067     *result = 0;
2068   }
2069 
2070   return napi_clear_last_error(env);
2071 }
2072 
napi_get_value_bigint_int64(napi_env env,napi_value value,int64_t * result,bool * lossless)2073 napi_status napi_get_value_bigint_int64(napi_env env,
2074                                         napi_value value,
2075                                         int64_t* result,
2076                                         bool* lossless) {
2077   CHECK_ENV(env);
2078   CHECK_ARG(env, value);
2079   CHECK_ARG(env, result);
2080   CHECK_ARG(env, lossless);
2081 
2082   v8::Local<v8::Value> val = v8impl::V8LocalValueFromJsValue(value);
2083 
2084   RETURN_STATUS_IF_FALSE(env, val->IsBigInt(), napi_bigint_expected);
2085 
2086   *result = val.As<v8::BigInt>()->Int64Value(lossless);
2087 
2088   return napi_clear_last_error(env);
2089 }
2090 
napi_get_value_bigint_uint64(napi_env env,napi_value value,uint64_t * result,bool * lossless)2091 napi_status napi_get_value_bigint_uint64(napi_env env,
2092                                          napi_value value,
2093                                          uint64_t* result,
2094                                          bool* lossless) {
2095   CHECK_ENV(env);
2096   CHECK_ARG(env, value);
2097   CHECK_ARG(env, result);
2098   CHECK_ARG(env, lossless);
2099 
2100   v8::Local<v8::Value> val = v8impl::V8LocalValueFromJsValue(value);
2101 
2102   RETURN_STATUS_IF_FALSE(env, val->IsBigInt(), napi_bigint_expected);
2103 
2104   *result = val.As<v8::BigInt>()->Uint64Value(lossless);
2105 
2106   return napi_clear_last_error(env);
2107 }
2108 
napi_get_value_bigint_words(napi_env env,napi_value value,int * sign_bit,size_t * word_count,uint64_t * words)2109 napi_status napi_get_value_bigint_words(napi_env env,
2110                                         napi_value value,
2111                                         int* sign_bit,
2112                                         size_t* word_count,
2113                                         uint64_t* words) {
2114   CHECK_ENV(env);
2115   CHECK_ARG(env, value);
2116   CHECK_ARG(env, word_count);
2117 
2118   v8::Local<v8::Value> val = v8impl::V8LocalValueFromJsValue(value);
2119 
2120   RETURN_STATUS_IF_FALSE(env, val->IsBigInt(), napi_bigint_expected);
2121 
2122   v8::Local<v8::BigInt> big = val.As<v8::BigInt>();
2123 
2124   int word_count_int = *word_count;
2125 
2126   if (sign_bit == nullptr && words == nullptr) {
2127     word_count_int = big->WordCount();
2128   } else {
2129     CHECK_ARG(env, sign_bit);
2130     CHECK_ARG(env, words);
2131     big->ToWordsArray(sign_bit, &word_count_int, words);
2132   }
2133 
2134   *word_count = word_count_int;
2135 
2136   return napi_clear_last_error(env);
2137 }
2138 
napi_get_value_bool(napi_env env,napi_value value,bool * result)2139 napi_status napi_get_value_bool(napi_env env, napi_value value, bool* result) {
2140   // Omit NAPI_PREAMBLE and GET_RETURN_STATUS because V8 calls here cannot throw
2141   // JS exceptions.
2142   CHECK_ENV(env);
2143   CHECK_ARG(env, value);
2144   CHECK_ARG(env, result);
2145 
2146   v8::Local<v8::Value> val = v8impl::V8LocalValueFromJsValue(value);
2147   RETURN_STATUS_IF_FALSE(env, val->IsBoolean(), napi_boolean_expected);
2148 
2149   *result = val.As<v8::Boolean>()->Value();
2150 
2151   return napi_clear_last_error(env);
2152 }
2153 
2154 // Copies a JavaScript string into a LATIN-1 string buffer. The result is the
2155 // number of bytes (excluding the null terminator) copied into buf.
2156 // A sufficient buffer size should be greater than the length of string,
2157 // reserving space for null terminator.
2158 // If bufsize is insufficient, the string will be truncated and null terminated.
2159 // If buf is NULL, this method returns the length of the string (in bytes)
2160 // via the result parameter.
2161 // 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)2162 napi_status napi_get_value_string_latin1(napi_env env,
2163                                          napi_value value,
2164                                          char* buf,
2165                                          size_t bufsize,
2166                                          size_t* result) {
2167   CHECK_ENV(env);
2168   CHECK_ARG(env, value);
2169 
2170   v8::Local<v8::Value> val = v8impl::V8LocalValueFromJsValue(value);
2171   RETURN_STATUS_IF_FALSE(env, val->IsString(), napi_string_expected);
2172 
2173   if (!buf) {
2174     CHECK_ARG(env, result);
2175     *result = val.As<v8::String>()->Length();
2176   } else if (bufsize != 0) {
2177     int copied =
2178         val.As<v8::String>()->WriteOneByte(env->isolate,
2179                                            reinterpret_cast<uint8_t*>(buf),
2180                                            0,
2181                                            bufsize - 1,
2182                                            v8::String::NO_NULL_TERMINATION);
2183 
2184     buf[copied] = '\0';
2185     if (result != nullptr) {
2186       *result = copied;
2187     }
2188   } else if (result != nullptr) {
2189     *result = 0;
2190   }
2191 
2192   return napi_clear_last_error(env);
2193 }
2194 
2195 // Copies a JavaScript string into a UTF-8 string buffer. The result is the
2196 // number of bytes (excluding the null terminator) copied into buf.
2197 // A sufficient buffer size should be greater than the length of string,
2198 // reserving space for null terminator.
2199 // If bufsize is insufficient, the string will be truncated and null terminated.
2200 // If buf is NULL, this method returns the length of the string (in bytes)
2201 // via the result parameter.
2202 // 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)2203 napi_status napi_get_value_string_utf8(napi_env env,
2204                                        napi_value value,
2205                                        char* buf,
2206                                        size_t bufsize,
2207                                        size_t* result) {
2208   CHECK_ENV(env);
2209   CHECK_ARG(env, value);
2210 
2211   v8::Local<v8::Value> val = v8impl::V8LocalValueFromJsValue(value);
2212   RETURN_STATUS_IF_FALSE(env, val->IsString(), napi_string_expected);
2213 
2214   if (!buf) {
2215     CHECK_ARG(env, result);
2216     *result = val.As<v8::String>()->Utf8Length(env->isolate);
2217   } else if (bufsize != 0) {
2218     int copied = val.As<v8::String>()->WriteUtf8(
2219         env->isolate,
2220         buf,
2221         bufsize - 1,
2222         nullptr,
2223         v8::String::REPLACE_INVALID_UTF8 | v8::String::NO_NULL_TERMINATION);
2224 
2225     buf[copied] = '\0';
2226     if (result != nullptr) {
2227       *result = copied;
2228     }
2229   } else if (result != nullptr) {
2230     *result = 0;
2231   }
2232 
2233   return napi_clear_last_error(env);
2234 }
2235 
2236 // Copies a JavaScript string into a UTF-16 string buffer. The result is the
2237 // number of 2-byte code units (excluding the null terminator) copied into buf.
2238 // A sufficient buffer size should be greater than the length of string,
2239 // reserving space for null terminator.
2240 // If bufsize is insufficient, the string will be truncated and null terminated.
2241 // If buf is NULL, this method returns the length of the string (in 2-byte
2242 // code units) via the result parameter.
2243 // 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)2244 napi_status napi_get_value_string_utf16(napi_env env,
2245                                         napi_value value,
2246                                         char16_t* buf,
2247                                         size_t bufsize,
2248                                         size_t* result) {
2249   CHECK_ENV(env);
2250   CHECK_ARG(env, value);
2251 
2252   v8::Local<v8::Value> val = v8impl::V8LocalValueFromJsValue(value);
2253   RETURN_STATUS_IF_FALSE(env, val->IsString(), napi_string_expected);
2254 
2255   if (!buf) {
2256     CHECK_ARG(env, result);
2257     // V8 assumes UTF-16 length is the same as the number of characters.
2258     *result = val.As<v8::String>()->Length();
2259   } else if (bufsize != 0) {
2260     int copied = val.As<v8::String>()->Write(env->isolate,
2261                                              reinterpret_cast<uint16_t*>(buf),
2262                                              0,
2263                                              bufsize - 1,
2264                                              v8::String::NO_NULL_TERMINATION);
2265 
2266     buf[copied] = '\0';
2267     if (result != nullptr) {
2268       *result = copied;
2269     }
2270   } else if (result != nullptr) {
2271     *result = 0;
2272   }
2273 
2274   return napi_clear_last_error(env);
2275 }
2276 
napi_coerce_to_bool(napi_env env,napi_value value,napi_value * result)2277 napi_status napi_coerce_to_bool(napi_env env,
2278                                 napi_value value,
2279                                 napi_value* result) {
2280   NAPI_PREAMBLE(env);
2281   CHECK_ARG(env, value);
2282   CHECK_ARG(env, result);
2283 
2284   v8::Isolate* isolate = env->isolate;
2285   v8::Local<v8::Boolean> b =
2286     v8impl::V8LocalValueFromJsValue(value)->ToBoolean(isolate);
2287   *result = v8impl::JsValueFromV8LocalValue(b);
2288   return GET_RETURN_STATUS(env);
2289 }
2290 
2291 #define GEN_COERCE_FUNCTION(UpperCaseName, MixedCaseName, LowerCaseName)      \
2292   napi_status napi_coerce_to_##LowerCaseName(napi_env env,                    \
2293                                              napi_value value,                \
2294                                              napi_value* result) {            \
2295     NAPI_PREAMBLE(env);                                                       \
2296     CHECK_ARG(env, value);                                                    \
2297     CHECK_ARG(env, result);                                                   \
2298                                                                               \
2299     v8::Local<v8::Context> context = env->context();                          \
2300     v8::Local<v8::MixedCaseName> str;                                         \
2301                                                                               \
2302     CHECK_TO_##UpperCaseName(env, context, str, value);                       \
2303                                                                               \
2304     *result = v8impl::JsValueFromV8LocalValue(str);                           \
2305     return GET_RETURN_STATUS(env);                                            \
2306   }
2307 
GEN_COERCE_FUNCTION(NUMBER,Number,number)2308 GEN_COERCE_FUNCTION(NUMBER, Number, number)
2309 GEN_COERCE_FUNCTION(OBJECT, Object, object)
2310 GEN_COERCE_FUNCTION(STRING, String, string)
2311 
2312 #undef GEN_COERCE_FUNCTION
2313 
2314 napi_status napi_wrap(napi_env env,
2315                       napi_value js_object,
2316                       void* native_object,
2317                       napi_finalize finalize_cb,
2318                       void* finalize_hint,
2319                       napi_ref* result) {
2320   return v8impl::Wrap<v8impl::retrievable>(env,
2321                                            js_object,
2322                                            native_object,
2323                                            finalize_cb,
2324                                            finalize_hint,
2325                                            result);
2326 }
2327 
napi_unwrap(napi_env env,napi_value obj,void ** result)2328 napi_status napi_unwrap(napi_env env, napi_value obj, void** result) {
2329   return v8impl::Unwrap(env, obj, result, v8impl::KeepWrap);
2330 }
2331 
napi_remove_wrap(napi_env env,napi_value obj,void ** result)2332 napi_status napi_remove_wrap(napi_env env, napi_value obj, void** result) {
2333   return v8impl::Unwrap(env, obj, result, v8impl::RemoveWrap);
2334 }
2335 
napi_create_external(napi_env env,void * data,napi_finalize finalize_cb,void * finalize_hint,napi_value * result)2336 napi_status napi_create_external(napi_env env,
2337                                  void* data,
2338                                  napi_finalize finalize_cb,
2339                                  void* finalize_hint,
2340                                  napi_value* result) {
2341   NAPI_PREAMBLE(env);
2342   CHECK_ARG(env, result);
2343 
2344   v8::Isolate* isolate = env->isolate;
2345 
2346   v8::Local<v8::Value> external_value = v8::External::New(isolate, data);
2347 
2348   // The Reference object will delete itself after invoking the finalizer
2349   // callback.
2350   v8impl::Reference::New(env,
2351       external_value,
2352       0,
2353       true,
2354       finalize_cb,
2355       data,
2356       finalize_hint);
2357 
2358   *result = v8impl::JsValueFromV8LocalValue(external_value);
2359 
2360   return napi_clear_last_error(env);
2361 }
2362 
napi_type_tag_object(napi_env env,napi_value object,const napi_type_tag * type_tag)2363 NAPI_EXTERN napi_status napi_type_tag_object(napi_env env,
2364                                              napi_value object,
2365                                              const napi_type_tag* type_tag) {
2366   NAPI_PREAMBLE(env);
2367   v8::Local<v8::Context> context = env->context();
2368   v8::Local<v8::Object> obj;
2369   CHECK_TO_OBJECT_WITH_PREAMBLE(env, context, obj, object);
2370   CHECK_ARG_WITH_PREAMBLE(env, type_tag);
2371 
2372   auto key = NAPI_PRIVATE_KEY(context, type_tag);
2373   auto maybe_has = obj->HasPrivate(context, key);
2374   CHECK_MAYBE_NOTHING_WITH_PREAMBLE(env, maybe_has, napi_generic_failure);
2375   RETURN_STATUS_IF_FALSE_WITH_PREAMBLE(env,
2376                                        !maybe_has.FromJust(),
2377                                        napi_invalid_arg);
2378 
2379   auto tag = v8::BigInt::NewFromWords(context,
2380                                    0,
2381                                    2,
2382                                    reinterpret_cast<const uint64_t*>(type_tag));
2383   CHECK_MAYBE_EMPTY_WITH_PREAMBLE(env, tag, napi_generic_failure);
2384 
2385   auto maybe_set = obj->SetPrivate(context, key, tag.ToLocalChecked());
2386   CHECK_MAYBE_NOTHING_WITH_PREAMBLE(env, maybe_set, napi_generic_failure);
2387   RETURN_STATUS_IF_FALSE_WITH_PREAMBLE(env,
2388                                        maybe_set.FromJust(),
2389                                        napi_generic_failure);
2390 
2391   return GET_RETURN_STATUS(env);
2392 }
2393 
2394 NAPI_EXTERN napi_status
napi_check_object_type_tag(napi_env env,napi_value object,const napi_type_tag * type_tag,bool * result)2395 napi_check_object_type_tag(napi_env env,
2396                            napi_value object,
2397                            const napi_type_tag* type_tag,
2398                            bool* result) {
2399   NAPI_PREAMBLE(env);
2400   v8::Local<v8::Context> context = env->context();
2401   v8::Local<v8::Object> obj;
2402   CHECK_TO_OBJECT_WITH_PREAMBLE(env, context, obj, object);
2403   CHECK_ARG_WITH_PREAMBLE(env, type_tag);
2404   CHECK_ARG_WITH_PREAMBLE(env, result);
2405 
2406   auto maybe_value = obj->GetPrivate(context,
2407                                      NAPI_PRIVATE_KEY(context, type_tag));
2408   CHECK_MAYBE_EMPTY_WITH_PREAMBLE(env, maybe_value, napi_generic_failure);
2409   v8::Local<v8::Value> val = maybe_value.ToLocalChecked();
2410 
2411   // We consider the type check to have failed unless we reach the line below
2412   // where we set whether the type check succeeded or not based on the
2413   // comparison of the two type tags.
2414   *result = false;
2415   if (val->IsBigInt()) {
2416     int sign;
2417     int size = 2;
2418     napi_type_tag tag;
2419     val.As<v8::BigInt>()->ToWordsArray(&sign,
2420                                        &size,
2421                                        reinterpret_cast<uint64_t*>(&tag));
2422     if (size == 2 && sign == 0)
2423       *result = (tag.lower == type_tag->lower && tag.upper == type_tag->upper);
2424   }
2425 
2426   return GET_RETURN_STATUS(env);
2427 }
2428 
napi_get_value_external(napi_env env,napi_value value,void ** result)2429 napi_status napi_get_value_external(napi_env env,
2430                                     napi_value value,
2431                                     void** result) {
2432   CHECK_ENV(env);
2433   CHECK_ARG(env, value);
2434   CHECK_ARG(env, result);
2435 
2436   v8::Local<v8::Value> val = v8impl::V8LocalValueFromJsValue(value);
2437   RETURN_STATUS_IF_FALSE(env, val->IsExternal(), napi_invalid_arg);
2438 
2439   v8::Local<v8::External> external_value = val.As<v8::External>();
2440   *result = external_value->Value();
2441 
2442   return napi_clear_last_error(env);
2443 }
2444 
2445 // 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)2446 napi_status napi_create_reference(napi_env env,
2447                                   napi_value value,
2448                                   uint32_t initial_refcount,
2449                                   napi_ref* result) {
2450   // Omit NAPI_PREAMBLE and GET_RETURN_STATUS because V8 calls here cannot throw
2451   // JS exceptions.
2452   CHECK_ENV(env);
2453   CHECK_ARG(env, value);
2454   CHECK_ARG(env, result);
2455 
2456   v8::Local<v8::Value> v8_value = v8impl::V8LocalValueFromJsValue(value);
2457   if (!(v8_value->IsObject() || v8_value->IsFunction() ||
2458         v8_value->IsSymbol())) {
2459     return napi_set_last_error(env, napi_invalid_arg);
2460   }
2461 
2462   v8impl::Reference* reference =
2463       v8impl::Reference::New(env, v8_value, initial_refcount, false);
2464 
2465   *result = reinterpret_cast<napi_ref>(reference);
2466   return napi_clear_last_error(env);
2467 }
2468 
2469 // Deletes a reference. The referenced value is released, and may be GC'd unless
2470 // there are other references to it.
napi_delete_reference(napi_env env,napi_ref ref)2471 napi_status napi_delete_reference(napi_env env, napi_ref ref) {
2472   // Omit NAPI_PREAMBLE and GET_RETURN_STATUS because V8 calls here cannot throw
2473   // JS exceptions.
2474   CHECK_ENV(env);
2475   CHECK_ARG(env, ref);
2476 
2477   v8impl::Reference::Delete(reinterpret_cast<v8impl::Reference*>(ref));
2478 
2479   return napi_clear_last_error(env);
2480 }
2481 
2482 // Increments the reference count, optionally returning the resulting count.
2483 // After this call the reference will be a strong reference because its
2484 // refcount is >0, and the referenced object is effectively "pinned".
2485 // Calling this when the refcount is 0 and the object is unavailable
2486 // results in an error.
napi_reference_ref(napi_env env,napi_ref ref,uint32_t * result)2487 napi_status napi_reference_ref(napi_env env, napi_ref ref, uint32_t* result) {
2488   // Omit NAPI_PREAMBLE and GET_RETURN_STATUS because V8 calls here cannot throw
2489   // JS exceptions.
2490   CHECK_ENV(env);
2491   CHECK_ARG(env, ref);
2492 
2493   v8impl::Reference* reference = reinterpret_cast<v8impl::Reference*>(ref);
2494   uint32_t count = reference->Ref();
2495 
2496   if (result != nullptr) {
2497     *result = count;
2498   }
2499 
2500   return napi_clear_last_error(env);
2501 }
2502 
2503 // Decrements the reference count, optionally returning the resulting count. If
2504 // the result is 0 the reference is now weak and the object may be GC'd at any
2505 // time if there are no other references. Calling this when the refcount is
2506 // already 0 results in an error.
napi_reference_unref(napi_env env,napi_ref ref,uint32_t * result)2507 napi_status napi_reference_unref(napi_env env, napi_ref ref, uint32_t* result) {
2508   // Omit NAPI_PREAMBLE and GET_RETURN_STATUS because V8 calls here cannot throw
2509   // JS exceptions.
2510   CHECK_ENV(env);
2511   CHECK_ARG(env, ref);
2512 
2513   v8impl::Reference* reference = reinterpret_cast<v8impl::Reference*>(ref);
2514 
2515   if (reference->RefCount() == 0) {
2516     return napi_set_last_error(env, napi_generic_failure);
2517   }
2518 
2519   uint32_t count = reference->Unref();
2520 
2521   if (result != nullptr) {
2522     *result = count;
2523   }
2524 
2525   return napi_clear_last_error(env);
2526 }
2527 
2528 // Attempts to get a referenced value. If the reference is weak, the value might
2529 // no longer be available, in that case the call is still successful but the
2530 // result is NULL.
napi_get_reference_value(napi_env env,napi_ref ref,napi_value * result)2531 napi_status napi_get_reference_value(napi_env env,
2532                                      napi_ref ref,
2533                                      napi_value* result) {
2534   // Omit NAPI_PREAMBLE and GET_RETURN_STATUS because V8 calls here cannot throw
2535   // JS exceptions.
2536   CHECK_ENV(env);
2537   CHECK_ARG(env, ref);
2538   CHECK_ARG(env, result);
2539 
2540   v8impl::Reference* reference = reinterpret_cast<v8impl::Reference*>(ref);
2541   *result = v8impl::JsValueFromV8LocalValue(reference->Get());
2542 
2543   return napi_clear_last_error(env);
2544 }
2545 
napi_open_handle_scope(napi_env env,napi_handle_scope * result)2546 napi_status napi_open_handle_scope(napi_env env, napi_handle_scope* result) {
2547   // Omit NAPI_PREAMBLE and GET_RETURN_STATUS because V8 calls here cannot throw
2548   // JS exceptions.
2549   CHECK_ENV(env);
2550   CHECK_ARG(env, result);
2551 
2552   *result = v8impl::JsHandleScopeFromV8HandleScope(
2553       new v8impl::HandleScopeWrapper(env->isolate));
2554   env->open_handle_scopes++;
2555   return napi_clear_last_error(env);
2556 }
2557 
napi_close_handle_scope(napi_env env,napi_handle_scope scope)2558 napi_status napi_close_handle_scope(napi_env env, napi_handle_scope scope) {
2559   // Omit NAPI_PREAMBLE and GET_RETURN_STATUS because V8 calls here cannot throw
2560   // JS exceptions.
2561   CHECK_ENV(env);
2562   CHECK_ARG(env, scope);
2563   if (env->open_handle_scopes == 0) {
2564     return napi_handle_scope_mismatch;
2565   }
2566 
2567   env->open_handle_scopes--;
2568   delete v8impl::V8HandleScopeFromJsHandleScope(scope);
2569   return napi_clear_last_error(env);
2570 }
2571 
napi_open_escapable_handle_scope(napi_env env,napi_escapable_handle_scope * result)2572 napi_status napi_open_escapable_handle_scope(
2573     napi_env env,
2574     napi_escapable_handle_scope* result) {
2575   // Omit NAPI_PREAMBLE and GET_RETURN_STATUS because V8 calls here cannot throw
2576   // JS exceptions.
2577   CHECK_ENV(env);
2578   CHECK_ARG(env, result);
2579 
2580   *result = v8impl::JsEscapableHandleScopeFromV8EscapableHandleScope(
2581       new v8impl::EscapableHandleScopeWrapper(env->isolate));
2582   env->open_handle_scopes++;
2583   return napi_clear_last_error(env);
2584 }
2585 
napi_close_escapable_handle_scope(napi_env env,napi_escapable_handle_scope scope)2586 napi_status napi_close_escapable_handle_scope(
2587     napi_env env,
2588     napi_escapable_handle_scope scope) {
2589   // Omit NAPI_PREAMBLE and GET_RETURN_STATUS because V8 calls here cannot throw
2590   // JS exceptions.
2591   CHECK_ENV(env);
2592   CHECK_ARG(env, scope);
2593   if (env->open_handle_scopes == 0) {
2594     return napi_handle_scope_mismatch;
2595   }
2596 
2597   delete v8impl::V8EscapableHandleScopeFromJsEscapableHandleScope(scope);
2598   env->open_handle_scopes--;
2599   return napi_clear_last_error(env);
2600 }
2601 
napi_escape_handle(napi_env env,napi_escapable_handle_scope scope,napi_value escapee,napi_value * result)2602 napi_status napi_escape_handle(napi_env env,
2603                                napi_escapable_handle_scope scope,
2604                                napi_value escapee,
2605                                napi_value* result) {
2606   // Omit NAPI_PREAMBLE and GET_RETURN_STATUS because V8 calls here cannot throw
2607   // JS exceptions.
2608   CHECK_ENV(env);
2609   CHECK_ARG(env, scope);
2610   CHECK_ARG(env, escapee);
2611   CHECK_ARG(env, result);
2612 
2613   v8impl::EscapableHandleScopeWrapper* s =
2614       v8impl::V8EscapableHandleScopeFromJsEscapableHandleScope(scope);
2615   if (!s->escape_called()) {
2616     *result = v8impl::JsValueFromV8LocalValue(
2617         s->Escape(v8impl::V8LocalValueFromJsValue(escapee)));
2618     return napi_clear_last_error(env);
2619   }
2620   return napi_set_last_error(env, napi_escape_called_twice);
2621 }
2622 
napi_new_instance(napi_env env,napi_value constructor,size_t argc,const napi_value * argv,napi_value * result)2623 napi_status napi_new_instance(napi_env env,
2624                               napi_value constructor,
2625                               size_t argc,
2626                               const napi_value* argv,
2627                               napi_value* result) {
2628   NAPI_PREAMBLE(env);
2629   CHECK_ARG(env, constructor);
2630   if (argc > 0) {
2631     CHECK_ARG(env, argv);
2632   }
2633   CHECK_ARG(env, result);
2634 
2635   v8::Local<v8::Context> context = env->context();
2636 
2637   v8::Local<v8::Function> ctor;
2638   CHECK_TO_FUNCTION(env, ctor, constructor);
2639 
2640   auto maybe = ctor->NewInstance(context, argc,
2641     reinterpret_cast<v8::Local<v8::Value>*>(const_cast<napi_value*>(argv)));
2642 
2643   CHECK_MAYBE_EMPTY(env, maybe, napi_pending_exception);
2644 
2645   *result = v8impl::JsValueFromV8LocalValue(maybe.ToLocalChecked());
2646   return GET_RETURN_STATUS(env);
2647 }
2648 
napi_instanceof(napi_env env,napi_value object,napi_value constructor,bool * result)2649 napi_status napi_instanceof(napi_env env,
2650                             napi_value object,
2651                             napi_value constructor,
2652                             bool* result) {
2653   NAPI_PREAMBLE(env);
2654   CHECK_ARG(env, object);
2655   CHECK_ARG(env, result);
2656 
2657   *result = false;
2658 
2659   v8::Local<v8::Object> ctor;
2660   v8::Local<v8::Context> context = env->context();
2661 
2662   CHECK_TO_OBJECT(env, context, ctor, constructor);
2663 
2664   if (!ctor->IsFunction()) {
2665     napi_throw_type_error(env,
2666                           "ERR_NAPI_CONS_FUNCTION",
2667                           "Constructor must be a function");
2668 
2669     return napi_set_last_error(env, napi_function_expected);
2670   }
2671 
2672   napi_status status = napi_generic_failure;
2673 
2674   v8::Local<v8::Value> val = v8impl::V8LocalValueFromJsValue(object);
2675   auto maybe_result = val->InstanceOf(context, ctor);
2676   CHECK_MAYBE_NOTHING(env, maybe_result, status);
2677   *result = maybe_result.FromJust();
2678   return GET_RETURN_STATUS(env);
2679 }
2680 
2681 // Methods to support catching exceptions
napi_is_exception_pending(napi_env env,bool * result)2682 napi_status napi_is_exception_pending(napi_env env, bool* result) {
2683   // NAPI_PREAMBLE is not used here: this function must execute when there is a
2684   // pending exception.
2685   CHECK_ENV(env);
2686   CHECK_ARG(env, result);
2687 
2688   *result = !env->last_exception.IsEmpty();
2689   return napi_clear_last_error(env);
2690 }
2691 
napi_get_and_clear_last_exception(napi_env env,napi_value * result)2692 napi_status napi_get_and_clear_last_exception(napi_env env,
2693                                               napi_value* result) {
2694   // NAPI_PREAMBLE is not used here: this function must execute when there is a
2695   // pending exception.
2696   CHECK_ENV(env);
2697   CHECK_ARG(env, result);
2698 
2699   if (env->last_exception.IsEmpty()) {
2700     return napi_get_undefined(env, result);
2701   } else {
2702     *result = v8impl::JsValueFromV8LocalValue(
2703       v8::Local<v8::Value>::New(env->isolate, env->last_exception));
2704     env->last_exception.Reset();
2705   }
2706 
2707   return napi_clear_last_error(env);
2708 }
2709 
napi_is_arraybuffer(napi_env env,napi_value value,bool * result)2710 napi_status napi_is_arraybuffer(napi_env env, napi_value value, bool* result) {
2711   CHECK_ENV(env);
2712   CHECK_ARG(env, value);
2713   CHECK_ARG(env, result);
2714 
2715   v8::Local<v8::Value> val = v8impl::V8LocalValueFromJsValue(value);
2716   *result = val->IsArrayBuffer();
2717 
2718   return napi_clear_last_error(env);
2719 }
2720 
napi_create_arraybuffer(napi_env env,size_t byte_length,void ** data,napi_value * result)2721 napi_status napi_create_arraybuffer(napi_env env,
2722                                     size_t byte_length,
2723                                     void** data,
2724                                     napi_value* result) {
2725   NAPI_PREAMBLE(env);
2726   CHECK_ARG(env, result);
2727 
2728   v8::Isolate* isolate = env->isolate;
2729   v8::Local<v8::ArrayBuffer> buffer =
2730       v8::ArrayBuffer::New(isolate, byte_length);
2731 
2732   // Optionally return a pointer to the buffer's data, to avoid another call to
2733   // retrieve it.
2734   if (data != nullptr) {
2735     *data = buffer->GetBackingStore()->Data();
2736   }
2737 
2738   *result = v8impl::JsValueFromV8LocalValue(buffer);
2739   return GET_RETURN_STATUS(env);
2740 }
2741 
napi_create_external_arraybuffer(napi_env env,void * external_data,size_t byte_length,napi_finalize finalize_cb,void * finalize_hint,napi_value * result)2742 napi_status napi_create_external_arraybuffer(napi_env env,
2743                                              void* external_data,
2744                                              size_t byte_length,
2745                                              napi_finalize finalize_cb,
2746                                              void* finalize_hint,
2747                                              napi_value* result) {
2748   // The API contract here is that the cleanup function runs on the JS thread,
2749   // and is able to use napi_env. Implementing that properly is hard, so use the
2750   // `Buffer` variant for easier implementation.
2751   napi_value buffer;
2752   STATUS_CALL(napi_create_external_buffer(
2753       env,
2754       byte_length,
2755       external_data,
2756       finalize_cb,
2757       finalize_hint,
2758       &buffer));
2759   return napi_get_typedarray_info(
2760       env,
2761       buffer,
2762       nullptr,
2763       nullptr,
2764       nullptr,
2765       result,
2766       nullptr);
2767 }
2768 
napi_get_arraybuffer_info(napi_env env,napi_value arraybuffer,void ** data,size_t * byte_length)2769 napi_status napi_get_arraybuffer_info(napi_env env,
2770                                       napi_value arraybuffer,
2771                                       void** data,
2772                                       size_t* byte_length) {
2773   CHECK_ENV(env);
2774   CHECK_ARG(env, arraybuffer);
2775 
2776   v8::Local<v8::Value> value = v8impl::V8LocalValueFromJsValue(arraybuffer);
2777   RETURN_STATUS_IF_FALSE(env, value->IsArrayBuffer(), napi_invalid_arg);
2778 
2779   std::shared_ptr<v8::BackingStore> backing_store =
2780       value.As<v8::ArrayBuffer>()->GetBackingStore();
2781 
2782   if (data != nullptr) {
2783     *data = backing_store->Data();
2784   }
2785 
2786   if (byte_length != nullptr) {
2787     *byte_length = backing_store->ByteLength();
2788   }
2789 
2790   return napi_clear_last_error(env);
2791 }
2792 
napi_is_typedarray(napi_env env,napi_value value,bool * result)2793 napi_status napi_is_typedarray(napi_env env, napi_value value, bool* result) {
2794   CHECK_ENV(env);
2795   CHECK_ARG(env, value);
2796   CHECK_ARG(env, result);
2797 
2798   v8::Local<v8::Value> val = v8impl::V8LocalValueFromJsValue(value);
2799   *result = val->IsTypedArray();
2800 
2801   return napi_clear_last_error(env);
2802 }
2803 
napi_create_typedarray(napi_env env,napi_typedarray_type type,size_t length,napi_value arraybuffer,size_t byte_offset,napi_value * result)2804 napi_status napi_create_typedarray(napi_env env,
2805                                    napi_typedarray_type type,
2806                                    size_t length,
2807                                    napi_value arraybuffer,
2808                                    size_t byte_offset,
2809                                    napi_value* result) {
2810   NAPI_PREAMBLE(env);
2811   CHECK_ARG(env, arraybuffer);
2812   CHECK_ARG(env, result);
2813 
2814   v8::Local<v8::Value> value = v8impl::V8LocalValueFromJsValue(arraybuffer);
2815   RETURN_STATUS_IF_FALSE(env, value->IsArrayBuffer(), napi_invalid_arg);
2816 
2817   v8::Local<v8::ArrayBuffer> buffer = value.As<v8::ArrayBuffer>();
2818   v8::Local<v8::TypedArray> typedArray;
2819 
2820   switch (type) {
2821     case napi_int8_array:
2822       CREATE_TYPED_ARRAY(
2823           env, Int8Array, 1, buffer, byte_offset, length, typedArray);
2824       break;
2825     case napi_uint8_array:
2826       CREATE_TYPED_ARRAY(
2827           env, Uint8Array, 1, buffer, byte_offset, length, typedArray);
2828       break;
2829     case napi_uint8_clamped_array:
2830       CREATE_TYPED_ARRAY(
2831           env, Uint8ClampedArray, 1, buffer, byte_offset, length, typedArray);
2832       break;
2833     case napi_int16_array:
2834       CREATE_TYPED_ARRAY(
2835           env, Int16Array, 2, buffer, byte_offset, length, typedArray);
2836       break;
2837     case napi_uint16_array:
2838       CREATE_TYPED_ARRAY(
2839           env, Uint16Array, 2, buffer, byte_offset, length, typedArray);
2840       break;
2841     case napi_int32_array:
2842       CREATE_TYPED_ARRAY(
2843           env, Int32Array, 4, buffer, byte_offset, length, typedArray);
2844       break;
2845     case napi_uint32_array:
2846       CREATE_TYPED_ARRAY(
2847           env, Uint32Array, 4, buffer, byte_offset, length, typedArray);
2848       break;
2849     case napi_float32_array:
2850       CREATE_TYPED_ARRAY(
2851           env, Float32Array, 4, buffer, byte_offset, length, typedArray);
2852       break;
2853     case napi_float64_array:
2854       CREATE_TYPED_ARRAY(
2855           env, Float64Array, 8, buffer, byte_offset, length, typedArray);
2856       break;
2857     case napi_bigint64_array:
2858       CREATE_TYPED_ARRAY(
2859           env, BigInt64Array, 8, buffer, byte_offset, length, typedArray);
2860       break;
2861     case napi_biguint64_array:
2862       CREATE_TYPED_ARRAY(
2863           env, BigUint64Array, 8, buffer, byte_offset, length, typedArray);
2864       break;
2865     default:
2866       return napi_set_last_error(env, napi_invalid_arg);
2867   }
2868 
2869   *result = v8impl::JsValueFromV8LocalValue(typedArray);
2870   return GET_RETURN_STATUS(env);
2871 }
2872 
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)2873 napi_status napi_get_typedarray_info(napi_env env,
2874                                      napi_value typedarray,
2875                                      napi_typedarray_type* type,
2876                                      size_t* length,
2877                                      void** data,
2878                                      napi_value* arraybuffer,
2879                                      size_t* byte_offset) {
2880   CHECK_ENV(env);
2881   CHECK_ARG(env, typedarray);
2882 
2883   v8::Local<v8::Value> value = v8impl::V8LocalValueFromJsValue(typedarray);
2884   RETURN_STATUS_IF_FALSE(env, value->IsTypedArray(), napi_invalid_arg);
2885 
2886   v8::Local<v8::TypedArray> array = value.As<v8::TypedArray>();
2887 
2888   if (type != nullptr) {
2889     if (value->IsInt8Array()) {
2890       *type = napi_int8_array;
2891     } else if (value->IsUint8Array()) {
2892       *type = napi_uint8_array;
2893     } else if (value->IsUint8ClampedArray()) {
2894       *type = napi_uint8_clamped_array;
2895     } else if (value->IsInt16Array()) {
2896       *type = napi_int16_array;
2897     } else if (value->IsUint16Array()) {
2898       *type = napi_uint16_array;
2899     } else if (value->IsInt32Array()) {
2900       *type = napi_int32_array;
2901     } else if (value->IsUint32Array()) {
2902       *type = napi_uint32_array;
2903     } else if (value->IsFloat32Array()) {
2904       *type = napi_float32_array;
2905     } else if (value->IsFloat64Array()) {
2906       *type = napi_float64_array;
2907     } else if (value->IsBigInt64Array()) {
2908       *type = napi_bigint64_array;
2909     } else if (value->IsBigUint64Array()) {
2910       *type = napi_biguint64_array;
2911     }
2912   }
2913 
2914   if (length != nullptr) {
2915     *length = array->Length();
2916   }
2917 
2918   v8::Local<v8::ArrayBuffer> buffer;
2919   if (data != nullptr || arraybuffer != nullptr) {
2920     // Calling Buffer() may have the side effect of allocating the buffer,
2921     // so only do this when it’s needed.
2922     buffer = array->Buffer();
2923   }
2924 
2925   if (data != nullptr) {
2926     *data = static_cast<uint8_t*>(buffer->GetBackingStore()->Data()) +
2927             array->ByteOffset();
2928   }
2929 
2930   if (arraybuffer != nullptr) {
2931     *arraybuffer = v8impl::JsValueFromV8LocalValue(buffer);
2932   }
2933 
2934   if (byte_offset != nullptr) {
2935     *byte_offset = array->ByteOffset();
2936   }
2937 
2938   return napi_clear_last_error(env);
2939 }
2940 
napi_create_dataview(napi_env env,size_t byte_length,napi_value arraybuffer,size_t byte_offset,napi_value * result)2941 napi_status napi_create_dataview(napi_env env,
2942                                  size_t byte_length,
2943                                  napi_value arraybuffer,
2944                                  size_t byte_offset,
2945                                  napi_value* result) {
2946   NAPI_PREAMBLE(env);
2947   CHECK_ARG(env, arraybuffer);
2948   CHECK_ARG(env, result);
2949 
2950   v8::Local<v8::Value> value = v8impl::V8LocalValueFromJsValue(arraybuffer);
2951   RETURN_STATUS_IF_FALSE(env, value->IsArrayBuffer(), napi_invalid_arg);
2952 
2953   v8::Local<v8::ArrayBuffer> buffer = value.As<v8::ArrayBuffer>();
2954   if (byte_length + byte_offset > buffer->ByteLength()) {
2955     napi_throw_range_error(
2956         env,
2957         "ERR_NAPI_INVALID_DATAVIEW_ARGS",
2958         "byte_offset + byte_length should be less than or "
2959         "equal to the size in bytes of the array passed in");
2960     return napi_set_last_error(env, napi_pending_exception);
2961   }
2962   v8::Local<v8::DataView> DataView = v8::DataView::New(buffer, byte_offset,
2963                                                        byte_length);
2964 
2965   *result = v8impl::JsValueFromV8LocalValue(DataView);
2966   return GET_RETURN_STATUS(env);
2967 }
2968 
napi_is_dataview(napi_env env,napi_value value,bool * result)2969 napi_status napi_is_dataview(napi_env env, napi_value value, bool* result) {
2970   CHECK_ENV(env);
2971   CHECK_ARG(env, value);
2972   CHECK_ARG(env, result);
2973 
2974   v8::Local<v8::Value> val = v8impl::V8LocalValueFromJsValue(value);
2975   *result = val->IsDataView();
2976 
2977   return napi_clear_last_error(env);
2978 }
2979 
napi_get_dataview_info(napi_env env,napi_value dataview,size_t * byte_length,void ** data,napi_value * arraybuffer,size_t * byte_offset)2980 napi_status napi_get_dataview_info(napi_env env,
2981                                    napi_value dataview,
2982                                    size_t* byte_length,
2983                                    void** data,
2984                                    napi_value* arraybuffer,
2985                                    size_t* byte_offset) {
2986   CHECK_ENV(env);
2987   CHECK_ARG(env, dataview);
2988 
2989   v8::Local<v8::Value> value = v8impl::V8LocalValueFromJsValue(dataview);
2990   RETURN_STATUS_IF_FALSE(env, value->IsDataView(), napi_invalid_arg);
2991 
2992   v8::Local<v8::DataView> array = value.As<v8::DataView>();
2993 
2994   if (byte_length != nullptr) {
2995     *byte_length = array->ByteLength();
2996   }
2997 
2998   v8::Local<v8::ArrayBuffer> buffer;
2999   if (data != nullptr || arraybuffer != nullptr) {
3000     // Calling Buffer() may have the side effect of allocating the buffer,
3001     // so only do this when it’s needed.
3002     buffer = array->Buffer();
3003   }
3004 
3005   if (data != nullptr) {
3006     *data = static_cast<uint8_t*>(buffer->GetBackingStore()->Data()) +
3007             array->ByteOffset();
3008   }
3009 
3010   if (arraybuffer != nullptr) {
3011     *arraybuffer = v8impl::JsValueFromV8LocalValue(buffer);
3012   }
3013 
3014   if (byte_offset != nullptr) {
3015     *byte_offset = array->ByteOffset();
3016   }
3017 
3018   return napi_clear_last_error(env);
3019 }
3020 
napi_get_version(napi_env env,uint32_t * result)3021 napi_status napi_get_version(napi_env env, uint32_t* result) {
3022   CHECK_ENV(env);
3023   CHECK_ARG(env, result);
3024   *result = NAPI_VERSION;
3025   return napi_clear_last_error(env);
3026 }
3027 
napi_create_promise(napi_env env,napi_deferred * deferred,napi_value * promise)3028 napi_status napi_create_promise(napi_env env,
3029                                 napi_deferred* deferred,
3030                                 napi_value* promise) {
3031   NAPI_PREAMBLE(env);
3032   CHECK_ARG(env, deferred);
3033   CHECK_ARG(env, promise);
3034 
3035   auto maybe = v8::Promise::Resolver::New(env->context());
3036   CHECK_MAYBE_EMPTY(env, maybe, napi_generic_failure);
3037 
3038   auto v8_resolver = maybe.ToLocalChecked();
3039   auto v8_deferred = new v8impl::Persistent<v8::Value>();
3040   v8_deferred->Reset(env->isolate, v8_resolver);
3041 
3042   *deferred = v8impl::JsDeferredFromNodePersistent(v8_deferred);
3043   *promise = v8impl::JsValueFromV8LocalValue(v8_resolver->GetPromise());
3044   return GET_RETURN_STATUS(env);
3045 }
3046 
napi_resolve_deferred(napi_env env,napi_deferred deferred,napi_value resolution)3047 napi_status napi_resolve_deferred(napi_env env,
3048                                   napi_deferred deferred,
3049                                   napi_value resolution) {
3050   return v8impl::ConcludeDeferred(env, deferred, resolution, true);
3051 }
3052 
napi_reject_deferred(napi_env env,napi_deferred deferred,napi_value resolution)3053 napi_status napi_reject_deferred(napi_env env,
3054                                  napi_deferred deferred,
3055                                  napi_value resolution) {
3056   return v8impl::ConcludeDeferred(env, deferred, resolution, false);
3057 }
3058 
napi_is_promise(napi_env env,napi_value value,bool * is_promise)3059 napi_status napi_is_promise(napi_env env,
3060                             napi_value value,
3061                             bool* is_promise) {
3062   CHECK_ENV(env);
3063   CHECK_ARG(env, value);
3064   CHECK_ARG(env, is_promise);
3065 
3066   *is_promise = v8impl::V8LocalValueFromJsValue(value)->IsPromise();
3067 
3068   return napi_clear_last_error(env);
3069 }
3070 
napi_create_date(napi_env env,double time,napi_value * result)3071 napi_status napi_create_date(napi_env env,
3072                              double time,
3073                              napi_value* result) {
3074   NAPI_PREAMBLE(env);
3075   CHECK_ARG(env, result);
3076 
3077   v8::MaybeLocal<v8::Value> maybe_date = v8::Date::New(env->context(), time);
3078   CHECK_MAYBE_EMPTY(env, maybe_date, napi_generic_failure);
3079 
3080   *result = v8impl::JsValueFromV8LocalValue(maybe_date.ToLocalChecked());
3081 
3082   return GET_RETURN_STATUS(env);
3083 }
3084 
napi_is_date(napi_env env,napi_value value,bool * is_date)3085 napi_status napi_is_date(napi_env env,
3086                          napi_value value,
3087                          bool* is_date) {
3088   CHECK_ENV(env);
3089   CHECK_ARG(env, value);
3090   CHECK_ARG(env, is_date);
3091 
3092   *is_date = v8impl::V8LocalValueFromJsValue(value)->IsDate();
3093 
3094   return napi_clear_last_error(env);
3095 }
3096 
napi_get_date_value(napi_env env,napi_value value,double * result)3097 napi_status napi_get_date_value(napi_env env,
3098                                 napi_value value,
3099                                 double* result) {
3100   NAPI_PREAMBLE(env);
3101   CHECK_ARG(env, value);
3102   CHECK_ARG(env, result);
3103 
3104   v8::Local<v8::Value> val = v8impl::V8LocalValueFromJsValue(value);
3105   RETURN_STATUS_IF_FALSE(env, val->IsDate(), napi_date_expected);
3106 
3107   v8::Local<v8::Date> date = val.As<v8::Date>();
3108   *result = date->ValueOf();
3109 
3110   return GET_RETURN_STATUS(env);
3111 }
3112 
napi_run_script(napi_env env,napi_value script,napi_value * result)3113 napi_status napi_run_script(napi_env env,
3114                             napi_value script,
3115                             napi_value* result) {
3116   NAPI_PREAMBLE(env);
3117   CHECK_ARG(env, script);
3118   CHECK_ARG(env, result);
3119 
3120   v8::Local<v8::Value> v8_script = v8impl::V8LocalValueFromJsValue(script);
3121 
3122   if (!v8_script->IsString()) {
3123     return napi_set_last_error(env, napi_string_expected);
3124   }
3125 
3126   v8::Local<v8::Context> context = env->context();
3127 
3128   auto maybe_script = v8::Script::Compile(context,
3129       v8::Local<v8::String>::Cast(v8_script));
3130   CHECK_MAYBE_EMPTY(env, maybe_script, napi_generic_failure);
3131 
3132   auto script_result =
3133       maybe_script.ToLocalChecked()->Run(context);
3134   CHECK_MAYBE_EMPTY(env, script_result, napi_generic_failure);
3135 
3136   *result = v8impl::JsValueFromV8LocalValue(script_result.ToLocalChecked());
3137   return GET_RETURN_STATUS(env);
3138 }
3139 
napi_add_finalizer(napi_env env,napi_value js_object,void * native_object,napi_finalize finalize_cb,void * finalize_hint,napi_ref * result)3140 napi_status napi_add_finalizer(napi_env env,
3141                                napi_value js_object,
3142                                void* native_object,
3143                                napi_finalize finalize_cb,
3144                                void* finalize_hint,
3145                                napi_ref* result) {
3146   return v8impl::Wrap<v8impl::anonymous>(env,
3147                                          js_object,
3148                                          native_object,
3149                                          finalize_cb,
3150                                          finalize_hint,
3151                                          result);
3152 }
3153 
napi_adjust_external_memory(napi_env env,int64_t change_in_bytes,int64_t * adjusted_value)3154 napi_status napi_adjust_external_memory(napi_env env,
3155                                         int64_t change_in_bytes,
3156                                         int64_t* adjusted_value) {
3157   CHECK_ENV(env);
3158   CHECK_ARG(env, adjusted_value);
3159 
3160   *adjusted_value = env->isolate->AdjustAmountOfExternalAllocatedMemory(
3161       change_in_bytes);
3162 
3163   return napi_clear_last_error(env);
3164 }
3165 
napi_set_instance_data(napi_env env,void * data,napi_finalize finalize_cb,void * finalize_hint)3166 napi_status napi_set_instance_data(napi_env env,
3167                                    void* data,
3168                                    napi_finalize finalize_cb,
3169                                    void* finalize_hint) {
3170   CHECK_ENV(env);
3171 
3172   v8impl::RefBase* old_data = static_cast<v8impl::RefBase*>(env->instance_data);
3173   if (old_data != nullptr) {
3174     // Our contract so far has been to not finalize any old data there may be.
3175     // So we simply delete it.
3176     v8impl::RefBase::Delete(old_data);
3177   }
3178 
3179   env->instance_data = v8impl::RefBase::New(env,
3180                                             0,
3181                                             true,
3182                                             finalize_cb,
3183                                             data,
3184                                             finalize_hint);
3185 
3186   return napi_clear_last_error(env);
3187 }
3188 
napi_get_instance_data(napi_env env,void ** data)3189 napi_status napi_get_instance_data(napi_env env,
3190                                    void** data) {
3191   CHECK_ENV(env);
3192   CHECK_ARG(env, data);
3193 
3194   v8impl::RefBase* idata = static_cast<v8impl::RefBase*>(env->instance_data);
3195 
3196   *data = (idata == nullptr ? nullptr : idata->Data());
3197 
3198   return napi_clear_last_error(env);
3199 }
3200 
napi_detach_arraybuffer(napi_env env,napi_value arraybuffer)3201 napi_status napi_detach_arraybuffer(napi_env env, napi_value arraybuffer) {
3202   CHECK_ENV(env);
3203   CHECK_ARG(env, arraybuffer);
3204 
3205   v8::Local<v8::Value> value = v8impl::V8LocalValueFromJsValue(arraybuffer);
3206   RETURN_STATUS_IF_FALSE(
3207       env, value->IsArrayBuffer(), napi_arraybuffer_expected);
3208 
3209   v8::Local<v8::ArrayBuffer> it = value.As<v8::ArrayBuffer>();
3210   RETURN_STATUS_IF_FALSE(
3211       env, it->IsDetachable(), napi_detachable_arraybuffer_expected);
3212 
3213   it->Detach();
3214 
3215   return napi_clear_last_error(env);
3216 }
3217 
napi_is_detached_arraybuffer(napi_env env,napi_value arraybuffer,bool * result)3218 napi_status napi_is_detached_arraybuffer(napi_env env,
3219                                          napi_value arraybuffer,
3220                                          bool* result) {
3221   CHECK_ENV(env);
3222   CHECK_ARG(env, arraybuffer);
3223   CHECK_ARG(env, result);
3224 
3225   v8::Local<v8::Value> value = v8impl::V8LocalValueFromJsValue(arraybuffer);
3226 
3227   *result = value->IsArrayBuffer() &&
3228             value.As<v8::ArrayBuffer>()->GetBackingStore()->Data() == nullptr;
3229 
3230   return napi_clear_last_error(env);
3231 }
3232