GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: js_native_api_v8.cc Lines: 1428 1467 97.3 %
Date: 2022-02-09 04:14:30 Branches: 1140 1794 63.5 %

Line Branch Exec Source
1
#include <climits>  // INT_MAX
2
#include <cmath>
3
#include <algorithm>
4
#define NAPI_EXPERIMENTAL
5
#include "env-inl.h"
6
#include "js_native_api_v8.h"
7
#include "js_native_api.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((env),                                        \
28
        (len == NAPI_AUTO_LENGTH) || len <= INT_MAX,                     \
29
        napi_invalid_arg);                                               \
30
    RETURN_STATUS_IF_FALSE((env),                                        \
31
        (str) != nullptr,                                                \
32
        napi_invalid_arg);                                               \
33
    auto str_maybe = v8::String::NewFromUtf8(                            \
34
        (env)->isolate, (str), v8::NewStringType::kInternalized,         \
35
        static_cast<int>(len));                                          \
36
    CHECK_MAYBE_EMPTY((env), str_maybe, napi_generic_failure);           \
37
    (result) = str_maybe.ToLocalChecked();                               \
38
  } while (0)
39
40
#define CHECK_NEW_FROM_UTF8(env, result, str) \
41
  CHECK_NEW_FROM_UTF8_LEN((env), (result), (str), NAPI_AUTO_LENGTH)
42
43
#define CREATE_TYPED_ARRAY(                                                    \
44
    env, type, size_of_element, buffer, byte_offset, length, out)              \
