GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: js_native_api_v8.cc Lines: 1420 1459 97.3 %
Date: 2022-01-15 04:15:29 Branches: 1136 1788 63.5 %

Line Branch Exec Source
1
#include <climits>  // INT_MAX
2
#include <cmath>
3
#include <algorithm>
4
#define NAPI_EXPERIMENTAL
5
#include "env-inl.h"
6
#include "js_native_api_v8.h"
7
#include "js_native_api.h"
8
#include "util-inl.h"
9
10
#define CHECK_MAYBE_NOTHING(env, maybe, status) \
11
  RETURN_STATUS_IF_FALSE((env), !((maybe).IsNothing()), (status))
12
13
#define CHECK_MAYBE_NOTHING_WITH_PREAMBLE(env, maybe, status) \
14
  RETURN_STATUS_IF_FALSE_WITH_PREAMBLE((env), !((maybe).IsNothing()), (status))
15
16
#define CHECK_TO_NUMBER(env, context, result, src) \
17
  CHECK_TO_TYPE((env), Number, (context), (result), (src), napi_number_expected)
18
19
// n-api defines NAPI_AUTO_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
473
V8NameFromPropertyDescriptor(napi_env env,
65
                             const napi_property_descriptor* p,
66
                             v8::Local<v8::Name>* result) {
67
473
  if (p->utf8name != nullptr) {
68

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

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


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

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


70
  NAPI_PREAMBLE(env);
201
35
  CHECK_ARG(env, js_object);
202
35
  if (action == KeepWrap) {
203
27
    CHECK_ARG(env, result);
204
  }
205
206
35
  v8::Local<v8::Context> context = env->context();
207
208
35
  v8::Local<v8::Value> value = v8impl::V8LocalValueFromJsValue(js_object);
209
35
  RETURN_STATUS_IF_FALSE(env, value->IsObject(), napi_invalid_arg);
210
35
  v8::Local<v8::Object> obj = value.As<v8::Object>();
211
212
35
  auto val = obj->GetPrivate(context, NAPI_PRIVATE_KEY(context, wrapper))
213
35
      .ToLocalChecked();
214
35
  RETURN_STATUS_IF_FALSE(env, val->IsExternal(), napi_invalid_arg);
215
  Reference* reference =
216
35
      static_cast<v8impl::Reference*>(val.As<v8::External>()->Value());
217
218
35
  if (result) {
219
35
    *result = reference->Data();
220
  }
221
222
35
  if (action == RemoveWrap) {
223
16
    CHECK(obj->DeletePrivate(context, NAPI_PRIVATE_KEY(context, wrapper))
224
        .FromJust());
225
8
    Reference::Delete(reference);
226
  }
227
228
35
  return GET_RETURN_STATUS(env);
229
}
230
231
//=== Function napi_callback wrapper =================================
232
233
// Use this data structure to associate callback data with each N-API function
234
// exposed to JavaScript. The structure is stored in a v8::External which gets
235
// passed into our callback wrapper. This reduces the performance impact of
236
// calling through N-API.
237
// Ref: benchmark/misc/function_call
238
// Discussion (incl. perf. data): https://github.com/nodejs/node/pull/21072
239
class CallbackBundle {
240
 public:
241
  // Creates an object to be made available to the static function callback
242
  // wrapper, used to retrieve the native callback function and data pointer.
243
  static inline v8::Local<v8::Value>
244
482
  New(napi_env env, napi_callback cb, void* data) {
245
482
    CallbackBundle* bundle = new CallbackBundle();
246
482
    bundle->cb = cb;
247
482
    bundle->cb_data = data;
248
482
    bundle->env = env;
249
250
482
    v8::Local<v8::Value> cbdata = v8::External::New(env->isolate, bundle);
251
482
    Reference::New(env, cbdata, 0, true, Delete, bundle, nullptr);
252
482
    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
473
  static void Delete(napi_env env, void* data, void* hint) {
259
473
    CallbackBundle* bundle = static_cast<CallbackBundle*>(data);
260
473
    delete bundle;
261
473
  }
262
};
263
264
// Base class extended by classes that wrap V8 function and property callback
265
// info.
266
class CallbackWrapper {
267
 public:
268
4654
  inline CallbackWrapper(napi_value this_arg, size_t args_length, void* data)
269
4654
      : _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
4654
  inline CallbackWrapperBase(const v8::FunctionCallbackInfo<v8::Value>& cbinfo,
290
                             const size_t args_length)
291
4654
      : CallbackWrapper(JsValueFromV8LocalValue(cbinfo.This()),
292
                        args_length,
293
                        nullptr),
294
9308
        _cbinfo(cbinfo) {
295
4654
    _bundle = reinterpret_cast<CallbackBundle*>(
296
9308
        cbinfo.Data().As<v8::External>()->Value());
297
4654
    _data = _bundle->cb_data;
298
4654
  }
299
300
 protected:
301
4654
  inline void InvokeCallback() {
302
4654
    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
4654
    napi_env env = _bundle->env;
307
4654
    napi_callback cb = _bundle->cb;
308
309
4654
    napi_value result = nullptr;
310
4654
    bool exceptionOccurred = false;
311
4654
    env->CallIntoModule([&](napi_env env) {
312
4654
      result = cb(env, cbinfo_wrapper);
313
5885
    }, [&](napi_env env, v8::Local<v8::Value> value) {
314
1231
      exceptionOccurred = true;
315
1231
      env->isolate->ThrowException(value);
316
1231
    });
317
318

4654
    if (!exceptionOccurred && (result != nullptr)) {
319
2815
      this->SetReturnValue(result);
320
    }
321
4654
  }
322
323
  const v8::FunctionCallbackInfo<v8::Value>& _cbinfo;
324
  CallbackBundle* _bundle;
325
};
326
327
class FunctionCallbackWrapper
328
    : public CallbackWrapperBase {
329
 public:
330
4654
  static void Invoke(const v8::FunctionCallbackInfo<v8::Value>& info) {
331
4654
    FunctionCallbackWrapper cbwrapper(info);
332
4654
    cbwrapper.InvokeCallback();
333
4654
  }
334
335
451
  static inline napi_status NewFunction(napi_env env,
336
                                        napi_callback cb,
337
                                        void* cb_data,
338
                                        v8::Local<v8::Function>* result) {
339
451
    v8::Local<v8::Value> cbdata = v8impl::CallbackBundle::New(env, cb, cb_data);
340
451
    RETURN_STATUS_IF_FALSE(env, !cbdata.IsEmpty(), napi_generic_failure);
341
342
    v8::MaybeLocal<v8::Function> maybe_function =
343
451
        v8::Function::New(env->context(), Invoke, cbdata);
344
451
    CHECK_MAYBE_EMPTY(env, maybe_function, napi_generic_failure);
345
346
451
    *result = maybe_function.ToLocalChecked();
347
451
    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
4654
  explicit FunctionCallbackWrapper(
363
      const v8::FunctionCallbackInfo<v8::Value>& cbinfo)
364
4654
      : 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
2815
  void SetReturnValue(napi_value value) override {
394
2815
    v8::Local<v8::Value> val = v8impl::V8LocalValueFromJsValue(value);
395
2815
    _cbinfo.GetReturnValue().Set(val);
396
2815
  }
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
3068
RefBase::RefBase(napi_env env,
459
                 uint32_t initial_refcount,
460
                 bool delete_self,
461
                 napi_finalize finalize_callback,
462
                 void* finalize_data,
463
3068
                 void* finalize_hint)
464
    : Finalizer(env, finalize_callback, finalize_data, finalize_hint),
465
      _refcount(initial_refcount),
466
3068
      _delete_self(delete_self) {
467
3068
  Link(finalize_callback == nullptr ? &env->reflist : &env->finalizing_reflist);
468
3068
}
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
6130
RefBase::~RefBase() {
485
6116
  Unlink();
486
6130
}
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
3072
void RefBase::Delete(RefBase* reference) {
508

4092
  if ((reference->RefCount() != 0) || (reference->_delete_self) ||
509
1020
      (reference->_finalize_ran)) {
510
3058
    delete reference;
511
  } else {
512
    // defer until finalizer runs as
513
    // it may already be queued
514
14
    reference->_delete_self = true;
515
  }
516
3072
}
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
6642
uint32_t RefBase::RefCount() {
530
6642
  return _refcount;
531
}
532
533
2524
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

2524
  if (is_env_teardown && RefCount() > 0) _refcount = 0;
554
555
2524
  if (_finalize_callback != nullptr) {
556
    // This ensures that we never call the finalizer twice.
557
1504
    napi_finalize fini = _finalize_callback;
558
1504
    _finalize_callback = nullptr;
559
1504
    _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

2524
  if (_delete_self || is_env_teardown) {
566
1518
    Delete(this);
567
  } else {
568
1006
    _finalize_ran = true;
569
  }
570
2524
}
571
572
template <typename... Args>
573
3061
Reference::Reference(napi_env env, v8::Local<v8::Value> value, Args&&... args)
574
15305
    : RefBase(env, std::forward<Args>(args)...),
575
3061
      _persistent(env->isolate, value),
576
3061
      _secondPassParameter(new SecondPassCallParameterRef(this)),
577
6122
      _secondPassScheduled(false) {
578
3061
  if (RefCount() == 0) {
579
2522
    SetWeak();
580
  }
581
3061
}
582
583
3061
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
3061
                       finalize_hint);
597
}
598
599
18306
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
6102
  if (!_secondPassScheduled) {
604
2058
    delete _secondPassParameter;
605
  }
606
12204
}
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
2517
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
2517
  if (is_env_teardown) {
640
496
    ClearWeak();
641
  }
642
643
  // Chain up to perform the rest of the finalization.
644
2517
  RefBase::Finalize(is_env_teardown);
645
2517
}
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
498
void Reference::ClearWeak() {
653
498
  if (!_persistent.IsEmpty()) {
654
496
    _persistent.ClearWeak();
655
  }
656
498
  if (_secondPassParameter != nullptr) {
657
498
    *_secondPassParameter = nullptr;
658
  }
659
498
}
660
661
// Mark the reference as weak and eligible for collection
662
// by the gc.
663
2524
void Reference::SetWeak() {
664
2524
  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
2524
  _persistent.SetWeak(
671
      _secondPassParameter, FinalizeCallback, v8::WeakCallbackType::kParameter);
672
2524
  *_secondPassParameter = this;
673
}
674
675
// The N-API finalizer callback may make calls into the engine. V8's heap is
676
// not in a consistent state during the weak callback, and therefore it does
677
// not support calls back into it. However, it provides a mechanism for adding
678
// a finalizer which may make calls back into the engine by allowing us to
679
// attach such a second-pass finalizer from the first pass finalizer. Thus,
680
// we do that here to ensure that the N-API finalizer callback is free to call
681
// into the engine.
682
2022
void Reference::FinalizeCallback(
683
    const v8::WeakCallbackInfo<SecondPassCallParameterRef>& data) {
684
2022
  SecondPassCallParameterRef* parameter = data.GetParameter();
685
2022
  Reference* reference = *parameter;
686
2022
  if (reference == nullptr) {
687
    return;
688
  }
689
690
  // The reference must be reset during the first pass.
691
2022
  reference->_persistent.Reset();
692
  // Mark the parameter not delete-able until the second pass callback is
693
  // invoked.
694
2022
  reference->_secondPassScheduled = true;
695
696
2022
  data.SetSecondPassCallback(SecondPassCallback);
697
}
698
699
// Second pass callbacks are scheduled with platform tasks. At env teardown,
700
// the tasks may have already be scheduled and we are unable to cancel the
701
// second pass callback task. We have to make sure that parameter is kept
702
// alive until the second pass callback is been invoked. In order to do
703
// this and still allow our code to Finalize/delete the Reference during
704
// shutdown we have to use a separately allocated parameter instead
705
// of a parameter within the Reference object itself. This is what
706
// is stored in _secondPassParameter and it is allocated in the
707
// constructor for the Reference.
708
2022
void Reference::SecondPassCallback(
709
    const v8::WeakCallbackInfo<SecondPassCallParameterRef>& data) {
710
2022
  SecondPassCallParameterRef* parameter = data.GetParameter();
711
2022
  Reference* reference = *parameter;
712
2022
  delete parameter;
713
2022
  if (reference == nullptr) {
714
    // the reference itself has already been deleted so nothing to do
715
1
    return;
716
  }
717
2021
  reference->_secondPassParameter = nullptr;
718
2021
  reference->Finalize();
719
}
720
721
}  // end of namespace v8impl
722
723
// Warning: Keep in-sync with napi_status enum
724
static
725
const char* error_messages[] = {nullptr,
726
                                "Invalid argument",
727
                                "An object was expected",
728
                                "A string was expected",
729
                                "A string or symbol was expected",
730
                                "A function was expected",
731
                                "A number was expected",
732
                                "A boolean was expected",
733
                                "An array was expected",
734
                                "Unknown failure",
735
                                "An exception is pending",
736
                                "The async work item was cancelled",
737
                                "napi_escape_handle already called on scope",
738
                                "Invalid handle scope usage",
739
                                "Invalid callback scope usage",
740
                                "Thread-safe function queue is full",
741
                                "Thread-safe function handle is closing",
742
                                "A bigint was expected",
743
                                "A date was expected",
744
                                "An arraybuffer was expected",
745
                                "A detachable arraybuffer was expected",
746
                                "Main thread would deadlock",
747
};
748
749
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
  // Wait until someone requests the last error information to fetch the error
