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