GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: js_native_api_v8.cc Lines: 1428 1458 97.9 %
Date: 2022-08-29 04:21:03 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 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 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 napi_deferred JsDeferredFromNodePersistent(
104
    v8impl::Persistent<v8::Value>* local) {
105
5
  return reinterpret_cast<napi_deferred>(local);
106
}
107
108
5
inline 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 napi_handle_scope JsHandleScopeFromV8HandleScope(HandleScopeWrapper* s) {
143
4
  return reinterpret_cast<napi_handle_scope>(s);
144
}
145
146
4
inline HandleScopeWrapper* V8HandleScopeFromJsHandleScope(napi_handle_scope s) {
147
4
  return reinterpret_cast<HandleScopeWrapper*>(s);
148
}
149
150
inline napi_escapable_handle_scope
151
2
JsEscapableHandleScopeFromV8EscapableHandleScope(
152
    EscapableHandleScopeWrapper* s) {
153
2
  return reinterpret_cast<napi_escapable_handle_scope>(s);
154
}
155
156
inline EscapableHandleScopeWrapper*
157
5
V8EscapableHandleScopeFromJsEscapableHandleScope(
158
    napi_escapable_handle_scope s) {
159
5
  return reinterpret_cast<EscapableHandleScopeWrapper*>(s);
160
}
161
162
5
inline napi_status ConcludeDeferred(napi_env env,
163
                                    napi_deferred deferred,
164
                                    napi_value result,
165
                                    bool is_resolved) {
166


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

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


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

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




2064
  NAPI_PREAMBLE(env);
405

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

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

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

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

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

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

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

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

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

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


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


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


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


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

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


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

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

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


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

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

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


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

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


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

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


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

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

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


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

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


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

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

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

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


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

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

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


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

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

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


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

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

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


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

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


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

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


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

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

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


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

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

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

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

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

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


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

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

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


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

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

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


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


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


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

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

15
  if (length > 0) CHECK_ARG(env, str);
1457
14
  CHECK_ARG(env, result);
1458

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

748
  if (length > 0) CHECK_ARG(env, str);
1479
746
  CHECK_ARG(env, result);
1480

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

17
  if (length > 0) CHECK_ARG(env, str);
1497
16
  CHECK_ARG(env, result);
1498

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


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

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

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

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

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


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

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


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


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

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


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

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


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

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


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

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

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


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




44
GEN_COERCE_FUNCTION(NUMBER, Number, number)
2351




51
GEN_COERCE_FUNCTION(OBJECT, Object, object)
2352




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


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


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


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

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

4
  CHECK_MAYBE_NOTHING_WITH_PREAMBLE(env, maybe_has, napi_generic_failure);
2412

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

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

4
  CHECK_MAYBE_NOTHING_WITH_PREAMBLE(env, maybe_set, napi_generic_failure);
2421

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


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


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

13
  CHECK_ARG_WITH_PREAMBLE(env, type_tag);
2436

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

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

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

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

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

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


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

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


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

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


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


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



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



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

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

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

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

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

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

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

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

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

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


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

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


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


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


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


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

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