GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: js_native_api_v8.cc Lines: 1414 1444 97.9 %
Date: 2022-12-31 04:22:30 Branches: 1129 1772 63.7 %

Line Branch Exec Source
1
#include <algorithm>
2
#include <climits>  // INT_MAX
3
#include <cmath>
4
#define NAPI_EXPERIMENTAL
5
#include "env-inl.h"
6
#include "js_native_api.h"
7
#include "js_native_api_v8.h"
8
#include "util-inl.h"
9
10
#define CHECK_MAYBE_NOTHING(env, maybe, status)                                \
11
  RETURN_STATUS_IF_FALSE((env), !((maybe).IsNothing()), (status))
12
13
#define CHECK_MAYBE_NOTHING_WITH_PREAMBLE(env, maybe, status)                  \
14
  RETURN_STATUS_IF_FALSE_WITH_PREAMBLE((env), !((maybe).IsNothing()), (status))
15
16
#define CHECK_TO_NUMBER(env, context, result, src)                             \
17
  CHECK_TO_TYPE((env), Number, (context), (result), (src), napi_number_expected)
18
19
// n-api defines NAPI_AUTO_LENGTH as the indicator that a string
20
// is null terminated. For V8 the equivalent is -1. The assert
21
// validates that our cast of NAPI_AUTO_LENGTH results in -1 as
22
// needed by V8.
23
#define CHECK_NEW_FROM_UTF8_LEN(env, result, str, len)                         \
24
  do {                                                                         \
25
    static_assert(static_cast<int>(NAPI_AUTO_LENGTH) == -1,                    \
26
                  "Casting NAPI_AUTO_LENGTH to int must result in -1");        \
27
    RETURN_STATUS_IF_FALSE(                                                    \
28
        (env), (len == NAPI_AUTO_LENGTH) || len <= INT_MAX, napi_invalid_arg); \
29
    RETURN_STATUS_IF_FALSE((env), (str) != nullptr, napi_invalid_arg);         \
30
    auto str_maybe = v8::String::NewFromUtf8((env)->isolate,                   \
31
                                             (str),                            \
32
                                             v8::NewStringType::kInternalized, \
33
                                             static_cast<int>(len));           \
34
    CHECK_MAYBE_EMPTY((env), str_maybe, napi_generic_failure);                 \
35
    (result) = str_maybe.ToLocalChecked();                                     \
36
  } while (0)
37
38
#define CHECK_NEW_FROM_UTF8(env, result, str)                                  \
39
  CHECK_NEW_FROM_UTF8_LEN((env), (result), (str), NAPI_AUTO_LENGTH)
40
41
#define CREATE_TYPED_ARRAY(                                                    \
42
    env, type, size_of_element, buffer, byte_offset, length, out)              \
