GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: js_native_api_v8.cc Lines: 1400 1439 97.3 %
Date: 2021-09-30 04:12:30 Branches: 1122 1762 63.7 %

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

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

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


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

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


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

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




2064
  NAPI_PREAMBLE(env);
412

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

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

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

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

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

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

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

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

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

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


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


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


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


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

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


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

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

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


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

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

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


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

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


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

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


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

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


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

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


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

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

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

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


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

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

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


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

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

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


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

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

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


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

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


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

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


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

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


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

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

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

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

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

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


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

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

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


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

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

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


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


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


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

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

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

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

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


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

12
  CHECK_MAYBE_EMPTY_WITH_PREAMBLE(env, b, napi_generic_failure);
1622
1623
11
  *result = v8impl::JsValueFromV8LocalValue(b.ToLocalChecked());
1624
11
  return GET_RETURN_STATUS(env);
1625
}
1626
1627
1294
napi_status napi_get_boolean(napi_env env, bool value, napi_value* result) {
1628
1294
  CHECK_ENV(env);
1629
1294
  CHECK_ARG(env, result);
1630
1631
1294
  v8::Isolate* isolate = env->isolate;
1632
1633
1294
  if (value) {
1634
731
    *result = v8impl::JsValueFromV8LocalValue(v8::True(isolate));
1635
  } else {
1636
563
    *result = v8impl::JsValueFromV8LocalValue(v8::False(isolate));
1637
  }
1638
1639
1294
  return napi_clear_last_error(env);
1640
}
1641
1642
14
napi_status napi_create_symbol(napi_env env,
1643
                               napi_value description,
1644
                               napi_value* result) {
1645
14
  CHECK_ENV(env);
1646
14
  CHECK_ARG(env, result);
1647
1648
14
  v8::Isolate* isolate = env->isolate;
1649
1650
14
  if (description == nullptr) {
1651
4
    *result = v8impl::JsValueFromV8LocalValue(v8::Symbol::New(isolate));
1652
  } else {
1653
12
    v8::Local<v8::Value> desc = v8impl::V8LocalValueFromJsValue(description);
1654
24
    RETURN_STATUS_IF_FALSE(env, desc->IsString(), napi_string_expected);
1655
1656
24
    *result = v8impl::JsValueFromV8LocalValue(
1657
      v8::Symbol::New(isolate, desc.As<v8::String>()));
1658
  }
1659
1660
14
  return napi_clear_last_error(env);
1661
}
1662
1663
194
static inline napi_status set_error_code(napi_env env,
1664
                                         v8::Local<v8::Value> error,
1665
                                         napi_value code,
1666
                                         const char* code_cstring) {
1667

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

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

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


228783
  NAPI_PREAMBLE(env);
1866
114389
  CHECK_ARG(env, recv);
1867
114389
  if (argc > 0) {
1868
104346
    CHECK_ARG(env, argv);
1869
  }
1870
1871
114389
  v8::Local<v8::Context> context = env->context();
1872
1873
114389
  v8::Local<v8::Value> v8recv = v8impl::V8LocalValueFromJsValue(recv);
1874
1875
  v8::Local<v8::Function> v8func;
1876

343167
  CHECK_TO_FUNCTION(env, v8func, func);
1877
1878
  auto maybe = v8func->Call(context, v8recv, argc,
1879
114389
    reinterpret_cast<v8::Local<v8::Value>*>(const_cast<napi_value*>(argv)));
1880
1881
114389
  if (try_catch.HasCaught()) {
1882
7
    return napi_set_last_error(env, napi_pending_exception);
1883
  } else {
1884
114382
    if (result != nullptr) {
1885
7
      CHECK_MAYBE_EMPTY(env, maybe, napi_generic_failure);
1886
7
      *result = v8impl::JsValueFromV8LocalValue(maybe.ToLocalChecked());
1887
    }
1888
114382
    return napi_clear_last_error(env);
1889
  }
1890
}
1891
1892
11
napi_status napi_get_global(napi_env env, napi_value* result) {
1893
11
  CHECK_ENV(env);
1894
11
  CHECK_ARG(env, result);
1895
1896
33
  *result = v8impl::JsValueFromV8LocalValue(env->context()->Global());
1897
1898
11
  return napi_clear_last_error(env);
1899
}
1900
1901
12
napi_status napi_throw(napi_env env, napi_value error) {
1902


24
  NAPI_PREAMBLE(env);
1903
12
  CHECK_ARG(env, error);
1904
1905
12
  v8::Isolate* isolate = env->isolate;
1906
1907
12
  isolate->ThrowException(v8impl::V8LocalValueFromJsValue(error));
1908
  // any VM calls after this point and before returning
1909
  // to the javascript invoker will fail
1910
12
  return napi_clear_last_error(env);
1911
}
1912
1913
81
napi_status napi_throw_error(napi_env env,
1914
                             const char* code,
1915
                             const char* msg) {
1916


154
  NAPI_PREAMBLE(env);
1917
1918
73
  v8::Isolate* isolate = env->isolate;
1919
  v8::Local<v8::String> str;
1920

146
  CHECK_NEW_FROM_UTF8(env, str, msg);
1921
1922
73
  v8::Local<v8::Value> error_obj = v8::Exception::Error(str);
1923
73
  STATUS_CALL(set_error_code(env, error_obj, nullptr, code));
1924
1925
73
  isolate->ThrowException(error_obj);
1926
  // any VM calls after this point and before returning
1927
  // to the javascript invoker will fail
1928
73
  return napi_clear_last_error(env);
1929
}
1930
1931
90
napi_status napi_throw_type_error(napi_env env,
1932
                                  const char* code,
1933
                                  const char* msg) {
1934


180
  NAPI_PREAMBLE(env);
1935
1936
90
  v8::Isolate* isolate = env->isolate;
1937
  v8::Local<v8::String> str;
1938

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


44
  NAPI_PREAMBLE(env);
1953
1954
22
  v8::Isolate* isolate = env->isolate;
1955
  v8::Local<v8::String> str;
1956

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

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


35
  NAPI_PREAMBLE(env);
2287
17
  CHECK_ARG(env, value);
2288
16
  CHECK_ARG(env, result);
2289
2290
15
  v8::Isolate* isolate = env->isolate;
2291
  v8::Local<v8::Boolean> b =
2292
30
    v8impl::V8LocalValueFromJsValue(value)->ToBoolean(isolate);
2293
15
  *result = v8impl::JsValueFromV8LocalValue(b);
2294
15
  return GET_RETURN_STATUS(env);
2295
}
2296
2297
#define GEN_COERCE_FUNCTION(UpperCaseName, MixedCaseName, LowerCaseName)      \
2298
  napi_status napi_coerce_to_##LowerCaseName(napi_env env,                    \
