GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: js_native_api_v8.cc Lines: 1428 1458 97.9 %
Date: 2022-08-21 04:19:51 Branches: 1155 1804 64.0 %

Line Branch Exec Source
1
#include <algorithm>
2
#include <climits>  // INT_MAX
3
#include <cmath>
4
#define NAPI_EXPERIMENTAL
5
#include "env-inl.h"
6
#include "js_native_api.h"
7
#include "js_native_api_v8.h"
8
#include "util-inl.h"
9
10
#define CHECK_MAYBE_NOTHING(env, maybe, status)                                \
11
  RETURN_STATUS_IF_FALSE((env), !((maybe).IsNothing()), (status))
12
13
#define CHECK_MAYBE_NOTHING_WITH_PREAMBLE(env, maybe, status)                  \
14
  RETURN_STATUS_IF_FALSE_WITH_PREAMBLE((env), !((maybe).IsNothing()), (status))
15
16
#define CHECK_TO_NUMBER(env, context, result, src)                             \
17
  CHECK_TO_TYPE((env), Number, (context), (result), (src), napi_number_expected)
18
19
// n-api defines NAPI_AUTO_LENGTH as the indicator that a string
20
// is null terminated. For V8 the equivalent is -1. The assert
21
// validates that our cast of NAPI_AUTO_LENGTH results in -1 as
22
// needed by V8.
23
#define CHECK_NEW_FROM_UTF8_LEN(env, result, str, len)                         \
24
  do {                                                                         \
25
    static_assert(static_cast<int>(NAPI_AUTO_LENGTH) == -1,                    \
26
                  "Casting NAPI_AUTO_LENGTH to int must result in -1");        \
27
    RETURN_STATUS_IF_FALSE(                                                    \
28
        (env), (len == NAPI_AUTO_LENGTH) || len <= INT_MAX, napi_invalid_arg); \
29
    RETURN_STATUS_IF_FALSE((env), (str) != nullptr, napi_invalid_arg);         \
30
    auto str_maybe = v8::String::NewFromUtf8((env)->isolate,                   \
31
                                             (str),                            \
32
                                             v8::NewStringType::kInternalized, \
33
                                             static_cast<int>(len));           \
34
    CHECK_MAYBE_EMPTY((env), str_maybe, napi_generic_failure);                 \
35
    (result) = str_maybe.ToLocalChecked();                                     \
36
  } while (0)
37
38
#define CHECK_NEW_FROM_UTF8(env, result, str)                                  \
39
  CHECK_NEW_FROM_UTF8_LEN((env), (result), (str), NAPI_AUTO_LENGTH)
40
41
#define CREATE_TYPED_ARRAY(                                                    \
42
    env, type, size_of_element, buffer, byte_offset, length, out)              \