45
  do {                                                                         \
46
    if ((size_of_element) > 1) {                                               \
47
      THROW_RANGE_ERROR_IF_FALSE(                                              \
48
          (env), (byte_offset) % (size_of_element) == 0,                       \
49
          "ERR_NAPI_INVALID_TYPEDARRAY_ALIGNMENT",                             \
50
          "start offset of "#type" should be a multiple of "#size_of_element); \
51
    }                                                                          \
52
    THROW_RANGE_ERROR_IF_FALSE((env), (length) * (size_of_element) +           \
53
        (byte_offset) <= buffer->ByteLength(),                                 \
54
        "ERR_NAPI_INVALID_TYPEDARRAY_LENGTH",                                  \
55
        "Invalid typed array length");                                         \
56
    (out) = v8::type::New((buffer), (byte_offset), (length));                  \
57
  } while (0)
58
59
namespace v8impl {
60
61
namespace {
62
63
inline static napi_status
64
478
V8NameFromPropertyDescriptor(napi_env env,
65
                             const napi_property_descriptor* p,
66
                             v8::Local<v8::Name>* result) {
67
478
  if (p->utf8name != nullptr) {
68

1422
    CHECK_NEW_FROM_UTF8(env, *result, p->utf8name);
69
  } else {
70
    v8::Local<v8::Value> property_value =
71
4
      v8impl::V8LocalValueFromJsValue(p->name);
72
73
4
    RETURN_STATUS_IF_FALSE(env, property_value->IsName(), napi_name_expected);
74
4
    *result = property_value.As<v8::Name>();
75
  }
76
77
478
  return napi_ok;
78
}
79
80
// convert from n-api property attributes to v8::PropertyAttribute
81
21
inline static v8::PropertyAttribute V8PropertyAttributesFromDescriptor(
82
    const napi_property_descriptor* descriptor) {
83
21
  unsigned int attribute_flags = v8::PropertyAttribute::None;
84
85
  // The napi_writable attribute is ignored for accessor descriptors, but
86
  // V8 would throw `TypeError`s on assignment with nonexistence of a setter.
87

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


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

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


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

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




2064
  NAPI_PREAMBLE(env);
412

1032
  CHECK_ARG(env, js_object);
413
414
1032
  v8::Local<v8::Context> context = env->context();
415
416
1032
  v8::Local<v8::Value> value = v8impl::V8LocalValueFromJsValue(js_object);
417

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

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

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

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

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

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

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

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

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


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


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


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


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

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


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

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

6
  CHECK_MAYBE_EMPTY_WITH_PREAMBLE(
990
      env, maybe_all_propertynames, napi_generic_failure);
991
992
12
  *result =
993
6
      v8impl::JsValueFromV8LocalValue(maybe_all_propertynames.ToLocalChecked());
994
6
  return GET_RETURN_STATUS(env);
995
}
996
997
27
napi_status napi_set_property(napi_env env,
998
                              napi_value object,
999
                              napi_value key,
1000
                              napi_value value) {
1001


52
  NAPI_PREAMBLE(env);
1002
25
  CHECK_ARG(env, key);
1003
22
  CHECK_ARG(env, value);
1004
1005
20
  v8::Local<v8::Context> context = env->context();
1006
  v8::Local<v8::Object> obj;
1007
1008

38
  CHECK_TO_OBJECT(env, context, obj, object);
1009
1010
18
  v8::Local<v8::Value> k = v8impl::V8LocalValueFromJsValue(key);
1011
18
  v8::Local<v8::Value> val = v8impl::V8LocalValueFromJsValue(value);
1012
1013
18
  v8::Maybe<bool> set_maybe = obj->Set(context, k, val);
1014
1015

36
  RETURN_STATUS_IF_FALSE(env, set_maybe.FromMaybe(false), napi_generic_failure);
1016
18
  return GET_RETURN_STATUS(env);
1017
}
1018
1019
16
napi_status napi_has_property(napi_env env,
1020
                              napi_value object,
1021
                              napi_value key,
1022
                              bool* result) {
1023


30
  NAPI_PREAMBLE(env);
1024
14
  CHECK_ARG(env, result);
1025
12
  CHECK_ARG(env, key);
1026
1027
10
  v8::Local<v8::Context> context = env->context();
1028
  v8::Local<v8::Object> obj;
1029
1030

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


66
  NAPI_PREAMBLE(env);
1046
32
  CHECK_ARG(env, key);
1047
28
  CHECK_ARG(env, result);
1048
1049
26
  v8::Local<v8::Context> context = env->context();
1050
26
  v8::Local<v8::Value> k = v8impl::V8LocalValueFromJsValue(key);
1051
  v8::Local<v8::Object> obj;
1052
1053

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


17
  NAPI_PREAMBLE(env);
1069
8
  CHECK_ARG(env, key);
1070
1071
7
  v8::Local<v8::Context> context = env->context();
1072
7
  v8::Local<v8::Value> k = v8impl::V8LocalValueFromJsValue(key);
1073
  v8::Local<v8::Object> obj;
1074
1075

19
  CHECK_TO_OBJECT(env, context, obj, object);
1076
6
  v8::Maybe<bool> delete_maybe = obj->Delete(context, k);
1077
6
  CHECK_MAYBE_NOTHING(env, delete_maybe, napi_generic_failure);
1078
1079
6
  if (result != nullptr)
1080
10
    *result = delete_maybe.FromMaybe(false);
1081
1082
6
  return GET_RETURN_STATUS(env);
1083
}
1084
1085
19
napi_status napi_has_own_property(napi_env env,
1086
                                  napi_value object,
1087
                                  napi_value key,
1088
                                  bool* result) {
1089


37
  NAPI_PREAMBLE(env);
1090
18
  CHECK_ARG(env, key);
1091
17
  CHECK_ARG(env, result);
1092
1093
16
  v8::Local<v8::Context> context = env->context();
1094
  v8::Local<v8::Object> obj;
1095
1096

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


333
  NAPI_PREAMBLE(env);
1111
166
  CHECK_ARG(env, value);
1112
1113
165
  v8::Local<v8::Context> context = env->context();
1114
  v8::Local<v8::Object> obj;
1115
1116

493
  CHECK_TO_OBJECT(env, context, obj, object);
1117
1118
  v8::Local<v8::Name> key;
1119

327
  CHECK_NEW_FROM_UTF8(env, key, utf8name);
1120
1121
163
  v8::Local<v8::Value> val = v8impl::V8LocalValueFromJsValue(value);
1122
1123
163
  v8::Maybe<bool> set_maybe = obj->Set(context, key, val);
1124
1125

326
  RETURN_STATUS_IF_FALSE(env, set_maybe.FromMaybe(false), napi_generic_failure);
1126
163
  return GET_RETURN_STATUS(env);
1127
}
1128
1129
9
napi_status napi_has_named_property(napi_env env,
1130
                                    napi_value object,
1131
                                    const char* utf8name,
1132
                                    bool* result) {
1133


17
  NAPI_PREAMBLE(env);
1134
8
  CHECK_ARG(env, result);
1135
1136
7
  v8::Local<v8::Context> context = env->context();
1137
  v8::Local<v8::Object> obj;
1138
1139

19
  CHECK_TO_OBJECT(env, context, obj, object);
1140
1141
  v8::Local<v8::Name> key;
1142

16
  CHECK_NEW_FROM_UTF8(env, key, utf8name);
1143
1144
5
  v8::Maybe<bool> has_maybe = obj->Has(context, key);
1145
1146
5
  CHECK_MAYBE_NOTHING(env, has_maybe, napi_generic_failure);
1147
1148
5
  *result = has_maybe.FromMaybe(false);
1149
5
  return GET_RETURN_STATUS(env);
1150
}
1151
1152
6
napi_status napi_get_named_property(napi_env env,
1153
                                    napi_value object,
1154
                                    const char* utf8name,
1155
                                    napi_value* result) {
1156


11
  NAPI_PREAMBLE(env);
1157
5
  CHECK_ARG(env, result);
1158
1159
4
  v8::Local<v8::Context> context = env->context();
1160
1161
  v8::Local<v8::Name> key;
1162

10
  CHECK_NEW_FROM_UTF8(env, key, utf8name);
1163
1164
  v8::Local<v8::Object> obj;
1165
1166

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


25
  NAPI_PREAMBLE(env);
1182
12
  CHECK_ARG(env, value);
1183
1184
12
  v8::Local<v8::Context> context = env->context();
1185
  v8::Local<v8::Object> obj;
1186
1187

23
  CHECK_TO_OBJECT(env, context, obj, object);
1188
1189
11
  v8::Local<v8::Value> val = v8impl::V8LocalValueFromJsValue(value);
1190
11
  auto set_maybe = obj->Set(context, index, val);
1191
1192

22
  RETURN_STATUS_IF_FALSE(env, set_maybe.FromMaybe(false), napi_generic_failure);
1193
1194
11
  return GET_RETURN_STATUS(env);
1195
}
1196
1197
5
napi_status napi_has_element(napi_env env,
1198
                             napi_value object,
1199
                             uint32_t index,
1200
                             bool* result) {
1201


9
  NAPI_PREAMBLE(env);
1202
4
  CHECK_ARG(env, result);
1203
1204
3
  v8::Local<v8::Context> context = env->context();
1205
  v8::Local<v8::Object> obj;
1206
1207

7
  CHECK_TO_OBJECT(env, context, obj, object);
1208
1209
2
  v8::Maybe<bool> has_maybe = obj->Has(context, index);
1210
1211
2
  CHECK_MAYBE_NOTHING(env, has_maybe, napi_generic_failure);
1212
1213
2
  *result = has_maybe.FromMaybe(false);
1214
2
  return GET_RETURN_STATUS(env);
1215
}
1216
1217
28
napi_status napi_get_element(napi_env env,
1218
                             napi_value object,
1219
                             uint32_t index,
1220
                             napi_value* result) {
1221


55
  NAPI_PREAMBLE(env);
1222
27
  CHECK_ARG(env, result);
1223
1224
27
  v8::Local<v8::Context> context = env->context();
1225
  v8::Local<v8::Object> obj;
1226
1227

81
  CHECK_TO_OBJECT(env, context, obj, object);
1228
1229
27
  auto get_maybe = obj->Get(context, index);
1230
1231
27
  CHECK_MAYBE_EMPTY(env, get_maybe, napi_generic_failure);
1232
1233
27
  *result = v8impl::JsValueFromV8LocalValue(get_maybe.ToLocalChecked());
1234
27
  return GET_RETURN_STATUS(env);
1235
}
1236
1237
4
napi_status napi_delete_element(napi_env env,
1238
                                napi_value object,
1239
                                uint32_t index,
1240
                                bool* result) {
1241


7
  NAPI_PREAMBLE(env);
1242
1243
3
  v8::Local<v8::Context> context = env->context();
1244
  v8::Local<v8::Object> obj;
1245
1246

7
  CHECK_TO_OBJECT(env, context, obj, object);
1247
2
  v8::Maybe<bool> delete_maybe = obj->Delete(context, index);
1248
2
  CHECK_MAYBE_NOTHING(env, delete_maybe, napi_generic_failure);
1249
1250
2
  if (result != nullptr)
1251
2
    *result = delete_maybe.FromMaybe(false);
1252
1253
2
  return GET_RETURN_STATUS(env);
1254
}
1255
1256
85
napi_status napi_define_properties(napi_env env,
1257
                                   napi_value object,
1258
                                   size_t property_count,
1259
                                   const napi_property_descriptor* properties) {
1260


169
  NAPI_PREAMBLE(env);
1261
84
  if (property_count > 0) {
1262
84
    CHECK_ARG(env, properties);
1263
  }
1264
1265
81
  v8::Local<v8::Context> context = env->context();
1266
1267
  v8::Local<v8::Object> obj;
1268

161
  CHECK_TO_OBJECT(env, context, obj, object);
1269
1270
537
  for (size_t i = 0; i < property_count; i++) {
1271
457
    const napi_property_descriptor* p = &properties[i];
1272
1273
    v8::Local<v8::Name> property_name;
1274
457
    STATUS_CALL(v8impl::V8NameFromPropertyDescriptor(env, p, &property_name));
1275
1276

457
    if (p->getter != nullptr || p->setter != nullptr) {
1277
      v8::Local<v8::Function> local_getter;
1278
      v8::Local<v8::Function> local_setter;
1279
1280
10
      if (p->getter != nullptr) {
1281
10
        STATUS_CALL(v8impl::FunctionCallbackWrapper::NewFunction(
1282
            env, p->getter, p->data, &local_getter));
1283
      }
1284
10
      if (p->setter != nullptr) {
1285
2
        STATUS_CALL(v8impl::FunctionCallbackWrapper::NewFunction(
1286
            env, p->setter, p->data, &local_setter));
1287
      }
1288
1289
10
      v8::PropertyDescriptor descriptor(local_getter, local_setter);
1290
10
      descriptor.set_enumerable((p->attributes & napi_enumerable) != 0);
1291
10
      descriptor.set_configurable((p->attributes & napi_configurable) != 0);
1292
1293
      auto define_maybe = obj->DefineProperty(context,
1294
                                              property_name,
1295
10
                                              descriptor);
1296
1297

20
      if (!define_maybe.FromMaybe(false)) {
1298
        return napi_set_last_error(env, napi_invalid_arg);
1299
10
      }
1300
447
    } else if (p->method != nullptr) {
1301
      v8::Local<v8::Function> method;
1302
427
      STATUS_CALL(v8impl::FunctionCallbackWrapper::NewFunction(
1303
          env, p->method, p->data, &method));
1304
      v8::PropertyDescriptor descriptor(method,
1305
427
                                        (p->attributes & napi_writable) != 0);
1306
427
      descriptor.set_enumerable((p->attributes & napi_enumerable) != 0);
1307
427
      descriptor.set_configurable((p->attributes & napi_configurable) != 0);
1308
1309
      auto define_maybe = obj->DefineProperty(context,
1310
                                              property_name,
1311
427
                                              descriptor);
1312
1313

854
      if (!define_maybe.FromMaybe(false)) {
1314
        return napi_set_last_error(env, napi_generic_failure);
1315
      }
1316
    } else {
1317
20
      v8::Local<v8::Value> value = v8impl::V8LocalValueFromJsValue(p->value);
1318
1319
      v8::PropertyDescriptor descriptor(value,
1320
20
                                        (p->attributes & napi_writable) != 0);
1321
20
      descriptor.set_enumerable((p->attributes & napi_enumerable) != 0);
1322
20
      descriptor.set_configurable((p->attributes & napi_configurable) != 0);
1323
1324
      auto define_maybe =
1325
20
          obj->DefineProperty(context, property_name, descriptor);
1326
1327

40
      if (!define_maybe.FromMaybe(false)) {
1328
        return napi_set_last_error(env, napi_invalid_arg);
1329
      }
1330
    }
1331
  }
1332
1333
80
  return GET_RETURN_STATUS(env);
1334
}
1335
1336
1
napi_status napi_object_freeze(napi_env env,
1337
                               napi_value object) {
1338


2
  NAPI_PREAMBLE(env);
1339
1340
1
  v8::Local<v8::Context> context = env->context();
1341
  v8::Local<v8::Object> obj;
1342
1343

3
  CHECK_TO_OBJECT(env, context, obj, object);
1344
1345
  v8::Maybe<bool> set_frozen =
1346
1
    obj->SetIntegrityLevel(context, v8::IntegrityLevel::kFrozen);
1347
1348

2
  RETURN_STATUS_IF_FALSE_WITH_PREAMBLE(env,
1349
    set_frozen.FromMaybe(false), napi_generic_failure);
1350
1351
1
  return GET_RETURN_STATUS(env);
1352
}
1353
1354
1
napi_status napi_object_seal(napi_env env,
1355
                             napi_value object) {
1356


2
  NAPI_PREAMBLE(env);
1357
1358
1
  v8::Local<v8::Context> context = env->context();
1359
  v8::Local<v8::Object> obj;
1360
1361

3
  CHECK_TO_OBJECT(env, context, obj, object);
1362
1363
  v8::Maybe<bool> set_sealed =
1364
1
    obj->SetIntegrityLevel(context, v8::IntegrityLevel::kSealed);
1365
1366

2
  RETURN_STATUS_IF_FALSE_WITH_PREAMBLE(env,
1367
    set_sealed.FromMaybe(false), napi_generic_failure);
1368
1369
1
  return GET_RETURN_STATUS(env);
1370
}
1371
1372
11
napi_status napi_is_array(napi_env env, napi_value value, bool* result) {
1373
11
  CHECK_ENV(env);
1374
11
  CHECK_ARG(env, value);
1375
11
  CHECK_ARG(env, result);
1376
1377
11
  v8::Local<v8::Value> val = v8impl::V8LocalValueFromJsValue(value);
1378
1379
11
  *result = val->IsArray();
1380
11
  return napi_clear_last_error(env);
1381
}
1382
1383
13
napi_status napi_get_array_length(napi_env env,
1384
                                  napi_value value,
1385
                                  uint32_t* result) {
1386


26
  NAPI_PREAMBLE(env);
1387
13
  CHECK_ARG(env, value);
1388
13
  CHECK_ARG(env, result);
1389
1390
13
  v8::Local<v8::Value> val = v8impl::V8LocalValueFromJsValue(value);
1391
13
  RETURN_STATUS_IF_FALSE(env, val->IsArray(), napi_array_expected);
1392
1393
13
  v8::Local<v8::Array> arr = val.As<v8::Array>();
1394
13
  *result = arr->Length();
1395
1396
13
  return GET_RETURN_STATUS(env);
1397
}
1398
1399
9
napi_status napi_strict_equals(napi_env env,
1400
                               napi_value lhs,
1401
                               napi_value rhs,
1402
                               bool* result) {
1403


18
  NAPI_PREAMBLE(env);
1404
9
  CHECK_ARG(env, lhs);
1405
9
  CHECK_ARG(env, rhs);
1406
9
  CHECK_ARG(env, result);
1407
1408
9
  v8::Local<v8::Value> a = v8impl::V8LocalValueFromJsValue(lhs);
1409
9
  v8::Local<v8::Value> b = v8impl::V8LocalValueFromJsValue(rhs);
1410
1411
9
  *result = a->StrictEquals(b);
1412
9
  return GET_RETURN_STATUS(env);
1413
}
1414
1415
7
napi_status napi_get_prototype(napi_env env,
1416
                               napi_value object,
1417
                               napi_value* result) {
1418


13
  NAPI_PREAMBLE(env);
1419
6
  CHECK_ARG(env, result);
1420
1421
5
  v8::Local<v8::Context> context = env->context();
1422
1423
  v8::Local<v8::Object> obj;
1424

13
  CHECK_TO_OBJECT(env, context, obj, object);
1425
1426
4
  v8::Local<v8::Value> val = obj->GetPrototype();
1427
4
  *result = v8impl::JsValueFromV8LocalValue(val);
1428
4
  return GET_RETURN_STATUS(env);
1429
}
1430
1431
70
napi_status napi_create_object(napi_env env, napi_value* result) {
1432
70
  CHECK_ENV(env);
1433
70
  CHECK_ARG(env, result);
1434
1435
70
  *result = v8impl::JsValueFromV8LocalValue(
1436
70
      v8::Object::New(env->isolate));
1437
1438
70
  return napi_clear_last_error(env);
1439
}
1440
1441
1
napi_status napi_create_array(napi_env env, napi_value* result) {
1442
1
  CHECK_ENV(env);
1443
1
  CHECK_ARG(env, result);
1444
1445
1
  *result = v8impl::JsValueFromV8LocalValue(
1446
1
      v8::Array::New(env->isolate));
1447
1448
1
  return napi_clear_last_error(env);
1449
}
1450
1451
4
napi_status napi_create_array_with_length(napi_env env,
1452
                                          size_t length,
1453
                                          napi_value* result) {
1454
4
  CHECK_ENV(env);
1455
4
  CHECK_ARG(env, result);
1456
1457
4
  *result = v8impl::JsValueFromV8LocalValue(
1458
4
      v8::Array::New(env->isolate, length));
1459
1460
4
  return napi_clear_last_error(env);
1461
}
1462
1463
16
napi_status napi_create_string_latin1(napi_env env,
1464
                                      const char* str,
1465
                                      size_t length,
1466
                                      napi_value* result) {
1467
16
  CHECK_ENV(env);
1468
15
  if (length > 0)
1469
13
      CHECK_ARG(env, str);
1470
14
  CHECK_ARG(env, result);
1471

13
  RETURN_STATUS_IF_FALSE(env,
1472
      (length == NAPI_AUTO_LENGTH) || length <= INT_MAX,
1473
      napi_invalid_arg);
1474
1475
12
  auto isolate = env->isolate;
1476
  auto str_maybe =
1477
      v8::String::NewFromOneByte(isolate,
1478
                                 reinterpret_cast<const uint8_t*>(str),
1479
                                 v8::NewStringType::kNormal,
1480
12
                                 length);
1481
12
  CHECK_MAYBE_EMPTY(env, str_maybe, napi_generic_failure);
1482
1483
12
  *result = v8impl::JsValueFromV8LocalValue(str_maybe.ToLocalChecked());
1484
12
  return napi_clear_last_error(env);
1485
}
1486
1487
746
napi_status napi_create_string_utf8(napi_env env,
1488
                                    const char* str,
1489
                                    size_t length,
1490
                                    napi_value* result) {
1491
746
  CHECK_ENV(env);
1492
745
  if (length > 0)
1493
742
      CHECK_ARG(env, str);
1494
743
  CHECK_ARG(env, result);
1495

742
  RETURN_STATUS_IF_FALSE(env,
1496
      (length == NAPI_AUTO_LENGTH) || length <= INT_MAX,
1497
      napi_invalid_arg);
1498
1499
741
  auto isolate = env->isolate;
1500
  auto str_maybe =
1501
      v8::String::NewFromUtf8(isolate,
1502
                              str,
1503
                              v8::NewStringType::kNormal,
1504
741
                              static_cast<int>(length));
1505
741
  CHECK_MAYBE_EMPTY(env, str_maybe, napi_generic_failure);
1506
741
  *result = v8impl::JsValueFromV8LocalValue(str_maybe.ToLocalChecked());
1507
741
  return napi_clear_last_error(env);
1508
}
1509
1510
18
napi_status napi_create_string_utf16(napi_env env,
1511
                                     const char16_t* str,
1512
                                     size_t length,
1513
                                     napi_value* result) {
1514
18
  CHECK_ENV(env);
1515
17
  if (length > 0)
1516
15
      CHECK_ARG(env, str);
1517
16
  CHECK_ARG(env, result);
1518

15
  RETURN_STATUS_IF_FALSE(env,
1519
      (length == NAPI_AUTO_LENGTH) || length <= INT_MAX,
1520
      napi_invalid_arg);
1521
1522
14
  auto isolate = env->isolate;
1523
  auto str_maybe =
1524
      v8::String::NewFromTwoByte(isolate,
1525
                                 reinterpret_cast<const uint16_t*>(str),
1526
                                 v8::NewStringType::kNormal,
1527
14
                                 length);
1528
14
  CHECK_MAYBE_EMPTY(env, str_maybe, napi_generic_failure);
1529
1530
14
  *result = v8impl::JsValueFromV8LocalValue(str_maybe.ToLocalChecked());
1531
14
  return napi_clear_last_error(env);
1532
}
1533
1534
71
napi_status napi_create_double(napi_env env,
1535
                               double value,
1536
                               napi_value* result) {
1537
71
  CHECK_ENV(env);
1538
71
  CHECK_ARG(env, result);
1539
1540
71
  *result = v8impl::JsValueFromV8LocalValue(
1541
71
      v8::Number::New(env->isolate, value));
1542
1543
71
  return napi_clear_last_error(env);
1544
}
1545
1546
104830
napi_status napi_create_int32(napi_env env,
1547
                              int32_t value,
1548
                              napi_value* result) {
1549
104830
  CHECK_ENV(env);
1550
104830
  CHECK_ARG(env, result);
1551
1552
104830
  *result = v8impl::JsValueFromV8LocalValue(
1553
104830
      v8::Integer::New(env->isolate, value));
1554
1555
104830
  return napi_clear_last_error(env);
1556
}
1557
1558
555
napi_status napi_create_uint32(napi_env env,
1559
                               uint32_t value,
1560
                               napi_value* result) {
1561
555
  CHECK_ENV(env);
1562
555
  CHECK_ARG(env, result);
1563
1564
555
  *result = v8impl::JsValueFromV8LocalValue(
1565
555
      v8::Integer::NewFromUnsigned(env->isolate, value));
1566
1567
555
  return napi_clear_last_error(env);
1568
}
1569
1570
24
napi_status napi_create_int64(napi_env env,
1571
                              int64_t value,
1572
                              napi_value* result) {
1573
24
  CHECK_ENV(env);
1574
24
  CHECK_ARG(env, result);
1575
1576
24
  *result = v8impl::JsValueFromV8LocalValue(
1577
24
      v8::Number::New(env->isolate, static_cast<double>(value)));
1578
1579
24
  return napi_clear_last_error(env);
1580
}
1581
1582
9
napi_status napi_create_bigint_int64(napi_env env,
1583
                                     int64_t value,
1584
                                     napi_value* result) {
1585
9
  CHECK_ENV(env);
1586
9
  CHECK_ARG(env, result);
1587
1588
9
  *result = v8impl::JsValueFromV8LocalValue(
1589
9
      v8::BigInt::New(env->isolate, value));
1590
1591
9
  return napi_clear_last_error(env);
1592
}
1593
1594
6
napi_status napi_create_bigint_uint64(napi_env env,
1595
                                      uint64_t value,
1596
                                      napi_value* result) {
1597
6
  CHECK_ENV(env);
1598
6
  CHECK_ARG(env, result);
1599
1600
6
  *result = v8impl::JsValueFromV8LocalValue(
1601
6
      v8::BigInt::NewFromUnsigned(env->isolate, value));
1602
1603
6
  return napi_clear_last_error(env);
1604
}
1605
1606
13
napi_status napi_create_bigint_words(napi_env env,
1607
                                     int sign_bit,
1608
                                     size_t word_count,
1609
                                     const uint64_t* words,
1610
                                     napi_value* result) {
1611


26
  NAPI_PREAMBLE(env);
1612
13
  CHECK_ARG(env, words);
1613
13
  CHECK_ARG(env, result);
1614
1615
13
  v8::Local<v8::Context> context = env->context();
1616
1617
13
  RETURN_STATUS_IF_FALSE(
1618
      env, word_count <= INT_MAX, napi_invalid_arg);
1619
1620
  v8::MaybeLocal<v8::BigInt> b = v8::BigInt::NewFromWords(
1621
12
      context, sign_bit, word_count, words);
1622
1623

12
  CHECK_MAYBE_EMPTY_WITH_PREAMBLE(env, b, napi_generic_failure);
1624
1625
11
  *result = v8impl::JsValueFromV8LocalValue(b.ToLocalChecked());
1626
11
  return GET_RETURN_STATUS(env);
1627
}
1628
1629
1294
napi_status napi_get_boolean(napi_env env, bool value, napi_value* result) {
1630
1294
  CHECK_ENV(env);
1631
1294
  CHECK_ARG(env, result);
1632
1633
1294
  v8::Isolate* isolate = env->isolate;
1634
1635
1294
  if (value) {
1636
731
    *result = v8impl::JsValueFromV8LocalValue(v8::True(isolate));
1637
  } else {
1638
563
    *result = v8impl::JsValueFromV8LocalValue(v8::False(isolate));
1639
  }
1640
1641
1294
  return napi_clear_last_error(env);
1642
}
1643
1644
15
napi_status napi_create_symbol(napi_env env,
1645
                               napi_value description,
1646
                               napi_value* result) {
1647
15
  CHECK_ENV(env);
1648
15
  CHECK_ARG(env, result);
1649
1650
15
  v8::Isolate* isolate = env->isolate;
1651
1652
15
  if (description == nullptr) {
1653
6
    *result = v8impl::JsValueFromV8LocalValue(v8::Symbol::New(isolate));
1654
  } else {
1655
12
    v8::Local<v8::Value> desc = v8impl::V8LocalValueFromJsValue(description);
1656
24
    RETURN_STATUS_IF_FALSE(env, desc->IsString(), napi_string_expected);
1657
1658
24
    *result = v8impl::JsValueFromV8LocalValue(
1659
      v8::Symbol::New(isolate, desc.As<v8::String>()));
1660
  }
1661
1662
15
  return napi_clear_last_error(env);
1663
}
1664
1665
4
napi_status node_api_symbol_for(napi_env env,
1666
                                const char* utf8description,
1667
                                size_t length,
1668
                                napi_value* result) {
1669
4
  CHECK_ENV(env);
1670
4
  CHECK_ARG(env, result);
1671
1672
  napi_value js_description_string;
1673
4
  STATUS_CALL(napi_create_string_utf8(env,
1674
                                      utf8description,
1675
                                      length,
1676
                                      &js_description_string));
1677
  v8::Local<v8::String> description_string =
1678
3
    v8impl::V8LocalValueFromJsValue(js_description_string).As<v8::String>();
1679
1680
3
  *result = v8impl::JsValueFromV8LocalValue(
1681
3
    v8::Symbol::For(env->isolate, description_string));
1682
1683
3
  return napi_clear_last_error(env);
1684
}
1685
1686
199
static inline napi_status set_error_code(napi_env env,
1687
                                         v8::Local<v8::Value> error,
1688
                                         napi_value code,
1689
                                         const char* code_cstring) {
1690

199
  if ((code != nullptr) || (code_cstring != nullptr)) {
1691
118
    v8::Local<v8::Context> context = env->context();
1692
118
    v8::Local<v8::Object> err_object = error.As<v8::Object>();
1693
1694
118
    v8::Local<v8::Value> code_value = v8impl::V8LocalValueFromJsValue(code);
1695
118
    if (code != nullptr) {
1696
6
      code_value = v8impl::V8LocalValueFromJsValue(code);
1697
12
      RETURN_STATUS_IF_FALSE(env, code_value->IsString(), napi_string_expected);
1698
    } else {
1699

336
      CHECK_NEW_FROM_UTF8(env, code_value, code_cstring);
1700
    }
1701
1702
    v8::Local<v8::Name> code_key;
1703
354
    CHECK_NEW_FROM_UTF8(env, code_key, "code");
1704
1705
118
    v8::Maybe<bool> set_maybe = err_object->Set(context, code_key, code_value);
1706

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


230625
  NAPI_PREAMBLE(env);
1909
115310
  CHECK_ARG(env, recv);
1910
115310
  if (argc > 0) {
1911
105267
    CHECK_ARG(env, argv);
1912
  }
1913
1914
115310
  v8::Local<v8::Context> context = env->context();
1915
1916
115310
  v8::Local<v8::Value> v8recv = v8impl::V8LocalValueFromJsValue(recv);
1917
1918
  v8::Local<v8::Function> v8func;
1919

345930
  CHECK_TO_FUNCTION(env, v8func, func);
1920
1921
  auto maybe = v8func->Call(context, v8recv, argc,
1922
115310
    reinterpret_cast<v8::Local<v8::Value>*>(const_cast<napi_value*>(argv)));
1923
1924
115310
  if (try_catch.HasCaught()) {
1925
7
    return napi_set_last_error(env, napi_pending_exception);
1926
  } else {
1927
115303
    if (result != nullptr) {
1928
7
      CHECK_MAYBE_EMPTY(env, maybe, napi_generic_failure);
1929
7
      *result = v8impl::JsValueFromV8LocalValue(maybe.ToLocalChecked());
1930
    }
1931
115303
    return napi_clear_last_error(env);
1932
  }
1933
}
1934
1935
11
napi_status napi_get_global(napi_env env, napi_value* result) {
1936
11
  CHECK_ENV(env);
1937
11
  CHECK_ARG(env, result);
1938
1939
33
  *result = v8impl::JsValueFromV8LocalValue(env->context()->Global());
1940
1941
11
  return napi_clear_last_error(env);
1942
}
1943
1944
12
napi_status napi_throw(napi_env env, napi_value error) {
1945


24
  NAPI_PREAMBLE(env);
1946
12
  CHECK_ARG(env, error);
1947
1948
12
  v8::Isolate* isolate = env->isolate;
1949
1950
12
  isolate->ThrowException(v8impl::V8LocalValueFromJsValue(error));
1951
  // any VM calls after this point and before returning
1952
  // to the javascript invoker will fail
1953
12
  return napi_clear_last_error(env);
1954
}
1955
1956
82
napi_status napi_throw_error(napi_env env,
1957
                             const char* code,
1958
                             const char* msg) {
1959


156
  NAPI_PREAMBLE(env);
1960
1961
74
  v8::Isolate* isolate = env->isolate;
1962
  v8::Local<v8::String> str;
1963

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


180
  NAPI_PREAMBLE(env);
1978
1979
90
  v8::Isolate* isolate = env->isolate;
1980
  v8::Local<v8::String> str;
1981

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


44
  NAPI_PREAMBLE(env);
1996
1997
22
  v8::Isolate* isolate = env->isolate;
1998
  v8::Local<v8::String> str;
1999

44
  CHECK_NEW_FROM_UTF8(env, str, msg);
2000
2001
22
  v8::Local<v8::Value> error_obj = v8::Exception::RangeError(str);
2002
22
  STATUS_CALL(set_error_code(env, error_obj, nullptr, code));
2003
2004
22
  isolate->ThrowException(error_obj);
2005
  // any VM calls after this point and before returning
2006
  // to the javascript invoker will fail
2007
22
  return napi_clear_last_error(env);
2008
}
2009
2010
2
napi_status node_api_throw_syntax_error(napi_env env,
2011
                                        const char* code,
2012
                                        const char* msg) {
2013


4
  NAPI_PREAMBLE(env);
2014
2015
2
  v8::Isolate* isolate = env->isolate;
2016
  v8::Local<v8::String> str;
2017

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

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


35
  NAPI_PREAMBLE(env);
2348
17
  CHECK_ARG(env, value);
2349
16
  CHECK_ARG(env, result);
2350
2351
15
  v8::Isolate* isolate = env->isolate;
2352
  v8::Local<v8::Boolean> b =
2353
30
    v8impl::V8LocalValueFromJsValue(value)->ToBoolean(isolate);
2354
15
  *result = v8impl::JsValueFromV8LocalValue(b);
2355
15
  return GET_RETURN_STATUS(env);
2356
}
2357
2358
#define GEN_COERCE_FUNCTION(UpperCaseName, MixedCaseName, LowerCaseName)      \
2359
  napi_status napi_coerce_to_##LowerCaseName(napi_env env,                    \
2360
                                             napi_value value,                \
2361
                                             napi_value* result) {            \
2362
    NAPI_PREAMBLE(env);                                                       \
2363
    CHECK_ARG(env, value);                                                    \
2364
    CHECK_ARG(env, result);                                                   \
2365
                                                                              \
2366
    v8::Local<v8::Context> context = env->context();                          \
2367
    v8::Local<v8::MixedCaseName> str;                                         \
2368
                                                                              \
2369
    CHECK_TO_##UpperCaseName(env, context, str, value);                       \
2370
                                                                              \
2371
    *result = v8impl::JsValueFromV8LocalValue(str);                           \
2372
    return GET_RETURN_STATUS(env);                                            \
2373
  }
2374
2375




44
GEN_COERCE_FUNCTION(NUMBER, Number, number)
2376




51
GEN_COERCE_FUNCTION(OBJECT, Object, object)
2377




47
GEN_COERCE_FUNCTION(STRING, String, string)
2378
2379
#undef GEN_COERCE_FUNCTION
2380
2381
1028
napi_status napi_wrap(napi_env env,
2382
                      napi_value js_object,
2383
                      void* native_object,
2384
                      napi_finalize finalize_cb,
2385
                      void* finalize_hint,
2386
                      napi_ref* result) {
2387
1028
  return v8impl::Wrap<v8impl::retrievable>(env,
2388
                                           js_object,
2389
                                           native_object,
2390
                                           finalize_cb,
2391
                                           finalize_hint,
2392
1028
                                           result);
2393
}
2394
2395
27
napi_status napi_unwrap(napi_env env, napi_value obj, void** result) {
2396
27
  return v8impl::Unwrap(env, obj, result, v8impl::KeepWrap);
2397
}
2398
2399
8
napi_status napi_remove_wrap(napi_env env, napi_value obj, void** result) {
2400
8
  return v8impl::Unwrap(env, obj, result, v8impl::RemoveWrap);
2401
}
2402
2403
7
napi_status napi_create_external(napi_env env,
2404
                                 void* data,
2405
                                 napi_finalize finalize_cb,
2406
                                 void* finalize_hint,
2407
                                 napi_value* result) {
2408


14
  NAPI_PREAMBLE(env);
2409
7
  CHECK_ARG(env, result);
2410
2411
7
  v8::Isolate* isolate = env->isolate;
2412
2413
7
  v8::Local<v8::Value> external_value = v8::External::New(isolate, data);
2414
2415
  // The Reference object will delete itself after invoking the finalizer
2416
  // callback.
2417
7
  v8impl::Reference::New(env,
2418
      external_value,
2419
      0,
2420
      true,
2421
      finalize_cb,
2422
      data,
2423
      finalize_hint);
2424
2425
7
  *result = v8impl::JsValueFromV8LocalValue(external_value);
2426
2427
7
  return napi_clear_last_error(env);
2428
}
2429
2430
2
NAPI_EXTERN napi_status napi_type_tag_object(napi_env env,
2431
                                             napi_value object,
2432
                                             const napi_type_tag* type_tag) {
2433


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


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

2
  CHECK_ARG_WITH_PREAMBLE(env, type_tag);
2438
2439
2
  auto key = NAPI_PRIVATE_KEY(context, type_tag);
2440
2
  auto maybe_has = obj->HasPrivate(context, key);
2441

2
  CHECK_MAYBE_NOTHING_WITH_PREAMBLE(env, maybe_has, napi_generic_failure);
2442

2
  RETURN_STATUS_IF_FALSE_WITH_PREAMBLE(env,
2443
                                       !maybe_has.FromJust(),
2444
                                       napi_invalid_arg);
2445
2446
  auto tag = v8::BigInt::NewFromWords(context,
2447
                                   0,
2448
                                   2,
2449
2
                                   reinterpret_cast<const uint64_t*>(type_tag));
2450

2
  CHECK_MAYBE_EMPTY_WITH_PREAMBLE(env, tag, napi_generic_failure);
2451
2452
4
  auto maybe_set = obj->SetPrivate(context, key, tag.ToLocalChecked());
2453

2
  CHECK_MAYBE_NOTHING_WITH_PREAMBLE(env, maybe_set, napi_generic_failure);
2454

2
  RETURN_STATUS_IF_FALSE_WITH_PREAMBLE(env,
2455
                                       maybe_set.FromJust(),
2456
                                       napi_generic_failure);
2457
2458
2
  return GET_RETURN_STATUS(env);
2459
}
2460
2461
NAPI_EXTERN napi_status
2462
6
napi_check_object_type_tag(napi_env env,
2463
                           napi_value object,
2464
                           const napi_type_tag* type_tag,
2465
                           bool* result) {
2466


12
  NAPI_PREAMBLE(env);
2467
6
  v8::Local<v8::Context> context = env->context();
2468
  v8::Local<v8::Object> obj;
2469


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

6
  CHECK_ARG_WITH_PREAMBLE(env, type_tag);
2471

6
  CHECK_ARG_WITH_PREAMBLE(env, result);
2472
2473
  auto maybe_value = obj->GetPrivate(context,
2474
6
                                     NAPI_PRIVATE_KEY(context, type_tag));
2475

6
  CHECK_MAYBE_EMPTY_WITH_PREAMBLE(env, maybe_value, napi_generic_failure);
2476
6
  v8::Local<v8::Value> val = maybe_value.ToLocalChecked();
2477
2478
  // We consider the type check to have failed unless we reach the line below
2479
  // where we set whether the type check succeeded or not based on the
2480
  // comparison of the two type tags.
2481
6
  *result = false;
2482
6
  if (val->IsBigInt()) {
2483
    int sign;
2484
4
    int size = 2;
2485
    napi_type_tag tag;
2486
4
    val.As<v8::BigInt>()->ToWordsArray(&sign,
2487
                                       &size,
2488
                                       reinterpret_cast<uint64_t*>(&tag));
2489

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

4
      *result = (tag.lower == type_tag->lower && tag.upper == type_tag->upper);
2491
  }
2492
2493
6
  return GET_RETURN_STATUS(env);
2494
}
2495
2496
2
napi_status napi_get_value_external(napi_env env,
2497
                                    napi_value value,
2498
                                    void** result) {
2499
2
  CHECK_ENV(env);
2500
2
  CHECK_ARG(env, value);
2501
2
  CHECK_ARG(env, result);
2502
2503
2
  v8::Local<v8::Value> val = v8impl::V8LocalValueFromJsValue(value);
2504
2
  RETURN_STATUS_IF_FALSE(env, val->IsExternal(), napi_invalid_arg);
2505
2506
2
  v8::Local<v8::External> external_value = val.As<v8::External>();
2507
2
  *result = external_value->Value();
2508
2509
2
  return napi_clear_last_error(env);
2510
}
2511
2512
// Set initial_refcount to 0 for a weak reference, >0 for a strong reference.
2513
1543
napi_status napi_create_reference(napi_env env,
2514
                                  napi_value value,
2515
                                  uint32_t initial_refcount,
2516
                                  napi_ref* result) {
2517
  // Omit NAPI_PREAMBLE and GET_RETURN_STATUS because V8 calls here cannot throw
2518
  // JS exceptions.
2519
1543
  CHECK_ENV(env);
2520
1543
  CHECK_ARG(env, value);
2521
1543
  CHECK_ARG(env, result);
2522
2523
1543
  v8::Local<v8::Value> v8_value = v8impl::V8LocalValueFromJsValue(value);
2524

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


22
  NAPI_PREAMBLE(env);
2696
11
  CHECK_ARG(env, constructor);
2697
11
  if (argc > 0) {
2698
7
    CHECK_ARG(env, argv);
2699
  }
2700
11
  CHECK_ARG(env, result);
2701
2702
11
  v8::Local<v8::Context> context = env->context();
2703
2704
  v8::Local<v8::Function> ctor;
2705

33
  CHECK_TO_FUNCTION(env, ctor, constructor);
2706
2707
  auto maybe = ctor->NewInstance(context, argc,
2708
11
    reinterpret_cast<v8::Local<v8::Value>*>(const_cast<napi_value*>(argv)));
2709
2710
11
  CHECK_MAYBE_EMPTY(env, maybe, napi_pending_exception);
2711
2712
9
  *result = v8impl::JsValueFromV8LocalValue(maybe.ToLocalChecked());
2713
9
  return GET_RETURN_STATUS(env);
2714
}
2715
2716
2278
napi_status napi_instanceof(napi_env env,
2717
                            napi_value object,
2718
                            napi_value constructor,
2719
                            bool* result) {
2720


4556
  NAPI_PREAMBLE(env);
2721
2278
  CHECK_ARG(env, object);
2722
2278
  CHECK_ARG(env, result);
2723
2724
2278
  *result = false;
2725
2726
  v8::Local<v8::Object> ctor;
2727
2278
  v8::Local<v8::Context> context = env->context();
2728
2729

6834
  CHECK_TO_OBJECT(env, context, ctor, constructor);
2730
2731
2278
  if (!ctor->IsFunction()) {
2732
88
    napi_throw_type_error(env,
2733
                          "ERR_NAPI_CONS_FUNCTION",
2734
                          "Constructor must be a function");
2735
2736
88
    return napi_set_last_error(env, napi_function_expected);
2737
  }
2738
2739
2190
  napi_status status = napi_generic_failure;
2740
2741
2190
  v8::Local<v8::Value> val = v8impl::V8LocalValueFromJsValue(object);
2742
2190
  auto maybe_result = val->InstanceOf(context, ctor);
2743
2190
  CHECK_MAYBE_NOTHING(env, maybe_result, status);
2744
1166
  *result = maybe_result.FromJust();
2745
1166
  return GET_RETURN_STATUS(env);
2746
}
2747
2748
// Methods to support catching exceptions
2749
1234
napi_status napi_is_exception_pending(napi_env env, bool* result) {
2750
  // NAPI_PREAMBLE is not used here: this function must execute when there is a
2751
  // pending exception.
2752
1234
  CHECK_ENV(env);
2753
1234
  CHECK_ARG(env, result);
2754
2755
1234
  *result = !env->last_exception.IsEmpty();
2756
1234
  return napi_clear_last_error(env);
2757
}
2758
2759
2
napi_status napi_get_and_clear_last_exception(napi_env env,
2760
                                              napi_value* result) {
2761
  // NAPI_PREAMBLE is not used here: this function must execute when there is a
2762
  // pending exception.
2763
2
  CHECK_ENV(env);
2764
2
  CHECK_ARG(env, result);
2765
2766
2
  if (env->last_exception.IsEmpty()) {
2767
    return napi_get_undefined(env, result);
2768
  } else {
2769
2
    *result = v8impl::JsValueFromV8LocalValue(
2770
2
      v8::Local<v8::Value>::New(env->isolate, env->last_exception));
2771
2
    env->last_exception.Reset();
2772
  }
2773
2774
2
  return napi_clear_last_error(env);
2775
}
2776
2777
57
napi_status napi_is_arraybuffer(napi_env env, napi_value value, bool* result) {
2778
57
  CHECK_ENV(env);
2779
57
  CHECK_ARG(env, value);
2780
57
  CHECK_ARG(env, result);
2781
2782
57
  v8::Local<v8::Value> val = v8impl::V8LocalValueFromJsValue(value);
2783
57
  *result = val->IsArrayBuffer();
2784
2785
57
  return napi_clear_last_error(env);
2786
}
2787
2788
2
napi_status napi_create_arraybuffer(napi_env env,
2789
                                    size_t byte_length,
2790
                                    void** data,
2791
                                    napi_value* result) {
2792


4
  NAPI_PREAMBLE(env);
2793
2
  CHECK_ARG(env, result);
2794
2795
2
  v8::Isolate* isolate = env->isolate;
2796
  v8::Local<v8::ArrayBuffer> buffer =
2797
2
      v8::ArrayBuffer::New(isolate, byte_length);
2798
2799
  // Optionally return a pointer to the buffer's data, to avoid another call to
2800
  // retrieve it.
2801
2
  if (data != nullptr) {
2802
2
    *data = buffer->GetBackingStore()->Data();
2803
  }
2804
2805
2
  *result = v8impl::JsValueFromV8LocalValue(buffer);
2806
2
  return GET_RETURN_STATUS(env);
2807
}
2808
2809
6
napi_status napi_create_external_arraybuffer(napi_env env,
2810
                                             void* external_data,
2811
                                             size_t byte_length,
2812
                                             napi_finalize finalize_cb,
2813
                                             void* finalize_hint,
2814
                                             napi_value* result) {
2815
  // The API contract here is that the cleanup function runs on the JS thread,
2816
  // and is able to use napi_env. Implementing that properly is hard, so use the
2817
  // `Buffer` variant for easier implementation.
2818
  napi_value buffer;
2819
6
  STATUS_CALL(napi_create_external_buffer(
2820
      env,
2821
      byte_length,
2822
      external_data,
2823
      finalize_cb,
2824
      finalize_hint,
2825
      &buffer));
2826
6
  return napi_get_typedarray_info(
2827
      env,
2828
      buffer,
2829
      nullptr,
2830
      nullptr,
2831
      nullptr,
2832
      result,
2833
6
      nullptr);
2834
}
2835
2836
2
napi_status napi_get_arraybuffer_info(napi_env env,
2837
                                      napi_value arraybuffer,
2838
                                      void** data,
2839
                                      size_t* byte_length) {
2840
2
  CHECK_ENV(env);
2841
2
  CHECK_ARG(env, arraybuffer);
2842
2843
2
  v8::Local<v8::Value> value = v8impl::V8LocalValueFromJsValue(arraybuffer);
2844
2
  RETURN_STATUS_IF_FALSE(env, value->IsArrayBuffer(), napi_invalid_arg);
2845
2846
  std::shared_ptr<v8::BackingStore> backing_store =
2847
4
      value.As<v8::ArrayBuffer>()->GetBackingStore();
2848
2849
2
  if (data != nullptr) {
2850
2
    *data = backing_store->Data();
2851
  }
2852
2853
2
  if (byte_length != nullptr) {
2854
2
    *byte_length = backing_store->ByteLength();
2855
  }
2856
2857
2
  return napi_clear_last_error(env);
2858
}
2859
2860
44
napi_status napi_is_typedarray(napi_env env, napi_value value, bool* result) {
2861
44
  CHECK_ENV(env);
2862
44
  CHECK_ARG(env, value);
2863
44
  CHECK_ARG(env, result);
2864
2865
44
  v8::Local<v8::Value> val = v8impl::V8LocalValueFromJsValue(value);
2866
44
  *result = val->IsTypedArray();
2867
2868
44
  return napi_clear_last_error(env);
2869
}
2870
2871
34
napi_status napi_create_typedarray(napi_env env,
2872
                                   napi_typedarray_type type,
2873
                                   size_t length,
2874
                                   napi_value arraybuffer,
2875
                                   size_t byte_offset,
2876
                                   napi_value* result) {
2877


68
  NAPI_PREAMBLE(env);
2878
34
  CHECK_ARG(env, arraybuffer);
2879
34
  CHECK_ARG(env, result);
2880
2881
34
  v8::Local<v8::Value> value = v8impl::V8LocalValueFromJsValue(arraybuffer);
2882
34
  RETURN_STATUS_IF_FALSE(env, value->IsArrayBuffer(), napi_invalid_arg);
2883
2884



34
  v8::Local<v8::ArrayBuffer> buffer = value.As<v8::ArrayBuffer>();
2885
  v8::Local<v8::TypedArray> typedArray;
2886
2887



34
  switch (type) {
2888
4
    case napi_int8_array:
2889
4
      CREATE_TYPED_ARRAY(
2890
          env, Int8Array, 1, buffer, byte_offset, length, typedArray);
2891
3
      break;
2892
3
    case napi_uint8_array:
2893
3
      CREATE_TYPED_ARRAY(
2894
          env, Uint8Array, 1, buffer, byte_offset, length, typedArray);
2895
2
      break;
2896
2
    case napi_uint8_clamped_array:
2897
2
      CREATE_TYPED_ARRAY(
2898
          env, Uint8ClampedArray, 1, buffer, byte_offset, length, typedArray);
2899
1
      break;
2900
3
    case napi_int16_array:
2901

3
      CREATE_TYPED_ARRAY(
2902
          env, Int16Array, 2, buffer, byte_offset, length, typedArray);
2903
1
      break;
2904
3
    case napi_uint16_array:
2905

3
      CREATE_TYPED_ARRAY(
2906
          env, Uint16Array, 2, buffer, byte_offset, length, typedArray);
2907
1
      break;
2908
3
    case napi_int32_array:
2909

3
      CREATE_TYPED_ARRAY(
2910
          env, Int32Array, 4, buffer, byte_offset, length, typedArray);
2911
1
      break;
2912
3
    case napi_uint32_array:
2913

3
      CREATE_TYPED_ARRAY(
2914
          env, Uint32Array, 4, buffer, byte_offset, length, typedArray);
2915
1
      break;
2916
3
    case napi_float32_array:
2917

3
      CREATE_TYPED_ARRAY(
2918
          env, Float32Array, 4, buffer, byte_offset, length, typedArray);
2919
1
      break;
2920
4
    case napi_float64_array:
2921

4
      CREATE_TYPED_ARRAY(
2922
          env, Float64Array, 8, buffer, byte_offset, length, typedArray);
2923
2
      break;
2924
3
    case napi_bigint64_array:
2925

3
      CREATE_TYPED_ARRAY(
2926
          env, BigInt64Array, 8, buffer, byte_offset, length, typedArray);
2927
1
      break;
2928
3
    case napi_biguint64_array:
2929

3
      CREATE_TYPED_ARRAY(
2930
          env, BigUint64Array, 8, buffer, byte_offset, length, typedArray);
2931
1
      break;
2932
    default:
2933
      return napi_set_last_error(env, napi_invalid_arg);
2934
  }
2935
2936
15
  *result = v8impl::JsValueFromV8LocalValue(typedArray);
2937
15
  return GET_RETURN_STATUS(env);
2938
}
2939
2940
50
napi_status napi_get_typedarray_info(napi_env env,
2941
                                     napi_value typedarray,
2942
                                     napi_typedarray_type* type,
2943
                                     size_t* length,
2944
                                     void** data,
2945
                                     napi_value* arraybuffer,
2946
                                     size_t* byte_offset) {
2947
50
  CHECK_ENV(env);
2948
50
  CHECK_ARG(env, typedarray);
2949
2950
50
  v8::Local<v8::Value> value = v8impl::V8LocalValueFromJsValue(typedarray);
2951
50
  RETURN_STATUS_IF_FALSE(env, value->IsTypedArray(), napi_invalid_arg);
2952
2953
50
  v8::Local<v8::TypedArray> array = value.As<v8::TypedArray>();
2954
2955
50
  if (type != nullptr) {
2956
32
    if (value->IsInt8Array()) {
2957
2
      *type = napi_int8_array;
2958
30
    } else if (value->IsUint8Array()) {
2959
3
      *type = napi_uint8_array;
2960
27
    } else if (value->IsUint8ClampedArray()) {
2961
2
      *type = napi_uint8_clamped_array;
2962
25
    } else if (value->IsInt16Array()) {
2963
3
      *type = napi_int16_array;
2964
22
    } else if (value->IsUint16Array()) {
2965
3
      *type = napi_uint16_array;
2966
19
    } else if (value->IsInt32Array()) {
2967
3
      *type = napi_int32_array;
2968
16
    } else if (value->IsUint32Array()) {
2969
3
      *type = napi_uint32_array;
2970
13
    } else if (value->IsFloat32Array()) {
2971
3
      *type = napi_float32_array;
2972
10
    } else if (value->IsFloat64Array()) {
2973
4
      *type = napi_float64_array;
2974
6
    } else if (value->IsBigInt64Array()) {
2975
3
      *type = napi_bigint64_array;
2976
3
    } else if (value->IsBigUint64Array()) {
2977
3
      *type = napi_biguint64_array;
2978
    }
2979
  }
2980
2981
50
  if (length != nullptr) {
2982
32
    *length = array->Length();
2983
  }
2984
2985
  v8::Local<v8::ArrayBuffer> buffer;
2986

50
  if (data != nullptr || arraybuffer != nullptr) {
2987
    // Calling Buffer() may have the side effect of allocating the buffer,
2988
    // so only do this when it’s needed.
2989
50
    buffer = array->Buffer();
2990
  }
2991
2992
50
  if (data != nullptr) {
2993
    *data = static_cast<uint8_t*>(buffer->GetBackingStore()->Data()) +
2994
            array->ByteOffset();
2995
  }
2996
2997
50
  if (arraybuffer != nullptr) {
2998
50
    *arraybuffer = v8impl::JsValueFromV8LocalValue(buffer);
2999
  }
3000
3001
50
  if (byte_offset != nullptr) {
3002
32
    *byte_offset = array->ByteOffset();
3003
  }
3004
3005
50
  return napi_clear_last_error(env);
3006
}
3007
3008
2
napi_status napi_create_dataview(napi_env env,
3009
                                 size_t byte_length,
3010
                                 napi_value arraybuffer,
3011
                                 size_t byte_offset,
3012
                                 napi_value* result) {
3013


4
  NAPI_PREAMBLE(env);
3014
2
  CHECK_ARG(env, arraybuffer);
3015
2
  CHECK_ARG(env, result);
3016
3017
2
  v8::Local<v8::Value> value = v8impl::V8LocalValueFromJsValue(arraybuffer);
3018
2
  RETURN_STATUS_IF_FALSE(env, value->IsArrayBuffer(), napi_invalid_arg);
3019
3020
2
  v8::Local<v8::ArrayBuffer> buffer = value.As<v8::ArrayBuffer>();
3021
2
  if (byte_length + byte_offset > buffer->ByteLength()) {
3022
1
    napi_throw_range_error(
3023
        env,
3024
        "ERR_NAPI_INVALID_DATAVIEW_ARGS",
3025
        "byte_offset + byte_length should be less than or "
3026
        "equal to the size in bytes of the array passed in");
3027
1
    return napi_set_last_error(env, napi_pending_exception);
3028
  }
3029
  v8::Local<v8::DataView> DataView = v8::DataView::New(buffer, byte_offset,
3030
1
                                                       byte_length);
3031
3032
1
  *result = v8impl::JsValueFromV8LocalValue(DataView);
3033
1
  return GET_RETURN_STATUS(env);
3034
}
3035
3036
1
napi_status napi_is_dataview(napi_env env, napi_value value, bool* result) {
3037
1
  CHECK_ENV(env);
3038
1
  CHECK_ARG(env, value);
3039
1
  CHECK_ARG(env, result);
3040
3041
1
  v8::Local<v8::Value> val = v8impl::V8LocalValueFromJsValue(value);
3042
1
  *result = val->IsDataView();
3043
3044
1
  return napi_clear_last_error(env);
3045
}
3046
3047
1
napi_status napi_get_dataview_info(napi_env env,
3048
                                   napi_value dataview,
3049
                                   size_t* byte_length,
3050
                                   void** data,
3051
                                   napi_value* arraybuffer,
3052
                                   size_t* byte_offset) {
3053
1
  CHECK_ENV(env);
3054
1
  CHECK_ARG(env, dataview);
3055
3056
1
  v8::Local<v8::Value> value = v8impl::V8LocalValueFromJsValue(dataview);
3057
1
  RETURN_STATUS_IF_FALSE(env, value->IsDataView(), napi_invalid_arg);
3058
3059
1
  v8::Local<v8::DataView> array = value.As<v8::DataView>();
3060
3061
1
  if (byte_length != nullptr) {
3062
1
    *byte_length = array->ByteLength();
3063
  }
3064
3065
  v8::Local<v8::ArrayBuffer> buffer;
3066

1
  if (data != nullptr || arraybuffer != nullptr) {
3067
    // Calling Buffer() may have the side effect of allocating the buffer,
3068
    // so only do this when it’s needed.
3069
1
    buffer = array->Buffer();
3070
  }
3071
3072
1
  if (data != nullptr) {
3073
    *data = static_cast<uint8_t*>(buffer->GetBackingStore()->Data()) +
3074
            array->ByteOffset();
3075
  }
3076
3077
1
  if (arraybuffer != nullptr) {
3078
1
    *arraybuffer = v8impl::JsValueFromV8LocalValue(buffer);
3079
  }
3080
3081
1
  if (byte_offset != nullptr) {
3082
1
    *byte_offset = array->ByteOffset();
3083
  }
3084
3085
1
  return napi_clear_last_error(env);
3086
}
3087
3088
1
napi_status napi_get_version(napi_env env, uint32_t* result) {
3089
1
  CHECK_ENV(env);
3090
1
  CHECK_ARG(env, result);
3091
1
  *result = NAPI_VERSION;
3092
1
  return napi_clear_last_error(env);
3093
}
3094
3095
5
napi_status napi_create_promise(napi_env env,
3096
                                napi_deferred* deferred,
3097
                                napi_value* promise) {
3098


10
  NAPI_PREAMBLE(env);
3099
5
  CHECK_ARG(env, deferred);
3100
5
  CHECK_ARG(env, promise);
3101
3102
5
  auto maybe = v8::Promise::Resolver::New(env->context());
3103
5
  CHECK_MAYBE_EMPTY(env, maybe, napi_generic_failure);
3104
3105
5
  auto v8_resolver = maybe.ToLocalChecked();
3106
5
  auto v8_deferred = new v8impl::Persistent<v8::Value>();
3107
5
  v8_deferred->Reset(env->isolate, v8_resolver);
3108
3109
5
  *deferred = v8impl::JsDeferredFromNodePersistent(v8_deferred);
3110
10
  *promise = v8impl::JsValueFromV8LocalValue(v8_resolver->GetPromise());
3111
5
  return GET_RETURN_STATUS(env);
3112
}
3113
3114
4
napi_status napi_resolve_deferred(napi_env env,
3115
                                  napi_deferred deferred,
3116
                                  napi_value resolution) {
3117
4
  return v8impl::ConcludeDeferred(env, deferred, resolution, true);
3118
}
3119
3120
1
napi_status napi_reject_deferred(napi_env env,
3121
                                 napi_deferred deferred,
3122
                                 napi_value resolution) {
3123
1
  return v8impl::ConcludeDeferred(env, deferred, resolution, false);
3124
}
3125
3126
7
napi_status napi_is_promise(napi_env env,
3127
                            napi_value value,
3128
                            bool* is_promise) {
3129
7
  CHECK_ENV(env);
3130
7
  CHECK_ARG(env, value);
3131
7
  CHECK_ARG(env, is_promise);
3132
3133
14
  *is_promise = v8impl::V8LocalValueFromJsValue(value)->IsPromise();
3134
3135
7
  return napi_clear_last_error(env);
3136
}
3137
3138
1
napi_status napi_create_date(napi_env env,
3139
                             double time,
3140
                             napi_value* result) {
3141


2
  NAPI_PREAMBLE(env);
3142
1
  CHECK_ARG(env, result);
3143
3144
1
  v8::MaybeLocal<v8::Value> maybe_date = v8::Date::New(env->context(), time);
3145
1
  CHECK_MAYBE_EMPTY(env, maybe_date, napi_generic_failure);
3146
3147
1
  *result = v8impl::JsValueFromV8LocalValue(maybe_date.ToLocalChecked());
3148
3149
1
  return GET_RETURN_STATUS(env);
3150
}
3151
3152
7
napi_status napi_is_date(napi_env env,
3153
                         napi_value value,
3154
                         bool* is_date) {
3155
7
  CHECK_ENV(env);
3156
7
  CHECK_ARG(env, value);
3157
7
  CHECK_ARG(env, is_date);
3158
3159
14
  *is_date = v8impl::V8LocalValueFromJsValue(value)->IsDate();
3160
3161
7
  return napi_clear_last_error(env);
3162
}
3163
3164
1
napi_status napi_get_date_value(napi_env env,
3165
                                napi_value value,
3166
                                double* result) {
3167


2
  NAPI_PREAMBLE(env);
3168
1
  CHECK_ARG(env, value);
3169
1
  CHECK_ARG(env, result);
3170
3171
1
  v8::Local<v8::Value> val = v8impl::V8LocalValueFromJsValue(value);
3172
1
  RETURN_STATUS_IF_FALSE(env, val->IsDate(), napi_date_expected);
3173
3174
1
  v8::Local<v8::Date> date = val.As<v8::Date>();
3175
1
  *result = date->ValueOf();
3176
3177
1
  return GET_RETURN_STATUS(env);
3178
}
3179
3180
2
napi_status napi_run_script(napi_env env,
3181
                            napi_value script,
3182
                            napi_value* result) {
3183


4
  NAPI_PREAMBLE(env);
3184
2
  CHECK_ARG(env, script);
3185
2
  CHECK_ARG(env, result);
3186
3187
2
  v8::Local<v8::Value> v8_script = v8impl::V8LocalValueFromJsValue(script);
3188
3189
4
  if (!v8_script->IsString()) {
3190
1
    return napi_set_last_error(env, napi_string_expected);
3191
  }
3192
3193
1
  v8::Local<v8::Context> context = env->context();
3194
3195
1
  auto maybe_script = v8::Script::Compile(context, v8_script.As<v8::String>());
3196
1
  CHECK_MAYBE_EMPTY(env, maybe_script, napi_generic_failure);
3197
3198
  auto script_result =
3199
1
      maybe_script.ToLocalChecked()->Run(context);
3200
1
  CHECK_MAYBE_EMPTY(env, script_result, napi_generic_failure);
3201
3202
1
  *result = v8impl::JsValueFromV8LocalValue(script_result.ToLocalChecked());
3203
1
  return GET_RETURN_STATUS(env);
3204
}
3205
3206
4
napi_status napi_add_finalizer(napi_env env,
3207
                               napi_value js_object,
3208
                               void* native_object,
3209
                               napi_finalize finalize_cb,
3210
                               void* finalize_hint,
3211
                               napi_ref* result) {
3212
4
  return v8impl::Wrap<v8impl::anonymous>(env,
3213
                                         js_object,
3214
                                         native_object,
3215
                                         finalize_cb,
3216
                                         finalize_hint,
3217
4
                                         result);
3218
}
3219
3220
1
napi_status napi_adjust_external_memory(napi_env env,
3221
                                        int64_t change_in_bytes,
3222
                                        int64_t* adjusted_value) {
3223
1
  CHECK_ENV(env);
3224
1
  CHECK_ARG(env, adjusted_value);
3225
3226
1
  *adjusted_value = env->isolate->AdjustAmountOfExternalAllocatedMemory(
3227
      change_in_bytes);
3228
3229
1
  return napi_clear_last_error(env);
3230
}
3231
3232
7
napi_status napi_set_instance_data(napi_env env,
3233
                                   void* data,
3234
                                   napi_finalize finalize_cb,
3235
                                   void* finalize_hint) {
3236
7
  CHECK_ENV(env);
3237
3238
7
  v8impl::RefBase* old_data = static_cast<v8impl::RefBase*>(env->instance_data);
3239
7
  if (old_data != nullptr) {
3240
    // Our contract so far has been to not finalize any old data there may be.
3241
    // So we simply delete it.
3242
    v8impl::RefBase::Delete(old_data);
3243
  }
3244
3245
7
  env->instance_data = v8impl::RefBase::New(env,
3246
                                            0,
3247
                                            true,
3248
                                            finalize_cb,
3249
                                            data,
3250
                                            finalize_hint);
3251
3252
7
  return napi_clear_last_error(env);
3253
}
3254
3255
22
napi_status napi_get_instance_data(napi_env env,
3256
                                   void** data) {
3257
22
  CHECK_ENV(env);
3258
22
  CHECK_ARG(env, data);
3259
3260
22
  v8impl::RefBase* idata = static_cast<v8impl::RefBase*>(env->instance_data);
3261
3262
22
  *data = (idata == nullptr ? nullptr : idata->Data());
3263
3264
22
  return napi_clear_last_error(env);
3265
}
3266
3267
12
napi_status napi_detach_arraybuffer(napi_env env, napi_value arraybuffer) {
3268
12
  CHECK_ENV(env);
3269
12
  CHECK_ARG(env, arraybuffer);
3270
3271
12
  v8::Local<v8::Value> value = v8impl::V8LocalValueFromJsValue(arraybuffer);
3272
12
  RETURN_STATUS_IF_FALSE(
3273
      env, value->IsArrayBuffer(), napi_arraybuffer_expected);
3274
3275
12
  v8::Local<v8::ArrayBuffer> it = value.As<v8::ArrayBuffer>();
3276
12
  RETURN_STATUS_IF_FALSE(
3277
      env, it->IsDetachable(), napi_detachable_arraybuffer_expected);
3278
3279
12
  it->Detach();
3280
3281
12
  return napi_clear_last_error(env);
3282
}
3283
3284
26
napi_status napi_is_detached_arraybuffer(napi_env env,
3285
                                         napi_value arraybuffer,
3286
                                         bool* result) {
3287
26
  CHECK_ENV(env);
3288
26
  CHECK_ARG(env, arraybuffer);
3289
26
  CHECK_ARG(env, result);
3290
3291
26
  v8::Local<v8::Value> value = v8impl::V8LocalValueFromJsValue(arraybuffer);
3292
3293

52
  *result = value->IsArrayBuffer() &&
3294