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: 1388 1419 97.8 %
Date: 2021-04-17 04:11:57 Branches: 1067 1700 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
436
V8NameFromPropertyDescriptor(napi_env env,
65
                             const napi_property_descriptor* p,
66
                             v8::Local<v8::Name>* result) {
67
436
  if (p->utf8name != nullptr) {
68

1302
    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
436
  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
3030
  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
3030
       : Finalizer(env, finalize_callback, finalize_data, finalize_hint),
201
        _refcount(initial_refcount),
202
3030
        _delete_self(delete_self) {
203
3030
    Link(finalize_callback == nullptr
204
        ? &env->reflist
205
3030
        : &env->finalizing_reflist);
206
3030
  }
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
3029
  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
3034
  static inline void Delete(RefBase* reference) {
245

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

4052
        (reference->_delete_self) ||
247
1018
        (reference->_finalize_ran)) {
248
3022
      delete reference;
249
    } else {
250
      // defer until finalizer runs as
251
      // it may alread be queued
252
12
      reference->_delete_self = true;
253
    }
254
3034
  }
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
6531
  inline uint32_t RefCount() {
268
6531
    return _refcount;
269
  }
270
271
 protected:
272
2488
  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

2488
    if (is_env_teardown && RefCount() > 0) _refcount = 0;
293
294
2488
    if (_finalize_callback != nullptr) {
295
      // This ensures that we never call the finalizer twice.
296
1470
      napi_finalize fini = _finalize_callback;
297
1470
      _finalize_callback = nullptr;
298
1470
      _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

2488
    if (_delete_self || is_env_teardown) {
305
1482
      Delete(this);
306
    } else {
307
1006
      _finalize_ran = true;
308
    }
309
2488
  }
310
311
 private:
312
  uint32_t _refcount;
313
  bool _delete_self;
314
};
315
316
9045
class Reference : public RefBase {
317
 protected:
318
  template <typename... Args>
319
3023
  Reference(napi_env env,
320
            v8::Local<v8::Value> value,
321
            Args&&... args)
322
15115
      : RefBase(env, std::forward<Args>(args)...),
323
15115
            _persistent(env->isolate, value) {
324
3023
    if (RefCount() == 0) {
325
2485
      _persistent.SetWeak(
326
          this, FinalizeCallback, v8::WeakCallbackType::kParameter);
327
    }
328
3023
  }
329
330
 public:
331
3023
  static inline Reference* New(napi_env env,
332
                             v8::Local<v8::Value> value,
333
                             uint32_t initial_refcount,
334
                             bool delete_self,
335
                             napi_finalize finalize_callback = nullptr,
336
                             void* finalize_data = nullptr,
337
                             void* finalize_hint = nullptr) {
338
    return new Reference(env,
339
                         value,
340
                         initial_refcount,
341
                         delete_self,
342
                         finalize_callback,
343
                         finalize_data,
344
3023
                         finalize_hint);
345
  }
346
347
3
  inline uint32_t Ref() {
348
3
    uint32_t refcount = RefBase::Ref();
349
3
    if (refcount == 1) {
350
2
      _persistent.ClearWeak();
351
    }
352
3
    return refcount;
353
  }
354
355
3
  inline uint32_t Unref() {
356
3
    uint32_t old_refcount = RefCount();
357
3
    uint32_t refcount = RefBase::Unref();
358

3
    if (old_refcount == 1 && refcount == 0) {
359
2
      _persistent.SetWeak(
360
          this, FinalizeCallback, v8::WeakCallbackType::kParameter);
361
    }
362
3
    return refcount;
363
  }
364
365
1550
  inline v8::Local<v8::Value> Get() {
366
3100
    if (_persistent.IsEmpty()) {
367
1002
      return v8::Local<v8::Value>();
368
    } else {
369
1096
      return v8::Local<v8::Value>::New(_env->isolate, _persistent);
370
    }
371
  }
372
373
 protected:
374
2481
  inline void Finalize(bool is_env_teardown = false) override {
375
2481
    if (is_env_teardown) env_teardown_finalize_started_ = true;
376

2481
    if (!is_env_teardown && env_teardown_finalize_started_) return;
377
378
    // During env teardown, `~napi_env()` alone is responsible for finalizing.
379
    // Thus, we don't want any stray gc passes to trigger a second call to
380
    // `Finalize()`, so let's reset the persistent here if nothing is
381
    // keeping it alive.
382

2942
    if (is_env_teardown && _persistent.IsWeak()) {
383
450
      _persistent.ClearWeak();
384
    }
385
386
    // Chain up to perform the rest of the finalization.
387
2481
    RefBase::Finalize(is_env_teardown);
388
  }
389
390
 private:
391
  // The N-API finalizer callback may make calls into the engine. V8's heap is
392
  // not in a consistent state during the weak callback, and therefore it does
393
  // not support calls back into it. However, it provides a mechanism for adding
394
  // a finalizer which may make calls back into the engine by allowing us to
395
  // attach such a second-pass finalizer from the first pass finalizer. Thus,
396
  // we do that here to ensure that the N-API finalizer callback is free to call
397
  // into the engine.
398
2020
  static void FinalizeCallback(const v8::WeakCallbackInfo<Reference>& data) {
399
2020
    Reference* reference = data.GetParameter();
400
401
    // The reference must be reset during the first pass.
402
2020
    reference->_persistent.Reset();
403
404
2020
    data.SetSecondPassCallback(SecondPassCallback);
405
2020
  }
406
407
2020
  static void SecondPassCallback(const v8::WeakCallbackInfo<Reference>& data) {
408
2020
    data.GetParameter()->Finalize();
409
2020
  }
410
411
  bool env_teardown_finalize_started_ = false;
412
  v8impl::Persistent<v8::Value> _persistent;
413
};
414
415
enum UnwrapAction {
416
  KeepWrap,
417
  RemoveWrap
418
};
419
420
35
inline static napi_status Unwrap(napi_env env,
421
                                 napi_value js_object,
422
                                 void** result,
423
                                 UnwrapAction action) {
424


105
  NAPI_PREAMBLE(env);
425
35
  CHECK_ARG(env, js_object);
426
35
  if (action == KeepWrap) {
427
27
    CHECK_ARG(env, result);
428
  }
429
430
35
  v8::Local<v8::Context> context = env->context();
431
432
35
  v8::Local<v8::Value> value = v8impl::V8LocalValueFromJsValue(js_object);
433
35
  RETURN_STATUS_IF_FALSE(env, value->IsObject(), napi_invalid_arg);
434
35
  v8::Local<v8::Object> obj = value.As<v8::Object>();
435
436
105
  auto val = obj->GetPrivate(context, NAPI_PRIVATE_KEY(context, wrapper))
437
35
      .ToLocalChecked();
438
35
  RETURN_STATUS_IF_FALSE(env, val->IsExternal(), napi_invalid_arg);
439
  Reference* reference =
440
70
      static_cast<v8impl::Reference*>(val.As<v8::External>()->Value());
441
442
35
  if (result) {
443
35
    *result = reference->Data();
444
  }
445
446
35
  if (action == RemoveWrap) {
447
24
    CHECK(obj->DeletePrivate(context, NAPI_PRIVATE_KEY(context, wrapper))
448
        .FromJust());
449
8
    Reference::Delete(reference);
450
  }
451
452
35
  return GET_RETURN_STATUS(env);
453
}
454
455
//=== Function napi_callback wrapper =================================
456
457
// Use this data structure to associate callback data with each N-API function
458
// exposed to JavaScript. The structure is stored in a v8::External which gets
459
// passed into our callback wrapper. This reduces the performance impact of
460
// calling through N-API.
461
// Ref: benchmark/misc/function_call
462
// Discussion (incl. perf. data): https://github.com/nodejs/node/pull/21072
463
class CallbackBundle {
464
 public:
465
  // Creates an object to be made available to the static function callback
466
  // wrapper, used to retrieve the native callback function and data pointer.
467
  static inline v8::Local<v8::Value>
468
447
  New(napi_env env, napi_callback cb, void* data) {
469
447
    CallbackBundle* bundle = new CallbackBundle();
470
447
    bundle->cb = cb;
471
447
    bundle->cb_data = data;
472
447
    bundle->env = env;
473
474
447
    v8::Local<v8::Value> cbdata = v8::External::New(env->isolate, bundle);
475
447
    Reference::New(env, cbdata, 0, true, Delete, bundle, nullptr);
476
447
    return cbdata;
477
  }
478
  napi_env       env;      // Necessary to invoke C++ NAPI callback
479
  void*          cb_data;  // The user provided callback data
480
  napi_callback  cb;
481
 private:
482
440
  static void Delete(napi_env env, void* data, void* hint) {
483
440
    CallbackBundle* bundle = static_cast<CallbackBundle*>(data);
484
440
    delete bundle;
485
440
  }
486
};
487
488
// Base class extended by classes that wrap V8 function and property callback
489
// info.
490
class CallbackWrapper {
491
 public:
492
4635
  inline CallbackWrapper(napi_value this_arg, size_t args_length, void* data)
493
4635
      : _this(this_arg), _args_length(args_length), _data(data) {}
494
495
  virtual napi_value GetNewTarget() = 0;
496
  virtual void Args(napi_value* buffer, size_t bufferlength) = 0;
497
  virtual void SetReturnValue(napi_value value) = 0;
498
499
42
  napi_value This() { return _this; }
500
501
4477
  size_t ArgsLength() { return _args_length; }
502
503
6
  void* Data() { return _data; }
504
505
 protected:
506
  const napi_value _this;
507
  const size_t _args_length;
508
  void* _data;
509
};
510
511
class CallbackWrapperBase : public CallbackWrapper {
512
 public:
513
4635
  inline CallbackWrapperBase(const v8::FunctionCallbackInfo<v8::Value>& cbinfo,
514
                             const size_t args_length)
515
4635
      : CallbackWrapper(JsValueFromV8LocalValue(cbinfo.This()),
516
                        args_length,
517
                        nullptr),
518
4635
        _cbinfo(cbinfo) {
519
4635
    _bundle = reinterpret_cast<CallbackBundle*>(
520
13905
        v8::Local<v8::External>::Cast(cbinfo.Data())->Value());
521
4635
    _data = _bundle->cb_data;
522
4635
  }
523
524
 protected:
525
4635
  inline void InvokeCallback() {
526
    napi_callback_info cbinfo_wrapper = reinterpret_cast<napi_callback_info>(
527
4635
        static_cast<CallbackWrapper*>(this));
528
529
    // All other pointers we need are stored in `_bundle`
530
4635
    napi_env env = _bundle->env;
531
4635
    napi_callback cb = _bundle->cb;
532
533
    napi_value result;
534
13905
    env->CallIntoModule([&](napi_env env) {
535
4635
      result = cb(env, cbinfo_wrapper);
536
9270
    });
537
538
4635
    if (result != nullptr) {
539
2809
      this->SetReturnValue(result);
540
    }
541
4635
  }
542
543
  const v8::FunctionCallbackInfo<v8::Value>& _cbinfo;
544
  CallbackBundle* _bundle;
545
};
546
547
class FunctionCallbackWrapper
548
    : public CallbackWrapperBase {
549
 public:
550
4635
  static void Invoke(const v8::FunctionCallbackInfo<v8::Value>& info) {
551
4635
    FunctionCallbackWrapper cbwrapper(info);
552
4635
    cbwrapper.InvokeCallback();
553
4635
  }
554
555
416
  static inline napi_status NewFunction(napi_env env,
556
                                        napi_callback cb,
557
                                        void* cb_data,
558
                                        v8::Local<v8::Function>* result) {
559
416
    v8::Local<v8::Value> cbdata = v8impl::CallbackBundle::New(env, cb, cb_data);
560
416
    RETURN_STATUS_IF_FALSE(env, !cbdata.IsEmpty(), napi_generic_failure);
561
562
    v8::MaybeLocal<v8::Function> maybe_function =
563
416
        v8::Function::New(env->context(), Invoke, cbdata);
564
416
    CHECK_MAYBE_EMPTY(env, maybe_function, napi_generic_failure);
565
566
416
    *result = maybe_function.ToLocalChecked();
567
416
    return napi_clear_last_error(env);
568
  }
569
570
31
  static inline napi_status NewTemplate(napi_env env,
571
                    napi_callback cb,
572
                    void* cb_data,
573
                    v8::Local<v8::FunctionTemplate>* result,
574
                    v8::Local<v8::Signature> sig = v8::Local<v8::Signature>()) {
575
31
    v8::Local<v8::Value> cbdata = v8impl::CallbackBundle::New(env, cb, cb_data);
576
31
    RETURN_STATUS_IF_FALSE(env, !cbdata.IsEmpty(), napi_generic_failure);
577
578
31
    *result = v8::FunctionTemplate::New(env->isolate, Invoke, cbdata, sig);
579
31
    return napi_clear_last_error(env);
580
  }
581
582
4635
  explicit FunctionCallbackWrapper(
583
      const v8::FunctionCallbackInfo<v8::Value>& cbinfo)
584
9270
      : CallbackWrapperBase(cbinfo, cbinfo.Length()) {}
585
586
8
  napi_value GetNewTarget() override {
587
16
    if (_cbinfo.IsConstructCall()) {
588
14
      return v8impl::JsValueFromV8LocalValue(_cbinfo.NewTarget());
589
    } else {
590
1
      return nullptr;
591
    }
592
  }
593
594
  /*virtual*/
595
4465
  void Args(napi_value* buffer, size_t buffer_length) override {
596
4465
    size_t i = 0;
597
4465
    size_t min = std::min(buffer_length, _args_length);
598
599
18545
    for (; i < min; i += 1) {
600
14080
      buffer[i] = v8impl::JsValueFromV8LocalValue(_cbinfo[i]);
601
    }
602
603
4465
    if (i < buffer_length) {
604
      napi_value undefined =
605
75
          v8impl::JsValueFromV8LocalValue(v8::Undefined(_cbinfo.GetIsolate()));
606
181
      for (; i < buffer_length; i += 1) {
607
78
        buffer[i] = undefined;
608
      }
609
    }
610
4465
  }
611
612
  /*virtual*/
613
2809
  void SetReturnValue(napi_value value) override {
614
2809
    v8::Local<v8::Value> val = v8impl::V8LocalValueFromJsValue(value);
615
8427
    _cbinfo.GetReturnValue().Set(val);
616
2809
  }
617
};
618
619
enum WrapType {
620
  retrievable,
621
  anonymous
622
};
623
624
template <WrapType wrap_type>
625
1031
inline napi_status Wrap(napi_env env,
626
                        napi_value js_object,
627
                        void* native_object,
628
                        napi_finalize finalize_cb,
629
                        void* finalize_hint,
630
                        napi_ref* result) {
631




3093
  NAPI_PREAMBLE(env);
632

1031
  CHECK_ARG(env, js_object);
633
634
1031
  v8::Local<v8::Context> context = env->context();
635
636
1031
  v8::Local<v8::Value> value = v8impl::V8LocalValueFromJsValue(js_object);
637

1031
  RETURN_STATUS_IF_FALSE(env, value->IsObject(), napi_invalid_arg);
638
1031
  v8::Local<v8::Object> obj = value.As<v8::Object>();
639
640
  if (wrap_type == retrievable) {
641
    // If we've already wrapped this object, we error out.
642
3084
    RETURN_STATUS_IF_FALSE(env,
643
        !obj->HasPrivate(context, NAPI_PRIVATE_KEY(context, wrapper))
644
            .FromJust(),
645
        napi_invalid_arg);
646
  } else if (wrap_type == anonymous) {
647
    // If no finalize callback is provided, we error out.
648
3
    CHECK_ARG(env, finalize_cb);
649
  }
650
651
1030
  v8impl::Reference* reference = nullptr;
652

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

11
    CHECK_ARG(env, finalize_cb);
658
22
    reference = v8impl::Reference::New(
659
        env, obj, 0, false, finalize_cb, native_object, finalize_hint);
660
11
    *result = reinterpret_cast<napi_ref>(reference);
661
  } else {
662
    // Create a self-deleting reference.
663

2038
    reference = v8impl::Reference::New(env, obj, 0, true, finalize_cb,
664
1019
        native_object, finalize_cb == nullptr ? nullptr : finalize_hint);
665
  }
