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: 1356 1392 97.4 %
Date: 2020-08-07 22:13:19 Branches: 1032 1644 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 the finalizer has already run or
232
  // cannot have been queued to run (ie the reference count is > 0),
233
  // otherwise we may crash when the finalizer does run.
234
  // If the finalizer may have been queued and has not already run
235
  // delay the delete until the finalizer runs by not doing the delete
236
  // and setting _delete_self to true so that the finalizer will
237
  // delete it when it runs.
238
  //
239
  // The second way this is called is from
240
  // the finalizer and _delete_self is set. In this case we
241
  // know we need to do the deletion so just do it.
242
3006
  static inline void Delete(RefBase* reference) {
243
3006
    reference->Unlink();
244

8482
    if ((reference->RefCount() != 0) ||
245

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

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

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


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




3075
  NAPI_PREAMBLE(env);
640

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

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

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

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

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

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


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


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


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


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

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

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


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

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

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


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

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


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

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


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

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


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

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


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

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


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

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

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


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

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

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


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

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

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


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

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


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

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


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

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


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

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


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

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

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


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


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


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

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

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

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

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


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

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

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

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


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

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


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


232
  NAPI_PREAMBLE(env);
1907
1908
74
  v8::Isolate* isolate = env->isolate;
1909
  v8::Local<v8::String> str;
1910

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


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

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


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

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

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


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




103
GEN_COERCE_FUNCTION(NUMBER, Number, number)
2308




117
GEN_COERCE_FUNCTION(OBJECT, Object, object)
2309




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


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


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


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

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

2
  CHECK_MAYBE_NOTHING_WITH_PREAMBLE(env, maybe_has, napi_generic_failure);
2374

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

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

2
  CHECK_MAYBE_NOTHING_WITH_PREAMBLE(env, maybe_set, napi_generic_failure);
2386

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


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


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

6
  CHECK_ARG_WITH_PREAMBLE(env, type_tag);
2403

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

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

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

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

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


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

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


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

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


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


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



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

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

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

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

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

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

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

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

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

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


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

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


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


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


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


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

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

13323
}