2299
                                             napi_value value,                \
2300
                                             napi_value* result) {            \
2301
    NAPI_PREAMBLE(env);                                                       \
2302
    CHECK_ARG(env, value);                                                    \
2303
    CHECK_ARG(env, result);                                                   \
2304
                                                                              \
2305
    v8::Local<v8::Context> context = env->context();                          \
2306
    v8::Local<v8::MixedCaseName> str;                                         \
2307
                                                                              \
2308
    CHECK_TO_##UpperCaseName(env, context, str, value);                       \
2309
                                                                              \
2310
    *result = v8impl::JsValueFromV8LocalValue(str);                           \
2311
    return GET_RETURN_STATUS(env);                                            \
2312
  }
2313
2314




44
GEN_COERCE_FUNCTION(NUMBER, Number, number)
2315




51
GEN_COERCE_FUNCTION(OBJECT, Object, object)
2316




47
GEN_COERCE_FUNCTION(STRING, String, string)
2317
2318
#undef GEN_COERCE_FUNCTION
2319
2320
1028
napi_status napi_wrap(napi_env env,
2321
                      napi_value js_object,
2322
                      void* native_object,
2323
                      napi_finalize finalize_cb,
2324
                      void* finalize_hint,
2325
                      napi_ref* result) {
2326
1028
  return v8impl::Wrap<v8impl::retrievable>(env,
2327
                                           js_object,
2328
                                           native_object,
2329
                                           finalize_cb,
2330
                                           finalize_hint,
2331
1028
                                           result);
2332
}
2333
2334
27
napi_status napi_unwrap(napi_env env, napi_value obj, void** result) {
2335
27
  return v8impl::Unwrap(env, obj, result, v8impl::KeepWrap);
2336
}
2337
2338
8
napi_status napi_remove_wrap(napi_env env, napi_value obj, void** result) {
2339
8
  return v8impl::Unwrap(env, obj, result, v8impl::RemoveWrap);
2340
}
2341
2342
7
napi_status napi_create_external(napi_env env,
2343
                                 void* data,
2344
                                 napi_finalize finalize_cb,
2345
                                 void* finalize_hint,
2346
                                 napi_value* result) {
2347


14
  NAPI_PREAMBLE(env);
2348
7
  CHECK_ARG(env, result);
2349
2350
7
  v8::Isolate* isolate = env->isolate;
2351
2352
7
  v8::Local<v8::Value> external_value = v8::External::New(isolate, data);
2353
2354
  // The Reference object will delete itself after invoking the finalizer
2355
  // callback.
2356
7
  v8impl::Reference::New(env,
2357
      external_value,
2358
      0,
2359
      true,
2360
      finalize_cb,
2361
      data,
2362
      finalize_hint);
2363
2364
7
  *result = v8impl::JsValueFromV8LocalValue(external_value);
2365
2366
7
  return napi_clear_last_error(env);
2367
}
2368
2369
2
NAPI_EXTERN napi_status napi_type_tag_object(napi_env env,
2370
                                             napi_value object,
2371
                                             const napi_type_tag* type_tag) {
2372


4
  NAPI_PREAMBLE(env);
2373
2
  v8::Local<v8::Context> context = env->context();
2374
  v8::Local<v8::Object> obj;
2375


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

2
  CHECK_ARG_WITH_PREAMBLE(env, type_tag);
2377
2378
2
  auto key = NAPI_PRIVATE_KEY(context, type_tag);
2379
2
  auto maybe_has = obj->HasPrivate(context, key);
2380

2
  CHECK_MAYBE_NOTHING_WITH_PREAMBLE(env, maybe_has, napi_generic_failure);
2381

2
  RETURN_STATUS_IF_FALSE_WITH_PREAMBLE(env,
2382
                                       !maybe_has.FromJust(),
2383
                                       napi_invalid_arg);
2384
2385
  auto tag = v8::BigInt::NewFromWords(context,
2386
                                   0,
2387
                                   2,
2388
2
                                   reinterpret_cast<const uint64_t*>(type_tag));
2389

2
  CHECK_MAYBE_EMPTY_WITH_PREAMBLE(env, tag, napi_generic_failure);
2390
2391
4
  auto maybe_set = obj->SetPrivate(context, key, tag.ToLocalChecked());
2392

2
  CHECK_MAYBE_NOTHING_WITH_PREAMBLE(env, maybe_set, napi_generic_failure);
2393

2
  RETURN_STATUS_IF_FALSE_WITH_PREAMBLE(env,
2394
                                       maybe_set.FromJust(),
2395
                                       napi_generic_failure);
2396
2397
2
  return GET_RETURN_STATUS(env);
2398
}
2399
2400
NAPI_EXTERN napi_status
2401
6
napi_check_object_type_tag(napi_env env,
2402
                           napi_value object,
2403
                           const napi_type_tag* type_tag,
2404
                           bool* result) {
2405


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


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

6
  CHECK_ARG_WITH_PREAMBLE(env, type_tag);
2410

6
  CHECK_ARG_WITH_PREAMBLE(env, result);
2411
2412
  auto maybe_value = obj->GetPrivate(context,
2413
6
                                     NAPI_PRIVATE_KEY(context, type_tag));
2414

6
  CHECK_MAYBE_EMPTY_WITH_PREAMBLE(env, maybe_value, napi_generic_failure);
2415
6
  v8::Local<v8::Value> val = maybe_value.ToLocalChecked();
2416
2417
  // We consider the type check to have failed unless we reach the line below
2418
  // where we set whether the type check succeeded or not based on the
2419
  // comparison of the two type tags.
2420
6
  *result = false;
2421
6
  if (val->IsBigInt()) {
2422
    int sign;
2423
4
    int size = 2;
2424
    napi_type_tag tag;
2425
4
    val.As<v8::BigInt>()->ToWordsArray(&sign,
2426
                                       &size,
2427
                                       reinterpret_cast<uint64_t*>(&tag));
2428

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

4
      *result = (tag.lower == type_tag->lower && tag.upper == type_tag->upper);
2430
  }
2431
2432
6
  return GET_RETURN_STATUS(env);
2433
}
2434
2435
2
napi_status napi_get_value_external(napi_env env,
2436
                                    napi_value value,
2437
                                    void** result) {
2438
2
  CHECK_ENV(env);
2439
2
  CHECK_ARG(env, value);
2440
2
  CHECK_ARG(env, result);
2441
2442
2
  v8::Local<v8::Value> val = v8impl::V8LocalValueFromJsValue(value);
2443
2
  RETURN_STATUS_IF_FALSE(env, val->IsExternal(), napi_invalid_arg);
2444
2445
2
  v8::Local<v8::External> external_value = val.As<v8::External>();
2446
2
  *result = external_value->Value();
2447
2448
2
  return napi_clear_last_error(env);
2449
}
2450
2451
// Set initial_refcount to 0 for a weak reference, >0 for a strong reference.
2452
1541
napi_status napi_create_reference(napi_env env,
2453
                                  napi_value value,
2454
                                  uint32_t initial_refcount,
2455
                                  napi_ref* result) {
2456
  // Omit NAPI_PREAMBLE and GET_RETURN_STATUS because V8 calls here cannot throw
2457
  // JS exceptions.
2458
1541
  CHECK_ENV(env);
2459
1541
  CHECK_ARG(env, value);
2460
1541
  CHECK_ARG(env, result);
2461
2462
1541
  v8::Local<v8::Value> v8_value = v8impl::V8LocalValueFromJsValue(value);
2463

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


22
  NAPI_PREAMBLE(env);
2635
11
  CHECK_ARG(env, constructor);
2636
11
  if (argc > 0) {
2637
7
    CHECK_ARG(env, argv);
2638
  }
2639
11
  CHECK_ARG(env, result);
2640
2641
11
  v8::Local<v8::Context> context = env->context();
2642
2643
  v8::Local<v8::Function> ctor;
2644

33
  CHECK_TO_FUNCTION(env, ctor, constructor);
2645
2646
  auto maybe = ctor->NewInstance(context, argc,
2647
11
    reinterpret_cast<v8::Local<v8::Value>*>(const_cast<napi_value*>(argv)));
2648
2649
11
  CHECK_MAYBE_EMPTY(env, maybe, napi_pending_exception);
2650
2651
9
  *result = v8impl::JsValueFromV8LocalValue(maybe.ToLocalChecked());
2652
9
  return GET_RETURN_STATUS(env);
2653
}
2654
2655
2278
napi_status napi_instanceof(napi_env env,
2656
                            napi_value object,
2657
                            napi_value constructor,
2658
                            bool* result) {
2659


4556
  NAPI_PREAMBLE(env);
2660
2278
  CHECK_ARG(env, object);
2661
2278
  CHECK_ARG(env, result);
2662
2663
2278
  *result = false;
2664
2665
  v8::Local<v8::Object> ctor;
2666
2278
  v8::Local<v8::Context> context = env->context();
2667
2668

6834
  CHECK_TO_OBJECT(env, context, ctor, constructor);
2669
2670
2278
  if (!ctor->IsFunction()) {
2671
88
    napi_throw_type_error(env,
2672
                          "ERR_NAPI_CONS_FUNCTION",
2673
                          "Constructor must be a function");
2674
2675
88
    return napi_set_last_error(env, napi_function_expected);
2676
  }
2677
2678
2190
  napi_status status = napi_generic_failure;
2679
2680
2190
  v8::Local<v8::Value> val = v8impl::V8LocalValueFromJsValue(object);
2681
2190
  auto maybe_result = val->InstanceOf(context, ctor);
2682
2190
  CHECK_MAYBE_NOTHING(env, maybe_result, status);
2683
1166
  *result = maybe_result.FromJust();
2684
1166
  return GET_RETURN_STATUS(env);
2685
}
2686
2687
// Methods to support catching exceptions
2688
1233
napi_status napi_is_exception_pending(napi_env env, bool* result) {
2689
  // NAPI_PREAMBLE is not used here: this function must execute when there is a
2690
  // pending exception.
2691
1233
  CHECK_ENV(env);
2692
1233
  CHECK_ARG(env, result);
2693
2694
1233
  *result = !env->last_exception.IsEmpty();
2695
1233
  return napi_clear_last_error(env);
2696
}
2697
2698
2
napi_status napi_get_and_clear_last_exception(napi_env env,
2699
                                              napi_value* result) {
2700
  // NAPI_PREAMBLE is not used here: this function must execute when there is a
2701
  // pending exception.
2702
2
  CHECK_ENV(env);
2703
2
  CHECK_ARG(env, result);
2704
2705
2
  if (env->last_exception.IsEmpty()) {
2706
    return napi_get_undefined(env, result);
2707
  } else {
2708
2
    *result = v8impl::JsValueFromV8LocalValue(
2709
2
      v8::Local<v8::Value>::New(env->isolate, env->last_exception));
2710
2
    env->last_exception.Reset();
2711
  }
2712
2713
2
  return napi_clear_last_error(env);
2714
}
2715
2716
57
napi_status napi_is_arraybuffer(napi_env env, napi_value value, bool* result) {
2717
57
  CHECK_ENV(env);
2718
57
  CHECK_ARG(env, value);
2719
57
  CHECK_ARG(env, result);
2720
2721
57
  v8::Local<v8::Value> val = v8impl::V8LocalValueFromJsValue(value);
2722
57
  *result = val->IsArrayBuffer();
2723
2724
57
  return napi_clear_last_error(env);
2725
}
2726
2727
2
napi_status napi_create_arraybuffer(napi_env env,
2728
                                    size_t byte_length,
2729
                                    void** data,
2730
                                    napi_value* result) {
2731


4
  NAPI_PREAMBLE(env);
2732
2
  CHECK_ARG(env, result);
2733
2734
2
  v8::Isolate* isolate = env->isolate;
2735
  v8::Local<v8::ArrayBuffer> buffer =
2736
2
      v8::ArrayBuffer::New(isolate, byte_length);
2737
2738
  // Optionally return a pointer to the buffer's data, to avoid another call to
2739
  // retrieve it.
2740
2
  if (data != nullptr) {
2741
2
    *data = buffer->GetBackingStore()->Data();
2742
  }
2743
2744
2
  *result = v8impl::JsValueFromV8LocalValue(buffer);
2745
2
  return GET_RETURN_STATUS(env);
2746
}
2747
2748
6
napi_status napi_create_external_arraybuffer(napi_env env,
2749
                                             void* external_data,
2750
                                             size_t byte_length,
2751
                                             napi_finalize finalize_cb,
2752
                                             void* finalize_hint,
2753
                                             napi_value* result) {
2754
  // The API contract here is that the cleanup function runs on the JS thread,
2755
  // and is able to use napi_env. Implementing that properly is hard, so use the
2756
  // `Buffer` variant for easier implementation.
2757
  napi_value buffer;
2758
6
  STATUS_CALL(napi_create_external_buffer(
2759
      env,
2760
      byte_length,
2761
      external_data,
2762
      finalize_cb,
2763
      finalize_hint,
2764
      &buffer));
2765
6
  return napi_get_typedarray_info(
2766
      env,
2767
      buffer,
2768
      nullptr,
2769
      nullptr,
2770
      nullptr,
2771
      result,
2772
6
      nullptr);
2773
}
2774
2775
2
napi_status napi_get_arraybuffer_info(napi_env env,
2776
                                      napi_value arraybuffer,
2777
                                      void** data,
2778
                                      size_t* byte_length) {
2779
2
  CHECK_ENV(env);
2780
2
  CHECK_ARG(env, arraybuffer);
2781
2782
2
  v8::Local<v8::Value> value = v8impl::V8LocalValueFromJsValue(arraybuffer);
2783
2
  RETURN_STATUS_IF_FALSE(env, value->IsArrayBuffer(), napi_invalid_arg);
2784
2785
  std::shared_ptr<v8::BackingStore> backing_store =
2786
4
      value.As<v8::ArrayBuffer>()->GetBackingStore();
2787
2788
2
  if (data != nullptr) {
2789
2
    *data = backing_store->Data();
2790
  }
2791
2792
2
  if (byte_length != nullptr) {
2793
2
    *byte_length = backing_store->ByteLength();
2794
  }
2795
2796
2
  return napi_clear_last_error(env);
2797
}
2798
2799
44
napi_status napi_is_typedarray(napi_env env, napi_value value, bool* result) {
2800
44
  CHECK_ENV(env);
2801
44
  CHECK_ARG(env, value);
2802
44
  CHECK_ARG(env, result);
2803
2804
44
  v8::Local<v8::Value> val = v8impl::V8LocalValueFromJsValue(value);
2805
44
  *result = val->IsTypedArray();
2806
2807
44
  return napi_clear_last_error(env);
2808
}
2809
2810
34
napi_status napi_create_typedarray(napi_env env,
2811
                                   napi_typedarray_type type,
2812
                                   size_t length,
2813
                                   napi_value arraybuffer,
2814
                                   size_t byte_offset,
2815
                                   napi_value* result) {
2816


68
  NAPI_PREAMBLE(env);
2817
34
  CHECK_ARG(env, arraybuffer);
2818
34
  CHECK_ARG(env, result);
2819
2820
34
  v8::Local<v8::Value> value = v8impl::V8LocalValueFromJsValue(arraybuffer);
2821
34
  RETURN_STATUS_IF_FALSE(env, value->IsArrayBuffer(), napi_invalid_arg);
2822
2823



34
  v8::Local<v8::ArrayBuffer> buffer = value.As<v8::ArrayBuffer>();
2824
  v8::Local<v8::TypedArray> typedArray;
2825
2826



34
  switch (type) {
2827
4
    case napi_int8_array:
2828
4
      CREATE_TYPED_ARRAY(
2829
          env, Int8Array, 1, buffer, byte_offset, length, typedArray);
2830
3
      break;
2831
3
    case napi_uint8_array:
2832
3
      CREATE_TYPED_ARRAY(
2833
          env, Uint8Array, 1, buffer, byte_offset, length, typedArray);
2834
2
      break;
2835
2
    case napi_uint8_clamped_array:
2836
2
      CREATE_TYPED_ARRAY(
2837
          env, Uint8ClampedArray, 1, buffer, byte_offset, length, typedArray);
2838
1
      break;
2839
3
    case napi_int16_array:
2840

3
      CREATE_TYPED_ARRAY(
2841
          env, Int16Array, 2, buffer, byte_offset, length, typedArray);
2842
1
      break;
2843
3
    case napi_uint16_array:
2844

3
      CREATE_TYPED_ARRAY(
2845
          env, Uint16Array, 2, buffer, byte_offset, length, typedArray);
2846
1
      break;
2847
3
    case napi_int32_array:
2848

3
      CREATE_TYPED_ARRAY(
2849
          env, Int32Array, 4, buffer, byte_offset, length, typedArray);
2850
1
      break;
2851
3
    case napi_uint32_array:
2852

3
      CREATE_TYPED_ARRAY(
2853
          env, Uint32Array, 4, buffer, byte_offset, length, typedArray);
2854
1
      break;
2855
3
    case napi_float32_array:
2856

3
      CREATE_TYPED_ARRAY(
2857
          env, Float32Array, 4, buffer, byte_offset, length, typedArray);
2858
1
      break;
2859
4
    case napi_float64_array:
2860

4
      CREATE_TYPED_ARRAY(
2861
          env, Float64Array, 8, buffer, byte_offset, length, typedArray);
2862
2
      break;
2863
3
    case napi_bigint64_array:
2864

3
      CREATE_TYPED_ARRAY(
2865
          env, BigInt64Array, 8, buffer, byte_offset, length, typedArray);
2866
1
      break;
2867
3
    case napi_biguint64_array:
2868

3
      CREATE_TYPED_ARRAY(
2869
          env, BigUint64Array, 8, buffer, byte_offset, length, typedArray);
2870
1
      break;
2871
    default:
2872
      return napi_set_last_error(env, napi_invalid_arg);
2873
  }
2874
2875
15
  *result = v8impl::JsValueFromV8LocalValue(typedArray);
2876
15
  return GET_RETURN_STATUS(env);
2877
}
2878
2879
50
napi_status napi_get_typedarray_info(napi_env env,
2880
                                     napi_value typedarray,
2881
                                     napi_typedarray_type* type,
2882
                                     size_t* length,
2883
                                     void** data,
2884
                                     napi_value* arraybuffer,
2885
                                     size_t* byte_offset) {
2886
50
  CHECK_ENV(env);
2887
50
  CHECK_ARG(env, typedarray);
2888
2889
50
  v8::Local<v8::Value> value = v8impl::V8LocalValueFromJsValue(typedarray);
2890
50
  RETURN_STATUS_IF_FALSE(env, value->IsTypedArray(), napi_invalid_arg);
2891
2892
50
  v8::Local<v8::TypedArray> array = value.As<v8::TypedArray>();
2893
2894
50
  if (type != nullptr) {
2895
32
    if (value->IsInt8Array()) {
2896
2
      *type = napi_int8_array;
2897
30
    } else if (value->IsUint8Array()) {
2898
3
      *type = napi_uint8_array;
2899
27
    } else if (value->IsUint8ClampedArray()) {
2900
2
      *type = napi_uint8_clamped_array;
2901
25
    } else if (value->IsInt16Array()) {
2902
3
      *type = napi_int16_array;
2903
22
    } else if (value->IsUint16Array()) {
2904
3
      *type = napi_uint16_array;
2905
19
    } else if (value->IsInt32Array()) {
2906
3
      *type = napi_int32_array;
2907
16
    } else if (value->IsUint32Array()) {
2908
3
      *type = napi_uint32_array;
2909
13
    } else if (value->IsFloat32Array()) {
2910
3
      *type = napi_float32_array;
2911
10
    } else if (value->IsFloat64Array()) {
2912
4
      *type = napi_float64_array;
2913
6
    } else if (value->IsBigInt64Array()) {
2914
3
      *type = napi_bigint64_array;
2915
3
    } else if (value->IsBigUint64Array()) {
2916
3
      *type = napi_biguint64_array;
2917
    }
2918
  }
2919
2920
50
  if (length != nullptr) {
2921
32
    *length = array->Length();
2922
  }
2923
2924
  v8::Local<v8::ArrayBuffer> buffer;
2925

50
  if (data != nullptr || arraybuffer != nullptr) {
2926
    // Calling Buffer() may have the side effect of allocating the buffer,
2927
    // so only do this when it’s needed.
2928
50
    buffer = array->Buffer();
2929
  }
2930
2931
50
  if (data != nullptr) {
2932
    *data = static_cast<uint8_t*>(buffer->GetBackingStore()->Data()) +
2933
            array->ByteOffset();
2934
  }
2935
2936
50
  if (arraybuffer != nullptr) {
2937
50
    *arraybuffer = v8impl::JsValueFromV8LocalValue(buffer);
2938
  }
2939
2940
50
  if (byte_offset != nullptr) {
2941
32
    *byte_offset = array->ByteOffset();
2942
  }
2943
2944
50
  return napi_clear_last_error(env);
2945
}
2946
2947
2
napi_status napi_create_dataview(napi_env env,
2948
                                 size_t byte_length,
2949
                                 napi_value arraybuffer,
2950
                                 size_t byte_offset,
2951
                                 napi_value* result) {
2952


4
  NAPI_PREAMBLE(env);
2953
2
  CHECK_ARG(env, arraybuffer);
2954
2
  CHECK_ARG(env, result);
2955
2956
2
  v8::Local<v8::Value> value = v8impl::V8LocalValueFromJsValue(arraybuffer);
2957
2
  RETURN_STATUS_IF_FALSE(env, value->IsArrayBuffer(), napi_invalid_arg);
2958
2959
2
  v8::Local<v8::ArrayBuffer> buffer = value.As<v8::ArrayBuffer>();
2960
2
  if (byte_length + byte_offset > buffer->ByteLength()) {
2961
1
    napi_throw_range_error(
2962
        env,
2963
        "ERR_NAPI_INVALID_DATAVIEW_ARGS",
2964
        "byte_offset + byte_length should be less than or "
2965
        "equal to the size in bytes of the array passed in");
2966
1
    return napi_set_last_error(env, napi_pending_exception);
2967
  }
2968
  v8::Local<v8::DataView> DataView = v8::DataView::New(buffer, byte_offset,
2969
1
                                                       byte_length);
2970
2971
1
  *result = v8impl::JsValueFromV8LocalValue(DataView);
2972
1
  return GET_RETURN_STATUS(env);
2973
}
2974
2975
1
napi_status napi_is_dataview(napi_env env, napi_value value, bool* result) {
2976
1
  CHECK_ENV(env);
2977
1
  CHECK_ARG(env, value);
2978
1
  CHECK_ARG(env, result);
2979
2980
1
  v8::Local<v8::Value> val = v8impl::V8LocalValueFromJsValue(value);
2981
1
  *result = val->IsDataView();
2982
2983
1
  return napi_clear_last_error(env);
2984
}
2985
2986
1
napi_status napi_get_dataview_info(napi_env env,
2987
                                   napi_value dataview,
2988
                                   size_t* byte_length,
2989
                                   void** data,
2990
                                   napi_value* arraybuffer,
2991
                                   size_t* byte_offset) {
2992
1
  CHECK_ENV(env);
2993
1
  CHECK_ARG(env, dataview);
2994
2995
1
  v8::Local<v8::Value> value = v8impl::V8LocalValueFromJsValue(dataview);
2996
1
  RETURN_STATUS_IF_FALSE(env, value->IsDataView(), napi_invalid_arg);
2997
2998
1
  v8::Local<v8::DataView> array = value.As<v8::DataView>();
2999
3000
1
  if (byte_length != nullptr) {
3001
1
    *byte_length = array->ByteLength();
3002
  }
3003
3004
  v8::Local<v8::ArrayBuffer> buffer;
3005

1
  if (data != nullptr || arraybuffer != nullptr) {
3006
    // Calling Buffer() may have the side effect of allocating the buffer,
3007
    // so only do this when it’s needed.
3008
1
    buffer = array->Buffer();
3009
  }
3010
3011
1
  if (data != nullptr) {
3012
    *data = static_cast<uint8_t*>(buffer->GetBackingStore()->Data()) +
3013
            array->ByteOffset();
3014
  }
3015
3016
1
  if (arraybuffer != nullptr) {
3017
1
    *arraybuffer = v8impl::JsValueFromV8LocalValue(buffer);
3018
  }
3019
3020
1
  if (byte_offset != nullptr) {
3021
1
    *byte_offset = array->ByteOffset();
3022
  }
3023
3024
1
  return napi_clear_last_error(env);
3025
}
3026
3027
1
napi_status napi_get_version(napi_env env, uint32_t* result) {
3028
1
  CHECK_ENV(env);
3029
1
  CHECK_ARG(env, result);
3030
1
  *result = NAPI_VERSION;
3031
1
  return napi_clear_last_error(env);
3032
}
3033
3034
5
napi_status napi_create_promise(napi_env env,
3035
                                napi_deferred* deferred,
3036
                                napi_value* promise) {
3037


10
  NAPI_PREAMBLE(env);
3038
5
  CHECK_ARG(env, deferred);
3039
5
  CHECK_ARG(env, promise);
3040
3041
5
  auto maybe = v8::Promise::Resolver::New(env->context());
3042
5
  CHECK_MAYBE_EMPTY(env, maybe, napi_generic_failure);
3043
3044
5
  auto v8_resolver = maybe.ToLocalChecked();
3045
5
  auto v8_deferred = new v8impl::Persistent<v8::Value>();
3046
5
  v8_deferred->Reset(env->isolate, v8_resolver);
3047
3048
5
  *deferred = v8impl::JsDeferredFromNodePersistent(v8_deferred);
3049
10
  *promise = v8impl::JsValueFromV8LocalValue(v8_resolver->GetPromise());
3050
5
  return GET_RETURN_STATUS(env);
3051
}
3052
3053
4
napi_status napi_resolve_deferred(napi_env env,
3054
                                  napi_deferred deferred,
3055
                                  napi_value resolution) {
3056
4
  return v8impl::ConcludeDeferred(env, deferred, resolution, true);
3057
}
3058
3059
1
napi_status napi_reject_deferred(napi_env env,
3060
                                 napi_deferred deferred,
3061
                                 napi_value resolution) {
3062
1
  return v8impl::ConcludeDeferred(env, deferred, resolution, false);
3063
}
3064
3065
7
napi_status napi_is_promise(napi_env env,
3066
                            napi_value value,
3067
                            bool* is_promise) {
3068
7
  CHECK_ENV(env);
3069
7
  CHECK_ARG(env, value);
3070
7
  CHECK_ARG(env, is_promise);
3071
3072
14
  *is_promise = v8impl::V8LocalValueFromJsValue(value)->IsPromise();
3073
3074
7
  return napi_clear_last_error(env);
3075
}
3076
3077
1
napi_status napi_create_date(napi_env env,
3078
                             double time,
3079
                             napi_value* result) {
3080


2
  NAPI_PREAMBLE(env);
3081
1
  CHECK_ARG(env, result);
3082
3083
1
  v8::MaybeLocal<v8::Value> maybe_date = v8::Date::New(env->context(), time);
3084
1
  CHECK_MAYBE_EMPTY(env, maybe_date, napi_generic_failure);
3085
3086
1
  *result = v8impl::JsValueFromV8LocalValue(maybe_date.ToLocalChecked());
3087
3088
1
  return GET_RETURN_STATUS(env);
3089
}
3090
3091
7
napi_status napi_is_date(napi_env env,
3092
                         napi_value value,
3093
                         bool* is_date) {
3094
7
  CHECK_ENV(env);
3095
7
  CHECK_ARG(env, value);
3096
7
  CHECK_ARG(env, is_date);
3097
3098
14
  *is_date = v8impl::V8LocalValueFromJsValue(value)->IsDate();
3099
3100
7
  return napi_clear_last_error(env);
3101
}
3102
3103
1
napi_status napi_get_date_value(napi_env env,
3104
                                napi_value value,
3105
                                double* result) {
3106


2
  NAPI_PREAMBLE(env);
3107
1
  CHECK_ARG(env, value);
3108
1
  CHECK_ARG(env, result);
3109
3110
1
  v8::Local<v8::Value> val = v8impl::V8LocalValueFromJsValue(value);
3111
1
  RETURN_STATUS_IF_FALSE(env, val->IsDate(), napi_date_expected);
3112
3113
1
  v8::Local<v8::Date> date = val.As<v8::Date>();
3114
1
  *result = date->ValueOf();
3115
3116
1
  return GET_RETURN_STATUS(env);
3117
}
3118
3119
2
napi_status napi_run_script(napi_env env,
3120
                            napi_value script,
3121
                            napi_value* result) {
3122


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

52
  *result = value->IsArrayBuffer() &&
3234
52
            value.As<v8::ArrayBuffer>()->GetBackingStore()->Data() == nullptr;
3235
3236
26
  return napi_clear_last_error(env);
3237
}