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: 1357 1393 97.4 %
Date: 2020-08-22 22:13:06 Branches: 1033 1646 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
431
V8NameFromPropertyDescriptor(napi_env env,
65
                             const napi_property_descriptor* p,
66
                             v8::Local<v8::Name>* result) {
67
431
  if (p->utf8name != nullptr) {
68

1287
    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
431
  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->isolate->GetCurrentContext();
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
3008
class RefBase : protected Finalizer, RefTracker {
193
 protected:
194
3010
  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
3010
       : Finalizer(env, finalize_callback, finalize_data, finalize_hint),
201
        _refcount(initial_refcount),
202
3010
        _delete_self(delete_self) {
203
3010
    Link(finalize_callback == nullptr
204
        ? &env->reflist
205
3010
        : &env->finalizing_reflist);
206
3010
  }
207
208
 public:
209
6
  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
6
                       finalize_hint);
221
  }
222
223
53
  inline void* Data() {
224
53
    return _finalize_data;
225
  }
226
227
  // Delete is called in 2 ways. Either from the finalizer or
228
  // from one of Unwrap or napi_delete_reference.
229
  //
230
  // When it is called from Unwrap or napi_delete_reference we only
231
  // want to do the delete if there is no finalizer or the finalizer has already
232
  // run or cannot have been queued to run (i.e. the reference count is > 0),
233
  // otherwise we may crash when the finalizer does run.
234
  //
235
  // If the finalizer may have been queued and has not already run
236
  // delay the delete until the finalizer runs by not doing the delete
237
  // and setting _delete_self to true so that the finalizer will
238
  // delete it when it runs.
239
  //
240
  // The second way this is called is from
241
  // the finalizer and _delete_self is set. In this case we
242
  // know we need to do the deletion so just do it.
243
3006
  static inline void Delete(RefBase* reference) {
244
3006
    reference->Unlink();
245

8483
    if ((reference->RefCount() != 0) ||
246
3935
        (reference->_finalize_callback == nullptr) ||
247

4478
        (reference->_delete_self) ||
248
8
        (reference->_finalize_ran)) {
249
3002
      delete reference;
250
    } else {
251
      // defer until finalizer runs as
252
      // it may alread be queued
253
4
      reference->_delete_self = true;
254
    }
255
3006
  }
256
257
1
  inline uint32_t Ref() {
258
1
    return ++_refcount;
259
  }
260
261
3
  inline uint32_t Unref() {
262
3
    if (_refcount == 0) {
263
        return 0;
264
    }
265
3
    return --_refcount;
266
  }
267
268
6016
  inline uint32_t RefCount() {
269
6016
    return _refcount;
270
  }
271
272
 protected:
273
2464
  inline void Finalize(bool is_env_teardown = false) override {
274
2464
    if (_finalize_callback != nullptr) {
275
1454
      _env->CallFinalizer(_finalize_callback, _finalize_data, _finalize_hint);
276
    }
277
278
    // this is safe because if a request to delete the reference
279
    // is made in the finalize_callback it will defer deletion
280
    // to this block and set _delete_self to true
281

2464
    if (_delete_self || is_env_teardown) {
282
1458
      Delete(this);
283
    } else {
284
1006
      _finalize_ran = true;
285
    }
286
2464
  }
287
288
 private:
289
  uint32_t _refcount;
290
  bool _delete_self;
291
};
292
293
8988
class Reference : public RefBase {
294
 protected:
295
  template <typename... Args>
296
3004
  Reference(napi_env env,
297
            v8::Local<v8::Value> value,
298
            Args&&... args)
299
15020
      : RefBase(env, std::forward<Args>(args)...),
300
15020
            _persistent(env->isolate, value) {
301
3004
    if (RefCount() == 0) {
302
2466
      _persistent.SetWeak(
303
          this, FinalizeCallback, v8::WeakCallbackType::kParameter);
304
    }
305
3004
  }
306
307
 public:
308
3004
  static inline Reference* New(napi_env env,
309
                             v8::Local<v8::Value> value,
310
                             uint32_t initial_refcount,
311
                             bool delete_self,
312
                             napi_finalize finalize_callback = nullptr,
313
                             void* finalize_data = nullptr,
314
                             void* finalize_hint = nullptr) {
315
    return new Reference(env,
316
                         value,
317
                         initial_refcount,
318
                         delete_self,
319
                         finalize_callback,
320
                         finalize_data,
321
3004
                         finalize_hint);
322
  }
323
324
1
  inline uint32_t Ref() {
325
1
    uint32_t refcount = RefBase::Ref();
326
1
    if (refcount == 1) {
327
      _persistent.ClearWeak();
328
    }
329
1
    return refcount;
330
  }
331
332
3
  inline uint32_t Unref() {
333
3
    uint32_t old_refcount = RefCount();
334
3
    uint32_t refcount = RefBase::Unref();
335

3
    if (old_refcount == 1 && refcount == 0) {
336
2
      _persistent.SetWeak(
337
          this, FinalizeCallback, v8::WeakCallbackType::kParameter);
338
    }
339
3
    return refcount;
340
  }
341
342
1550
  inline v8::Local<v8::Value> Get() {
343
3100
    if (_persistent.IsEmpty()) {
344
1002
      return v8::Local<v8::Value>();
345
    } else {
346
1096
      return v8::Local<v8::Value>::New(_env->isolate, _persistent);
347
    }
348
  }
349
350
 private:
351
  // The N-API finalizer callback may make calls into the engine. V8's heap is
352
  // not in a consistent state during the weak callback, and therefore it does
353
  // not support calls back into it. However, it provides a mechanism for adding
354
  // a finalizer which may make calls back into the engine by allowing us to
355
  // attach such a second-pass finalizer from the first pass finalizer. Thus,
356
  // we do that here to ensure that the N-API finalizer callback is free to call
357
  // into the engine.
358
2019
  static void FinalizeCallback(const v8::WeakCallbackInfo<Reference>& data) {
359
2019
    Reference* reference = data.GetParameter();
360
361
    // The reference must be reset during the first pass.
362
2019
    reference->_persistent.Reset();
363
364
2019
    data.SetSecondPassCallback(SecondPassCallback);
365
2019
  }
366
367
2019
  static void SecondPassCallback(const v8::WeakCallbackInfo<Reference>& data) {
368
2019
    data.GetParameter()->Finalize();
369
2019
  }
370
371
  v8impl::Persistent<v8::Value> _persistent;
372
};
373
374
enum UnwrapAction {
375
  KeepWrap,
376
  RemoveWrap
377
};
378
379
31
inline static napi_status Unwrap(napi_env env,
380
                                 napi_value js_object,
381
                                 void** result,
382
                                 UnwrapAction action) {
383


93
  NAPI_PREAMBLE(env);
384
31
  CHECK_ARG(env, js_object);
385
31
  if (action == KeepWrap) {
386
25
    CHECK_ARG(env, result);
387
  }
388
389
31
  v8::Isolate* isolate = env->isolate;
390
31
  v8::Local<v8::Context> context = isolate->GetCurrentContext();
391
392
31
  v8::Local<v8::Value> value = v8impl::V8LocalValueFromJsValue(js_object);
393
31
  RETURN_STATUS_IF_FALSE(env, value->IsObject(), napi_invalid_arg);
394
31
  v8::Local<v8::Object> obj = value.As<v8::Object>();
395
396
93
  auto val = obj->GetPrivate(context, NAPI_PRIVATE_KEY(context, wrapper))
397
31
      .ToLocalChecked();
398
31
  RETURN_STATUS_IF_FALSE(env, val->IsExternal(), napi_invalid_arg);
399
  Reference* reference =
400
62
      static_cast<v8impl::Reference*>(val.As<v8::External>()->Value());
401
402
31
  if (result) {
403
31
    *result = reference->Data();
404
  }
405
406
31
  if (action == RemoveWrap) {
407
18
    CHECK(obj->DeletePrivate(context, NAPI_PRIVATE_KEY(context, wrapper))
408
        .FromJust());
409
6
    Reference::Delete(reference);
410
  }
411
412
31
  return GET_RETURN_STATUS(env);
413
}
414
415
//=== Function napi_callback wrapper =================================
416
417
// Use this data structure to associate callback data with each N-API function
418
// exposed to JavaScript. The structure is stored in a v8::External which gets
419
// passed into our callback wrapper. This reduces the performance impact of
420
// calling through N-API.
421
// Ref: benchmark/misc/function_call
422
// Discussion (incl. perf. data): https://github.com/nodejs/node/pull/21072
423
struct CallbackBundle {
424
  napi_env       env;      // Necessary to invoke C++ NAPI callback
425
  void*          cb_data;  // The user provided callback data
426
  napi_callback  function_or_getter;
427
  napi_callback  setter;
428
};
429
430
// Base class extended by classes that wrap V8 function and property callback
431
// info.
432
class CallbackWrapper {
433
 public:
434
4623
  CallbackWrapper(napi_value this_arg, size_t args_length, void* data)
435
4623
      : _this(this_arg), _args_length(args_length), _data(data) {}
436
437
  virtual napi_value GetNewTarget() = 0;
438
  virtual void Args(napi_value* buffer, size_t bufferlength) = 0;
439
  virtual void SetReturnValue(napi_value value) = 0;
440
441
39
  napi_value This() { return _this; }
442
443
4466
  size_t ArgsLength() { return _args_length; }
444
445
6
  void* Data() { return _data; }
446
447
 protected:
448
  const napi_value _this;
449
  const size_t _args_length;
450
  void* _data;
451
};
452
453
template <typename Info, napi_callback CallbackBundle::*FunctionField>
454
class CallbackWrapperBase : public CallbackWrapper {
455
 public:
456
4623
  CallbackWrapperBase(const Info& cbinfo, const size_t args_length)
457
      : CallbackWrapper(JsValueFromV8LocalValue(cbinfo.This()),
458
                        args_length,
459
                        nullptr),
460
4623
        _cbinfo(cbinfo) {
461
4623
    _bundle = reinterpret_cast<CallbackBundle*>(
462
9246
        v8::Local<v8::External>::Cast(cbinfo.Data())->Value());
463
4623
    _data = _bundle->cb_data;
464
4623
  }
465
466
  napi_value GetNewTarget() override { return nullptr; }
467
468
 protected:
469
4623
  void InvokeCallback() {
470
    napi_callback_info cbinfo_wrapper = reinterpret_cast<napi_callback_info>(
471
4623
        static_cast<CallbackWrapper*>(this));
472
473
    // All other pointers we need are stored in `_bundle`
474
4623
    napi_env env = _bundle->env;
475
4623
    napi_callback cb = _bundle->*FunctionField;
476
477
    napi_value result;
478
9246
    env->CallIntoModule([&](napi_env env) {
479
4623
      result = cb(env, cbinfo_wrapper);
480
4623
    });
481
482
4623
    if (result != nullptr) {
483
2798
      this->SetReturnValue(result);
484
    }
485
4623
  }
486
487
  const Info& _cbinfo;
488
  CallbackBundle* _bundle;
489
};
490
491
class FunctionCallbackWrapper
492
    : public CallbackWrapperBase<v8::FunctionCallbackInfo<v8::Value>,
