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