43
  do {                                                                         \
44
    if ((size_of_element) > 1) {                                               \
45
      THROW_RANGE_ERROR_IF_FALSE(                                              \
46
          (env),                                                               \
47
          (byte_offset) % (size_of_element) == 0,                              \
48
          "ERR_NAPI_INVALID_TYPEDARRAY_ALIGNMENT",                             \
49
          "start offset of " #type                                             \
50
          " should be a multiple of " #size_of_element);                       \
51
    }                                                                          \
52
    THROW_RANGE_ERROR_IF_FALSE(                                                \
53
        (env),                                                                 \
54
        (length) * (size_of_element) + (byte_offset) <= buffer->ByteLength(),  \
55
        "ERR_NAPI_INVALID_TYPEDARRAY_LENGTH",                                  \
56
        "Invalid typed array length");                                         \
57
    (out) = v8::type::New((buffer), (byte_offset), (length));                  \
58
  } while (0)
59
60
namespace v8impl {
61
62
namespace {
63
64
539
inline static napi_status V8NameFromPropertyDescriptor(
65
    napi_env env,
66
    const napi_property_descriptor* p,
67
    v8::Local<v8::Name>* result) {
68
539
  if (p->utf8name != nullptr) {
69

1605
    CHECK_NEW_FROM_UTF8(env, *result, p->utf8name);
70
  } else {
71
    v8::Local<v8::Value> property_value =
72
4
        v8impl::V8LocalValueFromJsValue(p->name);
73
74
4
    RETURN_STATUS_IF_FALSE(env, property_value->IsName(), napi_name_expected);
75
4
    *result = property_value.As<v8::Name>();
76
  }
77
78
539
  return napi_ok;
79
}
80
81
// convert from n-api property attributes to v8::PropertyAttribute
82
21
inline static v8::PropertyAttribute V8PropertyAttributesFromDescriptor(
83
    const napi_property_descriptor* descriptor) {
84
21
  unsigned int attribute_flags = v8::PropertyAttribute::None;
85
86
  // The napi_writable attribute is ignored for accessor descriptors, but
87
  // V8 would throw `TypeError`s on assignment with nonexistence of a setter.
88

21
  if ((descriptor->getter == nullptr && descriptor->setter == nullptr) &&
89
11
      (descriptor->attributes & napi_writable) == 0) {
90
9
    attribute_flags |= v8::PropertyAttribute::ReadOnly;
91
  }
92
93
21
  if ((descriptor->attributes & napi_enumerable) == 0) {
94
15
    attribute_flags |= v8::PropertyAttribute::DontEnum;
95
  }
96
21
  if ((descriptor->attributes & napi_configurable) == 0) {
97
21
    attribute_flags |= v8::PropertyAttribute::DontDelete;
98
  }
99
100
21
  return static_cast<v8::PropertyAttribute>(attribute_flags);
101
}
102
103
5
inline static napi_deferred JsDeferredFromNodePersistent(
104
    v8impl::Persistent<v8::Value>* local) {
105
5
  return reinterpret_cast<napi_deferred>(local);
106
}
107
108
5
inline static v8impl::Persistent<v8::Value>* NodePersistentFromJsDeferred(
109
    napi_deferred local) {
110
5
  return reinterpret_cast<v8impl::Persistent<v8::Value>*>(local);
111
}
112
113
class HandleScopeWrapper {
114
 public:
115
4
  explicit HandleScopeWrapper(v8::Isolate* isolate) : scope(isolate) {}
116
117
 private:
118
  v8::HandleScope scope;
119
};
120
121
// In node v0.10 version of v8, there is no EscapableHandleScope and the
122
// node v0.10 port use HandleScope::Close(Local<T> v) to mimic the behavior
123
// of a EscapableHandleScope::Escape(Local<T> v), but it is not the same
124
// semantics. This is an example of where the api abstraction fail to work
125
// across different versions.
126
class EscapableHandleScopeWrapper {
127
 public:
128
2
  explicit EscapableHandleScopeWrapper(v8::Isolate* isolate)
129
2
      : scope(isolate), escape_called_(false) {}
130
3
  bool escape_called() const { return escape_called_; }
131
  template <typename T>
132
2
  v8::Local<T> Escape(v8::Local<T> handle) {
133
2
    escape_called_ = true;
134
4
    return scope.Escape(handle);
135
  }
136
137
 private:
138
  v8::EscapableHandleScope scope;
139
  bool escape_called_;
140
};
141
142
4
inline static napi_handle_scope JsHandleScopeFromV8HandleScope(
143
    HandleScopeWrapper* s) {
144
4
  return reinterpret_cast<napi_handle_scope>(s);
145
}
146
147
4
inline static HandleScopeWrapper* V8HandleScopeFromJsHandleScope(
148
    napi_handle_scope s) {
149
4
  return reinterpret_cast<HandleScopeWrapper*>(s);
150
}
151
152
inline static napi_escapable_handle_scope
153
2
JsEscapableHandleScopeFromV8EscapableHandleScope(
154
    EscapableHandleScopeWrapper* s) {
155
2
  return reinterpret_cast<napi_escapable_handle_scope>(s);
156
}
157
158
inline static EscapableHandleScopeWrapper*
159
5
V8EscapableHandleScopeFromJsEscapableHandleScope(
160
    napi_escapable_handle_scope s) {
161
5
  return reinterpret_cast<EscapableHandleScopeWrapper*>(s);
162
}
163
164
5
inline static napi_status ConcludeDeferred(napi_env env,
165
                                           napi_deferred deferred,
166
                                           napi_value result,
167
                                           bool is_resolved) {
168


10
  NAPI_PREAMBLE(env);
169
5
  CHECK_ARG(env, result);
170
171
5
  v8::Local<v8::Context> context = env->context();
172
  v8impl::Persistent<v8::Value>* deferred_ref =
173
5
      NodePersistentFromJsDeferred(deferred);
174
  v8::Local<v8::Value> v8_deferred =
175
10
      v8::Local<v8::Value>::New(env->isolate, *deferred_ref);
176
177
5
  auto v8_resolver = v8_deferred.As<v8::Promise::Resolver>();
178
179
  v8::Maybe<bool> success =
180
      is_resolved ? v8_resolver->Resolve(
181
4
                        context, v8impl::V8LocalValueFromJsValue(result))
182
                  : v8_resolver->Reject(
183
6
                        context, v8impl::V8LocalValueFromJsValue(result));
184
185
10
  delete deferred_ref;
186
187

10
  RETURN_STATUS_IF_FALSE(env, success.FromMaybe(false), napi_generic_failure);
188
189
5
  return GET_RETURN_STATUS(env);
190
}
191
192
enum UnwrapAction { KeepWrap, RemoveWrap };
193
194
35
inline static napi_status Unwrap(napi_env env,
195
                                 napi_value js_object,
196
                                 void** result,
197
                                 UnwrapAction action) {
198


70
  NAPI_PREAMBLE(env);
199
35
  CHECK_ARG(env, js_object);
200
35
  if (action == KeepWrap) {
201
27
    CHECK_ARG(env, result);
202
  }
203
204
35
  v8::Local<v8::Context> context = env->context();
205
206
35
  v8::Local<v8::Value> value = v8impl::V8LocalValueFromJsValue(js_object);
207
35
  RETURN_STATUS_IF_FALSE(env, value->IsObject(), napi_invalid_arg);
208
35
  v8::Local<v8::Object> obj = value.As<v8::Object>();
209
210
35
  auto val = obj->GetPrivate(context, NAPI_PRIVATE_KEY(context, wrapper))
211
35
                 .ToLocalChecked();
212
35
  RETURN_STATUS_IF_FALSE(env, val->IsExternal(), napi_invalid_arg);
213
  Reference* reference =
214
35
      static_cast<v8impl::Reference*>(val.As<v8::External>()->Value());
215
216
35
  if (result) {
217
35
    *result = reference->Data();
218
  }
219
220
35
  if (action == RemoveWrap) {
221
16
    CHECK(obj->DeletePrivate(context, NAPI_PRIVATE_KEY(context, wrapper))
222
              .FromJust());
223
8
    Reference::Delete(reference);
224
  }
225
226
35
  return GET_RETURN_STATUS(env);
227
}
228
229
//=== Function napi_callback wrapper =================================
230
231
// Use this data structure to associate callback data with each N-API function
232
// exposed to JavaScript. The structure is stored in a v8::External which gets
233
// passed into our callback wrapper. This reduces the performance impact of
234
// calling through N-API.
235
// Ref: benchmark/misc/function_call
236
// Discussion (incl. perf. data): https://github.com/nodejs/node/pull/21072
237
class CallbackBundle {
238
 public:
239
  // Creates an object to be made available to the static function callback
240
  // wrapper, used to retrieve the native callback function and data pointer.
241
540
  static inline v8::Local<v8::Value> New(napi_env env,
242
                                         napi_callback cb,
243
                                         void* data) {
244
540
    CallbackBundle* bundle = new CallbackBundle();
245
540
    bundle->cb = cb;
246
540
    bundle->cb_data = data;
247
540
    bundle->env = env;
248
249
540
    v8::Local<v8::Value> cbdata = v8::External::New(env->isolate, bundle);
250
540
    Reference::New(env, cbdata, 0, true, Delete, bundle, nullptr);
251
540
    return cbdata;
252
  }
253
  napi_env env;   // Necessary to invoke C++ NAPI callback
254
  void* cb_data;  // The user provided callback data
255
  napi_callback cb;
256
257
 private:
258
531
  static void Delete(napi_env env, void* data, void* hint) {
259
531
    CallbackBundle* bundle = static_cast<CallbackBundle*>(data);
260
531
    delete bundle;
261
531
  }
262
};
263
264
// Base class extended by classes that wrap V8 function and property callback
265
// info.
266
class CallbackWrapper {
267
 public:
268
4683
  inline CallbackWrapper(napi_value this_arg, size_t args_length, void* data)
269
4683
      : _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
275
42
  napi_value This() { return _this; }
276
277
4505
  size_t ArgsLength() { return _args_length; }
278
279
6
  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:
289
4683
  inline CallbackWrapperBase(const v8::FunctionCallbackInfo<v8::Value>& cbinfo,
290
                             const size_t args_length)
291
4683
      : CallbackWrapper(
292
            JsValueFromV8LocalValue(cbinfo.This()), args_length, nullptr),
293
9366
        _cbinfo(cbinfo) {
294
4683
    _bundle = reinterpret_cast<CallbackBundle*>(
295
9366
        cbinfo.Data().As<v8::External>()->Value());
296
4683
    _data = _bundle->cb_data;
297
4683
  }
298
299
 protected:
300
4683
  inline void InvokeCallback() {
301
4683
    napi_callback_info cbinfo_wrapper = reinterpret_cast<napi_callback_info>(
302
        static_cast<CallbackWrapper*>(this));
303
304
    // All other pointers we need are stored in `_bundle`
305
4683
    napi_env env = _bundle->env;
306
4683
    napi_callback cb = _bundle->cb;
307
308
4683
    napi_value result = nullptr;
309
4683
    bool exceptionOccurred = false;
310
9366
    env->CallIntoModule([&](napi_env env) { result = cb(env, cbinfo_wrapper); },
311
1232
                        [&](napi_env env, v8::Local<v8::Value> value) {
312
1232
                          exceptionOccurred = true;
313
1232
                          env->isolate->ThrowException(value);
314
1232
                        });
315
316

4683
    if (!exceptionOccurred && (result != nullptr)) {
317
2837
      this->SetReturnValue(result);
318
    }
319
4683
  }
320
321
  const v8::FunctionCallbackInfo<v8::Value>& _cbinfo;
322
  CallbackBundle* _bundle;
323
};
324
325
class FunctionCallbackWrapper : public CallbackWrapperBase {
326
 public:
327
4683
  static void Invoke(const v8::FunctionCallbackInfo<v8::Value>& info) {
328
4683
    FunctionCallbackWrapper cbwrapper(info);
329
4683
    cbwrapper.InvokeCallback();
330
4683
  }
331
332
509
  static inline napi_status NewFunction(napi_env env,
333
                                        napi_callback cb,
334
                                        void* cb_data,
335
                                        v8::Local<v8::Function>* result) {
336
509
    v8::Local<v8::Value> cbdata = v8impl::CallbackBundle::New(env, cb, cb_data);
337
509
    RETURN_STATUS_IF_FALSE(env, !cbdata.IsEmpty(), napi_generic_failure);
338
339
    v8::MaybeLocal<v8::Function> maybe_function =
340
509
        v8::Function::New(env->context(), Invoke, cbdata);
341
509
    CHECK_MAYBE_EMPTY(env, maybe_function, napi_generic_failure);
342
343
509
    *result = maybe_function.ToLocalChecked();
344
509
    return napi_clear_last_error(env);
345
  }
346
347
31
  static inline napi_status NewTemplate(
348
      napi_env env,
349
      napi_callback cb,
350
      void* cb_data,
351
      v8::Local<v8::FunctionTemplate>* result,
352
      v8::Local<v8::Signature> sig = v8::Local<v8::Signature>()) {
353
31
    v8::Local<v8::Value> cbdata = v8impl::CallbackBundle::New(env, cb, cb_data);
354
31
    RETURN_STATUS_IF_FALSE(env, !cbdata.IsEmpty(), napi_generic_failure);
355
356
31
    *result = v8::FunctionTemplate::New(env->isolate, Invoke, cbdata, sig);
357
31
    return napi_clear_last_error(env);
358
  }
359
360
4683
  explicit FunctionCallbackWrapper(
361
      const v8::FunctionCallbackInfo<v8::Value>& cbinfo)
362
4683
      : CallbackWrapperBase(cbinfo, cbinfo.Length()) {}
363
364
8
  napi_value GetNewTarget() override {
365
16
    if (_cbinfo.IsConstructCall()) {
366
7
      return v8impl::JsValueFromV8LocalValue(_cbinfo.NewTarget());
367
    } else {
368
1
      return nullptr;
369
    }
370
  }
371
372
  /*virtual*/
373
4493
  void Args(napi_value* buffer, size_t buffer_length) override {
374
4493
    size_t i = 0;
375
4493
    size_t min = std::min(buffer_length, _args_length);
376
377
11581
    for (; i < min; i += 1) {
378
14176
      buffer[i] = v8impl::JsValueFromV8LocalValue(_cbinfo[i]);
379
    }
380
381
4493
    if (i < buffer_length) {
382
      napi_value undefined =
383
50
          v8impl::JsValueFromV8LocalValue(v8::Undefined(_cbinfo.GetIsolate()));
384
103
      for (; i < buffer_length; i += 1) {
385
78
        buffer[i] = undefined;
386
      }
387
    }
388
4493
  }
389
390
  /*virtual*/
391
2837
  void SetReturnValue(napi_value value) override {
392
2837
    v8::Local<v8::Value> val = v8impl::V8LocalValueFromJsValue(value);
393
2837
    _cbinfo.GetReturnValue().Set(val);
394
2837
  }
395
};
396
397
enum WrapType { retrievable, anonymous };
398
399
template <WrapType wrap_type>
400
2064
inline napi_status Wrap(napi_env env,
401
                        napi_value js_object,
402
                        void* native_object,
403
                        napi_finalize finalize_cb,
404
                        void* finalize_hint,
405
                        napi_ref* result) {
406




2064
  NAPI_PREAMBLE(env);
407

1032
  CHECK_ARG(env, js_object);
408
409
1032
  v8::Local<v8::Context> context = env->context();
410
411
1032
  v8::Local<v8::Value> value = v8impl::V8LocalValueFromJsValue(js_object);
412

1032
  RETURN_STATUS_IF_FALSE(env, value->IsObject(), napi_invalid_arg);
413
1032
  v8::Local<v8::Object> obj = value.As<v8::Object>();
414
415
  if (wrap_type == retrievable) {
416
    // If we've already wrapped this object, we error out.
417
2056
    RETURN_STATUS_IF_FALSE(
418
        env,
419
        !obj->HasPrivate(context, NAPI_PRIVATE_KEY(context, wrapper))
420
             .FromJust(),
421
        napi_invalid_arg);
422
  } else if (wrap_type == anonymous) {
423
    // If no finalize callback is provided, we error out.
424
4
    CHECK_ARG(env, finalize_cb);
425
  }
426
427
1031
  v8impl::Reference* reference = nullptr;
428

1031
  if (result != nullptr) {
429
    // The returned reference should be deleted via napi_delete_reference()
430
    // ONLY in response to the finalize callback invocation. (If it is deleted
431
    // before then, then the finalize callback will never be invoked.)
432
    // Therefore a finalize callback is required when returning a reference.
433

12
    CHECK_ARG(env, finalize_cb);
434
12
    reference = v8impl::Reference::New(
435
        env, obj, 0, false, finalize_cb, native_object, finalize_hint);
436
12
    *result = reinterpret_cast<napi_ref>(reference);
437
  } else {
438
    // Create a self-deleting reference.
439
1019
    reference = v8impl::Reference::New(
440
        env,
441
        obj,
442
        0,
443
        true,
444
        finalize_cb,
445
        native_object,
446

1019
        finalize_cb == nullptr ? nullptr : finalize_hint);
447
  }
448
449
  if (wrap_type == retrievable) {
450
3081
    CHECK(obj->SetPrivate(context,
451
                          NAPI_PRIVATE_KEY(context, wrapper),
452
                          v8::External::New(env->isolate, reference))
453
              .FromJust());
454
  }
455
456

1031
  return GET_RETURN_STATUS(env);
457
}
458
459
}  // end of anonymous namespace
460
461
// Wrapper around v8impl::Persistent that implements reference counting.
462
3133
RefBase::RefBase(napi_env env,
463
                 uint32_t initial_refcount,
464
                 bool delete_self,
465
                 napi_finalize finalize_callback,
466
                 void* finalize_data,
467
3133
                 void* finalize_hint)
468
    : Finalizer(env, finalize_callback, finalize_data, finalize_hint),
469
      _refcount(initial_refcount),
470
3133
      _delete_self(delete_self) {
471
3133
  Link(finalize_callback == nullptr ? &env->reflist : &env->finalizing_reflist);
472
3133
}
473
474
7
RefBase* RefBase::New(napi_env env,
475
                      uint32_t initial_refcount,
476
                      bool delete_self,
477
                      napi_finalize finalize_callback,
478
                      void* finalize_data,
479
                      void* finalize_hint) {
480
  return new RefBase(env,
481
                     initial_refcount,
482
                     delete_self,
483
                     finalize_callback,
484
                     finalize_data,
485
7
                     finalize_hint);
486
}
487
488
6260
RefBase::~RefBase() {
489
6246
  Unlink();
490
6260
}
491
492
57
void* RefBase::Data() {
493
57
  return _finalize_data;
494
}
495
496
// Delete is called in 2 ways. Either from the finalizer or
497
// from one of Unwrap or napi_delete_reference.
498
//
499
// When it is called from Unwrap or napi_delete_reference we only
500
// want to do the delete if the finalizer has already run or
501
// cannot have been queued to run (ie the reference count is > 0),
502
// otherwise we may crash when the finalizer does run.
503
// If the finalizer may have been queued and has not already run
504
// delay the delete until the finalizer runs by not doing the delete
505
// and setting _delete_self to true so that the finalizer will
506
// delete it when it runs.
507
//
508
// The second way this is called is from
509
// the finalizer and _delete_self is set. In this case we
510
// know we need to do the deletion so just do it.
511
3143
void RefBase::Delete(RefBase* reference) {
512

4169
  if ((reference->RefCount() != 0) || (reference->_delete_self) ||
513
1026
      (reference->_finalize_ran)) {
514
3123
    delete reference;
515
  } else {
516
    // defer until finalizer runs as
517
    // it may already be queued
518
20
    reference->_delete_self = true;
519
  }
520
3143
}
521
522
3
uint32_t RefBase::Ref() {
523
3
  return ++_refcount;
524
}
525
526
3
uint32_t RefBase::Unref() {
527
3
  if (_refcount == 0) {
528
    return 0;
529
  }
530
3
  return --_refcount;
531
}
532
533
6847
uint32_t RefBase::RefCount() {
534
6847
  return _refcount;
535
}
536
537
2594
void RefBase::Finalize(bool is_env_teardown) {
538
  // In addition to being called during environment teardown, this method is
539
  // also the entry point for the garbage collector. During environment
540
  // teardown we have to remove the garbage collector's reference to this
541
  // method so that, if, as part of the user's callback, JS gets executed,
542
  // resulting in a garbage collection pass, this method is not re-entered as
543
  // part of that pass, because that'll cause a double free (as seen in
544
  // https://github.com/nodejs/node/issues/37236).
545
  //
546
  // Since this class does not have access to the V8 persistent reference,
547
  // this method is overridden in the `Reference` class below. Therein the
548
  // weak callback is removed, ensuring that the garbage collector does not
549
  // re-enter this method, and the method chains up to continue the process of
550
  // environment-teardown-induced finalization.
551
552
  // During environment teardown we have to convert a strong reference to
553
  // a weak reference to force the deferring behavior if the user's finalizer
554
  // happens to delete this reference so that the code in this function that
555
  // follows the call to the user's finalizer may safely access variables from
556
  // this instance.
557

2594
  if (is_env_teardown && RefCount() > 0) _refcount = 0;
558
559
2594
  if (_finalize_callback != nullptr) {
560
    // This ensures that we never call the finalizer twice.
561
1563
    napi_finalize fini = _finalize_callback;
562
1563
    _finalize_callback = nullptr;
563
1563
    _env->CallFinalizer(fini, _finalize_data, _finalize_hint);
564
  }
565
566
  // this is safe because if a request to delete the reference
567
  // is made in the finalize_callback it will defer deletion
568
  // to this block and set _delete_self to true
569

2594
  if (_delete_self || is_env_teardown) {
570
1588
    Delete(this);
571
  } else {
572
1006
    _finalize_ran = true;
573
  }
574
2594
}
575
576
template <typename... Args>
577
3126
Reference::Reference(napi_env env, v8::Local<v8::Value> value, Args&&... args)
578
15630
    : RefBase(env, std::forward<Args>(args)...),
579
3126
      _persistent(env->isolate, value),
580
3126
      _secondPassParameter(new SecondPassCallParameterRef(this)),
581
6252
      _secondPassScheduled(false) {
582
3126
  if (RefCount() == 0) {
583
2583
    SetWeak();
584
  }
585
3126
}
586
587
3126
Reference* Reference::New(napi_env env,
588
                          v8::Local<v8::Value> value,
589
                          uint32_t initial_refcount,
590
                          bool delete_self,
591
                          napi_finalize finalize_callback,
592
                          void* finalize_data,
593
                          void* finalize_hint) {
594
  return new Reference(env,
595
                       value,
596
                       initial_refcount,
597
                       delete_self,
598
                       finalize_callback,
599
                       finalize_data,
600
3126
                       finalize_hint);
601
}
602
603
18696
Reference::~Reference() {
604
  // If the second pass callback is scheduled, it will delete the
605
  // parameter passed to it, otherwise it will never be scheduled
606
  // and we need to delete it here.
607
6232
  if (!_secondPassScheduled) {
608
2186
    delete _secondPassParameter;
609
  }
610
12464
}
611
612
3
uint32_t Reference::Ref() {
613
3
  uint32_t refcount = RefBase::Ref();
614
3
  if (refcount == 1) {
615
2
    ClearWeak();
616
  }
617
3
  return refcount;
618
}
619
620
3
uint32_t Reference::Unref() {
621
3
  uint32_t old_refcount = RefCount();
622
3
  uint32_t refcount = RefBase::Unref();
623

3
  if (old_refcount == 1 && refcount == 0) {
624
2
    SetWeak();
625
  }
626
3
  return refcount;
627
}
628
629
11550
v8::Local<v8::Value> Reference::Get() {
630
11550
  if (_persistent.IsEmpty()) {
631
1002
    return v8::Local<v8::Value>();
632
  } else {
633
21096
    return v8::Local<v8::Value>::New(_env->isolate, _persistent);
634
  }
635
}
636
637
2587
void Reference::Finalize(bool is_env_teardown) {
638
  // During env teardown, `~napi_env()` alone is responsible for finalizing.
639
  // Thus, we don't want any stray gc passes to trigger a second call to
640
  // `RefBase::Finalize()`. ClearWeak will ensure that even if the
641
  // gc is in progress no Finalization will be run for this Reference
642
  // by the gc.
643
2587
  if (is_env_teardown) {
644
565
    ClearWeak();
645
  }
646
647
  // Chain up to perform the rest of the finalization.
648
2587
  RefBase::Finalize(is_env_teardown);
649
2587
}
650
651
// ClearWeak is marking the Reference so that the gc should not
652
// collect it, but it is possible that a second pass callback
653
// may have been scheduled already if we are in shutdown. We clear
654
// the secondPassParameter so that even if it has been
655
// scheduled no Finalization will be run.
656
567
void Reference::ClearWeak() {
657
567
  if (!_persistent.IsEmpty()) {
658
565
    _persistent.ClearWeak();
659
  }
660
567
  if (_secondPassParameter != nullptr) {
661
567
    *_secondPassParameter = nullptr;
662
  }
663
567
}
664
665
// Mark the reference as weak and eligible for collection
666
// by the gc.
667
2585
void Reference::SetWeak() {
668
2585
  if (_secondPassParameter == nullptr) {
669
    // This means that the Reference has already been processed
670
    // by the second pass callback, so its already been Finalized, do
671
    // nothing
672
    return;
673
  }
674
2585
  _persistent.SetWeak(
675
      _secondPassParameter, FinalizeCallback, v8::WeakCallbackType::kParameter);
676
2585
  *_secondPassParameter = this;
677
}
678
679
// The N-API finalizer callback may make calls into the engine. V8's heap is
680
// not in a consistent state during the weak callback, and therefore it does
681
// not support calls back into it. However, it provides a mechanism for adding
682
// a finalizer which may make calls back into the engine by allowing us to
683
// attach such a second-pass finalizer from the first pass finalizer. Thus,
684
// we do that here to ensure that the N-API finalizer callback is free to call
685
// into the engine.
686
2023
void Reference::FinalizeCallback(
687
    const v8::WeakCallbackInfo<SecondPassCallParameterRef>& data) {
688
2023
  SecondPassCallParameterRef* parameter = data.GetParameter();
689
2023
  Reference* reference = *parameter;
690
2023
  if (reference == nullptr) {
691
    return;
692
  }
693
694
  // The reference must be reset during the first pass.
695
2023
  reference->_persistent.Reset();
696
  // Mark the parameter not delete-able until the second pass callback is
697
  // invoked.
698
2023
  reference->_secondPassScheduled = true;
699
700
2023
  data.SetSecondPassCallback(SecondPassCallback);
701
}
702
703
// Second pass callbacks are scheduled with platform tasks. At env teardown,
704
// the tasks may have already be scheduled and we are unable to cancel the
705
// second pass callback task. We have to make sure that parameter is kept
706
// alive until the second pass callback is been invoked. In order to do
707
// this and still allow our code to Finalize/delete the Reference during
708
// shutdown we have to use a separately allocated parameter instead
709
// of a parameter within the Reference object itself. This is what
710
// is stored in _secondPassParameter and it is allocated in the
711
// constructor for the Reference.
712
2023
void Reference::SecondPassCallback(
713
    const v8::WeakCallbackInfo<SecondPassCallParameterRef>& data) {
714
2023
  SecondPassCallParameterRef* parameter = data.GetParameter();
715
2023
  Reference* reference = *parameter;
716
2023
  delete parameter;
717
2023
  if (reference == nullptr) {
718
    // the reference itself has already been deleted so nothing to do
719
1
    return;
720
  }
721
2022
  reference->_secondPassParameter = nullptr;
722
2022
  reference->Finalize();
723
}
724
725
}  // end of namespace v8impl
726
727
// Warning: Keep in-sync with napi_status enum
728
static const char* error_messages[] = {
729
    nullptr,
730
    "Invalid argument",
731
    "An object was expected",
732
    "A string was expected",
733
    "A string or symbol was expected",
734
    "A function was expected",
735
    "A number was expected",
736
    "A boolean was expected",
737
    "An array was expected",
738
    "Unknown failure",
739
    "An exception is pending",
740
    "The async work item was cancelled",
741
    "napi_escape_handle already called on scope",
742
    "Invalid handle scope usage",
743
    "Invalid callback scope usage",
744
    "Thread-safe function queue is full",
745
    "Thread-safe function handle is closing",
746
    "A bigint was expected",
747
    "A date was expected",
748
    "An arraybuffer was expected",
749
    "A detachable arraybuffer was expected",
750
    "Main thread would deadlock",
751
};
752
753
1318
napi_status NAPI_CDECL napi_get_last_error_info(
754
    napi_env env, const napi_extended_error_info** result) {
755
1318
  CHECK_ENV(env);
756
1318
  CHECK_ARG(env, result);
757
758
  // The value of the constant below must be updated to reference the last
759
  // message in the `napi_status` enum each time a new error message is added.
760
  // We don't have a napi_status_last as this would result in an ABI
761
  // change each time a message was added.
762
1318
  const int last_status = napi_would_deadlock;
763
764
  static_assert(NAPI_ARRAYSIZE(error_messages) == last_status + 1,
765
                "Count of error messages must match count of error values");
766
1318
  CHECK_LE(env->last_error.error_code, last_status);
767
  // Wait until someone requests the last error information to fetch the error
768
  // message string
769
1318
  env->last_error.error_message = error_messages[env->last_error.error_code];
770
771
1318
  if (env->last_error.error_code == napi_ok) {
772
10
    napi_clear_last_error(env);
773
  }
774
1318
  *result = &(env->last_error);
775
1318
  return napi_ok;
776
}
777
778
15
napi_status NAPI_CDECL napi_create_function(napi_env env,
779
                                            const char* utf8name,
780
                                            size_t length,
781
                                            napi_callback cb,
782
                                            void* callback_data,
783
                                            napi_value* result) {
784


30
  NAPI_PREAMBLE(env);
785
15
  CHECK_ARG(env, result);
786
15
  CHECK_ARG(env, cb);
787
788
  v8::Local<v8::Function> return_value;
789
15
  v8::EscapableHandleScope scope(env->isolate);
790
  v8::Local<v8::Function> fn;
791
15
  STATUS_CALL(v8impl::FunctionCallbackWrapper::NewFunction(
792
      env, cb, callback_data, &fn));
793
15
  return_value = scope.Escape(fn);
794
795
15
  if (utf8name != nullptr) {
796
    v8::Local<v8::String> name_string;
797


9
    CHECK_NEW_FROM_UTF8_LEN(env, name_string, utf8name, length);
798
3
    return_value->SetName(name_string);
799
  }
800
801
15
  *result = v8impl::JsValueFromV8LocalValue(return_value);
802
803
15
  return GET_RETURN_STATUS(env);
804
}
805
806
napi_status NAPI_CDECL
807
15
napi_define_class(napi_env env,
808
                  const char* utf8name,
809
                  size_t length,
810
                  napi_callback constructor,
811
                  void* callback_data,
812
                  size_t property_count,
813
                  const napi_property_descriptor* properties,
814
                  napi_value* result) {
815


29
  NAPI_PREAMBLE(env);
816
14
  CHECK_ARG(env, result);
817
13
  CHECK_ARG(env, constructor);
818
819
12
  if (property_count > 0) {
820
7
    CHECK_ARG(env, properties);
821
  }
822
823
11
  v8::Isolate* isolate = env->isolate;
824
825
11
  v8::EscapableHandleScope scope(isolate);
826
  v8::Local<v8::FunctionTemplate> tpl;
827
11
  STATUS_CALL(v8impl::FunctionCallbackWrapper::NewTemplate(
828
      env, constructor, callback_data, &tpl));
829
830
  v8::Local<v8::String> name_string;
831


31
  CHECK_NEW_FROM_UTF8_LEN(env, name_string, utf8name, length);
832
10
  tpl->SetClassName(name_string);
833
834
10
  size_t static_property_count = 0;
835
38
  for (size_t i = 0; i < property_count; i++) {
836
28
    const napi_property_descriptor* p = properties + i;
837
838
28
    if ((p->attributes & napi_static) != 0) {
839
      // Static properties are handled separately below.
840
7
      static_property_count++;
841
7
      continue;
842
    }
843
844
    v8::Local<v8::Name> property_name;
845
21
    STATUS_CALL(v8impl::V8NameFromPropertyDescriptor(env, p, &property_name));
846
847
    v8::PropertyAttribute attributes =
848
21
        v8impl::V8PropertyAttributesFromDescriptor(p);
849
850
    // This code is similar to that in napi_define_properties(); the
851
    // difference is it applies to a template instead of an object,
852
    // and preferred PropertyAttribute for lack of PropertyDescriptor
853
    // support on ObjectTemplate.
854

21
    if (p->getter != nullptr || p->setter != nullptr) {
855
      v8::Local<v8::FunctionTemplate> getter_tpl;
856
      v8::Local<v8::FunctionTemplate> setter_tpl;
857
10
      if (p->getter != nullptr) {
858
10
        STATUS_CALL(v8impl::FunctionCallbackWrapper::NewTemplate(
859
            env, p->getter, p->data, &getter_tpl));
860
      }
861
10
      if (p->setter != nullptr) {
862
5
        STATUS_CALL(v8impl::FunctionCallbackWrapper::NewTemplate(
863
            env, p->setter, p->data, &setter_tpl));
864
      }
865
866
20
      tpl->PrototypeTemplate()->SetAccessorProperty(property_name,
867
                                                    getter_tpl,
868
                                                    setter_tpl,
869
                                                    attributes,
870
10
                                                    v8::AccessControl::DEFAULT);
871
11
    } else if (p->method != nullptr) {
872
      v8::Local<v8::FunctionTemplate> t;
873
5
      STATUS_CALL(v8impl::FunctionCallbackWrapper::NewTemplate(
874
          env, p->method, p->data, &t, v8::Signature::New(isolate, tpl)));
875
876
10
      tpl->PrototypeTemplate()->Set(property_name, t, attributes);
877
    } else {
878
6
      v8::Local<v8::Value> value = v8impl::V8LocalValueFromJsValue(p->value);
879
12
      tpl->PrototypeTemplate()->Set(property_name, value, attributes);
880
    }
881
  }
882
883
10
  v8::Local<v8::Context> context = env->context();
884
10
  *result = v8impl::JsValueFromV8LocalValue(
885
10
      scope.Escape(tpl->GetFunction(context).ToLocalChecked()));
886
887
10
  if (static_property_count > 0) {
888
3
    std::vector<napi_property_descriptor> static_descriptors;
889
3
    static_descriptors.reserve(static_property_count);
890
891
26
    for (size_t i = 0; i < property_count; i++) {
892
23
      const napi_property_descriptor* p = properties + i;
893
23
      if ((p->attributes & napi_static) != 0) {
894
7
        static_descriptors.push_back(*p);
895
      }
896
    }
897
898
3
    STATUS_CALL(napi_define_properties(
899
        env, *result, static_descriptors.size(), static_descriptors.data()));
900
  }
901
902
10
  return GET_RETURN_STATUS(env);
903
}
904
905
8
napi_status NAPI_CDECL napi_get_property_names(napi_env env,
906
                                               napi_value object,
907
                                               napi_value* result) {
908
8
  return napi_get_all_property_names(
909
      env,
910
      object,
911
      napi_key_include_prototypes,
912
      static_cast<napi_key_filter>(napi_key_enumerable | napi_key_skip_symbols),
913
      napi_key_numbers_to_strings,
914
8
      result);
915
}
916
917
napi_status NAPI_CDECL
918
16
napi_get_all_property_names(napi_env env,
919
                            napi_value object,
920
                            napi_key_collection_mode key_mode,
921
                            napi_key_filter key_filter,
922
                            napi_key_conversion key_conversion,
923
                            napi_value* result) {
924


30
  NAPI_PREAMBLE(env);
925
14
  CHECK_ARG(env, result);
926
927
12
  v8::Local<v8::Context> context = env->context();
928
  v8::Local<v8::Object> obj;
929

22
  CHECK_TO_OBJECT(env, context, obj, object);
930
931
10
  v8::PropertyFilter filter = v8::PropertyFilter::ALL_PROPERTIES;
932
10
  if (key_filter & napi_key_writable) {
933
2
    filter = static_cast<v8::PropertyFilter>(filter |
934
                                             v8::PropertyFilter::ONLY_WRITABLE);
935
  }
936
10
  if (key_filter & napi_key_enumerable) {
937
7
    filter = static_cast<v8::PropertyFilter>(
938
7
        filter | v8::PropertyFilter::ONLY_ENUMERABLE);
939
  }
940
10
  if (key_filter & napi_key_configurable) {
941
2
    filter = static_cast<v8::PropertyFilter>(
942
2
        filter | v8::PropertyFilter::ONLY_CONFIGURABLE);
943
  }
944
10
  if (key_filter & napi_key_skip_strings) {
945
1
    filter = static_cast<v8::PropertyFilter>(filter |
946
                                             v8::PropertyFilter::SKIP_STRINGS);
947
  }
948
10
  if (key_filter & napi_key_skip_symbols) {
949
5
    filter = static_cast<v8::PropertyFilter>(filter |
950
                                             v8::PropertyFilter::SKIP_SYMBOLS);
951
  }
952
  v8::KeyCollectionMode collection_mode;
953
  v8::KeyConversionMode conversion_mode;
954
955
10
  switch (key_mode) {
956
8
    case napi_key_include_prototypes:
957
8
      collection_mode = v8::KeyCollectionMode::kIncludePrototypes;
958
8
      break;
959
2
    case napi_key_own_only:
960
2
      collection_mode = v8::KeyCollectionMode::kOwnOnly;
961
2
      break;
962
    default:
963
      return napi_set_last_error(env, napi_invalid_arg);
964
  }
965
966
10
  switch (key_conversion) {
967
    case napi_key_keep_numbers:
968
      conversion_mode = v8::KeyConversionMode::kKeepNumbers;
969
      break;
970
10
    case napi_key_numbers_to_strings:
971
10
      conversion_mode = v8::KeyConversionMode::kConvertToString;
972
10
      break;
973
    default:
974
      return napi_set_last_error(env, napi_invalid_arg);
975
  }
976
977
  v8::MaybeLocal<v8::Array> maybe_all_propertynames =
978
      obj->GetPropertyNames(context,
979
                            collection_mode,
980
                            filter,
981
                            v8::IndexFilter::kIncludeIndices,
982
10
                            conversion_mode);
983
984

10
  CHECK_MAYBE_EMPTY_WITH_PREAMBLE(
985
      env, maybe_all_propertynames, napi_generic_failure);
986
987
20
  *result =
988
10
      v8impl::JsValueFromV8LocalValue(maybe_all_propertynames.ToLocalChecked());
989
10
  return GET_RETURN_STATUS(env);
990
}
991
992
27
napi_status NAPI_CDECL napi_set_property(napi_env env,
993
                                         napi_value object,
994
                                         napi_value key,
995
                                         napi_value value) {
996


52
  NAPI_PREAMBLE(env);
997
25
  CHECK_ARG(env, key);
998
22
  CHECK_ARG(env, value);
999
1000
20
  v8::Local<v8::Context> context = env->context();
1001
  v8::Local<v8::Object> obj;
1002
1003

38
  CHECK_TO_OBJECT(env, context, obj, object);
1004
1005
18
  v8::Local<v8::Value> k = v8impl::V8LocalValueFromJsValue(key);
1006
18
  v8::Local<v8::Value> val = v8impl::V8LocalValueFromJsValue(value);
1007
1008
18
  v8::Maybe<bool> set_maybe = obj->Set(context, k, val);
1009
1010

36
  RETURN_STATUS_IF_FALSE(env, set_maybe.FromMaybe(false), napi_generic_failure);
1011
18
  return GET_RETURN_STATUS(env);
1012
}
1013
1014
16
napi_status NAPI_CDECL napi_has_property(napi_env env,
1015
                                         napi_value object,
1016
                                         napi_value key,
1017
                                         bool* result) {
1018


30
  NAPI_PREAMBLE(env);
1019
14
  CHECK_ARG(env, result);
1020
12
  CHECK_ARG(env, key);
1021
1022
10
  v8::Local<v8::Context> context = env->context();
1023
  v8::Local<v8::Object> obj;
1024
1025

18
  CHECK_TO_OBJECT(env, context, obj, object);
1026
1027
8
  v8::Local<v8::Value> k = v8impl::V8LocalValueFromJsValue(key);
1028
8
  v8::Maybe<bool> has_maybe = obj->Has(context, k);
1029
1030
8
  CHECK_MAYBE_NOTHING(env, has_maybe, napi_generic_failure);
1031
1032
8
  *result = has_maybe.FromMaybe(false);
1033
8
  return GET_RETURN_STATUS(env);
1034
}
1035
1036
34
napi_status NAPI_CDECL napi_get_property(napi_env env,
1037
                                         napi_value object,
1038
                                         napi_value key,
1039
                                         napi_value* result) {
1040


66
  NAPI_PREAMBLE(env);
1041
32
  CHECK_ARG(env, key);
1042
28
  CHECK_ARG(env, result);
1043
1044
26
  v8::Local<v8::Context> context = env->context();
1045
26
  v8::Local<v8::Value> k = v8impl::V8LocalValueFromJsValue(key);
1046
  v8::Local<v8::Object> obj;
1047
1048

74
  CHECK_TO_OBJECT(env, context, obj, object);
1049
1050
24
  auto get_maybe = obj->Get(context, k);
1051
1052
24
  CHECK_MAYBE_EMPTY(env, get_maybe, napi_generic_failure);
1053
1054
24
  v8::Local<v8::Value> val = get_maybe.ToLocalChecked();
1055
24
  *result = v8impl::JsValueFromV8LocalValue(val);
1056
24
  return GET_RETURN_STATUS(env);
1057
}
1058
1059
9
napi_status NAPI_CDECL napi_delete_property(napi_env env,
1060
                                            napi_value object,
1061
                                            napi_value key,
1062
                                            bool* result) {
1063


17
  NAPI_PREAMBLE(env);
1064
8
  CHECK_ARG(env, key);
1065
1066
7
  v8::Local<v8::Context> context = env->context();
1067
7
  v8::Local<v8::Value> k = v8impl::V8LocalValueFromJsValue(key);
1068
  v8::Local<v8::Object> obj;
1069
1070

19
  CHECK_TO_OBJECT(env, context, obj, object);
1071
6
  v8::Maybe<bool> delete_maybe = obj->Delete(context, k);
1072
6
  CHECK_MAYBE_NOTHING(env, delete_maybe, napi_generic_failure);
1073
1074

11
  if (result != nullptr) *result = delete_maybe.FromMaybe(false);
1075
1076
6
  return GET_RETURN_STATUS(env);
1077
}
1078
1079
19
napi_status NAPI_CDECL napi_has_own_property(napi_env env,
1080
                                             napi_value object,
1081
                                             napi_value key,
1082
                                             bool* result) {
1083


37
  NAPI_PREAMBLE(env);
1084
18
  CHECK_ARG(env, key);
1085
17
  CHECK_ARG(env, result);
1086
1087
16
  v8::Local<v8::Context> context = env->context();
1088
  v8::Local<v8::Object> obj;
1089
1090

31
  CHECK_TO_OBJECT(env, context, obj, object);
1091
15
  v8::Local<v8::Value> k = v8impl::V8LocalValueFromJsValue(key);
1092
15
  RETURN_STATUS_IF_FALSE(env, k->IsName(), napi_name_expected);
1093
12
  v8::Maybe<bool> has_maybe = obj->HasOwnProperty(context, k.As<v8::Name>());
1094
6
  CHECK_MAYBE_NOTHING(env, has_maybe, napi_generic_failure);
1095
6
  *result = has_maybe.FromMaybe(false);
1096
1097
6
  return GET_RETURN_STATUS(env);
1098
}
1099
1100
168
napi_status NAPI_CDECL napi_set_named_property(napi_env env,
1101
                                               napi_value object,
1102
                                               const char* utf8name,
1103
                                               napi_value value) {
1104


335
  NAPI_PREAMBLE(env);
1105
167
  CHECK_ARG(env, value);
1106
1107
166
  v8::Local<v8::Context> context = env->context();
1108
  v8::Local<v8::Object> obj;
1109
1110

496
  CHECK_TO_OBJECT(env, context, obj, object);
1111
1112
  v8::Local<v8::Name> key;
1113

329
  CHECK_NEW_FROM_UTF8(env, key, utf8name);
1114
1115
164
  v8::Local<v8::Value> val = v8impl::V8LocalValueFromJsValue(value);
1116
1117
164
  v8::Maybe<bool> set_maybe = obj->Set(context, key, val);
1118
1119

328
  RETURN_STATUS_IF_FALSE(env, set_maybe.FromMaybe(false), napi_generic_failure);
1120
164
  return GET_RETURN_STATUS(env);
1121
}
1122
1123
9
napi_status NAPI_CDECL napi_has_named_property(napi_env env,
1124
                                               napi_value object,
1125
                                               const char* utf8name,
1126
                                               bool* result) {
1127


17
  NAPI_PREAMBLE(env);
1128
8
  CHECK_ARG(env, result);
1129
1130
7
  v8::Local<v8::Context> context = env->context();
1131
  v8::Local<v8::Object> obj;
1132
1133

19
  CHECK_TO_OBJECT(env, context, obj, object);
1134
1135
  v8::Local<v8::Name> key;
1136

16
  CHECK_NEW_FROM_UTF8(env, key, utf8name);
1137
1138
5
  v8::Maybe<bool> has_maybe = obj->Has(context, key);
1139
1140
5
  CHECK_MAYBE_NOTHING(env, has_maybe, napi_generic_failure);
1141
1142
5
  *result = has_maybe.FromMaybe(false);
1143
5
  return GET_RETURN_STATUS(env);
1144
}
1145
1146
6
napi_status NAPI_CDECL napi_get_named_property(napi_env env,
1147
                                               napi_value object,
1148
                                               const char* utf8name,
1149
                                               napi_value* result) {
1150


10
  NAPI_PREAMBLE(env);
1151
4
  CHECK_ARG(env, result);
1152
1153
3
  v8::Local<v8::Context> context = env->context();
1154
1155
  v8::Local<v8::Name> key;
1156

7
  CHECK_NEW_FROM_UTF8(env, key, utf8name);
1157
1158
  v8::Local<v8::Object> obj;
1159
1160

4
  CHECK_TO_OBJECT(env, context, obj, object);
1161
1162
1
  auto get_maybe = obj->Get(context, key);
1163
1164
1
  CHECK_MAYBE_EMPTY(env, get_maybe, napi_generic_failure);
1165
1166
1
  v8::Local<v8::Value> val = get_maybe.ToLocalChecked();
1167
1
  *result = v8impl::JsValueFromV8LocalValue(val);
1168
1
  return GET_RETURN_STATUS(env);
1169
}
1170
1171
13
napi_status NAPI_CDECL napi_set_element(napi_env env,
1172
                                        napi_value object,
1173
                                        uint32_t index,
1174
                                        napi_value value) {
1175


25
  NAPI_PREAMBLE(env);
1176
12
  CHECK_ARG(env, value);
1177
1178
12
  v8::Local<v8::Context> context = env->context();
1179
  v8::Local<v8::Object> obj;
1180
1181

23
  CHECK_TO_OBJECT(env, context, obj, object);
1182
1183
11
  v8::Local<v8::Value> val = v8impl::V8LocalValueFromJsValue(value);
1184
11
  auto set_maybe = obj->Set(context, index, val);
1185
1186

22
  RETURN_STATUS_IF_FALSE(env, set_maybe.FromMaybe(false), napi_generic_failure);
1187
1188
11
  return GET_RETURN_STATUS(env);
1189
}
1190
1191
5
napi_status NAPI_CDECL napi_has_element(napi_env env,
1192
                                        napi_value object,
1193
                                        uint32_t index,
1194
                                        bool* result) {
1195


9
  NAPI_PREAMBLE(env);
1196
4
  CHECK_ARG(env, result);
1197
1198
3
  v8::Local<v8::Context> context = env->context();
1199
  v8::Local<v8::Object> obj;
1200
1201

7
  CHECK_TO_OBJECT(env, context, obj, object);
1202
1203
2
  v8::Maybe<bool> has_maybe = obj->Has(context, index);
1204
1205
2
  CHECK_MAYBE_NOTHING(env, has_maybe, napi_generic_failure);
1206
1207
2
  *result = has_maybe.FromMaybe(false);
1208
2
  return GET_RETURN_STATUS(env);
1209
}
1210
1211
28
napi_status NAPI_CDECL napi_get_element(napi_env env,
1212
                                        napi_value object,
1213
                                        uint32_t index,
1214
                                        napi_value* result) {
1215


55
  NAPI_PREAMBLE(env);
1216
27
  CHECK_ARG(env, result);
1217
1218
27
  v8::Local<v8::Context> context = env->context();
1219
  v8::Local<v8::Object> obj;
1220
1221

81
  CHECK_TO_OBJECT(env, context, obj, object);
1222
1223
27
  auto get_maybe = obj->Get(context, index);
1224
1225
27
  CHECK_MAYBE_EMPTY(env, get_maybe, napi_generic_failure);
1226
1227
27
  *result = v8impl::JsValueFromV8LocalValue(get_maybe.ToLocalChecked());
1228
27
  return GET_RETURN_STATUS(env);
1229
}
1230
1231
4
napi_status NAPI_CDECL napi_delete_element(napi_env env,
1232
                                           napi_value object,
1233
                                           uint32_t index,
1234
                                           bool* result) {
1235


7
  NAPI_PREAMBLE(env);
1236
1237
3
  v8::Local<v8::Context> context = env->context();
1238
  v8::Local<v8::Object> obj;
1239
1240

7
  CHECK_TO_OBJECT(env, context, obj, object);
1241
2
  v8::Maybe<bool> delete_maybe = obj->Delete(context, index);
1242
2
  CHECK_MAYBE_NOTHING(env, delete_maybe, napi_generic_failure);
1243
1244

3
  if (result != nullptr) *result = delete_maybe.FromMaybe(false);
1245
1246
2
  return GET_RETURN_STATUS(env);
1247
}
1248
1249
napi_status NAPI_CDECL
1250
91
napi_define_properties(napi_env env,
1251
                       napi_value object,
1252
                       size_t property_count,
1253
                       const napi_property_descriptor* properties) {
1254


181
  NAPI_PREAMBLE(env);
1255
90
  if (property_count > 0) {
1256
90
    CHECK_ARG(env, properties);
1257
  }
1258
1259
87
  v8::Local<v8::Context> context = env->context();
1260
1261
  v8::Local<v8::Object> obj;
1262

173
  CHECK_TO_OBJECT(env, context, obj, object);
1263
1264
604
  for (size_t i = 0; i < property_count; i++) {
1265
518
    const napi_property_descriptor* p = &properties[i];
1266
1267
    v8::Local<v8::Name> property_name;
1268
518
    STATUS_CALL(v8impl::V8NameFromPropertyDescriptor(env, p, &property_name));
1269
1270

518
    if (p->getter != nullptr || p->setter != nullptr) {
1271
      v8::Local<v8::Function> local_getter;
1272
      v8::Local<v8::Function> local_setter;
1273
1274
13
      if (p->getter != nullptr) {
1275
13
        STATUS_CALL(v8impl::FunctionCallbackWrapper::NewFunction(
1276
            env, p->getter, p->data, &local_getter));
1277
      }
1278
13
      if (p->setter != nullptr) {
1279
2
        STATUS_CALL(v8impl::FunctionCallbackWrapper::NewFunction(
1280
            env, p->setter, p->data, &local_setter));
1281
      }
1282
1283
13
      v8::PropertyDescriptor descriptor(local_getter, local_setter);
1284
13
      descriptor.set_enumerable((p->attributes & napi_enumerable) != 0);
1285
13
      descriptor.set_configurable((p->attributes & napi_configurable) != 0);
1286
1287
      auto define_maybe =
1288
13
          obj->DefineProperty(context, property_name, descriptor);
1289
1290

26
      if (!define_maybe.FromMaybe(false)) {
1291
        return napi_set_last_error(env, napi_invalid_arg);
1292
13
      }
1293
505
    } else if (p->method != nullptr) {
1294
      v8::Local<v8::Function> method;
1295
479
      STATUS_CALL(v8impl::FunctionCallbackWrapper::NewFunction(
1296
          env, p->method, p->data, &method));
1297
      v8::PropertyDescriptor descriptor(method,
1298
479
                                        (p->attributes & napi_writable) != 0);
1299
479
      descriptor.set_enumerable((p->attributes & napi_enumerable) != 0);
1300
479
      descriptor.set_configurable((p->attributes & napi_configurable) != 0);
1301
1302
      auto define_maybe =
1303
479
          obj->DefineProperty(context, property_name, descriptor);
1304
1305

958
      if (!define_maybe.FromMaybe(false)) {
1306
        return napi_set_last_error(env, napi_generic_failure);
1307
      }
1308
    } else {
1309
26
      v8::Local<v8::Value> value = v8impl::V8LocalValueFromJsValue(p->value);
1310
1311
      v8::PropertyDescriptor descriptor(value,
1312
26
                                        (p->attributes & napi_writable) != 0);
1313
26
      descriptor.set_enumerable((p->attributes & napi_enumerable) != 0);
1314
26
      descriptor.set_configurable((p->attributes & napi_configurable) != 0);
1315
1316
      auto define_maybe =
1317
26
          obj->DefineProperty(context, property_name, descriptor);
1318
1319

52
      if (!define_maybe.FromMaybe(false)) {
1320
        return napi_set_last_error(env, napi_invalid_arg);
1321
      }
1322
    }
1323
  }
1324
1325
86
  return GET_RETURN_STATUS(env);
1326
}
1327
1328
1
napi_status NAPI_CDECL napi_object_freeze(napi_env env, napi_value object) {
1329


2
  NAPI_PREAMBLE(env);
1330
1331
1
  v8::Local<v8::Context> context = env->context();
1332
  v8::Local<v8::Object> obj;
1333
1334

3
  CHECK_TO_OBJECT(env, context, obj, object);
1335
1336
  v8::Maybe<bool> set_frozen =
1337
1
      obj->SetIntegrityLevel(context, v8::IntegrityLevel::kFrozen);
1338
1339

2
  RETURN_STATUS_IF_FALSE_WITH_PREAMBLE(
1340
      env, set_frozen.FromMaybe(false), napi_generic_failure);
1341
1342
1
  return GET_RETURN_STATUS(env);
1343
}
1344
1345
1
napi_status NAPI_CDECL napi_object_seal(napi_env env, napi_value object) {
1346


2
  NAPI_PREAMBLE(env);
1347
1348
1
  v8::Local<v8::Context> context = env->context();
1349
  v8::Local<v8::Object> obj;
1350
1351

3
  CHECK_TO_OBJECT(env, context, obj, object);
1352
1353
  v8::Maybe<bool> set_sealed =
1354
1
      obj->SetIntegrityLevel(context, v8::IntegrityLevel::kSealed);
1355
1356

2
  RETURN_STATUS_IF_FALSE_WITH_PREAMBLE(
1357
      env, set_sealed.FromMaybe(false), napi_generic_failure);
1358
1359
1
  return GET_RETURN_STATUS(env);
1360
}
1361
1362
11
napi_status NAPI_CDECL napi_is_array(napi_env env,
1363
                                     napi_value value,
1364
                                     bool* result) {
1365
11
  CHECK_ENV(env);
1366
11
  CHECK_ARG(env, value);
1367
11
  CHECK_ARG(env, result);
1368
1369
11
  v8::Local<v8::Value> val = v8impl::V8LocalValueFromJsValue(value);
1370
1371
11
  *result = val->IsArray();
1372
11
  return napi_clear_last_error(env);
1373
}
1374
1375
13
napi_status NAPI_CDECL napi_get_array_length(napi_env env,
1376
                                             napi_value value,
1377
                                             uint32_t* result) {
1378


26
  NAPI_PREAMBLE(env);
1379
13
  CHECK_ARG(env, value);
1380
13
  CHECK_ARG(env, result);
1381
1382
13
  v8::Local<v8::Value> val = v8impl::V8LocalValueFromJsValue(value);
1383
13
  RETURN_STATUS_IF_FALSE(env, val->IsArray(), napi_array_expected);
1384
1385
13
  v8::Local<v8::Array> arr = val.As<v8::Array>();
1386
13
  *result = arr->Length();
1387
1388
13
  return GET_RETURN_STATUS(env);
1389
}
1390
1391
9
napi_status NAPI_CDECL napi_strict_equals(napi_env env,
1392
                                          napi_value lhs,
1393
                                          napi_value rhs,
1394
                                          bool* result) {
1395


18
  NAPI_PREAMBLE(env);
1396
9
  CHECK_ARG(env, lhs);
1397
9
  CHECK_ARG(env, rhs);
1398
9
  CHECK_ARG(env, result);
1399
1400
9
  v8::Local<v8::Value> a = v8impl::V8LocalValueFromJsValue(lhs);
1401
9
  v8::Local<v8::Value> b = v8impl::V8LocalValueFromJsValue(rhs);
1402
1403
9
  *result = a->StrictEquals(b);
1404
9
  return GET_RETURN_STATUS(env);
1405
}
1406
1407
7
napi_status NAPI_CDECL napi_get_prototype(napi_env env,
1408
                                          napi_value object,
1409
                                          napi_value* result) {
1410


13
  NAPI_PREAMBLE(env);
1411
6
  CHECK_ARG(env, result);
1412
1413
5
  v8::Local<v8::Context> context = env->context();
1414
1415
  v8::Local<v8::Object> obj;
1416

13
  CHECK_TO_OBJECT(env, context, obj, object);
1417
1418
4
  v8::Local<v8::Value> val = obj->GetPrototype();
1419
4
  *result = v8impl::JsValueFromV8LocalValue(val);
1420
4
  return GET_RETURN_STATUS(env);
1421
}
1422
1423
72
napi_status NAPI_CDECL napi_create_object(napi_env env, napi_value* result) {
1424
72
  CHECK_ENV(env);
1425
72
  CHECK_ARG(env, result);
1426
1427
144
  *result = v8impl::JsValueFromV8LocalValue(v8::Object::New(env->isolate));
1428
1429
72
  return napi_clear_last_error(env);
1430
}
1431
1432
1
napi_status NAPI_CDECL napi_create_array(napi_env env, napi_value* result) {
1433
1
  CHECK_ENV(env);
1434
1
  CHECK_ARG(env, result);
1435
1436
2
  *result = v8impl::JsValueFromV8LocalValue(v8::Array::New(env->isolate));
1437
1438
1
  return napi_clear_last_error(env);
1439
}
1440
1441
4
napi_status NAPI_CDECL napi_create_array_with_length(napi_env env,
1442
                                                     size_t length,
1443
                                                     napi_value* result) {
1444
4
  CHECK_ENV(env);
1445
4
  CHECK_ARG(env, result);
1446
1447
8
  *result =
1448
8
      v8impl::JsValueFromV8LocalValue(v8::Array::New(env->isolate, length));
1449
1450
4
  return napi_clear_last_error(env);
1451
}
1452
1453
16
napi_status NAPI_CDECL napi_create_string_latin1(napi_env env,
1454
                                                 const char* str,
1455
                                                 size_t length,
1456
                                                 napi_value* result) {
1457
16
  CHECK_ENV(env);
1458

15
  if (length > 0) CHECK_ARG(env, str);
1459
14
  CHECK_ARG(env, result);
1460

13
  RETURN_STATUS_IF_FALSE(
1461
      env, (length == NAPI_AUTO_LENGTH) || length <= INT_MAX, napi_invalid_arg);
1462
1463
12
  auto isolate = env->isolate;
1464
  auto str_maybe =
1465
      v8::String::NewFromOneByte(isolate,
1466
                                 reinterpret_cast<const uint8_t*>(str),
1467
                                 v8::NewStringType::kNormal,
1468
12
                                 length);
1469
12
  CHECK_MAYBE_EMPTY(env, str_maybe, napi_generic_failure);
1470
1471
12
  *result = v8impl::JsValueFromV8LocalValue(str_maybe.ToLocalChecked());
1472
12
  return napi_clear_last_error(env);
1473
}
1474
1475
749
napi_status NAPI_CDECL napi_create_string_utf8(napi_env env,
1476
                                               const char* str,
1477
                                               size_t length,
1478
                                               napi_value* result) {
1479
749
  CHECK_ENV(env);
1480

748
  if (length > 0) CHECK_ARG(env, str);
1481
746
  CHECK_ARG(env, result);
1482

745
  RETURN_STATUS_IF_FALSE(
1483
      env, (length == NAPI_AUTO_LENGTH) || length <= INT_MAX, napi_invalid_arg);
1484
1485
744
  auto isolate = env->isolate;
1486
  auto str_maybe = v8::String::NewFromUtf8(
1487
744
      isolate, str, v8::NewStringType::kNormal, static_cast<int>(length));
1488
744
  CHECK_MAYBE_EMPTY(env, str_maybe, napi_generic_failure);
1489
744
  *result = v8impl::JsValueFromV8LocalValue(str_maybe.ToLocalChecked());
1490
744
  return napi_clear_last_error(env);
1491
}
1492
1493
18
napi_status NAPI_CDECL napi_create_string_utf16(napi_env env,
1494
                                                const char16_t* str,
1495
                                                size_t length,
1496
                                                napi_value* result) {
1497
18
  CHECK_ENV(env);
1498

17
  if (length > 0) CHECK_ARG(env, str);
1499
16
  CHECK_ARG(env, result);
1500

15
  RETURN_STATUS_IF_FALSE(
1501
      env, (length == NAPI_AUTO_LENGTH) || length <= INT_MAX, napi_invalid_arg);
1502
1503
14
  auto isolate = env->isolate;
1504
  auto str_maybe =
1505
      v8::String::NewFromTwoByte(isolate,
1506
                                 reinterpret_cast<const uint16_t*>(str),
1507
                                 v8::NewStringType::kNormal,
1508
14
                                 length);
1509
14
  CHECK_MAYBE_EMPTY(env, str_maybe, napi_generic_failure);
1510
1511
14
  *result = v8impl::JsValueFromV8LocalValue(str_maybe.ToLocalChecked());
1512
14
  return napi_clear_last_error(env);
1513
}
1514
1515
71
napi_status NAPI_CDECL napi_create_double(napi_env env,
1516
                                          double value,
1517
                                          napi_value* result) {
1518
71
  CHECK_ENV(env);
1519
71
  CHECK_ARG(env, result);
1520
1521
142
  *result =
1522
142
      v8impl::JsValueFromV8LocalValue(v8::Number::New(env->isolate, value));
1523
1524
71
  return napi_clear_last_error(env);
1525
}
1526
1527
105064
napi_status NAPI_CDECL napi_create_int32(napi_env env,
1528
                                         int32_t value,
1529
                                         napi_value* result) {
1530
105064
  CHECK_ENV(env);
1531
105064
  CHECK_ARG(env, result);
1532
1533
210128
  *result =
1534
210128
      v8impl::JsValueFromV8LocalValue(v8::Integer::New(env->isolate, value));
1535
1536
105064
  return napi_clear_last_error(env);
1537
}
1538
1539
559
napi_status NAPI_CDECL napi_create_uint32(napi_env env,
1540
                                          uint32_t value,
1541
                                          napi_value* result) {
1542
559
  CHECK_ENV(env);
1543
559
  CHECK_ARG(env, result);
1544
1545
559
  *result = v8impl::JsValueFromV8LocalValue(
1546
559
      v8::Integer::NewFromUnsigned(env->isolate, value));
1547
1548
559
  return napi_clear_last_error(env);
1549
}
1550
1551
24
napi_status NAPI_CDECL napi_create_int64(napi_env env,
1552
                                         int64_t value,
1553
                                         napi_value* result) {
1554
24
  CHECK_ENV(env);
1555
24
  CHECK_ARG(env, result);
1556
1557
24
  *result = v8impl::JsValueFromV8LocalValue(
1558
24
      v8::Number::New(env->isolate, static_cast<double>(value)));
1559
1560
24
  return napi_clear_last_error(env);
1561
}
1562
1563
9
napi_status NAPI_CDECL napi_create_bigint_int64(napi_env env,
1564
                                                int64_t value,
1565
                                                napi_value* result) {
1566
9
  CHECK_ENV(env);
1567
9
  CHECK_ARG(env, result);
1568
1569
18
  *result =
1570
18
      v8impl::JsValueFromV8LocalValue(v8::BigInt::New(env->isolate, value));
1571
1572
9
  return napi_clear_last_error(env);
1573
}
1574
1575
6
napi_status NAPI_CDECL napi_create_bigint_uint64(napi_env env,
1576
                                                 uint64_t value,
1577
                                                 napi_value* result) {
1578
6
  CHECK_ENV(env);
1579
6
  CHECK_ARG(env, result);
1580
1581
6
  *result = v8impl::JsValueFromV8LocalValue(
1582
6
      v8::BigInt::NewFromUnsigned(env->isolate, value));
1583
1584
6
  return napi_clear_last_error(env);
1585
}
1586
1587
13
napi_status NAPI_CDECL napi_create_bigint_words(napi_env env,
1588
                                                int sign_bit,
1589
                                                size_t word_count,
1590
                                                const uint64_t* words,
1591
                                                napi_value* result) {
1592


26
  NAPI_PREAMBLE(env);
1593
13
  CHECK_ARG(env, words);
1594
13
  CHECK_ARG(env, result);
1595
1596
13
  v8::Local<v8::Context> context = env->context();
1597
1598
13
  RETURN_STATUS_IF_FALSE(env, word_count <= INT_MAX, napi_invalid_arg);
1599
1600
  v8::MaybeLocal<v8::BigInt> b =
1601
12
      v8::BigInt::NewFromWords(context, sign_bit, word_count, words);
1602
1603

12
  CHECK_MAYBE_EMPTY_WITH_PREAMBLE(env, b, napi_generic_failure);
1604
1605
11
  *result = v8impl::JsValueFromV8LocalValue(b.ToLocalChecked());
1606
11
  return GET_RETURN_STATUS(env);
1607
}
1608
1609
1301
napi_status NAPI_CDECL napi_get_boolean(napi_env env,
1610
                                        bool value,
1611
                                        napi_value* result) {
1612
1301
  CHECK_ENV(env);
1613
1301
  CHECK_ARG(env, result);
1614
1615
1301
  v8::Isolate* isolate = env->isolate;
1616
1617
1301
  if (value) {
1618
733
    *result = v8impl::JsValueFromV8LocalValue(v8::True(isolate));
1619
  } else {
1620
568
    *result = v8impl::JsValueFromV8LocalValue(v8::False(isolate));
1621
  }
1622
1623
1301
  return napi_clear_last_error(env);
1624
}
1625
1626
15
napi_status NAPI_CDECL napi_create_symbol(napi_env env,
1627
                                          napi_value description,
1628
                                          napi_value* result) {
1629
15
  CHECK_ENV(env);
1630
15
  CHECK_ARG(env, result);
1631
1632
15
  v8::Isolate* isolate = env->isolate;
1633
1634
15
  if (description == nullptr) {
1635
6
    *result = v8impl::JsValueFromV8LocalValue(v8::Symbol::New(isolate));
1636
  } else {
1637
12
    v8::Local<v8::Value> desc = v8impl::V8LocalValueFromJsValue(description);
1638
24
    RETURN_STATUS_IF_FALSE(env, desc->IsString(), napi_string_expected);
1639
1640
24
    *result = v8impl::JsValueFromV8LocalValue(
1641
        v8::Symbol::New(isolate, desc.As<v8::String>()));
1642
  }
1643
1644
15
  return napi_clear_last_error(env);
1645
}
1646
1647
4
napi_status NAPI_CDECL node_api_symbol_for(napi_env env,
1648
                                           const char* utf8description,
1649
                                           size_t length,
1650
                                           napi_value* result) {
1651
4
  CHECK_ENV(env);
1652
4
  CHECK_ARG(env, result);
1653
1654
  napi_value js_description_string;
1655
4
  STATUS_CALL(napi_create_string_utf8(
1656
      env, utf8description, length, &js_description_string));
1657
  v8::Local<v8::String> description_string =
1658
3
      v8impl::V8LocalValueFromJsValue(js_description_string).As<v8::String>();
1659
1660
3
  *result = v8impl::JsValueFromV8LocalValue(
1661
3
      v8::Symbol::For(env->isolate, description_string));
1662
1663
3
  return napi_clear_last_error(env);
1664
}
1665
1666
199
static inline napi_status set_error_code(napi_env env,
1667
                                         v8::Local<v8::Value> error,
1668
                                         napi_value code,
1669
                                         const char* code_cstring) {
1670

199
  if ((code != nullptr) || (code_cstring != nullptr)) {
1671
118
    v8::Local<v8::Context> context = env->context();
1672
118
    v8::Local<v8::Object> err_object = error.As<v8::Object>();
1673
1674
118
    v8::Local<v8::Value> code_value = v8impl::V8LocalValueFromJsValue(code);
1675
118
    if (code != nullptr) {
1676
6
      code_value = v8impl::V8LocalValueFromJsValue(code);
1677
12
      RETURN_STATUS_IF_FALSE(env, code_value->IsString(), napi_string_expected);
1678
    } else {
1679

336
      CHECK_NEW_FROM_UTF8(env, code_value, code_cstring);
1680
    }
1681
1682
    v8::Local<v8::Name> code_key;
1683
354
    CHECK_NEW_FROM_UTF8(env, code_key, "code");
1684
1685
118
    v8::Maybe<bool> set_maybe = err_object->Set(context, code_key, code_value);
1686

236
    RETURN_STATUS_IF_FALSE(
1687
        env, set_maybe.FromMaybe(false), napi_generic_failure);
1688
  }
1689
199
  return napi_ok;
1690
}
1691
1692
5
napi_status NAPI_CDECL napi_create_error(napi_env env,
1693
                                         napi_value code,
1694
                                         napi_value msg,
1695
                                         napi_value* result) {
1696
5
  CHECK_ENV(env);
1697
5
  CHECK_ARG(env, msg);
1698
5
  CHECK_ARG(env, result);
1699
1700
5
  v8::Local<v8::Value> message_value = v8impl::V8LocalValueFromJsValue(msg);
1701
10
  RETURN_STATUS_IF_FALSE(env, message_value->IsString(), napi_string_expected);
1702
1703
  v8::Local<v8::Value> error_obj =
1704
5
      v8::Exception::Error(message_value.As<v8::String>());
1705
5
  STATUS_CALL(set_error_code(env, error_obj, code, nullptr));
1706
1707
5
  *result = v8impl::JsValueFromV8LocalValue(error_obj);
1708
1709
5
  return napi_clear_last_error(env);
1710
}
1711
1712
2
napi_status NAPI_CDECL napi_create_type_error(napi_env env,
1713
                                              napi_value code,
1714
                                              napi_value msg,
1715
                                              napi_value* result) {
1716
2
  CHECK_ENV(env);
1717
2
  CHECK_ARG(env, msg);
1718
2
  CHECK_ARG(env, result);
1719
1720
2
  v8::Local<v8::Value> message_value = v8impl::V8LocalValueFromJsValue(msg);
1721
4
  RETURN_STATUS_IF_FALSE(env, message_value->IsString(), napi_string_expected);
1722
1723
  v8::Local<v8::Value> error_obj =
1724
2
      v8::Exception::TypeError(message_value.As<v8::String>());
1725
2
  STATUS_CALL(set_error_code(env, error_obj, code, nullptr));
1726
1727
2
  *result = v8impl::JsValueFromV8LocalValue(error_obj);
1728
1729
2
  return napi_clear_last_error(env);
1730
}
1731
1732
2
napi_status NAPI_CDECL napi_create_range_error(napi_env env,
1733
                                               napi_value code,
1734
                                               napi_value msg,
1735
                                               napi_value* result) {
1736
2
  CHECK_ENV(env);
1737
2
  CHECK_ARG(env, msg);
1738
2
  CHECK_ARG(env, result);
1739
1740
2
  v8::Local<v8::Value> message_value = v8impl::V8LocalValueFromJsValue(msg);
1741
4
  RETURN_STATUS_IF_FALSE(env, message_value->IsString(), napi_string_expected);
1742
1743
  v8::Local<v8::Value> error_obj =
1744
2
      v8::Exception::RangeError(message_value.As<v8::String>());
1745
2
  STATUS_CALL(set_error_code(env, error_obj, code, nullptr));
1746
1747
2
  *result = v8impl::JsValueFromV8LocalValue(error_obj);
1748
1749
2
  return napi_clear_last_error(env);
1750
}
1751
1752
2
napi_status NAPI_CDECL node_api_create_syntax_error(napi_env env,
1753
                                                    napi_value code,
1754
                                                    napi_value msg,
1755
                                                    napi_value* result) {
1756
2
  CHECK_ENV(env);
1757
2
  CHECK_ARG(env, msg);
1758
2
  CHECK_ARG(env, result);
1759
1760
2
  v8::Local<v8::Value> message_value = v8impl::V8LocalValueFromJsValue(msg);
1761
4
  RETURN_STATUS_IF_FALSE(env, message_value->IsString(), napi_string_expected);
1762
1763
  v8::Local<v8::Value> error_obj =
1764
2
      v8::Exception::SyntaxError(message_value.As<v8::String>());
1765
2
  STATUS_CALL(set_error_code(env, error_obj, code, nullptr));
1766
1767
2
  *result = v8impl::JsValueFromV8LocalValue(error_obj);
1768
1769
2
  return napi_clear_last_error(env);
1770
}
1771
1772
443
napi_status NAPI_CDECL napi_typeof(napi_env env,
1773
                                   napi_value value,
1774
                                   napi_valuetype* result) {
1775
  // Omit NAPI_PREAMBLE and GET_RETURN_STATUS because V8 calls here cannot throw
1776
  // JS exceptions.
1777
443
  CHECK_ENV(env);
1778
443
  CHECK_ARG(env, value);
1779
443
  CHECK_ARG(env, result);
1780
1781
443
  v8::Local<v8::Value> v = v8impl::V8LocalValueFromJsValue(value);
1782
1783
443
  if (v->IsNumber()) {
1784
136
    *result = napi_number;
1785
307
  } else if (v->IsBigInt()) {
1786
26
    *result = napi_bigint;
1787
562
  } else if (v->IsString()) {
1788
87
    *result = napi_string;
1789
194
  } else if (v->IsFunction()) {
1790
    // This test has to come before IsObject because IsFunction
1791
    // implies IsObject
1792
35
    *result = napi_function;
1793
159
  } else if (v->IsExternal()) {
1794
    // This test has to come before IsObject because IsExternal
1795
    // implies IsObject
1796
2
    *result = napi_external;
1797
157
  } else if (v->IsObject()) {
1798
143
    *result = napi_object;
1799
14
  } else if (v->IsBoolean()) {
1800
1
    *result = napi_boolean;
1801
26
  } else if (v->IsUndefined()) {
1802
3
    *result = napi_undefined;
1803
10
  } else if (v->IsSymbol()) {
1804
9
    *result = napi_symbol;
1805
2
  } else if (v->IsNull()) {
1806
1
    *result = napi_null;
1807
  } else {
1808
    // Should not get here unless V8 has added some new kind of value.
1809
    return napi_set_last_error(env, napi_invalid_arg);
1810
  }
1811
1812
443
  return napi_clear_last_error(env);
1813
}
1814
1815
115031
napi_status NAPI_CDECL napi_get_undefined(napi_env env, napi_value* result) {
1816
115031
  CHECK_ENV(env);
1817
115031
  CHECK_ARG(env, result);
1818
1819
230062
  *result = v8impl::JsValueFromV8LocalValue(v8::Undefined(env->isolate));
1820
1821
115031
  return napi_clear_last_error(env);
1822
}
1823
1824
5
napi_status NAPI_CDECL napi_get_null(napi_env env, napi_value* result) {
1825
5
  CHECK_ENV(env);
1826
5
  CHECK_ARG(env, result);
1827
1828
10
  *result = v8impl::JsValueFromV8LocalValue(v8::Null(env->isolate));
1829
1830
5
  return napi_clear_last_error(env);
1831
}
1832
1833
// Gets all callback info in a single call. (Ugly, but faster.)
1834
4525
napi_status NAPI_CDECL napi_get_cb_info(
1835
    napi_env env,               // [in] NAPI environment handle
1836
    napi_callback_info cbinfo,  // [in] Opaque callback-info handle
1837
    size_t* argc,      // [in-out] Specifies the size of the provided argv array
1838
                       // and receives the actual count of args.
1839
    napi_value* argv,  // [out] Array of values
1840
    napi_value* this_arg,  // [out] Receives the JS 'this' arg for the call
1841
    void** data) {         // [out] Receives the data pointer for the callback.
1842
4525
  CHECK_ENV(env);
1843
4525
  CHECK_ARG(env, cbinfo);
1844
1845
4525
  v8impl::CallbackWrapper* info =
1846
      reinterpret_cast<v8impl::CallbackWrapper*>(cbinfo);
1847
1848
4525
  if (argv != nullptr) {
1849
4493
    CHECK_ARG(env, argc);
1850
4493
    info->Args(argv, *argc);
1851
  }
1852
4525
  if (argc != nullptr) {
1853
4505
    *argc = info->ArgsLength();
1854
  }
1855
4525
  if (this_arg != nullptr) {
1856
42
    *this_arg = info->This();
1857
  }
1858
4525
  if (data != nullptr) {
1859
6
    *data = info->Data();
1860
  }
1861
1862
4525
  return napi_clear_last_error(env);
1863
}
1864
1865
8
napi_status NAPI_CDECL napi_get_new_target(napi_env env,
1866
                                           napi_callback_info cbinfo,
1867
                                           napi_value* result) {
1868
8
  CHECK_ENV(env);
1869
8
  CHECK_ARG(env, cbinfo);
1870
8
  CHECK_ARG(env, result);
1871
1872
8
  v8impl::CallbackWrapper* info =
1873
      reinterpret_cast<v8impl::CallbackWrapper*>(cbinfo);
1874
1875
8
  *result = info->GetNewTarget();
1876
8
  return napi_clear_last_error(env);
1877
}
1878
1879
115553
napi_status NAPI_CDECL napi_call_function(napi_env env,
1880
                                          napi_value recv,
1881
                                          napi_value func,
1882
                                          size_t argc,
1883
                                          const napi_value* argv,
1884
                                          napi_value* result) {
1885


231101
  NAPI_PREAMBLE(env);
1886
115548
  CHECK_ARG(env, recv);
1887
115548
  if (argc > 0) {
1888
105500
    CHECK_ARG(env, argv);
1889
  }
1890
1891
115548
  v8::Local<v8::Context> context = env->context();
1892
1893
115548
  v8::Local<v8::Value> v8recv = v8impl::V8LocalValueFromJsValue(recv);
1894
1895
  v8::Local<v8::Function> v8func;
1896

346644
  CHECK_TO_FUNCTION(env, v8func, func);
1897
1898
  auto maybe = v8func->Call(
1899
      context,
1900
      v8recv,
1901
      argc,
1902
115548
      reinterpret_cast<v8::Local<v8::Value>*>(const_cast<napi_value*>(argv)));
1903
1904
115548
  if (try_catch.HasCaught()) {
1905
12
    return napi_set_last_error(env, napi_pending_exception);
1906
  } else {
1907
115536
    if (result != nullptr) {
1908
7
      CHECK_MAYBE_EMPTY(env, maybe, napi_generic_failure);
1909
7
      *result = v8impl::JsValueFromV8LocalValue(maybe.ToLocalChecked());
1910
    }
1911
115536
    return napi_clear_last_error(env);
1912
  }
1913
}
1914
1915
15
napi_status NAPI_CDECL napi_get_global(napi_env env, napi_value* result) {
1916
15
  CHECK_ENV(env);
1917
15
  CHECK_ARG(env, result);
1918
1919
45
  *result = v8impl::JsValueFromV8LocalValue(env->context()->Global());
1920
1921
15
  return napi_clear_last_error(env);
1922
}
1923
1924
12
napi_status NAPI_CDECL napi_throw(napi_env env, napi_value error) {
1925


24
  NAPI_PREAMBLE(env);
1926
12
  CHECK_ARG(env, error);
1927
1928
12
  v8::Isolate* isolate = env->isolate;
1929
1930
12
  isolate->ThrowException(v8impl::V8LocalValueFromJsValue(error));
1931
  // any VM calls after this point and before returning
1932
  // to the javascript invoker will fail
1933
12
  return napi_clear_last_error(env);
1934
}
1935
1936
83
napi_status NAPI_CDECL napi_throw_error(napi_env env,
1937
                                        const char* code,
1938
                                        const char* msg) {
1939


157
  NAPI_PREAMBLE(env);
1940
1941
74
  v8::Isolate* isolate = env->isolate;
1942
  v8::Local<v8::String> str;
1943

148
  CHECK_NEW_FROM_UTF8(env, str, msg);
1944
1945
74
  v8::Local<v8::Value> error_obj = v8::Exception::Error(str);
1946
74
  STATUS_CALL(set_error_code(env, error_obj, nullptr, code));
1947
1948
74
  isolate->ThrowException(error_obj);
1949
  // any VM calls after this point and before returning
1950
  // to the javascript invoker will fail
1951
74
  return napi_clear_last_error(env);
1952
}
1953
1954
90
napi_status NAPI_CDECL napi_throw_type_error(napi_env env,
1955
                                             const char* code,
1956
                                             const char* msg) {
1957


180
  NAPI_PREAMBLE(env);
1958
1959
90
  v8::Isolate* isolate = env->isolate;
1960
  v8::Local<v8::String> str;
1961

180
  CHECK_NEW_FROM_UTF8(env, str, msg);
1962
1963
90
  v8::Local<v8::Value> error_obj = v8::Exception::TypeError(str);
1964
90
  STATUS_CALL(set_error_code(env, error_obj, nullptr, code));
1965
1966
90
  isolate->ThrowException(error_obj);
1967
  // any VM calls after this point and before returning
1968
  // to the javascript invoker will fail
1969
90
  return napi_clear_last_error(env);
1970
}
1971
1972
22
napi_status NAPI_CDECL napi_throw_range_error(napi_env env,
1973
                                              const char* code,
1974
                                              const char* msg) {
1975


44
  NAPI_PREAMBLE(env);
1976
1977
22
  v8::Isolate* isolate = env->isolate;
1978
  v8::Local<v8::String> str;
1979

44
  CHECK_NEW_FROM_UTF8(env, str, msg);
1980
1981
22
  v8::Local<v8::Value> error_obj = v8::Exception::RangeError(str);
1982
22
  STATUS_CALL(set_error_code(env, error_obj, nullptr, code));
1983
1984
22
  isolate->ThrowException(error_obj);
1985
  // any VM calls after this point and before returning
1986
  // to the javascript invoker will fail
1987
22
  return napi_clear_last_error(env);
1988
}
1989
1990
2
napi_status NAPI_CDECL node_api_throw_syntax_error(napi_env env,
1991
                                                   const char* code,
1992
                                                   const char* msg) {
1993


4
  NAPI_PREAMBLE(env);
1994
1995
2
  v8::Isolate* isolate = env->isolate;
1996
  v8::Local<v8::String> str;
1997

4
  CHECK_NEW_FROM_UTF8(env, str, msg);
1998
1999
2
  v8::Local<v8::Value> error_obj = v8::Exception::SyntaxError(str);
2000
2
  STATUS_CALL(set_error_code(env, error_obj, nullptr, code));
2001
2002
2
  isolate->ThrowException(error_obj);
2003
  // any VM calls after this point and before returning
2004
  // to the javascript invoker will fail
2005
2
  return napi_clear_last_error(env);
2006
}
2007
2008
10
napi_status NAPI_CDECL napi_is_error(napi_env env,
2009
                                     napi_value value,
2010
                                     bool* result) {
2011
  // Omit NAPI_PREAMBLE and GET_RETURN_STATUS because V8 calls here cannot
2012
  // throw JS exceptions.
2013
10
  CHECK_ENV(env);
2014
10
  CHECK_ARG(env, value);
2015
10
  CHECK_ARG(env, result);
2016
2017
10
  v8::Local<v8::Value> val = v8impl::V8LocalValueFromJsValue(value);
2018
10
  *result = val->IsNativeError();
2019
2020
10
  return napi_clear_last_error(env);
2021
}
2022
2023
73
napi_status NAPI_CDECL napi_get_value_double(napi_env env,
2024
                                             napi_value value,
2025
                                             double* result) {
2026
  // Omit NAPI_PREAMBLE and GET_RETURN_STATUS because V8 calls here cannot throw
2027
  // JS exceptions.
2028
73
  CHECK_ENV(env);
2029
72
  CHECK_ARG(env, value);
2030
71
  CHECK_ARG(env, result);
2031
2032
70
  v8::Local<v8::Value> val = v8impl::V8LocalValueFromJsValue(value);
2033
70
  RETURN_STATUS_IF_FALSE(env, val->IsNumber(), napi_number_expected);
2034
2035
60
  *result = val.As<v8::Number>()->Value();
2036
2037
60
  return napi_clear_last_error(env);
2038
}
2039
2040
61
napi_status NAPI_CDECL napi_get_value_int32(napi_env env,
2041
                                            napi_value value,
2042
                                            int32_t* result) {
2043
  // Omit NAPI_PREAMBLE and GET_RETURN_STATUS because V8 calls here cannot throw
2044
  // JS exceptions.
2045
61
  CHECK_ENV(env);
2046
60
  CHECK_ARG(env, value);
2047
59
  CHECK_ARG(env, result);
2048
2049
58
  v8::Local<v8::Value> val = v8impl::V8LocalValueFromJsValue(value);
2050
2051
58
  if (val->IsInt32()) {
2052
25
    *result = val.As<v8::Int32>()->Value();
2053
  } else {
2054
33
    RETURN_STATUS_IF_FALSE(env, val->IsNumber(), napi_number_expected);
2055
2056
    // Empty context: https://github.com/nodejs/node/issues/14379
2057
    v8::Local<v8::Context> context;
2058
48
    *result = val->Int32Value(context).FromJust();
2059
  }
2060
2061
49
  return napi_clear_last_error(env);
2062
}
2063
2064
113
napi_status NAPI_CDECL napi_get_value_uint32(napi_env env,
2065
                                             napi_value value,
2066
                                             uint32_t* result) {
2067
  // Omit NAPI_PREAMBLE and GET_RETURN_STATUS because V8 calls here cannot throw
2068
  // JS exceptions.
2069
113
  CHECK_ENV(env);
2070
112
  CHECK_ARG(env, value);
2071
111
  CHECK_ARG(env, result);
2072
2073
110
  v8::Local<v8::Value> val = v8impl::V8LocalValueFromJsValue(value);
2074
2075
110
  if (val->IsUint32()) {
2076
90
    *result = val.As<v8::Uint32>()->Value();
2077
  } else {
2078
20
    RETURN_STATUS_IF_FALSE(env, val->IsNumber(), napi_number_expected);
2079
2080
    // Empty context: https://github.com/nodejs/node/issues/14379
2081
    v8::Local<v8::Context> context;
2082
22
    *result = val->Uint32Value(context).FromJust();
2083
  }
2084
2085
101
  return napi_clear_last_error(env);
2086
}
2087
2088
36
napi_status NAPI_CDECL napi_get_value_int64(napi_env env,
2089
                                            napi_value value,
2090
                                            int64_t* result) {
2091
  // Omit NAPI_PREAMBLE and GET_RETURN_STATUS because V8 calls here cannot throw
2092
  // JS exceptions.
2093
36
  CHECK_ENV(env);
2094
35
  CHECK_ARG(env, value);
2095
34
  CHECK_ARG(env, result);
2096
2097
33
  v8::Local<v8::Value> val = v8impl::V8LocalValueFromJsValue(value);
2098
2099
  // This is still a fast path very likely to be taken.
2100
33
  if (val->IsInt32()) {
2101
5
    *result = val.As<v8::Int32>()->Value();
2102
5
    return napi_clear_last_error(env);
2103
  }
2104
2105
28
  RETURN_STATUS_IF_FALSE(env, val->IsNumber(), napi_number_expected);
2106
2107
  // v8::Value::IntegerValue() converts NaN, +Inf, and -Inf to INT64_MIN,
2108
  // inconsistent with v8::Value::Int32Value() which converts those values to 0.
2109
  // Special-case all non-finite values to match that behavior.
2110
19
  double doubleValue = val.As<v8::Number>()->Value();
2111
19
  if (std::isfinite(doubleValue)) {
2112
    // Empty context: https://github.com/nodejs/node/issues/14379
2113
    v8::Local<v8::Context> context;
2114
30
    *result = val->IntegerValue(context).FromJust();
2115
  } else {
2116
4
    *result = 0;
2117
  }
2118
2119
19
  return napi_clear_last_error(env);
2120
}
2121
2122
20
napi_status NAPI_CDECL napi_get_value_bigint_int64(napi_env env,
2123
                                                   napi_value value,
2124
                                                   int64_t* result,
2125
                                                   bool* lossless) {
2126
20
  CHECK_ENV(env);
2127
20
  CHECK_ARG(env, value);
2128
20
  CHECK_ARG(env, result);
2129
20
  CHECK_ARG(env, lossless);
2130
2131
20
  v8::Local<v8::Value> val = v8impl::V8LocalValueFromJsValue(value);
2132
2133
20
  RETURN_STATUS_IF_FALSE(env, val->IsBigInt(), napi_bigint_expected);
2134
2135
20
  *result = val.As<v8::BigInt>()->Int64Value(lossless);
2136
2137
20
  return napi_clear_last_error(env);
2138
}
2139
2140
17
napi_status NAPI_CDECL napi_get_value_bigint_uint64(napi_env env,
2141
                                                    napi_value value,
2142
                                                    uint64_t* result,
2143
                                                    bool* lossless) {
2144
17
  CHECK_ENV(env);
2145
17
  CHECK_ARG(env, value);
2146
17
  CHECK_ARG(env, result);
2147
17
  CHECK_ARG(env, lossless);
2148
2149
17
  v8::Local<v8::Value> val = v8impl::V8LocalValueFromJsValue(value);
2150
2151
17
  RETURN_STATUS_IF_FALSE(env, val->IsBigInt(), napi_bigint_expected);
2152
2153
17
  *result = val.As<v8::BigInt>()->Uint64Value(lossless);
2154
2155
17
  return napi_clear_last_error(env);
2156
}
2157
2158
22
napi_status NAPI_CDECL napi_get_value_bigint_words(napi_env env,
2159
                                                   napi_value value,
2160
                                                   int* sign_bit,
2161
                                                   size_t* word_count,
2162
                                                   uint64_t* words) {
2163
22
  CHECK_ENV(env);
2164
22
  CHECK_ARG(env, value);
2165
22
  CHECK_ARG(env, word_count);
2166
2167
22
  v8::Local<v8::Value> val = v8impl::V8LocalValueFromJsValue(value);
2168
2169
22
  RETURN_STATUS_IF_FALSE(env, val->IsBigInt(), napi_bigint_expected);
2170
2171
22
  v8::Local<v8::BigInt> big = val.As<v8::BigInt>();
2172
2173
22
  int word_count_int = *word_count;
2174
2175

22
  if (sign_bit == nullptr && words == nullptr) {
2176
11
    word_count_int = big->WordCount();
2177
  } else {
2178
11
    CHECK_ARG(env, sign_bit);
2179
11
    CHECK_ARG(env, words);
2180
11
    big->ToWordsArray(sign_bit, &word_count_int, words);
2181
  }
2182
2183
22
  *word_count = word_count_int;
2184
2185
22
  return napi_clear_last_error(env);
2186
}
2187
2188
93
napi_status NAPI_CDECL napi_get_value_bool(napi_env env,
2189
                                           napi_value value,
2190
                                           bool* result) {
2191
  // Omit NAPI_PREAMBLE and GET_RETURN_STATUS because V8 calls here cannot throw
2192
  // JS exceptions.
2193
93
  CHECK_ENV(env);
2194
92
  CHECK_ARG(env, value);
2195
91
  CHECK_ARG(env, result);
2196
2197
90
  v8::Local<v8::Value> val = v8impl::V8LocalValueFromJsValue(value);
2198
90
  RETURN_STATUS_IF_FALSE(env, val->IsBoolean(), napi_boolean_expected);
2199
2200
77
  *result = val.As<v8::Boolean>()->Value();
2201
2202
77
  return napi_clear_last_error(env);
2203
}
2204
2205
// Copies a JavaScript string into a LATIN-1 string buffer. The result is the
2206
// number of bytes (excluding the null terminator) copied into buf.
2207
// A sufficient buffer size should be greater than the length of string,
2208
// reserving space for null terminator.
2209
// If bufsize is insufficient, the string will be truncated and null terminated.
2210
// If buf is NULL, this method returns the length of the string (in bytes)
2211
// via the result parameter.
2212
// The result argument is optional unless buf is NULL.
2213
15
napi_status NAPI_CDECL napi_get_value_string_latin1(
2214
    napi_env env, napi_value value, char* buf, size_t bufsize, size_t* result) {
2215
15
  CHECK_ENV(env);
2216
14
  CHECK_ARG(env, value);
2217
2218
13
  v8::Local<v8::Value> val = v8impl::V8LocalValueFromJsValue(value);
2219
26
  RETURN_STATUS_IF_FALSE(env, val->IsString(), napi_string_expected);
2220
2221
12
  if (!buf) {
2222
1
    CHECK_ARG(env, result);
2223
    *result = val.As<v8::String>()->Length();
2224
11
  } else if (bufsize != 0) {
2225
    int copied =
2226
11
        val.As<v8::String>()->WriteOneByte(env->isolate,
2227
                                           reinterpret_cast<uint8_t*>(buf),
2228
                                           0,
2229
11
                                           bufsize - 1,
2230
                                           v8::String::NO_NULL_TERMINATION);
2231
2232
11
    buf[copied] = '\0';
2233
11
    if (result != nullptr) {
2234
11
      *result = copied;
2235
    }
2236
  } else if (result != nullptr) {
2237
    *result = 0;
2238
  }
2239
2240
11
  return napi_clear_last_error(env);
2241
}
2242
2243
// Copies a JavaScript string into a UTF-8 string buffer. The result is the
2244
// number of bytes (excluding the null terminator) copied into buf.
2245
// A sufficient buffer size should be greater than the length of string,
2246
// reserving space for null terminator.
2247
// If bufsize is insufficient, the string will be truncated and null terminated.
2248
// If buf is NULL, this method returns the length of the string (in bytes)
2249
// via the result parameter.
2250
// The result argument is optional unless buf is NULL.
2251
44
napi_status NAPI_CDECL napi_get_value_string_utf8(
2252
    napi_env env, napi_value value, char* buf, size_t bufsize, size_t* result) {
2253
44
  CHECK_ENV(env);
2254
43
  CHECK_ARG(env, value);
2255
2256
42
  v8::Local<v8::Value> val = v8impl::V8LocalValueFromJsValue(value);
2257
84
  RETURN_STATUS_IF_FALSE(env, val->IsString(), napi_string_expected);
2258
2259
32
  if (!buf) {
2260
8
    CHECK_ARG(env, result);
2261
7
    *result = val.As<v8::String>()->Utf8Length(env->isolate);
2262
24
  } else if (bufsize != 0) {
2263
23
    int copied = val.As<v8::String>()->WriteUtf8(
2264
23
        env->isolate,
2265
        buf,
2266
23
        bufsize - 1,
2267
        nullptr,
2268
        v8::String::REPLACE_INVALID_UTF8 | v8::String::NO_NULL_TERMINATION);
2269
2270
23
    buf[copied] = '\0';
2271
23
    if (result != nullptr) {
2272
21
      *result = copied;
2273
    }
2274
1
  } else if (result != nullptr) {
2275
    *result = 0;
2276
  }
2277
2278
31
  return napi_clear_last_error(env);
2279
}
2280
2281
// Copies a JavaScript string into a UTF-16 string buffer. The result is the
2282
// number of 2-byte code units (excluding the null terminator) copied into buf.
2283
// A sufficient buffer size should be greater than the length of string,
2284
// reserving space for null terminator.
2285
// If bufsize is insufficient, the string will be truncated and null terminated.
2286
// If buf is NULL, this method returns the length of the string (in 2-byte
2287
// code units) via the result parameter.
2288
// The result argument is optional unless buf is NULL.
2289
24
napi_status NAPI_CDECL napi_get_value_string_utf16(napi_env env,
2290
                                                   napi_value value,
2291
                                                   char16_t* buf,
2292
                                                   size_t bufsize,
2293
                                                   size_t* result) {
2294
24
  CHECK_ENV(env);
2295
23
  CHECK_ARG(env, value);
2296
2297
22
  v8::Local<v8::Value> val = v8impl::V8LocalValueFromJsValue(value);
2298
44
  RETURN_STATUS_IF_FALSE(env, val->IsString(), napi_string_expected);
2299
2300
21
  if (!buf) {
2301
8
    CHECK_ARG(env, result);
2302
    // V8 assumes UTF-16 length is the same as the number of characters.
2303
7
    *result = val.As<v8::String>()->Length();
2304
13
  } else if (bufsize != 0) {
2305
13
    int copied = val.As<v8::String>()->Write(env->isolate,
2306
                                             reinterpret_cast<uint16_t*>(buf),
2307
                                             0,
2308
13
                                             bufsize - 1,
2309
                                             v8::String::NO_NULL_TERMINATION);
2310
2311
13
    buf[copied] = '\0';
2312
13
    if (result != nullptr) {
2313
13
      *result = copied;
2314
    }
2315
  } else if (result != nullptr) {
2316
    *result = 0;
2317
  }
2318
2319
20
  return napi_clear_last_error(env);
2320
}
2321
2322
18
napi_status NAPI_CDECL napi_coerce_to_bool(napi_env env,
2323
                                           napi_value value,
2324
                                           napi_value* result) {
2325


35
  NAPI_PREAMBLE(env);
2326
17
  CHECK_ARG(env, value);
2327
16
  CHECK_ARG(env, result);
2328
2329
15
  v8::Isolate* isolate = env->isolate;
2330
  v8::Local<v8::Boolean> b =
2331
30
      v8impl::V8LocalValueFromJsValue(value)->ToBoolean(isolate);
2332
15
  *result = v8impl::JsValueFromV8LocalValue(b);
2333
15
  return GET_RETURN_STATUS(env);
2334
}
2335
2336
#define GEN_COERCE_FUNCTION(UpperCaseName, MixedCaseName, LowerCaseName)       \
2337
  napi_status NAPI_CDECL napi_coerce_to_##LowerCaseName(                       \
2338
      napi_env env, napi_value value, napi_value* result) {                    \
2339
    NAPI_PREAMBLE(env);                                                        \
2340
    CHECK_ARG(env, value);                                                     \
2341
    CHECK_ARG(env, result);                                                    \
2342
                                                                               \
2343
    v8::Local<v8::Context> context = env->context();                           \
2344
    v8::Local<v8::MixedCaseName> str;                                          \
2345
                                                                               \
2346
    CHECK_TO_##UpperCaseName(env, context, str, value);                        \
2347
                                                                               \
2348
    *result = v8impl::JsValueFromV8LocalValue(str);                            \
2349
    return GET_RETURN_STATUS(env);                                             \
2350
  }