493
                                 &CallbackBundle::function_or_getter> {
494
 public:
495
4623
  static void Invoke(const v8::FunctionCallbackInfo<v8::Value>& info) {
496
4623
    FunctionCallbackWrapper cbwrapper(info);
497
4623
    cbwrapper.InvokeCallback();
498
4623
  }
499
500
4623
  explicit FunctionCallbackWrapper(
501
      const v8::FunctionCallbackInfo<v8::Value>& cbinfo)
502
9246
      : CallbackWrapperBase(cbinfo, cbinfo.Length()) {}
503
504
8
  napi_value GetNewTarget() override {
505
16
    if (_cbinfo.IsConstructCall()) {
506
14
      return v8impl::JsValueFromV8LocalValue(_cbinfo.NewTarget());
507
    } else {
508
1
      return nullptr;
509
    }
510
  }
511
512
  /*virtual*/
513
4454
  void Args(napi_value* buffer, size_t buffer_length) override {
514
4454
    size_t i = 0;
515
4454
    size_t min = std::min(buffer_length, _args_length);
516
517
18490
    for (; i < min; i += 1) {
518
14036
      buffer[i] = v8impl::JsValueFromV8LocalValue(_cbinfo[i]);
519
    }
520
521
4454
    if (i < buffer_length) {
522
      napi_value undefined =
523
63
          v8impl::JsValueFromV8LocalValue(v8::Undefined(_cbinfo.GetIsolate()));
524
157
      for (; i < buffer_length; i += 1) {
525
68
        buffer[i] = undefined;
526
      }
527
    }
528
4454
  }
529
530
  /*virtual*/
531
2798
  void SetReturnValue(napi_value value) override {
532
2798
    v8::Local<v8::Value> val = v8impl::V8LocalValueFromJsValue(value);
533
8394
    _cbinfo.GetReturnValue().Set(val);
534
2798
  }
535
};
536
537
class GetterCallbackWrapper
538
    : public CallbackWrapperBase<v8::PropertyCallbackInfo<v8::Value>,
