GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: js_native_api_v8.cc Lines: 1422 1454 97.8 %
Date: 2022-05-20 04:15:46 Branches: 1143 1794 63.7 %

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

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

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


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

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


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

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




2064
  NAPI_PREAMBLE(env);
407

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

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

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

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

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

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

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

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

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

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


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


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


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


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

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


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

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

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


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

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

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


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

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


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

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


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

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

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


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

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


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

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

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

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


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

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

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


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

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

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


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

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

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


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

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


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

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


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

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

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


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

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

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

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

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

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


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

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

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


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

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

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


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


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


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

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

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

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

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

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

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

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


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

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

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

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

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


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

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


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


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

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


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

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


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

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


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

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

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


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




44
GEN_COERCE_FUNCTION(NUMBER, Number, number)
2353




51
GEN_COERCE_FUNCTION(OBJECT, Object, object)
2354




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


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


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


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

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

2
  CHECK_MAYBE_NOTHING_WITH_PREAMBLE(env, maybe_has, napi_generic_failure);
2414

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

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

2
  CHECK_MAYBE_NOTHING_WITH_PREAMBLE(env, maybe_set, napi_generic_failure);
2423

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


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


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

6
  CHECK_ARG_WITH_PREAMBLE(env, type_tag);
2438

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

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

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

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

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


22
  NAPI_PREAMBLE(env);
2666
11
  CHECK_ARG(env, constructor);
2667
11
  if (argc > 0) {
2668
7
    CHECK_ARG(env, argv);
2669
  }
2670
11
  CHECK_ARG(env, result);
2671
2672
11
  v8::Local<v8::Context> context = env->context();
2673
2674
  v8::Local<v8::Function> ctor;
2675

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


4556
  NAPI_PREAMBLE(env);
2693
2278
  CHECK_ARG(env, object);
2694
2278
  CHECK_ARG(env, result);
2695
2696
2278
  *result = false;
2697
2698
  v8::Local<v8::Object> ctor;
2699
2278
  v8::Local<v8::Context> context = env->context();
2700
2701

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


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


68
  NAPI_PREAMBLE(env);
2843
34
  CHECK_ARG(env, arraybuffer);
2844
34
  CHECK_ARG(env, result);
2845
2846
34
  v8::Local<v8::Value> value = v8impl::V8LocalValueFromJsValue(arraybuffer);
2847
34
  RETURN_STATUS_IF_FALSE(env, value->IsArrayBuffer(), napi_invalid_arg);
2848
2849



34
  v8::Local<v8::ArrayBuffer> buffer = value.As<v8::ArrayBuffer>();
2850
  v8::Local<v8::TypedArray> typedArray;
2851
2852



34
  switch (type) {
2853
4
    case napi_int8_array:
2854
4
      CREATE_TYPED_ARRAY(
2855
          env, Int8Array, 1, buffer, byte_offset, length, typedArray);
2856
3
      break;
2857
3
    case napi_uint8_array:
2858
3
      CREATE_TYPED_ARRAY(
2859
          env, Uint8Array, 1, buffer, byte_offset, length, typedArray);
2860
2
      break;
2861
2
    case napi_uint8_clamped_array:
2862
2
      CREATE_TYPED_ARRAY(
2863
          env, Uint8ClampedArray, 1, buffer, byte_offset, length, typedArray);
2864
1
      break;
2865
3
    case napi_int16_array:
2866

3
      CREATE_TYPED_ARRAY(
2867
          env, Int16Array, 2, buffer, byte_offset, length, typedArray);
2868
1
      break;
2869
3
    case napi_uint16_array:
2870

3
      CREATE_TYPED_ARRAY(
2871
          env, Uint16Array, 2, buffer, byte_offset, length, typedArray);
2872
1
      break;
2873
3
    case napi_int32_array:
2874

3
      CREATE_TYPED_ARRAY(
2875
          env, Int32Array, 4, buffer, byte_offset, length, typedArray);
2876
1
      break;
2877
3
    case napi_uint32_array:
2878

3
      CREATE_TYPED_ARRAY(
2879
          env, Uint32Array, 4, buffer, byte_offset, length, typedArray);
2880
1
      break;
2881
3
    case napi_float32_array:
2882

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

4
      CREATE_TYPED_ARRAY(
2887
          env, Float64Array, 8, buffer, byte_offset, length, typedArray);
2888
2
      break;
2889
3
    case napi_bigint64_array:
2890

3
      CREATE_TYPED_ARRAY(
2891
          env, BigInt64Array, 8, buffer, byte_offset, length, typedArray);
2892
1
      break;
2893
3
    case napi_biguint64_array:
2894

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

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


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

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


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


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


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


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

52
  *result = value->IsArrayBuffer() &&
3251
52
            value.As<v8::ArrayBuffer>()->GetBackingStore()->Data() == nullptr;
3252
3253
26
  return napi_clear_last_error(env);
3254
}