765
  // message string
766
2624
  env->last_error.error_message =
767
2624
      error_messages[env->last_error.error_code];
768
769
1312
  if (env->last_error.error_code == napi_ok) {
770
10
     napi_clear_last_error(env);
771
  }
772
1312
  *result = &(env->last_error);
773
1312
  return napi_ok;
774
}
775
776
15
napi_status napi_create_function(napi_env env,
777
                                 const char* utf8name,
778
                                 size_t length,
779
                                 napi_callback cb,
780
                                 void* callback_data,
781
                                 napi_value* result) {
782


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


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


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


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

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


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

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

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


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

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

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


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

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


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

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


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

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


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

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


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

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

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

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


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

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

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


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

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

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


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

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

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


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

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


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

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


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

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


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

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

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

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

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

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


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

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

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


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

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

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


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


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


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

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

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

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

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


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

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

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

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

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


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

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


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


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

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


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

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


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

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


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

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

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


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




44
GEN_COERCE_FUNCTION(NUMBER, Number, number)
2355




51
GEN_COERCE_FUNCTION(OBJECT, Object, object)
2356




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


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


4
  NAPI_PREAMBLE(env);
2413
2
  v8::Local<v8::Context> context = env->context();
2414
  v8::Local<v8::Object> obj;
2415


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

2
  CHECK_ARG_WITH_PREAMBLE(env, type_tag);
2417
2418
2
  auto key = NAPI_PRIVATE_KEY(context, type_tag);
2419
2
  auto maybe_has = obj->HasPrivate(context, key);
2420

2
  CHECK_MAYBE_NOTHING_WITH_PREAMBLE(env, maybe_has, napi_generic_failure);
2421

2
  RETURN_STATUS_IF_FALSE_WITH_PREAMBLE(env,
2422
                                       !maybe_has.FromJust(),
2423
                                       napi_invalid_arg);
2424
2425
  auto tag = v8::BigInt::NewFromWords(context,
2426
                                   0,
2427
                                   2,
2428
2
                                   reinterpret_cast<const uint64_t*>(type_tag));
2429

2
  CHECK_MAYBE_EMPTY_WITH_PREAMBLE(env, tag, napi_generic_failure);
2430
2431
4
  auto maybe_set = obj->SetPrivate(context, key, tag.ToLocalChecked());
2432

2
  CHECK_MAYBE_NOTHING_WITH_PREAMBLE(env, maybe_set, napi_generic_failure);
2433

2
  RETURN_STATUS_IF_FALSE_WITH_PREAMBLE(env,
2434
                                       maybe_set.FromJust(),
2435
                                       napi_generic_failure);
2436
2437
2
  return GET_RETURN_STATUS(env);
2438
}
2439
2440
NAPI_EXTERN napi_status
2441
6
napi_check_object_type_tag(napi_env env,
2442
                           napi_value object,
2443
                           const napi_type_tag* type_tag,
2444
                           bool* result) {
2445


12
  NAPI_PREAMBLE(env);
2446
6
  v8::Local<v8::Context> context = env->context();
2447
  v8::Local<v8::Object> obj;
2448


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

6
  CHECK_ARG_WITH_PREAMBLE(env, type_tag);
2450

6
  CHECK_ARG_WITH_PREAMBLE(env, result);
2451
2452
  auto maybe_value = obj->GetPrivate(context,
2453
6
                                     NAPI_PRIVATE_KEY(context, type_tag));
2454

6
  CHECK_MAYBE_EMPTY_WITH_PREAMBLE(env, maybe_value, napi_generic_failure);
2455
6
  v8::Local<v8::Value> val = maybe_value.ToLocalChecked();
2456
2457
  // We consider the type check to have failed unless we reach the line below
2458
  // where we set whether the type check succeeded or not based on the
2459
  // comparison of the two type tags.
2460
6
  *result = false;
2461
6
  if (val->IsBigInt()) {
2462
    int sign;
2463
4
    int size = 2;
2464
    napi_type_tag tag;
2465
4
    val.As<v8::BigInt>()->ToWordsArray(&sign,
2466
                                       &size,
2467
                                       reinterpret_cast<uint64_t*>(&tag));
2468

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

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

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


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

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


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

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


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


68
  NAPI_PREAMBLE(env);
2857
34
  CHECK_ARG(env, arraybuffer);
2858
34
  CHECK_ARG(env, result);
2859
2860
34
  v8::Local<v8::Value> value = v8impl::V8LocalValueFromJsValue(arraybuffer);
2861
34
  RETURN_STATUS_IF_FALSE(env, value->IsArrayBuffer(), napi_invalid_arg);
2862
2863



34
  v8::Local<v8::ArrayBuffer> buffer = value.As<v8::ArrayBuffer>();
2864
  v8::Local<v8::TypedArray> typedArray;
2865
2866



34
  switch (type) {
2867
4
    case napi_int8_array:
2868
4
      CREATE_TYPED_ARRAY(
2869
          env, Int8Array, 1, buffer, byte_offset, length, typedArray);
2870
3
      break;
2871
3
    case napi_uint8_array:
2872
3
      CREATE_TYPED_ARRAY(
2873
          env, Uint8Array, 1, buffer, byte_offset, length, typedArray);
2874
2
      break;
2875
2
    case napi_uint8_clamped_array:
2876
2
      CREATE_TYPED_ARRAY(
2877
          env, Uint8ClampedArray, 1, buffer, byte_offset, length, typedArray);
2878
1
      break;
2879
3
    case napi_int16_array:
2880

3
      CREATE_TYPED_ARRAY(
2881
          env, Int16Array, 2, buffer, byte_offset, length, typedArray);
2882
1
      break;
2883
3
    case napi_uint16_array:
2884

3
      CREATE_TYPED_ARRAY(
2885
          env, Uint16Array, 2, buffer, byte_offset, length, typedArray);
2886
1
      break;
2887
3
    case napi_int32_array:
2888

3
      CREATE_TYPED_ARRAY(
2889
          env, Int32Array, 4, buffer, byte_offset, length, typedArray);
2890
1
      break;
2891
3
    case napi_uint32_array:
2892

3
      CREATE_TYPED_ARRAY(
2893
          env, Uint32Array, 4, buffer, byte_offset, length, typedArray);
2894
1
      break;
2895
3
    case napi_float32_array:
2896

3
      CREATE_TYPED_ARRAY(
2897
          env, Float32Array, 4, buffer, byte_offset, length, typedArray);
2898
1
      break;
2899
4
    case napi_float64_array:
2900

4
      CREATE_TYPED_ARRAY(
2901
          env, Float64Array, 8, buffer, byte_offset, length, typedArray);
2902
2
      break;
2903
3
    case napi_bigint64_array:
2904

3
      CREATE_TYPED_ARRAY(
2905
          env, BigInt64Array, 8, buffer, byte_offset, length, typedArray);
2906
1
      break;
2907
3
    case napi_biguint64_array:
2908

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

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


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

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


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


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


2
  NAPI_PREAMBLE(env);
3147
1
  CHECK_ARG(env, value);
3148
1
  CHECK_ARG(env, result);
3149
3150
1
  v8::Local<v8::Value> val = v8impl::V8LocalValueFromJsValue(value);
3151
1
  RETURN_STATUS_IF_FALSE(env, val->IsDate(), napi_date_expected);
3152
3153
1
  v8::Local<v8::Date> date = val.As<v8::Date>();
3154
1
  *result = date->ValueOf();
3155
3156
1
  return GET_RETURN_STATUS(env);
3157
}
3158
3159
2
napi_status napi_run_script(napi_env env,
3160
                            napi_value script,
3161
                            napi_value* result) {
3162


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

52
  *result = value->IsArrayBuffer() &&
3273
52
            value.As<v8::ArrayBuffer>()->GetBackingStore()->Data() == nullptr;
3274
3275
26
  return napi_clear_last_error(env);
3276
}