539
                                 &CallbackBundle::function_or_getter> {
540
 public:
541
  static void Invoke(v8::Local<v8::Name> property,
542
                     const v8::PropertyCallbackInfo<v8::Value>& info) {
543
    GetterCallbackWrapper cbwrapper(info);
544
    cbwrapper.InvokeCallback();
545
  }
546
547
  explicit GetterCallbackWrapper(
548
      const v8::PropertyCallbackInfo<v8::Value>& cbinfo)
549
      : CallbackWrapperBase(cbinfo, 0) {}
550
551
  /*virtual*/
552
  void Args(napi_value* buffer, size_t buffer_length) override {
553
    if (buffer_length > 0) {
554
      napi_value undefined =
555
          v8impl::JsValueFromV8LocalValue(v8::Undefined(_cbinfo.GetIsolate()));
556
      for (size_t i = 0; i < buffer_length; i += 1) {
557
        buffer[i] = undefined;
558
      }
559
    }
560
  }
561
562
  /*virtual*/
563
  void SetReturnValue(napi_value value) override {
564
    v8::Local<v8::Value> val = v8impl::V8LocalValueFromJsValue(value);
565
    _cbinfo.GetReturnValue().Set(val);
566
  }
567
};
568
569
class SetterCallbackWrapper
570
    : public CallbackWrapperBase<v8::PropertyCallbackInfo<void>,