43
  do {                                                                         \
44
    if ((size_of_element) > 1) {                                               \
45
      THROW_RANGE_ERROR_IF_FALSE(                                              \
46
          (env),                                                               \
47
          (byte_offset) % (size_of_element) == 0,                              \
48
          "ERR_NAPI_INVALID_TYPEDARRAY_ALIGNMENT",                             \
49
          "start offset of " #type                                             \
50
          " should be a multiple of " #size_of_element);                       \
51
    }                                                                          \
52
    THROW_RANGE_ERROR_IF_FALSE(                                                \
53
        (env),                                                                 \
54
        (length) * (size_of_element) + (byte_offset) <= buffer->ByteLength(),  \
55
        "ERR_NAPI_INVALID_TYPEDARRAY_LENGTH",                                  \
56
        "Invalid typed array length");                                         \
57
    (out) = v8::type::New((buffer), (byte_offset), (length));                  \
58
  } while (0)
59
60
namespace v8impl {
61
62
namespace {
63
64
549
inline napi_status V8NameFromPropertyDescriptor(
65
    napi_env env,
66
    const napi_property_descriptor* p,
67
    v8::Local<v8::Name>* result) {
68
549
  if (p->utf8name != nullptr) {
69

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

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


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

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


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

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


4132
  NAPI_PREAMBLE(env);
414
2066
  CHECK_ARG(env, js_object);
415
416
2066
  v8::Local<v8::Context> context = env->context();
417
418
2066
  v8::Local<v8::Value> value = v8impl::V8LocalValueFromJsValue(js_object);
419
2066
  RETURN_STATUS_IF_FALSE(env, value->IsObject(), napi_invalid_arg);
420
2066
  v8::Local<v8::Object> obj = value.As<v8::Object>();
421
422
  if (wrap_type == retrievable) {
423
    // If we've already wrapped this object, we error out.
424
4120
    RETURN_STATUS_IF_FALSE(
425
        env,
426
        !obj->HasPrivate(context, NAPI_PRIVATE_KEY(context, wrapper))
427
             .FromJust(),
428
        napi_invalid_arg);
429
  } else if (wrap_type == anonymous) {
430
    // If no finalize callback is provided, we error out.
431
6
    CHECK_ARG(env, finalize_cb);
432
  }
433
434
2064
  v8impl::Reference* reference = nullptr;
435
2064
  if (result != nullptr) {
436
    // The returned reference should be deleted via napi_delete_reference()
437
    // ONLY in response to the finalize callback invocation. (If it is deleted
438
    // before then, then the finalize callback will never be invoked.)
439
    // Therefore a finalize callback is required when returning a reference.
440
26
    CHECK_ARG(env, finalize_cb);
441
26
    reference = v8impl::Reference::New(env,
442
                                       obj,
443
                                       0,
444
                                       v8impl::Ownership::kUserland,
445
                                       finalize_cb,
446
                                       native_object,
447
                                       finalize_hint);
448
26
    *result = reinterpret_cast<napi_ref>(reference);
449
  } else {
450
    // Create a self-deleting reference.
451
2038
    reference = v8impl::Reference::New(
452
        env,
453
        obj,
454
        0,
455
        v8impl::Ownership::kRuntime,
456
        finalize_cb,
457
        native_object,
458
2038
        finalize_cb == nullptr ? nullptr : finalize_hint);
459
  }
460
461
  if (wrap_type == retrievable) {
462
6174
    CHECK(obj->SetPrivate(context,
463
                          NAPI_PRIVATE_KEY(context, wrapper),
464
                          v8::External::New(env->isolate, reference))
465
              .FromJust());
466
  }
467
468
2064
  return GET_RETURN_STATUS(env);
469
}
470
471
}  // end of anonymous namespace
472
473
2102
void Finalizer::ResetFinalizer() {
474
2102
  finalize_callback_ = nullptr;
475
2102
  finalize_data_ = nullptr;
476
2102
  finalize_hint_ = nullptr;
477
2102
}
478
479
// Wrapper around v8impl::Persistent that implements reference counting.
480
3146
RefBase::RefBase(napi_env env,
481
                 uint32_t initial_refcount,
482
                 Ownership ownership,
483
                 napi_finalize finalize_callback,
484
                 void* finalize_data,
485
3146
                 void* finalize_hint)
486
    : Finalizer(env, finalize_callback, finalize_data, finalize_hint),
487
      refcount_(initial_refcount),
488
3146
      ownership_(ownership) {
489
3146
  Link(finalize_callback == nullptr ? &env->reflist : &env->finalizing_reflist);
490
3146
}
491
492
// When a RefBase is being deleted, it may have been queued to call its
493
// finalizer.
494
6262
RefBase::~RefBase() {
495
  // Remove from the env's tracked list.
496
6248
  Unlink();
497
  // Try to remove the finalizer from the scheduled second pass callback.
498
6248
  env_->DequeueFinalizer(this);
499
6262
}
500
501
7
RefBase* RefBase::New(napi_env env,
502
                      uint32_t initial_refcount,
503
                      Ownership ownership,
504
                      napi_finalize finalize_callback,
505
                      void* finalize_data,
506
                      void* finalize_hint) {
507
  return new RefBase(env,
508
                     initial_refcount,
509
                     ownership,
510
                     finalize_callback,
511
                     finalize_data,
512
7
                     finalize_hint);
513
}
514
515
57
void* RefBase::Data() {
516
57
  return finalize_data_;
517
}
518
519
3
uint32_t RefBase::Ref() {
520
3
  return ++refcount_;
521
}
522
523
3
uint32_t RefBase::Unref() {
524
3
  if (refcount_ == 0) {
525
    return 0;
526
  }
527
3
  return --refcount_;
528
}
529
530
3145
uint32_t RefBase::RefCount() {
531
3145
  return refcount_;
532
}
533
534
2100
void RefBase::Finalize() {
535
2100
  Ownership ownership = ownership_;
536
  // Swap out the field finalize_callback so that it can not be accidentally
537
  // called more than once.
538
2100
  napi_finalize finalize_callback = finalize_callback_;
539
2100
  void* finalize_data = finalize_data_;
540
2100
  void* finalize_hint = finalize_hint_;
541
2100
  ResetFinalizer();
542
543
  // Either the RefBase is going to be deleted in the finalize_callback or not,
544
  // it should be removed from the tracked list.
545
2100
  Unlink();
546
  // 1. If the finalize_callback is present, it should either delete the
547
  //    RefBase, or set ownership with Ownership::kRuntime.
548
  // 2. If the finalizer is not present, the RefBase can be deleted after the
549
  //    call.
550
2100
  if (finalize_callback != nullptr) {
551
1575
    env_->CallFinalizer(finalize_callback, finalize_data, finalize_hint);
552
    // No access to `this` after finalize_callback is called.
553
  }
554
555
  // If the RefBase is not Ownership::kRuntime, userland code should delete it.
556
  // Now delete it if it is Ownership::kRuntime.
557
2099
  if (ownership == Ownership::kRuntime) {
558
1567
    delete this;
559
  }
560
2099
}
561
562
template <typename... Args>
563
3139
Reference::Reference(napi_env env, v8::Local<v8::Value> value, Args&&... args)
564
15695
    : RefBase(env, std::forward<Args>(args)...),
565
3139
      persistent_(env->isolate, value) {
566
3139
  if (RefCount() == 0) {
567
2595
    SetWeak();
568
  }
569
3139
}
570
571
18702
Reference::~Reference() {
572
  // Reset the handle. And no weak callback will be invoked.
573
6234
  persistent_.Reset();
574
12468
}
575
576
3139
Reference* Reference::New(napi_env env,
577
                          v8::Local<v8::Value> value,
578
                          uint32_t initial_refcount,
579
                          Ownership ownership,
580
                          napi_finalize finalize_callback,
581
                          void* finalize_data,
582
                          void* finalize_hint) {
583
  return new Reference(env,
584
                       value,
585
                       initial_refcount,
586
                       ownership,
587
                       finalize_callback,
588
                       finalize_data,
589
3139
                       finalize_hint);
590
}
591
592
3
uint32_t Reference::Ref() {
593
  // When the persistent_ is cleared in the WeakCallback, and a second pass
594
  // callback is pending, return 0 unconditionally.
595
3
  if (persistent_.IsEmpty()) {
596
    return 0;
597
  }
598
3
  uint32_t refcount = RefBase::Ref();
599
3
  if (refcount == 1) {
600
2
    persistent_.ClearWeak();
601
  }
602
3
  return refcount;
603
}
604
605
3
uint32_t Reference::Unref() {
606
  // When the persistent_ is cleared in the WeakCallback, and a second pass
607
  // callback is pending, return 0 unconditionally.
608
3
  if (persistent_.IsEmpty()) {
609
    return 0;
610
  }
611
3
  uint32_t old_refcount = RefCount();
612
3
  uint32_t refcount = RefBase::Unref();
613

3
  if (old_refcount == 1 && refcount == 0) {
614
2
    SetWeak();
615
  }
616
3
  return refcount;
617
}
618
619
11551
v8::Local<v8::Value> Reference::Get() {
620
11551
  if (persistent_.IsEmpty()) {
621
1003
    return v8::Local<v8::Value>();
622
  } else {
623
21096
    return v8::Local<v8::Value>::New(env_->isolate, persistent_);
624
  }
625
}
626
627
2093
void Reference::Finalize() {
628
  // Unconditionally reset the persistent handle so that no weak callback will
629
  // be invoked again.
630
2093
  persistent_.Reset();
631
632
  // Chain up to perform the rest of the finalization.
633
2093
  RefBase::Finalize();
634
2092
}
635
636
// Mark the reference as weak and eligible for collection
637
// by the gc.
638
2597
void Reference::SetWeak() {
639
2597
  persistent_.SetWeak(this, WeakCallback, v8::WeakCallbackType::kParameter);
640
2597
}
641
642
// The N-API finalizer callback may make calls into the engine. V8's heap is
643
// not in a consistent state during the weak callback, and therefore it does
644
// not support calls back into it. Enqueue the invocation of the finalizer.
645
2024
void Reference::WeakCallback(const v8::WeakCallbackInfo<Reference>& data) {
646
2024
  Reference* reference = data.GetParameter();
647
  // The reference must be reset during the weak callback as the API protocol.
648
2024
  reference->persistent_.Reset();
649
2024
  reference->env_->EnqueueFinalizer(reference);
650
2024
}
651
652
}  // end of namespace v8impl
653
654
// Warning: Keep in-sync with napi_status enum
655
static const char* error_messages[] = {
656
    nullptr,
657
    "Invalid argument",
658
    "An object was expected",
659
    "A string was expected",
660
    "A string or symbol was expected",
661
    "A function was expected",
662
    "A number was expected",
663
    "A boolean was expected",
664
    "An array was expected",
665
    "Unknown failure",
666
    "An exception is pending",
667
    "The async work item was cancelled",
668
    "napi_escape_handle already called on scope",
669
    "Invalid handle scope usage",
670
    "Invalid callback scope usage",
671
    "Thread-safe function queue is full",
672
    "Thread-safe function handle is closing",
673
    "A bigint was expected",
674
    "A date was expected",
675
    "An arraybuffer was expected",
676
    "A detachable arraybuffer was expected",
677
    "Main thread would deadlock",
678
    "External buffers are not allowed",
679
};
680
681
1318
napi_status NAPI_CDECL napi_get_last_error_info(
682
    napi_env env, const napi_extended_error_info** result) {
683
1318
  CHECK_ENV(env);
684
1318
  CHECK_ARG(env, result);
685
686
  // The value of the constant below must be updated to reference the last
687
  // message in the `napi_status` enum each time a new error message is added.
688
  // We don't have a napi_status_last as this would result in an ABI
689
  // change each time a message was added.
690
1318
  const int last_status = napi_no_external_buffers_allowed;
691
692
  static_assert(NAPI_ARRAYSIZE(error_messages) == last_status + 1,
693
                "Count of error messages must match count of error values");
694
1318
  CHECK_LE(env->last_error.error_code, last_status);
695
  // Wait until someone requests the last error information to fetch the error
696
  // message string
697
1318
  env->last_error.error_message = error_messages[env->last_error.error_code];
698
699
1318
  if (env->last_error.error_code == napi_ok) {
700
10
    napi_clear_last_error(env);
701
  }
702
1318
  *result = &(env->last_error);
703
1318
  return napi_ok;
704
}
705
706
15
napi_status NAPI_CDECL napi_create_function(napi_env env,
707
                                            const char* utf8name,
708
                                            size_t length,
709
                                            napi_callback cb,
710
                                            void* callback_data,
711
                                            napi_value* result) {
712


30
  NAPI_PREAMBLE(env);
713
15
  CHECK_ARG(env, result);
714
15
  CHECK_ARG(env, cb);
715
716
  v8::Local<v8::Function> return_value;
717
15
  v8::EscapableHandleScope scope(env->isolate);
718
  v8::Local<v8::Function> fn;
719
15
  STATUS_CALL(v8impl::FunctionCallbackWrapper::NewFunction(
720
      env, cb, callback_data, &fn));
721
15
  return_value = scope.Escape(fn);
722
723
15
  if (utf8name != nullptr) {
724
    v8::Local<v8::String> name_string;
725


9
    CHECK_NEW_FROM_UTF8_LEN(env, name_string, utf8name, length);
726
3
    return_value->SetName(name_string);
727
  }
728
729
15
  *result = v8impl::JsValueFromV8LocalValue(return_value);
730
731
15
  return GET_RETURN_STATUS(env);
732
}
733
734
napi_status NAPI_CDECL
735
17
napi_define_class(napi_env env,
736
                  const char* utf8name,
737
                  size_t length,
738
                  napi_callback constructor,
739
                  void* callback_data,
740
                  size_t property_count,
741
                  const napi_property_descriptor* properties,
742
                  napi_value* result) {
743


33
  NAPI_PREAMBLE(env);
744
16
  CHECK_ARG(env, result);
745
15
  CHECK_ARG(env, constructor);
746
747
14
  if (property_count > 0) {
748
8
    CHECK_ARG(env, properties);
749
  }
750
751
13
  v8::Isolate* isolate = env->isolate;
752
753
13
  v8::EscapableHandleScope scope(isolate);
754
  v8::Local<v8::FunctionTemplate> tpl;
755
13
  STATUS_CALL(v8impl::FunctionCallbackWrapper::NewTemplate(
756
      env, constructor, callback_data, &tpl));
757
758
  v8::Local<v8::String> name_string;
759


37
  CHECK_NEW_FROM_UTF8_LEN(env, name_string, utf8name, length);
760
12
  tpl->SetClassName(name_string);
761
762
12
  size_t static_property_count = 0;
763
44
  for (size_t i = 0; i < property_count; i++) {
764
32
    const napi_property_descriptor* p = properties + i;
765
766
32
    if ((p->attributes & napi_static) != 0) {
767
      // Static properties are handled separately below.
768
7
      static_property_count++;
769
7
      continue;
770
    }
771
772
    v8::Local<v8::Name> property_name;
773
25
    STATUS_CALL(v8impl::V8NameFromPropertyDescriptor(env, p, &property_name));
774
775
    v8::PropertyAttribute attributes =
776
25
        v8impl::V8PropertyAttributesFromDescriptor(p);
777
778
    // This code is similar to that in napi_define_properties(); the
779
    // difference is it applies to a template instead of an object,
780
    // and preferred PropertyAttribute for lack of PropertyDescriptor
781
    // support on ObjectTemplate.
782

25
    if (p->getter != nullptr || p->setter != nullptr) {
783
      v8::Local<v8::FunctionTemplate> getter_tpl;
784
      v8::Local<v8::FunctionTemplate> setter_tpl;
785
12
      if (p->getter != nullptr) {
786
12
        STATUS_CALL(v8impl::FunctionCallbackWrapper::NewTemplate(
787
            env, p->getter, p->data, &getter_tpl));
788
      }
789
12
      if (p->setter != nullptr) {
790
6
        STATUS_CALL(v8impl::FunctionCallbackWrapper::NewTemplate(
791
            env, p->setter, p->data, &setter_tpl));
792
      }
793
794
24
      tpl->PrototypeTemplate()->SetAccessorProperty(property_name,
795
                                                    getter_tpl,
796
                                                    setter_tpl,
797
                                                    attributes,
798
12
                                                    v8::AccessControl::DEFAULT);
799
13
    } else if (p->method != nullptr) {
800
      v8::Local<v8::FunctionTemplate> t;
801
7
      STATUS_CALL(v8impl::FunctionCallbackWrapper::NewTemplate(
802
          env, p->method, p->data, &t, v8::Signature::New(isolate, tpl)));
803
804
14
      tpl->PrototypeTemplate()->Set(property_name, t, attributes);
805
    } else {
806
6
      v8::Local<v8::Value> value = v8impl::V8LocalValueFromJsValue(p->value);
807
12
      tpl->PrototypeTemplate()->Set(property_name, value, attributes);
808
    }
809
  }
810
811
12
  v8::Local<v8::Context> context = env->context();
812
12
  *result = v8impl::JsValueFromV8LocalValue(
813
12
      scope.Escape(tpl->GetFunction(context).ToLocalChecked()));
814
815
12
  if (static_property_count > 0) {
816
3
    std::vector<napi_property_descriptor> static_descriptors;
817
3
    static_descriptors.reserve(static_property_count);
818
819
26
    for (size_t i = 0; i < property_count; i++) {
820
23
      const napi_property_descriptor* p = properties + i;
821
23
      if ((p->attributes & napi_static) != 0) {
822
7
        static_descriptors.push_back(*p);
823
      }
824
    }
825
826
3
    STATUS_CALL(napi_define_properties(
827
        env, *result, static_descriptors.size(), static_descriptors.data()));
828
  }
829
830
12
  return GET_RETURN_STATUS(env);
831
}
832
833
8
napi_status NAPI_CDECL napi_get_property_names(napi_env env,
834
                                               napi_value object,
835
                                               napi_value* result) {
836
8
  return napi_get_all_property_names(
837
      env,
838
      object,
839
      napi_key_include_prototypes,
840
      static_cast<napi_key_filter>(napi_key_enumerable | napi_key_skip_symbols),
841
      napi_key_numbers_to_strings,
842
8
      result);
843
}
844
845
napi_status NAPI_CDECL
846
16
napi_get_all_property_names(napi_env env,
847
                            napi_value object,
848
                            napi_key_collection_mode key_mode,
849
                            napi_key_filter key_filter,
850
                            napi_key_conversion key_conversion,
851
                            napi_value* result) {
852


30
  NAPI_PREAMBLE(env);
853
14
  CHECK_ARG(env, result);
854
855
12
  v8::Local<v8::Context> context = env->context();
856
  v8::Local<v8::Object> obj;
857

22
  CHECK_TO_OBJECT(env, context, obj, object);
858
859
10
  v8::PropertyFilter filter = v8::PropertyFilter::ALL_PROPERTIES;
860
10
  if (key_filter & napi_key_writable) {
861
2
    filter = static_cast<v8::PropertyFilter>(filter |
862
                                             v8::PropertyFilter::ONLY_WRITABLE);
863
  }
864
10
  if (key_filter & napi_key_enumerable) {
865
7
    filter = static_cast<v8::PropertyFilter>(
866
7
        filter | v8::PropertyFilter::ONLY_ENUMERABLE);
867
  }
868
10
  if (key_filter & napi_key_configurable) {
869
2
    filter = static_cast<v8::PropertyFilter>(
870
2
        filter | v8::PropertyFilter::ONLY_CONFIGURABLE);
871
  }
872
10
  if (key_filter & napi_key_skip_strings) {
873
1
    filter = static_cast<v8::PropertyFilter>(filter |
874
                                             v8::PropertyFilter::SKIP_STRINGS);
875
  }
876
10
  if (key_filter & napi_key_skip_symbols) {
877
5
    filter = static_cast<v8::PropertyFilter>(filter |
878
                                             v8::PropertyFilter::SKIP_SYMBOLS);
879
  }
880
  v8::KeyCollectionMode collection_mode;
881
  v8::KeyConversionMode conversion_mode;
882
883
10
  switch (key_mode) {
884
8
    case napi_key_include_prototypes:
885
8
      collection_mode = v8::KeyCollectionMode::kIncludePrototypes;
886
8
      break;
887
2
    case napi_key_own_only:
888
2
      collection_mode = v8::KeyCollectionMode::kOwnOnly;
889
2
      break;
890
    default:
891
      return napi_set_last_error(env, napi_invalid_arg);
892
  }
893
894
10
  switch (key_conversion) {
895
    case napi_key_keep_numbers:
896
      conversion_mode = v8::KeyConversionMode::kKeepNumbers;
897
      break;
898
10
    case napi_key_numbers_to_strings:
899
10
      conversion_mode = v8::KeyConversionMode::kConvertToString;
900
10
      break;
901
    default:
902
      return napi_set_last_error(env, napi_invalid_arg);
903
  }
904
905
  v8::MaybeLocal<v8::Array> maybe_all_propertynames =
906
      obj->GetPropertyNames(context,
907
                            collection_mode,
908
                            filter,
909
                            v8::IndexFilter::kIncludeIndices,
910
10
                            conversion_mode);
911
912

10
  CHECK_MAYBE_EMPTY_WITH_PREAMBLE(
913
      env, maybe_all_propertynames, napi_generic_failure);
914
915
20
  *result =
916
10
      v8impl::JsValueFromV8LocalValue(maybe_all_propertynames.ToLocalChecked());
917
10
  return GET_RETURN_STATUS(env);
918
}
919
920
27
napi_status NAPI_CDECL napi_set_property(napi_env env,
921
                                         napi_value object,
922
                                         napi_value key,
923
                                         napi_value value) {
924


52
  NAPI_PREAMBLE(env);
925
25
  CHECK_ARG(env, key);
926
22
  CHECK_ARG(env, value);
927
928
20
  v8::Local<v8::Context> context = env->context();
929
  v8::Local<v8::Object> obj;
930
931

38
  CHECK_TO_OBJECT(env, context, obj, object);
932
933
18
  v8::Local<v8::Value> k = v8impl::V8LocalValueFromJsValue(key);
934
18
  v8::Local<v8::Value> val = v8impl::V8LocalValueFromJsValue(value);
935
936
18
  v8::Maybe<bool> set_maybe = obj->Set(context, k, val);
937
938

36
  RETURN_STATUS_IF_FALSE(env, set_maybe.FromMaybe(false), napi_generic_failure);
939
18
  return GET_RETURN_STATUS(env);
940
}
941
942
16
napi_status NAPI_CDECL napi_has_property(napi_env env,
943
                                         napi_value object,
944
                                         napi_value key,
945
                                         bool* result) {
946


30
  NAPI_PREAMBLE(env);
947
14
  CHECK_ARG(env, result);
948
12
  CHECK_ARG(env, key);
949
950
10
  v8::Local<v8::Context> context = env->context();
951
  v8::Local<v8::Object> obj;
952
953

18
  CHECK_TO_OBJECT(env, context, obj, object);
954
955
8
  v8::Local<v8::Value> k = v8impl::V8LocalValueFromJsValue(key);
956
8
  v8::Maybe<bool> has_maybe = obj->Has(context, k);
957
958
8
  CHECK_MAYBE_NOTHING(env, has_maybe, napi_generic_failure);
959
960
8
  *result = has_maybe.FromMaybe(false);
961
8
  return GET_RETURN_STATUS(env);
962
}
963
964
34
napi_status NAPI_CDECL napi_get_property(napi_env env,
965
                                         napi_value object,
966
                                         napi_value key,
967
                                         napi_value* result) {
968


66
  NAPI_PREAMBLE(env);
969
32
  CHECK_ARG(env, key);
970
28
  CHECK_ARG(env, result);
971
972
26
  v8::Local<v8::Context> context = env->context();
973
26
  v8::Local<v8::Value> k = v8impl::V8LocalValueFromJsValue(key);
974
  v8::Local<v8::Object> obj;
975
976

74
  CHECK_TO_OBJECT(env, context, obj, object);
977
978
24
  auto get_maybe = obj->Get(context, k);
979
980
24
  CHECK_MAYBE_EMPTY(env, get_maybe, napi_generic_failure);
981
982
24
  v8::Local<v8::Value> val = get_maybe.ToLocalChecked();
983
24
  *result = v8impl::JsValueFromV8LocalValue(val);
984
24
  return GET_RETURN_STATUS(env);
985
}
986
987
9
napi_status NAPI_CDECL napi_delete_property(napi_env env,
988
                                            napi_value object,
989
                                            napi_value key,
990
                                            bool* result) {
991


17
  NAPI_PREAMBLE(env);
992
8
  CHECK_ARG(env, key);
993
994
7
  v8::Local<v8::Context> context = env->context();
995
7
  v8::Local<v8::Value> k = v8impl::V8LocalValueFromJsValue(key);
996
  v8::Local<v8::Object> obj;
997
998

19
  CHECK_TO_OBJECT(env, context, obj, object);
999
6
  v8::Maybe<bool> delete_maybe = obj->Delete(context, k);
1000
6
  CHECK_MAYBE_NOTHING(env, delete_maybe, napi_generic_failure);
1001
1002

11
  if (result != nullptr) *result = delete_maybe.FromMaybe(false);
1003
1004
6
  return GET_RETURN_STATUS(env);
1005
}
1006
1007
19
napi_status NAPI_CDECL napi_has_own_property(napi_env env,
1008
                                             napi_value object,
1009
                                             napi_value key,
1010
                                             bool* result) {
1011


37
  NAPI_PREAMBLE(env);
1012
18
  CHECK_ARG(env, key);
1013
17
  CHECK_ARG(env, result);
1014
1015
16
  v8::Local<v8::Context> context = env->context();
1016
  v8::Local<v8::Object> obj;
1017
1018

31
  CHECK_TO_OBJECT(env, context, obj, object);
1019
15
  v8::Local<v8::Value> k = v8impl::V8LocalValueFromJsValue(key);
1020
15
  RETURN_STATUS_IF_FALSE(env, k->IsName(), napi_name_expected);
1021
12
  v8::Maybe<bool> has_maybe = obj->HasOwnProperty(context, k.As<v8::Name>());
1022
6
  CHECK_MAYBE_NOTHING(env, has_maybe, napi_generic_failure);
1023
6
  *result = has_maybe.FromMaybe(false);
1024
1025
6
  return GET_RETURN_STATUS(env);
1026
}
1027
1028
170
napi_status NAPI_CDECL napi_set_named_property(napi_env env,
1029
                                               napi_value object,
1030
                                               const char* utf8name,
1031
                                               napi_value value) {
1032


339
  NAPI_PREAMBLE(env);
1033
169
  CHECK_ARG(env, value);
1034
1035
168
  v8::Local<v8::Context> context = env->context();
1036
  v8::Local<v8::Object> obj;
1037
1038

502
  CHECK_TO_OBJECT(env, context, obj, object);
1039
1040
  v8::Local<v8::Name> key;
1041

333
  CHECK_NEW_FROM_UTF8(env, key, utf8name);
1042
1043
166
  v8::Local<v8::Value> val = v8impl::V8LocalValueFromJsValue(value);
1044
1045
166
  v8::Maybe<bool> set_maybe = obj->Set(context, key, val);
1046
1047

332
  RETURN_STATUS_IF_FALSE(env, set_maybe.FromMaybe(false), napi_generic_failure);
1048
166
  return GET_RETURN_STATUS(env);
1049
}
1050
1051
9
napi_status NAPI_CDECL napi_has_named_property(napi_env env,
1052
                                               napi_value object,
1053
                                               const char* utf8name,
1054
                                               bool* result) {
1055


17
  NAPI_PREAMBLE(env);
1056
8
  CHECK_ARG(env, result);
1057
1058
7
  v8::Local<v8::Context> context = env->context();
1059
  v8::Local<v8::Object> obj;
1060
1061

19
  CHECK_TO_OBJECT(env, context, obj, object);
1062
1063
  v8::Local<v8::Name> key;
1064

16
  CHECK_NEW_FROM_UTF8(env, key, utf8name);
1065
1066
5
  v8::Maybe<bool> has_maybe = obj->Has(context, key);
1067
1068
5
  CHECK_MAYBE_NOTHING(env, has_maybe, napi_generic_failure);
1069
1070
5
  *result = has_maybe.FromMaybe(false);
1071
5
  return GET_RETURN_STATUS(env);
1072
}
1073
1074
6
napi_status NAPI_CDECL napi_get_named_property(napi_env env,
1075
                                               napi_value object,
1076
                                               const char* utf8name,
1077
                                               napi_value* result) {
1078


10
  NAPI_PREAMBLE(env);
1079
4
  CHECK_ARG(env, result);
1080
1081
3
  v8::Local<v8::Context> context = env->context();
1082
1083
  v8::Local<v8::Name> key;
1084

7
  CHECK_NEW_FROM_UTF8(env, key, utf8name);
1085
1086
  v8::Local<v8::Object> obj;
1087
1088

4
  CHECK_TO_OBJECT(env, context, obj, object);
1089
1090
1
  auto get_maybe = obj->Get(context, key);
1091
1092
1
  CHECK_MAYBE_EMPTY(env, get_maybe, napi_generic_failure);
1093
1094
1
  v8::Local<v8::Value> val = get_maybe.ToLocalChecked();
1095
1
  *result = v8impl::JsValueFromV8LocalValue(val);
1096
1
  return GET_RETURN_STATUS(env);
1097
}
1098
1099
13
napi_status NAPI_CDECL napi_set_element(napi_env env,
1100
                                        napi_value object,
1101
                                        uint32_t index,
1102
                                        napi_value value) {
1103


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

23
  CHECK_TO_OBJECT(env, context, obj, object);
1110
1111
11
  v8::Local<v8::Value> val = v8impl::V8LocalValueFromJsValue(value);
1112
11
  auto set_maybe = obj->Set(context, index, val);
1113
1114

22
  RETURN_STATUS_IF_FALSE(env, set_maybe.FromMaybe(false), napi_generic_failure);
1115
1116
11
  return GET_RETURN_STATUS(env);
1117
}
1118
1119
5
napi_status NAPI_CDECL napi_has_element(napi_env env,
1120
                                        napi_value object,
1121
                                        uint32_t index,
1122
                                        bool* result) {
1123


9
  NAPI_PREAMBLE(env);
1124
4
  CHECK_ARG(env, result);
1125
1126
3
  v8::Local<v8::Context> context = env->context();
1127
  v8::Local<v8::Object> obj;
1128
1129

7
  CHECK_TO_OBJECT(env, context, obj, object);
1130
1131
2
  v8::Maybe<bool> has_maybe = obj->Has(context, index);
1132
1133
2
  CHECK_MAYBE_NOTHING(env, has_maybe, napi_generic_failure);
1134
1135
2
  *result = has_maybe.FromMaybe(false);
1136
2
  return GET_RETURN_STATUS(env);
1137
}
1138
1139
28
napi_status NAPI_CDECL napi_get_element(napi_env env,
1140
                                        napi_value object,
1141
                                        uint32_t index,
1142
                                        napi_value* result) {
1143


55
  NAPI_PREAMBLE(env);
1144
27
  CHECK_ARG(env, result);
1145
1146
27
  v8::Local<v8::Context> context = env->context();
1147
  v8::Local<v8::Object> obj;
1148
1149

81
  CHECK_TO_OBJECT(env, context, obj, object);
1150
1151
27
  auto get_maybe = obj->Get(context, index);
1152
1153
27
  CHECK_MAYBE_EMPTY(env, get_maybe, napi_generic_failure);
1154
1155
27
  *result = v8impl::JsValueFromV8LocalValue(get_maybe.ToLocalChecked());
1156
27
  return GET_RETURN_STATUS(env);
1157
}
1158
1159
4
napi_status NAPI_CDECL napi_delete_element(napi_env env,
1160
                                           napi_value object,
1161
                                           uint32_t index,
1162
                                           bool* result) {
1163


7
  NAPI_PREAMBLE(env);
1164
1165
3
  v8::Local<v8::Context> context = env->context();
1166
  v8::Local<v8::Object> obj;
1167
1168

7
  CHECK_TO_OBJECT(env, context, obj, object);
1169
2
  v8::Maybe<bool> delete_maybe = obj->Delete(context, index);
1170
2
  CHECK_MAYBE_NOTHING(env, delete_maybe, napi_generic_failure);
1171
1172

3
  if (result != nullptr) *result = delete_maybe.FromMaybe(false);
1173
1174
2
  return GET_RETURN_STATUS(env);
1175
}
1176
1177
napi_status NAPI_CDECL
1178
95
napi_define_properties(napi_env env,
1179
                       napi_value object,
1180
                       size_t property_count,
1181
                       const napi_property_descriptor* properties) {
1182


189
  NAPI_PREAMBLE(env);
1183
94
  if (property_count > 0) {
1184
94
    CHECK_ARG(env, properties);
1185
  }
1186
1187
91
  v8::Local<v8::Context> context = env->context();
1188
1189
  v8::Local<v8::Object> obj;
1190

181
  CHECK_TO_OBJECT(env, context, obj, object);
1191
1192
614
  for (size_t i = 0; i < property_count; i++) {
1193
524
    const napi_property_descriptor* p = &properties[i];
1194
1195
    v8::Local<v8::Name> property_name;
1196
524
    STATUS_CALL(v8impl::V8NameFromPropertyDescriptor(env, p, &property_name));
1197
1198

524
    if (p->getter != nullptr || p->setter != nullptr) {
1199
      v8::Local<v8::Function> local_getter;
1200
      v8::Local<v8::Function> local_setter;
1201
1202
13
      if (p->getter != nullptr) {
1203
13
        STATUS_CALL(v8impl::FunctionCallbackWrapper::NewFunction(
1204
            env, p->getter, p->data, &local_getter));
1205
      }
1206
13
      if (p->setter != nullptr) {
1207
2
        STATUS_CALL(v8impl::FunctionCallbackWrapper::NewFunction(
1208
            env, p->setter, p->data, &local_setter));
1209
      }
1210
1211
13
      v8::PropertyDescriptor descriptor(local_getter, local_setter);
1212
13
      descriptor.set_enumerable((p->attributes & napi_enumerable) != 0);
1213
13
      descriptor.set_configurable((p->attributes & napi_configurable) != 0);
1214
1215
      auto define_maybe =
1216
13
          obj->DefineProperty(context, property_name, descriptor);
1217
1218

26
      if (!define_maybe.FromMaybe(false)) {
1219
        return napi_set_last_error(env, napi_invalid_arg);
1220
13
      }
1221
511
    } else if (p->method != nullptr) {
1222
      v8::Local<v8::Function> method;
1223
485
      STATUS_CALL(v8impl::FunctionCallbackWrapper::NewFunction(
1224
          env, p->method, p->data, &method));
1225
      v8::PropertyDescriptor descriptor(method,
1226
485
                                        (p->attributes & napi_writable) != 0);
1227
485
      descriptor.set_enumerable((p->attributes & napi_enumerable) != 0);
1228
485
      descriptor.set_configurable((p->attributes & napi_configurable) != 0);
1229
1230
      auto define_maybe =
1231
485
          obj->DefineProperty(context, property_name, descriptor);
1232
1233

970
      if (!define_maybe.FromMaybe(false)) {
1234
        return napi_set_last_error(env, napi_generic_failure);
1235
      }
1236
    } else {
1237
26
      v8::Local<v8::Value> value = v8impl::V8LocalValueFromJsValue(p->value);
1238
1239
      v8::PropertyDescriptor descriptor(value,
1240
26
                                        (p->attributes & napi_writable) != 0);
1241
26
      descriptor.set_enumerable((p->attributes & napi_enumerable) != 0);
1242
26
      descriptor.set_configurable((p->attributes & napi_configurable) != 0);
1243
1244
      auto define_maybe =
1245
26
          obj->DefineProperty(context, property_name, descriptor);
1246
1247

52
      if (!define_maybe.FromMaybe(false)) {
1248
        return napi_set_last_error(env, napi_invalid_arg);
1249
      }
1250
    }
1251
  }
1252
1253
90
  return GET_RETURN_STATUS(env);
1254
}
1255
1256
1
napi_status NAPI_CDECL napi_object_freeze(napi_env env, napi_value object) {
1257


2
  NAPI_PREAMBLE(env);
1258
1259
1
  v8::Local<v8::Context> context = env->context();
1260
  v8::Local<v8::Object> obj;
1261
1262

3
  CHECK_TO_OBJECT(env, context, obj, object);
1263
1264
  v8::Maybe<bool> set_frozen =
1265
1
      obj->SetIntegrityLevel(context, v8::IntegrityLevel::kFrozen);
1266
1267

2
  RETURN_STATUS_IF_FALSE_WITH_PREAMBLE(
1268
      env, set_frozen.FromMaybe(false), napi_generic_failure);
1269
1270
1
  return GET_RETURN_STATUS(env);
1271
}
1272
1273
1
napi_status NAPI_CDECL napi_object_seal(napi_env env, napi_value object) {
1274


2
  NAPI_PREAMBLE(env);
1275
1276
1
  v8::Local<v8::Context> context = env->context();
1277
  v8::Local<v8::Object> obj;
1278
1279

3
  CHECK_TO_OBJECT(env, context, obj, object);
1280
1281
  v8::Maybe<bool> set_sealed =
1282
1
      obj->SetIntegrityLevel(context, v8::IntegrityLevel::kSealed);
1283
1284

2
  RETURN_STATUS_IF_FALSE_WITH_PREAMBLE(
1285
      env, set_sealed.FromMaybe(false), napi_generic_failure);
1286
1287
1
  return GET_RETURN_STATUS(env);
1288
}
1289
1290
11
napi_status NAPI_CDECL napi_is_array(napi_env env,
1291
                                     napi_value value,
1292
                                     bool* result) {
1293
11
  CHECK_ENV(env);
1294
11
  CHECK_ARG(env, value);
1295
11
  CHECK_ARG(env, result);
1296
1297
11
  v8::Local<v8::Value> val = v8impl::V8LocalValueFromJsValue(value);
1298
1299
11
  *result = val->IsArray();
1300
11
  return napi_clear_last_error(env);
1301
}
1302
1303
13
napi_status NAPI_CDECL napi_get_array_length(napi_env env,
1304
                                             napi_value value,
1305
                                             uint32_t* result) {
1306


26
  NAPI_PREAMBLE(env);
1307
13
  CHECK_ARG(env, value);
1308
13
  CHECK_ARG(env, result);
1309
1310
13
  v8::Local<v8::Value> val = v8impl::V8LocalValueFromJsValue(value);
1311
13
  RETURN_STATUS_IF_FALSE(env, val->IsArray(), napi_array_expected);
1312
1313
13
  v8::Local<v8::Array> arr = val.As<v8::Array>();
1314
13
  *result = arr->Length();
1315
1316
13
  return GET_RETURN_STATUS(env);
1317
}
1318
1319
9
napi_status NAPI_CDECL napi_strict_equals(napi_env env,
1320
                                          napi_value lhs,
1321
                                          napi_value rhs,
1322
                                          bool* result) {
1323


18
  NAPI_PREAMBLE(env);
1324
9
  CHECK_ARG(env, lhs);
1325
9
  CHECK_ARG(env, rhs);
1326
9
  CHECK_ARG(env, result);
1327
1328
9
  v8::Local<v8::Value> a = v8impl::V8LocalValueFromJsValue(lhs);
1329
9
  v8::Local<v8::Value> b = v8impl::V8LocalValueFromJsValue(rhs);
1330
1331
9
  *result = a->StrictEquals(b);
1332
9
  return GET_RETURN_STATUS(env);
1333
}
1334
1335
7
napi_status NAPI_CDECL napi_get_prototype(napi_env env,
1336
                                          napi_value object,
1337
                                          napi_value* result) {
1338


13
  NAPI_PREAMBLE(env);
1339
6
  CHECK_ARG(env, result);
1340
1341
5
  v8::Local<v8::Context> context = env->context();
1342
1343
  v8::Local<v8::Object> obj;
1344

13
  CHECK_TO_OBJECT(env, context, obj, object);
1345
1346
4
  v8::Local<v8::Value> val = obj->GetPrototype();
1347
4
  *result = v8impl::JsValueFromV8LocalValue(val);
1348
4
  return GET_RETURN_STATUS(env);
1349
}
1350
1351
71
napi_status NAPI_CDECL napi_create_object(napi_env env, napi_value* result) {
1352
71
  CHECK_ENV(env);
1353
71
  CHECK_ARG(env, result);
1354
1355
142
  *result = v8impl::JsValueFromV8LocalValue(v8::Object::New(env->isolate));
1356
1357
71
  return napi_clear_last_error(env);
1358
}
1359
1360
1
napi_status NAPI_CDECL napi_create_array(napi_env env, napi_value* result) {
1361
1
  CHECK_ENV(env);
1362
1
  CHECK_ARG(env, result);
1363
1364
2
  *result = v8impl::JsValueFromV8LocalValue(v8::Array::New(env->isolate));
1365
1366
1
  return napi_clear_last_error(env);
1367
}
1368
1369
4
napi_status NAPI_CDECL napi_create_array_with_length(napi_env env,
1370
                                                     size_t length,
1371
                                                     napi_value* result) {
1372
4
  CHECK_ENV(env);
1373
4
  CHECK_ARG(env, result);
1374
1375
8
  *result =
1376
8
      v8impl::JsValueFromV8LocalValue(v8::Array::New(env->isolate, length));
1377
1378
4
  return napi_clear_last_error(env);
1379
}
1380
1381
16
napi_status NAPI_CDECL napi_create_string_latin1(napi_env env,
1382
                                                 const char* str,
1383
                                                 size_t length,
1384
                                                 napi_value* result) {
1385
16
  CHECK_ENV(env);
1386

15
  if (length > 0) CHECK_ARG(env, str);
1387
14
  CHECK_ARG(env, result);
1388

13
  RETURN_STATUS_IF_FALSE(
1389
      env, (length == NAPI_AUTO_LENGTH) || length <= INT_MAX, napi_invalid_arg);
1390
1391
12
  auto isolate = env->isolate;
1392
  auto str_maybe =
1393
      v8::String::NewFromOneByte(isolate,
1394
                                 reinterpret_cast<const uint8_t*>(str),
1395
                                 v8::NewStringType::kNormal,
1396
12
                                 length);
1397
12
  CHECK_MAYBE_EMPTY(env, str_maybe, napi_generic_failure);
1398
1399
12
  *result = v8impl::JsValueFromV8LocalValue(str_maybe.ToLocalChecked());
1400
12
  return napi_clear_last_error(env);
1401
}
1402
1403
749
napi_status NAPI_CDECL napi_create_string_utf8(napi_env env,
1404
                                               const char* str,
1405
                                               size_t length,
1406
                                               napi_value* result) {
1407
749
  CHECK_ENV(env);
1408

748
  if (length > 0) CHECK_ARG(env, str);
1409
746
  CHECK_ARG(env, result);
1410

745
  RETURN_STATUS_IF_FALSE(
1411
      env, (length == NAPI_AUTO_LENGTH) || length <= INT_MAX, napi_invalid_arg);
1412
1413
744
  auto isolate = env->isolate;
1414
  auto str_maybe = v8::String::NewFromUtf8(
1415
744
      isolate, str, v8::NewStringType::kNormal, static_cast<int>(length));
1416
744
  CHECK_MAYBE_EMPTY(env, str_maybe, napi_generic_failure);
1417
744
  *result = v8impl::JsValueFromV8LocalValue(str_maybe.ToLocalChecked());
1418
744
  return napi_clear_last_error(env);
1419
}
1420
1421
18
napi_status NAPI_CDECL napi_create_string_utf16(napi_env env,
1422
                                                const char16_t* str,
1423
                                                size_t length,
1424
                                                napi_value* result) {
1425
18
  CHECK_ENV(env);
1426

17
  if (length > 0) CHECK_ARG(env, str);
1427
16
  CHECK_ARG(env, result);
1428

15
  RETURN_STATUS_IF_FALSE(
1429
      env, (length == NAPI_AUTO_LENGTH) || length <= INT_MAX, napi_invalid_arg);
1430
1431
14
  auto isolate = env->isolate;
1432
  auto str_maybe =
1433
      v8::String::NewFromTwoByte(isolate,
1434
                                 reinterpret_cast<const uint16_t*>(str),
1435
                                 v8::NewStringType::kNormal,
1436
14
                                 length);
1437
14
  CHECK_MAYBE_EMPTY(env, str_maybe, napi_generic_failure);
1438
1439
14
  *result = v8impl::JsValueFromV8LocalValue(str_maybe.ToLocalChecked());
1440
14
  return napi_clear_last_error(env);
1441
}
1442
1443
71
napi_status NAPI_CDECL napi_create_double(napi_env env,
1444
                                          double value,
1445
                                          napi_value* result) {
1446
71
  CHECK_ENV(env);
1447
71
  CHECK_ARG(env, result);
1448
1449
142
  *result =
1450
142
      v8impl::JsValueFromV8LocalValue(v8::Number::New(env->isolate, value));
1451
1452
71
  return napi_clear_last_error(env);
1453
}
1454
1455
104076
napi_status NAPI_CDECL napi_create_int32(napi_env env,
1456
                                         int32_t value,
1457
                                         napi_value* result) {
1458
104076
  CHECK_ENV(env);
1459
104076
  CHECK_ARG(env, result);
1460
1461
208152
  *result =
1462
208152
      v8impl::JsValueFromV8LocalValue(v8::Integer::New(env->isolate, value));
1463
1464
104076
  return napi_clear_last_error(env);
1465
}
1466
1467
558
napi_status NAPI_CDECL napi_create_uint32(napi_env env,
1468
                                          uint32_t value,
1469
                                          napi_value* result) {
1470
558
  CHECK_ENV(env);
1471
558
  CHECK_ARG(env, result);
1472
1473
558
  *result = v8impl::JsValueFromV8LocalValue(
1474
558
      v8::Integer::NewFromUnsigned(env->isolate, value));
1475
1476
558
  return napi_clear_last_error(env);
1477
}
1478
1479
24
napi_status NAPI_CDECL napi_create_int64(napi_env env,
1480
                                         int64_t value,
1481
                                         napi_value* result) {
1482
24
  CHECK_ENV(env);
1483
24
  CHECK_ARG(env, result);
1484
1485
24
  *result = v8impl::JsValueFromV8LocalValue(
1486
24
      v8::Number::New(env->isolate, static_cast<double>(value)));
1487
1488
24
  return napi_clear_last_error(env);
1489
}
1490
1491
9
napi_status NAPI_CDECL napi_create_bigint_int64(napi_env env,
1492
                                                int64_t value,
1493
                                                napi_value* result) {
1494
9
  CHECK_ENV(env);
1495
9
  CHECK_ARG(env, result);
1496
1497
18
  *result =
1498
18
      v8impl::JsValueFromV8LocalValue(v8::BigInt::New(env->isolate, value));
1499
1500
9
  return napi_clear_last_error(env);
1501
}
1502
1503
6
napi_status NAPI_CDECL napi_create_bigint_uint64(napi_env env,
1504
                                                 uint64_t value,
1505
                                                 napi_value* result) {
1506
6
  CHECK_ENV(env);
1507
6
  CHECK_ARG(env, result);
1508
1509
6
  *result = v8impl::JsValueFromV8LocalValue(
1510
6
      v8::BigInt::NewFromUnsigned(env->isolate, value));
1511
1512
6
  return napi_clear_last_error(env);
1513
}
1514
1515
13
napi_status NAPI_CDECL napi_create_bigint_words(napi_env env,
1516
                                                int sign_bit,
1517
                                                size_t word_count,
1518
                                                const uint64_t* words,
1519
                                                napi_value* result) {
1520


26
  NAPI_PREAMBLE(env);
1521
13
  CHECK_ARG(env, words);
1522
13
  CHECK_ARG(env, result);
1523
1524
13
  v8::Local<v8::Context> context = env->context();
1525
1526
13
  RETURN_STATUS_IF_FALSE(env, word_count <= INT_MAX, napi_invalid_arg);
1527
1528
  v8::MaybeLocal<v8::BigInt> b =
1529
12
      v8::BigInt::NewFromWords(context, sign_bit, word_count, words);
1530
1531

12
  CHECK_MAYBE_EMPTY_WITH_PREAMBLE(env, b, napi_generic_failure);
1532
1533
11
  *result = v8impl::JsValueFromV8LocalValue(b.ToLocalChecked());
1534
11
  return GET_RETURN_STATUS(env);
1535
}
1536
1537
1301
napi_status NAPI_CDECL napi_get_boolean(napi_env env,
1538
                                        bool value,
1539
                                        napi_value* result) {
1540
1301
  CHECK_ENV(env);
1541
1301
  CHECK_ARG(env, result);
1542
1543
1301
  v8::Isolate* isolate = env->isolate;
1544
1545
1301
  if (value) {
1546
734
    *result = v8impl::JsValueFromV8LocalValue(v8::True(isolate));
1547
  } else {
1548
567
    *result = v8impl::JsValueFromV8LocalValue(v8::False(isolate));
1549
  }
1550
1551
1301
  return napi_clear_last_error(env);
1552
}
1553
1554
15
napi_status NAPI_CDECL napi_create_symbol(napi_env env,
1555
                                          napi_value description,
1556
                                          napi_value* result) {
1557
15
  CHECK_ENV(env);
1558
15
  CHECK_ARG(env, result);
1559
1560
15
  v8::Isolate* isolate = env->isolate;
1561
1562
15
  if (description == nullptr) {
1563
6
    *result = v8impl::JsValueFromV8LocalValue(v8::Symbol::New(isolate));
1564
  } else {
1565
12
    v8::Local<v8::Value> desc = v8impl::V8LocalValueFromJsValue(description);
1566
24
    RETURN_STATUS_IF_FALSE(env, desc->IsString(), napi_string_expected);
1567
1568
24
    *result = v8impl::JsValueFromV8LocalValue(
1569
        v8::Symbol::New(isolate, desc.As<v8::String>()));
1570
  }
1571
1572
15
  return napi_clear_last_error(env);
1573
}
1574
1575
4
napi_status NAPI_CDECL node_api_symbol_for(napi_env env,
1576
                                           const char* utf8description,
1577
                                           size_t length,
1578
                                           napi_value* result) {
1579
4
  CHECK_ENV(env);
1580
4
  CHECK_ARG(env, result);
1581
1582
  napi_value js_description_string;
1583
4
  STATUS_CALL(napi_create_string_utf8(
1584
      env, utf8description, length, &js_description_string));
1585
  v8::Local<v8::String> description_string =
1586
3
      v8impl::V8LocalValueFromJsValue(js_description_string).As<v8::String>();
1587
1588
3
  *result = v8impl::JsValueFromV8LocalValue(
1589
3
      v8::Symbol::For(env->isolate, description_string));
1590
1591
3
  return napi_clear_last_error(env);
1592
}
1593
1594
199
static inline napi_status set_error_code(napi_env env,
1595
                                         v8::Local<v8::Value> error,
1596
                                         napi_value code,
1597
                                         const char* code_cstring) {
1598

199
  if ((code != nullptr) || (code_cstring != nullptr)) {
1599
118
    v8::Local<v8::Context> context = env->context();
1600
118
    v8::Local<v8::Object> err_object = error.As<v8::Object>();
1601
1602
118
    v8::Local<v8::Value> code_value = v8impl::V8LocalValueFromJsValue(code);
1603
118
    if (code != nullptr) {
1604
6
      code_value = v8impl::V8LocalValueFromJsValue(code);
1605
12
      RETURN_STATUS_IF_FALSE(env, code_value->IsString(), napi_string_expected);
1606
    } else {
1607

336
      CHECK_NEW_FROM_UTF8(env, code_value, code_cstring);
1608
    }
1609
1610
    v8::Local<v8::Name> code_key;
1611
354
    CHECK_NEW_FROM_UTF8(env, code_key, "code");
1612
1613
118
    v8::Maybe<bool> set_maybe = err_object->Set(context, code_key, code_value);
1614

236
    RETURN_STATUS_IF_FALSE(
1615
        env, set_maybe.FromMaybe(false), napi_generic_failure);
1616
  }
1617
199
  return napi_ok;
1618
}
1619
1620
5
napi_status NAPI_CDECL napi_create_error(napi_env env,
1621
                                         napi_value code,
1622
                                         napi_value msg,
1623
                                         napi_value* result) {
1624
5
  CHECK_ENV(env);
1625
5
  CHECK_ARG(env, msg);
1626
5
  CHECK_ARG(env, result);
1627
1628
5
  v8::Local<v8::Value> message_value = v8impl::V8LocalValueFromJsValue(msg);
1629
10
  RETURN_STATUS_IF_FALSE(env, message_value->IsString(), napi_string_expected);
1630
1631
  v8::Local<v8::Value> error_obj =
1632
5
      v8::Exception::Error(message_value.As<v8::String>());
1633
5
  STATUS_CALL(set_error_code(env, error_obj, code, nullptr));
1634
1635
5
  *result = v8impl::JsValueFromV8LocalValue(error_obj);
1636
1637
5
  return napi_clear_last_error(env);
1638
}
1639
1640
2
napi_status NAPI_CDECL napi_create_type_error(napi_env env,
1641
                                              napi_value code,
1642
                                              napi_value msg,
1643
                                              napi_value* result) {
1644
2
  CHECK_ENV(env);
1645
2
  CHECK_ARG(env, msg);
1646
2
  CHECK_ARG(env, result);
1647
1648
2
  v8::Local<v8::Value> message_value = v8impl::V8LocalValueFromJsValue(msg);
1649
4
  RETURN_STATUS_IF_FALSE(env, message_value->IsString(), napi_string_expected);
1650
1651
  v8::Local<v8::Value> error_obj =
1652
2
      v8::Exception::TypeError(message_value.As<v8::String>());
1653
2
  STATUS_CALL(set_error_code(env, error_obj, code, nullptr));
1654
1655
2
  *result = v8impl::JsValueFromV8LocalValue(error_obj);
1656
1657
2
  return napi_clear_last_error(env);
1658
}
1659
1660
2
napi_status NAPI_CDECL napi_create_range_error(napi_env env,
1661
                                               napi_value code,
1662
                                               napi_value msg,
1663
                                               napi_value* result) {
1664
2
  CHECK_ENV(env);
1665
2
  CHECK_ARG(env, msg);
1666
2
  CHECK_ARG(env, result);
1667
1668
2
  v8::Local<v8::Value> message_value = v8impl::V8LocalValueFromJsValue(msg);
1669
4
  RETURN_STATUS_IF_FALSE(env, message_value->IsString(), napi_string_expected);
1670
1671
  v8::Local<v8::Value> error_obj =
1672
2
      v8::Exception::RangeError(message_value.As<v8::String>());
1673
2
  STATUS_CALL(set_error_code(env, error_obj, code, nullptr));
1674
1675
2
  *result = v8impl::JsValueFromV8LocalValue(error_obj);
1676
1677
2
  return napi_clear_last_error(env);
1678
}
1679
1680
2
napi_status NAPI_CDECL node_api_create_syntax_error(napi_env env,
1681
                                                    napi_value code,
1682
                                                    napi_value msg,
1683
                                                    napi_value* result) {
1684
2
  CHECK_ENV(env);
1685
2
  CHECK_ARG(env, msg);
1686
2
  CHECK_ARG(env, result);
1687
1688
2
  v8::Local<v8::Value> message_value = v8impl::V8LocalValueFromJsValue(msg);
1689
4
  RETURN_STATUS_IF_FALSE(env, message_value->IsString(), napi_string_expected);
1690
1691
  v8::Local<v8::Value> error_obj =
1692
2
      v8::Exception::SyntaxError(message_value.As<v8::String>());
1693
2
  STATUS_CALL(set_error_code(env, error_obj, code, nullptr));
1694
1695
2
  *result = v8impl::JsValueFromV8LocalValue(error_obj);
1696
1697
2
  return napi_clear_last_error(env);
1698
}
1699
1700
444
napi_status NAPI_CDECL napi_typeof(napi_env env,
1701
                                   napi_value value,
1702
                                   napi_valuetype* result) {
1703
  // Omit NAPI_PREAMBLE and GET_RETURN_STATUS because V8 calls here cannot throw
1704
  // JS exceptions.
1705
444
  CHECK_ENV(env);
1706
444
  CHECK_ARG(env, value);
1707
444
  CHECK_ARG(env, result);
1708
1709
444
  v8::Local<v8::Value> v = v8impl::V8LocalValueFromJsValue(value);
1710
1711
444
  if (v->IsNumber()) {
1712
136
    *result = napi_number;
1713
308
  } else if (v->IsBigInt()) {
1714
26
    *result = napi_bigint;
1715
564
  } else if (v->IsString()) {
1716
87
    *result = napi_string;
1717
195
  } else if (v->IsFunction()) {
1718
    // This test has to come before IsObject because IsFunction
1719
    // implies IsObject
1720
35
    *result = napi_function;
1721
160
  } else if (v->IsExternal()) {
1722
    // This test has to come before IsObject because IsExternal
1723
    // implies IsObject
1724
2
    *result = napi_external;
1725
158
  } else if (v->IsObject()) {
1726
144
    *result = napi_object;
1727
14
  } else if (v->IsBoolean()) {
1728
1
    *result = napi_boolean;
1729
26
  } else if (v->IsUndefined()) {
1730
3
    *result = napi_undefined;
1731
10
  } else if (v->IsSymbol()) {
1732
9
    *result = napi_symbol;
1733
2
  } else if (v->IsNull()) {
1734
1
    *result = napi_null;
1735
  } else {
1736
    // Should not get here unless V8 has added some new kind of value.
1737
    return napi_set_last_error(env, napi_invalid_arg);
1738
  }
1739
1740
444
  return napi_clear_last_error(env);
1741
}
1742
1743
114044
napi_status NAPI_CDECL napi_get_undefined(napi_env env, napi_value* result) {
1744
114044
  CHECK_ENV(env);
1745
114044
  CHECK_ARG(env, result);
1746
1747
228088
  *result = v8impl::JsValueFromV8LocalValue(v8::Undefined(env->isolate));
1748
1749
114044
  return napi_clear_last_error(env);
1750
}
1751
1752
5
napi_status NAPI_CDECL napi_get_null(napi_env env, napi_value* result) {
1753
5
  CHECK_ENV(env);
1754
5
  CHECK_ARG(env, result);
1755
1756
10
  *result = v8impl::JsValueFromV8LocalValue(v8::Null(env->isolate));
1757
1758
5
  return napi_clear_last_error(env);
1759
}
1760
1761
// Gets all callback info in a single call. (Ugly, but faster.)
1762
4527
napi_status NAPI_CDECL napi_get_cb_info(
1763
    napi_env env,               // [in] NAPI environment handle
1764
    napi_callback_info cbinfo,  // [in] Opaque callback-info handle
1765
    size_t* argc,      // [in-out] Specifies the size of the provided argv array
1766
                       // and receives the actual count of args.
1767
    napi_value* argv,  // [out] Array of values
1768
    napi_value* this_arg,  // [out] Receives the JS 'this' arg for the call
1769
    void** data) {         // [out] Receives the data pointer for the callback.
1770
4527
  CHECK_ENV(env);
1771
4527
  CHECK_ARG(env, cbinfo);
1772
1773
4527
  v8impl::CallbackWrapper* info =
1774
      reinterpret_cast<v8impl::CallbackWrapper*>(cbinfo);
1775
1776
4527
  if (argv != nullptr) {
1777
4495
    CHECK_ARG(env, argc);
1778
4495
    info->Args(argv, *argc);
1779
  }
1780
4527
  if (argc != nullptr) {
1781
4507
    *argc = info->ArgsLength();
1782
  }
1783
4527
  if (this_arg != nullptr) {
1784
42
    *this_arg = info->This();
1785
  }
1786
4527
  if (data != nullptr) {
1787
6
    *data = info->Data();
1788
  }
1789
1790
4527
  return napi_clear_last_error(env);
1791
}
1792
1793
8
napi_status NAPI_CDECL napi_get_new_target(napi_env env,
1794
                                           napi_callback_info cbinfo,
1795
                                           napi_value* result) {
1796
8
  CHECK_ENV(env);
1797
8
  CHECK_ARG(env, cbinfo);
1798
8
  CHECK_ARG(env, result);
1799
1800
8
  v8impl::CallbackWrapper* info =
1801
      reinterpret_cast<v8impl::CallbackWrapper*>(cbinfo);
1802
1803
8
  *result = info->GetNewTarget();
1804
8
  return napi_clear_last_error(env);
1805
}
1806
1807
114565
napi_status NAPI_CDECL napi_call_function(napi_env env,
1808
                                          napi_value recv,
1809
                                          napi_value func,
1810
                                          size_t argc,
1811
                                          const napi_value* argv,
1812
                                          napi_value* result) {
1813


229126
  NAPI_PREAMBLE(env);
1814
114561
  CHECK_ARG(env, recv);
1815
114561
  if (argc > 0) {
1816
104513
    CHECK_ARG(env, argv);
1817
  }
1818
1819
114561
  v8::Local<v8::Context> context = env->context();
1820
1821
114561
  v8::Local<v8::Value> v8recv = v8impl::V8LocalValueFromJsValue(recv);
1822
1823
  v8::Local<v8::Function> v8func;
1824

343683
  CHECK_TO_FUNCTION(env, v8func, func);
1825
1826
  auto maybe = v8func->Call(
1827
      context,
1828
      v8recv,
1829
      argc,
1830
114561
      reinterpret_cast<v8::Local<v8::Value>*>(const_cast<napi_value*>(argv)));
1831
1832
114561
  if (try_catch.HasCaught()) {
1833
13
    return napi_set_last_error(env, napi_pending_exception);
1834
  } else {
1835
114548
    if (result != nullptr) {
1836
7
      CHECK_MAYBE_EMPTY(env, maybe, napi_generic_failure);
1837
7
      *result = v8impl::JsValueFromV8LocalValue(maybe.ToLocalChecked());
1838
    }
1839
114548
    return napi_clear_last_error(env);
1840
  }
1841
}
1842
1843
15
napi_status NAPI_CDECL napi_get_global(napi_env env, napi_value* result) {
1844
15
  CHECK_ENV(env);
1845
15
  CHECK_ARG(env, result);
1846
1847
45
  *result = v8impl::JsValueFromV8LocalValue(env->context()->Global());
1848
1849
15
  return napi_clear_last_error(env);
1850
}
1851
1852
12
napi_status NAPI_CDECL napi_throw(napi_env env, napi_value error) {
1853


24
  NAPI_PREAMBLE(env);
1854
12
  CHECK_ARG(env, error);
1855
1856
12
  v8::Isolate* isolate = env->isolate;
1857
1858
12
  isolate->ThrowException(v8impl::V8LocalValueFromJsValue(error));
1859
  // any VM calls after this point and before returning
1860
  // to the javascript invoker will fail
1861
12
  return napi_clear_last_error(env);
1862
}
1863
1864
83
napi_status NAPI_CDECL napi_throw_error(napi_env env,
1865
                                        const char* code,
1866
                                        const char* msg) {
1867


157
  NAPI_PREAMBLE(env);
1868
1869
74
  v8::Isolate* isolate = env->isolate;
1870
  v8::Local<v8::String> str;
1871

148
  CHECK_NEW_FROM_UTF8(env, str, msg);
1872
1873
74
  v8::Local<v8::Value> error_obj = v8::Exception::Error(str);
1874
74
  STATUS_CALL(set_error_code(env, error_obj, nullptr, code));
1875
1876
74
  isolate->ThrowException(error_obj);
1877
  // any VM calls after this point and before returning
1878
  // to the javascript invoker will fail
1879
74
  return napi_clear_last_error(env);
1880
}
1881
1882
90
napi_status NAPI_CDECL napi_throw_type_error(napi_env env,
1883
                                             const char* code,
1884
                                             const char* msg) {
1885


180
  NAPI_PREAMBLE(env);
1886
1887
90
  v8::Isolate* isolate = env->isolate;
1888
  v8::Local<v8::String> str;
1889

180
  CHECK_NEW_FROM_UTF8(env, str, msg);
1890
1891
90
  v8::Local<v8::Value> error_obj = v8::Exception::TypeError(str);
1892
90
  STATUS_CALL(set_error_code(env, error_obj, nullptr, code));
1893
1894
90
  isolate->ThrowException(error_obj);
1895
  // any VM calls after this point and before returning
1896
  // to the javascript invoker will fail
1897
90
  return napi_clear_last_error(env);
1898
}
1899
1900
22
napi_status NAPI_CDECL napi_throw_range_error(napi_env env,
1901
                                              const char* code,
1902
                                              const char* msg) {
1903


44
  NAPI_PREAMBLE(env);
1904
1905
22
  v8::Isolate* isolate = env->isolate;
1906
  v8::Local<v8::String> str;
1907

44
  CHECK_NEW_FROM_UTF8(env, str, msg);
1908
1909
22
  v8::Local<v8::Value> error_obj = v8::Exception::RangeError(str);
1910
22
  STATUS_CALL(set_error_code(env, error_obj, nullptr, code));
1911
1912
22
  isolate->ThrowException(error_obj);
1913
  // any VM calls after this point and before returning
1914
  // to the javascript invoker will fail
1915
22
  return napi_clear_last_error(env);
1916
}
1917
1918
2
napi_status NAPI_CDECL node_api_throw_syntax_error(napi_env env,
1919
                                                   const char* code,
1920
                                                   const char* msg) {
1921


4
  NAPI_PREAMBLE(env);
1922
1923
2
  v8::Isolate* isolate = env->isolate;
1924
  v8::Local<v8::String> str;
1925

4
  CHECK_NEW_FROM_UTF8(env, str, msg);
1926
1927
2
  v8::Local<v8::Value> error_obj = v8::Exception::SyntaxError(str);
1928
2
  STATUS_CALL(set_error_code(env, error_obj, nullptr, code));
1929
1930
2
  isolate->ThrowException(error_obj);
1931
  // any VM calls after this point and before returning
1932
  // to the javascript invoker will fail
1933
2
  return napi_clear_last_error(env);
1934
}
1935
1936
10
napi_status NAPI_CDECL napi_is_error(napi_env env,
1937
                                     napi_value value,
1938
                                     bool* result) {
1939
  // Omit NAPI_PREAMBLE and GET_RETURN_STATUS because V8 calls here cannot
1940
  // throw JS exceptions.
1941
10
  CHECK_ENV(env);
1942
10
  CHECK_ARG(env, value);
1943
10
  CHECK_ARG(env, result);
1944
1945
10
  v8::Local<v8::Value> val = v8impl::V8LocalValueFromJsValue(value);
1946
10
  *result = val->IsNativeError();
1947
1948
10
  return napi_clear_last_error(env);
1949
}
1950
1951
73
napi_status NAPI_CDECL napi_get_value_double(napi_env env,
1952
                                             napi_value value,
1953
                                             double* result) {
1954
  // Omit NAPI_PREAMBLE and GET_RETURN_STATUS because V8 calls here cannot throw
1955
  // JS exceptions.
1956
73
  CHECK_ENV(env);
1957
72
  CHECK_ARG(env, value);
1958
71
  CHECK_ARG(env, result);
1959
1960
70
  v8::Local<v8::Value> val = v8impl::V8LocalValueFromJsValue(value);
1961
70
  RETURN_STATUS_IF_FALSE(env, val->IsNumber(), napi_number_expected);
1962
1963
60
  *result = val.As<v8::Number>()->Value();
1964
1965
60
  return napi_clear_last_error(env);
1966
}
1967
1968
61
napi_status NAPI_CDECL napi_get_value_int32(napi_env env,
1969
                                            napi_value value,
1970
                                            int32_t* result) {
1971
  // Omit NAPI_PREAMBLE and GET_RETURN_STATUS because V8 calls here cannot throw
1972
  // JS exceptions.
1973
61
  CHECK_ENV(env);
1974
60
  CHECK_ARG(env, value);
1975
59
  CHECK_ARG(env, result);
1976
1977
58
  v8::Local<v8::Value> val = v8impl::V8LocalValueFromJsValue(value);
1978
1979
58
  if (val->IsInt32()) {
1980
25
    *result = val.As<v8::Int32>()->Value();
1981
  } else {
1982
33
    RETURN_STATUS_IF_FALSE(env, val->IsNumber(), napi_number_expected);
1983
1984
    // Empty context: https://github.com/nodejs/node/issues/14379
1985
    v8::Local<v8::Context> context;
1986
48
    *result = val->Int32Value(context).FromJust();
1987
  }
1988
1989
49
  return napi_clear_last_error(env);
1990
}
1991
1992
113
napi_status NAPI_CDECL napi_get_value_uint32(napi_env env,
1993
                                             napi_value value,
1994
                                             uint32_t* result) {
1995
  // Omit NAPI_PREAMBLE and GET_RETURN_STATUS because V8 calls here cannot throw
1996
  // JS exceptions.
1997
113
  CHECK_ENV(env);
1998
112
  CHECK_ARG(env, value);
1999
111
  CHECK_ARG(env, result);
2000
2001
110
  v8::Local<v8::Value> val = v8impl::V8LocalValueFromJsValue(value);
2002
2003
110
  if (val->IsUint32()) {
2004
90
    *result = val.As<v8::Uint32>()->Value();
2005
  } else {
2006
20
    RETURN_STATUS_IF_FALSE(env, val->IsNumber(), napi_number_expected);
2007
2008
    // Empty context: https://github.com/nodejs/node/issues/14379
2009
    v8::Local<v8::Context> context;
2010
22
    *result = val->Uint32Value(context).FromJust();
2011
  }
2012
2013
101
  return napi_clear_last_error(env);
2014
}
2015
2016
36
napi_status NAPI_CDECL napi_get_value_int64(napi_env env,
2017
                                            napi_value value,
2018
                                            int64_t* result) {
2019
  // Omit NAPI_PREAMBLE and GET_RETURN_STATUS because V8 calls here cannot throw
2020
  // JS exceptions.
2021
36
  CHECK_ENV(env);
2022
35
  CHECK_ARG(env, value);
2023
34
  CHECK_ARG(env, result);
2024
2025
33
  v8::Local<v8::Value> val = v8impl::V8LocalValueFromJsValue(value);
2026
2027
  // This is still a fast path very likely to be taken.
2028
33
  if (val->IsInt32()) {
2029
5
    *result = val.As<v8::Int32>()->Value();
2030
5
    return napi_clear_last_error(env);
2031
  }
2032
2033
28
  RETURN_STATUS_IF_FALSE(env, val->IsNumber(), napi_number_expected);
2034
2035
  // v8::Value::IntegerValue() converts NaN, +Inf, and -Inf to INT64_MIN,
2036
  // inconsistent with v8::Value::Int32Value() which converts those values to 0.
2037
  // Special-case all non-finite values to match that behavior.
2038
19
  double doubleValue = val.As<v8::Number>()->Value();
2039
19
  if (std::isfinite(doubleValue)) {
2040
    // Empty context: https://github.com/nodejs/node/issues/14379
2041
    v8::Local<v8::Context> context;
2042
30
    *result = val->IntegerValue(context).FromJust();
2043
  } else {
2044
4
    *result = 0;
2045
  }
2046
2047
19
  return napi_clear_last_error(env);
2048
}
2049
2050
20
napi_status NAPI_CDECL napi_get_value_bigint_int64(napi_env env,
2051
                                                   napi_value value,
2052
                                                   int64_t* result,
2053
                                                   bool* lossless) {
2054
20
  CHECK_ENV(env);
2055
20
  CHECK_ARG(env, value);
2056
20
  CHECK_ARG(env, result);
2057
20
  CHECK_ARG(env, lossless);
2058
2059
20
  v8::Local<v8::Value> val = v8impl::V8LocalValueFromJsValue(value);
2060
2061
20
  RETURN_STATUS_IF_FALSE(env, val->IsBigInt(), napi_bigint_expected);
2062
2063
20
  *result = val.As<v8::BigInt>()->Int64Value(lossless);
2064
2065
20
  return napi_clear_last_error(env);
2066
}
2067
2068
17
napi_status NAPI_CDECL napi_get_value_bigint_uint64(napi_env env,
2069
                                                    napi_value value,
2070
                                                    uint64_t* result,
2071
                                                    bool* lossless) {
2072
17
  CHECK_ENV(env);
2073
17
  CHECK_ARG(env, value);
2074
17
  CHECK_ARG(env, result);
2075
17
  CHECK_ARG(env, lossless);
2076
2077
17
  v8::Local<v8::Value> val = v8impl::V8LocalValueFromJsValue(value);
2078
2079
17
  RETURN_STATUS_IF_FALSE(env, val->IsBigInt(), napi_bigint_expected);
2080
2081
17
  *result = val.As<v8::BigInt>()->Uint64Value(lossless);
2082
2083
17
  return napi_clear_last_error(env);
2084
}
2085
2086
22
napi_status NAPI_CDECL napi_get_value_bigint_words(napi_env env,
2087
                                                   napi_value value,
2088
                                                   int* sign_bit,
2089
                                                   size_t* word_count,
2090
                                                   uint64_t* words) {
2091
22
  CHECK_ENV(env);
2092
22
  CHECK_ARG(env, value);
2093
22
  CHECK_ARG(env, word_count);
2094
2095
22
  v8::Local<v8::Value> val = v8impl::V8LocalValueFromJsValue(value);
2096
2097
22
  RETURN_STATUS_IF_FALSE(env, val->IsBigInt(), napi_bigint_expected);
2098
2099
22
  v8::Local<v8::BigInt> big = val.As<v8::BigInt>();
2100
2101
22
  int word_count_int = *word_count;
2102
2103

22
  if (sign_bit == nullptr && words == nullptr) {
2104
11
    word_count_int = big->WordCount();
2105
  } else {
2106
11
    CHECK_ARG(env, sign_bit);
2107
11
    CHECK_ARG(env, words);
2108
11
    big->ToWordsArray(sign_bit, &word_count_int, words);
2109
  }
2110
2111
22
  *word_count = word_count_int;
2112
2113
22
  return napi_clear_last_error(env);
2114
}
2115
2116
93
napi_status NAPI_CDECL napi_get_value_bool(napi_env env,
2117
                                           napi_value value,
2118
                                           bool* result) {
2119
  // Omit NAPI_PREAMBLE and GET_RETURN_STATUS because V8 calls here cannot throw
2120
  // JS exceptions.
2121
93
  CHECK_ENV(env);
2122
92
  CHECK_ARG(env, value);
2123
91
  CHECK_ARG(env, result);
2124
2125
90
  v8::Local<v8::Value> val = v8impl::V8LocalValueFromJsValue(value);
2126
90
  RETURN_STATUS_IF_FALSE(env, val->IsBoolean(), napi_boolean_expected);
2127
2128
77
  *result = val.As<v8::Boolean>()->Value();
2129
2130
77
  return napi_clear_last_error(env);
2131
}
2132
2133
// Copies a JavaScript string into a LATIN-1 string buffer. The result is the
2134
// number of bytes (excluding the null terminator) copied into buf.
2135
// A sufficient buffer size should be greater than the length of string,
2136
// reserving space for null terminator.
2137
// If bufsize is insufficient, the string will be truncated and null terminated.
2138
// If buf is NULL, this method returns the length of the string (in bytes)
2139
// via the result parameter.
2140
// The result argument is optional unless buf is NULL.
2141
15
napi_status NAPI_CDECL napi_get_value_string_latin1(
2142
    napi_env env, napi_value value, char* buf, size_t bufsize, size_t* result) {
2143
15
  CHECK_ENV(env);
2144
14
  CHECK_ARG(env, value);
2145
2146
13
  v8::Local<v8::Value> val = v8impl::V8LocalValueFromJsValue(value);
2147
26
  RETURN_STATUS_IF_FALSE(env, val->IsString(), napi_string_expected);
2148
2149
12
  if (!buf) {
2150
1
    CHECK_ARG(env, result);
2151
    *result = val.As<v8::String>()->Length();
2152
11
  } else if (bufsize != 0) {
2153
    int copied =
2154
11
        val.As<v8::String>()->WriteOneByte(env->isolate,
2155
                                           reinterpret_cast<uint8_t*>(buf),
2156
                                           0,
2157
11
                                           bufsize - 1,
2158
                                           v8::String::NO_NULL_TERMINATION);
2159
2160
11
    buf[copied] = '\0';
2161
11
    if (result != nullptr) {
2162
11
      *result = copied;
2163
    }
2164
  } else if (result != nullptr) {
2165
    *result = 0;
2166
  }
2167
2168
11
  return napi_clear_last_error(env);
2169
}
2170
2171
// Copies a JavaScript string into a UTF-8 string buffer. The result is the
2172
// number of bytes (excluding the null terminator) copied into buf.
2173
// A sufficient buffer size should be greater than the length of string,
2174
// reserving space for null terminator.
2175
// If bufsize is insufficient, the string will be truncated and null terminated.
2176
// If buf is NULL, this method returns the length of the string (in bytes)
2177
// via the result parameter.
2178
// The result argument is optional unless buf is NULL.
2179
44
napi_status NAPI_CDECL napi_get_value_string_utf8(
2180
    napi_env env, napi_value value, char* buf, size_t bufsize, size_t* result) {
2181
44
  CHECK_ENV(env);
2182
43
  CHECK_ARG(env, value);
2183
2184
42
  v8::Local<v8::Value> val = v8impl::V8LocalValueFromJsValue(value);
2185
84
  RETURN_STATUS_IF_FALSE(env, val->IsString(), napi_string_expected);
2186
2187
32
  if (!buf) {
2188
8
    CHECK_ARG(env, result);
2189
7
    *result = val.As<v8::String>()->Utf8Length(env->isolate);
2190
24
  } else if (bufsize != 0) {
2191
23
    int copied = val.As<v8::String>()->WriteUtf8(
2192
23
        env->isolate,
2193
        buf,
2194
23
        bufsize - 1,
2195
        nullptr,
2196
        v8::String::REPLACE_INVALID_UTF8 | v8::String::NO_NULL_TERMINATION);
2197
2198
23
    buf[copied] = '\0';
2199
23
    if (result != nullptr) {
2200
21
      *result = copied;
2201
    }
2202
1
  } else if (result != nullptr) {
2203
    *result = 0;
2204
  }
2205
2206
31
  return napi_clear_last_error(env);
2207
}
2208
2209
// Copies a JavaScript string into a UTF-16 string buffer. The result is the
2210
// number of 2-byte code units (excluding the null terminator) copied into buf.
2211
// A sufficient buffer size should be greater than the length of string,
2212
// reserving space for null terminator.
2213
// If bufsize is insufficient, the string will be truncated and null terminated.
2214
// If buf is NULL, this method returns the length of the string (in 2-byte
2215
// code units) via the result parameter.
2216
// The result argument is optional unless buf is NULL.
2217
24
napi_status NAPI_CDECL napi_get_value_string_utf16(napi_env env,
2218
                                                   napi_value value,
2219
                                                   char16_t* buf,
2220
                                                   size_t bufsize,
2221
                                                   size_t* result) {
2222
24
  CHECK_ENV(env);
2223
23
  CHECK_ARG(env, value);
2224
2225
22
  v8::Local<v8::Value> val = v8impl::V8LocalValueFromJsValue(value);
2226
44
  RETURN_STATUS_IF_FALSE(env, val->IsString(), napi_string_expected);
2227
2228
21
  if (!buf) {
2229
8
    CHECK_ARG(env, result);
2230
    // V8 assumes UTF-16 length is the same as the number of characters.
2231
7
    *result = val.As<v8::String>()->Length();
2232
13
  } else if (bufsize != 0) {
2233
13
    int copied = val.As<v8::String>()->Write(env->isolate,
2234
                                             reinterpret_cast<uint16_t*>(buf),
2235
                                             0,
2236
13
                                             bufsize - 1,
2237
                                             v8::String::NO_NULL_TERMINATION);
2238
2239
13
    buf[copied] = '\0';
2240
13
    if (result != nullptr) {
2241
13
      *result = copied;
2242
    }
2243
  } else if (result != nullptr) {
2244
    *result = 0;
2245
  }
2246
2247
20
  return napi_clear_last_error(env);
2248
}
2249
2250
18
napi_status NAPI_CDECL napi_coerce_to_bool(napi_env env,
2251
                                           napi_value value,
2252
                                           napi_value* result) {
2253


35
  NAPI_PREAMBLE(env);
2254
17
  CHECK_ARG(env, value);
2255
16
  CHECK_ARG(env, result);
2256
2257
15
  v8::Isolate* isolate = env->isolate;
2258
  v8::Local<v8::Boolean> b =
2259
30
      v8impl::V8LocalValueFromJsValue(value)->ToBoolean(isolate);
2260
15
  *result = v8impl::JsValueFromV8LocalValue(b);
2261
15
  return GET_RETURN_STATUS(env);
2262
}
2263
2264
#define GEN_COERCE_FUNCTION(UpperCaseName, MixedCaseName, LowerCaseName)       \
2265
  napi_status NAPI_CDECL napi_coerce_to_##LowerCaseName(                       \
2266
      napi_env env, napi_value value, napi_value* result) {                    \
2267
    NAPI_PREAMBLE(env);                                                        \
2268
    CHECK_ARG(env, value);                                                     \
2269
    CHECK_ARG(env, result);                                                    \
2270
                                                                               \
2271
    v8::Local<v8::Context> context = env->context();                           \
2272
    v8::Local<v8::MixedCaseName> str;                                          \
2273
                                                                               \
2274
    CHECK_TO_##UpperCaseName(env, context, str, value);                        \
2275
                                                                               \
2276
    *result = v8impl::JsValueFromV8LocalValue(str);                            \
2277
    return GET_RETURN_STATUS(env);                                             \
2278
  }
2279
2280




44
GEN_COERCE_FUNCTION(NUMBER, Number, number)
2281




51
GEN_COERCE_FUNCTION(OBJECT, Object, object)
2282




47
GEN_COERCE_FUNCTION(STRING, String, string)
2283
2284
#undef GEN_COERCE_FUNCTION
2285
2286
1030
napi_status NAPI_CDECL napi_wrap(napi_env env,
2287
                                 napi_value js_object,
2288
                                 void* native_object,
2289
                                 napi_finalize finalize_cb,
2290
                                 void* finalize_hint,
2291
                                 napi_ref* result) {
2292
1030
  return v8impl::Wrap<v8impl::retrievable>(
2293
1030
      env, js_object, native_object, finalize_cb, finalize_hint, result);
2294
}
2295
2296
27
napi_status NAPI_CDECL napi_unwrap(napi_env env,
2297
                                   napi_value obj,
2298
                                   void** result) {
2299
27
  return v8impl::Unwrap(env, obj, result, v8impl::KeepWrap);
2300
}
2301
2302
10
napi_status NAPI_CDECL napi_remove_wrap(napi_env env,
2303
                                        napi_value obj,
2304
                                        void** result) {
2305
10
  return v8impl::Unwrap(env, obj, result, v8impl::RemoveWrap);
2306
}
2307
2308
8
napi_status NAPI_CDECL napi_create_external(napi_env env,
2309
                                            void* data,
2310
                                            napi_finalize finalize_cb,
2311
                                            void* finalize_hint,
2312
                                            napi_value* result) {
2313


16
  NAPI_PREAMBLE(env);
2314
8
  CHECK_ARG(env, result);
2315
2316
8
  v8::Isolate* isolate = env->isolate;
2317
2318
8
  v8::Local<v8::Value> external_value = v8::External::New(isolate, data);
2319
2320
8
  if (finalize_cb) {
2321
    // The Reference object will delete itself after invoking the finalizer
2322
    // callback.
2323
6
    v8impl::Reference::New(env,
2324
                           external_value,
2325
                           0,
2326
                           v8impl::Ownership::kRuntime,
2327
                           finalize_cb,
2328
                           data,
2329
                           finalize_hint);
2330
  }
2331
2332
8
  *result = v8impl::JsValueFromV8LocalValue(external_value);
2333
2334
8
  return napi_clear_last_error(env);
2335
}
2336
2337
4
napi_status NAPI_CDECL napi_type_tag_object(napi_env env,
2338
                                            napi_value object,
2339
                                            const napi_type_tag* type_tag) {
2340


8
  NAPI_PREAMBLE(env);
2341
4
  v8::Local<v8::Context> context = env->context();
2342
  v8::Local<v8::Object> obj;
2343


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

4
  CHECK_ARG_WITH_PREAMBLE(env, type_tag);
2345
2346
4
  auto key = NAPI_PRIVATE_KEY(context, type_tag);
2347
4
  auto maybe_has = obj->HasPrivate(context, key);
2348

4
  CHECK_MAYBE_NOTHING_WITH_PREAMBLE(env, maybe_has, napi_generic_failure);
2349

4
  RETURN_STATUS_IF_FALSE_WITH_PREAMBLE(
2350
      env, !maybe_has.FromJust(), napi_invalid_arg);
2351
2352
  auto tag = v8::BigInt::NewFromWords(
2353
4
      context, 0, 2, reinterpret_cast<const uint64_t*>(type_tag));
2354

4
  CHECK_MAYBE_EMPTY_WITH_PREAMBLE(env, tag, napi_generic_failure);
2355
2356
8
  auto maybe_set = obj->SetPrivate(context, key, tag.ToLocalChecked());
2357

4
  CHECK_MAYBE_NOTHING_WITH_PREAMBLE(env, maybe_set, napi_generic_failure);
2358

4
  RETURN_STATUS_IF_FALSE_WITH_PREAMBLE(
2359
      env, maybe_set.FromJust(), napi_generic_failure);
2360
2361
4
  return GET_RETURN_STATUS(env);
2362
}
2363
2364
13
napi_status NAPI_CDECL napi_check_object_type_tag(napi_env env,
2365
                                                  napi_value object,
2366
                                                  const napi_type_tag* type_tag,
2367
                                                  bool* result) {
2368


26
  NAPI_PREAMBLE(env);
2369
13
  v8::Local<v8::Context> context = env->context();
2370
  v8::Local<v8::Object> obj;
2371


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

13
  CHECK_ARG_WITH_PREAMBLE(env, type_tag);
2373

13
  CHECK_ARG_WITH_PREAMBLE(env, result);
2374
2375
  auto maybe_value =
2376
13
      obj->GetPrivate(context, NAPI_PRIVATE_KEY(context, type_tag));
2377

13
  CHECK_MAYBE_EMPTY_WITH_PREAMBLE(env, maybe_value, napi_generic_failure);
2378
13
  v8::Local<v8::Value> val = maybe_value.ToLocalChecked();
2379
2380
  // We consider the type check to have failed unless we reach the line below
2381
  // where we set whether the type check succeeded or not based on the
2382
  // comparison of the two type tags.
2383
13
  *result = false;
2384
13
  if (val->IsBigInt()) {
2385
    int sign;
2386
11
    int size = 2;
2387
    napi_type_tag tag;
2388
11
    val.As<v8::BigInt>()->ToWordsArray(
2389
        &sign, &size, reinterpret_cast<uint64_t*>(&tag));
2390
11
    if (sign == 0) {
2391
11
      if (size == 2) {
2392
4
        *result =
2393

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

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

3
        *result = (0 == type_tag->lower && 0 == type_tag->upper);
2398
      }
2399
    }
2400
  }
2401
2402
13
  return GET_RETURN_STATUS(env);
2403
}
2404
2405
2
napi_status NAPI_CDECL napi_get_value_external(napi_env env,
2406
                                               napi_value value,
2407
                                               void** result) {
2408
2
  CHECK_ENV(env);
2409
2
  CHECK_ARG(env, value);
2410
2
  CHECK_ARG(env, result);
2411
2412
2
  v8::Local<v8::Value> val = v8impl::V8LocalValueFromJsValue(value);
2413
2
  RETURN_STATUS_IF_FALSE(env, val->IsExternal(), napi_invalid_arg);
2414
2415
2
  v8::Local<v8::External> external_value = val.As<v8::External>();
2416
2
  *result = external_value->Value();
2417
2418
2
  return napi_clear_last_error(env);
2419
}
2420
2421
// Set initial_refcount to 0 for a weak reference, >0 for a strong reference.
2422
1548
napi_status NAPI_CDECL napi_create_reference(napi_env env,
2423
                                             napi_value value,
2424
                                             uint32_t initial_refcount,
2425
                                             napi_ref* result) {
2426
  // Omit NAPI_PREAMBLE and GET_RETURN_STATUS because V8 calls here cannot throw
2427
  // JS exceptions.
2428
1548
  CHECK_ENV(env);
2429
1548
  CHECK_ARG(env, value);
2430
1548
  CHECK_ARG(env, result);
2431
2432
1548
  v8::Local<v8::Value> v8_value = v8impl::V8LocalValueFromJsValue(value);
2433

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


22
  NAPI_PREAMBLE(env);
2609
11
  CHECK_ARG(env, constructor);
2610
11
  if (argc > 0) {
2611
7
    CHECK_ARG(env, argv);
2612
  }
2613
11
  CHECK_ARG(env, result);
2614
2615
11
  v8::Local<v8::Context> context = env->context();
2616
2617
  v8::Local<v8::Function> ctor;
2618

33
  CHECK_TO_FUNCTION(env, ctor, constructor);
2619
2620
  auto maybe = ctor->NewInstance(
2621
      context,
2622
      argc,
2623
11
      reinterpret_cast<v8::Local<v8::Value>*>(const_cast<napi_value*>(argv)));
2624
2625
11
  CHECK_MAYBE_EMPTY(env, maybe, napi_pending_exception);
2626
2627
9
  *result = v8impl::JsValueFromV8LocalValue(maybe.ToLocalChecked());
2628
9
  return GET_RETURN_STATUS(env);
2629
}
2630
2631
2278
napi_status NAPI_CDECL napi_instanceof(napi_env env,
2632
                                       napi_value object,
2633
                                       napi_value constructor,
2634
                                       bool* result) {
2635


4556
  NAPI_PREAMBLE(env);
2636
2278
  CHECK_ARG(env, object);
2637
2278
  CHECK_ARG(env, result);
2638
2639
2278
  *result = false;
2640
2641
  v8::Local<v8::Object> ctor;
2642
2278
  v8::Local<v8::Context> context = env->context();
2643
2644

6834
  CHECK_TO_OBJECT(env, context, ctor, constructor);
2645
2646
2278
  if (!ctor->IsFunction()) {
2647
88
    napi_throw_type_error(
2648
        env, "ERR_NAPI_CONS_FUNCTION", "Constructor must be a function");
2649
2650
88
    return napi_set_last_error(env, napi_function_expected);
2651
  }
2652
2653
2190
  napi_status status = napi_generic_failure;
2654
2655
2190
  v8::Local<v8::Value> val = v8impl::V8LocalValueFromJsValue(object);
2656
2190
  auto maybe_result = val->InstanceOf(context, ctor);
2657
2190
  CHECK_MAYBE_NOTHING(env, maybe_result, status);
2658
1166
  *result = maybe_result.FromJust();
2659
1166
  return GET_RETURN_STATUS(env);
2660
}
2661
2662
// Methods to support catching exceptions
2663
1239
napi_status NAPI_CDECL napi_is_exception_pending(napi_env env, bool* result) {
2664
  // NAPI_PREAMBLE is not used here: this function must execute when there is a
2665
  // pending exception.
2666
1239
  CHECK_ENV(env);
2667
1239
  CHECK_ARG(env, result);
2668
2669
1239
  *result = !env->last_exception.IsEmpty();
2670
1239
  return napi_clear_last_error(env);
2671
}
2672
2673
2
napi_status NAPI_CDECL napi_get_and_clear_last_exception(napi_env env,
2674
                                                         napi_value* result) {
2675
  // NAPI_PREAMBLE is not used here: this function must execute when there is a
2676
  // pending exception.
2677
2
  CHECK_ENV(env);
2678
2
  CHECK_ARG(env, result);
2679
2680
2
  if (env->last_exception.IsEmpty()) {
2681
    return napi_get_undefined(env, result);
2682
  } else {
2683
2
    *result = v8impl::JsValueFromV8LocalValue(
2684
2
        v8::Local<v8::Value>::New(env->isolate, env->last_exception));
2685
2
    env->last_exception.Reset();
2686
  }
2687
2688
2
  return napi_clear_last_error(env);
2689
}
2690
2691
57
napi_status NAPI_CDECL napi_is_arraybuffer(napi_env env,
2692
                                           napi_value value,
2693
                                           bool* result) {
2694
57
  CHECK_ENV(env);
2695
57
  CHECK_ARG(env, value);
2696
57
  CHECK_ARG(env, result);
2697
2698
57
  v8::Local<v8::Value> val = v8impl::V8LocalValueFromJsValue(value);
2699
57
  *result = val->IsArrayBuffer();
2700
2701
57
  return napi_clear_last_error(env);
2702
}
2703
2704
2
napi_status NAPI_CDECL napi_create_arraybuffer(napi_env env,
2705
                                               size_t byte_length,
2706
                                               void** data,
2707
                                               napi_value* result) {
2708


4
  NAPI_PREAMBLE(env);
2709
2
  CHECK_ARG(env, result);
2710
2711
2
  v8::Isolate* isolate = env->isolate;
2712
  v8::Local<v8::ArrayBuffer> buffer =
2713
2
      v8::ArrayBuffer::New(isolate, byte_length);
2714
2715
  // Optionally return a pointer to the buffer's data, to avoid another call to
2716
  // retrieve it.
2717
2
  if (data != nullptr) {
2718
2
    *data = buffer->Data();
2719
  }
2720
2721
2
  *result = v8impl::JsValueFromV8LocalValue(buffer);
2722
2
  return GET_RETURN_STATUS(env);
2723
}
2724
2725
napi_status NAPI_CDECL
2726
6
napi_create_external_arraybuffer(napi_env env,
2727
                                 void* external_data,
2728
                                 size_t byte_length,
2729
                                 napi_finalize finalize_cb,
2730
                                 void* finalize_hint,
2731
                                 napi_value* result) {
2732
  // The API contract here is that the cleanup function runs on the JS thread,
2733
  // and is able to use napi_env. Implementing that properly is hard, so use the
2734
  // `Buffer` variant for easier implementation.
2735
  napi_value buffer;
2736
6
  STATUS_CALL(napi_create_external_buffer(
2737
      env, byte_length, external_data, finalize_cb, finalize_hint, &buffer));
2738
6
  return napi_get_typedarray_info(
2739
6
      env, buffer, nullptr, nullptr, nullptr, result, nullptr);
2740
}
2741
2742
2
napi_status NAPI_CDECL napi_get_arraybuffer_info(napi_env env,
2743
                                                 napi_value arraybuffer,
2744
                                                 void** data,
2745
                                                 size_t* byte_length) {
2746
2
  CHECK_ENV(env);
2747
2
  CHECK_ARG(env, arraybuffer);
2748
2749
2
  v8::Local<v8::Value> value = v8impl::V8LocalValueFromJsValue(arraybuffer);
2750
2
  RETURN_STATUS_IF_FALSE(env, value->IsArrayBuffer(), napi_invalid_arg);
2751
2752
2
  v8::Local<v8::ArrayBuffer> ab = value.As<v8::ArrayBuffer>();
2753
2754
2
  if (data != nullptr) {
2755
2
    *data = ab->Data();
2756
  }
2757
2758
2
  if (byte_length != nullptr) {
2759
2
    *byte_length = ab->ByteLength();
2760
  }
2761
2762
2
  return napi_clear_last_error(env);
2763
}
2764
2765
44
napi_status NAPI_CDECL napi_is_typedarray(napi_env env,
2766
                                          napi_value value,
2767
                                          bool* result) {
2768
44
  CHECK_ENV(env);
2769
44
  CHECK_ARG(env, value);
2770
44
  CHECK_ARG(env, result);
2771
2772
44
  v8::Local<v8::Value> val = v8impl::V8LocalValueFromJsValue(value);
2773
44
  *result = val->IsTypedArray();
2774
2775
44
  return napi_clear_last_error(env);
2776
}
2777
2778
34
napi_status NAPI_CDECL napi_create_typedarray(napi_env env,
2779
                                              napi_typedarray_type type,
2780
                                              size_t length,
2781
                                              napi_value arraybuffer,
2782
                                              size_t byte_offset,
2783
                                              napi_value* result) {
2784


68
  NAPI_PREAMBLE(env);
2785
34
  CHECK_ARG(env, arraybuffer);
2786
34
  CHECK_ARG(env, result);
2787
2788
34
  v8::Local<v8::Value> value = v8impl::V8LocalValueFromJsValue(arraybuffer);
2789
34
  RETURN_STATUS_IF_FALSE(env, value->IsArrayBuffer(), napi_invalid_arg);
2790
2791



34
  v8::Local<v8::ArrayBuffer> buffer = value.As<v8::ArrayBuffer>();
2792
  v8::Local<v8::TypedArray> typedArray;
2793
2794



34
  switch (type) {
2795
4
    case napi_int8_array:
2796
4
      CREATE_TYPED_ARRAY(
2797
          env, Int8Array, 1, buffer, byte_offset, length, typedArray);
2798
3
      break;
2799
3
    case napi_uint8_array:
2800
3
      CREATE_TYPED_ARRAY(
2801
          env, Uint8Array, 1, buffer, byte_offset, length, typedArray);
2802
2
      break;
2803
2
    case napi_uint8_clamped_array:
2804
2
      CREATE_TYPED_ARRAY(
2805
          env, Uint8ClampedArray, 1, buffer, byte_offset, length, typedArray);
2806
1
      break;
2807
3
    case napi_int16_array:
2808

3
      CREATE_TYPED_ARRAY(
2809
          env, Int16Array, 2, buffer, byte_offset, length, typedArray);
2810
1
      break;
2811
3
    case napi_uint16_array:
2812

3
      CREATE_TYPED_ARRAY(
2813
          env, Uint16Array, 2, buffer, byte_offset, length, typedArray);
2814
1
      break;
2815
3
    case napi_int32_array:
2816

3
      CREATE_TYPED_ARRAY(
2817
          env, Int32Array, 4, buffer, byte_offset, length, typedArray);
2818
1
      break;
2819
3
    case napi_uint32_array:
2820

3
      CREATE_TYPED_ARRAY(
2821
          env, Uint32Array, 4, buffer, byte_offset, length, typedArray);
2822
1
      break;
2823
3
    case napi_float32_array:
2824

3
      CREATE_TYPED_ARRAY(
2825
          env, Float32Array, 4, buffer, byte_offset, length, typedArray);
2826
1
      break;
2827
4
    case napi_float64_array:
2828

4
      CREATE_TYPED_ARRAY(
2829
          env, Float64Array, 8, buffer, byte_offset, length, typedArray);
2830
2
      break;
2831
3
    case napi_bigint64_array:
2832

3
      CREATE_TYPED_ARRAY(
2833
          env, BigInt64Array, 8, buffer, byte_offset, length, typedArray);
2834
1
      break;
2835
3
    case napi_biguint64_array:
2836

3
      CREATE_TYPED_ARRAY(
2837
          env, BigUint64Array, 8, buffer, byte_offset, length, typedArray);
2838
1
      break;
2839
    default:
2840
      return napi_set_last_error(env, napi_invalid_arg);
2841
  }
2842
2843
15
  *result = v8impl::JsValueFromV8LocalValue(typedArray);
2844
15
  return GET_RETURN_STATUS(env);
2845
}
2846
2847
50
napi_status NAPI_CDECL napi_get_typedarray_info(napi_env env,
2848
                                                napi_value typedarray,
2849
                                                napi_typedarray_type* type,
2850
                                                size_t* length,
2851
                                                void** data,
2852
                                                napi_value* arraybuffer,
2853
                                                size_t* byte_offset) {
2854
50
  CHECK_ENV(env);
2855
50
  CHECK_ARG(env, typedarray);
2856
2857
50
  v8::Local<v8::Value> value = v8impl::V8LocalValueFromJsValue(typedarray);
2858
50
  RETURN_STATUS_IF_FALSE(env, value->IsTypedArray(), napi_invalid_arg);
2859
2860
50
  v8::Local<v8::TypedArray> array = value.As<v8::TypedArray>();
2861
2862
50
  if (type != nullptr) {
2863
32
    if (value->IsInt8Array()) {
2864
2
      *type = napi_int8_array;
2865
30
    } else if (value->IsUint8Array()) {
2866
3
      *type = napi_uint8_array;
2867
27
    } else if (value->IsUint8ClampedArray()) {
2868
2
      *type = napi_uint8_clamped_array;
2869
25
    } else if (value->IsInt16Array()) {
2870
3
      *type = napi_int16_array;
2871
22
    } else if (value->IsUint16Array()) {
2872
3
      *type = napi_uint16_array;
2873
19
    } else if (value->IsInt32Array()) {
2874
3
      *type = napi_int32_array;
2875
16
    } else if (value->IsUint32Array()) {
2876
3
      *type = napi_uint32_array;
2877
13
    } else if (value->IsFloat32Array()) {
2878
3
      *type = napi_float32_array;
2879
10
    } else if (value->IsFloat64Array()) {
2880
4
      *type = napi_float64_array;
2881
6
    } else if (value->IsBigInt64Array()) {
2882
3
      *type = napi_bigint64_array;
2883
3
    } else if (value->IsBigUint64Array()) {
2884
3
      *type = napi_biguint64_array;
2885
    }
2886
  }
2887
2888
50
  if (length != nullptr) {
2889
32
    *length = array->Length();
2890
  }
2891
2892
  v8::Local<v8::ArrayBuffer> buffer;
2893

50
  if (data != nullptr || arraybuffer != nullptr) {
2894
    // Calling Buffer() may have the side effect of allocating the buffer,
2895
    // so only do this when it’s needed.
2896
50
    buffer = array->Buffer();
2897
  }
2898
2899
50
  if (data != nullptr) {
2900
    *data = static_cast<uint8_t*>(buffer->Data()) + array->ByteOffset();
2901
  }
2902
2903
50
  if (arraybuffer != nullptr) {
2904
50
    *arraybuffer = v8impl::JsValueFromV8LocalValue(buffer);
2905
  }
2906
2907
50
  if (byte_offset != nullptr) {
2908
32
    *byte_offset = array->ByteOffset();
2909
  }
2910
2911
50
  return napi_clear_last_error(env);
2912
}
2913
2914
2
napi_status NAPI_CDECL napi_create_dataview(napi_env env,
2915
                                            size_t byte_length,
2916
                                            napi_value arraybuffer,
2917
                                            size_t byte_offset,
2918
                                            napi_value* result) {
2919


4
  NAPI_PREAMBLE(env);
2920
2
  CHECK_ARG(env, arraybuffer);
2921
2
  CHECK_ARG(env, result);
2922
2923
2
  v8::Local<v8::Value> value = v8impl::V8LocalValueFromJsValue(arraybuffer);
2924
2
  RETURN_STATUS_IF_FALSE(env, value->IsArrayBuffer(), napi_invalid_arg);
2925
2926
2
  v8::Local<v8::ArrayBuffer> buffer = value.As<v8::ArrayBuffer>();
2927
2
  if (byte_length + byte_offset > buffer->ByteLength()) {
2928
1
    napi_throw_range_error(env,
2929
                           "ERR_NAPI_INVALID_DATAVIEW_ARGS",
2930
                           "byte_offset + byte_length should be less than or "
2931
                           "equal to the size in bytes of the array passed in");
2932
1
    return napi_set_last_error(env, napi_pending_exception);
2933
  }
2934
  v8::Local<v8::DataView> DataView =
2935
1
      v8::DataView::New(buffer, byte_offset, byte_length);
2936
2937
1
  *result = v8impl::JsValueFromV8LocalValue(DataView);
2938
1
  return GET_RETURN_STATUS(env);
2939
}
2940
2941
1
napi_status NAPI_CDECL napi_is_dataview(napi_env env,
2942
                                        napi_value value,
2943
                                        bool* result) {
2944
1
  CHECK_ENV(env);
2945
1
  CHECK_ARG(env, value);
2946
1
  CHECK_ARG(env, result);
2947
2948
1
  v8::Local<v8::Value> val = v8impl::V8LocalValueFromJsValue(value);
2949
1
  *result = val->IsDataView();
2950
2951
1
  return napi_clear_last_error(env);
2952
}
2953
2954
1
napi_status NAPI_CDECL napi_get_dataview_info(napi_env env,
2955
                                              napi_value dataview,
2956
                                              size_t* byte_length,
2957
                                              void** data,
2958
                                              napi_value* arraybuffer,
2959
                                              size_t* byte_offset) {
2960
1
  CHECK_ENV(env);
2961
1
  CHECK_ARG(env, dataview);
2962
2963
1
  v8::Local<v8::Value> value = v8impl::V8LocalValueFromJsValue(dataview);
2964
1
  RETURN_STATUS_IF_FALSE(env, value->IsDataView(), napi_invalid_arg);
2965
2966
1
  v8::Local<v8::DataView> array = value.As<v8::DataView>();
2967
2968
1
  if (byte_length != nullptr) {
2969
1
    *byte_length = array->ByteLength();
2970
  }
2971
2972
  v8::Local<v8::ArrayBuffer> buffer;
2973

1
  if (data != nullptr || arraybuffer != nullptr) {
2974
    // Calling Buffer() may have the side effect of allocating the buffer,
2975
    // so only do this when it’s needed.
2976
1
    buffer = array->Buffer();
2977
  }
2978
2979
1
  if (data != nullptr) {
2980
    *data = static_cast<uint8_t*>(buffer->Data()) + array->ByteOffset();
2981
  }
2982
2983
1
  if (arraybuffer != nullptr) {
2984
1
    *arraybuffer = v8impl::JsValueFromV8LocalValue(buffer);
2985
  }
2986
2987
1
  if (byte_offset != nullptr) {
2988
1
    *byte_offset = array->ByteOffset();
2989
  }
2990
2991
1
  return napi_clear_last_error(env);
2992
}
2993
2994
1
napi_status NAPI_CDECL napi_get_version(napi_env env, uint32_t* result) {
2995
1
  CHECK_ENV(env);
2996
1
  CHECK_ARG(env, result);
2997
1
  *result = NAPI_VERSION;
2998
1
  return napi_clear_last_error(env);
2999
}
3000
3001
5
napi_status NAPI_CDECL napi_create_promise(napi_env env,
3002
                                           napi_deferred* deferred,
3003
                                           napi_value* promise) {
3004


10
  NAPI_PREAMBLE(env);
3005
5
  CHECK_ARG(env, deferred);
3006
5
  CHECK_ARG(env, promise);
3007
3008
5
  auto maybe = v8::Promise::Resolver::New(env->context());
3009
5
  CHECK_MAYBE_EMPTY(env, maybe, napi_generic_failure);
3010
3011
5
  auto v8_resolver = maybe.ToLocalChecked();
3012
5
  auto v8_deferred = new v8impl::Persistent<v8::Value>();
3013
5
  v8_deferred->Reset(env->isolate, v8_resolver);
3014
3015
5
  *deferred = v8impl::JsDeferredFromNodePersistent(v8_deferred);
3016
10
  *promise = v8impl::JsValueFromV8LocalValue(v8_resolver->GetPromise());
3017
5
  return GET_RETURN_STATUS(env);
3018
}
3019
3020
4
napi_status NAPI_CDECL napi_resolve_deferred(napi_env env,
3021
                                             napi_deferred deferred,
3022
                                             napi_value resolution) {
3023
4
  return v8impl::ConcludeDeferred(env, deferred, resolution, true);
3024
}
3025
3026
1
napi_status NAPI_CDECL napi_reject_deferred(napi_env env,
3027
                                            napi_deferred deferred,
3028
                                            napi_value resolution) {
3029
1
  return v8impl::ConcludeDeferred(env, deferred, resolution, false);
3030
}
3031
3032
7
napi_status NAPI_CDECL napi_is_promise(napi_env env,
3033
                                       napi_value value,
3034
                                       bool* is_promise) {
3035
7
  CHECK_ENV(env);
3036
7
  CHECK_ARG(env, value);
3037
7
  CHECK_ARG(env, is_promise);
3038
3039
14
  *is_promise = v8impl::V8LocalValueFromJsValue(value)->IsPromise();
3040
3041
7
  return napi_clear_last_error(env);
3042
}
3043
3044
1
napi_status NAPI_CDECL napi_create_date(napi_env env,
3045
                                        double time,
3046
                                        napi_value* result) {
3047


2
  NAPI_PREAMBLE(env);
3048
1
  CHECK_ARG(env, result);
3049
3050
1
  v8::MaybeLocal<v8::Value> maybe_date = v8::Date::New(env->context(), time);
3051
1
  CHECK_MAYBE_EMPTY(env, maybe_date, napi_generic_failure);
3052
3053
1
  *result = v8impl::JsValueFromV8LocalValue(maybe_date.ToLocalChecked());
3054
3055
1
  return GET_RETURN_STATUS(env);
3056
}
3057
3058
7
napi_status NAPI_CDECL napi_is_date(napi_env env,
3059
                                    napi_value value,
3060
                                    bool* is_date) {
3061
7
  CHECK_ENV(env);
3062
7
  CHECK_ARG(env, value);
3063
7
  CHECK_ARG(env, is_date);
3064
3065
14
  *is_date = v8impl::V8LocalValueFromJsValue(value)->IsDate();
3066
3067
7
  return napi_clear_last_error(env);
3068
}
3069
3070
1
napi_status NAPI_CDECL napi_get_date_value(napi_env env,
3071
                                           napi_value value,
3072
                                           double* result) {
3073


2
  NAPI_PREAMBLE(env);
3074
1
  CHECK_ARG(env, value);
3075
1
  CHECK_ARG(env, result);
3076
3077
1
  v8::Local<v8::Value> val = v8impl::V8LocalValueFromJsValue(value);
3078
1
  RETURN_STATUS_IF_FALSE(env, val->IsDate(), napi_date_expected);
3079
3080
1
  v8::Local<v8::Date> date = val.As<v8::Date>();
3081
1
  *result = date->ValueOf();
3082
3083
1
  return GET_RETURN_STATUS(env);
3084
}
3085
3086
2
napi_status NAPI_CDECL napi_run_script(napi_env env,
3087
                                       napi_value script,
3088
                                       napi_value* result) {
3089


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

52
      value->IsArrayBuffer() && value.As<v8::ArrayBuffer>()->WasDetached();
3192
3193
26
  return napi_clear_last_error(env);
3194
}