GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: js_native_api_v8.cc Lines: 1416 1453 97.5 %
Date: 2022-04-03 04:14:58 Branches: 1140 1794 63.5 %

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
480
inline static napi_status V8NameFromPropertyDescriptor(
65
    napi_env env,
66
    const napi_property_descriptor* p,
67
    v8::Local<v8::Name>* result) {
68
480
  if (p->utf8name != nullptr) {
69

1428
    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
480
  return napi_ok;
79
}
80
81
// convert from n-api property attributes to v8::PropertyAttribute
82
21
inline static v8::PropertyAttribute V8PropertyAttributesFromDescriptor(
83
    const napi_property_descriptor* descriptor) {
84
21
  unsigned int attribute_flags = v8::PropertyAttribute::None;
85
86
  // The napi_writable attribute is ignored for accessor descriptors, but
87
  // V8 would throw `TypeError`s on assignment with nonexistence of a setter.
88

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


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

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


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

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




2064
  NAPI_PREAMBLE(env);
407

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

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

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

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

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

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

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

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

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

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


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


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


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


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

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


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

14
  CHECK_TO_OBJECT(env, context, obj, object);
928
929
6
  v8::PropertyFilter filter = v8::PropertyFilter::ALL_PROPERTIES;
930
6
  if (key_filter & napi_key_writable) {
931
    filter = static_cast<v8::PropertyFilter>(filter |
932
                                             v8::PropertyFilter::ONLY_WRITABLE);
933
  }
934
6
  if (key_filter & napi_key_enumerable) {
935
5
    filter = static_cast<v8::PropertyFilter>(
936
5
        filter | v8::PropertyFilter::ONLY_ENUMERABLE);
937
  }
938
6
  if (key_filter & napi_key_configurable) {
939
    filter = static_cast<v8::PropertyFilter>(filter |
940
                                             v8::PropertyFilter::ONLY_WRITABLE);
941
  }
942
6
  if (key_filter & napi_key_skip_strings) {
943
1
    filter = static_cast<v8::PropertyFilter>(filter |
944
                                             v8::PropertyFilter::SKIP_STRINGS);
945
  }
946
6
  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
6
  switch (key_mode) {
954
6
    case napi_key_include_prototypes:
955
6
      collection_mode = v8::KeyCollectionMode::kIncludePrototypes;
956
6
      break;
957
    case napi_key_own_only:
958
      collection_mode = v8::KeyCollectionMode::kOwnOnly;
959
      break;
960
    default:
961
      return napi_set_last_error(env, napi_invalid_arg);
962
  }
963
964
6
  switch (key_conversion) {
965
    case napi_key_keep_numbers:
966
      conversion_mode = v8::KeyConversionMode::kKeepNumbers;
967
      break;
968
6
    case napi_key_numbers_to_strings:
969
6
      conversion_mode = v8::KeyConversionMode::kConvertToString;
970
6
      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
6
                            conversion_mode);
981
982

6
  CHECK_MAYBE_EMPTY_WITH_PREAMBLE(
983
      env, maybe_all_propertynames, napi_generic_failure);
984
985
12
  *result =
986
6
      v8impl::JsValueFromV8LocalValue(maybe_all_propertynames.ToLocalChecked());
987
6
  return GET_RETURN_STATUS(env);
988
}
989
990
27
napi_status 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_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_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_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_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
167
napi_status napi_set_named_property(napi_env env,
1099
                                    napi_value object,
1100
                                    const char* utf8name,
1101
                                    napi_value value) {
1102


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

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

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

326
  RETURN_STATUS_IF_FALSE(env, set_maybe.FromMaybe(false), napi_generic_failure);
1118
163
  return GET_RETURN_STATUS(env);
1119
}
1120
1121
9
napi_status 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_get_named_property(napi_env env,
1145
                                    napi_value object,
1146
                                    const char* utf8name,
1147
                                    napi_value* result) {
1148


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

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

7
  CHECK_TO_OBJECT(env, context, obj, object);
1159
1160
2
  auto get_maybe = obj->Get(context, key);
1161
1162
2
  CHECK_MAYBE_EMPTY(env, get_maybe, napi_generic_failure);
1163
1164
2
  v8::Local<v8::Value> val = get_maybe.ToLocalChecked();
1165
2
  *result = v8impl::JsValueFromV8LocalValue(val);
1166
2
  return GET_RETURN_STATUS(env);
1167
}
1168
1169
13
napi_status 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_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_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_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
86
napi_status napi_define_properties(napi_env env,
1248
                                   napi_value object,
1249
                                   size_t property_count,
1250
                                   const napi_property_descriptor* properties) {
1251


171
  NAPI_PREAMBLE(env);
1252
85
  if (property_count > 0) {
1253
85
    CHECK_ARG(env, properties);
1254
  }
1255
1256
82
  v8::Local<v8::Context> context = env->context();
1257
1258
  v8::Local<v8::Object> obj;
1259

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

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

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

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

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


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

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

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


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

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

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


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


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


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

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

15
  if (length > 0) CHECK_ARG(env, str);
1454
14
  CHECK_ARG(env, result);
1455

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

746
  if (length > 0) CHECK_ARG(env, str);
1476
744
  CHECK_ARG(env, result);
1477

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

17
  if (length > 0) CHECK_ARG(env, str);
1494
16
  CHECK_ARG(env, result);
1495

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


26
  NAPI_PREAMBLE(env);
1582
13
  CHECK_ARG(env, words);
1583
13
  CHECK_ARG(env, result);
1584
1585
13
  v8::Local<v8::Context> context = env->context();
1586
1587
13
  RETURN_STATUS_IF_FALSE(env, word_count <= INT_MAX, napi_invalid_arg);
1588
1589
  v8::MaybeLocal<v8::BigInt> b =
1590
12
      v8::BigInt::NewFromWords(context, sign_bit, word_count, words);
1591
1592

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

199
  if ((code != nullptr) || (code_cstring != nullptr)) {
1658
118
    v8::Local<v8::Context> context = env->context();
1659
118
    v8::Local<v8::Object> err_object = error.As<v8::Object>();
1660
1661
118
    v8::Local<v8::Value> code_value = v8impl::V8LocalValueFromJsValue(code);
1662
118
    if (code != nullptr) {
1663
6
      code_value = v8impl::V8LocalValueFromJsValue(code);
1664
12
      RETURN_STATUS_IF_FALSE(env, code_value->IsString(), napi_string_expected);
1665
    } else {
1666

336
      CHECK_NEW_FROM_UTF8(env, code_value, code_cstring);
1667
    }
1668
1669
    v8::Local<v8::Name> code_key;
1670
354
    CHECK_NEW_FROM_UTF8(env, code_key, "code");
1671
1672
118
    v8::Maybe<bool> set_maybe = err_object->Set(context, code_key, code_value);
1673

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


230853
  NAPI_PREAMBLE(env);
1873
115424
  CHECK_ARG(env, recv);
1874
115424
  if (argc > 0) {
1875
105381
    CHECK_ARG(env, argv);
1876
  }
1877
1878
115424
  v8::Local<v8::Context> context = env->context();
1879
1880
115424
  v8::Local<v8::Value> v8recv = v8impl::V8LocalValueFromJsValue(recv);
1881
1882
  v8::Local<v8::Function> v8func;
1883

346272
  CHECK_TO_FUNCTION(env, v8func, func);
1884
1885
  auto maybe = v8func->Call(
1886
      context,
1887
      v8recv,
1888
      argc,
1889
115424
      reinterpret_cast<v8::Local<v8::Value>*>(const_cast<napi_value*>(argv)));
1890
1891
115424
  if (try_catch.HasCaught()) {
1892
7
    return napi_set_last_error(env, napi_pending_exception);
1893
  } else {
1894
115417
    if (result != nullptr) {
1895
7
      CHECK_MAYBE_EMPTY(env, maybe, napi_generic_failure);
1896
7
      *result = v8impl::JsValueFromV8LocalValue(maybe.ToLocalChecked());
1897
    }
1898
115417
    return napi_clear_last_error(env);
1899
  }
1900
}
1901
1902
11
napi_status napi_get_global(napi_env env, napi_value* result) {
1903
11
  CHECK_ENV(env);
1904
11
  CHECK_ARG(env, result);
1905
1906
33
  *result = v8impl::JsValueFromV8LocalValue(env->context()->Global());
1907
1908
11
  return napi_clear_last_error(env);
1909
}
1910
1911
12
napi_status napi_throw(napi_env env, napi_value error) {
1912


24
  NAPI_PREAMBLE(env);
1913
12
  CHECK_ARG(env, error);
1914
1915
12
  v8::Isolate* isolate = env->isolate;
1916
1917
12
  isolate->ThrowException(v8impl::V8LocalValueFromJsValue(error));
1918
  // any VM calls after this point and before returning
1919
  // to the javascript invoker will fail
1920
12
  return napi_clear_last_error(env);
1921
}
1922
1923
82
napi_status napi_throw_error(napi_env env, const char* code, const char* msg) {
1924


156
  NAPI_PREAMBLE(env);
1925
1926
74
  v8::Isolate* isolate = env->isolate;
1927
  v8::Local<v8::String> str;
1928

148
  CHECK_NEW_FROM_UTF8(env, str, msg);
1929
1930
74
  v8::Local<v8::Value> error_obj = v8::Exception::Error(str);
1931
74
  STATUS_CALL(set_error_code(env, error_obj, nullptr, code));
1932
1933
74
  isolate->ThrowException(error_obj);
1934
  // any VM calls after this point and before returning
1935
  // to the javascript invoker will fail
1936
74
  return napi_clear_last_error(env);
1937
}
1938
1939
90
napi_status napi_throw_type_error(napi_env env,
1940
                                  const char* code,
1941
                                  const char* msg) {
1942


180
  NAPI_PREAMBLE(env);
1943
1944
90
  v8::Isolate* isolate = env->isolate;
1945
  v8::Local<v8::String> str;
1946

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


44
  NAPI_PREAMBLE(env);
1961
1962
22
  v8::Isolate* isolate = env->isolate;
1963
  v8::Local<v8::String> str;
1964

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


4
  NAPI_PREAMBLE(env);
1979
1980
2
  v8::Isolate* isolate = env->isolate;
1981
  v8::Local<v8::String> str;
1982

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

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


35
  NAPI_PREAMBLE(env);
2307
17
  CHECK_ARG(env, value);
2308
16
  CHECK_ARG(env, result);
2309
2310
15
  v8::Isolate* isolate = env->isolate;
2311
  v8::Local<v8::Boolean> b =
2312
30
      v8impl::V8LocalValueFromJsValue(value)->ToBoolean(isolate);
2313
15
  *result = v8impl::JsValueFromV8LocalValue(b);
2314
15
  return GET_RETURN_STATUS(env);
2315
}
2316
2317
#define GEN_COERCE_FUNCTION(UpperCaseName, MixedCaseName, LowerCaseName)       \
2318
  napi_status napi_coerce_to_##LowerCaseName(                                  \
2319
      napi_env env, napi_value value, napi_value* result) {                    \
2320
    NAPI_PREAMBLE(env);                                                        \
2321
    CHECK_ARG(env, value);                                                     \
2322
    CHECK_ARG(env, result);                                                    \
2323
                                                                               \
2324
    v8::Local<v8::Context> context = env->context();                           \
2325
    v8::Local<v8::MixedCaseName> str;                                          \
2326
                                                                               \
2327
    CHECK_TO_##UpperCaseName(env, context, str, value);                        \
2328
                                                                               \
2329
    *result = v8impl::JsValueFromV8LocalValue(str);                            \
2330
    return GET_RETURN_STATUS(env);                                             \
2331
  }
2332
2333




44
GEN_COERCE_FUNCTION(NUMBER, Number, number)
2334




51
GEN_COERCE_FUNCTION(OBJECT, Object, object)
2335




47
GEN_COERCE_FUNCTION(STRING, String, string)
2336
2337
#undef GEN_COERCE_FUNCTION
2338
2339
1028
napi_status napi_wrap(napi_env env,
2340
                      napi_value js_object,
2341
                      void* native_object,
2342
                      napi_finalize finalize_cb,
2343
                      void* finalize_hint,
2344
                      napi_ref* result) {
2345
1028
  return v8impl::Wrap<v8impl::retrievable>(
2346
1028
      env, js_object, native_object, finalize_cb, finalize_hint, result);
2347
}
2348
2349
27
napi_status napi_unwrap(napi_env env, napi_value obj, void** result) {
2350
27
  return v8impl::Unwrap(env, obj, result, v8impl::KeepWrap);
2351
}
2352
2353
8
napi_status napi_remove_wrap(napi_env env, napi_value obj, void** result) {
2354
8
  return v8impl::Unwrap(env, obj, result, v8impl::RemoveWrap);
2355
}
2356
2357
7
napi_status napi_create_external(napi_env env,
2358
                                 void* data,
2359
                                 napi_finalize finalize_cb,
2360
                                 void* finalize_hint,
2361
                                 napi_value* result) {
2362


14
  NAPI_PREAMBLE(env);
2363
7
  CHECK_ARG(env, result);
2364
2365
7
  v8::Isolate* isolate = env->isolate;
2366
2367
7
  v8::Local<v8::Value> external_value = v8::External::New(isolate, data);
2368
2369
  // The Reference object will delete itself after invoking the finalizer
2370
  // callback.
2371
7
  v8impl::Reference::New(
2372
      env, external_value, 0, true, finalize_cb, data, finalize_hint);
2373
2374
7
  *result = v8impl::JsValueFromV8LocalValue(external_value);
2375
2376
7
  return napi_clear_last_error(env);
2377
}
2378
2379
2
NAPI_EXTERN napi_status napi_type_tag_object(napi_env env,
2380
                                             napi_value object,
2381
                                             const napi_type_tag* type_tag) {
2382


4
  NAPI_PREAMBLE(env);
2383
2
  v8::Local<v8::Context> context = env->context();
2384
  v8::Local<v8::Object> obj;
2385


4
  CHECK_TO_OBJECT_WITH_PREAMBLE(env, context, obj, object);
2386

2
  CHECK_ARG_WITH_PREAMBLE(env, type_tag);
2387
2388
2
  auto key = NAPI_PRIVATE_KEY(context, type_tag);
2389
2
  auto maybe_has = obj->HasPrivate(context, key);
2390

2
  CHECK_MAYBE_NOTHING_WITH_PREAMBLE(env, maybe_has, napi_generic_failure);
2391

2
  RETURN_STATUS_IF_FALSE_WITH_PREAMBLE(
2392
      env, !maybe_has.FromJust(), napi_invalid_arg);
2393
2394
  auto tag = v8::BigInt::NewFromWords(
2395
2
      context, 0, 2, reinterpret_cast<const uint64_t*>(type_tag));
2396

2
  CHECK_MAYBE_EMPTY_WITH_PREAMBLE(env, tag, napi_generic_failure);
2397
2398
4
  auto maybe_set = obj->SetPrivate(context, key, tag.ToLocalChecked());
2399

2
  CHECK_MAYBE_NOTHING_WITH_PREAMBLE(env, maybe_set, napi_generic_failure);
2400

2
  RETURN_STATUS_IF_FALSE_WITH_PREAMBLE(
2401
      env, maybe_set.FromJust(), napi_generic_failure);
2402
2403
2
  return GET_RETURN_STATUS(env);
2404
}
2405
2406
NAPI_EXTERN napi_status
2407
6
napi_check_object_type_tag(napi_env env,
2408
                           napi_value object,
2409
                           const napi_type_tag* type_tag,
2410
                           bool* result) {
2411


12
  NAPI_PREAMBLE(env);
2412
6
  v8::Local<v8::Context> context = env->context();
2413
  v8::Local<v8::Object> obj;
2414


12
  CHECK_TO_OBJECT_WITH_PREAMBLE(env, context, obj, object);
2415

6
  CHECK_ARG_WITH_PREAMBLE(env, type_tag);
2416

6
  CHECK_ARG_WITH_PREAMBLE(env, result);
2417
2418
  auto maybe_value =
2419
6
      obj->GetPrivate(context, NAPI_PRIVATE_KEY(context, type_tag));
2420

6
  CHECK_MAYBE_EMPTY_WITH_PREAMBLE(env, maybe_value, napi_generic_failure);
2421
6
  v8::Local<v8::Value> val = maybe_value.ToLocalChecked();
2422
2423
  // We consider the type check to have failed unless we reach the line below
2424
  // where we set whether the type check succeeded or not based on the
2425
  // comparison of the two type tags.
2426
6
  *result = false;
2427
6
  if (val->IsBigInt()) {
2428
    int sign;
2429
4
    int size = 2;
2430
    napi_type_tag tag;
2431
4
    val.As<v8::BigInt>()->ToWordsArray(
2432
        &sign, &size, reinterpret_cast<uint64_t*>(&tag));
2433

4
    if (size == 2 && sign == 0)
2434

4
      *result = (tag.lower == type_tag->lower && tag.upper == type_tag->upper);
2435
  }
2436
2437
6
  return GET_RETURN_STATUS(env);
2438
}
2439
2440
2
napi_status napi_get_value_external(napi_env env,
2441
                                    napi_value value,
2442
                                    void** result) {
2443
2
  CHECK_ENV(env);
2444
2
  CHECK_ARG(env, value);
2445
2
  CHECK_ARG(env, result);
2446
2447
2
  v8::Local<v8::Value> val = v8impl::V8LocalValueFromJsValue(value);
2448
2
  RETURN_STATUS_IF_FALSE(env, val->IsExternal(), napi_invalid_arg);
2449
2450
2
  v8::Local<v8::External> external_value = val.As<v8::External>();
2451
2
  *result = external_value->Value();
2452
2453
2
  return napi_clear_last_error(env);
2454
}
2455
2456
// Set initial_refcount to 0 for a weak reference, >0 for a strong reference.
2457
1543
napi_status napi_create_reference(napi_env env,
2458
                                  napi_value value,
2459
                                  uint32_t initial_refcount,
2460
                                  napi_ref* result) {
2461
  // Omit NAPI_PREAMBLE and GET_RETURN_STATUS because V8 calls here cannot throw
2462
  // JS exceptions.
2463
1543
  CHECK_ENV(env);
2464
1543
  CHECK_ARG(env, value);
2465
1543
  CHECK_ARG(env, result);
2466
2467
1543
  v8::Local<v8::Value> v8_value = v8impl::V8LocalValueFromJsValue(value);
2468

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


22
  NAPI_PREAMBLE(env);
2638
11
  CHECK_ARG(env, constructor);
2639
11
  if (argc > 0) {
2640
7
    CHECK_ARG(env, argv);
2641
  }
2642
11
  CHECK_ARG(env, result);
2643
2644
11
  v8::Local<v8::Context> context = env->context();
2645
2646
  v8::Local<v8::Function> ctor;
2647

33
  CHECK_TO_FUNCTION(env, ctor, constructor);
2648
2649
  auto maybe = ctor->NewInstance(
2650
      context,
2651
      argc,
2652
11
      reinterpret_cast<v8::Local<v8::Value>*>(const_cast<napi_value*>(argv)));
2653
2654
11
  CHECK_MAYBE_EMPTY(env, maybe, napi_pending_exception);
2655
2656
9
  *result = v8impl::JsValueFromV8LocalValue(maybe.ToLocalChecked());
2657
9
  return GET_RETURN_STATUS(env);
2658
}
2659
2660
2278
napi_status napi_instanceof(napi_env env,
2661
                            napi_value object,
2662
                            napi_value constructor,
2663
                            bool* result) {
2664


4556
  NAPI_PREAMBLE(env);
2665
2278
  CHECK_ARG(env, object);
2666
2278
  CHECK_ARG(env, result);
2667
2668
2278
  *result = false;
2669
2670
  v8::Local<v8::Object> ctor;
2671
2278
  v8::Local<v8::Context> context = env->context();
2672
2673

6834
  CHECK_TO_OBJECT(env, context, ctor, constructor);
2674
2675
2278
  if (!ctor->IsFunction()) {
2676
88
    napi_throw_type_error(
2677
        env, "ERR_NAPI_CONS_FUNCTION", "Constructor must be a function");
2678
2679
88
    return napi_set_last_error(env, napi_function_expected);
2680
  }
2681
2682
2190
  napi_status status = napi_generic_failure;
2683
2684
2190
  v8::Local<v8::Value> val = v8impl::V8LocalValueFromJsValue(object);
2685
2190
  auto maybe_result = val->InstanceOf(context, ctor);
2686
2190
  CHECK_MAYBE_NOTHING(env, maybe_result, status);
2687
1166
  *result = maybe_result.FromJust();
2688
1166
  return GET_RETURN_STATUS(env);
2689
}
2690
2691
// Methods to support catching exceptions
2692
1234
napi_status napi_is_exception_pending(napi_env env, bool* result) {
2693
  // NAPI_PREAMBLE is not used here: this function must execute when there is a
2694
  // pending exception.
2695
1234
  CHECK_ENV(env);
2696
1234
  CHECK_ARG(env, result);
2697
2698
1234
  *result = !env->last_exception.IsEmpty();
2699
1234
  return napi_clear_last_error(env);
2700
}
2701
2702
2
napi_status napi_get_and_clear_last_exception(napi_env env,
2703
                                              napi_value* result) {
2704
  // NAPI_PREAMBLE is not used here: this function must execute when there is a
2705
  // pending exception.
2706
2
  CHECK_ENV(env);
2707
2
  CHECK_ARG(env, result);
2708
2709
2
  if (env->last_exception.IsEmpty()) {
2710
    return napi_get_undefined(env, result);
2711
  } else {
2712
2
    *result = v8impl::JsValueFromV8LocalValue(
2713
2
        v8::Local<v8::Value>::New(env->isolate, env->last_exception));
2714
2
    env->last_exception.Reset();
2715
  }
2716
2717
2
  return napi_clear_last_error(env);
2718
}
2719
2720
57
napi_status napi_is_arraybuffer(napi_env env, napi_value value, bool* result) {
2721
57
  CHECK_ENV(env);
2722
57
  CHECK_ARG(env, value);
2723
57
  CHECK_ARG(env, result);
2724
2725
57
  v8::Local<v8::Value> val = v8impl::V8LocalValueFromJsValue(value);
2726
57
  *result = val->IsArrayBuffer();
2727
2728
57
  return napi_clear_last_error(env);
2729
}
2730
2731
2
napi_status napi_create_arraybuffer(napi_env env,
2732
                                    size_t byte_length,
2733
                                    void** data,
2734
                                    napi_value* result) {
2735


4
  NAPI_PREAMBLE(env);
2736
2
  CHECK_ARG(env, result);
2737
2738
2
  v8::Isolate* isolate = env->isolate;
2739
  v8::Local<v8::ArrayBuffer> buffer =
2740
2
      v8::ArrayBuffer::New(isolate, byte_length);
2741
2742
  // Optionally return a pointer to the buffer's data, to avoid another call to
2743
  // retrieve it.
2744
2
  if (data != nullptr) {
2745
2
    *data = buffer->GetBackingStore()->Data();
2746
  }
2747
2748
2
  *result = v8impl::JsValueFromV8LocalValue(buffer);
2749
2
  return GET_RETURN_STATUS(env);
2750
}
2751
2752
6
napi_status napi_create_external_arraybuffer(napi_env env,
2753
                                             void* external_data,
2754
                                             size_t byte_length,
2755
                                             napi_finalize finalize_cb,
2756
                                             void* finalize_hint,
2757
                                             napi_value* result) {
2758
  // The API contract here is that the cleanup function runs on the JS thread,
2759
  // and is able to use napi_env. Implementing that properly is hard, so use the
2760
  // `Buffer` variant for easier implementation.
2761
  napi_value buffer;
2762
6
  STATUS_CALL(napi_create_external_buffer(
2763
      env, byte_length, external_data, finalize_cb, finalize_hint, &buffer));
2764
6
  return napi_get_typedarray_info(
2765
6
      env, buffer, nullptr, nullptr, nullptr, result, nullptr);
2766
}
2767
2768
2
napi_status napi_get_arraybuffer_info(napi_env env,
2769
                                      napi_value arraybuffer,
2770
                                      void** data,
2771
                                      size_t* byte_length) {
2772
2
  CHECK_ENV(env);
2773
2
  CHECK_ARG(env, arraybuffer);
2774
2775
2
  v8::Local<v8::Value> value = v8impl::V8LocalValueFromJsValue(arraybuffer);
2776
2
  RETURN_STATUS_IF_FALSE(env, value->IsArrayBuffer(), napi_invalid_arg);
2777
2778
  std::shared_ptr<v8::BackingStore> backing_store =
2779
4
      value.As<v8::ArrayBuffer>()->GetBackingStore();
2780
2781
2
  if (data != nullptr) {
2782
2
    *data = backing_store->Data();
2783
  }
2784
2785
2
  if (byte_length != nullptr) {
2786
2
    *byte_length = backing_store->ByteLength();
2787
  }
2788
2789
2
  return napi_clear_last_error(env);
2790
}
2791
2792
44
napi_status napi_is_typedarray(napi_env env, napi_value value, bool* result) {
2793
44
  CHECK_ENV(env);
2794
44
  CHECK_ARG(env, value);
2795
44
  CHECK_ARG(env, result);
2796
2797
44
  v8::Local<v8::Value> val = v8impl::V8LocalValueFromJsValue(value);
2798
44
  *result = val->IsTypedArray();
2799
2800
44
  return napi_clear_last_error(env);
2801
}
2802
2803
34
napi_status napi_create_typedarray(napi_env env,
2804
                                   napi_typedarray_type type,
2805
                                   size_t length,
2806
                                   napi_value arraybuffer,
2807
                                   size_t byte_offset,
2808
                                   napi_value* result) {
2809


68
  NAPI_PREAMBLE(env);
2810
34
  CHECK_ARG(env, arraybuffer);
2811
34
  CHECK_ARG(env, result);
2812
2813
34
  v8::Local<v8::Value> value = v8impl::V8LocalValueFromJsValue(arraybuffer);
2814
34
  RETURN_STATUS_IF_FALSE(env, value->IsArrayBuffer(), napi_invalid_arg);
2815
2816



34
  v8::Local<v8::ArrayBuffer> buffer = value.As<v8::ArrayBuffer>();
2817
  v8::Local<v8::TypedArray> typedArray;
2818
2819



34
  switch (type) {
2820
4
    case napi_int8_array:
2821
4
      CREATE_TYPED_ARRAY(
2822
          env, Int8Array, 1, buffer, byte_offset, length, typedArray);
2823
3
      break;
2824
3
    case napi_uint8_array:
2825
3
      CREATE_TYPED_ARRAY(
2826
          env, Uint8Array, 1, buffer, byte_offset, length, typedArray);
2827
2
      break;
2828
2
    case napi_uint8_clamped_array:
2829
2
      CREATE_TYPED_ARRAY(
2830
          env, Uint8ClampedArray, 1, buffer, byte_offset, length, typedArray);
2831
1
      break;
2832
3
    case napi_int16_array:
2833

3
      CREATE_TYPED_ARRAY(
2834
          env, Int16Array, 2, buffer, byte_offset, length, typedArray);
2835
1
      break;
2836
3
    case napi_uint16_array:
2837

3
      CREATE_TYPED_ARRAY(
2838
          env, Uint16Array, 2, buffer, byte_offset, length, typedArray);
2839
1
      break;
2840
3
    case napi_int32_array:
2841

3
      CREATE_TYPED_ARRAY(
2842
          env, Int32Array, 4, buffer, byte_offset, length, typedArray);
2843
1
      break;
2844
3
    case napi_uint32_array:
2845

3
      CREATE_TYPED_ARRAY(
2846
          env, Uint32Array, 4, buffer, byte_offset, length, typedArray);
2847
1
      break;
2848
3
    case napi_float32_array:
2849

3
      CREATE_TYPED_ARRAY(
2850
          env, Float32Array, 4, buffer, byte_offset, length, typedArray);
2851
1
      break;
2852
4
    case napi_float64_array:
2853

4
      CREATE_TYPED_ARRAY(
2854
          env, Float64Array, 8, buffer, byte_offset, length, typedArray);
2855
2
      break;
2856
3
    case napi_bigint64_array:
2857

3
      CREATE_TYPED_ARRAY(
2858
          env, BigInt64Array, 8, buffer, byte_offset, length, typedArray);
2859
1
      break;
2860
3
    case napi_biguint64_array:
2861

3
      CREATE_TYPED_ARRAY(
2862
          env, BigUint64Array, 8, buffer, byte_offset, length, typedArray);
2863
1
      break;
2864
    default:
2865
      return napi_set_last_error(env, napi_invalid_arg);
2866
  }
2867
2868
15
  *result = v8impl::JsValueFromV8LocalValue(typedArray);
2869
15
  return GET_RETURN_STATUS(env);
2870
}
2871
2872
50
napi_status napi_get_typedarray_info(napi_env env,
2873
                                     napi_value typedarray,
2874
                                     napi_typedarray_type* type,
2875
                                     size_t* length,
2876
                                     void** data,
2877
                                     napi_value* arraybuffer,
2878
                                     size_t* byte_offset) {
2879
50
  CHECK_ENV(env);
2880
50
  CHECK_ARG(env, typedarray);
2881
2882
50
  v8::Local<v8::Value> value = v8impl::V8LocalValueFromJsValue(typedarray);
2883
50
  RETURN_STATUS_IF_FALSE(env, value->IsTypedArray(), napi_invalid_arg);
2884
2885
50
  v8::Local<v8::TypedArray> array = value.As<v8::TypedArray>();
2886
2887
50
  if (type != nullptr) {
2888
32
    if (value->IsInt8Array()) {
2889
2
      *type = napi_int8_array;
2890
30
    } else if (value->IsUint8Array()) {
2891
3
      *type = napi_uint8_array;
2892
27
    } else if (value->IsUint8ClampedArray()) {
2893
2
      *type = napi_uint8_clamped_array;
2894
25
    } else if (value->IsInt16Array()) {
2895
3
      *type = napi_int16_array;
2896
22
    } else if (value->IsUint16Array()) {
2897
3
      *type = napi_uint16_array;
2898
19
    } else if (value->IsInt32Array()) {
2899
3
      *type = napi_int32_array;
2900
16
    } else if (value->IsUint32Array()) {
2901
3
      *type = napi_uint32_array;
2902
13
    } else if (value->IsFloat32Array()) {
2903
3
      *type = napi_float32_array;
2904
10
    } else if (value->IsFloat64Array()) {
2905
4
      *type = napi_float64_array;
2906
6
    } else if (value->IsBigInt64Array()) {
2907
3
      *type = napi_bigint64_array;
2908
3
    } else if (value->IsBigUint64Array()) {
2909
3
      *type = napi_biguint64_array;
2910
    }
2911
  }
2912
2913
50
  if (length != nullptr) {
2914
32
    *length = array->Length();
2915
  }
2916
2917
  v8::Local<v8::ArrayBuffer> buffer;
2918

50
  if (data != nullptr || arraybuffer != nullptr) {
2919
    // Calling Buffer() may have the side effect of allocating the buffer,
2920
    // so only do this when it’s needed.
2921
50
    buffer = array->Buffer();
2922
  }
2923
2924
50
  if (data != nullptr) {
2925
    *data = static_cast<uint8_t*>(buffer->GetBackingStore()->Data()) +
2926
            array->ByteOffset();
2927
  }
2928
2929
50
  if (arraybuffer != nullptr) {
2930
50
    *arraybuffer = v8impl::JsValueFromV8LocalValue(buffer);
2931
  }
2932
2933
50
  if (byte_offset != nullptr) {
2934
32
    *byte_offset = array->ByteOffset();
2935
  }
2936
2937
50
  return napi_clear_last_error(env);
2938
}
2939
2940
2
napi_status napi_create_dataview(napi_env env,
2941
                                 size_t byte_length,
2942
                                 napi_value arraybuffer,
2943
                                 size_t byte_offset,
2944
                                 napi_value* result) {
2945


4
  NAPI_PREAMBLE(env);
2946
2
  CHECK_ARG(env, arraybuffer);
2947
2
  CHECK_ARG(env, result);
2948
2949
2
  v8::Local<v8::Value> value = v8impl::V8LocalValueFromJsValue(arraybuffer);
2950
2
  RETURN_STATUS_IF_FALSE(env, value->IsArrayBuffer(), napi_invalid_arg);
2951
2952
2
  v8::Local<v8::ArrayBuffer> buffer = value.As<v8::ArrayBuffer>();
2953
2
  if (byte_length + byte_offset > buffer->ByteLength()) {
2954
1
    napi_throw_range_error(env,
2955
                           "ERR_NAPI_INVALID_DATAVIEW_ARGS",
2956
                           "byte_offset + byte_length should be less than or "
2957
                           "equal to the size in bytes of the array passed in");
2958
1
    return napi_set_last_error(env, napi_pending_exception);
2959
  }
2960
  v8::Local<v8::DataView> DataView =
2961
1
      v8::DataView::New(buffer, byte_offset, byte_length);
2962
2963
1
  *result = v8impl::JsValueFromV8LocalValue(DataView);
2964
1
  return GET_RETURN_STATUS(env);
2965
}
2966
2967
1
napi_status napi_is_dataview(napi_env env, napi_value value, bool* result) {
2968
1
  CHECK_ENV(env);
2969
1
  CHECK_ARG(env, value);
2970
1
  CHECK_ARG(env, result);
2971
2972
1
  v8::Local<v8::Value> val = v8impl::V8LocalValueFromJsValue(value);
2973
1
  *result = val->IsDataView();
2974
2975
1
  return napi_clear_last_error(env);
2976
}
2977
2978
1
napi_status napi_get_dataview_info(napi_env env,
2979
                                   napi_value dataview,
2980
                                   size_t* byte_length,
2981
                                   void** data,
2982
                                   napi_value* arraybuffer,
2983
                                   size_t* byte_offset) {
2984
1
  CHECK_ENV(env);
2985
1
  CHECK_ARG(env, dataview);
2986
2987
1
  v8::Local<v8::Value> value = v8impl::V8LocalValueFromJsValue(dataview);
2988
1
  RETURN_STATUS_IF_FALSE(env, value->IsDataView(), napi_invalid_arg);
2989
2990
1
  v8::Local<v8::DataView> array = value.As<v8::DataView>();
2991
2992
1
  if (byte_length != nullptr) {
2993
1
    *byte_length = array->ByteLength();
2994
  }
2995
2996
  v8::Local<v8::ArrayBuffer> buffer;
2997

1
  if (data != nullptr || arraybuffer != nullptr) {
2998
    // Calling Buffer() may have the side effect of allocating the buffer,
2999
    // so only do this when it’s needed.
3000
1
    buffer = array->Buffer();
3001
  }
3002
3003
1
  if (data != nullptr) {
3004
    *data = static_cast<uint8_t*>(buffer->GetBackingStore()->Data()) +
3005
            array->ByteOffset();
3006
  }
3007
3008
1
  if (arraybuffer != nullptr) {
3009
1
    *arraybuffer = v8impl::JsValueFromV8LocalValue(buffer);
3010
  }
3011
3012
1
  if (byte_offset != nullptr) {
3013
1
    *byte_offset = array->ByteOffset();
3014
  }
3015
3016
1
  return napi_clear_last_error(env);
3017
}
3018
3019
1
napi_status napi_get_version(napi_env env, uint32_t* result) {
3020
1
  CHECK_ENV(env);
3021
1
  CHECK_ARG(env, result);
3022
1
  *result = NAPI_VERSION;
3023
1
  return napi_clear_last_error(env);
3024
}
3025
3026
5
napi_status napi_create_promise(napi_env env,
3027
                                napi_deferred* deferred,
3028
                                napi_value* promise) {
3029


10
  NAPI_PREAMBLE(env);
3030
5
  CHECK_ARG(env, deferred);
3031
5
  CHECK_ARG(env, promise);
3032
3033
5
  auto maybe = v8::Promise::Resolver::New(env->context());
3034
5
  CHECK_MAYBE_EMPTY(env, maybe, napi_generic_failure);
3035
3036
5
  auto v8_resolver = maybe.ToLocalChecked();
3037
5
  auto v8_deferred = new v8impl::Persistent<v8::Value>();
3038
5
  v8_deferred->Reset(env->isolate, v8_resolver);
3039
3040
5
  *deferred = v8impl::JsDeferredFromNodePersistent(v8_deferred);
3041
10
  *promise = v8impl::JsValueFromV8LocalValue(v8_resolver->GetPromise());
3042
5
  return GET_RETURN_STATUS(env);
3043
}
3044
3045
4
napi_status napi_resolve_deferred(napi_env env,
3046
                                  napi_deferred deferred,
3047
                                  napi_value resolution) {
3048
4
  return v8impl::ConcludeDeferred(env, deferred, resolution, true);
3049
}
3050
3051
1
napi_status napi_reject_deferred(napi_env env,
3052
                                 napi_deferred deferred,
3053
                                 napi_value resolution) {
3054
1
  return v8impl::ConcludeDeferred(env, deferred, resolution, false);
3055
}
3056
3057
7
napi_status napi_is_promise(napi_env env, napi_value value, bool* is_promise) {
3058
7
  CHECK_ENV(env);
3059
7
  CHECK_ARG(env, value);
3060
7
  CHECK_ARG(env, is_promise);
3061
3062
14
  *is_promise = v8impl::V8LocalValueFromJsValue(value)->IsPromise();
3063
3064
7
  return napi_clear_last_error(env);
3065
}
3066
3067
1
napi_status napi_create_date(napi_env env, double time, napi_value* result) {
3068


2
  NAPI_PREAMBLE(env);
3069
1
  CHECK_ARG(env, result);
3070
3071
1
  v8::MaybeLocal<v8::Value> maybe_date = v8::Date::New(env->context(), time);
3072
1
  CHECK_MAYBE_EMPTY(env, maybe_date, napi_generic_failure);
3073
3074
1
  *result = v8impl::JsValueFromV8LocalValue(maybe_date.ToLocalChecked());
3075
3076
1
  return GET_RETURN_STATUS(env);
3077
}
3078
3079
7
napi_status napi_is_date(napi_env env, napi_value value, bool* is_date) {
3080
7
  CHECK_ENV(env);
3081
7
  CHECK_ARG(env, value);
3082
7
  CHECK_ARG(env, is_date);
3083
3084
14
  *is_date = v8impl::V8LocalValueFromJsValue(value)->IsDate();
3085
3086
7
  return napi_clear_last_error(env);
3087
}
3088
3089
1
napi_status napi_get_date_value(napi_env env,
3090
                                napi_value value,
3091
                                double* result) {
3092


2
  NAPI_PREAMBLE(env);
3093
1
  CHECK_ARG(env, value);
3094
1
  CHECK_ARG(env, result);
3095
3096
1
  v8::Local<v8::Value> val = v8impl::V8LocalValueFromJsValue(value);
3097
1
  RETURN_STATUS_IF_FALSE(env, val->IsDate(), napi_date_expected);
3098
3099
1
  v8::Local<v8::Date> date = val.As<v8::Date>();
3100
1
  *result = date->ValueOf();
3101
3102
1
  return GET_RETURN_STATUS(env);
3103
}
3104
3105
2
napi_status napi_run_script(napi_env env,
3106
                            napi_value script,
3107
                            napi_value* result) {
3108


4
  NAPI_PREAMBLE(env);
3109
2
  CHECK_ARG(env, script);
3110
2
  CHECK_ARG(env, result);
3111
3112
2
  v8::Local<v8::Value> v8_script = v8impl::V8LocalValueFromJsValue(script);
3113
3114
4
  if (!v8_script->IsString()) {
3115
1
    return napi_set_last_error(env, napi_string_expected);
3116
  }
3117
3118
1
  v8::Local<v8::Context> context = env->context();
3119
3120
1
  auto maybe_script = v8::Script::Compile(context, v8_script.As<v8::String>());
3121
1
  CHECK_MAYBE_EMPTY(env, maybe_script, napi_generic_failure);
3122
3123
1
  auto script_result = maybe_script.ToLocalChecked()->Run(context);
3124
1
  CHECK_MAYBE_EMPTY(env, script_result, napi_generic_failure);
3125
3126
1
  *result = v8impl::JsValueFromV8LocalValue(script_result.ToLocalChecked());
3127
1
  return GET_RETURN_STATUS(env);
3128
}
3129
3130
4
napi_status napi_add_finalizer(napi_env env,
3131
                               napi_value js_object,
3132
                               void* native_object,
3133
                               napi_finalize finalize_cb,
3134
                               void* finalize_hint,
3135
                               napi_ref* result) {
3136
4
  return v8impl::Wrap<v8impl::anonymous>(
3137
4
      env, js_object, native_object, finalize_cb, finalize_hint, result);
3138
}
3139
3140
1
napi_status napi_adjust_external_memory(napi_env env,
3141
                                        int64_t change_in_bytes,
3142
                                        int64_t* adjusted_value) {
3143
1
  CHECK_ENV(env);
3144
1
  CHECK_ARG(env, adjusted_value);
3145
3146
2
  *adjusted_value =
3147
1
      env->isolate->AdjustAmountOfExternalAllocatedMemory(change_in_bytes);
3148
3149
1
  return napi_clear_last_error(env);
3150
}
3151
3152
7
napi_status napi_set_instance_data(napi_env env,
3153
                                   void* data,
3154
                                   napi_finalize finalize_cb,
3155
                                   void* finalize_hint) {
3156
7
  CHECK_ENV(env);
3157
3158
7
  v8impl::RefBase* old_data = static_cast<v8impl::RefBase*>(env->instance_data);
3159
7
  if (old_data != nullptr) {
3160
    // Our contract so far has been to not finalize any old data there may be.
3161
    // So we simply delete it.
3162
    v8impl::RefBase::Delete(old_data);
3163
  }
3164
3165
14
  env->instance_data =
3166
7
      v8impl::RefBase::New(env, 0, true, finalize_cb, data, finalize_hint);
3167
3168
7
  return napi_clear_last_error(env);
3169
}
3170
3171
22
napi_status napi_get_instance_data(napi_env env, void** data) {
3172
22
  CHECK_ENV(env);
3173
22
  CHECK_ARG(env, data);
3174
3175
22
  v8impl::RefBase* idata = static_cast<v8impl::RefBase*>(env->instance_data);
3176
3177
22
  *data = (idata == nullptr ? nullptr : idata->Data());
3178
3179
22
  return napi_clear_last_error(env);
3180
}
3181
3182
12
napi_status napi_detach_arraybuffer(napi_env env, napi_value arraybuffer) {
3183
12
  CHECK_ENV(env);
3184
12
  CHECK_ARG(env, arraybuffer);
3185
3186
12
  v8::Local<v8::Value> value = v8impl::V8LocalValueFromJsValue(arraybuffer);
3187
12
  RETURN_STATUS_IF_FALSE(
3188
      env, value->IsArrayBuffer(), napi_arraybuffer_expected);
3189
3190
12
  v8::Local<v8::ArrayBuffer> it = value.As<v8::ArrayBuffer>();
3191
12
  RETURN_STATUS_IF_FALSE(
3192
      env, it->IsDetachable(), napi_detachable_arraybuffer_expected);
3193
3194
12
  it->Detach();
3195
3196
12
  return napi_clear_last_error(env);
3197
}
3198
3199
26
napi_status napi_is_detached_arraybuffer(napi_env env,
3200
                                         napi_value arraybuffer,
3201
                                         bool* result) {
3202
26
  CHECK_ENV(env);
3203
26
  CHECK_ARG(env, arraybuffer);
3204
26
  CHECK_ARG(env, result);
3205
3206
26
  v8::Local<v8::Value> value = v8impl::V8LocalValueFromJsValue(arraybuffer);
3207
3208

52
  *result = value->IsArrayBuffer() &&
3209
52
            value.As<v8::ArrayBuffer>()->GetBackingStore()->Data() == nullptr;
3210
3211
26
  return napi_clear_last_error(env);
3212
}