571
                                 &CallbackBundle::setter> {
572
 public:
573
  static void Invoke(v8::Local<v8::Name> property,
574
                     v8::Local<v8::Value> value,
575
                     const v8::PropertyCallbackInfo<void>& info) {
576
    SetterCallbackWrapper cbwrapper(info, value);
577
    cbwrapper.InvokeCallback();
578
  }
579
580
  SetterCallbackWrapper(const v8::PropertyCallbackInfo<void>& cbinfo,
581
                        const v8::Local<v8::Value>& value)
582
      : CallbackWrapperBase(cbinfo, 1), _value(value) {}
583
584
  /*virtual*/
585
  void Args(napi_value* buffer, size_t buffer_length) override {
586
    if (buffer_length > 0) {
587
      buffer[0] = v8impl::JsValueFromV8LocalValue(_value);
588
589
      if (buffer_length > 1) {
590
        napi_value undefined = v8impl::JsValueFromV8LocalValue(
591
            v8::Undefined(_cbinfo.GetIsolate()));
592
        for (size_t i = 1; i < buffer_length; i += 1) {
593
          buffer[i] = undefined;
594
        }
595
      }
596
    }
597
  }
598
599
  /*virtual*/
600
  void SetReturnValue(napi_value value) override {
601
    // Ignore any value returned from a setter callback.
602
  }
603
604
 private:
605
  const v8::Local<v8::Value>& _value;
606
};
607
608
428
static void DeleteCallbackBundle(napi_env env, void* data, void* hint) {
609
428
  CallbackBundle* bundle = static_cast<CallbackBundle*>(data);
610
428
  delete bundle;
611
428
}
612
613
// Creates an object to be made available to the static function callback
614
// wrapper, used to retrieve the native callback function and data pointer.
615
static
616
435
v8::Local<v8::Value> CreateFunctionCallbackData(napi_env env,
617
                                                napi_callback cb,
618
                                                void* data) {
619
435
  CallbackBundle* bundle = new CallbackBundle();
620
435
  bundle->function_or_getter = cb;
621
435
  bundle->cb_data = data;
622
435
  bundle->env = env;
623
435
  v8::Local<v8::Value> cbdata = v8::External::New(env->isolate, bundle);
624
435
  Reference::New(env, cbdata, 0, true, DeleteCallbackBundle, bundle, nullptr);
625
626
435
  return cbdata;
627
}
628
629
enum WrapType {
630
  retrievable,
631
  anonymous
632
};
633
634
template <WrapType wrap_type>
635
1025
inline napi_status Wrap(napi_env env,
636
                        napi_value js_object,
637
                        void* native_object,
638
                        napi_finalize finalize_cb,
639
                        void* finalize_hint,
640
                        napi_ref* result) {
641




3075
  NAPI_PREAMBLE(env);
642

1025
  CHECK_ARG(env, js_object);
643
644
1025
  v8::Local<v8::Context> context = env->context();
645
646
1025
  v8::Local<v8::Value> value = v8impl::V8LocalValueFromJsValue(js_object);
647

1025
  RETURN_STATUS_IF_FALSE(env, value->IsObject(), napi_invalid_arg);
648
1025
  v8::Local<v8::Object> obj = value.As<v8::Object>();
649
650
  if (wrap_type == retrievable) {
651
    // If we've already wrapped this object, we error out.
652
3066
    RETURN_STATUS_IF_FALSE(env,
653
        !obj->HasPrivate(context, NAPI_PRIVATE_KEY(context, wrapper))
654
            .FromJust(),
655
        napi_invalid_arg);
656
  } else if (wrap_type == anonymous) {
657
    // If no finalize callback is provided, we error out.
658
3
    CHECK_ARG(env, finalize_cb);
659
  }
660
661
1024
  v8impl::Reference* reference = nullptr;
662

1024
  if (result != nullptr) {
663
    // The returned reference should be deleted via napi_delete_reference()
664
    // ONLY in response to the finalize callback invocation. (If it is deleted
665
    // before then, then the finalize callback will never be invoked.)
666
    // Therefore a finalize callback is required when returning a reference.
667

8
    CHECK_ARG(env, finalize_cb);
668
16
    reference = v8impl::Reference::New(
669
        env, obj, 0, false, finalize_cb, native_object, finalize_hint);
670
8
    *result = reinterpret_cast<napi_ref>(reference);
671
  } else {
672
    // Create a self-deleting reference.
673

2032
    reference = v8impl::Reference::New(env, obj, 0, true, finalize_cb,
674
1016
        native_object, finalize_cb == nullptr ? nullptr : finalize_hint);
675
  }
676
677
  if (wrap_type == retrievable) {
678
4084
    CHECK(obj->SetPrivate(context, NAPI_PRIVATE_KEY(context, wrapper),
679
          v8::External::New(env->isolate, reference)).FromJust());
680
  }
681
682

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


30
  NAPI_PREAMBLE(env);
747
10
  CHECK_ARG(env, result);
748
10
  CHECK_ARG(env, cb);
749
750
10
  v8::Isolate* isolate = env->isolate;
751
  v8::Local<v8::Function> return_value;
752
10
  v8::EscapableHandleScope scope(isolate);
753
  v8::Local<v8::Value> cbdata =
754
10
      v8impl::CreateFunctionCallbackData(env, cb, callback_data);
755
756
10
  RETURN_STATUS_IF_FALSE(env, !cbdata.IsEmpty(), napi_generic_failure);
757
758
10
  v8::Local<v8::Context> context = env->context();
759
  v8::MaybeLocal<v8::Function> maybe_function =
760
      v8::Function::New(context,
761
                        v8impl::FunctionCallbackWrapper::Invoke,
762
10
                        cbdata);
763
10
  CHECK_MAYBE_EMPTY(env, maybe_function, napi_generic_failure);
764
765
10
  return_value = scope.Escape(maybe_function.ToLocalChecked());
766
767
10
  if (utf8name != nullptr) {
768
    v8::Local<v8::String> name_string;
769


9
    CHECK_NEW_FROM_UTF8_LEN(env, name_string, utf8name, length);
770
3
    return_value->SetName(name_string);
771
  }
772
773
20
  *result = v8impl::JsValueFromV8LocalValue(return_value);
774
775
10
  return GET_RETURN_STATUS(env);
776
}
777
778
13
napi_status napi_define_class(napi_env env,
779
                              const char* utf8name,
780
                              size_t length,
781
                              napi_callback constructor,
782
                              void* callback_data,
783
                              size_t property_count,
784
                              const napi_property_descriptor* properties,
785
                              napi_value* result) {
786


37
  NAPI_PREAMBLE(env);
787
12
  CHECK_ARG(env, result);
788
11
  CHECK_ARG(env, constructor);
789
790
10
  if (property_count > 0) {
791
7
    CHECK_ARG(env, properties);
792
  }
793
794
9
  v8::Isolate* isolate = env->isolate;
795
796
9
  v8::EscapableHandleScope scope(isolate);
797
  v8::Local<v8::Value> cbdata =
798
9
      v8impl::CreateFunctionCallbackData(env, constructor, callback_data);
799
800
9
  RETURN_STATUS_IF_FALSE(env, !cbdata.IsEmpty(), napi_generic_failure);
801
802
  v8::Local<v8::FunctionTemplate> tpl = v8::FunctionTemplate::New(
803
9
      isolate, v8impl::FunctionCallbackWrapper::Invoke, cbdata);
804
805
  v8::Local<v8::String> name_string;
806


26
  CHECK_NEW_FROM_UTF8_LEN(env, name_string, utf8name, length);
807
8
  tpl->SetClassName(name_string);
808
809
8
  size_t static_property_count = 0;
810
72
  for (size_t i = 0; i < property_count; i++) {
811
28
    const napi_property_descriptor* p = properties + i;
812
813
28
    if ((p->attributes & napi_static) != 0) {
814
      // Static properties are handled separately below.
815
7
      static_property_count++;
816
7
      continue;
817
    }
818
819
    v8::Local<v8::Name> property_name;
820
    napi_status status =
821
21
        v8impl::V8NameFromPropertyDescriptor(env, p, &property_name);
822
823
21
    if (status != napi_ok) {
824
      return napi_set_last_error(env, status);
825
    }
826
827
    v8::PropertyAttribute attributes =
828
21
        v8impl::V8PropertyAttributesFromDescriptor(p);
829
830
    // This code is similar to that in napi_define_properties(); the
831
    // difference is it applies to a template instead of an object,
832
    // and preferred PropertyAttribute for lack of PropertyDescriptor
833
    // support on ObjectTemplate.
834

21
    if (p->getter != nullptr || p->setter != nullptr) {
835
      v8::Local<v8::FunctionTemplate> getter_tpl;
836
      v8::Local<v8::FunctionTemplate> setter_tpl;
837
10
      if (p->getter != nullptr) {
838
        v8::Local<v8::Value> getter_data =
839
10
            v8impl::CreateFunctionCallbackData(env, p->getter, p->data);
840
841
        getter_tpl = v8::FunctionTemplate::New(
842
10
            isolate, v8impl::FunctionCallbackWrapper::Invoke, getter_data);
843
      }
844
10
      if (p->setter != nullptr) {
845
        v8::Local<v8::Value> setter_data =
846
5
            v8impl::CreateFunctionCallbackData(env, p->setter, p->data);
847
848
        setter_tpl = v8::FunctionTemplate::New(
849
5
            isolate, v8impl::FunctionCallbackWrapper::Invoke, setter_data);
850
      }
851
852
30
      tpl->PrototypeTemplate()->SetAccessorProperty(
853
        property_name,
854
        getter_tpl,
855
        setter_tpl,
856
        attributes,
857
20
        v8::AccessControl::DEFAULT);
858
11
    } else if (p->method != nullptr) {
859
      v8::Local<v8::Value> cbdata =
860
5
          v8impl::CreateFunctionCallbackData(env, p->method, p->data);
861
862
5
      RETURN_STATUS_IF_FALSE(env, !cbdata.IsEmpty(), napi_generic_failure);
863
864
      v8::Local<v8::FunctionTemplate> t =
865
        v8::FunctionTemplate::New(isolate,
866
          v8impl::FunctionCallbackWrapper::Invoke,
867
          cbdata,
868
5
          v8::Signature::New(isolate, tpl));
869
870
10
      tpl->PrototypeTemplate()->Set(property_name, t, attributes);
871
    } else {
872
6
      v8::Local<v8::Value> value = v8impl::V8LocalValueFromJsValue(p->value);
873
12
      tpl->PrototypeTemplate()->Set(property_name, value, attributes);
874
    }
875
  }
876
877
8
  v8::Local<v8::Context> context = env->context();
878
16
  *result = v8impl::JsValueFromV8LocalValue(
879
16
      scope.Escape(tpl->GetFunction(context).ToLocalChecked()));
880
881
8
  if (static_property_count > 0) {
882
6
    std::vector<napi_property_descriptor> static_descriptors;
883
3
    static_descriptors.reserve(static_property_count);
884
885
26
    for (size_t i = 0; i < property_count; i++) {
886
23
      const napi_property_descriptor* p = properties + i;
887
23
      if ((p->attributes & napi_static) != 0) {
888
7
        static_descriptors.push_back(*p);
889
      }
890
    }
891
892
    napi_status status =
893
3
        napi_define_properties(env,
894
                               *result,
895
                               static_descriptors.size(),
896
6
                               static_descriptors.data());
897

3
    if (status != napi_ok) return status;
898
  }
899
900
8
  return GET_RETURN_STATUS(env);
901
}
902
903
8
napi_status napi_get_property_names(napi_env env,
904
                                    napi_value object,
905
                                    napi_value* result) {
906
  return napi_get_all_property_names(
907
      env,
908
      object,
909
      napi_key_include_prototypes,
910
      static_cast<napi_key_filter>(napi_key_enumerable |
911
                                   napi_key_skip_symbols),
912
      napi_key_numbers_to_strings,
913
8
      result);
914
}
915
916
12
napi_status napi_get_all_property_names(napi_env env,
917
                                        napi_value object,
918
                                        napi_key_collection_mode key_mode,
919
                                        napi_key_filter key_filter,
920
                                        napi_key_conversion key_conversion,
921
                                        napi_value* result) {
922


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

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

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


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

64
  CHECK_TO_OBJECT(env, context, obj, object);
1007
1008
15
  v8::Local<v8::Value> k = v8impl::V8LocalValueFromJsValue(key);
1009
15
  v8::Local<v8::Value> val = v8impl::V8LocalValueFromJsValue(value);
1010
1011
15
  v8::Maybe<bool> set_maybe = obj->Set(context, k, val);
1012
1013
30
  RETURN_STATUS_IF_FALSE(env, set_maybe.FromMaybe(false), napi_generic_failure);
1014
15
  return GET_RETURN_STATUS(env);
1015
}
1016
1017
16
napi_status napi_has_property(napi_env env,
1018
                              napi_value object,
1019
                              napi_value key,
1020
                              bool* result) {
1021


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

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


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

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


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

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


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

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


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

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

434
  CHECK_NEW_FROM_UTF8(env, key, utf8name);
1118
1119
144
  v8::Local<v8::Value> val = v8impl::V8LocalValueFromJsValue(value);
1120
1121
144
  v8::Maybe<bool> set_maybe = obj->Set(context, key, val);
1122
1123
288
  RETURN_STATUS_IF_FALSE(env, set_maybe.FromMaybe(false), napi_generic_failure);
1124
144
  return GET_RETURN_STATUS(env);
1125
}
1126
1127
9
napi_status napi_has_named_property(napi_env env,
1128
                                    napi_value object,
1129
                                    const char* utf8name,
1130
                                    bool* result) {
1131


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

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

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


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

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

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


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

46
  CHECK_TO_OBJECT(env, context, obj, object);
1186
1187
11
  v8::Local<v8::Value> val = v8impl::V8LocalValueFromJsValue(value);
1188
11
  auto set_maybe = obj->Set(context, index, val);
1189
1190
22
  RETURN_STATUS_IF_FALSE(env, set_maybe.FromMaybe(false), napi_generic_failure);
1191
1192
11
  return GET_RETURN_STATUS(env);
1193
}
1194
1195
5
napi_status napi_has_element(napi_env env,
1196
                             napi_value object,
1197
                             uint32_t index,
1198
                             bool* result) {
1199


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

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


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

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


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

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


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

294
  CHECK_TO_OBJECT(env, context, obj, object);
1267
1268
966
  for (size_t i = 0; i < property_count; i++) {
1269
410
    const napi_property_descriptor* p = &properties[i];
1270
1271
    v8::Local<v8::Name> property_name;
1272
    napi_status status =
1273
410
        v8impl::V8NameFromPropertyDescriptor(env, p, &property_name);
1274
1275
410
    if (status != napi_ok) {
1276
      return napi_set_last_error(env, status);
1277
    }
1278
1279

410
    if (p->getter != nullptr || p->setter != nullptr) {
1280
      v8::Local<v8::Value> local_getter;
1281
      v8::Local<v8::Value> local_setter;
1282
1283
9
      if (p->getter != nullptr) {
1284
        v8::Local<v8::Value> getter_data =
1285
9
            v8impl::CreateFunctionCallbackData(env, p->getter, p->data);
1286
9
        CHECK_MAYBE_EMPTY(env, getter_data, napi_generic_failure);
1287
1288
        v8::MaybeLocal<v8::Function> maybe_getter =
1289
            v8::Function::New(context,
1290
                              v8impl::FunctionCallbackWrapper::Invoke,
1291
9
                              getter_data);
1292
9
        CHECK_MAYBE_EMPTY(env, maybe_getter, napi_generic_failure);
1293
1294
9
        local_getter = maybe_getter.ToLocalChecked();
1295
      }
1296
9
      if (p->setter != nullptr) {
1297
        v8::Local<v8::Value> setter_data =
1298
2
            v8impl::CreateFunctionCallbackData(env, p->setter, p->data);
1299
2
        CHECK_MAYBE_EMPTY(env, setter_data, napi_generic_failure);
1300
1301
        v8::MaybeLocal<v8::Function> maybe_setter =
1302
            v8::Function::New(context,
1303
                              v8impl::FunctionCallbackWrapper::Invoke,
1304
2
                              setter_data);
1305
2
        CHECK_MAYBE_EMPTY(env, maybe_setter, napi_generic_failure);
1306
2
        local_setter = maybe_setter.ToLocalChecked();
1307
      }
1308
1309
18
      v8::PropertyDescriptor descriptor(local_getter, local_setter);
1310
9
      descriptor.set_enumerable((p->attributes & napi_enumerable) != 0);
1311
9
      descriptor.set_configurable((p->attributes & napi_configurable) != 0);
1312
1313
      auto define_maybe = obj->DefineProperty(context,
1314
                                              property_name,
1315
9
                                              descriptor);
1316
1317
18
      if (!define_maybe.FromMaybe(false)) {
1318
        return napi_set_last_error(env, napi_invalid_arg);
1319
9
      }
1320
401
    } else if (p->method != nullptr) {
1321
      v8::Local<v8::Value> cbdata =
1322
385
          v8impl::CreateFunctionCallbackData(env, p->method, p->data);
1323
1324
385
      CHECK_MAYBE_EMPTY(env, cbdata, napi_generic_failure);
1325
1326
      v8::MaybeLocal<v8::Function> maybe_fn =
1327
          v8::Function::New(context,
1328
                            v8impl::FunctionCallbackWrapper::Invoke,
1329
385
                            cbdata);
1330
1331
385
      CHECK_MAYBE_EMPTY(env, maybe_fn, napi_generic_failure);
1332
1333
      v8::PropertyDescriptor descriptor(maybe_fn.ToLocalChecked(),
1334
1155
                                        (p->attributes & napi_writable) != 0);
1335
385
      descriptor.set_enumerable((p->attributes & napi_enumerable) != 0);
1336
385
      descriptor.set_configurable((p->attributes & napi_configurable) != 0);
1337
1338
      auto define_maybe = obj->DefineProperty(context,
1339
                                              property_name,
1340
385
                                              descriptor);
1341
1342
770
      if (!define_maybe.FromMaybe(false)) {
1343
        return napi_set_last_error(env, napi_generic_failure);
1344
      }
1345
    } else {
1346
16
      v8::Local<v8::Value> value = v8impl::V8LocalValueFromJsValue(p->value);
1347
1348
      v8::PropertyDescriptor descriptor(value,
1349
32
                                        (p->attributes & napi_writable) != 0);
1350
16
      descriptor.set_enumerable((p->attributes & napi_enumerable) != 0);
1351
16
      descriptor.set_configurable((p->attributes & napi_configurable) != 0);
1352
1353
      auto define_maybe =
1354
16
          obj->DefineProperty(context, property_name, descriptor);
1355
1356
32
      if (!define_maybe.FromMaybe(false)) {
1357
        return napi_set_last_error(env, napi_invalid_arg);
1358
      }
1359
    }
1360
  }
1361
1362
73
  return GET_RETURN_STATUS(env);
1363
}
1364
1365
11
napi_status napi_is_array(napi_env env, napi_value value, bool* result) {
1366
11
  CHECK_ENV(env);
1367
11
  CHECK_ARG(env, value);
1368
11
  CHECK_ARG(env, result);
1369
1370
11
  v8::Local<v8::Value> val = v8impl::V8LocalValueFromJsValue(value);
1371
1372
22
  *result = val->IsArray();
1373
11
  return napi_clear_last_error(env);
1374
}
1375
1376
13
napi_status napi_get_array_length(napi_env env,
1377
                                  napi_value value,
1378
                                  uint32_t* result) {
1379


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


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


19
  NAPI_PREAMBLE(env);
1412
6
  CHECK_ARG(env, result);
1413
1414
5
  v8::Local<v8::Context> context = env->context();
1415
1416
  v8::Local<v8::Object> obj;
1417

18
  CHECK_TO_OBJECT(env, context, obj, object);
1418
1419
4
  v8::Local<v8::Value> val = obj->GetPrototype();
1420
4
  *result = v8impl::JsValueFromV8LocalValue(val);
1421
4
  return GET_RETURN_STATUS(env);
1422
}
1423
1424
62
napi_status napi_create_object(napi_env env, napi_value* result) {
1425
62
  CHECK_ENV(env);
1426
62
  CHECK_ARG(env, result);
1427
1428
186
  *result = v8impl::JsValueFromV8LocalValue(
1429
62
      v8::Object::New(env->isolate));
1430
1431
62
  return napi_clear_last_error(env);
1432
}
1433
1434
1
napi_status napi_create_array(napi_env env, napi_value* result) {
1435
1
  CHECK_ENV(env);
1436
1
  CHECK_ARG(env, result);
1437
1438
3
  *result = v8impl::JsValueFromV8LocalValue(
1439
1
      v8::Array::New(env->isolate));
1440
1441
1
  return napi_clear_last_error(env);
1442
}
1443
1444
4
napi_status napi_create_array_with_length(napi_env env,
1445
                                          size_t length,
1446
                                          napi_value* result) {
1447
4
  CHECK_ENV(env);
1448
4
  CHECK_ARG(env, result);
1449
1450
12
  *result = v8impl::JsValueFromV8LocalValue(
1451
4
      v8::Array::New(env->isolate, length));
1452
1453
4
  return napi_clear_last_error(env);
1454
}
1455
1456
12
napi_status napi_create_string_latin1(napi_env env,
1457
                                      const char* str,
1458
                                      size_t length,
1459
                                      napi_value* result) {
1460
12
  CHECK_ENV(env);
1461
12
  CHECK_ARG(env, result);
1462

12
  RETURN_STATUS_IF_FALSE(env,
1463
      (length == NAPI_AUTO_LENGTH) || length <= INT_MAX,
1464
      napi_invalid_arg);
1465
1466
11
  auto isolate = env->isolate;
1467
  auto str_maybe =
1468
      v8::String::NewFromOneByte(isolate,
1469
                                 reinterpret_cast<const uint8_t*>(str),
1470
                                 v8::NewStringType::kNormal,
1471
11
                                 length);
1472
11
  CHECK_MAYBE_EMPTY(env, str_maybe, napi_generic_failure);
1473
1474
22
  *result = v8impl::JsValueFromV8LocalValue(str_maybe.ToLocalChecked());
1475
11
  return napi_clear_last_error(env);
1476
}
1477
1478
714
napi_status napi_create_string_utf8(napi_env env,
1479
                                    const char* str,
1480
                                    size_t length,
1481
                                    napi_value* result) {
1482
714
  CHECK_ENV(env);
1483
714
  CHECK_ARG(env, result);
1484

714
  RETURN_STATUS_IF_FALSE(env,
1485
      (length == NAPI_AUTO_LENGTH) || length <= INT_MAX,
1486
      napi_invalid_arg);
1487
1488
713
  auto isolate = env->isolate;
1489
  auto str_maybe =
1490
      v8::String::NewFromUtf8(isolate,
1491
                              str,
1492
                              v8::NewStringType::kNormal,
1493
713
                              static_cast<int>(length));
1494
713
  CHECK_MAYBE_EMPTY(env, str_maybe, napi_generic_failure);
1495
1426
  *result = v8impl::JsValueFromV8LocalValue(str_maybe.ToLocalChecked());
1496
713
  return napi_clear_last_error(env);
1497
}
1498
1499
14
napi_status napi_create_string_utf16(napi_env env,
1500
                                     const char16_t* str,
1501
                                     size_t length,
1502
                                     napi_value* result) {
1503
14
  CHECK_ENV(env);
1504
14
  CHECK_ARG(env, result);
1505

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


39
  NAPI_PREAMBLE(env);
1599
13
  CHECK_ARG(env, words);
1600
13
  CHECK_ARG(env, result);
1601
1602
13
  v8::Local<v8::Context> context = env->context();
1603
1604
13
  RETURN_STATUS_IF_FALSE(
1605
      env, word_count <= INT_MAX, napi_invalid_arg);
1606
1607
  v8::MaybeLocal<v8::BigInt> b = v8::BigInt::NewFromWords(
1608
12
      context, sign_bit, word_count, words);
1609
1610

12
  CHECK_MAYBE_EMPTY_WITH_PREAMBLE(env, b, napi_generic_failure);
1611
1612
22
  *result = v8impl::JsValueFromV8LocalValue(b.ToLocalChecked());
1613
11
  return GET_RETURN_STATUS(env);
1614
}
1615
1616
1292
napi_status napi_get_boolean(napi_env env, bool value, napi_value* result) {
1617
1292
  CHECK_ENV(env);
1618
1292
  CHECK_ARG(env, result);
1619
1620
1292
  v8::Isolate* isolate = env->isolate;
1621
1622
1292
  if (value) {
1623
1460
    *result = v8impl::JsValueFromV8LocalValue(v8::True(isolate));
1624
  } else {
1625
1124
    *result = v8impl::JsValueFromV8LocalValue(v8::False(isolate));
1626
  }
1627
1628
1292
  return napi_clear_last_error(env);
1629
}
1630
1631
13
napi_status napi_create_symbol(napi_env env,
1632
                               napi_value description,
1633
                               napi_value* result) {
1634
13
  CHECK_ENV(env);
1635
13
  CHECK_ARG(env, result);
1636
1637
13
  v8::Isolate* isolate = env->isolate;
1638
1639
13
  if (description == nullptr) {
1640
6
    *result = v8impl::JsValueFromV8LocalValue(v8::Symbol::New(isolate));
1641
  } else {
1642
11
    v8::Local<v8::Value> desc = v8impl::V8LocalValueFromJsValue(description);
1643
22
    RETURN_STATUS_IF_FALSE(env, desc->IsString(), napi_string_expected);
1644
1645
33
    *result = v8impl::JsValueFromV8LocalValue(
1646
      v8::Symbol::New(isolate, desc.As<v8::String>()));
1647
  }
1648
1649
13
  return napi_clear_last_error(env);
1650
}
1651
1652
194
static inline napi_status set_error_code(napi_env env,
1653
                                         v8::Local<v8::Value> error,
1654
                                         napi_value code,
1655
                                         const char* code_cstring) {
1656

194
  if ((code != nullptr) || (code_cstring != nullptr)) {
1657
116
    v8::Local<v8::Context> context = env->context();
1658
116
    v8::Local<v8::Object> err_object = error.As<v8::Object>();
1659
1660
116
    v8::Local<v8::Value> code_value = v8impl::V8LocalValueFromJsValue(code);
1661
116
    if (code != nullptr) {
1662
5
      code_value = v8impl::V8LocalValueFromJsValue(code);
1663
10
      RETURN_STATUS_IF_FALSE(env, code_value->IsString(), napi_string_expected);
1664
    } else {
1665

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


1963
  NAPI_PREAMBLE(env);
1858
653
  CHECK_ARG(env, recv);
1859
653
  if (argc > 0) {
1860
602
    CHECK_ARG(env, argv);
1861
  }
1862
1863
653
  v8::Local<v8::Context> context = env->context();
1864
1865
653
  v8::Local<v8::Value> v8recv = v8impl::V8LocalValueFromJsValue(recv);
1866
1867
  v8::Local<v8::Function> v8func;
1868

1959
  CHECK_TO_FUNCTION(env, v8func, func);
1869
1870
  auto maybe = v8func->Call(context, v8recv, argc,
1871
1306
    reinterpret_cast<v8::Local<v8::Value>*>(const_cast<napi_value*>(argv)));
1872
1873
653
  if (try_catch.HasCaught()) {
1874
6
    return napi_set_last_error(env, napi_pending_exception);
1875
  } else {
1876
647
    if (result != nullptr) {
1877
7
      CHECK_MAYBE_EMPTY(env, maybe, napi_generic_failure);
1878
7
      *result = v8impl::JsValueFromV8LocalValue(maybe.ToLocalChecked());
1879
    }
1880
647
    return napi_clear_last_error(env);
1881
  }
1882
}
1883
1884
10
napi_status napi_get_global(napi_env env, napi_value* result) {
1885
10
  CHECK_ENV(env);
1886
10
  CHECK_ARG(env, result);
1887
1888
30
  *result = v8impl::JsValueFromV8LocalValue(env->context()->Global());
1889
1890
10
  return napi_clear_last_error(env);
1891
}
1892
1893
12
napi_status napi_throw(napi_env env, napi_value error) {
1894


36
  NAPI_PREAMBLE(env);
1895
12
  CHECK_ARG(env, error);
1896
1897
12
  v8::Isolate* isolate = env->isolate;
1898
1899
12
  isolate->ThrowException(v8impl::V8LocalValueFromJsValue(error));
1900
  // any VM calls after this point and before returning
1901
  // to the javascript invoker will fail
1902
12
  return napi_clear_last_error(env);
1903
}
1904
1905
78
napi_status napi_throw_error(napi_env env,
1906
                             const char* code,
1907
                             const char* msg) {
1908


229
  NAPI_PREAMBLE(env);
1909
1910
73
  v8::Isolate* isolate = env->isolate;
1911
  v8::Local<v8::String> str;
1912

219
  CHECK_NEW_FROM_UTF8(env, str, msg);
1913
1914
73
  v8::Local<v8::Value> error_obj = v8::Exception::Error(str);
1915
73
  napi_status status = set_error_code(env, error_obj, nullptr, code);
1916
73
  if (status != napi_ok) return status;
1917
1918
73
  isolate->ThrowException(error_obj);
1919
  // any VM calls after this point and before returning
1920
  // to the javascript invoker will fail
1921
73
  return napi_clear_last_error(env);
1922
}
1923
1924
90
napi_status napi_throw_type_error(napi_env env,
1925
                                  const char* code,
1926
                                  const char* msg) {
1927


270
  NAPI_PREAMBLE(env);
1928
1929
90
  v8::Isolate* isolate = env->isolate;
1930
  v8::Local<v8::String> str;
1931

270
  CHECK_NEW_FROM_UTF8(env, str, msg);
1932
1933
90
  v8::Local<v8::Value> error_obj = v8::Exception::TypeError(str);
1934
90
  napi_status status = set_error_code(env, error_obj, nullptr, code);
1935
90
  if (status != napi_ok) return status;
1936
1937
90
  isolate->ThrowException(error_obj);
1938
  // any VM calls after this point and before returning
1939
  // to the javascript invoker will fail
1940
90
  return napi_clear_last_error(env);
1941
}
1942
1943
22
napi_status napi_throw_range_error(napi_env env,
1944
                                   const char* code,
1945
                                   const char* msg) {
1946


66
  NAPI_PREAMBLE(env);
1947
1948
22
  v8::Isolate* isolate = env->isolate;
1949
  v8::Local<v8::String> str;
1950

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

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


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




103
GEN_COERCE_FUNCTION(NUMBER, Number, number)
2310




117
GEN_COERCE_FUNCTION(OBJECT, Object, object)
2311




108
GEN_COERCE_FUNCTION(STRING, String, string)
2312
2313
#undef GEN_COERCE_FUNCTION
2314
2315
1022
napi_status napi_wrap(napi_env env,
2316
                      napi_value js_object,
2317
                      void* native_object,
2318
                      napi_finalize finalize_cb,
2319
                      void* finalize_hint,
2320
                      napi_ref* result) {
2321
  return v8impl::Wrap<v8impl::retrievable>(env,
2322
                                           js_object,
2323
                                           native_object,
2324
                                           finalize_cb,
2325
                                           finalize_hint,
2326
1022
                                           result);
2327
}
2328
2329
25
napi_status napi_unwrap(napi_env env, napi_value obj, void** result) {
2330
25
  return v8impl::Unwrap(env, obj, result, v8impl::KeepWrap);
2331
}
2332
2333
6
napi_status napi_remove_wrap(napi_env env, napi_value obj, void** result) {
2334
6
  return v8impl::Unwrap(env, obj, result, v8impl::RemoveWrap);
2335
}
2336
2337
6
napi_status napi_create_external(napi_env env,
2338
                                 void* data,
2339
                                 napi_finalize finalize_cb,
2340
                                 void* finalize_hint,
2341
                                 napi_value* result) {
2342


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


6
  NAPI_PREAMBLE(env);
2368
2
  v8::Local<v8::Context> context = env->context();
2369
  v8::Local<v8::Object> obj;
2370


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

2
  CHECK_ARG_WITH_PREAMBLE(env, type_tag);
2372
2373
2
  auto key = NAPI_PRIVATE_KEY(context, type_tag);
2374
2
  auto maybe_has = obj->HasPrivate(context, key);
2375

2
  CHECK_MAYBE_NOTHING_WITH_PREAMBLE(env, maybe_has, napi_generic_failure);
2376

2
  RETURN_STATUS_IF_FALSE_WITH_PREAMBLE(env,
2377
                                       !maybe_has.FromJust(),
2378
                                       napi_invalid_arg);
2379
2380
  auto tag = v8::BigInt::NewFromWords(context,
2381
                                   0,
2382
                                   2,
2383
2
                                   reinterpret_cast<const uint64_t*>(type_tag));
2384

2
  CHECK_MAYBE_EMPTY_WITH_PREAMBLE(env, tag, napi_generic_failure);
2385
2386
2
  auto maybe_set = obj->SetPrivate(context, key, tag.ToLocalChecked());
2387

2
  CHECK_MAYBE_NOTHING_WITH_PREAMBLE(env, maybe_set, napi_generic_failure);
2388

2
  RETURN_STATUS_IF_FALSE_WITH_PREAMBLE(env,
2389
                                       maybe_set.FromJust(),
2390
                                       napi_generic_failure);
2391
2392
2
  return GET_RETURN_STATUS(env);
2393
}
2394
2395
NAPI_EXTERN napi_status
2396
6
napi_check_object_type_tag(napi_env env,
2397
                           napi_value object,
2398
                           const napi_type_tag* type_tag,
2399
                           bool* result) {
2400


18
  NAPI_PREAMBLE(env);
2401
6
  v8::Local<v8::Context> context = env->context();
2402
  v8::Local<v8::Object> obj;
2403


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

6
  CHECK_ARG_WITH_PREAMBLE(env, type_tag);
2405

6
  CHECK_ARG_WITH_PREAMBLE(env, result);
2406
2407
  auto maybe_value = obj->GetPrivate(context,
2408
12
                                     NAPI_PRIVATE_KEY(context, type_tag));
2409

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

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

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

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


21
  NAPI_PREAMBLE(env);
2630
7
  CHECK_ARG(env, constructor);
2631
7
  if (argc > 0) {
2632
7
    CHECK_ARG(env, argv);
2633
  }
2634
7
  CHECK_ARG(env, result);
2635
2636
7
  v8::Local<v8::Context> context = env->context();
2637
2638
  v8::Local<v8::Function> ctor;
2639

21
  CHECK_TO_FUNCTION(env, ctor, constructor);
2640
2641
  auto maybe = ctor->NewInstance(context, argc,
2642
14
    reinterpret_cast<v8::Local<v8::Value>*>(const_cast<napi_value*>(argv)));
2643
2644
7
  CHECK_MAYBE_EMPTY(env, maybe, napi_generic_failure);
2645
2646
14
  *result = v8impl::JsValueFromV8LocalValue(maybe.ToLocalChecked());
2647
7
  return GET_RETURN_STATUS(env);
2648
}
2649
2650
2278
napi_status napi_instanceof(napi_env env,
2651
                            napi_value object,
2652
                            napi_value constructor,
2653
                            bool* result) {
2654


6834
  NAPI_PREAMBLE(env);
2655
2278
  CHECK_ARG(env, object);
2656
2278
  CHECK_ARG(env, result);
2657
2658
2278
  *result = false;
2659
2660
  v8::Local<v8::Object> ctor;
2661
2278
  v8::Local<v8::Context> context = env->context();
2662
2663

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


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


102
  NAPI_PREAMBLE(env);
2814
34
  CHECK_ARG(env, arraybuffer);
2815
34
  CHECK_ARG(env, result);
2816
2817
34
  v8::Local<v8::Value> value = v8impl::V8LocalValueFromJsValue(arraybuffer);
2818
34
  RETURN_STATUS_IF_FALSE(env, value->IsArrayBuffer(), napi_invalid_arg);
2819
2820
34
  v8::Local<v8::ArrayBuffer> buffer = value.As<v8::ArrayBuffer>();
2821
  v8::Local<v8::TypedArray> typedArray;
2822
2823



34
  switch (type) {
2824
    case napi_int8_array:
2825
11
      CREATE_TYPED_ARRAY(
2826
          env, Int8Array, 1, buffer, byte_offset, length, typedArray);
2827
3
      break;
2828
    case napi_uint8_array:
2829
8
      CREATE_TYPED_ARRAY(
2830
          env, Uint8Array, 1, buffer, byte_offset, length, typedArray);
2831
2
      break;
2832
    case napi_uint8_clamped_array:
2833
5
      CREATE_TYPED_ARRAY(
2834
          env, Uint8ClampedArray, 1, buffer, byte_offset, length, typedArray);
2835
1
      break;
2836
    case napi_int16_array:
2837

6
      CREATE_TYPED_ARRAY(
2838
          env, Int16Array, 2, buffer, byte_offset, length, typedArray);
2839
1
      break;
2840
    case napi_uint16_array:
2841

6
      CREATE_TYPED_ARRAY(
2842
          env, Uint16Array, 2, buffer, byte_offset, length, typedArray);
2843
1
      break;
2844
    case napi_int32_array:
2845

6
      CREATE_TYPED_ARRAY(
2846
          env, Int32Array, 4, buffer, byte_offset, length, typedArray);
2847
1
      break;
2848
    case napi_uint32_array:
2849

6
      CREATE_TYPED_ARRAY(
2850
          env, Uint32Array, 4, buffer, byte_offset, length, typedArray);
2851
1
      break;
2852
    case napi_float32_array:
2853

6
      CREATE_TYPED_ARRAY(
2854
          env, Float32Array, 4, buffer, byte_offset, length, typedArray);
2855
1
      break;
2856
    case napi_float64_array:
2857

9
      CREATE_TYPED_ARRAY(
2858
          env, Float64Array, 8, buffer, byte_offset, length, typedArray);
2859
2
      break;
2860
    case napi_bigint64_array:
2861

6
      CREATE_TYPED_ARRAY(
2862
          env, BigInt64Array, 8, buffer, byte_offset, length, typedArray);
2863
1
      break;
2864
    case napi_biguint64_array:
2865

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

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


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

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


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


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


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


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

104
  *result = value->IsArrayBuffer() &&
3231
104
            value.As<v8::ArrayBuffer>()->GetBackingStore()->Data() == nullptr;
3232
3233
26
  return napi_clear_last_error(env);
3234

13395
}