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