GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: js_native_api_v8.cc Lines: 1429 1459 97.9 %
Date: 2022-11-20 04:28:36 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
4683
  inline CallbackWrapper(napi_value this_arg, size_t args_length, void* data)
267
4683
      : _this(this_arg), _args_length(args_length), _data(data) {}
268
269
  virtual napi_value GetNewTarget() = 0;
270
  virtual void Args(napi_value* buffer, size_t bufferlength) = 0;
271
  virtual void SetReturnValue(napi_value value) = 0;
272
273
42
  napi_value This() { return _this; }
274
275
4505
  size_t ArgsLength() { return _args_length; }
276
277
6
  void* Data() { return _data; }
278
279
 protected:
280
  const napi_value _this;
281
  const size_t _args_length;
282
  void* _data;
283
};
284
285
class CallbackWrapperBase : public CallbackWrapper {
286
 public:
287
4683
  inline CallbackWrapperBase(const v8::FunctionCallbackInfo<v8::Value>& cbinfo,
288
                             const size_t args_length)
289
4683
      : CallbackWrapper(
290
            JsValueFromV8LocalValue(cbinfo.This()), args_length, nullptr),
291
9366
        _cbinfo(cbinfo) {
292
4683
    _bundle = reinterpret_cast<CallbackBundle*>(
293
9366
        cbinfo.Data().As<v8::External>()->Value());
294
4683
    _data = _bundle->cb_data;
295
4683
  }
296
297
 protected:
298
4683
  inline void InvokeCallback() {
299
4683
    napi_callback_info cbinfo_wrapper = reinterpret_cast<napi_callback_info>(
300
        static_cast<CallbackWrapper*>(this));
301
302
    // All other pointers we need are stored in `_bundle`
303
4683
    napi_env env = _bundle->env;
304
4683
    napi_callback cb = _bundle->cb;
305
306
4683
    napi_value result = nullptr;
307
4683
    bool exceptionOccurred = false;
308
9366
    env->CallIntoModule([&](napi_env env) { result = cb(env, cbinfo_wrapper); },
309
1232
                        [&](napi_env env, v8::Local<v8::Value> value) {
310
1232
                          exceptionOccurred = true;
311
1232
                          env->isolate->ThrowException(value);
312
1232
                        });
313
314

4683
    if (!exceptionOccurred && (result != nullptr)) {
315
2837
      this->SetReturnValue(result);
316
    }
317
4683
  }
318
319
  const v8::FunctionCallbackInfo<v8::Value>& _cbinfo;
320
  CallbackBundle* _bundle;
321
};
322
323
class FunctionCallbackWrapper : public CallbackWrapperBase {
324
 public:
325
4683
  static void Invoke(const v8::FunctionCallbackInfo<v8::Value>& info) {
326
4683
    FunctionCallbackWrapper cbwrapper(info);
327
4683
    cbwrapper.InvokeCallback();
328
4683
  }
329
330
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
4683
  explicit FunctionCallbackWrapper(
359
      const v8::FunctionCallbackInfo<v8::Value>& cbinfo)
360
4683
      : CallbackWrapperBase(cbinfo, cbinfo.Length()) {}
361
362
8
  napi_value GetNewTarget() override {
363
16
    if (_cbinfo.IsConstructCall()) {
364
7
      return v8impl::JsValueFromV8LocalValue(_cbinfo.NewTarget());
365
    } else {
366
1
      return nullptr;
367
    }
368
  }
369
370
  /*virtual*/
371
4493
  void Args(napi_value* buffer, size_t buffer_length) override {
372
4493
    size_t i = 0;
373
4493
    size_t min = std::min(buffer_length, _args_length);
374
375
11580
    for (; i < min; i += 1) {
376
14174
      buffer[i] = v8impl::JsValueFromV8LocalValue(_cbinfo[i]);
377
    }
378
379
4493
    if (i < buffer_length) {
380
      napi_value undefined =
381
50
          v8impl::JsValueFromV8LocalValue(v8::Undefined(_cbinfo.GetIsolate()));
382
103
      for (; i < buffer_length; i += 1) {
383
78
        buffer[i] = undefined;
384
      }
385
    }
386
4493
  }
387
388
  /*virtual*/
389
2837
  void SetReturnValue(napi_value value) override {
390
2837
    v8::Local<v8::Value> val = v8impl::V8LocalValueFromJsValue(value);
391
2837
    _cbinfo.GetReturnValue().Set(val);
392
2837
  }
393
};
394
395
enum WrapType { retrievable, anonymous };
396
397
template <WrapType wrap_type>
398
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
3133
RefBase::RefBase(napi_env env,
461
                 uint32_t initial_refcount,
462
                 bool delete_self,
463
                 napi_finalize finalize_callback,
464
                 void* finalize_data,
465
3133
                 void* finalize_hint)
466
    : Finalizer(env, finalize_callback, finalize_data, finalize_hint),
467
      _refcount(initial_refcount),