666
667
  if (wrap_type == retrievable) {
668
4108
    CHECK(obj->SetPrivate(context, NAPI_PRIVATE_KEY(context, wrapper),
669
          v8::External::New(env->isolate, reference)).FromJust());
670
  }
671
672

1030
  return GET_RETURN_STATUS(env);
673
}
674
675
}  // end of anonymous namespace
676
677
}  // end of namespace v8impl
678
679
// Warning: Keep in-sync with napi_status enum
680
static
681
const char* error_messages[] = {nullptr,
682
                                "Invalid argument",
683
                                "An object was expected",
684
                                "A string was expected",
685
                                "A string or symbol was expected",
686
                                "A function was expected",
687
                                "A number was expected",
688
                                "A boolean was expected",
689
                                "An array was expected",
690
                                "Unknown failure",
691
                                "An exception is pending",
692
                                "The async work item was cancelled",
693
                                "napi_escape_handle already called on scope",
694
                                "Invalid handle scope usage",
695
                                "Invalid callback scope usage",
696
                                "Thread-safe function queue is full",
697
                                "Thread-safe function handle is closing",
698
                                "A bigint was expected",
699
                                "A date was expected",
700
                                "An arraybuffer was expected",
701
                                "A detachable arraybuffer was expected",
702
                                "Main thread would deadlock",
703
};
704
705
1300
napi_status napi_get_last_error_info(napi_env env,
706
                                     const napi_extended_error_info** result) {
707
1300
  CHECK_ENV(env);
708
1300
  CHECK_ARG(env, result);
709
710
  // The value of the constant below must be updated to reference the last
711
  // message in the `napi_status` enum each time a new error message is added.
712
  // We don't have a napi_status_last as this would result in an ABI
713
  // change each time a message was added.
714
1300
  const int last_status = napi_would_deadlock;
715
716
  static_assert(
717
      NAPI_ARRAYSIZE(error_messages) == last_status + 1,
718
      "Count of error messages must match count of error values");
719
1300
  CHECK_LE(env->last_error.error_code, last_status);
720
721
  // Wait until someone requests the last error information to fetch the error
722
  // message string
723
2600
  env->last_error.error_message =
724
1300
      error_messages[env->last_error.error_code];
725
726
1300
  *result = &(env->last_error);
727
1300
  return napi_ok;
728
}
729
730
15
napi_status napi_create_function(napi_env env,
731
                                 const char* utf8name,
732
                                 size_t length,
733
                                 napi_callback cb,
734
                                 void* callback_data,
735
                                 napi_value* result) {
736


45
  NAPI_PREAMBLE(env);
737
15
  CHECK_ARG(env, result);
738
15
  CHECK_ARG(env, cb);
739
740
  v8::Local<v8::Function> return_value;
741
15
  v8::EscapableHandleScope scope(env->isolate);
742
  v8::Local<v8::Function> fn;
743
15
  STATUS_CALL(v8impl::FunctionCallbackWrapper::NewFunction(
744
      env, cb, callback_data, &fn));
745
15
  return_value = scope.Escape(fn);
746
747
15
  if (utf8name != nullptr) {
748
    v8::Local<v8::String> name_string;
749

3
    CHECK_NEW_FROM_UTF8_LEN(env, name_string, utf8name, length);
750
3
    return_value->SetName(name_string);
751
6
  }
752
3
753
30
  *result = v8impl::JsValueFromV8LocalValue(return_value);
754
755
15
  return GET_RETURN_STATUS(env);
756
}
757
758
15
napi_status napi_define_class(napi_env env,
759
                              const char* utf8name,
760
                              size_t length,
761
                              napi_callback constructor,
762
                              void* callback_data,
763
                              size_t property_count,
764
                              const napi_property_descriptor* properties,
765
                              napi_value* result) {
766


43
  NAPI_PREAMBLE(env);
767
14
  CHECK_ARG(env, result);
768
13
  CHECK_ARG(env, constructor);
769
770
12
  if (property_count > 0) {
771
7
    CHECK_ARG(env, properties);
772
  }
773
774
11
  v8::Isolate* isolate = env->isolate;
775
776
11
  v8::EscapableHandleScope scope(isolate);
777
  v8::Local<v8::FunctionTemplate> tpl;
778
11
  STATUS_CALL(v8impl::FunctionCallbackWrapper::NewTemplate(
779
      env, constructor, callback_data, &tpl));
780
781
  v8::Local<v8::String> name_string;
782

12
  CHECK_NEW_FROM_UTF8_LEN(env, name_string, utf8name, length);
783
11
  tpl->SetClassName(name_string);
784
20
785
20
  size_t static_property_count = 0;
786
76
  for (size_t i = 0; i < property_count; i++) {
787
28
    const napi_property_descriptor* p = properties + i;
788
789
28
    if ((p->attributes & napi_static) != 0) {
790
      // Static properties are handled separately below.
791
7
      static_property_count++;
792
7
      continue;
793
    }
794
795
    v8::Local<v8::Name> property_name;
796
21
    STATUS_CALL(v8impl::V8NameFromPropertyDescriptor(env, p, &property_name));
797
798
    v8::PropertyAttribute attributes =
799
21
        v8impl::V8PropertyAttributesFromDescriptor(p);
800
801
    // This code is similar to that in napi_define_properties(); the
802
    // difference is it applies to a template instead of an object,
803
    // and preferred PropertyAttribute for lack of PropertyDescriptor
804
    // support on ObjectTemplate.
805

21
    if (p->getter != nullptr || p->setter != nullptr) {
806
      v8::Local<v8::FunctionTemplate> getter_tpl;
807
      v8::Local<v8::FunctionTemplate> setter_tpl;
808
10
      if (p->getter != nullptr) {
809
10
        STATUS_CALL(v8impl::FunctionCallbackWrapper::NewTemplate(
810
            env, p->getter, p->data, &getter_tpl));
811
      }
812
10
      if (p->setter != nullptr) {
813
5
        STATUS_CALL(v8impl::FunctionCallbackWrapper::NewTemplate(
814
            env, p->setter, p->data, &setter_tpl));
815
      }
816
817
30
      tpl->PrototypeTemplate()->SetAccessorProperty(
818
        property_name,
819
        getter_tpl,
820
        setter_tpl,
821
        attributes,
822
20
        v8::AccessControl::DEFAULT);
823
11
    } else if (p->method != nullptr) {
824
      v8::Local<v8::FunctionTemplate> t;
825
5
      STATUS_CALL(v8impl::FunctionCallbackWrapper::NewTemplate(
826
          env, p->method, p->data, &t, v8::Signature::New(isolate, tpl)));
827
828
10
      tpl->PrototypeTemplate()->Set(property_name, t, attributes);
829
    } else {
830
6
      v8::Local<v8::Value> value = v8impl::V8LocalValueFromJsValue(p->value);
831
12
      tpl->PrototypeTemplate()->Set(property_name, value, attributes);
832
    }
833
  }
834
835
10
  v8::Local<v8::Context> context = env->context();
836
20
  *result = v8impl::JsValueFromV8LocalValue(
837
20
      scope.Escape(tpl->GetFunction(context).ToLocalChecked()));
838
839
10
  if (static_property_count > 0) {
840
6
    std::vector<napi_property_descriptor> static_descriptors;
841
3
    static_descriptors.reserve(static_property_count);
842
843
26
    for (size_t i = 0; i < property_count; i++) {
844
23
      const napi_property_descriptor* p = properties + i;
845
23
      if ((p->attributes & napi_static) != 0) {
846
7
        static_descriptors.push_back(*p);
847
      }
848
    }
849
850

3
    STATUS_CALL(napi_define_properties(env,
851
                                       *result,
852
                                       static_descriptors.size(),
853
                                       static_descriptors.data()));
854
  }
855
856
10
  return GET_RETURN_STATUS(env);
857
}
858
859
8
napi_status napi_get_property_names(napi_env env,
860
                                    napi_value object,
861
                                    napi_value* result) {
862
  return napi_get_all_property_names(
863
      env,
864
      object,
865
      napi_key_include_prototypes,
866
      static_cast<napi_key_filter>(napi_key_enumerable |
867
                                   napi_key_skip_symbols),
868
      napi_key_numbers_to_strings,
869
8
      result);
870
}
871
872
12
napi_status napi_get_all_property_names(napi_env env,
873
                                        napi_value object,
874
                                        napi_key_collection_mode key_mode,
875
                                        napi_key_filter key_filter,
876
                                        napi_key_conversion key_conversion,
877
                                        napi_value* result) {
878


32
  NAPI_PREAMBLE(env);
879
10
  CHECK_ARG(env, result);
880
881
8
  v8::Local<v8::Context> context = env->context();
882
  v8::Local<v8::Object> obj;
883

28
  CHECK_TO_OBJECT(env, context, obj, object);
884
885
6
  v8::PropertyFilter filter = v8::PropertyFilter::ALL_PROPERTIES;
886
6
  if (key_filter & napi_key_writable) {
887
    filter =
888
        static_cast<v8::PropertyFilter>(filter |
889
                                        v8::PropertyFilter::ONLY_WRITABLE);
890
  }
891
6
  if (key_filter & napi_key_enumerable) {
892
5
    filter =
893
5
        static_cast<v8::PropertyFilter>(filter |
894
                                        v8::PropertyFilter::ONLY_ENUMERABLE);
895
  }
896
6
  if (key_filter & napi_key_configurable) {
897
    filter =
898
        static_cast<v8::PropertyFilter>(filter |
899
                                        v8::PropertyFilter::ONLY_WRITABLE);
900
  }
901
6
  if (key_filter & napi_key_skip_strings) {
902
1
    filter =
903
1
        static_cast<v8::PropertyFilter>(filter |
904
                                        v8::PropertyFilter::SKIP_STRINGS);
905
  }
906
6
  if (key_filter & napi_key_skip_symbols) {
907
5
    filter =
908
5
        static_cast<v8::PropertyFilter>(filter |
909
                                        v8::PropertyFilter::SKIP_SYMBOLS);
910
  }
911
  v8::KeyCollectionMode collection_mode;
912
  v8::KeyConversionMode conversion_mode;
913
914
6
  switch (key_mode) {
915
    case napi_key_include_prototypes:
916
6
      collection_mode = v8::KeyCollectionMode::kIncludePrototypes;
917
6
      break;
918
    case napi_key_own_only:
919
      collection_mode = v8::KeyCollectionMode::kOwnOnly;
920
      break;
921
    default:
922
      return napi_set_last_error(env, napi_invalid_arg);
923
  }
924
925
6
  switch (key_conversion) {
926
    case napi_key_keep_numbers:
927
      conversion_mode = v8::KeyConversionMode::kKeepNumbers;
928
      break;
929
    case napi_key_numbers_to_strings:
930
6
      conversion_mode = v8::KeyConversionMode::kConvertToString;
931
6
      break;
932
    default:
933
      return napi_set_last_error(env, napi_invalid_arg);
934
  }
935
936
  v8::MaybeLocal<v8::Array> maybe_all_propertynames =
937
      obj->GetPropertyNames(context,
938
                            collection_mode,
939
                            filter,
940
                            v8::IndexFilter::kIncludeIndices,
941
6
                            conversion_mode);
942
943

6
  CHECK_MAYBE_EMPTY_WITH_PREAMBLE(
944
      env, maybe_all_propertynames, napi_generic_failure);
945
946
12
  *result =
947
12
      v8impl::JsValueFromV8LocalValue(maybe_all_propertynames.ToLocalChecked());
948
6
  return GET_RETURN_STATUS(env);
949
}
950
951
26
napi_status napi_set_property(napi_env env,
952
                              napi_value object,
953
                              napi_value key,
954
                              napi_value value) {
955


74
  NAPI_PREAMBLE(env);
956
24
  CHECK_ARG(env, key);
957
21
  CHECK_ARG(env, value);
958
959
19
  v8::Local<v8::Context> context = env->context();
960
  v8::Local<v8::Object> obj;
961
962

72
  CHECK_TO_OBJECT(env, context, obj, object);
963
964
17
  v8::Local<v8::Value> k = v8impl::V8LocalValueFromJsValue(key);
965
17
  v8::Local<v8::Value> val = v8impl::V8LocalValueFromJsValue(value);
966
967
17
  v8::Maybe<bool> set_maybe = obj->Set(context, k, val);
968
969
34
  RETURN_STATUS_IF_FALSE(env, set_maybe.FromMaybe(false), napi_generic_failure);
970
17
  return GET_RETURN_STATUS(env);
971
}
972
973
16
napi_status napi_has_property(napi_env env,
974
                              napi_value object,
975
                              napi_value key,
976
                              bool* result) {
977


44
  NAPI_PREAMBLE(env);
978
14
  CHECK_ARG(env, result);
979
12
  CHECK_ARG(env, key);
980
981
10
  v8::Local<v8::Context> context = env->context();
982
  v8::Local<v8::Object> obj;
983
984

36
  CHECK_TO_OBJECT(env, context, obj, object);
985
986
8
  v8::Local<v8::Value> k = v8impl::V8LocalValueFromJsValue(key);
987
8
  v8::Maybe<bool> has_maybe = obj->Has(context, k);
988
989
8
  CHECK_MAYBE_NOTHING(env, has_maybe, napi_generic_failure);
990
991
16
  *result = has_maybe.FromMaybe(false);
992
8
  return GET_RETURN_STATUS(env);
993
}
994
995
34
napi_status napi_get_property(napi_env env,
996
                              napi_value object,
997
                              napi_value key,
998
                              napi_value* result) {
999


98
  NAPI_PREAMBLE(env);
1000
32
  CHECK_ARG(env, key);
1001
28
  CHECK_ARG(env, result);
1002
1003
26
  v8::Local<v8::Context> context = env->context();
1004
26
  v8::Local<v8::Value> k = v8impl::V8LocalValueFromJsValue(key);
1005
  v8::Local<v8::Object> obj;
1006
1007

100
  CHECK_TO_OBJECT(env, context, obj, object);
1008
1009
24
  auto get_maybe = obj->Get(context, k);
1010
1011
24
  CHECK_MAYBE_EMPTY(env, get_maybe, napi_generic_failure);
1012
1013
24
  v8::Local<v8::Value> val = get_maybe.ToLocalChecked();
1014
24
  *result = v8impl::JsValueFromV8LocalValue(val);
1015
24
  return GET_RETURN_STATUS(env);
1016
}
1017
1018
9
napi_status napi_delete_property(napi_env env,
1019
                                 napi_value object,
1020
                                 napi_value key,
1021
                                 bool* result) {
1022


25
  NAPI_PREAMBLE(env);
1023
8
  CHECK_ARG(env, key);
1024
1025
7
  v8::Local<v8::Context> context = env->context();
1026
7
  v8::Local<v8::Value> k = v8impl::V8LocalValueFromJsValue(key);
1027
  v8::Local<v8::Object> obj;
1028
1029

26
  CHECK_TO_OBJECT(env, context, obj, object);
1030
6
  v8::Maybe<bool> delete_maybe = obj->Delete(context, k);
1031
6
  CHECK_MAYBE_NOTHING(env, delete_maybe, napi_generic_failure);
1032
1033
6
  if (result != nullptr)
1034
10
    *result = delete_maybe.FromMaybe(false);
1035
1036
6
  return GET_RETURN_STATUS(env);
1037
}
1038
1039
19
napi_status napi_has_own_property(napi_env env,
1040
                                  napi_value object,
1041
                                  napi_value key,
1042
                                  bool* result) {
1043


55
  NAPI_PREAMBLE(env);
1044
18
  CHECK_ARG(env, key);
1045
17
  CHECK_ARG(env, result);
1046
1047
16
  v8::Local<v8::Context> context = env->context();
1048
  v8::Local<v8::Object> obj;
1049
1050

62
  CHECK_TO_OBJECT(env, context, obj, object);
1051
15
  v8::Local<v8::Value> k = v8impl::V8LocalValueFromJsValue(key);
1052
24
  RETURN_STATUS_IF_FALSE(env, k->IsName(), napi_name_expected);
1053
6
  v8::Maybe<bool> has_maybe = obj->HasOwnProperty(context, k.As<v8::Name>());
1054
6
  CHECK_MAYBE_NOTHING(env, has_maybe, napi_generic_failure);
1055
12
  *result = has_maybe.FromMaybe(false);
1056
1057
6
  return GET_RETURN_STATUS(env);
1058
}
1059
1060
155
napi_status napi_set_named_property(napi_env env,
1061
                                    napi_value object,
1062
                                    const char* utf8name,
1063
                                    napi_value value) {
1064


463
  NAPI_PREAMBLE(env);
1065
154
  CHECK_ARG(env, value);
1066
1067
153
  v8::Local<v8::Context> context = env->context();
1068
  v8::Local<v8::Object> obj;
1069
1070

610
  CHECK_TO_OBJECT(env, context, obj, object);
1071
1072
  v8::Local<v8::Name> key;
1073

455
  CHECK_NEW_FROM_UTF8(env, key, utf8name);
1074
1075
151
  v8::Local<v8::Value> val = v8impl::V8LocalValueFromJsValue(value);
1076
1077
151
  v8::Maybe<bool> set_maybe = obj->Set(context, key, val);
1078
1079
302
  RETURN_STATUS_IF_FALSE(env, set_maybe.FromMaybe(false), napi_generic_failure);
1080
151
  return GET_RETURN_STATUS(env);
1081
}
1082
1083
9
napi_status napi_has_named_property(napi_env env,
1084
                                    napi_value object,
1085
                                    const char* utf8name,
1086
                                    bool* result) {
1087


25
  NAPI_PREAMBLE(env);
1088
8
  CHECK_ARG(env, result);
1089
1090
7
  v8::Local<v8::Context> context = env->context();
1091
  v8::Local<v8::Object> obj;
1092
1093

26
  CHECK_TO_OBJECT(env, context, obj, object);
1094
1095
  v8::Local<v8::Name> key;
1096

17
  CHECK_NEW_FROM_UTF8(env, key, utf8name);
1097
1098
5
  v8::Maybe<bool> has_maybe = obj->Has(context, key);
1099
1100
5
  CHECK_MAYBE_NOTHING(env, has_maybe, napi_generic_failure);
1101
1102
10
  *result = has_maybe.FromMaybe(false);
1103
5
  return GET_RETURN_STATUS(env);
1104
}
1105
1106
6
napi_status napi_get_named_property(napi_env env,
1107
                                    napi_value object,
1108
                                    const char* utf8name,
1109
                                    napi_value* result) {
1110


16
  NAPI_PREAMBLE(env);
1111
5
  CHECK_ARG(env, result);
1112
1113
4
  v8::Local<v8::Context> context = env->context();
1114
1115
  v8::Local<v8::Name> key;
1116

11
  CHECK_NEW_FROM_UTF8(env, key, utf8name);
1117
1118
  v8::Local<v8::Object> obj;
1119
1120

11
  CHECK_TO_OBJECT(env, context, obj, object);
1121
1122
2
  auto get_maybe = obj->Get(context, key);
1123
1124
2
  CHECK_MAYBE_EMPTY(env, get_maybe, napi_generic_failure);
1125
1126
2
  v8::Local<v8::Value> val = get_maybe.ToLocalChecked();
1127
2
  *result = v8impl::JsValueFromV8LocalValue(val);
1128
2
  return GET_RETURN_STATUS(env);
1129
}
1130
1131
13
napi_status napi_set_element(napi_env env,
1132
                             napi_value object,
1133
                             uint32_t index,
1134
                             napi_value value) {
1135


37
  NAPI_PREAMBLE(env);
1136
12
  CHECK_ARG(env, value);
1137
1138
12
  v8::Local<v8::Context> context = env->context();
1139
  v8::Local<v8::Object> obj;
1140
1141

46
  CHECK_TO_OBJECT(env, context, obj, object);
1142
1143
11
  v8::Local<v8::Value> val = v8impl::V8LocalValueFromJsValue(value);
1144
11
  auto set_maybe = obj->Set(context, index, val);
1145
1146
22
  RETURN_STATUS_IF_FALSE(env, set_maybe.FromMaybe(false), napi_generic_failure);
1147
1148
11
  return GET_RETURN_STATUS(env);
1149
}
1150
1151
5
napi_status napi_has_element(napi_env env,
1152
                             napi_value object,
1153
                             uint32_t index,
1154
                             bool* result) {
1155


13
  NAPI_PREAMBLE(env);
1156
4
  CHECK_ARG(env, result);
1157
1158
3
  v8::Local<v8::Context> context = env->context();
1159
  v8::Local<v8::Object> obj;
1160
1161

10
  CHECK_TO_OBJECT(env, context, obj, object);
1162
1163
2
  v8::Maybe<bool> has_maybe = obj->Has(context, index);
1164
1165
2
  CHECK_MAYBE_NOTHING(env, has_maybe, napi_generic_failure);
1166
1167
4
  *result = has_maybe.FromMaybe(false);
1168
2
  return GET_RETURN_STATUS(env);
1169
}
1170
1171
28
napi_status napi_get_element(napi_env env,
1172
                             napi_value object,
1173
                             uint32_t index,
1174
                             napi_value* result) {
1175


82
  NAPI_PREAMBLE(env);
1176
27
  CHECK_ARG(env, result);
1177
1178
27
  v8::Local<v8::Context> context = env->context();
1179
  v8::Local<v8::Object> obj;
1180
1181

108
  CHECK_TO_OBJECT(env, context, obj, object);
1182
1183
27
  auto get_maybe = obj->Get(context, index);
1184
1185
27
  CHECK_MAYBE_EMPTY(env, get_maybe, napi_generic_failure);
1186
1187
54
  *result = v8impl::JsValueFromV8LocalValue(get_maybe.ToLocalChecked());
1188
27
  return GET_RETURN_STATUS(env);
1189
}
1190
1191
4
napi_status napi_delete_element(napi_env env,
1192
                                napi_value object,
1193
                                uint32_t index,
1194
                                bool* result) {
1195


10
  NAPI_PREAMBLE(env);
1196
1197
3
  v8::Local<v8::Context> context = env->context();
1198
  v8::Local<v8::Object> obj;
1199
1200

10
  CHECK_TO_OBJECT(env, context, obj, object);
1201
2
  v8::Maybe<bool> delete_maybe = obj->Delete(context, index);
1202
2
  CHECK_MAYBE_NOTHING(env, delete_maybe, napi_generic_failure);
1203
1204
2
  if (result != nullptr)
1205
2
    *result = delete_maybe.FromMaybe(false);
1206
1207
2
  return GET_RETURN_STATUS(env);
1208
}
1209
1210
78
napi_status napi_define_properties(napi_env env,
1211
                                   napi_value object,
1212
                                   size_t property_count,
1213
                                   const napi_property_descriptor* properties) {
1214


232
  NAPI_PREAMBLE(env);
1215
77
  if (property_count > 0) {
1216
77
    CHECK_ARG(env, properties);
1217
  }
1218
1219
74
  v8::Local<v8::Context> context = env->context();
1220
1221
  v8::Local<v8::Object> obj;
1222

294
  CHECK_TO_OBJECT(env, context, obj, object);
1223
1224
976
  for (size_t i = 0; i < property_count; i++) {
1225
415
    const napi_property_descriptor* p = &properties[i];
1226
1227
    v8::Local<v8::Name> property_name;
1228
415
    STATUS_CALL(v8impl::V8NameFromPropertyDescriptor(env, p, &property_name));
1229
1230

415
    if (p->getter != nullptr || p->setter != nullptr) {
1231
      v8::Local<v8::Function> local_getter;
1232
      v8::Local<v8::Function> local_setter;
1233
1234
10
      if (p->getter != nullptr) {
1235
10
        STATUS_CALL(v8impl::FunctionCallbackWrapper::NewFunction(
1236
            env, p->getter, p->data, &local_getter));
1237
      }
1238
10
      if (p->setter != nullptr) {
1239
2
        STATUS_CALL(v8impl::FunctionCallbackWrapper::NewFunction(
1240
            env, p->setter, p->data, &local_setter));
1241
      }
1242
1243
20
      v8::PropertyDescriptor descriptor(local_getter, local_setter);
1244
10
      descriptor.set_enumerable((p->attributes & napi_enumerable) != 0);
1245
10
      descriptor.set_configurable((p->attributes & napi_configurable) != 0);
1246
1247
      auto define_maybe = obj->DefineProperty(context,
1248
                                              property_name,
1249
10
                                              descriptor);
1250
1251
20
      if (!define_maybe.FromMaybe(false)) {
1252
        return napi_set_last_error(env, napi_invalid_arg);
1253
10
      }
1254
405
    } else if (p->method != nullptr) {
1255
      v8::Local<v8::Function> method;
1256
389
      STATUS_CALL(v8impl::FunctionCallbackWrapper::NewFunction(
1257
          env, p->method, p->data, &method));
1258
      v8::PropertyDescriptor descriptor(method,
1259
1167
                                        (p->attributes & napi_writable) != 0);
1260
389
      descriptor.set_enumerable((p->attributes & napi_enumerable) != 0);
1261
389
      descriptor.set_configurable((p->attributes & napi_configurable) != 0);
1262
1263
      auto define_maybe = obj->DefineProperty(context,
1264
                                              property_name,
1265
389
                                              descriptor);
1266
1267
778
      if (!define_maybe.FromMaybe(false)) {
1268
        return napi_set_last_error(env, napi_generic_failure);
1269
      }
1270
    } else {
1271
16
      v8::Local<v8::Value> value = v8impl::V8LocalValueFromJsValue(p->value);
1272
1273
      v8::PropertyDescriptor descriptor(value,
1274
32
                                        (p->attributes & napi_writable) != 0);
1275
16
      descriptor.set_enumerable((p->attributes & napi_enumerable) != 0);
1276
16
      descriptor.set_configurable((p->attributes & napi_configurable) != 0);
1277
1278
      auto define_maybe =
1279
16
          obj->DefineProperty(context, property_name, descriptor);
1280
1281
32
      if (!define_maybe.FromMaybe(false)) {
1282
        return napi_set_last_error(env, napi_invalid_arg);
1283
      }
1284
    }
1285
  }
1286
1287
73
  return GET_RETURN_STATUS(env);
1288
}
1289
1290
1
napi_status napi_object_freeze(napi_env env,
1291
                               napi_value object) {
1292


3
  NAPI_PREAMBLE(env);
1293
1294
1
  v8::Local<v8::Context> context = env->context();
1295
  v8::Local<v8::Object> obj;
1296
1297

4
  CHECK_TO_OBJECT(env, context, obj, object);
1298
1299
  v8::Maybe<bool> set_frozen =
1300
1
    obj->SetIntegrityLevel(context, v8::IntegrityLevel::kFrozen);
1301
1302

2
  RETURN_STATUS_IF_FALSE_WITH_PREAMBLE(env,
1303
    set_frozen.FromMaybe(false), napi_generic_failure);
1304
1305
1
  return GET_RETURN_STATUS(env);
1306
}
1307
1308
1
napi_status napi_object_seal(napi_env env,
1309
                             napi_value object) {
1310


3
  NAPI_PREAMBLE(env);
1311
1312
1
  v8::Local<v8::Context> context = env->context();
1313
  v8::Local<v8::Object> obj;
1314
1315

4
  CHECK_TO_OBJECT(env, context, obj, object);
1316
1317
  v8::Maybe<bool> set_sealed =
1318
1
    obj->SetIntegrityLevel(context, v8::IntegrityLevel::kSealed);
1319
1320

2
  RETURN_STATUS_IF_FALSE_WITH_PREAMBLE(env,
1321
    set_sealed.FromMaybe(false), napi_generic_failure);
1322
1323
1
  return GET_RETURN_STATUS(env);
1324
}
1325
1326
11
napi_status napi_is_array(napi_env env, napi_value value, bool* result) {
1327
11
  CHECK_ENV(env);
1328
11
  CHECK_ARG(env, value);
1329
11
  CHECK_ARG(env, result);
1330
1331
11
  v8::Local<v8::Value> val = v8impl::V8LocalValueFromJsValue(value);
1332
1333
22
  *result = val->IsArray();
1334
11
  return napi_clear_last_error(env);
1335
}
1336
1337
13
napi_status napi_get_array_length(napi_env env,
1338
                                  napi_value value,
1339
                                  uint32_t* result) {
1340


39
  NAPI_PREAMBLE(env);
1341
13
  CHECK_ARG(env, value);
1342
13
  CHECK_ARG(env, result);
1343
1344
13
  v8::Local<v8::Value> val = v8impl::V8LocalValueFromJsValue(value);
1345
13
  RETURN_STATUS_IF_FALSE(env, val->IsArray(), napi_array_expected);
1346
1347
13
  v8::Local<v8::Array> arr = val.As<v8::Array>();
1348
26
  *result = arr->Length();
1349
1350
13
  return GET_RETURN_STATUS(env);
1351
}
1352
1353
9
napi_status napi_strict_equals(napi_env env,
1354
                               napi_value lhs,
1355
                               napi_value rhs,
1356
                               bool* result) {
1357


27
  NAPI_PREAMBLE(env);
1358
9
  CHECK_ARG(env, lhs);
1359
9
  CHECK_ARG(env, rhs);
1360
9
  CHECK_ARG(env, result);
1361
1362
9
  v8::Local<v8::Value> a = v8impl::V8LocalValueFromJsValue(lhs);
1363
9
  v8::Local<v8::Value> b = v8impl::V8LocalValueFromJsValue(rhs);
1364
1365
18
  *result = a->StrictEquals(b);
1366
9
  return GET_RETURN_STATUS(env);
1367
}
1368
1369
7
napi_status napi_get_prototype(napi_env env,
1370
                               napi_value object,
1371
                               napi_value* result) {
1372


19
  NAPI_PREAMBLE(env);
1373
6
  CHECK_ARG(env, result);
1374
1375
5
  v8::Local<v8::Context> context = env->context();
1376
1377
  v8::Local<v8::Object> obj;
1378

18
  CHECK_TO_OBJECT(env, context, obj, object);
1379
1380
4
  v8::Local<v8::Value> val = obj->GetPrototype();
1381
4
  *result = v8impl::JsValueFromV8LocalValue(val);
1382
4
  return GET_RETURN_STATUS(env);
1383
}
1384
1385
64
napi_status napi_create_object(napi_env env, napi_value* result) {
1386
64
  CHECK_ENV(env);
1387
64
  CHECK_ARG(env, result);
1388
1389
192
  *result = v8impl::JsValueFromV8LocalValue(
1390
64
      v8::Object::New(env->isolate));
1391
1392
64
  return napi_clear_last_error(env);
1393
}
1394
1395
1
napi_status napi_create_array(napi_env env, napi_value* result) {
1396
1
  CHECK_ENV(env);
1397
1
  CHECK_ARG(env, result);
1398
1399
3
  *result = v8impl::JsValueFromV8LocalValue(
1400
1
      v8::Array::New(env->isolate));
1401
1402
1
  return napi_clear_last_error(env);
1403
}
1404
1405
4
napi_status napi_create_array_with_length(napi_env env,
1406
                                          size_t length,
1407
                                          napi_value* result) {
1408
4
  CHECK_ENV(env);
1409
4
  CHECK_ARG(env, result);
1410
1411
12
  *result = v8impl::JsValueFromV8LocalValue(
1412
4
      v8::Array::New(env->isolate, length));
1413
1414
4
  return napi_clear_last_error(env);
1415
}
1416
1417
12
napi_status napi_create_string_latin1(napi_env env,
1418
                                      const char* str,
1419
                                      size_t length,
1420
                                      napi_value* result) {
1421
12
  CHECK_ENV(env);
1422
12
  CHECK_ARG(env, result);
1423

12
  RETURN_STATUS_IF_FALSE(env,
1424
      (length == NAPI_AUTO_LENGTH) || length <= INT_MAX,
1425
      napi_invalid_arg);
1426
1427
11
  auto isolate = env->isolate;
1428
  auto str_maybe =
1429
      v8::String::NewFromOneByte(isolate,
1430
                                 reinterpret_cast<const uint8_t*>(str),
1431
                                 v8::NewStringType::kNormal,
1432
11
                                 length);
1433
11
  CHECK_MAYBE_EMPTY(env, str_maybe, napi_generic_failure);
1434
1435
22
  *result = v8impl::JsValueFromV8LocalValue(str_maybe.ToLocalChecked());
1436
11
  return napi_clear_last_error(env);
1437
}
1438
1439
720
napi_status napi_create_string_utf8(napi_env env,
1440
                                    const char* str,
1441
                                    size_t length,
1442
                                    napi_value* result) {
1443
720
  CHECK_ENV(env);
1444
720
  CHECK_ARG(env, result);
1445

720
  RETURN_STATUS_IF_FALSE(env,
1446
      (length == NAPI_AUTO_LENGTH) || length <= INT_MAX,
1447
      napi_invalid_arg);
1448
1449
719
  auto isolate = env->isolate;
1450
  auto str_maybe =
1451
      v8::String::NewFromUtf8(isolate,
1452
                              str,
1453
                              v8::NewStringType::kNormal,
1454
719
                              static_cast<int>(length));
1455
719
  CHECK_MAYBE_EMPTY(env, str_maybe, napi_generic_failure);
1456
1438
  *result = v8impl::JsValueFromV8LocalValue(str_maybe.ToLocalChecked());
1457
719
  return napi_clear_last_error(env);
1458
}
1459
1460
14
napi_status napi_create_string_utf16(napi_env env,
1461
                                     const char16_t* str,
1462
                                     size_t length,
1463
                                     napi_value* result) {
1464
14
  CHECK_ENV(env);
1465
14
  CHECK_ARG(env, result);
1466

14
  RETURN_STATUS_IF_FALSE(env,
1467
      (length == NAPI_AUTO_LENGTH) || length <= INT_MAX,
1468
      napi_invalid_arg);
1469
1470
13
  auto isolate = env->isolate;
1471
  auto str_maybe =
1472
      v8::String::NewFromTwoByte(isolate,
1473
                                 reinterpret_cast<const uint16_t*>(str),
1474
                                 v8::NewStringType::kNormal,
1475
13
                                 length);
1476
13
  CHECK_MAYBE_EMPTY(env, str_maybe, napi_generic_failure);
1477
1478
26
  *result = v8impl::JsValueFromV8LocalValue(str_maybe.ToLocalChecked());
1479
13
  return napi_clear_last_error(env);
1480
}
1481
1482
71
napi_status napi_create_double(napi_env env,
1483
                               double value,
1484
                               napi_value* result) {
1485
71
  CHECK_ENV(env);
1486
71
  CHECK_ARG(env, result);
1487
1488
213
  *result = v8impl::JsValueFromV8LocalValue(
1489
71
      v8::Number::New(env->isolate, value));
1490
1491
71
  return napi_clear_last_error(env);
1492
}
1493
1494
162
napi_status napi_create_int32(napi_env env,
1495
                              int32_t value,
1496
                              napi_value* result) {
1497
162
  CHECK_ENV(env);
1498
162
  CHECK_ARG(env, result);
1499
1500
486
  *result = v8impl::JsValueFromV8LocalValue(
1501
162
      v8::Integer::New(env->isolate, value));
1502
1503
162
  return napi_clear_last_error(env);
1504
}
1505
1506
555
napi_status napi_create_uint32(napi_env env,
1507
                               uint32_t value,
1508
                               napi_value* result) {
1509
555
  CHECK_ENV(env);
1510
555
  CHECK_ARG(env, result);
1511
1512
1665
  *result = v8impl::JsValueFromV8LocalValue(
1513
555
      v8::Integer::NewFromUnsigned(env->isolate, value));
1514
1515
555
  return napi_clear_last_error(env);
1516
}
1517
1518
24
napi_status napi_create_int64(napi_env env,
1519
                              int64_t value,
1520
                              napi_value* result) {
1521
24
  CHECK_ENV(env);
1522
24
  CHECK_ARG(env, result);
1523
1524
72
  *result = v8impl::JsValueFromV8LocalValue(
1525
24
      v8::Number::New(env->isolate, static_cast<double>(value)));
1526
1527
24
  return napi_clear_last_error(env);
1528
}
1529
1530
9
napi_status napi_create_bigint_int64(napi_env env,
1531
                                     int64_t value,
1532
                                     napi_value* result) {
1533
9
  CHECK_ENV(env);
1534
9
  CHECK_ARG(env, result);
1535
1536
27
  *result = v8impl::JsValueFromV8LocalValue(
1537
9
      v8::BigInt::New(env->isolate, value));
1538
1539
9
  return napi_clear_last_error(env);
1540
}
1541
1542
6
napi_status napi_create_bigint_uint64(napi_env env,
1543
                                      uint64_t value,
1544
                                      napi_value* result) {
1545
6
  CHECK_ENV(env);
1546
6
  CHECK_ARG(env, result);
1547
1548
18
  *result = v8impl::JsValueFromV8LocalValue(
1549
6
      v8::BigInt::NewFromUnsigned(env->isolate, value));
1550
1551
6
  return napi_clear_last_error(env);
1552
}
1553
1554
13
napi_status napi_create_bigint_words(napi_env env,
1555
                                     int sign_bit,
1556
                                     size_t word_count,
1557
                                     const uint64_t* words,
1558
                                     napi_value* result) {
1559


39
  NAPI_PREAMBLE(env);
1560
13
  CHECK_ARG(env, words);
1561
13
  CHECK_ARG(env, result);
1562
1563
13
  v8::Local<v8::Context> context = env->context();
1564
1565
13
  RETURN_STATUS_IF_FALSE(
1566
      env, word_count <= INT_MAX, napi_invalid_arg);
1567
1568
  v8::MaybeLocal<v8::BigInt> b = v8::BigInt::NewFromWords(
1569
12
      context, sign_bit, word_count, words);
1570
1571

12
  CHECK_MAYBE_EMPTY_WITH_PREAMBLE(env, b, napi_generic_failure);
1572
1573
22
  *result = v8impl::JsValueFromV8LocalValue(b.ToLocalChecked());
1574
11
  return GET_RETURN_STATUS(env);
1575
}
1576
1577
1292
napi_status napi_get_boolean(napi_env env, bool value, napi_value* result) {
1578
1292
  CHECK_ENV(env);
1579
1292
  CHECK_ARG(env, result);
1580
1581
1292
  v8::Isolate* isolate = env->isolate;
1582
1583
1292
  if (value) {
1584
1460
    *result = v8impl::JsValueFromV8LocalValue(v8::True(isolate));
1585
  } else {
1586
1124
    *result = v8impl::JsValueFromV8LocalValue(v8::False(isolate));
1587
  }
1588
1589
1292
  return napi_clear_last_error(env);
1590
}
1591
1592
13
napi_status napi_create_symbol(napi_env env,
1593
                               napi_value description,
1594
                               napi_value* result) {
1595
13
  CHECK_ENV(env);
1596
13
  CHECK_ARG(env, result);
1597
1598
13
  v8::Isolate* isolate = env->isolate;
1599
1600
13
  if (description == nullptr) {
1601
6
    *result = v8impl::JsValueFromV8LocalValue(v8::Symbol::New(isolate));
1602
  } else {
1603
11
    v8::Local<v8::Value> desc = v8impl::V8LocalValueFromJsValue(description);
1604
22
    RETURN_STATUS_IF_FALSE(env, desc->IsString(), napi_string_expected);
1605
1606
33
    *result = v8impl::JsValueFromV8LocalValue(
1607
      v8::Symbol::New(isolate, desc.As<v8::String>()));
1608
  }
1609
1610
13
  return napi_clear_last_error(env);
1611
}
1612
1613
194
static inline napi_status set_error_code(napi_env env,
1614
                                         v8::Local<v8::Value> error,
1615
                                         napi_value code,
1616
                                         const char* code_cstring) {
1617

194
  if ((code != nullptr) || (code_cstring != nullptr)) {
1618
116
    v8::Local<v8::Context> context = env->context();
1619
116
    v8::Local<v8::Object> err_object = error.As<v8::Object>();
1620
1621
116
    v8::Local<v8::Value> code_value = v8impl::V8LocalValueFromJsValue(code);
1622
116
    if (code != nullptr) {
1623
5
      code_value = v8impl::V8LocalValueFromJsValue(code);
1624
10
      RETURN_STATUS_IF_FALSE(env, code_value->IsString(), napi_string_expected);
1625
    } else {
1626

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


1966
  NAPI_PREAMBLE(env);
1816
654
  CHECK_ARG(env, recv);
1817
654
  if (argc > 0) {
1818
602
    CHECK_ARG(env, argv);
1819
  }
1820
1821
654
  v8::Local<v8::Context> context = env->context();
1822
1823
654
  v8::Local<v8::Value> v8recv = v8impl::V8LocalValueFromJsValue(recv);
1824
1825
  v8::Local<v8::Function> v8func;
1826

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


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


229
  NAPI_PREAMBLE(env);
1867
1868
73
  v8::Isolate* isolate = env->isolate;
1869
  v8::Local<v8::String> str;
1870

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


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

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


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

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

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


52
  NAPI_PREAMBLE(env);
2237
17
  CHECK_ARG(env, value);
2238
16
  CHECK_ARG(env, result);
2239
2240
15
  v8::Isolate* isolate = env->isolate;
2241
  v8::Local<v8::Boolean> b =
2242
30
    v8impl::V8LocalValueFromJsValue(value)->ToBoolean(isolate);
2243
30
  *result = v8impl::JsValueFromV8LocalValue(b);
2244
15
  return GET_RETURN_STATUS(env);
2245
}
2246
2247
#define GEN_COERCE_FUNCTION(UpperCaseName, MixedCaseName, LowerCaseName)      \
2248
  napi_status napi_coerce_to_##LowerCaseName(napi_env env,                    \
2249
                                             napi_value value,                \
2250
                                             napi_value* result) {            \
2251
    NAPI_PREAMBLE(env);                                                       \
2252
    CHECK_ARG(env, value);                                                    \
2253
    CHECK_ARG(env, result);                                                   \
2254
                                                                              \
2255
    v8::Local<v8::Context> context = env->context();                          \
2256
    v8::Local<v8::MixedCaseName> str;                                         \
2257
                                                                              \
2258
    CHECK_TO_##UpperCaseName(env, context, str, value);                       \
2259
                                                                              \
2260
    *result = v8impl::JsValueFromV8LocalValue(str);                           \
2261
    return GET_RETURN_STATUS(env);                                            \
2262
  }
2263
2264
15
GEN_COERCE_FUNCTION(NUMBER, Number, number)
2265


49
GEN_COERCE_FUNCTION(OBJECT, Object, object)
2266


69
GEN_COERCE_FUNCTION(STRING, String, string)
2267


67
2268

35
#undef GEN_COERCE_FUNCTION
2269

48
2270

1092
napi_status napi_wrap(napi_env env,
2271

63
                      napi_value js_object,
2272

59
                      void* native_object,
2273
47
                      napi_finalize finalize_cb,
2274
44
                      void* finalize_hint,
2275
14
                      napi_ref* result) {
2276
  return v8impl::Wrap<v8impl::retrievable>(env,
2277
                                           js_object,
2278
                                           native_object,
2279
                                           finalize_cb,
2280
                                           finalize_hint,
2281
1028
                                           result);
2282
}
2283
2284
27
napi_status napi_unwrap(napi_env env, napi_value obj, void** result) {
2285
27
  return v8impl::Unwrap(env, obj, result, v8impl::KeepWrap);
2286
}
2287
2288
8
napi_status napi_remove_wrap(napi_env env, napi_value obj, void** result) {
2289
8
  return v8impl::Unwrap(env, obj, result, v8impl::RemoveWrap);
2290
}
2291
2292
7
napi_status napi_create_external(napi_env env,
2293
                                 void* data,
2294
                                 napi_finalize finalize_cb,
2295
                                 void* finalize_hint,
2296
                                 napi_value* result) {
2297


21
  NAPI_PREAMBLE(env);
2298
7
  CHECK_ARG(env, result);
2299
2300
7
  v8::Isolate* isolate = env->isolate;
2301
2302
7
  v8::Local<v8::Value> external_value = v8::External::New(isolate, data);
2303
2304
  // The Reference object will delete itself after invoking the finalizer
2305
  // callback.
2306
  v8impl::Reference::New(env,
2307
      external_value,
2308
      0,
2309
      true,
2310
      finalize_cb,
2311
      data,
2312
7
      finalize_hint);
2313
2314
7
  *result = v8impl::JsValueFromV8LocalValue(external_value);
2315
2316
7
  return napi_clear_last_error(env);
2317
}
2318
2319
2
NAPI_EXTERN napi_status napi_type_tag_object(napi_env env,
2320
                                             napi_value object,
2321
                                             const napi_type_tag* type_tag) {
2322


6
  NAPI_PREAMBLE(env);
2323
2
  v8::Local<v8::Context> context = env->context();
2324
  v8::Local<v8::Object> obj;
2325


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

2
  CHECK_ARG_WITH_PREAMBLE(env, type_tag);
2327
2328
2
  auto key = NAPI_PRIVATE_KEY(context, type_tag);
2329
2
  auto maybe_has = obj->HasPrivate(context, key);
2330

2
  CHECK_MAYBE_NOTHING_WITH_PREAMBLE(env, maybe_has, napi_generic_failure);
2331

2
  RETURN_STATUS_IF_FALSE_WITH_PREAMBLE(env,
2332
                                       !maybe_has.FromJust(),
2333
                                       napi_invalid_arg);
2334
2335
  auto tag = v8::BigInt::NewFromWords(context,
2336
                                   0,
2337
                                   2,
2338
2
                                   reinterpret_cast<const uint64_t*>(type_tag));
2339

2
  CHECK_MAYBE_EMPTY_WITH_PREAMBLE(env, tag, napi_generic_failure);
2340
2341
2
  auto maybe_set = obj->SetPrivate(context, key, tag.ToLocalChecked());
2342

2
  CHECK_MAYBE_NOTHING_WITH_PREAMBLE(env, maybe_set, napi_generic_failure);
2343

2
  RETURN_STATUS_IF_FALSE_WITH_PREAMBLE(env,
2344
                                       maybe_set.FromJust(),
2345
                                       napi_generic_failure);
2346
2347
2
  return GET_RETURN_STATUS(env);
2348
}
2349
2350
NAPI_EXTERN napi_status
2351
6
napi_check_object_type_tag(napi_env env,
2352
                           napi_value object,
2353
                           const napi_type_tag* type_tag,
2354
                           bool* result) {
2355


18
  NAPI_PREAMBLE(env);
2356
6
  v8::Local<v8::Context> context = env->context();
2357
  v8::Local<v8::Object> obj;
2358


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

6
  CHECK_ARG_WITH_PREAMBLE(env, type_tag);
2360

6
  CHECK_ARG_WITH_PREAMBLE(env, result);
2361
2362
  auto maybe_value = obj->GetPrivate(context,
2363
12
                                     NAPI_PRIVATE_KEY(context, type_tag));
2364

6
  CHECK_MAYBE_EMPTY_WITH_PREAMBLE(env, maybe_value, napi_generic_failure);
2365
6
  v8::Local<v8::Value> val = maybe_value.ToLocalChecked();
2366
2367
  // We consider the type check to have failed unless we reach the line below
2368
  // where we set whether the type check succeeded or not based on the
2369
  // comparison of the two type tags.
2370
6
  *result = false;
2371
6
  if (val->IsBigInt()) {
2372
    int sign;
2373
4
    int size = 2;
2374
    napi_type_tag tag;
2375
12
    val.As<v8::BigInt>()->ToWordsArray(&sign,
2376
                                       &size,
2377
4
                                       reinterpret_cast<uint64_t*>(&tag));
2378

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

4
      *result = (tag.lower == type_tag->lower && tag.upper == type_tag->upper);
2380
  }
2381
2382
6
  return GET_RETURN_STATUS(env);
2383
}
2384
2385
2
napi_status napi_get_value_external(napi_env env,
2386
                                    napi_value value,
2387
                                    void** result) {
2388
2
  CHECK_ENV(env);
2389
2
  CHECK_ARG(env, value);
2390
2
  CHECK_ARG(env, result);
2391
2392
2
  v8::Local<v8::Value> val = v8impl::V8LocalValueFromJsValue(value);
2393
2
  RETURN_STATUS_IF_FALSE(env, val->IsExternal(), napi_invalid_arg);
2394
2395
2
  v8::Local<v8::External> external_value = val.As<v8::External>();
2396
4
  *result = external_value->Value();
2397
2398
2
  return napi_clear_last_error(env);
2399
}
2400
2401
// Set initial_refcount to 0 for a weak reference, >0 for a strong reference.
2402
1539
napi_status napi_create_reference(napi_env env,
2403
                                  napi_value value,
2404
                                  uint32_t initial_refcount,
2405
                                  napi_ref* result) {
2406
  // Omit NAPI_PREAMBLE and GET_RETURN_STATUS because V8 calls here cannot throw
2407
  // JS exceptions.
2408
1539
  CHECK_ENV(env);
2409
1539
  CHECK_ARG(env, value);
2410
1539
  CHECK_ARG(env, result);
2411
2412
1539
  v8::Local<v8::Value> v8_value = v8impl::V8LocalValueFromJsValue(value);
2413
2414

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


21
  NAPI_PREAMBLE(env);
2585
7
  CHECK_ARG(env, constructor);
2586
7
  if (argc > 0) {
2587
7
    CHECK_ARG(env, argv);
2588
  }
2589
7
  CHECK_ARG(env, result);
2590
2591
7
  v8::Local<v8::Context> context = env->context();
2592
2593
  v8::Local<v8::Function> ctor;
2594

21
  CHECK_TO_FUNCTION(env, ctor, constructor);
2595
2596
  auto maybe = ctor->NewInstance(context, argc,
2597
14
    reinterpret_cast<v8::Local<v8::Value>*>(const_cast<napi_value*>(argv)));
2598
2599
7
  CHECK_MAYBE_EMPTY(env, maybe, napi_generic_failure);
2600
2601
14
  *result = v8impl::JsValueFromV8LocalValue(maybe.ToLocalChecked());
2602
7
  return GET_RETURN_STATUS(env);
2603
}
2604
2605
2278
napi_status napi_instanceof(napi_env env,
2606
                            napi_value object,
2607
                            napi_value constructor,
2608
                            bool* result) {
2609


6834
  NAPI_PREAMBLE(env);
2610
2278
  CHECK_ARG(env, object);
2611
2278
  CHECK_ARG(env, result);
2612
2613
2278
  *result = false;
2614
2615
  v8::Local<v8::Object> ctor;
2616
2278
  v8::Local<v8::Context> context = env->context();
2617
2618

9112
  CHECK_TO_OBJECT(env, context, ctor, constructor);
2619
2620
2278
  if (!ctor->IsFunction()) {
2621
    napi_throw_type_error(env,
2622
                          "ERR_NAPI_CONS_FUNCTION",
2623
88
                          "Constructor must be a function");
2624
2625
88
    return napi_set_last_error(env, napi_function_expected);
2626
  }
2627
2628
2190
  napi_status status = napi_generic_failure;
2629
2630
2190
  v8::Local<v8::Value> val = v8impl::V8LocalValueFromJsValue(object);
2631
2190
  auto maybe_result = val->InstanceOf(context, ctor);
2632
2190
  CHECK_MAYBE_NOTHING(env, maybe_result, status);
2633
2332
  *result = maybe_result.FromJust();
2634
1166
  return GET_RETURN_STATUS(env);
2635
}
2636
2637
// Methods to support catching exceptions
2638
1228
napi_status napi_is_exception_pending(napi_env env, bool* result) {
2639
  // NAPI_PREAMBLE is not used here: this function must execute when there is a
2640
  // pending exception.
2641
1228
  CHECK_ENV(env);
2642
1228
  CHECK_ARG(env, result);
2643
2644
2456
  *result = !env->last_exception.IsEmpty();
2645
1228
  return napi_clear_last_error(env);
2646
}
2647
2648
1
napi_status napi_get_and_clear_last_exception(napi_env env,
2649
                                              napi_value* result) {
2650
  // NAPI_PREAMBLE is not used here: this function must execute when there is a
2651
  // pending exception.
2652
1
  CHECK_ENV(env);
2653
1
  CHECK_ARG(env, result);
2654
2655
2
  if (env->last_exception.IsEmpty()) {
2656
    return napi_get_undefined(env, result);
2657
  } else {
2658
2
    *result = v8impl::JsValueFromV8LocalValue(
2659
1
      v8::Local<v8::Value>::New(env->isolate, env->last_exception));
2660
1
    env->last_exception.Reset();
2661
  }
2662
2663
1
  return napi_clear_last_error(env);
2664
}
2665
2666
57
napi_status napi_is_arraybuffer(napi_env env, napi_value value, bool* result) {
2667
57
  CHECK_ENV(env);
2668
57
  CHECK_ARG(env, value);
2669
57
  CHECK_ARG(env, result);
2670
2671
57
  v8::Local<v8::Value> val = v8impl::V8LocalValueFromJsValue(value);
2672
114
  *result = val->IsArrayBuffer();
2673
2674
57
  return napi_clear_last_error(env);
2675
}
2676
2677
2
napi_status napi_create_arraybuffer(napi_env env,
2678
                                    size_t byte_length,
2679
                                    void** data,
2680
                                    napi_value* result) {
2681


6
  NAPI_PREAMBLE(env);
2682
2
  CHECK_ARG(env, result);
2683
2684
2
  v8::Isolate* isolate = env->isolate;
2685
  v8::Local<v8::ArrayBuffer> buffer =
2686
2
      v8::ArrayBuffer::New(isolate, byte_length);
2687
2688
  // Optionally return a pointer to the buffer's data, to avoid another call to
2689
  // retrieve it.
2690
2
  if (data != nullptr) {
2691
2
    *data = buffer->GetBackingStore()->Data();
2692
  }
2693
2694
4
  *result = v8impl::JsValueFromV8LocalValue(buffer);
2695
2
  return GET_RETURN_STATUS(env);
2696
}
2697
2698
6
napi_status napi_create_external_arraybuffer(napi_env env,
2699
                                             void* external_data,
2700
                                             size_t byte_length,
2701
                                             napi_finalize finalize_cb,
2702
                                             void* finalize_hint,
2703
                                             napi_value* result) {
2704
  // The API contract here is that the cleanup function runs on the JS thread,
2705
  // and is able to use napi_env. Implementing that properly is hard, so use the
2706
  // `Buffer` variant for easier implementation.
2707
  napi_value buffer;
2708
6
  STATUS_CALL(napi_create_external_buffer(
2709
      env,
2710
      byte_length,
2711
      external_data,
2712
      finalize_cb,
2713
      finalize_hint,
2714
      &buffer));
2715
6
  return napi_get_typedarray_info(
2716
      env,
2717
      buffer,
2718
      nullptr,
2719
      nullptr,
2720
      nullptr,
2721
      result,
2722
6
      nullptr);
2723
}
2724
2725
2
napi_status napi_get_arraybuffer_info(napi_env env,
2726
                                      napi_value arraybuffer,
2727
                                      void** data,
2728
                                      size_t* byte_length) {
2729
2
  CHECK_ENV(env);
2730
2
  CHECK_ARG(env, arraybuffer);
2731
2732
2
  v8::Local<v8::Value> value = v8impl::V8LocalValueFromJsValue(arraybuffer);
2733
2
  RETURN_STATUS_IF_FALSE(env, value->IsArrayBuffer(), napi_invalid_arg);
2734
2735
  std::shared_ptr<v8::BackingStore> backing_store =
2736
6
      value.As<v8::ArrayBuffer>()->GetBackingStore();
2737
2738
2
  if (data != nullptr) {
2739
2
    *data = backing_store->Data();
2740
  }
2741
2742
2
  if (byte_length != nullptr) {
2743
2
    *byte_length = backing_store->ByteLength();
2744
  }
2745
2746
2
  return napi_clear_last_error(env);
2747
}
2748
2749
44
napi_status napi_is_typedarray(napi_env env, napi_value value, bool* result) {
2750
44
  CHECK_ENV(env);
2751
44
  CHECK_ARG(env, value);
2752
44
  CHECK_ARG(env, result);
2753
2754
44
  v8::Local<v8::Value> val = v8impl::V8LocalValueFromJsValue(value);
2755
88
  *result = val->IsTypedArray();
2756
2757
44
  return napi_clear_last_error(env);
2758
}
2759
2760
34
napi_status napi_create_typedarray(napi_env env,
2761
                                   napi_typedarray_type type,
2762
                                   size_t length,
2763
                                   napi_value arraybuffer,
2764
                                   size_t byte_offset,
2765
                                   napi_value* result) {
2766


102
  NAPI_PREAMBLE(env);
2767
34
  CHECK_ARG(env, arraybuffer);
2768
34
  CHECK_ARG(env, result);
2769
2770
34
  v8::Local<v8::Value> value = v8impl::V8LocalValueFromJsValue(arraybuffer);
2771
34
  RETURN_STATUS_IF_FALSE(env, value->IsArrayBuffer(), napi_invalid_arg);
2772
2773
34
  v8::Local<v8::ArrayBuffer> buffer = value.As<v8::ArrayBuffer>();
2774
  v8::Local<v8::TypedArray> typedArray;
2775
2776



34
  switch (type) {
2777
    case napi_int8_array:
2778
8
      CREATE_TYPED_ARRAY(
2779
          env, Int8Array, 1, buffer, byte_offset, length, typedArray);
2780
3
      break;
2781
    case napi_uint8_array:
2782
4
      CREATE_TYPED_ARRAY(
2783
          env, Uint8Array, 1, buffer, byte_offset, length, typedArray);
2784
8
      break;
2785
1
    case napi_uint8_clamped_array:
2786
3
      CREATE_TYPED_ARRAY(
2787
          env, Uint8ClampedArray, 1, buffer, byte_offset, length, typedArray);
2788
5
      break;
2789
1
    case napi_int16_array:
2790
5
      CREATE_TYPED_ARRAY(
2791
1
          env, Int16Array, 2, buffer, byte_offset, length, typedArray);
2792
4
      break;
2793
1
    case napi_uint16_array:
2794
5
      CREATE_TYPED_ARRAY(
2795
1
          env, Uint16Array, 2, buffer, byte_offset, length, typedArray);
2796
4
      break;
2797
1
    case napi_int32_array:
2798
5
      CREATE_TYPED_ARRAY(
2799
1
          env, Int32Array, 4, buffer, byte_offset, length, typedArray);
2800
4
      break;
2801
1
    case napi_uint32_array:
2802
5
      CREATE_TYPED_ARRAY(
2803
1
          env, Uint32Array, 4, buffer, byte_offset, length, typedArray);
2804
4
      break;
2805
1
    case napi_float32_array:
2806
5
      CREATE_TYPED_ARRAY(
2807
1
          env, Float32Array, 4, buffer, byte_offset, length, typedArray);
2808
4
      break;
2809
1
    case napi_float64_array:
2810
6
      CREATE_TYPED_ARRAY(
2811
1
          env, Float64Array, 8, buffer, byte_offset, length, typedArray);
2812
6
      break;
2813
1
    case napi_bigint64_array:
2814
6
      CREATE_TYPED_ARRAY(
2815
1
          env, BigInt64Array, 8, buffer, byte_offset, length, typedArray);
2816
4
      break;
2817
1
    case napi_biguint64_array:
2818
5
      CREATE_TYPED_ARRAY(
2819
1
          env, BigUint64Array, 8, buffer, byte_offset, length, typedArray);
2820
4
      break;
2821
1
    default:
2822
2
      return napi_set_last_error(env, napi_invalid_arg);
2823
  }
2824
2825
30
  *result = v8impl::JsValueFromV8LocalValue(typedArray);
2826
15
  return GET_RETURN_STATUS(env);
2827
}
2828
2829
50
napi_status napi_get_typedarray_info(napi_env env,
2830
                                     napi_value typedarray,
2831
                                     napi_typedarray_type* type,
2832
                                     size_t* length,
2833
                                     void** data,
2834
                                     napi_value* arraybuffer,
2835
                                     size_t* byte_offset) {
2836
50
  CHECK_ENV(env);
2837
50
  CHECK_ARG(env, typedarray);
2838
2839
50
  v8::Local<v8::Value> value = v8impl::V8LocalValueFromJsValue(typedarray);
2840
50
  RETURN_STATUS_IF_FALSE(env, value->IsTypedArray(), napi_invalid_arg);
2841
2842
50
  v8::Local<v8::TypedArray> array = value.As<v8::TypedArray>();
2843
2844
50
  if (type != nullptr) {
2845
32
    if (value->IsInt8Array()) {
2846
2
      *type = napi_int8_array;
2847
30
    } else if (value->IsUint8Array()) {
2848
3
      *type = napi_uint8_array;
2849
27
    } else if (value->IsUint8ClampedArray()) {
2850
2
      *type = napi_uint8_clamped_array;
2851
25
    } else if (value->IsInt16Array()) {
2852
3
      *type = napi_int16_array;
2853
22
    } else if (value->IsUint16Array()) {
2854
3
      *type = napi_uint16_array;
2855
19
    } else if (value->IsInt32Array()) {
2856
3
      *type = napi_int32_array;
2857
16
    } else if (value->IsUint32Array()) {
2858
3
      *type = napi_uint32_array;
2859
13
    } else if (value->IsFloat32Array()) {
2860
3
      *type = napi_float32_array;
2861
10
    } else if (value->IsFloat64Array()) {
2862
4
      *type = napi_float64_array;
2863
6
    } else if (value->IsBigInt64Array()) {
2864
3
      *type = napi_bigint64_array;
2865
3
    } else if (value->IsBigUint64Array()) {
2866
3
      *type = napi_biguint64_array;
2867
    }
2868
  }
2869
2870
50
  if (length != nullptr) {
2871
32
    *length = array->Length();
2872
  }
2873
2874
  v8::Local<v8::ArrayBuffer> buffer;
2875

50
  if (data != nullptr || arraybuffer != nullptr) {
2876
    // Calling Buffer() may have the side effect of allocating the buffer,
2877
    // so only do this when it’s needed.
2878
50
    buffer = array->Buffer();
2879
  }
2880
2881
50
  if (data != nullptr) {
2882
    *data = static_cast<uint8_t*>(buffer->GetBackingStore()->Data()) +
2883
            array->ByteOffset();
2884
  }
2885
2886
50
  if (arraybuffer != nullptr) {
2887
50
    *arraybuffer = v8impl::JsValueFromV8LocalValue(buffer);
2888
  }
2889
2890
50
  if (byte_offset != nullptr) {
2891
32
    *byte_offset = array->ByteOffset();
2892
  }
2893
2894
50
  return napi_clear_last_error(env);
2895
}
2896
2897
2
napi_status napi_create_dataview(napi_env env,
2898
                                 size_t byte_length,
2899
                                 napi_value arraybuffer,
2900
                                 size_t byte_offset,
2901
                                 napi_value* result) {
2902


6
  NAPI_PREAMBLE(env);
2903
2
  CHECK_ARG(env, arraybuffer);
2904
2
  CHECK_ARG(env, result);
2905
2906
2
  v8::Local<v8::Value> value = v8impl::V8LocalValueFromJsValue(arraybuffer);
2907
2
  RETURN_STATUS_IF_FALSE(env, value->IsArrayBuffer(), napi_invalid_arg);
2908
2909
2
  v8::Local<v8::ArrayBuffer> buffer = value.As<v8::ArrayBuffer>();
2910
4
  if (byte_length + byte_offset > buffer->ByteLength()) {
2911
    napi_throw_range_error(
2912
        env,
2913
        "ERR_NAPI_INVALID_DATAVIEW_ARGS",
2914
        "byte_offset + byte_length should be less than or "
2915
1
        "equal to the size in bytes of the array passed in");
2916
1
    return napi_set_last_error(env, napi_pending_exception);
2917
  }
2918
  v8::Local<v8::DataView> DataView = v8::DataView::New(buffer, byte_offset,
2919
1
                                                       byte_length);
2920
2921
2
  *result = v8impl::JsValueFromV8LocalValue(DataView);
2922
1
  return GET_RETURN_STATUS(env);
2923
}
2924
2925
1
napi_status napi_is_dataview(napi_env env, napi_value value, bool* result) {
2926
1
  CHECK_ENV(env);
2927
1
  CHECK_ARG(env, value);
2928
1
  CHECK_ARG(env, result);
2929
2930
1
  v8::Local<v8::Value> val = v8impl::V8LocalValueFromJsValue(value);
2931
2
  *result = val->IsDataView();
2932
2933
1
  return napi_clear_last_error(env);
2934
}
2935
2936
1
napi_status napi_get_dataview_info(napi_env env,
2937
                                   napi_value dataview,
2938
                                   size_t* byte_length,
2939
                                   void** data,
2940
                                   napi_value* arraybuffer,
2941
                                   size_t* byte_offset) {
2942
1
  CHECK_ENV(env);
2943
1
  CHECK_ARG(env, dataview);
2944
2945
1
  v8::Local<v8::Value> value = v8impl::V8LocalValueFromJsValue(dataview);
2946
1
  RETURN_STATUS_IF_FALSE(env, value->IsDataView(), napi_invalid_arg);
2947
2948
1
  v8::Local<v8::DataView> array = value.As<v8::DataView>();
2949
2950
1
  if (byte_length != nullptr) {
2951
1
    *byte_length = array->ByteLength();
2952
  }
2953
2954
  v8::Local<v8::ArrayBuffer> buffer;
2955

1
  if (data != nullptr || arraybuffer != nullptr) {
2956
    // Calling Buffer() may have the side effect of allocating the buffer,
2957
    // so only do this when it’s needed.
2958
1
    buffer = array->Buffer();
2959
  }
2960
2961
1
  if (data != nullptr) {
2962
    *data = static_cast<uint8_t*>(buffer->GetBackingStore()->Data()) +
2963
            array->ByteOffset();
2964
  }
2965
2966
1
  if (arraybuffer != nullptr) {
2967
1
    *arraybuffer = v8impl::JsValueFromV8LocalValue(buffer);
2968
  }
2969
2970
1
  if (byte_offset != nullptr) {
2971
1
    *byte_offset = array->ByteOffset();
2972
  }
2973
2974
1
  return napi_clear_last_error(env);
2975
}
2976
2977
1
napi_status napi_get_version(napi_env env, uint32_t* result) {
2978
1
  CHECK_ENV(env);
2979
1
  CHECK_ARG(env, result);
2980
1
  *result = NAPI_VERSION;
2981
1
  return napi_clear_last_error(env);
2982
}
2983
2984
5
napi_status napi_create_promise(napi_env env,
2985
                                napi_deferred* deferred,
2986
                                napi_value* promise) {
2987


15
  NAPI_PREAMBLE(env);
2988
5
  CHECK_ARG(env, deferred);
2989
5
  CHECK_ARG(env, promise);
2990
2991
5
  auto maybe = v8::Promise::Resolver::New(env->context());
2992
5
  CHECK_MAYBE_EMPTY(env, maybe, napi_generic_failure);
2993
2994
5
  auto v8_resolver = maybe.ToLocalChecked();
2995
10
  auto v8_deferred = new v8impl::Persistent<v8::Value>();
2996
5
  v8_deferred->Reset(env->isolate, v8_resolver);
2997
2998
5
  *deferred = v8impl::JsDeferredFromNodePersistent(v8_deferred);
2999
15
  *promise = v8impl::JsValueFromV8LocalValue(v8_resolver->GetPromise());
3000
5
  return GET_RETURN_STATUS(env);
3001
}
3002
3003
4
napi_status napi_resolve_deferred(napi_env env,
3004
                                  napi_deferred deferred,
3005
                                  napi_value resolution) {
3006
4
  return v8impl::ConcludeDeferred(env, deferred, resolution, true);
3007
}
3008
3009
1
napi_status napi_reject_deferred(napi_env env,
3010
                                 napi_deferred deferred,
3011
                                 napi_value resolution) {
3012
1
  return v8impl::ConcludeDeferred(env, deferred, resolution, false);
3013
}
3014
3015
7
napi_status napi_is_promise(napi_env env,
3016
                            napi_value value,
3017
                            bool* is_promise) {
3018
7
  CHECK_ENV(env);
3019
7
  CHECK_ARG(env, value);
3020
7
  CHECK_ARG(env, is_promise);
3021
3022
14
  *is_promise = v8impl::V8LocalValueFromJsValue(value)->IsPromise();
3023
3024
7
  return napi_clear_last_error(env);
3025
}
3026
3027
1
napi_status napi_create_date(napi_env env,
3028
                             double time,
3029
                             napi_value* result) {
3030


3
  NAPI_PREAMBLE(env);
3031
1
  CHECK_ARG(env, result);
3032
3033
1
  v8::MaybeLocal<v8::Value> maybe_date = v8::Date::New(env->context(), time);
3034
1
  CHECK_MAYBE_EMPTY(env, maybe_date, napi_generic_failure);
3035
3036
2
  *result = v8impl::JsValueFromV8LocalValue(maybe_date.ToLocalChecked());
3037
3038
1
  return GET_RETURN_STATUS(env);
3039
}
3040
3041
7
napi_status napi_is_date(napi_env env,
3042
                         napi_value value,
3043
                         bool* is_date) {
3044
7
  CHECK_ENV(env);
3045
7
  CHECK_ARG(env, value);
3046
7
  CHECK_ARG(env, is_date);
3047
3048
14
  *is_date = v8impl::V8LocalValueFromJsValue(value)->IsDate();
3049
3050
7
  return napi_clear_last_error(env);
3051
}
3052
3053
1
napi_status napi_get_date_value(napi_env env,
3054
                                napi_value value,
3055
                                double* result) {
3056


3
  NAPI_PREAMBLE(env);
3057
1
  CHECK_ARG(env, value);
3058
1
  CHECK_ARG(env, result);
3059
3060
1
  v8::Local<v8::Value> val = v8impl::V8LocalValueFromJsValue(value);
3061
1
  RETURN_STATUS_IF_FALSE(env, val->IsDate(), napi_date_expected);
3062
3063
1
  v8::Local<v8::Date> date = val.As<v8::Date>();
3064
2
  *result = date->ValueOf();
3065
3066
1
  return GET_RETURN_STATUS(env);
3067
}
3068
3069
2
napi_status napi_run_script(napi_env env,
3070
                            napi_value script,
3071
                            napi_value* result) {
3072


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

104
  *result = value->IsArrayBuffer() &&
3184
104
            value.As<v8::ArrayBuffer>()->GetBackingStore()->Data() == nullptr;
3185
3186
26
  return napi_clear_last_error(env);
3187

14310
}