GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: js_native_api_v8.cc Lines: 1429 1459 97.9 %
Date: 2022-11-05 03:21:31 Branches: 1147 1786 64.2 %

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

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

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


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

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


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

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


4132
  NAPI_PREAMBLE(env);
405
2066
  CHECK_ARG(env, js_object);
406
407
2066
  v8::Local<v8::Context> context = env->context();
408
409
2066
  v8::Local<v8::Value> value = v8impl::V8LocalValueFromJsValue(js_object);
410
2066
  RETURN_STATUS_IF_FALSE(env, value->IsObject(), napi_invalid_arg);
411
2066
  v8::Local<v8::Object> obj = value.As<v8::Object>();
412
413
  if (wrap_type == retrievable) {
414
    // If we've already wrapped this object, we error out.
415
4116
    RETURN_STATUS_IF_FALSE(
416
        env,
417
        !obj->HasPrivate(context, NAPI_PRIVATE_KEY(context, wrapper))
418
             .FromJust(),
419
        napi_invalid_arg);
420
  } else if (wrap_type == anonymous) {
421
    // If no finalize callback is provided, we error out.
422
8
    CHECK_ARG(env, finalize_cb);
423
  }
424
425
2064
  v8impl::Reference* reference = nullptr;
426
2064
  if (result != nullptr) {
427
    // The returned reference should be deleted via napi_delete_reference()
428
    // ONLY in response to the finalize callback invocation. (If it is deleted
429
    // before then, then the finalize callback will never be invoked.)
430
    // Therefore a finalize callback is required when returning a reference.
431
26
    CHECK_ARG(env, finalize_cb);
432
26
    reference = v8impl::Reference::New(
433
        env, obj, 0, false, finalize_cb, native_object, finalize_hint);
434
26
    *result = reinterpret_cast<napi_ref>(reference);
435
  } else {
436
    // Create a self-deleting reference.
437
2038
    reference = v8impl::Reference::New(
438
        env,
439
        obj,
440
        0,
441
        true,
442
        finalize_cb,
443
        native_object,
444
2038
        finalize_cb == nullptr ? nullptr : finalize_hint);
445
  }
446
447
  if (wrap_type == retrievable) {
448
6168
    CHECK(obj->SetPrivate(context,
449
                          NAPI_PRIVATE_KEY(context, wrapper),
450
                          v8::External::New(env->isolate, reference))
451
              .FromJust());
452
  }
453
454
2064
  return GET_RETURN_STATUS(env);
455
}
456
457
}  // end of anonymous namespace
458
459
// Wrapper around v8impl::Persistent that implements reference counting.
460
3135
RefBase::RefBase(napi_env env,
461
                 uint32_t initial_refcount,
462
                 bool delete_self,
463
                 napi_finalize finalize_callback,
464
                 void* finalize_data,
465
3135
                 void* finalize_hint)
466
    : Finalizer(env, finalize_callback, finalize_data, finalize_hint),
467
      _refcount(initial_refcount),
468
3135
      _delete_self(delete_self) {
469
3135
  Link(finalize_callback == nullptr ? &env->reflist : &env->finalizing_reflist);
470
3135
}
471
472
7
RefBase* RefBase::New(napi_env env,
473
                      uint32_t initial_refcount,
474
                      bool delete_self,
475
                      napi_finalize finalize_callback,
476
                      void* finalize_data,
477
                      void* finalize_hint) {
478
  return new RefBase(env,
479
                     initial_refcount,
480
                     delete_self,
481
                     finalize_callback,
482
                     finalize_data,
483
7
                     finalize_hint);
484
}
485
486
6264
RefBase::~RefBase() {
487
6250
  Unlink();
488
6264
}
489
490
57
void* RefBase::Data() {
491
57
  return _finalize_data;
492
}
493
494
// Delete is called in 2 ways. Either from the finalizer or
495
// from one of Unwrap or napi_delete_reference.
496
//
497
// When it is called from Unwrap or napi_delete_reference we only
498
// want to do the delete if the finalizer has already run or
499
// cannot have been queued to run (ie the reference count is > 0),
500
// otherwise we may crash when the finalizer does run.
501
// If the finalizer may have been queued and has not already run
502
// delay the delete until the finalizer runs by not doing the delete
503
// and setting _delete_self to true so that the finalizer will
504
// delete it when it runs.
505
//
506
// The second way this is called is from
507
// the finalizer and _delete_self is set. In this case we
508
// know we need to do the deletion so just do it.
509
3143
void RefBase::Delete(RefBase* reference) {
510

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

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

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

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


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


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


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


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

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


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

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

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


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

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

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


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

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


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

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


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

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

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


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

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


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

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

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

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


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

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

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


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

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

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


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

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

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


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

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


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

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


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

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

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


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

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

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

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

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

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


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

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

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


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

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

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


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


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


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

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

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

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

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

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

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

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


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

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

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

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

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


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

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


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


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

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


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

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


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

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


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

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

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


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




44
GEN_COERCE_FUNCTION(NUMBER, Number, number)
2351




51
GEN_COERCE_FUNCTION(OBJECT, Object, object)
2352




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


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


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


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

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

4
  CHECK_MAYBE_NOTHING_WITH_PREAMBLE(env, maybe_has, napi_generic_failure);
2414

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

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

4
  CHECK_MAYBE_NOTHING_WITH_PREAMBLE(env, maybe_set, napi_generic_failure);
2423

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


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


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

13
  CHECK_ARG_WITH_PREAMBLE(env, type_tag);
2438

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

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

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

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

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

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


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

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


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

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


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


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



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



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

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

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

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

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

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

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

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

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

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


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

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


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


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


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


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

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