468
3133
      _delete_self(delete_self) {
469
3133
  Link(finalize_callback == nullptr ? &env->reflist : &env->finalizing_reflist);
470
3133
}
471
472
7
RefBase* RefBase::New(napi_env env,
473
                      uint32_t initial_refcount,
474
                      bool delete_self,
475
                      napi_finalize finalize_callback,
476
                      void* finalize_data,
477
                      void* finalize_hint) {
478
  return new RefBase(env,
479
                     initial_refcount,
480
                     delete_self,
481
                     finalize_callback,
482
                     finalize_data,
483
7
                     finalize_hint);
484
}
485
486
6260
RefBase::~RefBase() {
487
6246
  Unlink();
488
6260
}
489
490
54
void* RefBase::Data() {
491
54
  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
3141
void RefBase::Delete(RefBase* reference) {
510

4168
  if ((reference->RefCount() != 0) || (reference->_delete_self) ||
511
1027
      (reference->_finalize_ran)) {
512
3123
    delete reference;
513
  } else {
514
    // defer until finalizer runs as
515
    // it may already be queued
516
18
    reference->_delete_self = true;
517
  }
518
3141
}
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
6844
uint32_t RefBase::RefCount() {
532
6844
  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
3126
Reference::Reference(napi_env env, v8::Local<v8::Value> value, Args&&... args)
576
15630
    : RefBase(env, std::forward<Args>(args)...),
577
3126
      _persistent(env->isolate, value),
578
3126
      _secondPassParameter(new SecondPassCallParameterRef(this)),
579
6252
      _secondPassScheduled(false) {
580
3126
  if (RefCount() == 0) {
581
2585
    SetWeak();
582
  }
583
3126
}
584
585
3126
Reference* Reference::New(napi_env env,
586
                          v8::Local<v8::Value> value,
587
                          uint32_t initial_refcount,
588
                          bool delete_self,
589
                          napi_finalize finalize_callback,
590
                          void* finalize_data,
591
                          void* finalize_hint) {
592
  return new Reference(env,
593
                       value,
594
                       initial_refcount,
595
                       delete_self,
596
                       finalize_callback,
597
                       finalize_data,
598
3126
                       finalize_hint);
599
}
600
601
18696
Reference::~Reference() {
602
  // If the second pass callback is scheduled, it will delete the
603
  // parameter passed to it, otherwise it will never be scheduled
604
  // and we need to delete it here.
605
6232
  if (!_secondPassScheduled) {
606
2182
    delete _secondPassParameter;
607
  }
608
12464
}
609
610
3
uint32_t Reference::Ref() {
611
3
  uint32_t refcount = RefBase::Ref();
612
3
  if (refcount == 1) {
613
2
    ClearWeak();
614
  }
615
3
  return refcount;
616
}
617
618
3
uint32_t Reference::Unref() {
619
3
  uint32_t old_refcount = RefCount();
620
3
  uint32_t refcount = RefBase::Unref();
621

3
  if (old_refcount == 1 && refcount == 0) {
622
2
    SetWeak();
623
  }
624
3
  return refcount;
625
}
626
627
11548
v8::Local<v8::Value> Reference::Get() {
628
11548
  if (_persistent.IsEmpty()) {
629
1002
    return v8::Local<v8::Value>();
630
  } else {
631
21092
    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
    "External buffers are not allowed",
750
};
751
752
1319
napi_status NAPI_CDECL napi_get_last_error_info(
753
    napi_env env, const napi_extended_error_info** result) {
754
1319
  CHECK_ENV(env);
755
1319
  CHECK_ARG(env, result);
756
757
  // The value of the constant below must be updated to reference the last
758
  // message in the `napi_status` enum each time a new error message is added.
759
  // We don't have a napi_status_last as this would result in an ABI
760
  // change each time a message was added.
761
1319
  const int last_status = napi_no_external_buffers_allowed;
762
763
  static_assert(NAPI_ARRAYSIZE(error_messages) == last_status + 1,
764
                "Count of error messages must match count of error values");
765
1319
  CHECK_LE(env->last_error.error_code, last_status);
766
  // Wait until someone requests the last error information to fetch the error
767
  // message string
768
1319
  env->last_error.error_message = error_messages[env->last_error.error_code];
769
770
1319
  if (env->last_error.error_code == napi_ok) {
771
10
    napi_clear_last_error(env);
772
  }
773
1319
  *result = &(env->last_error);
774
1319
  return napi_ok;
775
}
776
777
15
napi_status NAPI_CDECL napi_create_function(napi_env env,
778
                                            const char* utf8name,
779
                                            size_t length,
780
                                            napi_callback cb,
781
                                            void* callback_data,
782
                                            napi_value* result) {
783


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


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


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


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

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


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

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

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


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

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

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


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

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


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

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


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

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

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


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

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


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

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

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

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


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

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

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


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

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

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


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

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

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


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

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


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

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


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

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

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


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

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

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

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

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

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


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

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

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


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

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

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


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


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


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

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

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

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

747
  if (length > 0) CHECK_ARG(env, str);
1480
745
  CHECK_ARG(env, result);
1481

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

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

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


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

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

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

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

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


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

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


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


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

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


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

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


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

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


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

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

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


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




44
GEN_COERCE_FUNCTION(NUMBER, Number, number)
2352




51
GEN_COERCE_FUNCTION(OBJECT, Object, object)
2353




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


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


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


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

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

4
  CHECK_MAYBE_NOTHING_WITH_PREAMBLE(env, maybe_has, napi_generic_failure);
2415

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

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

4
  CHECK_MAYBE_NOTHING_WITH_PREAMBLE(env, maybe_set, napi_generic_failure);
2424

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


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


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

13
  CHECK_ARG_WITH_PREAMBLE(env, type_tag);
2439

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

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

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

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

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

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


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

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


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

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


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


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



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



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

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

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

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

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

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

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

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

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

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


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

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


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


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


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


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

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