2351
2352




44
GEN_COERCE_FUNCTION(NUMBER, Number, number)
2353




51
GEN_COERCE_FUNCTION(OBJECT, Object, object)
2354




47
GEN_COERCE_FUNCTION(STRING, String, string)
2355
2356
#undef GEN_COERCE_FUNCTION
2357
2358
1028
napi_status NAPI_CDECL napi_wrap(napi_env env,
2359
                                 napi_value js_object,
2360
                                 void* native_object,
2361
                                 napi_finalize finalize_cb,
2362
                                 void* finalize_hint,
2363
                                 napi_ref* result) {
2364
1028
  return v8impl::Wrap<v8impl::retrievable>(
2365
1028
      env, js_object, native_object, finalize_cb, finalize_hint, result);
2366
}
2367
2368
27
napi_status NAPI_CDECL napi_unwrap(napi_env env,
2369
                                   napi_value obj,
2370
                                   void** result) {
2371
27
  return v8impl::Unwrap(env, obj, result, v8impl::KeepWrap);
2372
}
2373
2374
8
napi_status NAPI_CDECL napi_remove_wrap(napi_env env,
2375
                                        napi_value obj,
2376
                                        void** result) {
2377
8
  return v8impl::Unwrap(env, obj, result, v8impl::RemoveWrap);
2378
}
2379
2380
8
napi_status NAPI_CDECL napi_create_external(napi_env env,
2381
                                            void* data,
2382
                                            napi_finalize finalize_cb,
2383
                                            void* finalize_hint,
2384
                                            napi_value* result) {
2385


16
  NAPI_PREAMBLE(env);
2386
8
  CHECK_ARG(env, result);
2387
2388
8
  v8::Isolate* isolate = env->isolate;
2389
2390
8
  v8::Local<v8::Value> external_value = v8::External::New(isolate, data);
2391
2392
  // The Reference object will delete itself after invoking the finalizer
2393
  // callback.
2394
8
  v8impl::Reference::New(
2395
      env, external_value, 0, true, finalize_cb, data, finalize_hint);
2396
2397
8
  *result = v8impl::JsValueFromV8LocalValue(external_value);
2398
2399
8
  return napi_clear_last_error(env);
2400
}
2401
2402
4
napi_status NAPI_CDECL napi_type_tag_object(napi_env env,
2403
                                            napi_value object,
2404
                                            const napi_type_tag* type_tag) {
2405


8
  NAPI_PREAMBLE(env);
2406
4
  v8::Local<v8::Context> context = env->context();
2407
  v8::Local<v8::Object> obj;
2408


8
  CHECK_TO_OBJECT_WITH_PREAMBLE(env, context, obj, object);
2409

4
  CHECK_ARG_WITH_PREAMBLE(env, type_tag);
2410
2411
4
  auto key = NAPI_PRIVATE_KEY(context, type_tag);
2412
4
  auto maybe_has = obj->HasPrivate(context, key);
2413

4
  CHECK_MAYBE_NOTHING_WITH_PREAMBLE(env, maybe_has, napi_generic_failure);
2414

4
  RETURN_STATUS_IF_FALSE_WITH_PREAMBLE(
2415
      env, !maybe_has.FromJust(), napi_invalid_arg);
2416
2417
  auto tag = v8::BigInt::NewFromWords(
2418
4
      context, 0, 2, reinterpret_cast<const uint64_t*>(type_tag));
2419

4
  CHECK_MAYBE_EMPTY_WITH_PREAMBLE(env, tag, napi_generic_failure);
2420
2421
8
  auto maybe_set = obj->SetPrivate(context, key, tag.ToLocalChecked());
2422

4
  CHECK_MAYBE_NOTHING_WITH_PREAMBLE(env, maybe_set, napi_generic_failure);
2423

4
  RETURN_STATUS_IF_FALSE_WITH_PREAMBLE(
2424
      env, maybe_set.FromJust(), napi_generic_failure);
2425
2426
4
  return GET_RETURN_STATUS(env);
2427
}
2428
2429
13
napi_status NAPI_CDECL napi_check_object_type_tag(napi_env env,
2430
                                                  napi_value object,
2431
                                                  const napi_type_tag* type_tag,
2432
                                                  bool* result) {
2433


26
  NAPI_PREAMBLE(env);
2434
13
  v8::Local<v8::Context> context = env->context();
2435
  v8::Local<v8::Object> obj;
2436


26
  CHECK_TO_OBJECT_WITH_PREAMBLE(env, context, obj, object);
2437

13
  CHECK_ARG_WITH_PREAMBLE(env, type_tag);
2438

13
  CHECK_ARG_WITH_PREAMBLE(env, result);
2439
2440
  auto maybe_value =
2441
13
      obj->GetPrivate(context, NAPI_PRIVATE_KEY(context, type_tag));
2442

13
  CHECK_MAYBE_EMPTY_WITH_PREAMBLE(env, maybe_value, napi_generic_failure);
2443
13
  v8::Local<v8::Value> val = maybe_value.ToLocalChecked();
2444
2445
  // We consider the type check to have failed unless we reach the line below
2446
  // where we set whether the type check succeeded or not based on the
2447
  // comparison of the two type tags.
2448
13
  *result = false;
2449
13
  if (val->IsBigInt()) {
2450
    int sign;
2451
11
    int size = 2;
2452
    napi_type_tag tag;
2453
11
    val.As<v8::BigInt>()->ToWordsArray(
2454
        &sign, &size, reinterpret_cast<uint64_t*>(&tag));
2455
11
    if (sign == 0) {
2456
11
      if (size == 2) {
2457
4
        *result =
2458

4
            (tag.lower == type_tag->lower && tag.upper == type_tag->upper);
2459
7
      } else if (size == 1) {
2460

4
        *result = (tag.lower == type_tag->lower && 0 == type_tag->upper);
2461
3
      } else if (size == 0) {
2462

3
        *result = (0 == type_tag->lower && 0 == type_tag->upper);
2463
      }
2464
    }
2465
  }
2466
2467
13
  return GET_RETURN_STATUS(env);
2468
}
2469
2470
2
napi_status NAPI_CDECL napi_get_value_external(napi_env env,
2471
                                               napi_value value,
2472
                                               void** result) {
2473
2
  CHECK_ENV(env);
2474
2
  CHECK_ARG(env, value);
2475
2
  CHECK_ARG(env, result);
2476
2477
2
  v8::Local<v8::Value> val = v8impl::V8LocalValueFromJsValue(value);
2478
2
  RETURN_STATUS_IF_FALSE(env, val->IsExternal(), napi_invalid_arg);
2479
2480
2
  v8::Local<v8::External> external_value = val.As<v8::External>();
2481
2
  *result = external_value->Value();
2482
2483
2
  return napi_clear_last_error(env);
2484
}
2485
2486
// Set initial_refcount to 0 for a weak reference, >0 for a strong reference.
2487
1547
napi_status NAPI_CDECL napi_create_reference(napi_env env,
2488
                                             napi_value value,
2489
                                             uint32_t initial_refcount,
2490
                                             napi_ref* result) {
2491
  // Omit NAPI_PREAMBLE and GET_RETURN_STATUS because V8 calls here cannot throw
2492
  // JS exceptions.
2493
1547
  CHECK_ENV(env);
2494
1547
  CHECK_ARG(env, value);
2495
1547
  CHECK_ARG(env, result);
2496
2497
1547
  v8::Local<v8::Value> v8_value = v8impl::V8LocalValueFromJsValue(value);
2498

1553
  if (!(v8_value->IsObject() || v8_value->IsFunction() ||
2499
3
        v8_value->IsSymbol())) {
2500
    return napi_set_last_error(env, napi_invalid_arg);
2501
  }
2502
2503
  v8impl::Reference* reference =
2504
1547
      v8impl::Reference::New(env, v8_value, initial_refcount, false);
2505
2506
1547
  *result = reinterpret_cast<napi_ref>(reference);
2507
1547
  return napi_clear_last_error(env);
2508
}
2509
2510
// Deletes a reference. The referenced value is released, and may be GC'd unless
2511
// there are other references to it.
2512
1547
napi_status NAPI_CDECL napi_delete_reference(napi_env env, napi_ref ref) {
2513
  // Omit NAPI_PREAMBLE and GET_RETURN_STATUS because V8 calls here cannot throw
2514
  // JS exceptions.
2515
1547
  CHECK_ENV(env);
2516
1547
  CHECK_ARG(env, ref);
2517
2518
1547
  v8impl::Reference::Delete(reinterpret_cast<v8impl::Reference*>(ref));
2519
2520
1547
  return napi_clear_last_error(env);
2521
}
2522
2523
// Increments the reference count, optionally returning the resulting count.
2524
// After this call the reference will be a strong reference because its
2525
// refcount is >0, and the referenced object is effectively "pinned".
2526
// Calling this when the refcount is 0 and the object is unavailable
2527
// results in an error.
2528
3
napi_status NAPI_CDECL napi_reference_ref(napi_env env,
2529
                                          napi_ref ref,
2530
                                          uint32_t* result) {
2531
  // Omit NAPI_PREAMBLE and GET_RETURN_STATUS because V8 calls here cannot throw
2532
  // JS exceptions.
2533
3
  CHECK_ENV(env);
2534
3
  CHECK_ARG(env, ref);
2535
2536
3
  v8impl::Reference* reference = reinterpret_cast<v8impl::Reference*>(ref);
2537
3
  uint32_t count = reference->Ref();
2538
2539
3
  if (result != nullptr) {
2540
1
    *result = count;
2541
  }
2542
2543
3
  return napi_clear_last_error(env);
2544
}
2545
2546
// Decrements the reference count, optionally returning the resulting count. If
2547
// the result is 0 the reference is now weak and the object may be GC'd at any
2548
// time if there are no other references. Calling this when the refcount is
2549
// already 0 results in an error.
2550
3
napi_status NAPI_CDECL napi_reference_unref(napi_env env,
2551
                                            napi_ref ref,
2552
                                            uint32_t* result) {
2553
  // Omit NAPI_PREAMBLE and GET_RETURN_STATUS because V8 calls here cannot throw
2554
  // JS exceptions.
2555
3
  CHECK_ENV(env);
2556
3
  CHECK_ARG(env, ref);
2557
2558
3
  v8impl::Reference* reference = reinterpret_cast<v8impl::Reference*>(ref);
2559
2560
3
  if (reference->RefCount() == 0) {
2561
    return napi_set_last_error(env, napi_generic_failure);
2562
  }
2563
2564
3
  uint32_t count = reference->Unref();
2565
2566
3
  if (result != nullptr) {
2567
3
    *result = count;
2568
  }
2569
2570
3
  return napi_clear_last_error(env);
2571
}
2572
2573
// Attempts to get a referenced value. If the reference is weak, the value might
2574
// no longer be available, in that case the call is still successful but the
2575
// result is NULL.
2576
11552
napi_status NAPI_CDECL napi_get_reference_value(napi_env env,
2577
                                                napi_ref ref,
2578
                                                napi_value* result) {
2579
  // Omit NAPI_PREAMBLE and GET_RETURN_STATUS because V8 calls here cannot throw
2580
  // JS exceptions.
2581
11552
  CHECK_ENV(env);
2582
11552
  CHECK_ARG(env, ref);
2583
11550
  CHECK_ARG(env, result);
2584
2585
11550
  v8impl::Reference* reference = reinterpret_cast<v8impl::Reference*>(ref);
2586
11550
  *result = v8impl::JsValueFromV8LocalValue(reference->Get());
2587
2588
11550
  return napi_clear_last_error(env);
2589
}
2590
2591
4
napi_status NAPI_CDECL napi_open_handle_scope(napi_env env,
2592
                                              napi_handle_scope* result) {
2593
  // Omit NAPI_PREAMBLE and GET_RETURN_STATUS because V8 calls here cannot throw
2594
  // JS exceptions.
2595
4
  CHECK_ENV(env);
2596
4
  CHECK_ARG(env, result);
2597
2598
4
  *result = v8impl::JsHandleScopeFromV8HandleScope(
2599
4
      new v8impl::HandleScopeWrapper(env->isolate));
2600
4
  env->open_handle_scopes++;
2601
4
  return napi_clear_last_error(env);
2602
}
2603
2604
4
napi_status NAPI_CDECL napi_close_handle_scope(napi_env env,
2605
                                               napi_handle_scope scope) {
2606
  // Omit NAPI_PREAMBLE and GET_RETURN_STATUS because V8 calls here cannot throw
2607
  // JS exceptions.
2608
4
  CHECK_ENV(env);
2609
4
  CHECK_ARG(env, scope);
2610
4
  if (env->open_handle_scopes == 0) {
2611
    return napi_handle_scope_mismatch;
2612
  }
2613
2614
4
  env->open_handle_scopes--;
2615
4
  delete v8impl::V8HandleScopeFromJsHandleScope(scope);
2616
4
  return napi_clear_last_error(env);
2617
}
2618
2619
2
napi_status NAPI_CDECL napi_open_escapable_handle_scope(
2620
    napi_env env, napi_escapable_handle_scope* result) {
2621
  // Omit NAPI_PREAMBLE and GET_RETURN_STATUS because V8 calls here cannot throw
2622
  // JS exceptions.
2623
2
  CHECK_ENV(env);
2624
2
  CHECK_ARG(env, result);
2625
2626
2
  *result = v8impl::JsEscapableHandleScopeFromV8EscapableHandleScope(
2627
2
      new v8impl::EscapableHandleScopeWrapper(env->isolate));
2628
2
  env->open_handle_scopes++;
2629
2
  return napi_clear_last_error(env);
2630
}
2631
2632
2
napi_status NAPI_CDECL napi_close_escapable_handle_scope(
2633
    napi_env env, napi_escapable_handle_scope scope) {
2634
  // Omit NAPI_PREAMBLE and GET_RETURN_STATUS because V8 calls here cannot throw
2635
  // JS exceptions.
2636
2
  CHECK_ENV(env);
2637
2
  CHECK_ARG(env, scope);
2638
2
  if (env->open_handle_scopes == 0) {
2639
    return napi_handle_scope_mismatch;
2640
  }
2641
2642
2
  delete v8impl::V8EscapableHandleScopeFromJsEscapableHandleScope(scope);
2643
2
  env->open_handle_scopes--;
2644
2
  return napi_clear_last_error(env);
2645
}
2646
2647
3
napi_status NAPI_CDECL napi_escape_handle(napi_env env,
2648
                                          napi_escapable_handle_scope scope,
2649
                                          napi_value escapee,
2650
                                          napi_value* result) {
2651
  // Omit NAPI_PREAMBLE and GET_RETURN_STATUS because V8 calls here cannot throw
2652
  // JS exceptions.
2653
3
  CHECK_ENV(env);
2654
3
  CHECK_ARG(env, scope);
2655
3
  CHECK_ARG(env, escapee);
2656
3
  CHECK_ARG(env, result);
2657
2658
  v8impl::EscapableHandleScopeWrapper* s =
2659
3
      v8impl::V8EscapableHandleScopeFromJsEscapableHandleScope(scope);
2660
3
  if (!s->escape_called()) {
2661
2
    *result = v8impl::JsValueFromV8LocalValue(
2662
        s->Escape(v8impl::V8LocalValueFromJsValue(escapee)));
2663
2
    return napi_clear_last_error(env);
2664
  }
2665
1
  return napi_set_last_error(env, napi_escape_called_twice);
2666
}
2667
2668
11
napi_status NAPI_CDECL napi_new_instance(napi_env env,
2669
                                         napi_value constructor,
2670
                                         size_t argc,
2671
                                         const napi_value* argv,
2672
                                         napi_value* result) {
2673


22
  NAPI_PREAMBLE(env);
2674
11
  CHECK_ARG(env, constructor);
2675
11
  if (argc > 0) {
2676
7
    CHECK_ARG(env, argv);
2677
  }
2678
11
  CHECK_ARG(env, result);
2679
2680
11
  v8::Local<v8::Context> context = env->context();
2681
2682
  v8::Local<v8::Function> ctor;
2683

33
  CHECK_TO_FUNCTION(env, ctor, constructor);
2684
2685
  auto maybe = ctor->NewInstance(
2686
      context,
2687
      argc,
2688
11
      reinterpret_cast<v8::Local<v8::Value>*>(const_cast<napi_value*>(argv)));
2689
2690
11
  CHECK_MAYBE_EMPTY(env, maybe, napi_pending_exception);
2691
2692
9
  *result = v8impl::JsValueFromV8LocalValue(maybe.ToLocalChecked());
2693
9
  return GET_RETURN_STATUS(env);
2694
}
2695
2696
2278
napi_status NAPI_CDECL napi_instanceof(napi_env env,
2697
                                       napi_value object,
2698
                                       napi_value constructor,
2699
                                       bool* result) {
2700


4556
  NAPI_PREAMBLE(env);
2701
2278
  CHECK_ARG(env, object);
2702
2278
  CHECK_ARG(env, result);
2703
2704
2278
  *result = false;
2705
2706
  v8::Local<v8::Object> ctor;
2707
2278
  v8::Local<v8::Context> context = env->context();
2708
2709

6834
  CHECK_TO_OBJECT(env, context, ctor, constructor);
2710
2711
2278
  if (!ctor->IsFunction()) {
2712
88
    napi_throw_type_error(
2713
        env, "ERR_NAPI_CONS_FUNCTION", "Constructor must be a function");
2714
2715
88
    return napi_set_last_error(env, napi_function_expected);
2716
  }
2717
2718
2190
  napi_status status = napi_generic_failure;
2719
2720
2190
  v8::Local<v8::Value> val = v8impl::V8LocalValueFromJsValue(object);
2721
2190
  auto maybe_result = val->InstanceOf(context, ctor);
2722
2190
  CHECK_MAYBE_NOTHING(env, maybe_result, status);
2723
1166
  *result = maybe_result.FromJust();
2724
1166
  return GET_RETURN_STATUS(env);
2725
}
2726
2727
// Methods to support catching exceptions
2728
1239
napi_status NAPI_CDECL napi_is_exception_pending(napi_env env, bool* result) {
2729
  // NAPI_PREAMBLE is not used here: this function must execute when there is a
2730
  // pending exception.
2731
1239
  CHECK_ENV(env);
2732
1239
  CHECK_ARG(env, result);
2733
2734
1239
  *result = !env->last_exception.IsEmpty();
2735
1239
  return napi_clear_last_error(env);
2736
}
2737
2738
2
napi_status NAPI_CDECL napi_get_and_clear_last_exception(napi_env env,
2739
                                                         napi_value* result) {
2740
  // NAPI_PREAMBLE is not used here: this function must execute when there is a
2741
  // pending exception.
2742
2
  CHECK_ENV(env);
2743
2
  CHECK_ARG(env, result);
2744
2745
2
  if (env->last_exception.IsEmpty()) {
2746
    return napi_get_undefined(env, result);
2747
  } else {
2748
2
    *result = v8impl::JsValueFromV8LocalValue(
2749
2
        v8::Local<v8::Value>::New(env->isolate, env->last_exception));
2750
2
    env->last_exception.Reset();
2751
  }
2752
2753
2
  return napi_clear_last_error(env);
2754
}
2755
2756
57
napi_status NAPI_CDECL napi_is_arraybuffer(napi_env env,
2757
                                           napi_value value,
2758
                                           bool* result) {
2759
57
  CHECK_ENV(env);
2760
57
  CHECK_ARG(env, value);
2761
57
  CHECK_ARG(env, result);
2762
2763
57
  v8::Local<v8::Value> val = v8impl::V8LocalValueFromJsValue(value);
2764
57
  *result = val->IsArrayBuffer();
2765
2766
57
  return napi_clear_last_error(env);
2767
}
2768
2769
2
napi_status NAPI_CDECL napi_create_arraybuffer(napi_env env,
2770
                                               size_t byte_length,
2771
                                               void** data,
2772
                                               napi_value* result) {
2773


4
  NAPI_PREAMBLE(env);
2774
2
  CHECK_ARG(env, result);
2775
2776
2
  v8::Isolate* isolate = env->isolate;
2777
  v8::Local<v8::ArrayBuffer> buffer =
2778
2
      v8::ArrayBuffer::New(isolate, byte_length);
2779
2780
  // Optionally return a pointer to the buffer's data, to avoid another call to
2781
  // retrieve it.
2782
2
  if (data != nullptr) {
2783
2
    *data = buffer->Data();
2784
  }
2785
2786
2
  *result = v8impl::JsValueFromV8LocalValue(buffer);
2787
2
  return GET_RETURN_STATUS(env);
2788
}
2789
2790
napi_status NAPI_CDECL
2791
6
napi_create_external_arraybuffer(napi_env env,
2792
                                 void* external_data,
2793
                                 size_t byte_length,
2794
                                 napi_finalize finalize_cb,
2795
                                 void* finalize_hint,
2796
                                 napi_value* result) {
2797
  // The API contract here is that the cleanup function runs on the JS thread,
2798
  // and is able to use napi_env. Implementing that properly is hard, so use the
2799
  // `Buffer` variant for easier implementation.
2800
  napi_value buffer;
2801
6
  STATUS_CALL(napi_create_external_buffer(
2802
      env, byte_length, external_data, finalize_cb, finalize_hint, &buffer));
2803
6
  return napi_get_typedarray_info(
2804
6
      env, buffer, nullptr, nullptr, nullptr, result, nullptr);
2805
}
2806
2807
2
napi_status NAPI_CDECL napi_get_arraybuffer_info(napi_env env,
2808
                                                 napi_value arraybuffer,
2809
                                                 void** data,
2810
                                                 size_t* byte_length) {
2811
2
  CHECK_ENV(env);
2812
2
  CHECK_ARG(env, arraybuffer);
2813
2814
2
  v8::Local<v8::Value> value = v8impl::V8LocalValueFromJsValue(arraybuffer);
2815
2
  RETURN_STATUS_IF_FALSE(env, value->IsArrayBuffer(), napi_invalid_arg);
2816
2817
2
  v8::Local<v8::ArrayBuffer> ab = value.As<v8::ArrayBuffer>();
2818
2819
2
  if (data != nullptr) {
2820
2
    *data = ab->Data();
2821
  }
2822
2823
2
  if (byte_length != nullptr) {
2824
2
    *byte_length = ab->ByteLength();
2825
  }
2826
2827
2
  return napi_clear_last_error(env);
2828
}
2829
2830
44
napi_status NAPI_CDECL napi_is_typedarray(napi_env env,
2831
                                          napi_value value,
2832
                                          bool* result) {
2833
44
  CHECK_ENV(env);
2834
44
  CHECK_ARG(env, value);
2835
44
  CHECK_ARG(env, result);
2836
2837
44
  v8::Local<v8::Value> val = v8impl::V8LocalValueFromJsValue(value);
2838
44
  *result = val->IsTypedArray();
2839
2840
44
  return napi_clear_last_error(env);
2841
}
2842
2843
34
napi_status NAPI_CDECL napi_create_typedarray(napi_env env,
2844
                                              napi_typedarray_type type,
2845
                                              size_t length,
2846
                                              napi_value arraybuffer,
2847
                                              size_t byte_offset,
2848
                                              napi_value* result) {
2849


68
  NAPI_PREAMBLE(env);
2850
34
  CHECK_ARG(env, arraybuffer);
2851
34
  CHECK_ARG(env, result);
2852
2853
34
  v8::Local<v8::Value> value = v8impl::V8LocalValueFromJsValue(arraybuffer);
2854
34
  RETURN_STATUS_IF_FALSE(env, value->IsArrayBuffer(), napi_invalid_arg);
2855
2856



34
  v8::Local<v8::ArrayBuffer> buffer = value.As<v8::ArrayBuffer>();
2857
  v8::Local<v8::TypedArray> typedArray;
2858
2859



34
  switch (type) {
2860
4
    case napi_int8_array:
2861
4
      CREATE_TYPED_ARRAY(
2862
          env, Int8Array, 1, buffer, byte_offset, length, typedArray);
2863
3
      break;
2864
3
    case napi_uint8_array:
2865
3
      CREATE_TYPED_ARRAY(
2866
          env, Uint8Array, 1, buffer, byte_offset, length, typedArray);
2867
2
      break;
2868
2
    case napi_uint8_clamped_array:
2869
2
      CREATE_TYPED_ARRAY(
2870
          env, Uint8ClampedArray, 1, buffer, byte_offset, length, typedArray);
2871
1
      break;
2872
3
    case napi_int16_array:
2873

3
      CREATE_TYPED_ARRAY(
2874
          env, Int16Array, 2, buffer, byte_offset, length, typedArray);
2875
1
      break;
2876
3
    case napi_uint16_array:
2877

3
      CREATE_TYPED_ARRAY(
2878
          env, Uint16Array, 2, buffer, byte_offset, length, typedArray);
2879
1
      break;
2880
3
    case napi_int32_array:
2881

3
      CREATE_TYPED_ARRAY(
2882
          env, Int32Array, 4, buffer, byte_offset, length, typedArray);
2883
1
      break;
2884
3
    case napi_uint32_array:
2885

3
      CREATE_TYPED_ARRAY(
2886
          env, Uint32Array, 4, buffer, byte_offset, length, typedArray);
2887
1
      break;
2888
3
    case napi_float32_array:
2889

3
      CREATE_TYPED_ARRAY(
2890
          env, Float32Array, 4, buffer, byte_offset, length, typedArray);
2891
1
      break;
2892
4
    case napi_float64_array:
2893

4
      CREATE_TYPED_ARRAY(
2894
          env, Float64Array, 8, buffer, byte_offset, length, typedArray);
2895
2
      break;
2896
3
    case napi_bigint64_array:
2897

3
      CREATE_TYPED_ARRAY(
2898
          env, BigInt64Array, 8, buffer, byte_offset, length, typedArray);
2899
1
      break;
2900
3
    case napi_biguint64_array:
2901

3
      CREATE_TYPED_ARRAY(
2902
          env, BigUint64Array, 8, buffer, byte_offset, length, typedArray);
2903
1
      break;
2904
    default:
2905
      return napi_set_last_error(env, napi_invalid_arg);
2906
  }
2907
2908
15
  *result = v8impl::JsValueFromV8LocalValue(typedArray);
2909
15
  return GET_RETURN_STATUS(env);
2910
}
2911
2912
50
napi_status NAPI_CDECL napi_get_typedarray_info(napi_env env,
2913
                                                napi_value typedarray,
2914
                                                napi_typedarray_type* type,
2915
                                                size_t* length,
2916
                                                void** data,
2917
                                                napi_value* arraybuffer,
2918
                                                size_t* byte_offset) {
2919
50
  CHECK_ENV(env);
2920
50
  CHECK_ARG(env, typedarray);
2921
2922
50
  v8::Local<v8::Value> value = v8impl::V8LocalValueFromJsValue(typedarray);
2923
50
  RETURN_STATUS_IF_FALSE(env, value->IsTypedArray(), napi_invalid_arg);
2924
2925
50
  v8::Local<v8::TypedArray> array = value.As<v8::TypedArray>();
2926
2927
50
  if (type != nullptr) {
2928
32
    if (value->IsInt8Array()) {
2929
2
      *type = napi_int8_array;
2930
30
    } else if (value->IsUint8Array()) {
2931
3
      *type = napi_uint8_array;
2932
27
    } else if (value->IsUint8ClampedArray()) {
2933
2
      *type = napi_uint8_clamped_array;
2934
25
    } else if (value->IsInt16Array()) {
2935
3
      *type = napi_int16_array;
2936
22
    } else if (value->IsUint16Array()) {
2937
3
      *type = napi_uint16_array;
2938
19
    } else if (value->IsInt32Array()) {
2939
3
      *type = napi_int32_array;
2940
16
    } else if (value->IsUint32Array()) {
2941
3
      *type = napi_uint32_array;
2942
13
    } else if (value->IsFloat32Array()) {
2943
3
      *type = napi_float32_array;
2944
10
    } else if (value->IsFloat64Array()) {
2945
4
      *type = napi_float64_array;
2946
6
    } else if (value->IsBigInt64Array()) {
2947
3
      *type = napi_bigint64_array;
2948
3
    } else if (value->IsBigUint64Array()) {
2949
3
      *type = napi_biguint64_array;
2950
    }
2951
  }
2952
2953
50
  if (length != nullptr) {
2954
32
    *length = array->Length();
2955
  }
2956
2957
  v8::Local<v8::ArrayBuffer> buffer;
2958

50
  if (data != nullptr || arraybuffer != nullptr) {
2959
    // Calling Buffer() may have the side effect of allocating the buffer,
2960
    // so only do this when it’s needed.
2961
50
    buffer = array->Buffer();
2962
  }
2963
2964
50
  if (data != nullptr) {
2965
    *data = static_cast<uint8_t*>(buffer->Data()) + array->ByteOffset();
2966
  }
2967
2968
50
  if (arraybuffer != nullptr) {
2969
50
    *arraybuffer = v8impl::JsValueFromV8LocalValue(buffer);
2970
  }
2971
2972
50
  if (byte_offset != nullptr) {
2973
32
    *byte_offset = array->ByteOffset();
2974
  }
2975
2976
50
  return napi_clear_last_error(env);
2977
}
2978
2979
2
napi_status NAPI_CDECL napi_create_dataview(napi_env env,
2980
                                            size_t byte_length,
2981
                                            napi_value arraybuffer,
2982
                                            size_t byte_offset,
2983
                                            napi_value* result) {
2984


4
  NAPI_PREAMBLE(env);
2985
2
  CHECK_ARG(env, arraybuffer);
2986
2
  CHECK_ARG(env, result);
2987
2988
2
  v8::Local<v8::Value> value = v8impl::V8LocalValueFromJsValue(arraybuffer);
2989
2
  RETURN_STATUS_IF_FALSE(env, value->IsArrayBuffer(), napi_invalid_arg);
2990
2991
2
  v8::Local<v8::ArrayBuffer> buffer = value.As<v8::ArrayBuffer>();
2992
2
  if (byte_length + byte_offset > buffer->ByteLength()) {
2993
1
    napi_throw_range_error(env,
2994
                           "ERR_NAPI_INVALID_DATAVIEW_ARGS",
2995
                           "byte_offset + byte_length should be less than or "
2996
                           "equal to the size in bytes of the array passed in");
2997
1
    return napi_set_last_error(env, napi_pending_exception);
2998
  }
2999
  v8::Local<v8::DataView> DataView =
3000
1
      v8::DataView::New(buffer, byte_offset, byte_length);
3001
3002
1
  *result = v8impl::JsValueFromV8LocalValue(DataView);
3003
1
  return GET_RETURN_STATUS(env);
3004
}
3005
3006
1
napi_status NAPI_CDECL napi_is_dataview(napi_env env,
3007
                                        napi_value value,
3008
                                        bool* result) {
3009
1
  CHECK_ENV(env);
3010
1
  CHECK_ARG(env, value);
3011
1
  CHECK_ARG(env, result);
3012
3013
1
  v8::Local<v8::Value> val = v8impl::V8LocalValueFromJsValue(value);
3014
1
  *result = val->IsDataView();
3015
3016
1
  return napi_clear_last_error(env);
3017
}
3018
3019
1
napi_status NAPI_CDECL napi_get_dataview_info(napi_env env,
3020
                                              napi_value dataview,
3021
                                              size_t* byte_length,
3022
                                              void** data,
3023
                                              napi_value* arraybuffer,
3024
                                              size_t* byte_offset) {
3025
1
  CHECK_ENV(env);
3026
1
  CHECK_ARG(env, dataview);
3027
3028
1
  v8::Local<v8::Value> value = v8impl::V8LocalValueFromJsValue(dataview);
3029
1
  RETURN_STATUS_IF_FALSE(env, value->IsDataView(), napi_invalid_arg);
3030
3031
1
  v8::Local<v8::DataView> array = value.As<v8::DataView>();
3032
3033
1
  if (byte_length != nullptr) {
3034
1
    *byte_length = array->ByteLength();
3035
  }
3036
3037
  v8::Local<v8::ArrayBuffer> buffer;
3038

1
  if (data != nullptr || arraybuffer != nullptr) {
3039
    // Calling Buffer() may have the side effect of allocating the buffer,
3040
    // so only do this when it’s needed.
3041
1
    buffer = array->Buffer();
3042
  }
3043
3044
1
  if (data != nullptr) {
3045
    *data = static_cast<uint8_t*>(buffer->Data()) + array->ByteOffset();
3046
  }
3047
3048
1
  if (arraybuffer != nullptr) {
3049
1
    *arraybuffer = v8impl::JsValueFromV8LocalValue(buffer);
3050
  }
3051
3052
1
  if (byte_offset != nullptr) {
3053
1
    *byte_offset = array->ByteOffset();
3054
  }
3055
3056
1
  return napi_clear_last_error(env);
3057
}
3058
3059
1
napi_status NAPI_CDECL napi_get_version(napi_env env, uint32_t* result) {
3060
1
  CHECK_ENV(env);
3061
1
  CHECK_ARG(env, result);
3062
1
  *result = NAPI_VERSION;
3063
1
  return napi_clear_last_error(env);
3064
}
3065
3066
5
napi_status NAPI_CDECL napi_create_promise(napi_env env,
3067
                                           napi_deferred* deferred,
3068
                                           napi_value* promise) {
3069


10
  NAPI_PREAMBLE(env);
3070
5
  CHECK_ARG(env, deferred);
3071
5
  CHECK_ARG(env, promise);
3072
3073
5
  auto maybe = v8::Promise::Resolver::New(env->context());
3074
5
  CHECK_MAYBE_EMPTY(env, maybe, napi_generic_failure);
3075
3076
5
  auto v8_resolver = maybe.ToLocalChecked();
3077
5
  auto v8_deferred = new v8impl::Persistent<v8::Value>();
3078
5
  v8_deferred->Reset(env->isolate, v8_resolver);
3079
3080
5
  *deferred = v8impl::JsDeferredFromNodePersistent(v8_deferred);
3081
10
  *promise = v8impl::JsValueFromV8LocalValue(v8_resolver->GetPromise());
3082
5
  return GET_RETURN_STATUS(env);
3083
}
3084
3085
4
napi_status NAPI_CDECL napi_resolve_deferred(napi_env env,
3086
                                             napi_deferred deferred,
3087
                                             napi_value resolution) {
3088
4
  return v8impl::ConcludeDeferred(env, deferred, resolution, true);
3089
}
3090
3091
1
napi_status NAPI_CDECL napi_reject_deferred(napi_env env,
3092
                                            napi_deferred deferred,
3093
                                            napi_value resolution) {
3094
1
  return v8impl::ConcludeDeferred(env, deferred, resolution, false);
3095
}
3096
3097
7
napi_status NAPI_CDECL napi_is_promise(napi_env env,
3098
                                       napi_value value,
3099
                                       bool* is_promise) {
3100
7
  CHECK_ENV(env);
3101
7
  CHECK_ARG(env, value);
3102
7
  CHECK_ARG(env, is_promise);
3103
3104
14
  *is_promise = v8impl::V8LocalValueFromJsValue(value)->IsPromise();
3105
3106
7
  return napi_clear_last_error(env);
3107
}
3108
3109
1
napi_status NAPI_CDECL napi_create_date(napi_env env,
3110
                                        double time,
3111
                                        napi_value* result) {
3112


2
  NAPI_PREAMBLE(env);
3113
1
  CHECK_ARG(env, result);
3114
3115
1
  v8::MaybeLocal<v8::Value> maybe_date = v8::Date::New(env->context(), time);
3116
1
  CHECK_MAYBE_EMPTY(env, maybe_date, napi_generic_failure);
3117
3118
1
  *result = v8impl::JsValueFromV8LocalValue(maybe_date.ToLocalChecked());
3119
3120
1
  return GET_RETURN_STATUS(env);
3121
}
3122
3123
7
napi_status NAPI_CDECL napi_is_date(napi_env env,
3124
                                    napi_value value,
3125
                                    bool* is_date) {
3126
7
  CHECK_ENV(env);
3127
7
  CHECK_ARG(env, value);
3128
7
  CHECK_ARG(env, is_date);
3129
3130
14
  *is_date = v8impl::V8LocalValueFromJsValue(value)->IsDate();
3131
3132
7
  return napi_clear_last_error(env);
3133
}
3134
3135
1
napi_status NAPI_CDECL napi_get_date_value(napi_env env,
3136
                                           napi_value value,
3137
                                           double* result) {
3138


2
  NAPI_PREAMBLE(env);
3139
1
  CHECK_ARG(env, value);
3140
1
  CHECK_ARG(env, result);
3141
3142
1
  v8::Local<v8::Value> val = v8impl::V8LocalValueFromJsValue(value);
3143
1
  RETURN_STATUS_IF_FALSE(env, val->IsDate(), napi_date_expected);
3144
3145
1
  v8::Local<v8::Date> date = val.As<v8::Date>();
3146
1
  *result = date->ValueOf();
3147
3148
1
  return GET_RETURN_STATUS(env);
3149
}
3150
3151
2
napi_status NAPI_CDECL napi_run_script(napi_env env,
3152
                                       napi_value script,
3153
                                       napi_value* result) {
3154


4
  NAPI_PREAMBLE(env);
3155
2
  CHECK_ARG(env, script);
3156
2
  CHECK_ARG(env, result);
3157
3158
2
  v8::Local<v8::Value> v8_script = v8impl::V8LocalValueFromJsValue(script);
3159
3160
4
  if (!v8_script->IsString()) {
3161
1
    return napi_set_last_error(env, napi_string_expected);
3162
  }
3163
3164
1
  v8::Local<v8::Context> context = env->context();
3165
3166
1
  auto maybe_script = v8::Script::Compile(context, v8_script.As<v8::String>());
3167
1
  CHECK_MAYBE_EMPTY(env, maybe_script, napi_generic_failure);
3168
3169
1
  auto script_result = maybe_script.ToLocalChecked()->Run(context);
3170
1
  CHECK_MAYBE_EMPTY(env, script_result, napi_generic_failure);
3171
3172
1
  *result = v8impl::JsValueFromV8LocalValue(script_result.ToLocalChecked());
3173
1
  return GET_RETURN_STATUS(env);
3174
}
3175
3176
4
napi_status NAPI_CDECL napi_add_finalizer(napi_env env,
3177
                                          napi_value js_object,
3178
                                          void* native_object,
3179
                                          napi_finalize finalize_cb,
3180
                                          void* finalize_hint,
3181
                                          napi_ref* result) {
3182
4
  return v8impl::Wrap<v8impl::anonymous>(
3183
4
      env, js_object, native_object, finalize_cb, finalize_hint, result);
3184
}
3185
3186
1
napi_status NAPI_CDECL napi_adjust_external_memory(napi_env env,
3187
                                                   int64_t change_in_bytes,
3188
                                                   int64_t* adjusted_value) {
3189
1
  CHECK_ENV(env);
3190
1
  CHECK_ARG(env, adjusted_value);
3191
3192
2
  *adjusted_value =
3193
1
      env->isolate->AdjustAmountOfExternalAllocatedMemory(change_in_bytes);
3194
3195
1
  return napi_clear_last_error(env);
3196
}
3197
3198
7
napi_status NAPI_CDECL napi_set_instance_data(napi_env env,
3199
                                              void* data,
3200
                                              napi_finalize finalize_cb,
3201
                                              void* finalize_hint) {
3202
7
  CHECK_ENV(env);
3203
3204
7
  v8impl::RefBase* old_data = static_cast<v8impl::RefBase*>(env->instance_data);
3205
7
  if (old_data != nullptr) {
3206
    // Our contract so far has been to not finalize any old data there may be.
3207
    // So we simply delete it.
3208
    v8impl::RefBase::Delete(old_data);
3209
  }
3210
3211
14
  env->instance_data =
3212
7
      v8impl::RefBase::New(env, 0, true, finalize_cb, data, finalize_hint);
3213
3214
7
  return napi_clear_last_error(env);
3215
}
3216
3217
22
napi_status NAPI_CDECL napi_get_instance_data(napi_env env, void** data) {
3218
22
  CHECK_ENV(env);
3219
22
  CHECK_ARG(env, data);
3220
3221
22
  v8impl::RefBase* idata = static_cast<v8impl::RefBase*>(env->instance_data);
3222
3223
22
  *data = (idata == nullptr ? nullptr : idata->Data());
3224
3225
22
  return napi_clear_last_error(env);
3226
}
3227
3228
12
napi_status NAPI_CDECL napi_detach_arraybuffer(napi_env env,
3229
                                               napi_value arraybuffer) {
3230
12
  CHECK_ENV(env);
3231
12
  CHECK_ARG(env, arraybuffer);
3232
3233
12
  v8::Local<v8::Value> value = v8impl::V8LocalValueFromJsValue(arraybuffer);
3234
12
  RETURN_STATUS_IF_FALSE(
3235
      env, value->IsArrayBuffer(), napi_arraybuffer_expected);
3236
3237
12
  v8::Local<v8::ArrayBuffer> it = value.As<v8::ArrayBuffer>();
3238
12
  RETURN_STATUS_IF_FALSE(
3239
      env, it->IsDetachable(), napi_detachable_arraybuffer_expected);
3240
3241
12
  it->Detach();
3242
3243
12
  return napi_clear_last_error(env);
3244
}
3245
3246
26
napi_status NAPI_CDECL napi_is_detached_arraybuffer(napi_env env,
3247
                                                    napi_value arraybuffer,
3248
                                                    bool* result) {
3249
26
  CHECK_ENV(env);
3250
26
  CHECK_ARG(env, arraybuffer);
3251
26
  CHECK_ARG(env, result);
3252
3253
26
  v8::Local<v8::Value> value = v8impl::V8LocalValueFromJsValue(arraybuffer);
3254
3255
26
  *result =
3256

52
      value->IsArrayBuffer() && value.As<v8::ArrayBuffer>()->Data() == nullptr;
3257
3258
26
  return napi_clear_last_error(env);
3259
}