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