• 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                                 "External buffers are not allowed",
748 };
749 
napi_get_last_error_info(napi_env env,const napi_extended_error_info ** result)750 napi_status napi_get_last_error_info(napi_env env,
751                                      const napi_extended_error_info** result) {
752   CHECK_ENV(env);
753   CHECK_ARG(env, result);
754 
755   // The value of the constant below must be updated to reference the last
756   // message in the `napi_status` enum each time a new error message is added.
757   // We don't have a napi_status_last as this would result in an ABI
758   // change each time a message was added.
759   const int last_status = napi_no_external_buffers_allowed;
760 
761   static_assert(
762       NAPI_ARRAYSIZE(error_messages) == last_status + 1,
763       "Count of error messages must match count of error values");
764   CHECK_LE(env->last_error.error_code, last_status);
765 
766   // Wait until someone requests the last error information to fetch the error
767   // message string
768   env->last_error.error_message =
769       error_messages[env->last_error.error_code];
770 
771   *result = &(env->last_error);
772   return napi_ok;
773 }
774 
napi_create_function(napi_env env,const char * utf8name,size_t length,napi_callback cb,void * callback_data,napi_value * result)775 napi_status napi_create_function(napi_env env,
776                                  const char* utf8name,
777                                  size_t length,
778                                  napi_callback cb,
779                                  void* callback_data,
780                                  napi_value* result) {
781   NAPI_PREAMBLE(env);
782   CHECK_ARG(env, result);
783   CHECK_ARG(env, cb);
784 
785   v8::Local<v8::Function> return_value;
786   v8::EscapableHandleScope scope(env->isolate);
787   v8::Local<v8::Function> fn;
788   STATUS_CALL(v8impl::FunctionCallbackWrapper::NewFunction(
789       env, cb, callback_data, &fn));
790   return_value = scope.Escape(fn);
791 
792   if (utf8name != nullptr) {
793     v8::Local<v8::String> name_string;
794     CHECK_NEW_FROM_UTF8_LEN(env, name_string, utf8name, length);
795     return_value->SetName(name_string);
796   }
797 
798   *result = v8impl::JsValueFromV8LocalValue(return_value);
799 
800   return GET_RETURN_STATUS(env);
801 }
802 
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)803 napi_status napi_define_class(napi_env env,
804                               const char* utf8name,
805                               size_t length,
806                               napi_callback constructor,
807                               void* callback_data,
808                               size_t property_count,
809                               const napi_property_descriptor* properties,
810                               napi_value* result) {
811   NAPI_PREAMBLE(env);
812   CHECK_ARG(env, result);
813   CHECK_ARG(env, constructor);
814 
815   if (property_count > 0) {
816     CHECK_ARG(env, properties);
817   }
818 
819   v8::Isolate* isolate = env->isolate;
820 
821   v8::EscapableHandleScope scope(isolate);
822   v8::Local<v8::FunctionTemplate> tpl;
823   STATUS_CALL(v8impl::FunctionCallbackWrapper::NewTemplate(
824       env, constructor, callback_data, &tpl));
825 
826   v8::Local<v8::String> name_string;
827   CHECK_NEW_FROM_UTF8_LEN(env, name_string, utf8name, length);
828   tpl->SetClassName(name_string);
829 
830   size_t static_property_count = 0;
831   for (size_t i = 0; i < property_count; i++) {
832     const napi_property_descriptor* p = properties + i;
833 
834     if ((p->attributes & napi_static) != 0) {
835       // Static properties are handled separately below.
836       static_property_count++;
837       continue;
838     }
839 
840     v8::Local<v8::Name> property_name;
841     STATUS_CALL(v8impl::V8NameFromPropertyDescriptor(env, p, &property_name));
842 
843     v8::PropertyAttribute attributes =
844         v8impl::V8PropertyAttributesFromDescriptor(p);
845 
846     // This code is similar to that in napi_define_properties(); the
847     // difference is it applies to a template instead of an object,
848     // and preferred PropertyAttribute for lack of PropertyDescriptor
849     // support on ObjectTemplate.
850     if (p->getter != nullptr || p->setter != nullptr) {
851       v8::Local<v8::FunctionTemplate> getter_tpl;
852       v8::Local<v8::FunctionTemplate> setter_tpl;
853       if (p->getter != nullptr) {
854         STATUS_CALL(v8impl::FunctionCallbackWrapper::NewTemplate(
855             env, p->getter, p->data, &getter_tpl));
856       }
857       if (p->setter != nullptr) {
858         STATUS_CALL(v8impl::FunctionCallbackWrapper::NewTemplate(
859             env, p->setter, p->data, &setter_tpl));
860       }
861 
862       tpl->PrototypeTemplate()->SetAccessorProperty(
863         property_name,
864         getter_tpl,
865         setter_tpl,
866         attributes,
867         v8::AccessControl::DEFAULT);
868     } else if (p->method != nullptr) {
869       v8::Local<v8::FunctionTemplate> t;
870       STATUS_CALL(v8impl::FunctionCallbackWrapper::NewTemplate(
871           env, p->method, p->data, &t, v8::Signature::New(isolate, tpl)));
872 
873       tpl->PrototypeTemplate()->Set(property_name, t, attributes);
874     } else {
875       v8::Local<v8::Value> value = v8impl::V8LocalValueFromJsValue(p->value);
876       tpl->PrototypeTemplate()->Set(property_name, value, attributes);
877     }
878   }
879 
880   v8::Local<v8::Context> context = env->context();
881   *result = v8impl::JsValueFromV8LocalValue(
882       scope.Escape(tpl->GetFunction(context).ToLocalChecked()));
883 
884   if (static_property_count > 0) {
885     std::vector<napi_property_descriptor> static_descriptors;
886     static_descriptors.reserve(static_property_count);
887 
888     for (size_t i = 0; i < property_count; i++) {
889       const napi_property_descriptor* p = properties + i;
890       if ((p->attributes & napi_static) != 0) {
891         static_descriptors.push_back(*p);
892       }
893     }
894 
895     STATUS_CALL(napi_define_properties(env,
896                                        *result,
897                                        static_descriptors.size(),
898                                        static_descriptors.data()));
899   }
900 
901   return GET_RETURN_STATUS(env);
902 }
903 
napi_get_property_names(napi_env env,napi_value object,napi_value * result)904 napi_status napi_get_property_names(napi_env env,
905                                     napi_value object,
906                                     napi_value* result) {
907   return napi_get_all_property_names(
908       env,
909       object,
910       napi_key_include_prototypes,
911       static_cast<napi_key_filter>(napi_key_enumerable |
912                                    napi_key_skip_symbols),
913       napi_key_numbers_to_strings,
914       result);
915 }
916 
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)917 napi_status napi_get_all_property_names(napi_env env,
918                                         napi_value object,
919                                         napi_key_collection_mode key_mode,
920                                         napi_key_filter key_filter,
921                                         napi_key_conversion key_conversion,
922                                         napi_value* result) {
923   NAPI_PREAMBLE(env);
924   CHECK_ARG(env, result);
925 
926   v8::Local<v8::Context> context = env->context();
927   v8::Local<v8::Object> obj;
928   CHECK_TO_OBJECT(env, context, obj, object);
929 
930   v8::PropertyFilter filter = v8::PropertyFilter::ALL_PROPERTIES;
931   if (key_filter & napi_key_writable) {
932     filter =
933         static_cast<v8::PropertyFilter>(filter |
934                                         v8::PropertyFilter::ONLY_WRITABLE);
935   }
936   if (key_filter & napi_key_enumerable) {
937     filter =
938         static_cast<v8::PropertyFilter>(filter |
939                                         v8::PropertyFilter::ONLY_ENUMERABLE);
940   }
941   if (key_filter & napi_key_configurable) {
942     filter =
943         static_cast<v8::PropertyFilter>(filter |
944                                         v8::PropertyFilter::ONLY_WRITABLE);
945   }
946   if (key_filter & napi_key_skip_strings) {
947     filter =
948         static_cast<v8::PropertyFilter>(filter |
949                                         v8::PropertyFilter::SKIP_STRINGS);
950   }
951   if (key_filter & napi_key_skip_symbols) {
952     filter =
953         static_cast<v8::PropertyFilter>(filter |
954                                         v8::PropertyFilter::SKIP_SYMBOLS);
955   }
956   v8::KeyCollectionMode collection_mode;
957   v8::KeyConversionMode conversion_mode;
958 
959   switch (key_mode) {
960     case napi_key_include_prototypes:
961       collection_mode = v8::KeyCollectionMode::kIncludePrototypes;
962       break;
963     case napi_key_own_only:
964       collection_mode = v8::KeyCollectionMode::kOwnOnly;
965       break;
966     default:
967       return napi_set_last_error(env, napi_invalid_arg);
968   }
969 
970   switch (key_conversion) {
971     case napi_key_keep_numbers:
972       conversion_mode = v8::KeyConversionMode::kKeepNumbers;
973       break;
974     case napi_key_numbers_to_strings:
975       conversion_mode = v8::KeyConversionMode::kConvertToString;
976       break;
977     default:
978       return napi_set_last_error(env, napi_invalid_arg);
979   }
980 
981   v8::MaybeLocal<v8::Array> maybe_all_propertynames =
982       obj->GetPropertyNames(context,
983                             collection_mode,
984                             filter,
985                             v8::IndexFilter::kIncludeIndices,
986                             conversion_mode);
987 
988   CHECK_MAYBE_EMPTY_WITH_PREAMBLE(
989       env, maybe_all_propertynames, napi_generic_failure);
990 
991   *result =
992       v8impl::JsValueFromV8LocalValue(maybe_all_propertynames.ToLocalChecked());
993   return GET_RETURN_STATUS(env);
994 }
995 
napi_set_property(napi_env env,napi_value object,napi_value key,napi_value value)996 napi_status napi_set_property(napi_env env,
997                               napi_value object,
998                               napi_value key,
999                               napi_value value) {
1000   NAPI_PREAMBLE(env);
1001   CHECK_ARG(env, key);
1002   CHECK_ARG(env, value);
1003 
1004   v8::Local<v8::Context> context = env->context();
1005   v8::Local<v8::Object> obj;
1006 
1007   CHECK_TO_OBJECT(env, context, obj, object);
1008 
1009   v8::Local<v8::Value> k = v8impl::V8LocalValueFromJsValue(key);
1010   v8::Local<v8::Value> val = v8impl::V8LocalValueFromJsValue(value);
1011 
1012   v8::Maybe<bool> set_maybe = obj->Set(context, k, val);
1013 
1014   RETURN_STATUS_IF_FALSE(env, set_maybe.FromMaybe(false), napi_generic_failure);
1015   return GET_RETURN_STATUS(env);
1016 }
1017 
napi_has_property(napi_env env,napi_value object,napi_value key,bool * result)1018 napi_status napi_has_property(napi_env env,
1019                               napi_value object,
1020                               napi_value key,
1021                               bool* result) {
1022   NAPI_PREAMBLE(env);
1023   CHECK_ARG(env, result);
1024   CHECK_ARG(env, key);
1025 
1026   v8::Local<v8::Context> context = env->context();
1027   v8::Local<v8::Object> obj;
1028 
1029   CHECK_TO_OBJECT(env, context, obj, object);
1030 
1031   v8::Local<v8::Value> k = v8impl::V8LocalValueFromJsValue(key);
1032   v8::Maybe<bool> has_maybe = obj->Has(context, k);
1033 
1034   CHECK_MAYBE_NOTHING(env, has_maybe, napi_generic_failure);
1035 
1036   *result = has_maybe.FromMaybe(false);
1037   return GET_RETURN_STATUS(env);
1038 }
1039 
napi_get_property(napi_env env,napi_value object,napi_value key,napi_value * result)1040 napi_status napi_get_property(napi_env env,
1041                               napi_value object,
1042                               napi_value key,
1043                               napi_value* result) {
1044   NAPI_PREAMBLE(env);
1045   CHECK_ARG(env, key);
1046   CHECK_ARG(env, result);
1047 
1048   v8::Local<v8::Context> context = env->context();
1049   v8::Local<v8::Value> k = v8impl::V8LocalValueFromJsValue(key);
1050   v8::Local<v8::Object> obj;
1051 
1052   CHECK_TO_OBJECT(env, context, obj, object);
1053 
1054   auto get_maybe = obj->Get(context, k);
1055 
1056   CHECK_MAYBE_EMPTY(env, get_maybe, napi_generic_failure);
1057 
1058   v8::Local<v8::Value> val = get_maybe.ToLocalChecked();
1059   *result = v8impl::JsValueFromV8LocalValue(val);
1060   return GET_RETURN_STATUS(env);
1061 }
1062 
napi_delete_property(napi_env env,napi_value object,napi_value key,bool * result)1063 napi_status napi_delete_property(napi_env env,
1064                                  napi_value object,
1065                                  napi_value key,
1066                                  bool* result) {
1067   NAPI_PREAMBLE(env);
1068   CHECK_ARG(env, key);
1069 
1070   v8::Local<v8::Context> context = env->context();
1071   v8::Local<v8::Value> k = v8impl::V8LocalValueFromJsValue(key);
1072   v8::Local<v8::Object> obj;
1073 
1074   CHECK_TO_OBJECT(env, context, obj, object);
1075   v8::Maybe<bool> delete_maybe = obj->Delete(context, k);
1076   CHECK_MAYBE_NOTHING(env, delete_maybe, napi_generic_failure);
1077 
1078   if (result != nullptr)
1079     *result = delete_maybe.FromMaybe(false);
1080 
1081   return GET_RETURN_STATUS(env);
1082 }
1083 
napi_has_own_property(napi_env env,napi_value object,napi_value key,bool * result)1084 napi_status napi_has_own_property(napi_env env,
1085                                   napi_value object,
1086                                   napi_value key,
1087                                   bool* result) {
1088   NAPI_PREAMBLE(env);
1089   CHECK_ARG(env, key);
1090   CHECK_ARG(env, result);
1091 
1092   v8::Local<v8::Context> context = env->context();
1093   v8::Local<v8::Object> obj;
1094 
1095   CHECK_TO_OBJECT(env, context, obj, object);
1096   v8::Local<v8::Value> k = v8impl::V8LocalValueFromJsValue(key);
1097   RETURN_STATUS_IF_FALSE(env, k->IsName(), napi_name_expected);
1098   v8::Maybe<bool> has_maybe = obj->HasOwnProperty(context, k.As<v8::Name>());
1099   CHECK_MAYBE_NOTHING(env, has_maybe, napi_generic_failure);
1100   *result = has_maybe.FromMaybe(false);
1101 
1102   return GET_RETURN_STATUS(env);
1103 }
1104 
napi_set_named_property(napi_env env,napi_value object,const char * utf8name,napi_value value)1105 napi_status napi_set_named_property(napi_env env,
1106                                     napi_value object,
1107                                     const char* utf8name,
1108                                     napi_value value) {
1109   NAPI_PREAMBLE(env);
1110   CHECK_ARG(env, value);
1111 
1112   v8::Local<v8::Context> context = env->context();
1113   v8::Local<v8::Object> obj;
1114 
1115   CHECK_TO_OBJECT(env, context, obj, object);
1116 
1117   v8::Local<v8::Name> key;
1118   CHECK_NEW_FROM_UTF8(env, key, utf8name);
1119 
1120   v8::Local<v8::Value> val = v8impl::V8LocalValueFromJsValue(value);
1121 
1122   v8::Maybe<bool> set_maybe = obj->Set(context, key, val);
1123 
1124   RETURN_STATUS_IF_FALSE(env, set_maybe.FromMaybe(false), napi_generic_failure);
1125   return GET_RETURN_STATUS(env);
1126 }
1127 
napi_has_named_property(napi_env env,napi_value object,const char * utf8name,bool * result)1128 napi_status napi_has_named_property(napi_env env,
1129                                     napi_value object,
1130                                     const char* utf8name,
1131                                     bool* result) {
1132   NAPI_PREAMBLE(env);
1133   CHECK_ARG(env, result);
1134 
1135   v8::Local<v8::Context> context = env->context();
1136   v8::Local<v8::Object> obj;
1137 
1138   CHECK_TO_OBJECT(env, context, obj, object);
1139 
1140   v8::Local<v8::Name> key;
1141   CHECK_NEW_FROM_UTF8(env, key, utf8name);
1142 
1143   v8::Maybe<bool> has_maybe = obj->Has(context, key);
1144 
1145   CHECK_MAYBE_NOTHING(env, has_maybe, napi_generic_failure);
1146 
1147   *result = has_maybe.FromMaybe(false);
1148   return GET_RETURN_STATUS(env);
1149 }
1150 
napi_get_named_property(napi_env env,napi_value object,const char * utf8name,napi_value * result)1151 napi_status napi_get_named_property(napi_env env,
1152                                     napi_value object,
1153                                     const char* utf8name,
1154                                     napi_value* result) {
1155   NAPI_PREAMBLE(env);
1156   CHECK_ARG(env, result);
1157 
1158   v8::Local<v8::Context> context = env->context();
1159 
1160   v8::Local<v8::Name> key;
1161   CHECK_NEW_FROM_UTF8(env, key, utf8name);
1162 
1163   v8::Local<v8::Object> obj;
1164 
1165   CHECK_TO_OBJECT(env, context, obj, object);
1166 
1167   auto get_maybe = obj->Get(context, key);
1168 
1169   CHECK_MAYBE_EMPTY(env, get_maybe, napi_generic_failure);
1170 
1171   v8::Local<v8::Value> val = get_maybe.ToLocalChecked();
1172   *result = v8impl::JsValueFromV8LocalValue(val);
1173   return GET_RETURN_STATUS(env);
1174 }
1175 
napi_set_element(napi_env env,napi_value object,uint32_t index,napi_value value)1176 napi_status napi_set_element(napi_env env,
1177                              napi_value object,
1178                              uint32_t index,
1179                              napi_value value) {
1180   NAPI_PREAMBLE(env);
1181   CHECK_ARG(env, value);
1182 
1183   v8::Local<v8::Context> context = env->context();
1184   v8::Local<v8::Object> obj;
1185 
1186   CHECK_TO_OBJECT(env, context, obj, object);
1187 
1188   v8::Local<v8::Value> val = v8impl::V8LocalValueFromJsValue(value);
1189   auto set_maybe = obj->Set(context, index, val);
1190 
1191   RETURN_STATUS_IF_FALSE(env, set_maybe.FromMaybe(false), napi_generic_failure);
1192 
1193   return GET_RETURN_STATUS(env);
1194 }
1195 
napi_has_element(napi_env env,napi_value object,uint32_t index,bool * result)1196 napi_status napi_has_element(napi_env env,
1197                              napi_value object,
1198                              uint32_t index,
1199                              bool* result) {
1200   NAPI_PREAMBLE(env);
1201   CHECK_ARG(env, result);
1202 
1203   v8::Local<v8::Context> context = env->context();
1204   v8::Local<v8::Object> obj;
1205 
1206   CHECK_TO_OBJECT(env, context, obj, object);
1207 
1208   v8::Maybe<bool> has_maybe = obj->Has(context, index);
1209 
1210   CHECK_MAYBE_NOTHING(env, has_maybe, napi_generic_failure);
1211 
1212   *result = has_maybe.FromMaybe(false);
1213   return GET_RETURN_STATUS(env);
1214 }
1215 
napi_get_element(napi_env env,napi_value object,uint32_t index,napi_value * result)1216 napi_status napi_get_element(napi_env env,
1217                              napi_value object,
1218                              uint32_t index,
1219                              napi_value* result) {
1220   NAPI_PREAMBLE(env);
1221   CHECK_ARG(env, result);
1222 
1223   v8::Local<v8::Context> context = env->context();
1224   v8::Local<v8::Object> obj;
1225 
1226   CHECK_TO_OBJECT(env, context, obj, object);
1227 
1228   auto get_maybe = obj->Get(context, index);
1229 
1230   CHECK_MAYBE_EMPTY(env, get_maybe, napi_generic_failure);
1231 
1232   *result = v8impl::JsValueFromV8LocalValue(get_maybe.ToLocalChecked());
1233   return GET_RETURN_STATUS(env);
1234 }
1235 
napi_delete_element(napi_env env,napi_value object,uint32_t index,bool * result)1236 napi_status napi_delete_element(napi_env env,
1237                                 napi_value object,
1238                                 uint32_t index,
1239                                 bool* result) {
1240   NAPI_PREAMBLE(env);
1241 
1242   v8::Local<v8::Context> context = env->context();
1243   v8::Local<v8::Object> obj;
1244 
1245   CHECK_TO_OBJECT(env, context, obj, object);
1246   v8::Maybe<bool> delete_maybe = obj->Delete(context, index);
1247   CHECK_MAYBE_NOTHING(env, delete_maybe, napi_generic_failure);
1248 
1249   if (result != nullptr)
1250     *result = delete_maybe.FromMaybe(false);
1251 
1252   return GET_RETURN_STATUS(env);
1253 }
1254 
napi_define_properties(napi_env env,napi_value object,size_t property_count,const napi_property_descriptor * properties)1255 napi_status napi_define_properties(napi_env env,
1256                                    napi_value object,
1257                                    size_t property_count,
1258                                    const napi_property_descriptor* properties) {
1259   NAPI_PREAMBLE(env);
1260   if (property_count > 0) {
1261     CHECK_ARG(env, properties);
1262   }
1263 
1264   v8::Local<v8::Context> context = env->context();
1265 
1266   v8::Local<v8::Object> obj;
1267   CHECK_TO_OBJECT(env, context, obj, object);
1268 
1269   for (size_t i = 0; i < property_count; i++) {
1270     const napi_property_descriptor* p = &properties[i];
1271 
1272     v8::Local<v8::Name> property_name;
1273     STATUS_CALL(v8impl::V8NameFromPropertyDescriptor(env, p, &property_name));
1274 
1275     if (p->getter != nullptr || p->setter != nullptr) {
1276       v8::Local<v8::Function> local_getter;
1277       v8::Local<v8::Function> local_setter;
1278 
1279       if (p->getter != nullptr) {
1280         STATUS_CALL(v8impl::FunctionCallbackWrapper::NewFunction(
1281             env, p->getter, p->data, &local_getter));
1282       }
1283       if (p->setter != nullptr) {
1284         STATUS_CALL(v8impl::FunctionCallbackWrapper::NewFunction(
1285             env, p->setter, p->data, &local_setter));
1286       }
1287 
1288       v8::PropertyDescriptor descriptor(local_getter, local_setter);
1289       descriptor.set_enumerable((p->attributes & napi_enumerable) != 0);
1290       descriptor.set_configurable((p->attributes & napi_configurable) != 0);
1291 
1292       auto define_maybe = obj->DefineProperty(context,
1293                                               property_name,
1294                                               descriptor);
1295 
1296       if (!define_maybe.FromMaybe(false)) {
1297         return napi_set_last_error(env, napi_invalid_arg);
1298       }
1299     } else if (p->method != nullptr) {
1300       v8::Local<v8::Function> method;
1301       STATUS_CALL(v8impl::FunctionCallbackWrapper::NewFunction(
1302           env, p->method, p->data, &method));
1303       v8::PropertyDescriptor descriptor(method,
1304                                         (p->attributes & napi_writable) != 0);
1305       descriptor.set_enumerable((p->attributes & napi_enumerable) != 0);
1306       descriptor.set_configurable((p->attributes & napi_configurable) != 0);
1307 
1308       auto define_maybe = obj->DefineProperty(context,
1309                                               property_name,
1310                                               descriptor);
1311 
1312       if (!define_maybe.FromMaybe(false)) {
1313         return napi_set_last_error(env, napi_generic_failure);
1314       }
1315     } else {
1316       v8::Local<v8::Value> value = v8impl::V8LocalValueFromJsValue(p->value);
1317 
1318       v8::PropertyDescriptor descriptor(value,
1319                                         (p->attributes & napi_writable) != 0);
1320       descriptor.set_enumerable((p->attributes & napi_enumerable) != 0);
1321       descriptor.set_configurable((p->attributes & napi_configurable) != 0);
1322 
1323       auto define_maybe =
1324           obj->DefineProperty(context, property_name, descriptor);
1325 
1326       if (!define_maybe.FromMaybe(false)) {
1327         return napi_set_last_error(env, napi_invalid_arg);
1328       }
1329     }
1330   }
1331 
1332   return GET_RETURN_STATUS(env);
1333 }
1334 
napi_object_freeze(napi_env env,napi_value object)1335 napi_status napi_object_freeze(napi_env env,
1336                                napi_value object) {
1337   NAPI_PREAMBLE(env);
1338 
1339   v8::Local<v8::Context> context = env->context();
1340   v8::Local<v8::Object> obj;
1341 
1342   CHECK_TO_OBJECT(env, context, obj, object);
1343 
1344   v8::Maybe<bool> set_frozen =
1345     obj->SetIntegrityLevel(context, v8::IntegrityLevel::kFrozen);
1346 
1347   RETURN_STATUS_IF_FALSE_WITH_PREAMBLE(env,
1348     set_frozen.FromMaybe(false), napi_generic_failure);
1349 
1350   return GET_RETURN_STATUS(env);
1351 }
1352 
napi_object_seal(napi_env env,napi_value object)1353 napi_status napi_object_seal(napi_env env,
1354                              napi_value object) {
1355   NAPI_PREAMBLE(env);
1356 
1357   v8::Local<v8::Context> context = env->context();
1358   v8::Local<v8::Object> obj;
1359 
1360   CHECK_TO_OBJECT(env, context, obj, object);
1361 
1362   v8::Maybe<bool> set_sealed =
1363     obj->SetIntegrityLevel(context, v8::IntegrityLevel::kSealed);
1364 
1365   RETURN_STATUS_IF_FALSE_WITH_PREAMBLE(env,
1366     set_sealed.FromMaybe(false), napi_generic_failure);
1367 
1368   return GET_RETURN_STATUS(env);
1369 }
1370 
napi_is_array(napi_env env,napi_value value,bool * result)1371 napi_status napi_is_array(napi_env env, napi_value value, bool* result) {
1372   CHECK_ENV(env);
1373   CHECK_ARG(env, value);
1374   CHECK_ARG(env, result);
1375 
1376   v8::Local<v8::Value> val = v8impl::V8LocalValueFromJsValue(value);
1377 
1378   *result = val->IsArray();
1379   return napi_clear_last_error(env);
1380 }
1381 
napi_get_array_length(napi_env env,napi_value value,uint32_t * result)1382 napi_status napi_get_array_length(napi_env env,
1383                                   napi_value value,
1384                                   uint32_t* result) {
1385   NAPI_PREAMBLE(env);
1386   CHECK_ARG(env, value);
1387   CHECK_ARG(env, result);
1388 
1389   v8::Local<v8::Value> val = v8impl::V8LocalValueFromJsValue(value);
1390   RETURN_STATUS_IF_FALSE(env, val->IsArray(), napi_array_expected);
1391 
1392   v8::Local<v8::Array> arr = val.As<v8::Array>();
1393   *result = arr->Length();
1394 
1395   return GET_RETURN_STATUS(env);
1396 }
1397 
napi_strict_equals(napi_env env,napi_value lhs,napi_value rhs,bool * result)1398 napi_status napi_strict_equals(napi_env env,
1399                                napi_value lhs,
1400                                napi_value rhs,
1401                                bool* result) {
1402   NAPI_PREAMBLE(env);
1403   CHECK_ARG(env, lhs);
1404   CHECK_ARG(env, rhs);
1405   CHECK_ARG(env, result);
1406 
1407   v8::Local<v8::Value> a = v8impl::V8LocalValueFromJsValue(lhs);
1408   v8::Local<v8::Value> b = v8impl::V8LocalValueFromJsValue(rhs);
1409 
1410   *result = a->StrictEquals(b);
1411   return GET_RETURN_STATUS(env);
1412 }
1413 
napi_get_prototype(napi_env env,napi_value object,napi_value * result)1414 napi_status napi_get_prototype(napi_env env,
1415                                napi_value object,
1416                                napi_value* result) {
1417   NAPI_PREAMBLE(env);
1418   CHECK_ARG(env, result);
1419 
1420   v8::Local<v8::Context> context = env->context();
1421 
1422   v8::Local<v8::Object> obj;
1423   CHECK_TO_OBJECT(env, context, obj, object);
1424 
1425   v8::Local<v8::Value> val = obj->GetPrototype();
1426   *result = v8impl::JsValueFromV8LocalValue(val);
1427   return GET_RETURN_STATUS(env);
1428 }
1429 
napi_create_object(napi_env env,napi_value * result)1430 napi_status napi_create_object(napi_env env, napi_value* result) {
1431   CHECK_ENV(env);
1432   CHECK_ARG(env, result);
1433 
1434   *result = v8impl::JsValueFromV8LocalValue(
1435       v8::Object::New(env->isolate));
1436 
1437   return napi_clear_last_error(env);
1438 }
1439 
napi_create_array(napi_env env,napi_value * result)1440 napi_status napi_create_array(napi_env env, napi_value* result) {
1441   CHECK_ENV(env);
1442   CHECK_ARG(env, result);
1443 
1444   *result = v8impl::JsValueFromV8LocalValue(
1445       v8::Array::New(env->isolate));
1446 
1447   return napi_clear_last_error(env);
1448 }
1449 
napi_create_array_with_length(napi_env env,size_t length,napi_value * result)1450 napi_status napi_create_array_with_length(napi_env env,
1451                                           size_t length,
1452                                           napi_value* result) {
1453   CHECK_ENV(env);
1454   CHECK_ARG(env, result);
1455 
1456   *result = v8impl::JsValueFromV8LocalValue(
1457       v8::Array::New(env->isolate, length));
1458 
1459   return napi_clear_last_error(env);
1460 }
1461 
napi_create_string_latin1(napi_env env,const char * str,size_t length,napi_value * result)1462 napi_status napi_create_string_latin1(napi_env env,
1463                                       const char* str,
1464                                       size_t length,
1465                                       napi_value* result) {
1466   CHECK_ENV(env);
1467   CHECK_ARG(env, result);
1468   RETURN_STATUS_IF_FALSE(env,
1469       (length == NAPI_AUTO_LENGTH) || length <= INT_MAX,
1470       napi_invalid_arg);
1471 
1472   auto isolate = env->isolate;
1473   auto str_maybe =
1474       v8::String::NewFromOneByte(isolate,
1475                                  reinterpret_cast<const uint8_t*>(str),
1476                                  v8::NewStringType::kNormal,
1477                                  length);
1478   CHECK_MAYBE_EMPTY(env, str_maybe, napi_generic_failure);
1479 
1480   *result = v8impl::JsValueFromV8LocalValue(str_maybe.ToLocalChecked());
1481   return napi_clear_last_error(env);
1482 }
1483 
napi_create_string_utf8(napi_env env,const char * str,size_t length,napi_value * result)1484 napi_status napi_create_string_utf8(napi_env env,
1485                                     const char* str,
1486                                     size_t length,
1487                                     napi_value* result) {
1488   CHECK_ENV(env);
1489   CHECK_ARG(env, result);
1490   RETURN_STATUS_IF_FALSE(env,
1491       (length == NAPI_AUTO_LENGTH) || length <= INT_MAX,
1492       napi_invalid_arg);
1493 
1494   auto isolate = env->isolate;
1495   auto str_maybe =
1496       v8::String::NewFromUtf8(isolate,
1497                               str,
1498                               v8::NewStringType::kNormal,
1499                               static_cast<int>(length));
1500   CHECK_MAYBE_EMPTY(env, str_maybe, napi_generic_failure);
1501   *result = v8impl::JsValueFromV8LocalValue(str_maybe.ToLocalChecked());
1502   return napi_clear_last_error(env);
1503 }
1504 
napi_create_string_utf16(napi_env env,const char16_t * str,size_t length,napi_value * result)1505 napi_status napi_create_string_utf16(napi_env env,
1506                                      const char16_t* str,
1507                                      size_t length,
1508                                      napi_value* result) {
1509   CHECK_ENV(env);
1510   CHECK_ARG(env, result);
1511   RETURN_STATUS_IF_FALSE(env,
1512       (length == NAPI_AUTO_LENGTH) || length <= INT_MAX,
1513       napi_invalid_arg);
1514 
1515   auto isolate = env->isolate;
1516   auto str_maybe =
1517       v8::String::NewFromTwoByte(isolate,
1518                                  reinterpret_cast<const uint16_t*>(str),
1519                                  v8::NewStringType::kNormal,
1520                                  length);
1521   CHECK_MAYBE_EMPTY(env, str_maybe, napi_generic_failure);
1522 
1523   *result = v8impl::JsValueFromV8LocalValue(str_maybe.ToLocalChecked());
1524   return napi_clear_last_error(env);
1525 }
1526 
napi_create_double(napi_env env,double value,napi_value * result)1527 napi_status napi_create_double(napi_env env,
1528                                double value,
1529                                napi_value* result) {
1530   CHECK_ENV(env);
1531   CHECK_ARG(env, result);
1532 
1533   *result = v8impl::JsValueFromV8LocalValue(
1534       v8::Number::New(env->isolate, value));
1535 
1536   return napi_clear_last_error(env);
1537 }
1538 
napi_create_int32(napi_env env,int32_t value,napi_value * result)1539 napi_status napi_create_int32(napi_env env,
1540                               int32_t value,
1541                               napi_value* result) {
1542   CHECK_ENV(env);
1543   CHECK_ARG(env, result);
1544 
1545   *result = v8impl::JsValueFromV8LocalValue(
1546       v8::Integer::New(env->isolate, value));
1547 
1548   return napi_clear_last_error(env);
1549 }
1550 
napi_create_uint32(napi_env env,uint32_t value,napi_value * result)1551 napi_status napi_create_uint32(napi_env env,
1552                                uint32_t value,
1553                                napi_value* result) {
1554   CHECK_ENV(env);
1555   CHECK_ARG(env, result);
1556 
1557   *result = v8impl::JsValueFromV8LocalValue(
1558       v8::Integer::NewFromUnsigned(env->isolate, value));
1559 
1560   return napi_clear_last_error(env);
1561 }
1562 
napi_create_int64(napi_env env,int64_t value,napi_value * result)1563 napi_status napi_create_int64(napi_env env,
1564                               int64_t value,
1565                               napi_value* result) {
1566   CHECK_ENV(env);
1567   CHECK_ARG(env, result);
1568 
1569   *result = v8impl::JsValueFromV8LocalValue(
1570       v8::Number::New(env->isolate, static_cast<double>(value)));
1571 
1572   return napi_clear_last_error(env);
1573 }
1574 
napi_create_bigint_int64(napi_env env,int64_t value,napi_value * result)1575 napi_status napi_create_bigint_int64(napi_env env,
1576                                      int64_t value,
1577                                      napi_value* result) {
1578   CHECK_ENV(env);
1579   CHECK_ARG(env, result);
1580 
1581   *result = v8impl::JsValueFromV8LocalValue(
1582       v8::BigInt::New(env->isolate, value));
1583 
1584   return napi_clear_last_error(env);
1585 }
1586 
napi_create_bigint_uint64(napi_env env,uint64_t value,napi_value * result)1587 napi_status napi_create_bigint_uint64(napi_env env,
1588                                       uint64_t value,
1589                                       napi_value* result) {
1590   CHECK_ENV(env);
1591   CHECK_ARG(env, result);
1592 
1593   *result = v8impl::JsValueFromV8LocalValue(
1594       v8::BigInt::NewFromUnsigned(env->isolate, value));
1595 
1596   return napi_clear_last_error(env);
1597 }
1598 
napi_create_bigint_words(napi_env env,int sign_bit,size_t word_count,const uint64_t * words,napi_value * result)1599 napi_status napi_create_bigint_words(napi_env env,
1600                                      int sign_bit,
1601                                      size_t word_count,
1602                                      const uint64_t* words,
1603                                      napi_value* result) {
1604   NAPI_PREAMBLE(env);
1605   CHECK_ARG(env, words);
1606   CHECK_ARG(env, result);
1607 
1608   v8::Local<v8::Context> context = env->context();
1609 
1610   RETURN_STATUS_IF_FALSE(
1611       env, word_count <= INT_MAX, napi_invalid_arg);
1612 
1613   v8::MaybeLocal<v8::BigInt> b = v8::BigInt::NewFromWords(
1614       context, sign_bit, word_count, words);
1615 
1616   CHECK_MAYBE_EMPTY_WITH_PREAMBLE(env, b, napi_generic_failure);
1617 
1618   *result = v8impl::JsValueFromV8LocalValue(b.ToLocalChecked());
1619   return GET_RETURN_STATUS(env);
1620 }
1621 
napi_get_boolean(napi_env env,bool value,napi_value * result)1622 napi_status napi_get_boolean(napi_env env, bool value, napi_value* result) {
1623   CHECK_ENV(env);
1624   CHECK_ARG(env, result);
1625 
1626   v8::Isolate* isolate = env->isolate;
1627 
1628   if (value) {
1629     *result = v8impl::JsValueFromV8LocalValue(v8::True(isolate));
1630   } else {
1631     *result = v8impl::JsValueFromV8LocalValue(v8::False(isolate));
1632   }
1633 
1634   return napi_clear_last_error(env);
1635 }
1636 
napi_create_symbol(napi_env env,napi_value description,napi_value * result)1637 napi_status napi_create_symbol(napi_env env,
1638                                napi_value description,
1639                                napi_value* result) {
1640   CHECK_ENV(env);
1641   CHECK_ARG(env, result);
1642 
1643   v8::Isolate* isolate = env->isolate;
1644 
1645   if (description == nullptr) {
1646     *result = v8impl::JsValueFromV8LocalValue(v8::Symbol::New(isolate));
1647   } else {
1648     v8::Local<v8::Value> desc = v8impl::V8LocalValueFromJsValue(description);
1649     RETURN_STATUS_IF_FALSE(env, desc->IsString(), napi_string_expected);
1650 
1651     *result = v8impl::JsValueFromV8LocalValue(
1652       v8::Symbol::New(isolate, desc.As<v8::String>()));
1653   }
1654 
1655   return napi_clear_last_error(env);
1656 }
1657 
set_error_code(napi_env env,v8::Local<v8::Value> error,napi_value code,const char * code_cstring)1658 static inline napi_status set_error_code(napi_env env,
1659                                          v8::Local<v8::Value> error,
1660                                          napi_value code,
1661                                          const char* code_cstring) {
1662   if ((code != nullptr) || (code_cstring != nullptr)) {
1663     v8::Local<v8::Context> context = env->context();
1664     v8::Local<v8::Object> err_object = error.As<v8::Object>();
1665 
1666     v8::Local<v8::Value> code_value = v8impl::V8LocalValueFromJsValue(code);
1667     if (code != nullptr) {
1668       code_value = v8impl::V8LocalValueFromJsValue(code);
1669       RETURN_STATUS_IF_FALSE(env, code_value->IsString(), napi_string_expected);
1670     } else {
1671       CHECK_NEW_FROM_UTF8(env, code_value, code_cstring);
1672     }
1673 
1674     v8::Local<v8::Name> code_key;
1675     CHECK_NEW_FROM_UTF8(env, code_key, "code");
1676 
1677     v8::Maybe<bool> set_maybe = err_object->Set(context, code_key, code_value);
1678     RETURN_STATUS_IF_FALSE(env,
1679                            set_maybe.FromMaybe(false),
1680                            napi_generic_failure);
1681   }
1682   return napi_ok;
1683 }
1684 
napi_create_error(napi_env env,napi_value code,napi_value msg,napi_value * result)1685 napi_status napi_create_error(napi_env env,
1686                               napi_value code,
1687                               napi_value msg,
1688                               napi_value* result) {
1689   CHECK_ENV(env);
1690   CHECK_ARG(env, msg);
1691   CHECK_ARG(env, result);
1692 
1693   v8::Local<v8::Value> message_value = v8impl::V8LocalValueFromJsValue(msg);
1694   RETURN_STATUS_IF_FALSE(env, message_value->IsString(), napi_string_expected);
1695 
1696   v8::Local<v8::Value> error_obj =
1697       v8::Exception::Error(message_value.As<v8::String>());
1698   STATUS_CALL(set_error_code(env, error_obj, code, nullptr));
1699 
1700   *result = v8impl::JsValueFromV8LocalValue(error_obj);
1701 
1702   return napi_clear_last_error(env);
1703 }
1704 
napi_create_type_error(napi_env env,napi_value code,napi_value msg,napi_value * result)1705 napi_status napi_create_type_error(napi_env env,
1706                                    napi_value code,
1707                                    napi_value msg,
1708                                    napi_value* result) {
1709   CHECK_ENV(env);
1710   CHECK_ARG(env, msg);
1711   CHECK_ARG(env, result);
1712 
1713   v8::Local<v8::Value> message_value = v8impl::V8LocalValueFromJsValue(msg);
1714   RETURN_STATUS_IF_FALSE(env, message_value->IsString(), napi_string_expected);
1715 
1716   v8::Local<v8::Value> error_obj =
1717       v8::Exception::TypeError(message_value.As<v8::String>());
1718   STATUS_CALL(set_error_code(env, error_obj, code, nullptr));
1719 
1720   *result = v8impl::JsValueFromV8LocalValue(error_obj);
1721 
1722   return napi_clear_last_error(env);
1723 }
1724 
napi_create_range_error(napi_env env,napi_value code,napi_value msg,napi_value * result)1725 napi_status napi_create_range_error(napi_env env,
1726                                     napi_value code,
1727                                     napi_value msg,
1728                                     napi_value* result) {
1729   CHECK_ENV(env);
1730   CHECK_ARG(env, msg);
1731   CHECK_ARG(env, result);
1732 
1733   v8::Local<v8::Value> message_value = v8impl::V8LocalValueFromJsValue(msg);
1734   RETURN_STATUS_IF_FALSE(env, message_value->IsString(), napi_string_expected);
1735 
1736   v8::Local<v8::Value> error_obj =
1737       v8::Exception::RangeError(message_value.As<v8::String>());
1738   STATUS_CALL(set_error_code(env, error_obj, code, nullptr));
1739 
1740   *result = v8impl::JsValueFromV8LocalValue(error_obj);
1741 
1742   return napi_clear_last_error(env);
1743 }
1744 
napi_typeof(napi_env env,napi_value value,napi_valuetype * result)1745 napi_status napi_typeof(napi_env env,
1746                         napi_value value,
1747                         napi_valuetype* result) {
1748   // Omit NAPI_PREAMBLE and GET_RETURN_STATUS because V8 calls here cannot throw
1749   // JS exceptions.
1750   CHECK_ENV(env);
1751   CHECK_ARG(env, value);
1752   CHECK_ARG(env, result);
1753 
1754   v8::Local<v8::Value> v = v8impl::V8LocalValueFromJsValue(value);
1755 
1756   if (v->IsNumber()) {
1757     *result = napi_number;
1758   } else if (v->IsBigInt()) {
1759     *result = napi_bigint;
1760   } else if (v->IsString()) {
1761     *result = napi_string;
1762   } else if (v->IsFunction()) {
1763     // This test has to come before IsObject because IsFunction
1764     // implies IsObject
1765     *result = napi_function;
1766   } else if (v->IsExternal()) {
1767     // This test has to come before IsObject because IsExternal
1768     // implies IsObject
1769     *result = napi_external;
1770   } else if (v->IsObject()) {
1771     *result = napi_object;
1772   } else if (v->IsBoolean()) {
1773     *result = napi_boolean;
1774   } else if (v->IsUndefined()) {
1775     *result = napi_undefined;
1776   } else if (v->IsSymbol()) {
1777     *result = napi_symbol;
1778   } else if (v->IsNull()) {
1779     *result = napi_null;
1780   } else {
1781     // Should not get here unless V8 has added some new kind of value.
1782     return napi_set_last_error(env, napi_invalid_arg);
1783   }
1784 
1785   return napi_clear_last_error(env);
1786 }
1787 
napi_get_undefined(napi_env env,napi_value * result)1788 napi_status napi_get_undefined(napi_env env, napi_value* result) {
1789   CHECK_ENV(env);
1790   CHECK_ARG(env, result);
1791 
1792   *result = v8impl::JsValueFromV8LocalValue(
1793       v8::Undefined(env->isolate));
1794 
1795   return napi_clear_last_error(env);
1796 }
1797 
napi_get_null(napi_env env,napi_value * result)1798 napi_status napi_get_null(napi_env env, napi_value* result) {
1799   CHECK_ENV(env);
1800   CHECK_ARG(env, result);
1801 
1802   *result = v8impl::JsValueFromV8LocalValue(
1803         v8::Null(env->isolate));
1804 
1805   return napi_clear_last_error(env);
1806 }
1807 
1808 // 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)1809 napi_status napi_get_cb_info(
1810     napi_env env,               // [in] NAPI environment handle
1811     napi_callback_info cbinfo,  // [in] Opaque callback-info handle
1812     size_t* argc,      // [in-out] Specifies the size of the provided argv array
1813                        // and receives the actual count of args.
1814     napi_value* argv,  // [out] Array of values
1815     napi_value* this_arg,  // [out] Receives the JS 'this' arg for the call
1816     void** data) {         // [out] Receives the data pointer for the callback.
1817   CHECK_ENV(env);
1818   CHECK_ARG(env, cbinfo);
1819 
1820   v8impl::CallbackWrapper* info =
1821       reinterpret_cast<v8impl::CallbackWrapper*>(cbinfo);
1822 
1823   if (argv != nullptr) {
1824     CHECK_ARG(env, argc);
1825     info->Args(argv, *argc);
1826   }
1827   if (argc != nullptr) {
1828     *argc = info->ArgsLength();
1829   }
1830   if (this_arg != nullptr) {
1831     *this_arg = info->This();
1832   }
1833   if (data != nullptr) {
1834     *data = info->Data();
1835   }
1836 
1837   return napi_clear_last_error(env);
1838 }
1839 
napi_get_new_target(napi_env env,napi_callback_info cbinfo,napi_value * result)1840 napi_status napi_get_new_target(napi_env env,
1841                                 napi_callback_info cbinfo,
1842                                 napi_value* result) {
1843   CHECK_ENV(env);
1844   CHECK_ARG(env, cbinfo);
1845   CHECK_ARG(env, result);
1846 
1847   v8impl::CallbackWrapper* info =
1848       reinterpret_cast<v8impl::CallbackWrapper*>(cbinfo);
1849 
1850   *result = info->GetNewTarget();
1851   return napi_clear_last_error(env);
1852 }
1853 
napi_call_function(napi_env env,napi_value recv,napi_value func,size_t argc,const napi_value * argv,napi_value * result)1854 napi_status napi_call_function(napi_env env,
1855                                napi_value recv,
1856                                napi_value func,
1857                                size_t argc,
1858                                const napi_value* argv,
1859                                napi_value* result) {
1860   NAPI_PREAMBLE(env);
1861   CHECK_ARG(env, recv);
1862   if (argc > 0) {
1863     CHECK_ARG(env, argv);
1864   }
1865 
1866   v8::Local<v8::Context> context = env->context();
1867 
1868   v8::Local<v8::Value> v8recv = v8impl::V8LocalValueFromJsValue(recv);
1869 
1870   v8::Local<v8::Function> v8func;
1871   CHECK_TO_FUNCTION(env, v8func, func);
1872 
1873   auto maybe = v8func->Call(context, v8recv, argc,
1874     reinterpret_cast<v8::Local<v8::Value>*>(const_cast<napi_value*>(argv)));
1875 
1876   if (try_catch.HasCaught()) {
1877     return napi_set_last_error(env, napi_pending_exception);
1878   } else {
1879     if (result != nullptr) {
1880       CHECK_MAYBE_EMPTY(env, maybe, napi_generic_failure);
1881       *result = v8impl::JsValueFromV8LocalValue(maybe.ToLocalChecked());
1882     }
1883     return napi_clear_last_error(env);
1884   }
1885 }
1886 
napi_get_global(napi_env env,napi_value * result)1887 napi_status napi_get_global(napi_env env, napi_value* result) {
1888   CHECK_ENV(env);
1889   CHECK_ARG(env, result);
1890 
1891   *result = v8impl::JsValueFromV8LocalValue(env->context()->Global());
1892 
1893   return napi_clear_last_error(env);
1894 }
1895 
napi_throw(napi_env env,napi_value error)1896 napi_status napi_throw(napi_env env, napi_value error) {
1897   NAPI_PREAMBLE(env);
1898   CHECK_ARG(env, error);
1899 
1900   v8::Isolate* isolate = env->isolate;
1901 
1902   isolate->ThrowException(v8impl::V8LocalValueFromJsValue(error));
1903   // any VM calls after this point and before returning
1904   // to the javascript invoker will fail
1905   return napi_clear_last_error(env);
1906 }
1907 
napi_throw_error(napi_env env,const char * code,const char * msg)1908 napi_status napi_throw_error(napi_env env,
1909                              const char* code,
1910                              const char* msg) {
1911   NAPI_PREAMBLE(env);
1912 
1913   v8::Isolate* isolate = env->isolate;
1914   v8::Local<v8::String> str;
1915   CHECK_NEW_FROM_UTF8(env, str, msg);
1916 
1917   v8::Local<v8::Value> error_obj = v8::Exception::Error(str);
1918   STATUS_CALL(set_error_code(env, error_obj, nullptr, code));
1919 
1920   isolate->ThrowException(error_obj);
1921   // any VM calls after this point and before returning
1922   // to the javascript invoker will fail
1923   return napi_clear_last_error(env);
1924 }
1925 
napi_throw_type_error(napi_env env,const char * code,const char * msg)1926 napi_status napi_throw_type_error(napi_env env,
1927                                   const char* code,
1928                                   const char* msg) {
1929   NAPI_PREAMBLE(env);
1930 
1931   v8::Isolate* isolate = env->isolate;
1932   v8::Local<v8::String> str;
1933   CHECK_NEW_FROM_UTF8(env, str, msg);
1934 
1935   v8::Local<v8::Value> error_obj = v8::Exception::TypeError(str);
1936   STATUS_CALL(set_error_code(env, error_obj, nullptr, code));
1937 
1938   isolate->ThrowException(error_obj);
1939   // any VM calls after this point and before returning
1940   // to the javascript invoker will fail
1941   return napi_clear_last_error(env);
1942 }
1943 
napi_throw_range_error(napi_env env,const char * code,const char * msg)1944 napi_status napi_throw_range_error(napi_env env,
1945                                    const char* code,
1946                                    const char* msg) {
1947   NAPI_PREAMBLE(env);
1948 
1949   v8::Isolate* isolate = env->isolate;
1950   v8::Local<v8::String> str;
1951   CHECK_NEW_FROM_UTF8(env, str, msg);
1952 
1953   v8::Local<v8::Value> error_obj = v8::Exception::RangeError(str);
1954   STATUS_CALL(set_error_code(env, error_obj, nullptr, code));
1955 
1956   isolate->ThrowException(error_obj);
1957   // any VM calls after this point and before returning
1958   // to the javascript invoker will fail
1959   return napi_clear_last_error(env);
1960 }
1961 
napi_is_error(napi_env env,napi_value value,bool * result)1962 napi_status napi_is_error(napi_env env, napi_value value, bool* result) {
1963   // Omit NAPI_PREAMBLE and GET_RETURN_STATUS because V8 calls here cannot
1964   // throw JS exceptions.
1965   CHECK_ENV(env);
1966   CHECK_ARG(env, value);
1967   CHECK_ARG(env, result);
1968 
1969   v8::Local<v8::Value> val = v8impl::V8LocalValueFromJsValue(value);
1970   *result = val->IsNativeError();
1971 
1972   return napi_clear_last_error(env);
1973 }
1974 
napi_get_value_double(napi_env env,napi_value value,double * result)1975 napi_status napi_get_value_double(napi_env env,
1976                                   napi_value value,
1977                                   double* result) {
1978   // Omit NAPI_PREAMBLE and GET_RETURN_STATUS because V8 calls here cannot throw
1979   // JS exceptions.
1980   CHECK_ENV(env);
1981   CHECK_ARG(env, value);
1982   CHECK_ARG(env, result);
1983 
1984   v8::Local<v8::Value> val = v8impl::V8LocalValueFromJsValue(value);
1985   RETURN_STATUS_IF_FALSE(env, val->IsNumber(), napi_number_expected);
1986 
1987   *result = val.As<v8::Number>()->Value();
1988 
1989   return napi_clear_last_error(env);
1990 }
1991 
napi_get_value_int32(napi_env env,napi_value value,int32_t * result)1992 napi_status napi_get_value_int32(napi_env env,
1993                                  napi_value value,
1994                                  int32_t* result) {
1995   // Omit NAPI_PREAMBLE and GET_RETURN_STATUS because V8 calls here cannot throw
1996   // JS exceptions.
1997   CHECK_ENV(env);
1998   CHECK_ARG(env, value);
1999   CHECK_ARG(env, result);
2000 
2001   v8::Local<v8::Value> val = v8impl::V8LocalValueFromJsValue(value);
2002 
2003   if (val->IsInt32()) {
2004     *result = val.As<v8::Int32>()->Value();
2005   } else {
2006     RETURN_STATUS_IF_FALSE(env, val->IsNumber(), napi_number_expected);
2007 
2008     // Empty context: https://github.com/nodejs/node/issues/14379
2009     v8::Local<v8::Context> context;
2010     *result = val->Int32Value(context).FromJust();
2011   }
2012 
2013   return napi_clear_last_error(env);
2014 }
2015 
napi_get_value_uint32(napi_env env,napi_value value,uint32_t * result)2016 napi_status napi_get_value_uint32(napi_env env,
2017                                   napi_value value,
2018                                   uint32_t* result) {
2019   // Omit NAPI_PREAMBLE and GET_RETURN_STATUS because V8 calls here cannot throw
2020   // JS exceptions.
2021   CHECK_ENV(env);
2022   CHECK_ARG(env, value);
2023   CHECK_ARG(env, result);
2024 
2025   v8::Local<v8::Value> val = v8impl::V8LocalValueFromJsValue(value);
2026 
2027   if (val->IsUint32()) {
2028     *result = val.As<v8::Uint32>()->Value();
2029   } else {
2030     RETURN_STATUS_IF_FALSE(env, val->IsNumber(), napi_number_expected);
2031 
2032     // Empty context: https://github.com/nodejs/node/issues/14379
2033     v8::Local<v8::Context> context;
2034     *result = val->Uint32Value(context).FromJust();
2035   }
2036 
2037   return napi_clear_last_error(env);
2038 }
2039 
napi_get_value_int64(napi_env env,napi_value value,int64_t * result)2040 napi_status napi_get_value_int64(napi_env env,
2041                                  napi_value value,
2042                                  int64_t* result) {
2043   // Omit NAPI_PREAMBLE and GET_RETURN_STATUS because V8 calls here cannot throw
2044   // JS exceptions.
2045   CHECK_ENV(env);
2046   CHECK_ARG(env, value);
2047   CHECK_ARG(env, result);
2048 
2049   v8::Local<v8::Value> val = v8impl::V8LocalValueFromJsValue(value);
2050 
2051   // This is still a fast path very likely to be taken.
2052   if (val->IsInt32()) {
2053     *result = val.As<v8::Int32>()->Value();
2054     return napi_clear_last_error(env);
2055   }
2056 
2057   RETURN_STATUS_IF_FALSE(env, val->IsNumber(), napi_number_expected);
2058 
2059   // v8::Value::IntegerValue() converts NaN, +Inf, and -Inf to INT64_MIN,
2060   // inconsistent with v8::Value::Int32Value() which converts those values to 0.
2061   // Special-case all non-finite values to match that behavior.
2062   double doubleValue = val.As<v8::Number>()->Value();
2063   if (std::isfinite(doubleValue)) {
2064     // Empty context: https://github.com/nodejs/node/issues/14379
2065     v8::Local<v8::Context> context;
2066     *result = val->IntegerValue(context).FromJust();
2067   } else {
2068     *result = 0;
2069   }
2070 
2071   return napi_clear_last_error(env);
2072 }
2073 
napi_get_value_bigint_int64(napi_env env,napi_value value,int64_t * result,bool * lossless)2074 napi_status napi_get_value_bigint_int64(napi_env env,
2075                                         napi_value value,
2076                                         int64_t* result,
2077                                         bool* lossless) {
2078   CHECK_ENV(env);
2079   CHECK_ARG(env, value);
2080   CHECK_ARG(env, result);
2081   CHECK_ARG(env, lossless);
2082 
2083   v8::Local<v8::Value> val = v8impl::V8LocalValueFromJsValue(value);
2084 
2085   RETURN_STATUS_IF_FALSE(env, val->IsBigInt(), napi_bigint_expected);
2086 
2087   *result = val.As<v8::BigInt>()->Int64Value(lossless);
2088 
2089   return napi_clear_last_error(env);
2090 }
2091 
napi_get_value_bigint_uint64(napi_env env,napi_value value,uint64_t * result,bool * lossless)2092 napi_status napi_get_value_bigint_uint64(napi_env env,
2093                                          napi_value value,
2094                                          uint64_t* result,
2095                                          bool* lossless) {
2096   CHECK_ENV(env);
2097   CHECK_ARG(env, value);
2098   CHECK_ARG(env, result);
2099   CHECK_ARG(env, lossless);
2100 
2101   v8::Local<v8::Value> val = v8impl::V8LocalValueFromJsValue(value);
2102 
2103   RETURN_STATUS_IF_FALSE(env, val->IsBigInt(), napi_bigint_expected);
2104 
2105   *result = val.As<v8::BigInt>()->Uint64Value(lossless);
2106 
2107   return napi_clear_last_error(env);
2108 }
2109 
napi_get_value_bigint_words(napi_env env,napi_value value,int * sign_bit,size_t * word_count,uint64_t * words)2110 napi_status napi_get_value_bigint_words(napi_env env,
2111                                         napi_value value,
2112                                         int* sign_bit,
2113                                         size_t* word_count,
2114                                         uint64_t* words) {
2115   CHECK_ENV(env);
2116   CHECK_ARG(env, value);
2117   CHECK_ARG(env, word_count);
2118 
2119   v8::Local<v8::Value> val = v8impl::V8LocalValueFromJsValue(value);
2120 
2121   RETURN_STATUS_IF_FALSE(env, val->IsBigInt(), napi_bigint_expected);
2122 
2123   v8::Local<v8::BigInt> big = val.As<v8::BigInt>();
2124 
2125   int word_count_int = *word_count;
2126 
2127   if (sign_bit == nullptr && words == nullptr) {
2128     word_count_int = big->WordCount();
2129   } else {
2130     CHECK_ARG(env, sign_bit);
2131     CHECK_ARG(env, words);
2132     big->ToWordsArray(sign_bit, &word_count_int, words);
2133   }
2134 
2135   *word_count = word_count_int;
2136 
2137   return napi_clear_last_error(env);
2138 }
2139 
napi_get_value_bool(napi_env env,napi_value value,bool * result)2140 napi_status napi_get_value_bool(napi_env env, napi_value value, bool* result) {
2141   // Omit NAPI_PREAMBLE and GET_RETURN_STATUS because V8 calls here cannot throw
2142   // JS exceptions.
2143   CHECK_ENV(env);
2144   CHECK_ARG(env, value);
2145   CHECK_ARG(env, result);
2146 
2147   v8::Local<v8::Value> val = v8impl::V8LocalValueFromJsValue(value);
2148   RETURN_STATUS_IF_FALSE(env, val->IsBoolean(), napi_boolean_expected);
2149 
2150   *result = val.As<v8::Boolean>()->Value();
2151 
2152   return napi_clear_last_error(env);
2153 }
2154 
2155 // Copies a JavaScript string into a LATIN-1 string buffer. The result is the
2156 // number of bytes (excluding the null terminator) copied into buf.
2157 // A sufficient buffer size should be greater than the length of string,
2158 // reserving space for null terminator.
2159 // If bufsize is insufficient, the string will be truncated and null terminated.
2160 // If buf is NULL, this method returns the length of the string (in bytes)
2161 // via the result parameter.
2162 // 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)2163 napi_status napi_get_value_string_latin1(napi_env env,
2164                                          napi_value value,
2165                                          char* buf,
2166                                          size_t bufsize,
2167                                          size_t* result) {
2168   CHECK_ENV(env);
2169   CHECK_ARG(env, value);
2170 
2171   v8::Local<v8::Value> val = v8impl::V8LocalValueFromJsValue(value);
2172   RETURN_STATUS_IF_FALSE(env, val->IsString(), napi_string_expected);
2173 
2174   if (!buf) {
2175     CHECK_ARG(env, result);
2176     *result = val.As<v8::String>()->Length();
2177   } else if (bufsize != 0) {
2178     int copied =
2179         val.As<v8::String>()->WriteOneByte(env->isolate,
2180                                            reinterpret_cast<uint8_t*>(buf),
2181                                            0,
2182                                            bufsize - 1,
2183                                            v8::String::NO_NULL_TERMINATION);
2184 
2185     buf[copied] = '\0';
2186     if (result != nullptr) {
2187       *result = copied;
2188     }
2189   } else if (result != nullptr) {
2190     *result = 0;
2191   }
2192 
2193   return napi_clear_last_error(env);
2194 }
2195 
2196 // Copies a JavaScript string into a UTF-8 string buffer. The result is the
2197 // number of bytes (excluding the null terminator) copied into buf.
2198 // A sufficient buffer size should be greater than the length of string,
2199 // reserving space for null terminator.
2200 // If bufsize is insufficient, the string will be truncated and null terminated.
2201 // If buf is NULL, this method returns the length of the string (in bytes)
2202 // via the result parameter.
2203 // 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)2204 napi_status napi_get_value_string_utf8(napi_env env,
2205                                        napi_value value,
2206                                        char* buf,
2207                                        size_t bufsize,
2208                                        size_t* result) {
2209   CHECK_ENV(env);
2210   CHECK_ARG(env, value);
2211 
2212   v8::Local<v8::Value> val = v8impl::V8LocalValueFromJsValue(value);
2213   RETURN_STATUS_IF_FALSE(env, val->IsString(), napi_string_expected);
2214 
2215   if (!buf) {
2216     CHECK_ARG(env, result);
2217     *result = val.As<v8::String>()->Utf8Length(env->isolate);
2218   } else if (bufsize != 0) {
2219     int copied = val.As<v8::String>()->WriteUtf8(
2220         env->isolate,
2221         buf,
2222         bufsize - 1,
2223         nullptr,
2224         v8::String::REPLACE_INVALID_UTF8 | v8::String::NO_NULL_TERMINATION);
2225 
2226     buf[copied] = '\0';
2227     if (result != nullptr) {
2228       *result = copied;
2229     }
2230   } else if (result != nullptr) {
2231     *result = 0;
2232   }
2233 
2234   return napi_clear_last_error(env);
2235 }
2236 
2237 // Copies a JavaScript string into a UTF-16 string buffer. The result is the
2238 // number of 2-byte code units (excluding the null terminator) copied into buf.
2239 // A sufficient buffer size should be greater than the length of string,
2240 // reserving space for null terminator.
2241 // If bufsize is insufficient, the string will be truncated and null terminated.
2242 // If buf is NULL, this method returns the length of the string (in 2-byte
2243 // code units) via the result parameter.
2244 // 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)2245 napi_status napi_get_value_string_utf16(napi_env env,
2246                                         napi_value value,
2247                                         char16_t* buf,
2248                                         size_t bufsize,
2249                                         size_t* result) {
2250   CHECK_ENV(env);
2251   CHECK_ARG(env, value);
2252 
2253   v8::Local<v8::Value> val = v8impl::V8LocalValueFromJsValue(value);
2254   RETURN_STATUS_IF_FALSE(env, val->IsString(), napi_string_expected);
2255 
2256   if (!buf) {
2257     CHECK_ARG(env, result);
2258     // V8 assumes UTF-16 length is the same as the number of characters.
2259     *result = val.As<v8::String>()->Length();
2260   } else if (bufsize != 0) {
2261     int copied = val.As<v8::String>()->Write(env->isolate,
2262                                              reinterpret_cast<uint16_t*>(buf),
2263                                              0,
2264                                              bufsize - 1,
2265                                              v8::String::NO_NULL_TERMINATION);
2266 
2267     buf[copied] = '\0';
2268     if (result != nullptr) {
2269       *result = copied;
2270     }
2271   } else if (result != nullptr) {
2272     *result = 0;
2273   }
2274 
2275   return napi_clear_last_error(env);
2276 }
2277 
napi_coerce_to_bool(napi_env env,napi_value value,napi_value * result)2278 napi_status napi_coerce_to_bool(napi_env env,
2279                                 napi_value value,
2280                                 napi_value* result) {
2281   NAPI_PREAMBLE(env);
2282   CHECK_ARG(env, value);
2283   CHECK_ARG(env, result);
2284 
2285   v8::Isolate* isolate = env->isolate;
2286   v8::Local<v8::Boolean> b =
2287     v8impl::V8LocalValueFromJsValue(value)->ToBoolean(isolate);
2288   *result = v8impl::JsValueFromV8LocalValue(b);
2289   return GET_RETURN_STATUS(env);
2290 }
2291 
2292 #define GEN_COERCE_FUNCTION(UpperCaseName, MixedCaseName, LowerCaseName)      \
2293   napi_status napi_coerce_to_##LowerCaseName(napi_env env,                    \
2294                                              napi_value value,                \
2295                                              napi_value* result) {            \
2296     NAPI_PREAMBLE(env);                                                       \
2297     CHECK_ARG(env, value);                                                    \
2298     CHECK_ARG(env, result);                                                   \
2299                                                                               \
2300     v8::Local<v8::Context> context = env->context();                          \
2301     v8::Local<v8::MixedCaseName> str;                                         \
2302                                                                               \
2303     CHECK_TO_##UpperCaseName(env, context, str, value);                       \
2304                                                                               \
2305     *result = v8impl::JsValueFromV8LocalValue(str);                           \
2306     return GET_RETURN_STATUS(env);                                            \
2307   }
2308 
GEN_COERCE_FUNCTION(NUMBER,Number,number)2309 GEN_COERCE_FUNCTION(NUMBER, Number, number)
2310 GEN_COERCE_FUNCTION(OBJECT, Object, object)
2311 GEN_COERCE_FUNCTION(STRING, String, string)
2312 
2313 #undef GEN_COERCE_FUNCTION
2314 
2315 napi_status napi_wrap(napi_env env,
2316                       napi_value js_object,
2317                       void* native_object,
2318                       napi_finalize finalize_cb,
2319                       void* finalize_hint,
2320                       napi_ref* result) {
2321   return v8impl::Wrap<v8impl::retrievable>(env,
2322                                            js_object,
2323                                            native_object,
2324                                            finalize_cb,
2325                                            finalize_hint,
2326                                            result);
2327 }
2328 
napi_unwrap(napi_env env,napi_value obj,void ** result)2329 napi_status napi_unwrap(napi_env env, napi_value obj, void** result) {
2330   return v8impl::Unwrap(env, obj, result, v8impl::KeepWrap);
2331 }
2332 
napi_remove_wrap(napi_env env,napi_value obj,void ** result)2333 napi_status napi_remove_wrap(napi_env env, napi_value obj, void** result) {
2334   return v8impl::Unwrap(env, obj, result, v8impl::RemoveWrap);
2335 }
2336 
napi_create_external(napi_env env,void * data,napi_finalize finalize_cb,void * finalize_hint,napi_value * result)2337 napi_status napi_create_external(napi_env env,
2338                                  void* data,
2339                                  napi_finalize finalize_cb,
2340                                  void* finalize_hint,
2341                                  napi_value* result) {
2342   NAPI_PREAMBLE(env);
2343   CHECK_ARG(env, result);
2344 
2345   v8::Isolate* isolate = env->isolate;
2346 
2347   v8::Local<v8::Value> external_value = v8::External::New(isolate, data);
2348 
2349   // The Reference object will delete itself after invoking the finalizer
2350   // callback.
2351   v8impl::Reference::New(env,
2352       external_value,
2353       0,
2354       true,
2355       finalize_cb,
2356       data,
2357       finalize_hint);
2358 
2359   *result = v8impl::JsValueFromV8LocalValue(external_value);
2360 
2361   return napi_clear_last_error(env);
2362 }
2363 
napi_type_tag_object(napi_env env,napi_value object,const napi_type_tag * type_tag)2364 NAPI_EXTERN napi_status napi_type_tag_object(napi_env env,
2365                                              napi_value object,
2366                                              const napi_type_tag* type_tag) {
2367   NAPI_PREAMBLE(env);
2368   v8::Local<v8::Context> context = env->context();
2369   v8::Local<v8::Object> obj;
2370   CHECK_TO_OBJECT_WITH_PREAMBLE(env, context, obj, object);
2371   CHECK_ARG_WITH_PREAMBLE(env, type_tag);
2372 
2373   auto key = NAPI_PRIVATE_KEY(context, type_tag);
2374   auto maybe_has = obj->HasPrivate(context, key);
2375   CHECK_MAYBE_NOTHING_WITH_PREAMBLE(env, maybe_has, napi_generic_failure);
2376   RETURN_STATUS_IF_FALSE_WITH_PREAMBLE(env,
2377                                        !maybe_has.FromJust(),
2378                                        napi_invalid_arg);
2379 
2380   auto tag = v8::BigInt::NewFromWords(context,
2381                                    0,
2382                                    2,
2383                                    reinterpret_cast<const uint64_t*>(type_tag));
2384   CHECK_MAYBE_EMPTY_WITH_PREAMBLE(env, tag, napi_generic_failure);
2385 
2386   auto maybe_set = obj->SetPrivate(context, key, tag.ToLocalChecked());
2387   CHECK_MAYBE_NOTHING_WITH_PREAMBLE(env, maybe_set, napi_generic_failure);
2388   RETURN_STATUS_IF_FALSE_WITH_PREAMBLE(env,
2389                                        maybe_set.FromJust(),
2390                                        napi_generic_failure);
2391 
2392   return GET_RETURN_STATUS(env);
2393 }
2394 
2395 NAPI_EXTERN napi_status
napi_check_object_type_tag(napi_env env,napi_value object,const napi_type_tag * type_tag,bool * result)2396 napi_check_object_type_tag(napi_env env,
2397                            napi_value object,
2398                            const napi_type_tag* type_tag,
2399                            bool* result) {
2400   NAPI_PREAMBLE(env);
2401   v8::Local<v8::Context> context = env->context();
2402   v8::Local<v8::Object> obj;
2403   CHECK_TO_OBJECT_WITH_PREAMBLE(env, context, obj, object);
2404   CHECK_ARG_WITH_PREAMBLE(env, type_tag);
2405   CHECK_ARG_WITH_PREAMBLE(env, result);
2406 
2407   auto maybe_value = obj->GetPrivate(context,
2408                                      NAPI_PRIVATE_KEY(context, type_tag));
2409   CHECK_MAYBE_EMPTY_WITH_PREAMBLE(env, maybe_value, napi_generic_failure);
2410   v8::Local<v8::Value> val = maybe_value.ToLocalChecked();
2411 
2412   // We consider the type check to have failed unless we reach the line below
2413   // where we set whether the type check succeeded or not based on the
2414   // comparison of the two type tags.
2415   *result = false;
2416   if (val->IsBigInt()) {
2417     int sign;
2418     int size = 2;
2419     napi_type_tag tag;
2420     val.As<v8::BigInt>()->ToWordsArray(&sign,
2421                                        &size,
2422                                        reinterpret_cast<uint64_t*>(&tag));
2423     if (size == 2 && sign == 0)
2424       *result = (tag.lower == type_tag->lower && tag.upper == type_tag->upper);
2425   }
2426 
2427   return GET_RETURN_STATUS(env);
2428 }
2429 
napi_get_value_external(napi_env env,napi_value value,void ** result)2430 napi_status napi_get_value_external(napi_env env,
2431                                     napi_value value,
2432                                     void** result) {
2433   CHECK_ENV(env);
2434   CHECK_ARG(env, value);
2435   CHECK_ARG(env, result);
2436 
2437   v8::Local<v8::Value> val = v8impl::V8LocalValueFromJsValue(value);
2438   RETURN_STATUS_IF_FALSE(env, val->IsExternal(), napi_invalid_arg);
2439 
2440   v8::Local<v8::External> external_value = val.As<v8::External>();
2441   *result = external_value->Value();
2442 
2443   return napi_clear_last_error(env);
2444 }
2445 
2446 // 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)2447 napi_status napi_create_reference(napi_env env,
2448                                   napi_value value,
2449                                   uint32_t initial_refcount,
2450                                   napi_ref* result) {
2451   // Omit NAPI_PREAMBLE and GET_RETURN_STATUS because V8 calls here cannot throw
2452   // JS exceptions.
2453   CHECK_ENV(env);
2454   CHECK_ARG(env, value);
2455   CHECK_ARG(env, result);
2456 
2457   v8::Local<v8::Value> v8_value = v8impl::V8LocalValueFromJsValue(value);
2458   if (!(v8_value->IsObject() || v8_value->IsFunction() ||
2459         v8_value->IsSymbol())) {
2460     return napi_set_last_error(env, napi_invalid_arg);
2461   }
2462 
2463   v8impl::Reference* reference =
2464       v8impl::Reference::New(env, v8_value, initial_refcount, false);
2465 
2466   *result = reinterpret_cast<napi_ref>(reference);
2467   return napi_clear_last_error(env);
2468 }
2469 
2470 // Deletes a reference. The referenced value is released, and may be GC'd unless
2471 // there are other references to it.
napi_delete_reference(napi_env env,napi_ref ref)2472 napi_status napi_delete_reference(napi_env env, napi_ref ref) {
2473   // Omit NAPI_PREAMBLE and GET_RETURN_STATUS because V8 calls here cannot throw
2474   // JS exceptions.
2475   CHECK_ENV(env);
2476   CHECK_ARG(env, ref);
2477 
2478   v8impl::Reference::Delete(reinterpret_cast<v8impl::Reference*>(ref));
2479 
2480   return napi_clear_last_error(env);
2481 }
2482 
2483 // Increments the reference count, optionally returning the resulting count.
2484 // After this call the reference will be a strong reference because its
2485 // refcount is >0, and the referenced object is effectively "pinned".
2486 // Calling this when the refcount is 0 and the object is unavailable
2487 // results in an error.
napi_reference_ref(napi_env env,napi_ref ref,uint32_t * result)2488 napi_status napi_reference_ref(napi_env env, napi_ref ref, uint32_t* result) {
2489   // Omit NAPI_PREAMBLE and GET_RETURN_STATUS because V8 calls here cannot throw
2490   // JS exceptions.
2491   CHECK_ENV(env);
2492   CHECK_ARG(env, ref);
2493 
2494   v8impl::Reference* reference = reinterpret_cast<v8impl::Reference*>(ref);
2495   uint32_t count = reference->Ref();
2496 
2497   if (result != nullptr) {
2498     *result = count;
2499   }
2500 
2501   return napi_clear_last_error(env);
2502 }
2503 
2504 // Decrements the reference count, optionally returning the resulting count. If
2505 // the result is 0 the reference is now weak and the object may be GC'd at any
2506 // time if there are no other references. Calling this when the refcount is
2507 // already 0 results in an error.
napi_reference_unref(napi_env env,napi_ref ref,uint32_t * result)2508 napi_status napi_reference_unref(napi_env env, napi_ref ref, uint32_t* result) {
2509   // Omit NAPI_PREAMBLE and GET_RETURN_STATUS because V8 calls here cannot throw
2510   // JS exceptions.
2511   CHECK_ENV(env);
2512   CHECK_ARG(env, ref);
2513 
2514   v8impl::Reference* reference = reinterpret_cast<v8impl::Reference*>(ref);
2515 
2516   if (reference->RefCount() == 0) {
2517     return napi_set_last_error(env, napi_generic_failure);
2518   }
2519 
2520   uint32_t count = reference->Unref();
2521 
2522   if (result != nullptr) {
2523     *result = count;
2524   }
2525 
2526   return napi_clear_last_error(env);
2527 }
2528 
2529 // Attempts to get a referenced value. If the reference is weak, the value might
2530 // no longer be available, in that case the call is still successful but the
2531 // result is NULL.
napi_get_reference_value(napi_env env,napi_ref ref,napi_value * result)2532 napi_status napi_get_reference_value(napi_env env,
2533                                      napi_ref ref,
2534                                      napi_value* result) {
2535   // Omit NAPI_PREAMBLE and GET_RETURN_STATUS because V8 calls here cannot throw
2536   // JS exceptions.
2537   CHECK_ENV(env);
2538   CHECK_ARG(env, ref);
2539   CHECK_ARG(env, result);
2540 
2541   v8impl::Reference* reference = reinterpret_cast<v8impl::Reference*>(ref);
2542   *result = v8impl::JsValueFromV8LocalValue(reference->Get());
2543 
2544   return napi_clear_last_error(env);
2545 }
2546 
napi_open_handle_scope(napi_env env,napi_handle_scope * result)2547 napi_status napi_open_handle_scope(napi_env env, napi_handle_scope* result) {
2548   // Omit NAPI_PREAMBLE and GET_RETURN_STATUS because V8 calls here cannot throw
2549   // JS exceptions.
2550   CHECK_ENV(env);
2551   CHECK_ARG(env, result);
2552 
2553   *result = v8impl::JsHandleScopeFromV8HandleScope(
2554       new v8impl::HandleScopeWrapper(env->isolate));
2555   env->open_handle_scopes++;
2556   return napi_clear_last_error(env);
2557 }
2558 
napi_close_handle_scope(napi_env env,napi_handle_scope scope)2559 napi_status napi_close_handle_scope(napi_env env, napi_handle_scope scope) {
2560   // Omit NAPI_PREAMBLE and GET_RETURN_STATUS because V8 calls here cannot throw
2561   // JS exceptions.
2562   CHECK_ENV(env);
2563   CHECK_ARG(env, scope);
2564   if (env->open_handle_scopes == 0) {
2565     return napi_handle_scope_mismatch;
2566   }
2567 
2568   env->open_handle_scopes--;
2569   delete v8impl::V8HandleScopeFromJsHandleScope(scope);
2570   return napi_clear_last_error(env);
2571 }
2572 
napi_open_escapable_handle_scope(napi_env env,napi_escapable_handle_scope * result)2573 napi_status napi_open_escapable_handle_scope(
2574     napi_env env,
2575     napi_escapable_handle_scope* result) {
2576   // Omit NAPI_PREAMBLE and GET_RETURN_STATUS because V8 calls here cannot throw
2577   // JS exceptions.
2578   CHECK_ENV(env);
2579   CHECK_ARG(env, result);
2580 
2581   *result = v8impl::JsEscapableHandleScopeFromV8EscapableHandleScope(
2582       new v8impl::EscapableHandleScopeWrapper(env->isolate));
2583   env->open_handle_scopes++;
2584   return napi_clear_last_error(env);
2585 }
2586 
napi_close_escapable_handle_scope(napi_env env,napi_escapable_handle_scope scope)2587 napi_status napi_close_escapable_handle_scope(
2588     napi_env env,
2589     napi_escapable_handle_scope scope) {
2590   // Omit NAPI_PREAMBLE and GET_RETURN_STATUS because V8 calls here cannot throw
2591   // JS exceptions.
2592   CHECK_ENV(env);
2593   CHECK_ARG(env, scope);
2594   if (env->open_handle_scopes == 0) {
2595     return napi_handle_scope_mismatch;
2596   }
2597 
2598   delete v8impl::V8EscapableHandleScopeFromJsEscapableHandleScope(scope);
2599   env->open_handle_scopes--;
2600   return napi_clear_last_error(env);
2601 }
2602 
napi_escape_handle(napi_env env,napi_escapable_handle_scope scope,napi_value escapee,napi_value * result)2603 napi_status napi_escape_handle(napi_env env,
2604                                napi_escapable_handle_scope scope,
2605                                napi_value escapee,
2606                                napi_value* result) {
2607   // Omit NAPI_PREAMBLE and GET_RETURN_STATUS because V8 calls here cannot throw
2608   // JS exceptions.
2609   CHECK_ENV(env);
2610   CHECK_ARG(env, scope);
2611   CHECK_ARG(env, escapee);
2612   CHECK_ARG(env, result);
2613 
2614   v8impl::EscapableHandleScopeWrapper* s =
2615       v8impl::V8EscapableHandleScopeFromJsEscapableHandleScope(scope);
2616   if (!s->escape_called()) {
2617     *result = v8impl::JsValueFromV8LocalValue(
2618         s->Escape(v8impl::V8LocalValueFromJsValue(escapee)));
2619     return napi_clear_last_error(env);
2620   }
2621   return napi_set_last_error(env, napi_escape_called_twice);
2622 }
2623 
napi_new_instance(napi_env env,napi_value constructor,size_t argc,const napi_value * argv,napi_value * result)2624 napi_status napi_new_instance(napi_env env,
2625                               napi_value constructor,
2626                               size_t argc,
2627                               const napi_value* argv,
2628                               napi_value* result) {
2629   NAPI_PREAMBLE(env);
2630   CHECK_ARG(env, constructor);
2631   if (argc > 0) {
2632     CHECK_ARG(env, argv);
2633   }
2634   CHECK_ARG(env, result);
2635 
2636   v8::Local<v8::Context> context = env->context();
2637 
2638   v8::Local<v8::Function> ctor;
2639   CHECK_TO_FUNCTION(env, ctor, constructor);
2640 
2641   auto maybe = ctor->NewInstance(context, argc,
2642     reinterpret_cast<v8::Local<v8::Value>*>(const_cast<napi_value*>(argv)));
2643 
2644   CHECK_MAYBE_EMPTY(env, maybe, napi_pending_exception);
2645 
2646   *result = v8impl::JsValueFromV8LocalValue(maybe.ToLocalChecked());
2647   return GET_RETURN_STATUS(env);
2648 }
2649 
napi_instanceof(napi_env env,napi_value object,napi_value constructor,bool * result)2650 napi_status napi_instanceof(napi_env env,
2651                             napi_value object,
2652                             napi_value constructor,
2653                             bool* result) {
2654   NAPI_PREAMBLE(env);
2655   CHECK_ARG(env, object);
2656   CHECK_ARG(env, result);
2657 
2658   *result = false;
2659 
2660   v8::Local<v8::Object> ctor;
2661   v8::Local<v8::Context> context = env->context();
2662 
2663   CHECK_TO_OBJECT(env, context, ctor, constructor);
2664 
2665   if (!ctor->IsFunction()) {
2666     napi_throw_type_error(env,
2667                           "ERR_NAPI_CONS_FUNCTION",
2668                           "Constructor must be a function");
2669 
2670     return napi_set_last_error(env, napi_function_expected);
2671   }
2672 
2673   napi_status status = napi_generic_failure;
2674 
2675   v8::Local<v8::Value> val = v8impl::V8LocalValueFromJsValue(object);
2676   auto maybe_result = val->InstanceOf(context, ctor);
2677   CHECK_MAYBE_NOTHING(env, maybe_result, status);
2678   *result = maybe_result.FromJust();
2679   return GET_RETURN_STATUS(env);
2680 }
2681 
2682 // Methods to support catching exceptions
napi_is_exception_pending(napi_env env,bool * result)2683 napi_status napi_is_exception_pending(napi_env env, bool* result) {
2684   // NAPI_PREAMBLE is not used here: this function must execute when there is a
2685   // pending exception.
2686   CHECK_ENV(env);
2687   CHECK_ARG(env, result);
2688 
2689   *result = !env->last_exception.IsEmpty();
2690   return napi_clear_last_error(env);
2691 }
2692 
napi_get_and_clear_last_exception(napi_env env,napi_value * result)2693 napi_status napi_get_and_clear_last_exception(napi_env env,
2694                                               napi_value* result) {
2695   // NAPI_PREAMBLE is not used here: this function must execute when there is a
2696   // pending exception.
2697   CHECK_ENV(env);
2698   CHECK_ARG(env, result);
2699 
2700   if (env->last_exception.IsEmpty()) {
2701     return napi_get_undefined(env, result);
2702   } else {
2703     *result = v8impl::JsValueFromV8LocalValue(
2704       v8::Local<v8::Value>::New(env->isolate, env->last_exception));
2705     env->last_exception.Reset();
2706   }
2707 
2708   return napi_clear_last_error(env);
2709 }
2710 
napi_is_arraybuffer(napi_env env,napi_value value,bool * result)2711 napi_status napi_is_arraybuffer(napi_env env, napi_value value, bool* result) {
2712   CHECK_ENV(env);
2713   CHECK_ARG(env, value);
2714   CHECK_ARG(env, result);
2715 
2716   v8::Local<v8::Value> val = v8impl::V8LocalValueFromJsValue(value);
2717   *result = val->IsArrayBuffer();
2718 
2719   return napi_clear_last_error(env);
2720 }
2721 
napi_create_arraybuffer(napi_env env,size_t byte_length,void ** data,napi_value * result)2722 napi_status napi_create_arraybuffer(napi_env env,
2723                                     size_t byte_length,
2724                                     void** data,
2725                                     napi_value* result) {
2726   NAPI_PREAMBLE(env);
2727   CHECK_ARG(env, result);
2728 
2729   v8::Isolate* isolate = env->isolate;
2730   v8::Local<v8::ArrayBuffer> buffer =
2731       v8::ArrayBuffer::New(isolate, byte_length);
2732 
2733   // Optionally return a pointer to the buffer's data, to avoid another call to
2734   // retrieve it.
2735   if (data != nullptr) {
2736     *data = buffer->GetBackingStore()->Data();
2737   }
2738 
2739   *result = v8impl::JsValueFromV8LocalValue(buffer);
2740   return GET_RETURN_STATUS(env);
2741 }
2742 
napi_create_external_arraybuffer(napi_env env,void * external_data,size_t byte_length,napi_finalize finalize_cb,void * finalize_hint,napi_value * result)2743 napi_status napi_create_external_arraybuffer(napi_env env,
2744                                              void* external_data,
2745                                              size_t byte_length,
2746                                              napi_finalize finalize_cb,
2747                                              void* finalize_hint,
2748                                              napi_value* result) {
2749   // The API contract here is that the cleanup function runs on the JS thread,
2750   // and is able to use napi_env. Implementing that properly is hard, so use the
2751   // `Buffer` variant for easier implementation.
2752   napi_value buffer;
2753   STATUS_CALL(napi_create_external_buffer(
2754       env,
2755       byte_length,
2756       external_data,
2757       finalize_cb,
2758       finalize_hint,
2759       &buffer));
2760   return napi_get_typedarray_info(
2761       env,
2762       buffer,
2763       nullptr,
2764       nullptr,
2765       nullptr,
2766       result,
2767       nullptr);
2768 }
2769 
napi_get_arraybuffer_info(napi_env env,napi_value arraybuffer,void ** data,size_t * byte_length)2770 napi_status napi_get_arraybuffer_info(napi_env env,
2771                                       napi_value arraybuffer,
2772                                       void** data,
2773                                       size_t* byte_length) {
2774   CHECK_ENV(env);
2775   CHECK_ARG(env, arraybuffer);
2776 
2777   v8::Local<v8::Value> value = v8impl::V8LocalValueFromJsValue(arraybuffer);
2778   RETURN_STATUS_IF_FALSE(env, value->IsArrayBuffer(), napi_invalid_arg);
2779 
2780   std::shared_ptr<v8::BackingStore> backing_store =
2781       value.As<v8::ArrayBuffer>()->GetBackingStore();
2782 
2783   if (data != nullptr) {
2784     *data = backing_store->Data();
2785   }
2786 
2787   if (byte_length != nullptr) {
2788     *byte_length = backing_store->ByteLength();
2789   }
2790 
2791   return napi_clear_last_error(env);
2792 }
2793 
napi_is_typedarray(napi_env env,napi_value value,bool * result)2794 napi_status napi_is_typedarray(napi_env env, napi_value value, bool* result) {
2795   CHECK_ENV(env);
2796   CHECK_ARG(env, value);
2797   CHECK_ARG(env, result);
2798 
2799   v8::Local<v8::Value> val = v8impl::V8LocalValueFromJsValue(value);
2800   *result = val->IsTypedArray();
2801 
2802   return napi_clear_last_error(env);
2803 }
2804 
napi_create_typedarray(napi_env env,napi_typedarray_type type,size_t length,napi_value arraybuffer,size_t byte_offset,napi_value * result)2805 napi_status napi_create_typedarray(napi_env env,
2806                                    napi_typedarray_type type,
2807                                    size_t length,
2808                                    napi_value arraybuffer,
2809                                    size_t byte_offset,
2810                                    napi_value* result) {
2811   NAPI_PREAMBLE(env);
2812   CHECK_ARG(env, arraybuffer);
2813   CHECK_ARG(env, result);
2814 
2815   v8::Local<v8::Value> value = v8impl::V8LocalValueFromJsValue(arraybuffer);
2816   RETURN_STATUS_IF_FALSE(env, value->IsArrayBuffer(), napi_invalid_arg);
2817 
2818   v8::Local<v8::ArrayBuffer> buffer = value.As<v8::ArrayBuffer>();
2819   v8::Local<v8::TypedArray> typedArray;
2820 
2821   switch (type) {
2822     case napi_int8_array:
2823       CREATE_TYPED_ARRAY(
2824           env, Int8Array, 1, buffer, byte_offset, length, typedArray);
2825       break;
2826     case napi_uint8_array:
2827       CREATE_TYPED_ARRAY(
2828           env, Uint8Array, 1, buffer, byte_offset, length, typedArray);
2829       break;
2830     case napi_uint8_clamped_array:
2831       CREATE_TYPED_ARRAY(
2832           env, Uint8ClampedArray, 1, buffer, byte_offset, length, typedArray);
2833       break;
2834     case napi_int16_array:
2835       CREATE_TYPED_ARRAY(
2836           env, Int16Array, 2, buffer, byte_offset, length, typedArray);
2837       break;
2838     case napi_uint16_array:
2839       CREATE_TYPED_ARRAY(
2840           env, Uint16Array, 2, buffer, byte_offset, length, typedArray);
2841       break;
2842     case napi_int32_array:
2843       CREATE_TYPED_ARRAY(
2844           env, Int32Array, 4, buffer, byte_offset, length, typedArray);
2845       break;
2846     case napi_uint32_array:
2847       CREATE_TYPED_ARRAY(
2848           env, Uint32Array, 4, buffer, byte_offset, length, typedArray);
2849       break;
2850     case napi_float32_array:
2851       CREATE_TYPED_ARRAY(
2852           env, Float32Array, 4, buffer, byte_offset, length, typedArray);
2853       break;
2854     case napi_float64_array:
2855       CREATE_TYPED_ARRAY(
2856           env, Float64Array, 8, buffer, byte_offset, length, typedArray);
2857       break;
2858     case napi_bigint64_array:
2859       CREATE_TYPED_ARRAY(
2860           env, BigInt64Array, 8, buffer, byte_offset, length, typedArray);
2861       break;
2862     case napi_biguint64_array:
2863       CREATE_TYPED_ARRAY(
2864           env, BigUint64Array, 8, buffer, byte_offset, length, typedArray);
2865       break;
2866     default:
2867       return napi_set_last_error(env, napi_invalid_arg);
2868   }
2869 
2870   *result = v8impl::JsValueFromV8LocalValue(typedArray);
2871   return GET_RETURN_STATUS(env);
2872 }
2873 
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)2874 napi_status napi_get_typedarray_info(napi_env env,
2875                                      napi_value typedarray,
2876                                      napi_typedarray_type* type,
2877                                      size_t* length,
2878                                      void** data,
2879                                      napi_value* arraybuffer,
2880                                      size_t* byte_offset) {
2881   CHECK_ENV(env);
2882   CHECK_ARG(env, typedarray);
2883 
2884   v8::Local<v8::Value> value = v8impl::V8LocalValueFromJsValue(typedarray);
2885   RETURN_STATUS_IF_FALSE(env, value->IsTypedArray(), napi_invalid_arg);
2886 
2887   v8::Local<v8::TypedArray> array = value.As<v8::TypedArray>();
2888 
2889   if (type != nullptr) {
2890     if (value->IsInt8Array()) {
2891       *type = napi_int8_array;
2892     } else if (value->IsUint8Array()) {
2893       *type = napi_uint8_array;
2894     } else if (value->IsUint8ClampedArray()) {
2895       *type = napi_uint8_clamped_array;
2896     } else if (value->IsInt16Array()) {
2897       *type = napi_int16_array;
2898     } else if (value->IsUint16Array()) {
2899       *type = napi_uint16_array;
2900     } else if (value->IsInt32Array()) {
2901       *type = napi_int32_array;
2902     } else if (value->IsUint32Array()) {
2903       *type = napi_uint32_array;
2904     } else if (value->IsFloat32Array()) {
2905       *type = napi_float32_array;
2906     } else if (value->IsFloat64Array()) {
2907       *type = napi_float64_array;
2908     } else if (value->IsBigInt64Array()) {
2909       *type = napi_bigint64_array;
2910     } else if (value->IsBigUint64Array()) {
2911       *type = napi_biguint64_array;
2912     }
2913   }
2914 
2915   if (length != nullptr) {
2916     *length = array->Length();
2917   }
2918 
2919   v8::Local<v8::ArrayBuffer> buffer;
2920   if (data != nullptr || arraybuffer != nullptr) {
2921     // Calling Buffer() may have the side effect of allocating the buffer,
2922     // so only do this when it’s needed.
2923     buffer = array->Buffer();
2924   }
2925 
2926   if (data != nullptr) {
2927     *data = static_cast<uint8_t*>(buffer->GetBackingStore()->Data()) +
2928             array->ByteOffset();
2929   }
2930 
2931   if (arraybuffer != nullptr) {
2932     *arraybuffer = v8impl::JsValueFromV8LocalValue(buffer);
2933   }
2934 
2935   if (byte_offset != nullptr) {
2936     *byte_offset = array->ByteOffset();
2937   }
2938 
2939   return napi_clear_last_error(env);
2940 }
2941 
napi_create_dataview(napi_env env,size_t byte_length,napi_value arraybuffer,size_t byte_offset,napi_value * result)2942 napi_status napi_create_dataview(napi_env env,
2943                                  size_t byte_length,
2944                                  napi_value arraybuffer,
2945                                  size_t byte_offset,
2946                                  napi_value* result) {
2947   NAPI_PREAMBLE(env);
2948   CHECK_ARG(env, arraybuffer);
2949   CHECK_ARG(env, result);
2950 
2951   v8::Local<v8::Value> value = v8impl::V8LocalValueFromJsValue(arraybuffer);
2952   RETURN_STATUS_IF_FALSE(env, value->IsArrayBuffer(), napi_invalid_arg);
2953 
2954   v8::Local<v8::ArrayBuffer> buffer = value.As<v8::ArrayBuffer>();
2955   if (byte_length + byte_offset > buffer->ByteLength()) {
2956     napi_throw_range_error(
2957         env,
2958         "ERR_NAPI_INVALID_DATAVIEW_ARGS",
2959         "byte_offset + byte_length should be less than or "
2960         "equal to the size in bytes of the array passed in");
2961     return napi_set_last_error(env, napi_pending_exception);
2962   }
2963   v8::Local<v8::DataView> DataView = v8::DataView::New(buffer, byte_offset,
2964                                                        byte_length);
2965 
2966   *result = v8impl::JsValueFromV8LocalValue(DataView);
2967   return GET_RETURN_STATUS(env);
2968 }
2969 
napi_is_dataview(napi_env env,napi_value value,bool * result)2970 napi_status napi_is_dataview(napi_env env, napi_value value, bool* result) {
2971   CHECK_ENV(env);
2972   CHECK_ARG(env, value);
2973   CHECK_ARG(env, result);
2974 
2975   v8::Local<v8::Value> val = v8impl::V8LocalValueFromJsValue(value);
2976   *result = val->IsDataView();
2977 
2978   return napi_clear_last_error(env);
2979 }
2980 
napi_get_dataview_info(napi_env env,napi_value dataview,size_t * byte_length,void ** data,napi_value * arraybuffer,size_t * byte_offset)2981 napi_status napi_get_dataview_info(napi_env env,
2982                                    napi_value dataview,
2983                                    size_t* byte_length,
2984                                    void** data,
2985                                    napi_value* arraybuffer,
2986                                    size_t* byte_offset) {
2987   CHECK_ENV(env);
2988   CHECK_ARG(env, dataview);
2989 
2990   v8::Local<v8::Value> value = v8impl::V8LocalValueFromJsValue(dataview);
2991   RETURN_STATUS_IF_FALSE(env, value->IsDataView(), napi_invalid_arg);
2992 
2993   v8::Local<v8::DataView> array = value.As<v8::DataView>();
2994 
2995   if (byte_length != nullptr) {
2996     *byte_length = array->ByteLength();
2997   }
2998 
2999   v8::Local<v8::ArrayBuffer> buffer;
3000   if (data != nullptr || arraybuffer != nullptr) {
3001     // Calling Buffer() may have the side effect of allocating the buffer,
3002     // so only do this when it’s needed.
3003     buffer = array->Buffer();
3004   }
3005 
3006   if (data != nullptr) {
3007     *data = static_cast<uint8_t*>(buffer->GetBackingStore()->Data()) +
3008             array->ByteOffset();
3009   }
3010 
3011   if (arraybuffer != nullptr) {
3012     *arraybuffer = v8impl::JsValueFromV8LocalValue(buffer);
3013   }
3014 
3015   if (byte_offset != nullptr) {
3016     *byte_offset = array->ByteOffset();
3017   }
3018 
3019   return napi_clear_last_error(env);
3020 }
3021 
napi_get_version(napi_env env,uint32_t * result)3022 napi_status napi_get_version(napi_env env, uint32_t* result) {
3023   CHECK_ENV(env);
3024   CHECK_ARG(env, result);
3025   *result = NAPI_VERSION;
3026   return napi_clear_last_error(env);
3027 }
3028 
napi_create_promise(napi_env env,napi_deferred * deferred,napi_value * promise)3029 napi_status napi_create_promise(napi_env env,
3030                                 napi_deferred* deferred,
3031                                 napi_value* promise) {
3032   NAPI_PREAMBLE(env);
3033   CHECK_ARG(env, deferred);
3034   CHECK_ARG(env, promise);
3035 
3036   auto maybe = v8::Promise::Resolver::New(env->context());
3037   CHECK_MAYBE_EMPTY(env, maybe, napi_generic_failure);
3038 
3039   auto v8_resolver = maybe.ToLocalChecked();
3040   auto v8_deferred = new v8impl::Persistent<v8::Value>();
3041   v8_deferred->Reset(env->isolate, v8_resolver);
3042 
3043   *deferred = v8impl::JsDeferredFromNodePersistent(v8_deferred);
3044   *promise = v8impl::JsValueFromV8LocalValue(v8_resolver->GetPromise());
3045   return GET_RETURN_STATUS(env);
3046 }
3047 
napi_resolve_deferred(napi_env env,napi_deferred deferred,napi_value resolution)3048 napi_status napi_resolve_deferred(napi_env env,
3049                                   napi_deferred deferred,
3050                                   napi_value resolution) {
3051   return v8impl::ConcludeDeferred(env, deferred, resolution, true);
3052 }
3053 
napi_reject_deferred(napi_env env,napi_deferred deferred,napi_value resolution)3054 napi_status napi_reject_deferred(napi_env env,
3055                                  napi_deferred deferred,
3056                                  napi_value resolution) {
3057   return v8impl::ConcludeDeferred(env, deferred, resolution, false);
3058 }
3059 
napi_is_promise(napi_env env,napi_value value,bool * is_promise)3060 napi_status napi_is_promise(napi_env env,
3061                             napi_value value,
3062                             bool* is_promise) {
3063   CHECK_ENV(env);
3064   CHECK_ARG(env, value);
3065   CHECK_ARG(env, is_promise);
3066 
3067   *is_promise = v8impl::V8LocalValueFromJsValue(value)->IsPromise();
3068 
3069   return napi_clear_last_error(env);
3070 }
3071 
napi_create_date(napi_env env,double time,napi_value * result)3072 napi_status napi_create_date(napi_env env,
3073                              double time,
3074                              napi_value* result) {
3075   NAPI_PREAMBLE(env);
3076   CHECK_ARG(env, result);
3077 
3078   v8::MaybeLocal<v8::Value> maybe_date = v8::Date::New(env->context(), time);
3079   CHECK_MAYBE_EMPTY(env, maybe_date, napi_generic_failure);
3080 
3081   *result = v8impl::JsValueFromV8LocalValue(maybe_date.ToLocalChecked());
3082 
3083   return GET_RETURN_STATUS(env);
3084 }
3085 
napi_is_date(napi_env env,napi_value value,bool * is_date)3086 napi_status napi_is_date(napi_env env,
3087                          napi_value value,
3088                          bool* is_date) {
3089   CHECK_ENV(env);
3090   CHECK_ARG(env, value);
3091   CHECK_ARG(env, is_date);
3092 
3093   *is_date = v8impl::V8LocalValueFromJsValue(value)->IsDate();
3094 
3095   return napi_clear_last_error(env);
3096 }
3097 
napi_get_date_value(napi_env env,napi_value value,double * result)3098 napi_status napi_get_date_value(napi_env env,
3099                                 napi_value value,
3100                                 double* result) {
3101   NAPI_PREAMBLE(env);
3102   CHECK_ARG(env, value);
3103   CHECK_ARG(env, result);
3104 
3105   v8::Local<v8::Value> val = v8impl::V8LocalValueFromJsValue(value);
3106   RETURN_STATUS_IF_FALSE(env, val->IsDate(), napi_date_expected);
3107 
3108   v8::Local<v8::Date> date = val.As<v8::Date>();
3109   *result = date->ValueOf();
3110 
3111   return GET_RETURN_STATUS(env);
3112 }
3113 
napi_run_script(napi_env env,napi_value script,napi_value * result)3114 napi_status napi_run_script(napi_env env,
3115                             napi_value script,
3116                             napi_value* result) {
3117   NAPI_PREAMBLE(env);
3118   CHECK_ARG(env, script);
3119   CHECK_ARG(env, result);
3120 
3121   v8::Local<v8::Value> v8_script = v8impl::V8LocalValueFromJsValue(script);
3122 
3123   if (!v8_script->IsString()) {
3124     return napi_set_last_error(env, napi_string_expected);
3125   }
3126 
3127   v8::Local<v8::Context> context = env->context();
3128 
3129   auto maybe_script = v8::Script::Compile(context,
3130       v8::Local<v8::String>::Cast(v8_script));
3131   CHECK_MAYBE_EMPTY(env, maybe_script, napi_generic_failure);
3132 
3133   auto script_result =
3134       maybe_script.ToLocalChecked()->Run(context);
3135   CHECK_MAYBE_EMPTY(env, script_result, napi_generic_failure);
3136 
3137   *result = v8impl::JsValueFromV8LocalValue(script_result.ToLocalChecked());
3138   return GET_RETURN_STATUS(env);
3139 }
3140 
napi_add_finalizer(napi_env env,napi_value js_object,void * native_object,napi_finalize finalize_cb,void * finalize_hint,napi_ref * result)3141 napi_status napi_add_finalizer(napi_env env,
3142                                napi_value js_object,
3143                                void* native_object,
3144                                napi_finalize finalize_cb,
3145                                void* finalize_hint,
3146                                napi_ref* result) {
3147   return v8impl::Wrap<v8impl::anonymous>(env,
3148                                          js_object,
3149                                          native_object,
3150                                          finalize_cb,
3151                                          finalize_hint,
3152                                          result);
3153 }
3154 
napi_adjust_external_memory(napi_env env,int64_t change_in_bytes,int64_t * adjusted_value)3155 napi_status napi_adjust_external_memory(napi_env env,
3156                                         int64_t change_in_bytes,
3157                                         int64_t* adjusted_value) {
3158   CHECK_ENV(env);
3159   CHECK_ARG(env, adjusted_value);
3160 
3161   *adjusted_value = env->isolate->AdjustAmountOfExternalAllocatedMemory(
3162       change_in_bytes);
3163 
3164   return napi_clear_last_error(env);
3165 }
3166 
napi_set_instance_data(napi_env env,void * data,napi_finalize finalize_cb,void * finalize_hint)3167 napi_status napi_set_instance_data(napi_env env,
3168                                    void* data,
3169                                    napi_finalize finalize_cb,
3170                                    void* finalize_hint) {
3171   CHECK_ENV(env);
3172 
3173   v8impl::RefBase* old_data = static_cast<v8impl::RefBase*>(env->instance_data);
3174   if (old_data != nullptr) {
3175     // Our contract so far has been to not finalize any old data there may be.
3176     // So we simply delete it.
3177     v8impl::RefBase::Delete(old_data);
3178   }
3179 
3180   env->instance_data = v8impl::RefBase::New(env,
3181                                             0,
3182                                             true,
3183                                             finalize_cb,
3184                                             data,
3185                                             finalize_hint);
3186 
3187   return napi_clear_last_error(env);
3188 }
3189 
napi_get_instance_data(napi_env env,void ** data)3190 napi_status napi_get_instance_data(napi_env env,
3191                                    void** data) {
3192   CHECK_ENV(env);
3193   CHECK_ARG(env, data);
3194 
3195   v8impl::RefBase* idata = static_cast<v8impl::RefBase*>(env->instance_data);
3196 
3197   *data = (idata == nullptr ? nullptr : idata->Data());
3198 
3199   return napi_clear_last_error(env);
3200 }
3201 
napi_detach_arraybuffer(napi_env env,napi_value arraybuffer)3202 napi_status napi_detach_arraybuffer(napi_env env, napi_value arraybuffer) {
3203   CHECK_ENV(env);
3204   CHECK_ARG(env, arraybuffer);
3205 
3206   v8::Local<v8::Value> value = v8impl::V8LocalValueFromJsValue(arraybuffer);
3207   RETURN_STATUS_IF_FALSE(
3208       env, value->IsArrayBuffer(), napi_arraybuffer_expected);
3209 
3210   v8::Local<v8::ArrayBuffer> it = value.As<v8::ArrayBuffer>();
3211   RETURN_STATUS_IF_FALSE(
3212       env, it->IsDetachable(), napi_detachable_arraybuffer_expected);
3213 
3214   it->Detach();
3215 
3216   return napi_clear_last_error(env);
3217 }
3218 
napi_is_detached_arraybuffer(napi_env env,napi_value arraybuffer,bool * result)3219 napi_status napi_is_detached_arraybuffer(napi_env env,
3220                                          napi_value arraybuffer,
3221                                          bool* result) {
3222   CHECK_ENV(env);
3223   CHECK_ARG(env, arraybuffer);
3224   CHECK_ARG(env, result);
3225 
3226   v8::Local<v8::Value> value = v8impl::V8LocalValueFromJsValue(arraybuffer);
3227 
3228   *result = value->IsArrayBuffer() &&
3229             value.As<v8::ArrayBuffer>()->GetBackingStore()->Data() == nullptr;
3230 
3231   return napi_clear_last_error(env);
3232 }
3233