GCC Code Coverage Report
Directory: ../ Exec Total Coverage
File: /home/iojs/build/workspace/node-test-commit-linux-coverage-daily/nodes/benchmark/out/../src/js_native_api_v8.cc Lines: 1409 1443 97.6 %
Date: 2021-06-10 04:11:54 Branches: 1072 1708 62.8 %

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

1329
    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
445
  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

32
  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
4
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
4
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


15
  NAPI_PREAMBLE(env);
170
5
  CHECK_ARG(env, result);
171
172
5
  v8::Local<v8::Context> context = env->context();
173
  v8impl::Persistent<v8::Value>* deferred_ref =
174
5
      NodePersistentFromJsDeferred(deferred);
175
  v8::Local<v8::Value> v8_deferred =
176
10
      v8::Local<v8::Value>::New(env->isolate, *deferred_ref);
177
178
5
  auto v8_resolver = v8::Local<v8::Promise::Resolver>::Cast(v8_deferred);
179
180
  v8::Maybe<bool> success = is_resolved ?
181
8
      v8_resolver->Resolve(context, v8impl::V8LocalValueFromJsValue(result)) :
182
10
      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
// Wrapper around v8impl::Persistent that implements reference counting.
192
class RefBase : protected Finalizer, RefTracker {
193
 protected:
194
3040
  RefBase(napi_env env,
195
          uint32_t initial_refcount,
196
          bool delete_self,
197
          napi_finalize finalize_callback,
198
          void* finalize_data,
199
          void* finalize_hint)
200
3040
       : Finalizer(env, finalize_callback, finalize_data, finalize_hint),
201
        _refcount(initial_refcount),
202
3040
        _delete_self(delete_self) {
203
3040
    Link(finalize_callback == nullptr
204
        ? &env->reflist
205
3040
        : &env->finalizing_reflist);
206
3040
  }
207
208
 public:
209
7
  static RefBase* New(napi_env env,
210
                      uint32_t initial_refcount,
211
                      bool delete_self,
212
                      napi_finalize finalize_callback,
213
                      void* finalize_data,
214
                      void* finalize_hint) {
215
    return new RefBase(env,
216
                       initial_refcount,
217
                       delete_self,
218
                       finalize_callback,
219
                       finalize_data,
220
7
                       finalize_hint);
221
  }
222
223
3037
  virtual ~RefBase() { Unlink(); }
224
225
57
  inline void* Data() {
226
57
    return _finalize_data;
227
  }
228
229
  // Delete is called in 2 ways. Either from the finalizer or
230
  // from one of Unwrap or napi_delete_reference.
231
  //
232
  // When it is called from Unwrap or napi_delete_reference we only
233
  // want to do the delete if the finalizer has already run or
234
  // cannot have been queued to run (ie the reference count is > 0),
235
  // otherwise we may crash when the finalizer does run.
236
  // If the finalizer may have been queued and has not already run
237
  // delay the delete until the finalizer runs by not doing the delete
238
  // and setting _delete_self to true so that the finalizer will
239
  // delete it when it runs.
240
  //
241
  // The second way this is called is from
242
  // the finalizer and _delete_self is set. In this case we
243
  // know we need to do the deletion so just do it.
244
3042
  static inline void Delete(RefBase* reference) {
245

8594
    if ((reference->RefCount() != 0) ||
246

4060
        (reference->_delete_self) ||
247
1018
        (reference->_finalize_ran)) {
248
3030
      delete reference;
249
    } else {
250
      // defer until finalizer runs as
251
      // it may already be queued
252
12
      reference->_delete_self = true;
253
    }
254
3042
  }
255
256
3
  inline uint32_t Ref() {
257
3
    return ++_refcount;
258
  }
259
260
3
  inline uint32_t Unref() {
261
3
    if (_refcount == 0) {
262
        return 0;
263
    }
264
3
    return --_refcount;
265
  }
266
267
6556
  inline uint32_t RefCount() {
268
6556
    return _refcount;
269
  }
270
271
 protected:
272
2495
  inline void Finalize(bool is_env_teardown = false) override {
273
    // In addition to being called during environment teardown, this method is
274
    // also the entry point for the garbage collector. During environment
275
    // teardown we have to remove the garbage collector's reference to this
276
    // method so that, if, as part of the user's callback, JS gets executed,
277
    // resulting in a garbage collection pass, this method is not re-entered as
278
    // part of that pass, because that'll cause a double free (as seen in
279
    // https://github.com/nodejs/node/issues/37236).
280
    //
281
    // Since this class does not have access to the V8 persistent reference,
282
    // this method is overridden in the `Reference` class below. Therein the
283
    // weak callback is removed, ensuring that the garbage collector does not
284
    // re-enter this method, and the method chains up to continue the process of
285
    // environment-teardown-induced finalization.
286
287
    // During environment teardown we have to convert a strong reference to
288
    // a weak reference to force the deferring behavior if the user's finalizer
289
    // happens to delete this reference so that the code in this function that
290
    // follows the call to the user's finalizer may safely access variables from
291
    // this instance.
292

2495
    if (is_env_teardown && RefCount() > 0) _refcount = 0;
293
294
2495
    if (_finalize_callback != nullptr) {
295
      // This ensures that we never call the finalizer twice.
296
1477
      napi_finalize fini = _finalize_callback;
297
1477
      _finalize_callback = nullptr;
298
1477
      _env->CallFinalizer(fini, _finalize_data, _finalize_hint);
299
    }
300
301
    // this is safe because if a request to delete the reference
302
    // is made in the finalize_callback it will defer deletion
303
    // to this block and set _delete_self to true
304

2495
    if (_delete_self || is_env_teardown) {
305
1489
      Delete(this);
306
    } else {
307
1006
      _finalize_ran = true;
308
    }
309
2495
  }
310
311
 private:
312
  uint32_t _refcount;
313
  bool _delete_self;
314
};
315
316
class Reference : public RefBase {
317
  using SecondPassCallParameterRef = Reference*;
318
319
 protected:
320
  template <typename... Args>
321
3033
  Reference(napi_env env, v8::Local<v8::Value> value, Args&&... args)
322
15165
      : RefBase(env, std::forward<Args>(args)...),
323
3033
        _persistent(env->isolate, value),
324
3033
        _secondPassParameter(new SecondPassCallParameterRef(this)),
325
21231
        _secondPassScheduled(false) {
326
3033
    if (RefCount() == 0) {
327
2494
      SetWeak();
328
    }
329
3033
  }
330
331
 public:
332
3033
  static inline Reference* New(napi_env env,
333
                             v8::Local<v8::Value> value,
334
                             uint32_t initial_refcount,
335
                             bool delete_self,
336
                             napi_finalize finalize_callback = nullptr,
337
                             void* finalize_data = nullptr,
338
                             void* finalize_hint = nullptr) {
339
    return new Reference(env,
340
                         value,
341
                         initial_refcount,
342
                         delete_self,
343
                         finalize_callback,
344
                         finalize_data,
345
3033
                         finalize_hint);
346
  }
347
348
12092
  virtual ~Reference() {
349
    // If the second pass callback is scheduled, it will delete the
350
    // parameter passed to it, otherwise it will never be scheduled
351
    // and we need to delete it here.
352
3023
    if (!_secondPassScheduled) {
353
1003
      delete _secondPassParameter;
354
    }
355
6046
  }
356
357
3
  inline uint32_t Ref() {
358
3
    uint32_t refcount = RefBase::Ref();
359
3
    if (refcount == 1) {
360
2
      ClearWeak();
361
    }
362
3
    return refcount;
363
  }
364
365
3
  inline uint32_t Unref() {
366
3
    uint32_t old_refcount = RefCount();
367
3
    uint32_t refcount = RefBase::Unref();
368

3
    if (old_refcount == 1 && refcount == 0) {
369
2
      SetWeak();
370
    }
371
3
    return refcount;
372
  }
373
374
11541
  inline v8::Local<v8::Value> Get() {
375
23082
    if (_persistent.IsEmpty()) {
376
1002
      return v8::Local<v8::Value>();
377
    } else {
378
21078
      return v8::Local<v8::Value>::New(_env->isolate, _persistent);
379
    }
380
  }
381
382
 protected:
383
2488
  inline void Finalize(bool is_env_teardown = false) override {
384
2488
    if (is_env_teardown) env_teardown_finalize_started_ = true;
385

2488
    if (!is_env_teardown && env_teardown_finalize_started_) return;
386
387
    // During env teardown, `~napi_env()` alone is responsible for finalizing.
388
    // Thus, we don't want any stray gc passes to trigger a second call to
389
    // `RefBase::Finalize()`. ClearWeak will ensure that even if the
390
    // gc is in progress no Finalization will be run for this Reference
391
    // by the gc.
392
2488
    if (is_env_teardown) {
393
468
      ClearWeak();
394
    }
395
396
    // Chain up to perform the rest of the finalization.
397
2488
    RefBase::Finalize(is_env_teardown);
398
  }
399
400
 private:
401
  // ClearWeak is marking the Reference so that the gc should not
402
  // collect it, but it is possible that a second pass callback
403
  // may have been scheduled already if we are in shutdown. We clear
404
  // the secondPassParameter so that even if it has been
405
  // secheduled no Finalization will be run.
406
470
  inline void ClearWeak() {
407
940
    if (!_persistent.IsEmpty()) {
408
470
      _persistent.ClearWeak();
409
    }
410
470
    if (_secondPassParameter != nullptr) {
411
470
      *_secondPassParameter = nullptr;
412
    }
413
470
  }
414
415
  // Mark the reference as weak and eligible for collection
416
  // by the gc.
417
2496
  inline void SetWeak() {
418
2496
    if (_secondPassParameter == nullptr) {
419
      // This means that the Reference has already been processed
420
      // by the second pass callback, so its already been Finalized, do
421
      // nothing
422
      return;
423
    }
424
2496
    _persistent.SetWeak(
425
        _secondPassParameter, FinalizeCallback,
426
        v8::WeakCallbackType::kParameter);
427
2496
    *_secondPassParameter = this;
428
  }
429
430
  // The N-API finalizer callback may make calls into the engine. V8's heap is
431
  // not in a consistent state during the weak callback, and therefore it does
432
  // not support calls back into it. However, it provides a mechanism for adding
433
  // a finalizer which may make calls back into the engine by allowing us to
434
  // attach such a second-pass finalizer from the first pass finalizer. Thus,
435
  // we do that here to ensure that the N-API finalizer callback is free to call
436
  // into the engine.
437
2020
  static void FinalizeCallback(
438
      const v8::WeakCallbackInfo<SecondPassCallParameterRef>& data) {
439
2020
    SecondPassCallParameterRef* parameter = data.GetParameter();
440
2020
    Reference* reference = *parameter;
441
2020
    if (reference == nullptr) {
442
      return;
443
    }
444
445
    // The reference must be reset during the first pass.
446
2020
    reference->_persistent.Reset();
447
    // Mark the parameter not delete-able until the second pass callback is
448
    // invoked.
449
2020
    reference->_secondPassScheduled = true;
450
2020
    data.SetSecondPassCallback(SecondPassCallback);
451
  }
452
453
  // Second pass callbacks are scheduled with platform tasks. At env teardown,
454
  // the tasks may have already be scheduled and we are unable to cancel the
455
  // second pass callback task. We have to make sure that parameter is kept
456
  // alive until the second pass callback is been invoked. In order to do
457
  // this and still allow our code to Finalize/delete the Reference during
458
  // shutdown we have to use a separately allocated parameter instead
459
  // of a parameter within the Reference object itself. This is what
460
  // is stored in _secondPassParameter and it is allocated in the
461
  // constructor for the Reference.
462
2020
  static void SecondPassCallback(
463
      const v8::WeakCallbackInfo<SecondPassCallParameterRef>& data) {
464
2020
    SecondPassCallParameterRef* parameter = data.GetParameter();
465
2020
    Reference* reference = *parameter;
466
2020
    delete parameter;
467
2020
    if (reference == nullptr) {
468
      // the reference itself has already been deleted so nothing to do
469
      return;
470
    }
471
2020
    reference->_secondPassParameter = nullptr;
472
2020
    reference->Finalize();
473
  }
474
475
  bool env_teardown_finalize_started_ = false;
476
  v8impl::Persistent<v8::Value> _persistent;
477
  SecondPassCallParameterRef* _secondPassParameter;
478
  bool _secondPassScheduled;
479
};
480
481
enum UnwrapAction {
482
  KeepWrap,
483
  RemoveWrap
484
};
485
486
35
inline static napi_status Unwrap(napi_env env,
487
                                 napi_value js_object,
488
                                 void** result,
489
                                 UnwrapAction action) {
490


105
  NAPI_PREAMBLE(env);
491
35
  CHECK_ARG(env, js_object);
492
35
  if (action == KeepWrap) {
493
27
    CHECK_ARG(env, result);
494
  }
495
496
35
  v8::Local<v8::Context> context = env->context();
497
498
35
  v8::Local<v8::Value> value = v8impl::V8LocalValueFromJsValue(js_object);
499
35
  RETURN_STATUS_IF_FALSE(env, value->IsObject(), napi_invalid_arg);
500
35
  v8::Local<v8::Object> obj = value.As<v8::Object>();
501
502
105
  auto val = obj->GetPrivate(context, NAPI_PRIVATE_KEY(context, wrapper))
503
35
      .ToLocalChecked();
504
35
  RETURN_STATUS_IF_FALSE(env, val->IsExternal(), napi_invalid_arg);
505
  Reference* reference =
506
70
      static_cast<v8impl::Reference*>(val.As<v8::External>()->Value());
507
508
35
  if (result) {
509
35
    *result = reference->Data();
510
  }
511
512
35
  if (action == RemoveWrap) {
513
24
    CHECK(obj->DeletePrivate(context, NAPI_PRIVATE_KEY(context, wrapper))
514
        .FromJust());
515
8
    Reference::Delete(reference);
516
  }
517
518
35
  return GET_RETURN_STATUS(env);
519
}
520
521
//=== Function napi_callback wrapper =================================
522
523
// Use this data structure to associate callback data with each N-API function
524
// exposed to JavaScript. The structure is stored in a v8::External which gets
525
// passed into our callback wrapper. This reduces the performance impact of
526
// calling through N-API.
527
// Ref: benchmark/misc/function_call
528
// Discussion (incl. perf. data): https://github.com/nodejs/node/pull/21072
529
class CallbackBundle {
530
 public:
531
  // Creates an object to be made available to the static function callback
532
  // wrapper, used to retrieve the native callback function and data pointer.
533
  static inline v8::Local<v8::Value>
534
456
  New(napi_env env, napi_callback cb, void* data) {
535
456
    CallbackBundle* bundle = new CallbackBundle();
536
456
    bundle->cb = cb;
537
456
    bundle->cb_data = data;
538
456
    bundle->env = env;
539
540
456
    v8::Local<v8::Value> cbdata = v8::External::New(env->isolate, bundle);
541
456
    Reference::New(env, cbdata, 0, true, Delete, bundle, nullptr);
542
456
    return cbdata;
543
  }
544
  napi_env       env;      // Necessary to invoke C++ NAPI callback
545
  void*          cb_data;  // The user provided callback data
546
  napi_callback  cb;
547
 private:
548
447
  static void Delete(napi_env env, void* data, void* hint) {
549
447
    CallbackBundle* bundle = static_cast<CallbackBundle*>(data);
550
447
    delete bundle;
551
447
  }
552
};
553
554
// Base class extended by classes that wrap V8 function and property callback
555
// info.
556
class CallbackWrapper {
557
 public:
558
4643
  inline CallbackWrapper(napi_value this_arg, size_t args_length, void* data)
559
4643
      : _this(this_arg), _args_length(args_length), _data(data) {}
560
561
  virtual napi_value GetNewTarget() = 0;
562
  virtual void Args(napi_value* buffer, size_t bufferlength) = 0;
563
  virtual void SetReturnValue(napi_value value) = 0;
564
565
42
  napi_value This() { return _this; }
566
567
4483
  size_t ArgsLength() { return _args_length; }
568
569
6
  void* Data() { return _data; }
570
571
 protected:
572
  const napi_value _this;
573
  const size_t _args_length;
574
  void* _data;
575
};
576
577
class CallbackWrapperBase : public CallbackWrapper {
578
 public:
579
4643
  inline CallbackWrapperBase(const v8::FunctionCallbackInfo<v8::Value>& cbinfo,
580
                             const size_t args_length)
581
4643
      : CallbackWrapper(JsValueFromV8LocalValue(cbinfo.This()),
582
                        args_length,
583
                        nullptr),
584
4643
        _cbinfo(cbinfo) {
585
4643
    _bundle = reinterpret_cast<CallbackBundle*>(
586
13929
        v8::Local<v8::External>::Cast(cbinfo.Data())->Value());
587
4643
    _data = _bundle->cb_data;
588
4643
  }
589
590
 protected:
591
4643
  inline void InvokeCallback() {
592
    napi_callback_info cbinfo_wrapper = reinterpret_cast<napi_callback_info>(
593
4643
        static_cast<CallbackWrapper*>(this));
594
595
    // All other pointers we need are stored in `_bundle`
596
4643
    napi_env env = _bundle->env;
597
4643
    napi_callback cb = _bundle->cb;
598
599
    napi_value result;
600
13929
    env->CallIntoModule([&](napi_env env) {
601
4643
      result = cb(env, cbinfo_wrapper);
602
9286
    });
603
604
4643
    if (result != nullptr) {
605
2812
      this->SetReturnValue(result);
606
    }
607
4643
  }
608
609
  const v8::FunctionCallbackInfo<v8::Value>& _cbinfo;
610
  CallbackBundle* _bundle;
611
};
612
613
class FunctionCallbackWrapper
614
    : public CallbackWrapperBase {
615
 public:
616
4643
  static void Invoke(const v8::FunctionCallbackInfo<v8::Value>& info) {
617
4643
    FunctionCallbackWrapper cbwrapper(info);
618
4643
    cbwrapper.InvokeCallback();
619
4643
  }
620
621
425
  static inline napi_status NewFunction(napi_env env,
622
                                        napi_callback cb,
623
                                        void* cb_data,
624
                                        v8::Local<v8::Function>* result) {
625
425
    v8::Local<v8::Value> cbdata = v8impl::CallbackBundle::New(env, cb, cb_data);
626
425
    RETURN_STATUS_IF_FALSE(env, !cbdata.IsEmpty(), napi_generic_failure);
627
628
    v8::MaybeLocal<v8::Function> maybe_function =
629
425
        v8::Function::New(env->context(), Invoke, cbdata);
630
425
    CHECK_MAYBE_EMPTY(env, maybe_function, napi_generic_failure);
631
632
425
    *result = maybe_function.ToLocalChecked();
633
425
    return napi_clear_last_error(env);
634
  }
635
636
31
  static inline napi_status NewTemplate(napi_env env,
637
                    napi_callback cb,
638
                    void* cb_data,
639
                    v8::Local<v8::FunctionTemplate>* result,
640
                    v8::Local<v8::Signature> sig = v8::Local<v8::Signature>()) {
641
31
    v8::Local<v8::Value> cbdata = v8impl::CallbackBundle::New(env, cb, cb_data);
642
31
    RETURN_STATUS_IF_FALSE(env, !cbdata.IsEmpty(), napi_generic_failure);
643
644
31
    *result = v8::FunctionTemplate::New(env->isolate, Invoke, cbdata, sig);
645
31
    return napi_clear_last_error(env);
646
  }
647
648
4643
  explicit FunctionCallbackWrapper(
649
      const v8::FunctionCallbackInfo<v8::Value>& cbinfo)
650
9286
      : CallbackWrapperBase(cbinfo, cbinfo.Length()) {}
651
652
8
  napi_value GetNewTarget() override {
653
16
    if (_cbinfo.IsConstructCall()) {
654
14
      return v8impl::JsValueFromV8LocalValue(_cbinfo.NewTarget());
655
    } else {
656
1
      return nullptr;
657
    }
658
  }
659
660
  /*virtual*/
661
4471
  void Args(napi_value* buffer, size_t buffer_length) override {
662
4471
    size_t i = 0;
663
4471
    size_t min = std::min(buffer_length, _args_length);
664
665
18571
    for (; i < min; i += 1) {
666
14100
      buffer[i] = v8impl::JsValueFromV8LocalValue(_cbinfo[i]);
667
    }
668
669
4471
    if (i < buffer_length) {
670
      napi_value undefined =
671
75
          v8impl::JsValueFromV8LocalValue(v8::Undefined(_cbinfo.GetIsolate()));
672
181
      for (; i < buffer_length; i += 1) {
673
78
        buffer[i] = undefined;
674
      }
675
    }
676
4471
  }
677
678
  /*virtual*/
679
2812
  void SetReturnValue(napi_value value) override {
680
2812
    v8::Local<v8::Value> val = v8impl::V8LocalValueFromJsValue(value);
681
8436
    _cbinfo.GetReturnValue().Set(val);
682
2812
  }
683
};
684
685
enum WrapType {
686
  retrievable,
687
  anonymous
688
};
689
690
template <WrapType wrap_type>
691
1031
inline napi_status Wrap(napi_env env,
692
                        napi_value js_object,
693
                        void* native_object,
694
                        napi_finalize finalize_cb,
695
                        void* finalize_hint,
696
                        napi_ref* result) {
697




3093
  NAPI_PREAMBLE(env);
698

1031
  CHECK_ARG(env, js_object);
699
700
1031
  v8::Local<v8::Context> context = env->context();
701
702
1031
  v8::Local<v8::Value> value = v8impl::V8LocalValueFromJsValue(js_object);
703

1031
  RETURN_STATUS_IF_FALSE(env, value->IsObject(), napi_invalid_arg);
704
1031
  v8::Local<v8::Object> obj = value.As<v8::Object>();
705
706
  if (wrap_type == retrievable) {
707
    // If we've already wrapped this object, we error out.
708
3084
    RETURN_STATUS_IF_FALSE(env,
709
        !obj->HasPrivate(context, NAPI_PRIVATE_KEY(context, wrapper))
710
            .FromJust(),
711
        napi_invalid_arg);
712
  } else if (wrap_type == anonymous) {
713
    // If no finalize callback is provided, we error out.
714
3
    CHECK_ARG(env, finalize_cb);
715
  }
716
717
1030
  v8impl::Reference* reference = nullptr;
718

1030
  if (result != nullptr) {
719
    // The returned reference should be deleted via napi_delete_reference()
720
    // ONLY in response to the finalize callback invocation. (If it is deleted
721
    // before then, then the finalize callback will never be invoked.)
722
    // Therefore a finalize callback is required when returning a reference.
723

11
    CHECK_ARG(env, finalize_cb);
724
22
    reference = v8impl::Reference::New(
725
        env, obj, 0, false, finalize_cb, native_object, finalize_hint);
726
11
    *result = reinterpret_cast<napi_ref>(reference);
727
  } else {
728
    // Create a self-deleting reference.
729

2038
    reference = v8impl::Reference::New(env, obj, 0, true, finalize_cb,
730
1019
        native_object, finalize_cb == nullptr ? nullptr : finalize_hint);
731
  }
732
733
  if (wrap_type == retrievable) {
734
4108
    CHECK(obj->SetPrivate(context, NAPI_PRIVATE_KEY(context, wrapper),
735
          v8::External::New(env->isolate, reference)).FromJust());
736
  }
737
738

1030
  return GET_RETURN_STATUS(env);
739
}
740
741
}  // end of anonymous namespace
742
743
}  // end of namespace v8impl
744
745
// Warning: Keep in-sync with napi_status enum
746
static
747
const char* error_messages[] = {nullptr,
748
                                "Invalid argument",
749
                                "An object was expected",
750
                                "A string was expected",
751
                                "A string or symbol was expected",
752
                                "A function was expected",
753
                                "A number was expected",
754
                                "A boolean was expected",
755
                                "An array was expected",
756
                                "Unknown failure",
757
                                "An exception is pending",
758
                                "The async work item was cancelled",
759
                                "napi_escape_handle already called on scope",
760
                                "Invalid handle scope usage",
761
                                "Invalid callback scope usage",
762
                                "Thread-safe function queue is full",
763
                                "Thread-safe function handle is closing",
764
                                "A bigint was expected",
765
                                "A date was expected",
766
                                "An arraybuffer was expected",
767
                                "A detachable arraybuffer was expected",
768
                                "Main thread would deadlock",
769
};
770
771
1303
napi_status napi_get_last_error_info(napi_env env,
772
                                     const napi_extended_error_info** result) {
773
1303
  CHECK_ENV(env);
774
1303
  CHECK_ARG(env, result);
775
776
  // The value of the constant below must be updated to reference the last
777
  // message in the `napi_status` enum each time a new error message is added.
778
  // We don't have a napi_status_last as this would result in an ABI
779
  // change each time a message was added.
780
1303
  const int last_status = napi_would_deadlock;
781
782
  static_assert(
783
      NAPI_ARRAYSIZE(error_messages) == last_status + 1,
784
      "Count of error messages must match count of error values");
785
1303
  CHECK_LE(env->last_error.error_code, last_status);
786
787
  // Wait until someone requests the last error information to fetch the error
788
  // message string
789
2606
  env->last_error.error_message =
790
1303
      error_messages[env->last_error.error_code];
791
792
1303
  *result = &(env->last_error);
793
1303
  return napi_ok;
794
}
795
796
15
napi_status napi_create_function(napi_env env,
797
                                 const char* utf8name,
798
                                 size_t length,
799
                                 napi_callback cb,
800
                                 void* callback_data,
801
                                 napi_value* result) {
802


45
  NAPI_PREAMBLE(env);
803
15
  CHECK_ARG(env, result);
804
15
  CHECK_ARG(env, cb);
805
806
  v8::Local<v8::Function> return_value;
807
15
  v8::EscapableHandleScope scope(env->isolate);
808
  v8::Local<v8::Function> fn;
809
15
  STATUS_CALL(v8impl::FunctionCallbackWrapper::NewFunction(
810
      env, cb, callback_data, &fn));
811
15
  return_value = scope.Escape(fn);
812
813
15
  if (utf8name != nullptr) {
814
    v8::Local<v8::String> name_string;
815

3
    CHECK_NEW_FROM_UTF8_LEN(env, name_string, utf8name, length);
816
3
    return_value->SetName(name_string);
817
6
  }
818
3
819
30
  *result = v8impl::JsValueFromV8LocalValue(return_value);
820
821
15
  return GET_RETURN_STATUS(env);
822
}
823
824
15
napi_status napi_define_class(napi_env env,
825
                              const char* utf8name,
826
                              size_t length,
827
                              napi_callback constructor,
828
                              void* callback_data,
829
                              size_t property_count,
830
                              const napi_property_descriptor* properties,
831
                              napi_value* result) {
832


43
  NAPI_PREAMBLE(env);
833
14
  CHECK_ARG(env, result);
834
13
  CHECK_ARG(env, constructor);
835
836
12
  if (property_count > 0) {
837
7
    CHECK_ARG(env, properties);
838
  }
839
840
11
  v8::Isolate* isolate = env->isolate;
841
842
11
  v8::EscapableHandleScope scope(isolate);
843
  v8::Local<v8::FunctionTemplate> tpl;
844
11
  STATUS_CALL(v8impl::FunctionCallbackWrapper::NewTemplate(
845
      env, constructor, callback_data, &tpl));
846
847
  v8::Local<v8::String> name_string;
848

12
  CHECK_NEW_FROM_UTF8_LEN(env, name_string, utf8name, length);
849
11
  tpl->SetClassName(name_string);
850
20
851
20
  size_t static_property_count = 0;
852
76
  for (size_t i = 0; i < property_count; i++) {
853
28
    const napi_property_descriptor* p = properties + i;
854
855
28
    if ((p->attributes & napi_static) != 0) {
856
      // Static properties are handled separately below.
857
7
      static_property_count++;
858
7
      continue;
859
    }
860
861
    v8::Local<v8::Name> property_name;
862
21
    STATUS_CALL(v8impl::V8NameFromPropertyDescriptor(env, p, &property_name));
863
864
    v8::PropertyAttribute attributes =
865
21
        v8impl::V8PropertyAttributesFromDescriptor(p);
866
867
    // This code is similar to that in napi_define_properties(); the
868
    // difference is it applies to a template instead of an object,
869
    // and preferred PropertyAttribute for lack of PropertyDescriptor
870
    // support on ObjectTemplate.
871

21
    if (p->getter != nullptr || p->setter != nullptr) {
872
      v8::Local<v8::FunctionTemplate> getter_tpl;
873
      v8::Local<v8::FunctionTemplate> setter_tpl;
874
10
      if (p->getter != nullptr) {
875
10
        STATUS_CALL(v8impl::FunctionCallbackWrapper::NewTemplate(
876
            env, p->getter, p->data, &getter_tpl));
877
      }
878
10
      if (p->setter != nullptr) {
879
5
        STATUS_CALL(v8impl::FunctionCallbackWrapper::NewTemplate(
880
            env, p->setter, p->data, &setter_tpl));
881
      }
882
883
30
      tpl->PrototypeTemplate()->SetAccessorProperty(
884
        property_name,
885
        getter_tpl,
886
        setter_tpl,
887
        attributes,
888
20
        v8::AccessControl::DEFAULT);
889
11
    } else if (p->method != nullptr) {
890
      v8::Local<v8::FunctionTemplate> t;
891
5
      STATUS_CALL(v8impl::FunctionCallbackWrapper::NewTemplate(
892
          env, p->method, p->data, &t, v8::Signature::New(isolate, tpl)));
893
894
10
      tpl->PrototypeTemplate()->Set(property_name, t, attributes);
895
    } else {
896
6
      v8::Local<v8::Value> value = v8impl::V8LocalValueFromJsValue(p->value);
897
12
      tpl->PrototypeTemplate()->Set(property_name, value, attributes);
898
    }
899
  }
900
901
10
  v8::Local<v8::Context> context = env->context();
902
20
  *result = v8impl::JsValueFromV8LocalValue(
903
20
      scope.Escape(tpl->GetFunction(context).ToLocalChecked()));
904
905
10
  if (static_property_count > 0) {
906
6
    std::vector<napi_property_descriptor> static_descriptors;
907
3
    static_descriptors.reserve(static_property_count);
908
909
26
    for (size_t i = 0; i < property_count; i++) {
910
23
      const napi_property_descriptor* p = properties + i;
911
23
      if ((p->attributes & napi_static) != 0) {
912
7
        static_descriptors.push_back(*p);
913
      }
914
    }
915
916

3
    STATUS_CALL(napi_define_properties(env,
917
                                       *result,
918
                                       static_descriptors.size(),
919
                                       static_descriptors.data()));
920
  }
921
922
10
  return GET_RETURN_STATUS(env);
923
}
924
925
8
napi_status napi_get_property_names(napi_env env,
926
                                    napi_value object,
927
                                    napi_value* result) {
928
  return napi_get_all_property_names(
929
      env,
930
      object,
931
      napi_key_include_prototypes,
932
      static_cast<napi_key_filter>(napi_key_enumerable |
933
                                   napi_key_skip_symbols),
934
      napi_key_numbers_to_strings,
935
8
      result);
936
}
937
938
12
napi_status napi_get_all_property_names(napi_env env,
939
                                        napi_value object,
940
                                        napi_key_collection_mode key_mode,
941
                                        napi_key_filter key_filter,
942
                                        napi_key_conversion key_conversion,
943
                                        napi_value* result) {
944


32
  NAPI_PREAMBLE(env);
945
10
  CHECK_ARG(env, result);
946
947
8
  v8::Local<v8::Context> context = env->context();
948
  v8::Local<v8::Object> obj;
949

28
  CHECK_TO_OBJECT(env, context, obj, object);
950
951
6
  v8::PropertyFilter filter = v8::PropertyFilter::ALL_PROPERTIES;
952
6
  if (key_filter & napi_key_writable) {
953
    filter =
954
        static_cast<v8::PropertyFilter>(filter |
955
                                        v8::PropertyFilter::ONLY_WRITABLE);
956
  }
957
6
  if (key_filter & napi_key_enumerable) {
958
5
    filter =
959
5
        static_cast<v8::PropertyFilter>(filter |
960
                                        v8::PropertyFilter::ONLY_ENUMERABLE);
961
  }
962
6
  if (key_filter & napi_key_configurable) {
963
    filter =
964
        static_cast<v8::PropertyFilter>(filter |
965
                                        v8::PropertyFilter::ONLY_WRITABLE);
966
  }
967
6
  if (key_filter & napi_key_skip_strings) {
968
1
    filter =
969
1
        static_cast<v8::PropertyFilter>(filter |
970
                                        v8::PropertyFilter::SKIP_STRINGS);
971
  }
972
6
  if (key_filter & napi_key_skip_symbols) {
973
5
    filter =
974
5
        static_cast<v8::PropertyFilter>(filter |
975
                                        v8::PropertyFilter::SKIP_SYMBOLS);
976
  }
977
  v8::KeyCollectionMode collection_mode;
978
  v8::KeyConversionMode conversion_mode;
979
980
6
  switch (key_mode) {
981
    case napi_key_include_prototypes:
982
6
      collection_mode = v8::KeyCollectionMode::kIncludePrototypes;
983
6
      break;
984
    case napi_key_own_only:
985
      collection_mode = v8::KeyCollectionMode::kOwnOnly;
986
      break;
987
    default:
988
      return napi_set_last_error(env, napi_invalid_arg);
989
  }
990
991
6
  switch (key_conversion) {
992
    case napi_key_keep_numbers:
993
      conversion_mode = v8::KeyConversionMode::kKeepNumbers;
994
      break;
995
    case napi_key_numbers_to_strings:
996
6
      conversion_mode = v8::KeyConversionMode::kConvertToString;
997
6
      break;
998
    default:
999
      return napi_set_last_error(env, napi_invalid_arg);
1000
  }
1001
1002
  v8::MaybeLocal<v8::Array> maybe_all_propertynames =
1003
      obj->GetPropertyNames(context,
1004
                            collection_mode,
1005
                            filter,
1006
                            v8::IndexFilter::kIncludeIndices,
1007
6
                            conversion_mode);
1008
1009

6
  CHECK_MAYBE_EMPTY_WITH_PREAMBLE(
1010
      env, maybe_all_propertynames, napi_generic_failure);
1011
1012
12
  *result =
1013
12
      v8impl::JsValueFromV8LocalValue(maybe_all_propertynames.ToLocalChecked());
1014
6
  return GET_RETURN_STATUS(env);
1015
}
1016
1017
26
napi_status napi_set_property(napi_env env,
1018
                              napi_value object,
1019
                              napi_value key,
1020
                              napi_value value) {
1021


74
  NAPI_PREAMBLE(env);
1022
24
  CHECK_ARG(env, key);
1023
21
  CHECK_ARG(env, value);
1024
1025
19
  v8::Local<v8::Context> context = env->context();
1026
  v8::Local<v8::Object> obj;
1027
1028

72
  CHECK_TO_OBJECT(env, context, obj, object);
1029
1030
17
  v8::Local<v8::Value> k = v8impl::V8LocalValueFromJsValue(key);
1031
17
  v8::Local<v8::Value> val = v8impl::V8LocalValueFromJsValue(value);
1032
1033
17
  v8::Maybe<bool> set_maybe = obj->Set(context, k, val);
1034
1035
34
  RETURN_STATUS_IF_FALSE(env, set_maybe.FromMaybe(false), napi_generic_failure);
1036
17
  return GET_RETURN_STATUS(env);
1037
}
1038
1039
16
napi_status napi_has_property(napi_env env,
1040
                              napi_value object,
1041
                              napi_value key,
1042
                              bool* result) {
1043


44
  NAPI_PREAMBLE(env);
1044
14
  CHECK_ARG(env, result);
1045
12
  CHECK_ARG(env, key);
1046
1047
10
  v8::Local<v8::Context> context = env->context();
1048
  v8::Local<v8::Object> obj;
1049
1050

36
  CHECK_TO_OBJECT(env, context, obj, object);
1051
1052
8
  v8::Local<v8::Value> k = v8impl::V8LocalValueFromJsValue(key);
1053
8
  v8::Maybe<bool> has_maybe = obj->Has(context, k);
1054
1055
8
  CHECK_MAYBE_NOTHING(env, has_maybe, napi_generic_failure);
1056
1057
16
  *result = has_maybe.FromMaybe(false);
1058
8
  return GET_RETURN_STATUS(env);
1059
}
1060
1061
34
napi_status napi_get_property(napi_env env,
1062
                              napi_value object,
1063
                              napi_value key,
1064
                              napi_value* result) {
1065


98
  NAPI_PREAMBLE(env);
1066
32
  CHECK_ARG(env, key);
1067
28
  CHECK_ARG(env, result);
1068
1069
26
  v8::Local<v8::Context> context = env->context();
1070
26
  v8::Local<v8::Value> k = v8impl::V8LocalValueFromJsValue(key);
1071
  v8::Local<v8::Object> obj;
1072
1073

100
  CHECK_TO_OBJECT(env, context, obj, object);
1074
1075
24
  auto get_maybe = obj->Get(context, k);
1076
1077
24
  CHECK_MAYBE_EMPTY(env, get_maybe, napi_generic_failure);
1078
1079
24
  v8::Local<v8::Value> val = get_maybe.ToLocalChecked();
1080
24
  *result = v8impl::JsValueFromV8LocalValue(val);
1081
24
  return GET_RETURN_STATUS(env);
1082
}
1083
1084
9
napi_status napi_delete_property(napi_env env,
1085
                                 napi_value object,
1086
                                 napi_value key,
1087
                                 bool* result) {
1088


25
  NAPI_PREAMBLE(env);
1089
8
  CHECK_ARG(env, key);
1090
1091
7
  v8::Local<v8::Context> context = env->context();
1092
7
  v8::Local<v8::Value> k = v8impl::V8LocalValueFromJsValue(key);
1093
  v8::Local<v8::Object> obj;
1094
1095

26
  CHECK_TO_OBJECT(env, context, obj, object);
1096
6
  v8::Maybe<bool> delete_maybe = obj->Delete(context, k);
1097
6
  CHECK_MAYBE_NOTHING(env, delete_maybe, napi_generic_failure);
1098
1099
6
  if (result != nullptr)
1100
10
    *result = delete_maybe.FromMaybe(false);
1101
1102
6
  return GET_RETURN_STATUS(env);
1103
}
1104
1105
19
napi_status napi_has_own_property(napi_env env,
1106
                                  napi_value object,
1107
                                  napi_value key,
1108
                                  bool* result) {
1109


55
  NAPI_PREAMBLE(env);
1110
18
  CHECK_ARG(env, key);
1111
17
  CHECK_ARG(env, result);
1112
1113
16
  v8::Local<v8::Context> context = env->context();
1114
  v8::Local<v8::Object> obj;
1115
1116

62
  CHECK_TO_OBJECT(env, context, obj, object);
1117
15
  v8::Local<v8::Value> k = v8impl::V8LocalValueFromJsValue(key);
1118
24
  RETURN_STATUS_IF_FALSE(env, k->IsName(), napi_name_expected);
1119
6
  v8::Maybe<bool> has_maybe = obj->HasOwnProperty(context, k.As<v8::Name>());
1120
6
  CHECK_MAYBE_NOTHING(env, has_maybe, napi_generic_failure);
1121
12
  *result = has_maybe.FromMaybe(false);
1122
1123
6
  return GET_RETURN_STATUS(env);
1124
}
1125
1126
155
napi_status napi_set_named_property(napi_env env,
1127
                                    napi_value object,
1128
                                    const char* utf8name,
1129
                                    napi_value value) {
1130


463
  NAPI_PREAMBLE(env);
1131
154
  CHECK_ARG(env, value);
1132
1133
153
  v8::Local<v8::Context> context = env->context();
1134
  v8::Local<v8::Object> obj;
1135
1136

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

455
  CHECK_NEW_FROM_UTF8(env, key, utf8name);
1140
1141
151
  v8::Local<v8::Value> val = v8impl::V8LocalValueFromJsValue(value);
1142
1143
151
  v8::Maybe<bool> set_maybe = obj->Set(context, key, val);
1144
1145
302
  RETURN_STATUS_IF_FALSE(env, set_maybe.FromMaybe(false), napi_generic_failure);
1146
151
  return GET_RETURN_STATUS(env);
1147
}
1148
1149
9
napi_status napi_has_named_property(napi_env env,
1150
                                    napi_value object,
1151
                                    const char* utf8name,
1152
                                    bool* result) {
1153


25
  NAPI_PREAMBLE(env);
1154
8
  CHECK_ARG(env, result);
1155
1156
7
  v8::Local<v8::Context> context = env->context();
1157
  v8::Local<v8::Object> obj;
1158
1159

26
  CHECK_TO_OBJECT(env, context, obj, object);
1160
1161
  v8::Local<v8::Name> key;
1162

17
  CHECK_NEW_FROM_UTF8(env, key, utf8name);
1163
1164
5
  v8::Maybe<bool> has_maybe = obj->Has(context, key);
1165
1166
5
  CHECK_MAYBE_NOTHING(env, has_maybe, napi_generic_failure);
1167
1168
10
  *result = has_maybe.FromMaybe(false);
1169
5
  return GET_RETURN_STATUS(env);
1170
}
1171
1172
6
napi_status napi_get_named_property(napi_env env,
1173
                                    napi_value object,
1174
                                    const char* utf8name,
1175
                                    napi_value* result) {
1176


16
  NAPI_PREAMBLE(env);
1177
5
  CHECK_ARG(env, result);
1178
1179
4
  v8::Local<v8::Context> context = env->context();
1180
1181
  v8::Local<v8::Name> key;
1182

11
  CHECK_NEW_FROM_UTF8(env, key, utf8name);
1183
1184
  v8::Local<v8::Object> obj;
1185
1186

11
  CHECK_TO_OBJECT(env, context, obj, object);
1187
1188
2
  auto get_maybe = obj->Get(context, key);
1189
1190
2
  CHECK_MAYBE_EMPTY(env, get_maybe, napi_generic_failure);
1191
1192
2
  v8::Local<v8::Value> val = get_maybe.ToLocalChecked();
1193
2
  *result = v8impl::JsValueFromV8LocalValue(val);
1194
2
  return GET_RETURN_STATUS(env);
1195
}
1196
1197
13
napi_status napi_set_element(napi_env env,
1198
                             napi_value object,
1199
                             uint32_t index,
1200
                             napi_value value) {
1201


37
  NAPI_PREAMBLE(env);
1202
12
  CHECK_ARG(env, value);
1203
1204
12
  v8::Local<v8::Context> context = env->context();
1205
  v8::Local<v8::Object> obj;
1206
1207

46
  CHECK_TO_OBJECT(env, context, obj, object);
1208
1209
11
  v8::Local<v8::Value> val = v8impl::V8LocalValueFromJsValue(value);
1210
11
  auto set_maybe = obj->Set(context, index, val);
1211
1212
22
  RETURN_STATUS_IF_FALSE(env, set_maybe.FromMaybe(false), napi_generic_failure);
1213
1214
11
  return GET_RETURN_STATUS(env);
1215
}
1216
1217
5
napi_status napi_has_element(napi_env env,
1218
                             napi_value object,
1219
                             uint32_t index,
1220
                             bool* result) {
1221


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

10
  CHECK_TO_OBJECT(env, context, obj, object);
1228
1229
2
  v8::Maybe<bool> has_maybe = obj->Has(context, index);
1230
1231
2
  CHECK_MAYBE_NOTHING(env, has_maybe, napi_generic_failure);
1232
1233
4
  *result = has_maybe.FromMaybe(false);
1234
2
  return GET_RETURN_STATUS(env);
1235
}
1236
1237
28
napi_status napi_get_element(napi_env env,
1238
                             napi_value object,
1239
                             uint32_t index,
1240
                             napi_value* result) {
1241


82
  NAPI_PREAMBLE(env);
1242
27
  CHECK_ARG(env, result);
1243
1244
27
  v8::Local<v8::Context> context = env->context();
1245
  v8::Local<v8::Object> obj;
1246
1247

108
  CHECK_TO_OBJECT(env, context, obj, object);
1248
1249
27
  auto get_maybe = obj->Get(context, index);
1250
1251
27
  CHECK_MAYBE_EMPTY(env, get_maybe, napi_generic_failure);
1252
1253
54
  *result = v8impl::JsValueFromV8LocalValue(get_maybe.ToLocalChecked());
1254
27
  return GET_RETURN_STATUS(env);
1255
}
1256
1257
4
napi_status napi_delete_element(napi_env env,
1258
                                napi_value object,
1259
                                uint32_t index,
1260
                                bool* result) {
1261


10
  NAPI_PREAMBLE(env);
1262
1263
3
  v8::Local<v8::Context> context = env->context();
1264
  v8::Local<v8::Object> obj;
1265
1266

10
  CHECK_TO_OBJECT(env, context, obj, object);
1267
2
  v8::Maybe<bool> delete_maybe = obj->Delete(context, index);
1268
2
  CHECK_MAYBE_NOTHING(env, delete_maybe, napi_generic_failure);
1269
1270
2
  if (result != nullptr)
1271
2
    *result = delete_maybe.FromMaybe(false);
1272
1273
2
  return GET_RETURN_STATUS(env);
1274
}
1275
1276
79
napi_status napi_define_properties(napi_env env,
1277
                                   napi_value object,
1278
                                   size_t property_count,
1279
                                   const napi_property_descriptor* properties) {
1280


235
  NAPI_PREAMBLE(env);
1281
78
  if (property_count > 0) {
1282
78
    CHECK_ARG(env, properties);
1283
  }
1284
1285
75
  v8::Local<v8::Context> context = env->context();
1286
1287
  v8::Local<v8::Object> obj;
1288

298
  CHECK_TO_OBJECT(env, context, obj, object);
1289
1290
996
  for (size_t i = 0; i < property_count; i++) {
1291
424
    const napi_property_descriptor* p = &properties[i];
1292
1293
    v8::Local<v8::Name> property_name;
1294
424
    STATUS_CALL(v8impl::V8NameFromPropertyDescriptor(env, p, &property_name));
1295
1296

424
    if (p->getter != nullptr || p->setter != nullptr) {
1297
      v8::Local<v8::Function> local_getter;
1298
      v8::Local<v8::Function> local_setter;
1299
1300
10
      if (p->getter != nullptr) {
1301
10
        STATUS_CALL(v8impl::FunctionCallbackWrapper::NewFunction(
1302
            env, p->getter, p->data, &local_getter));
1303
      }
1304
10
      if (p->setter != nullptr) {
1305
2
        STATUS_CALL(v8impl::FunctionCallbackWrapper::NewFunction(
1306
            env, p->setter, p->data, &local_setter));
1307
      }
1308
1309
20
      v8::PropertyDescriptor descriptor(local_getter, local_setter);
1310
10
      descriptor.set_enumerable((p->attributes & napi_enumerable) != 0);
1311
10
      descriptor.set_configurable((p->attributes & napi_configurable) != 0);
1312
1313
      auto define_maybe = obj->DefineProperty(context,
1314
                                              property_name,
1315
10
                                              descriptor);
1316
1317
20
      if (!define_maybe.FromMaybe(false)) {
1318
        return napi_set_last_error(env, napi_invalid_arg);
1319
10
      }
1320
414
    } else if (p->method != nullptr) {
1321
      v8::Local<v8::Function> method;
1322
398
      STATUS_CALL(v8impl::FunctionCallbackWrapper::NewFunction(
1323
          env, p->method, p->data, &method));
1324
      v8::PropertyDescriptor descriptor(method,
1325
1194
                                        (p->attributes & napi_writable) != 0);
1326
398
      descriptor.set_enumerable((p->attributes & napi_enumerable) != 0);
1327
398
      descriptor.set_configurable((p->attributes & napi_configurable) != 0);
1328
1329
      auto define_maybe = obj->DefineProperty(context,
1330
                                              property_name,
1331
398
                                              descriptor);
1332
1333
796
      if (!define_maybe.FromMaybe(false)) {
1334
        return napi_set_last_error(env, napi_generic_failure);
1335
      }
1336
    } else {
1337
16
      v8::Local<v8::Value> value = v8impl::V8LocalValueFromJsValue(p->value);
1338
1339
      v8::PropertyDescriptor descriptor(value,
1340
32
                                        (p->attributes & napi_writable) != 0);
1341
16
      descriptor.set_enumerable((p->attributes & napi_enumerable) != 0);
1342
16
      descriptor.set_configurable((p->attributes & napi_configurable) != 0);
1343
1344
      auto define_maybe =
1345
16
          obj->DefineProperty(context, property_name, descriptor);
1346
1347
32
      if (!define_maybe.FromMaybe(false)) {
1348
        return napi_set_last_error(env, napi_invalid_arg);
1349
      }
1350
    }
1351
  }
1352
1353
74
  return GET_RETURN_STATUS(env);
1354
}
1355
1356
1
napi_status napi_object_freeze(napi_env env,
1357
                               napi_value object) {
1358


3
  NAPI_PREAMBLE(env);
1359
1360
1
  v8::Local<v8::Context> context = env->context();
1361
  v8::Local<v8::Object> obj;
1362
1363

4
  CHECK_TO_OBJECT(env, context, obj, object);
1364
1365
  v8::Maybe<bool> set_frozen =
1366
1
    obj->SetIntegrityLevel(context, v8::IntegrityLevel::kFrozen);
1367
1368

2
  RETURN_STATUS_IF_FALSE_WITH_PREAMBLE(env,
1369
    set_frozen.FromMaybe(false), napi_generic_failure);
1370
1371
1
  return GET_RETURN_STATUS(env);
1372
}
1373
1374
1
napi_status napi_object_seal(napi_env env,
1375
                             napi_value object) {
1376


3
  NAPI_PREAMBLE(env);
1377
1378
1
  v8::Local<v8::Context> context = env->context();
1379
  v8::Local<v8::Object> obj;
1380
1381

4
  CHECK_TO_OBJECT(env, context, obj, object);
1382
1383
  v8::Maybe<bool> set_sealed =
1384
1
    obj->SetIntegrityLevel(context, v8::IntegrityLevel::kSealed);
1385
1386

2
  RETURN_STATUS_IF_FALSE_WITH_PREAMBLE(env,
1387
    set_sealed.FromMaybe(false), napi_generic_failure);
1388
1389
1
  return GET_RETURN_STATUS(env);
1390
}
1391
1392
11
napi_status napi_is_array(napi_env env, napi_value value, bool* result) {
1393
11
  CHECK_ENV(env);
1394
11
  CHECK_ARG(env, value);
1395
11
  CHECK_ARG(env, result);
1396
1397
11
  v8::Local<v8::Value> val = v8impl::V8LocalValueFromJsValue(value);
1398
1399
22
  *result = val->IsArray();
1400
11
  return napi_clear_last_error(env);
1401
}
1402
1403
13
napi_status napi_get_array_length(napi_env env,
1404
                                  napi_value value,
1405
                                  uint32_t* result) {
1406


39
  NAPI_PREAMBLE(env);
1407
13
  CHECK_ARG(env, value);
1408
13
  CHECK_ARG(env, result);
1409
1410
13
  v8::Local<v8::Value> val = v8impl::V8LocalValueFromJsValue(value);
1411
13
  RETURN_STATUS_IF_FALSE(env, val->IsArray(), napi_array_expected);
1412
1413
13
  v8::Local<v8::Array> arr = val.As<v8::Array>();
1414
26
  *result = arr->Length();
1415
1416
13
  return GET_RETURN_STATUS(env);
1417
}
1418
1419
9
napi_status napi_strict_equals(napi_env env,
1420
                               napi_value lhs,
1421
                               napi_value rhs,
1422
                               bool* result) {
1423


27
  NAPI_PREAMBLE(env);
1424
9
  CHECK_ARG(env, lhs);
1425
9
  CHECK_ARG(env, rhs);
1426
9
  CHECK_ARG(env, result);
1427
1428
9
  v8::Local<v8::Value> a = v8impl::V8LocalValueFromJsValue(lhs);
1429
9
  v8::Local<v8::Value> b = v8impl::V8LocalValueFromJsValue(rhs);
1430
1431
18
  *result = a->StrictEquals(b);
1432
9
  return GET_RETURN_STATUS(env);
1433
}
1434
1435
7
napi_status napi_get_prototype(napi_env env,
1436
                               napi_value object,
1437
                               napi_value* result) {
1438


19
  NAPI_PREAMBLE(env);
1439
6
  CHECK_ARG(env, result);
1440
1441
5
  v8::Local<v8::Context> context = env->context();
1442
1443
  v8::Local<v8::Object> obj;
1444

18
  CHECK_TO_OBJECT(env, context, obj, object);
1445
1446
4
  v8::Local<v8::Value> val = obj->GetPrototype();
1447
4
  *result = v8impl::JsValueFromV8LocalValue(val);
1448
4
  return GET_RETURN_STATUS(env);
1449
}
1450
1451
64
napi_status napi_create_object(napi_env env, napi_value* result) {
1452
64
  CHECK_ENV(env);
1453
64
  CHECK_ARG(env, result);
1454
1455
192
  *result = v8impl::JsValueFromV8LocalValue(
1456
64
      v8::Object::New(env->isolate));
1457
1458
64
  return napi_clear_last_error(env);
1459
}
1460
1461
1
napi_status napi_create_array(napi_env env, napi_value* result) {
1462
1
  CHECK_ENV(env);
1463
1
  CHECK_ARG(env, result);
1464
1465
3
  *result = v8impl::JsValueFromV8LocalValue(
1466
1
      v8::Array::New(env->isolate));
1467
1468
1
  return napi_clear_last_error(env);
1469
}
1470
1471
4
napi_status napi_create_array_with_length(napi_env env,
1472
                                          size_t length,
1473
                                          napi_value* result) {
1474
4
  CHECK_ENV(env);
1475
4
  CHECK_ARG(env, result);
1476
1477
12
  *result = v8impl::JsValueFromV8LocalValue(
1478
4
      v8::Array::New(env->isolate, length));
1479
1480
4
  return napi_clear_last_error(env);
1481
}
1482
1483
12
napi_status napi_create_string_latin1(napi_env env,
1484
                                      const char* str,
1485
                                      size_t length,
1486
                                      napi_value* result) {
1487
12
  CHECK_ENV(env);
1488
12
  CHECK_ARG(env, result);
1489

12
  RETURN_STATUS_IF_FALSE(env,
1490
      (length == NAPI_AUTO_LENGTH) || length <= INT_MAX,
1491
      napi_invalid_arg);
1492
1493
11
  auto isolate = env->isolate;
1494
  auto str_maybe =
1495
      v8::String::NewFromOneByte(isolate,
1496
                                 reinterpret_cast<const uint8_t*>(str),
1497
                                 v8::NewStringType::kNormal,
1498
11
                                 length);
1499
11
  CHECK_MAYBE_EMPTY(env, str_maybe, napi_generic_failure);
1500
1501
22
  *result = v8impl::JsValueFromV8LocalValue(str_maybe.ToLocalChecked());
1502
11
  return napi_clear_last_error(env);
1503
}
1504
1505
721
napi_status napi_create_string_utf8(napi_env env,
1506
                                    const char* str,
1507
                                    size_t length,
1508
                                    napi_value* result) {
1509
721
  CHECK_ENV(env);
1510
721
  CHECK_ARG(env, result);
1511

721
  RETURN_STATUS_IF_FALSE(env,
1512
      (length == NAPI_AUTO_LENGTH) || length <= INT_MAX,
1513
      napi_invalid_arg);
1514
1515
720
  auto isolate = env->isolate;
1516
  auto str_maybe =
1517
      v8::String::NewFromUtf8(isolate,
1518
                              str,
1519
                              v8::NewStringType::kNormal,
1520
720
                              static_cast<int>(length));
1521
720
  CHECK_MAYBE_EMPTY(env, str_maybe, napi_generic_failure);
1522
1440
  *result = v8impl::JsValueFromV8LocalValue(str_maybe.ToLocalChecked());
1523
720
  return napi_clear_last_error(env);
1524
}
1525
1526
14
napi_status napi_create_string_utf16(napi_env env,
1527
                                     const char16_t* str,
1528
                                     size_t length,
1529
                                     napi_value* result) {
1530
14
  CHECK_ENV(env);
1531
14
  CHECK_ARG(env, result);
1532

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


39
  NAPI_PREAMBLE(env);
1626
13
  CHECK_ARG(env, words);
1627
13
  CHECK_ARG(env, result);
1628
1629
13
  v8::Local<v8::Context> context = env->context();
1630
1631
13
  RETURN_STATUS_IF_FALSE(
1632
      env, word_count <= INT_MAX, napi_invalid_arg);
1633
1634
  v8::MaybeLocal<v8::BigInt> b = v8::BigInt::NewFromWords(
1635
12
      context, sign_bit, word_count, words);
1636
1637

12
  CHECK_MAYBE_EMPTY_WITH_PREAMBLE(env, b, napi_generic_failure);
1638
1639
22
  *result = v8impl::JsValueFromV8LocalValue(b.ToLocalChecked());
1640
11
  return GET_RETURN_STATUS(env);
1641
}
1642
1643
1294
napi_status napi_get_boolean(napi_env env, bool value, napi_value* result) {
1644
1294
  CHECK_ENV(env);
1645
1294
  CHECK_ARG(env, result);
1646
1647
1294
  v8::Isolate* isolate = env->isolate;
1648
1649
1294
  if (value) {
1650
1462
    *result = v8impl::JsValueFromV8LocalValue(v8::True(isolate));
1651
  } else {
1652
1126
    *result = v8impl::JsValueFromV8LocalValue(v8::False(isolate));
1653
  }
1654
1655
1294
  return napi_clear_last_error(env);
1656
}
1657
1658
13
napi_status napi_create_symbol(napi_env env,
1659
                               napi_value description,
1660
                               napi_value* result) {
1661
13
  CHECK_ENV(env);
1662
13
  CHECK_ARG(env, result);
1663
1664
13
  v8::Isolate* isolate = env->isolate;
1665
1666
13
  if (description == nullptr) {
1667
6
    *result = v8impl::JsValueFromV8LocalValue(v8::Symbol::New(isolate));
1668
  } else {
1669
11
    v8::Local<v8::Value> desc = v8impl::V8LocalValueFromJsValue(description);
1670
22
    RETURN_STATUS_IF_FALSE(env, desc->IsString(), napi_string_expected);
1671
1672
33
    *result = v8impl::JsValueFromV8LocalValue(
1673
      v8::Symbol::New(isolate, desc.As<v8::String>()));
1674
  }
1675
1676
13
  return napi_clear_last_error(env);
1677
}
1678
1679
194
static inline napi_status set_error_code(napi_env env,
1680
                                         v8::Local<v8::Value> error,
1681
                                         napi_value code,
1682
                                         const char* code_cstring) {
1683

194
  if ((code != nullptr) || (code_cstring != nullptr)) {
1684
116
    v8::Local<v8::Context> context = env->context();
1685
116
    v8::Local<v8::Object> err_object = error.As<v8::Object>();
1686
1687
116
    v8::Local<v8::Value> code_value = v8impl::V8LocalValueFromJsValue(code);
1688
116
    if (code != nullptr) {
1689
5
      code_value = v8impl::V8LocalValueFromJsValue(code);
1690
10
      RETURN_STATUS_IF_FALSE(env, code_value->IsString(), napi_string_expected);
1691
    } else {
1692

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


341776
  NAPI_PREAMBLE(env);
1882
113922
  CHECK_ARG(env, recv);
1883
113922
  if (argc > 0) {
1884
103879
    CHECK_ARG(env, argv);
1885
  }
1886
1887
113922
  v8::Local<v8::Context> context = env->context();
1888
1889
113922
  v8::Local<v8::Value> v8recv = v8impl::V8LocalValueFromJsValue(recv);
1890
1891
  v8::Local<v8::Function> v8func;
1892

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


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


235
  NAPI_PREAMBLE(env);
1933
1934
73
  v8::Isolate* isolate = env->isolate;
1935
  v8::Local<v8::String> str;
1936

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


270
  NAPI_PREAMBLE(env);
1951
1952
90
  v8::Isolate* isolate = env->isolate;
1953
  v8::Local<v8::String> str;
1954

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


66
  NAPI_PREAMBLE(env);
1969
1970
22
  v8::Isolate* isolate = env->isolate;
1971
  v8::Local<v8::String> str;
1972

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

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


52
  NAPI_PREAMBLE(env);
2303
17
  CHECK_ARG(env, value);
2304
16
  CHECK_ARG(env, result);
2305
2306
15
  v8::Isolate* isolate = env->isolate;
2307
  v8::Local<v8::Boolean> b =
2308
30
    v8impl::V8LocalValueFromJsValue(value)->ToBoolean(isolate);
2309
30
  *result = v8impl::JsValueFromV8LocalValue(b);
2310
15
  return GET_RETURN_STATUS(env);
2311
}
2312
2313
#define GEN_COERCE_FUNCTION(UpperCaseName, MixedCaseName, LowerCaseName)      \
2314
  napi_status napi_coerce_to_##LowerCaseName(napi_env env,                    \
2315
                                             napi_value value,                \
2316
                                             napi_value* result) {            \
2317
    NAPI_PREAMBLE(env);                                                       \
2318
    CHECK_ARG(env, value);                                                    \
2319
    CHECK_ARG(env, result);                                                   \
2320
                                                                              \
2321
    v8::Local<v8::Context> context = env->context();                          \
2322
    v8::Local<v8::MixedCaseName> str;                                         \
2323
                                                                              \
2324
    CHECK_TO_##UpperCaseName(env, context, str, value);                       \
2325
                                                                              \
2326
    *result = v8impl::JsValueFromV8LocalValue(str);                           \
2327
    return GET_RETURN_STATUS(env);                                            \
2328
  }
2329
2330
15
GEN_COERCE_FUNCTION(NUMBER, Number, number)
2331


49
GEN_COERCE_FUNCTION(OBJECT, Object, object)
2332


69
GEN_COERCE_FUNCTION(STRING, String, string)
2333


67
2334

35
#undef GEN_COERCE_FUNCTION
2335

48
2336

1092
napi_status napi_wrap(napi_env env,
2337

63
                      napi_value js_object,
2338

59
                      void* native_object,
2339
47
                      napi_finalize finalize_cb,
2340
44
                      void* finalize_hint,
2341
14
                      napi_ref* result) {
2342
  return v8impl::Wrap<v8impl::retrievable>(env,
2343
                                           js_object,
2344
                                           native_object,
2345
                                           finalize_cb,
2346
                                           finalize_hint,
2347
1028
                                           result);
2348
}
2349
2350
27
napi_status napi_unwrap(napi_env env, napi_value obj, void** result) {
2351
27
  return v8impl::Unwrap(env, obj, result, v8impl::KeepWrap);
2352
}
2353
2354
8
napi_status napi_remove_wrap(napi_env env, napi_value obj, void** result) {
2355
8
  return v8impl::Unwrap(env, obj, result, v8impl::RemoveWrap);
2356
}
2357
2358
7
napi_status napi_create_external(napi_env env,
2359
                                 void* data,
2360
                                 napi_finalize finalize_cb,
2361
                                 void* finalize_hint,
2362
                                 napi_value* result) {
2363


21
  NAPI_PREAMBLE(env);
2364
7
  CHECK_ARG(env, result);
2365
2366
7
  v8::Isolate* isolate = env->isolate;
2367
2368
7
  v8::Local<v8::Value> external_value = v8::External::New(isolate, data);
2369
2370
  // The Reference object will delete itself after invoking the finalizer
2371
  // callback.
2372
  v8impl::Reference::New(env,
2373
      external_value,
2374
      0,
2375
      true,
2376
      finalize_cb,
2377
      data,
2378
7
      finalize_hint);
2379
2380
7
  *result = v8impl::JsValueFromV8LocalValue(external_value);
2381
2382
7
  return napi_clear_last_error(env);
2383
}
2384
2385
2
NAPI_EXTERN napi_status napi_type_tag_object(napi_env env,
2386
                                             napi_value object,
2387
                                             const napi_type_tag* type_tag) {
2388


6
  NAPI_PREAMBLE(env);
2389
2
  v8::Local<v8::Context> context = env->context();
2390
  v8::Local<v8::Object> obj;
2391


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

2
  CHECK_ARG_WITH_PREAMBLE(env, type_tag);
2393
2394
2
  auto key = NAPI_PRIVATE_KEY(context, type_tag);
2395
2
  auto maybe_has = obj->HasPrivate(context, key);
2396

2
  CHECK_MAYBE_NOTHING_WITH_PREAMBLE(env, maybe_has, napi_generic_failure);
2397

2
  RETURN_STATUS_IF_FALSE_WITH_PREAMBLE(env,
2398
                                       !maybe_has.FromJust(),
2399
                                       napi_invalid_arg);
2400
2401
  auto tag = v8::BigInt::NewFromWords(context,
2402
                                   0,
2403
                                   2,
2404
2
                                   reinterpret_cast<const uint64_t*>(type_tag));
2405

2
  CHECK_MAYBE_EMPTY_WITH_PREAMBLE(env, tag, napi_generic_failure);
2406
2407
2
  auto maybe_set = obj->SetPrivate(context, key, tag.ToLocalChecked());
2408

2
  CHECK_MAYBE_NOTHING_WITH_PREAMBLE(env, maybe_set, napi_generic_failure);
2409

2
  RETURN_STATUS_IF_FALSE_WITH_PREAMBLE(env,
2410
                                       maybe_set.FromJust(),
2411
                                       napi_generic_failure);
2412
2413
2
  return GET_RETURN_STATUS(env);
2414
}
2415
2416
NAPI_EXTERN napi_status
2417
6
napi_check_object_type_tag(napi_env env,
2418
                           napi_value object,
2419
                           const napi_type_tag* type_tag,
2420
                           bool* result) {
2421


18
  NAPI_PREAMBLE(env);
2422
6
  v8::Local<v8::Context> context = env->context();
2423
  v8::Local<v8::Object> obj;
2424


24
  CHECK_TO_OBJECT_WITH_PREAMBLE(env, context, obj, object);
2425

6
  CHECK_ARG_WITH_PREAMBLE(env, type_tag);
2426

6
  CHECK_ARG_WITH_PREAMBLE(env, result);
2427
2428
  auto maybe_value = obj->GetPrivate(context,
2429
12
                                     NAPI_PRIVATE_KEY(context, type_tag));
2430

6
  CHECK_MAYBE_EMPTY_WITH_PREAMBLE(env, maybe_value, napi_generic_failure);
2431
6
  v8::Local<v8::Value> val = maybe_value.ToLocalChecked();
2432
2433
  // We consider the type check to have failed unless we reach the line below
2434
  // where we set whether the type check succeeded or not based on the
2435
  // comparison of the two type tags.
2436
6
  *result = false;
2437
6
  if (val->IsBigInt()) {
2438
    int sign;
2439
4
    int size = 2;
2440
    napi_type_tag tag;
2441
12
    val.As<v8::BigInt>()->ToWordsArray(&sign,
2442
                                       &size,
2443
4
                                       reinterpret_cast<uint64_t*>(&tag));
2444

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

4
      *result = (tag.lower == type_tag->lower && tag.upper == type_tag->upper);
2446
  }
2447
2448
6
  return GET_RETURN_STATUS(env);
2449
}
2450
2451
2
napi_status napi_get_value_external(napi_env env,
2452
                                    napi_value value,
2453
                                    void** result) {
2454
2
  CHECK_ENV(env);
2455
2
  CHECK_ARG(env, value);
2456
2
  CHECK_ARG(env, result);
2457
2458
2
  v8::Local<v8::Value> val = v8impl::V8LocalValueFromJsValue(value);
2459
2
  RETURN_STATUS_IF_FALSE(env, val->IsExternal(), napi_invalid_arg);
2460
2461
2
  v8::Local<v8::External> external_value = val.As<v8::External>();
2462
4
  *result = external_value->Value();
2463
2464
2
  return napi_clear_last_error(env);
2465
}
2466
2467
// Set initial_refcount to 0 for a weak reference, >0 for a strong reference.
2468
1540
napi_status napi_create_reference(napi_env env,
2469
                                  napi_value value,
2470
                                  uint32_t initial_refcount,
2471
                                  napi_ref* result) {
2472
  // Omit NAPI_PREAMBLE and GET_RETURN_STATUS because V8 calls here cannot throw
2473
  // JS exceptions.
2474
1540
  CHECK_ENV(env);
2475
1540
  CHECK_ARG(env, value);
2476
1540
  CHECK_ARG(env, result);
2477
2478
1540
  v8::Local<v8::Value> v8_value = v8impl::V8LocalValueFromJsValue(value);
2479
2480

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


33
  NAPI_PREAMBLE(env);
2651
11
  CHECK_ARG(env, constructor);
2652
11
  if (argc > 0) {
2653
7
    CHECK_ARG(env, argv);
2654
  }
2655
11
  CHECK_ARG(env, result);
2656
2657
11
  v8::Local<v8::Context> context = env->context();
2658
2659
  v8::Local<v8::Function> ctor;
2660

33
  CHECK_TO_FUNCTION(env, ctor, constructor);
2661
2662
  auto maybe = ctor->NewInstance(context, argc,
2663
22
    reinterpret_cast<v8::Local<v8::Value>*>(const_cast<napi_value*>(argv)));
2664
2665
13
  CHECK_MAYBE_EMPTY(env, maybe, napi_pending_exception);
2666
2667
18
  *result = v8impl::JsValueFromV8LocalValue(maybe.ToLocalChecked());
2668
9
  return GET_RETURN_STATUS(env);
2669
}
2670
2671
2278
napi_status napi_instanceof(napi_env env,
2672
                            napi_value object,
2673
                            napi_value constructor,
2674
                            bool* result) {
2675


6834
  NAPI_PREAMBLE(env);
2676
2278
  CHECK_ARG(env, object);
2677
2278
  CHECK_ARG(env, result);
2678
2679
2278
  *result = false;
2680
2681
  v8::Local<v8::Object> ctor;
2682
2278
  v8::Local<v8::Context> context = env->context();
2683
2684

9112
  CHECK_TO_OBJECT(env, context, ctor, constructor);
2685
2686
2278
  if (!ctor->IsFunction()) {
2687
    napi_throw_type_error(env,
2688
                          "ERR_NAPI_CONS_FUNCTION",
2689
88
                          "Constructor must be a function");
2690
2691
88
    return napi_set_last_error(env, napi_function_expected);
2692
  }
2693
2694
2190
  napi_status status = napi_generic_failure;
2695
2696
2190
  v8::Local<v8::Value> val = v8impl::V8LocalValueFromJsValue(object);
2697
2190
  auto maybe_result = val->InstanceOf(context, ctor);
2698
2190
  CHECK_MAYBE_NOTHING(env, maybe_result, status);
2699
2332
  *result = maybe_result.FromJust();
2700
1166
  return GET_RETURN_STATUS(env);
2701
}
2702
2703
// Methods to support catching exceptions
2704
1233
napi_status napi_is_exception_pending(napi_env env, bool* result) {
2705
  // NAPI_PREAMBLE is not used here: this function must execute when there is a
2706
  // pending exception.
2707
1233
  CHECK_ENV(env);
2708
1233
  CHECK_ARG(env, result);
2709
2710
2466
  *result = !env->last_exception.IsEmpty();
2711
1233
  return napi_clear_last_error(env);
2712
}
2713
2714
2
napi_status napi_get_and_clear_last_exception(napi_env env,
2715
                                              napi_value* result) {
2716
  // NAPI_PREAMBLE is not used here: this function must execute when there is a
2717
  // pending exception.
2718
2
  CHECK_ENV(env);
2719
2
  CHECK_ARG(env, result);
2720
2721
4
  if (env->last_exception.IsEmpty()) {
2722
    return napi_get_undefined(env, result);
2723
  } else {
2724
4
    *result = v8impl::JsValueFromV8LocalValue(
2725
2
      v8::Local<v8::Value>::New(env->isolate, env->last_exception));
2726
2
    env->last_exception.Reset();
2727
  }
2728
2729
2
  return napi_clear_last_error(env);
2730
}
2731
2732
57
napi_status napi_is_arraybuffer(napi_env env, napi_value value, bool* result) {
2733
57
  CHECK_ENV(env);
2734
57
  CHECK_ARG(env, value);
2735
57
  CHECK_ARG(env, result);
2736
2737
57
  v8::Local<v8::Value> val = v8impl::V8LocalValueFromJsValue(value);
2738
114
  *result = val->IsArrayBuffer();
2739
2740
57
  return napi_clear_last_error(env);
2741
}
2742
2743
2
napi_status napi_create_arraybuffer(napi_env env,
2744
                                    size_t byte_length,
2745
                                    void** data,
2746
                                    napi_value* result) {
2747


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


102
  NAPI_PREAMBLE(env);
2833
34
  CHECK_ARG(env, arraybuffer);
2834
34
  CHECK_ARG(env, result);
2835
2836
34
  v8::Local<v8::Value> value = v8impl::V8LocalValueFromJsValue(arraybuffer);
2837
34
  RETURN_STATUS_IF_FALSE(env, value->IsArrayBuffer(), napi_invalid_arg);
2838
2839
34
  v8::Local<v8::ArrayBuffer> buffer = value.As<v8::ArrayBuffer>();
2840
  v8::Local<v8::TypedArray> typedArray;
2841
2842



34
  switch (type) {
2843
    case napi_int8_array:
2844
8
      CREATE_TYPED_ARRAY(
2845
          env, Int8Array, 1, buffer, byte_offset, length, typedArray);
2846
3
      break;
2847
    case napi_uint8_array:
2848
4
      CREATE_TYPED_ARRAY(
2849
          env, Uint8Array, 1, buffer, byte_offset, length, typedArray);
2850
8
      break;
2851
1
    case napi_uint8_clamped_array:
2852
3
      CREATE_TYPED_ARRAY(
2853
          env, Uint8ClampedArray, 1, buffer, byte_offset, length, typedArray);
2854
5
      break;
2855
1
    case napi_int16_array:
2856
5
      CREATE_TYPED_ARRAY(
2857
1
          env, Int16Array, 2, buffer, byte_offset, length, typedArray);
2858
4
      break;
2859
1
    case napi_uint16_array:
2860
5
      CREATE_TYPED_ARRAY(
2861
1
          env, Uint16Array, 2, buffer, byte_offset, length, typedArray);
2862
4
      break;
2863
1
    case napi_int32_array:
2864
5
      CREATE_TYPED_ARRAY(
2865
1
          env, Int32Array, 4, buffer, byte_offset, length, typedArray);
2866
4
      break;
2867
1
    case napi_uint32_array:
2868
5
      CREATE_TYPED_ARRAY(
2869
1
          env, Uint32Array, 4, buffer, byte_offset, length, typedArray);
2870
4
      break;
2871
1
    case napi_float32_array:
2872
5
      CREATE_TYPED_ARRAY(
2873
1
          env, Float32Array, 4, buffer, byte_offset, length, typedArray);
2874
4
      break;
2875
1
    case napi_float64_array:
2876
6
      CREATE_TYPED_ARRAY(
2877
1
          env, Float64Array, 8, buffer, byte_offset, length, typedArray);
2878
6
      break;
2879
1
    case napi_bigint64_array:
2880
6
      CREATE_TYPED_ARRAY(
2881
1
          env, BigInt64Array, 8, buffer, byte_offset, length, typedArray);
2882
4
      break;
2883
1
    case napi_biguint64_array:
2884
5
      CREATE_TYPED_ARRAY(
2885
1
          env, BigUint64Array, 8, buffer, byte_offset, length, typedArray);
2886
4
      break;
2887
1
    default:
2888
2
      return napi_set_last_error(env, napi_invalid_arg);
2889
  }
2890
2891
30
  *result = v8impl::JsValueFromV8LocalValue(typedArray);
2892
15
  return GET_RETURN_STATUS(env);
2893
}
2894
2895
50
napi_status napi_get_typedarray_info(napi_env env,
2896
                                     napi_value typedarray,
2897
                                     napi_typedarray_type* type,
2898
                                     size_t* length,
2899
                                     void** data,
2900
                                     napi_value* arraybuffer,
2901
                                     size_t* byte_offset) {
2902
50
  CHECK_ENV(env);
2903
50
  CHECK_ARG(env, typedarray);
2904
2905
50
  v8::Local<v8::Value> value = v8impl::V8LocalValueFromJsValue(typedarray);
2906
50
  RETURN_STATUS_IF_FALSE(env, value->IsTypedArray(), napi_invalid_arg);
2907
2908
50
  v8::Local<v8::TypedArray> array = value.As<v8::TypedArray>();
2909
2910
50
  if (type != nullptr) {
2911
32
    if (value->IsInt8Array()) {
2912
2
      *type = napi_int8_array;
2913
30
    } else if (value->IsUint8Array()) {
2914
3
      *type = napi_uint8_array;
2915
27
    } else if (value->IsUint8ClampedArray()) {
2916
2
      *type = napi_uint8_clamped_array;
2917
25
    } else if (value->IsInt16Array()) {
2918
3
      *type = napi_int16_array;
2919
22
    } else if (value->IsUint16Array()) {
2920
3
      *type = napi_uint16_array;
2921
19
    } else if (value->IsInt32Array()) {
2922
3
      *type = napi_int32_array;
2923
16
    } else if (value->IsUint32Array()) {
2924
3
      *type = napi_uint32_array;
2925
13
    } else if (value->IsFloat32Array()) {
2926
3
      *type = napi_float32_array;
2927
10
    } else if (value->IsFloat64Array()) {
2928
4
      *type = napi_float64_array;
2929
6
    } else if (value->IsBigInt64Array()) {
2930
3
      *type = napi_bigint64_array;
2931
3
    } else if (value->IsBigUint64Array()) {
2932
3
      *type = napi_biguint64_array;
2933
    }
2934
  }
2935
2936
50
  if (length != nullptr) {
2937
32
    *length = array->Length();
2938
  }
2939
2940
  v8::Local<v8::ArrayBuffer> buffer;
2941

50
  if (data != nullptr || arraybuffer != nullptr) {
2942
    // Calling Buffer() may have the side effect of allocating the buffer,
2943
    // so only do this when it’s needed.
2944
50
    buffer = array->Buffer();
2945
  }
2946
2947
50
  if (data != nullptr) {
2948
    *data = static_cast<uint8_t*>(buffer->GetBackingStore()->Data()) +
2949
            array->ByteOffset();
2950
  }
2951
2952
50
  if (arraybuffer != nullptr) {
2953
50
    *arraybuffer = v8impl::JsValueFromV8LocalValue(buffer);
2954
  }
2955
2956
50
  if (byte_offset != nullptr) {
2957
32
    *byte_offset = array->ByteOffset();
2958
  }
2959
2960
50
  return napi_clear_last_error(env);
2961
}
2962
2963
2
napi_status napi_create_dataview(napi_env env,
2964
                                 size_t byte_length,
2965
                                 napi_value arraybuffer,
2966
                                 size_t byte_offset,
2967
                                 napi_value* result) {
2968


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

1
  if (data != nullptr || arraybuffer != nullptr) {
3022
    // Calling Buffer() may have the side effect of allocating the buffer,
3023
    // so only do this when it’s needed.
3024
1
    buffer = array->Buffer();
3025
  }
3026
3027
1
  if (data != nullptr) {
3028
    *data = static_cast<uint8_t*>(buffer->GetBackingStore()->Data()) +
3029
            array->ByteOffset();
3030
  }
3031
3032
1
  if (arraybuffer != nullptr) {
3033
1
    *arraybuffer = v8impl::JsValueFromV8LocalValue(buffer);
3034
  }
3035
3036
1
  if (byte_offset != nullptr) {
3037
1
    *byte_offset = array->ByteOffset();
3038
  }
3039
3040
1
  return napi_clear_last_error(env);
3041
}
3042
3043
1
napi_status napi_get_version(napi_env env, uint32_t* result) {
3044
1
  CHECK_ENV(env);
3045
1
  CHECK_ARG(env, result);
3046
1
  *result = NAPI_VERSION;
3047
1
  return napi_clear_last_error(env);
3048
}
3049
3050
5
napi_status napi_create_promise(napi_env env,
3051
                                napi_deferred* deferred,
3052
                                napi_value* promise) {
3053


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


3
  NAPI_PREAMBLE(env);
3097
1
  CHECK_ARG(env, result);
3098
3099
1
  v8::MaybeLocal<v8::Value> maybe_date = v8::Date::New(env->context(), time);
3100
1
  CHECK_MAYBE_EMPTY(env, maybe_date, napi_generic_failure);
3101
3102
2
  *result = v8impl::JsValueFromV8LocalValue(maybe_date.ToLocalChecked());
3103
3104
1
  return GET_RETURN_STATUS(env);
3105
}
3106
3107
7
napi_status napi_is_date(napi_env env,
3108
                         napi_value value,
3109
                         bool* is_date) {
3110
7
  CHECK_ENV(env);
3111
7
  CHECK_ARG(env, value);
3112
7
  CHECK_ARG(env, is_date);
3113
3114
14
  *is_date = v8impl::V8LocalValueFromJsValue(value)->IsDate();
3115
3116
7
  return napi_clear_last_error(env);
3117
}
3118
3119
1
napi_status napi_get_date_value(napi_env env,
3120
                                napi_value value,
3121
                                double* result) {
3122


3
  NAPI_PREAMBLE(env);
3123
1
  CHECK_ARG(env, value);
3124
1
  CHECK_ARG(env, result);
3125
3126
1
  v8::Local<v8::Value> val = v8impl::V8LocalValueFromJsValue(value);
3127
1
  RETURN_STATUS_IF_FALSE(env, val->IsDate(), napi_date_expected);
3128
3129
1
  v8::Local<v8::Date> date = val.As<v8::Date>();
3130
2
  *result = date->ValueOf();
3131
3132
1
  return GET_RETURN_STATUS(env);
3133
}
3134
3135
2
napi_status napi_run_script(napi_env env,
3136
                            napi_value script,
3137
                            napi_value* result) {
3138


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

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

14538
}