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