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: 1387 1420 97.7 %
Date: 2020-11-20 19:51:53 Branches: 1047 1680 62.3 %

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

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

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


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

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

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

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

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


105
  NAPI_PREAMBLE(env);
383
35
  CHECK_ARG(env, js_object);
384
35
  if (action == KeepWrap) {
385
27
    CHECK_ARG(env, result);
386
  }
387
388
35
  v8::Local<v8::Context> context = env->context();
389
390
35
  v8::Local<v8::Value> value = v8impl::V8LocalValueFromJsValue(js_object);
391
35
  RETURN_STATUS_IF_FALSE(env, value->IsObject(), napi_invalid_arg);
392
35
  v8::Local<v8::Object> obj = value.As<v8::Object>();
393
394
105
  auto val = obj->GetPrivate(context, NAPI_PRIVATE_KEY(context, wrapper))
395
35
      .ToLocalChecked();
396
35
  RETURN_STATUS_IF_FALSE(env, val->IsExternal(), napi_invalid_arg);
397
  Reference* reference =
398
70
      static_cast<v8impl::Reference*>(val.As<v8::External>()->Value());
399
400
35
  if (result) {
401
35
    *result = reference->Data();
402
  }
403
404
35
  if (action == RemoveWrap) {
405
24
    CHECK(obj->DeletePrivate(context, NAPI_PRIVATE_KEY(context, wrapper))
406
        .FromJust());
407
8
    Reference::Delete(reference);
408
  }
409
410
35
  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
4631
  CallbackWrapper(napi_value this_arg, size_t args_length, void* data)
433
4631
      : _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
4475
  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
4631
  CallbackWrapperBase(const Info& cbinfo, const size_t args_length)
455
      : CallbackWrapper(JsValueFromV8LocalValue(cbinfo.This()),
456
                        args_length,
457
                        nullptr),
458
4631
        _cbinfo(cbinfo) {
459
4631
    _bundle = reinterpret_cast<CallbackBundle*>(
460
9262
        v8::Local<v8::External>::Cast(cbinfo.Data())->Value());
461
4631
    _data = _bundle->cb_data;
462
4631
  }
463
464
  napi_value GetNewTarget() override { return nullptr; }
465
466
 protected:
467
4631
  void InvokeCallback() {
468
    napi_callback_info cbinfo_wrapper = reinterpret_cast<napi_callback_info>(
469
4631
        static_cast<CallbackWrapper*>(this));
470
471
    // All other pointers we need are stored in `_bundle`
472
4631
    napi_env env = _bundle->env;
473
4631
    napi_callback cb = _bundle->*FunctionField;
474
475
    napi_value result;
476
9262
    env->CallIntoModule([&](napi_env env) {
477
4631
      result = cb(env, cbinfo_wrapper);
478
4631
    });
479
480
4631
    if (result != nullptr) {
481
2806
      this->SetReturnValue(result);
482
    }
483
4631
  }
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
4631
  static void Invoke(const v8::FunctionCallbackInfo<v8::Value>& info) {
494
4631
    FunctionCallbackWrapper cbwrapper(info);
495
4631
    cbwrapper.InvokeCallback();
496
4631
  }
497
498
4631
  explicit FunctionCallbackWrapper(
499
      const v8::FunctionCallbackInfo<v8::Value>& cbinfo)
500
9262
      : 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
4463
  void Args(napi_value* buffer, size_t buffer_length) override {
512
4463
    size_t i = 0;
513
4463
    size_t min = std::min(buffer_length, _args_length);
514
515
18539
    for (; i < min; i += 1) {
516
14076
      buffer[i] = v8impl::JsValueFromV8LocalValue(_cbinfo[i]);
517
    }
518
519
4463
    if (i < buffer_length) {
520
      napi_value undefined =
521
75
          v8impl::JsValueFromV8LocalValue(v8::Undefined(_cbinfo.GetIsolate()));
522
181
      for (; i < buffer_length; i += 1) {
523
78
        buffer[i] = undefined;
524
      }
525
    }
526
4463
  }
527
528
  /*virtual*/
529
2806
  void SetReturnValue(napi_value value) override {
530
2806
    v8::Local<v8::Value> val = v8impl::V8LocalValueFromJsValue(value);
531
8418
    _cbinfo.GetReturnValue().Set(val);
532
2806
  }
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
437
static void DeleteCallbackBundle(napi_env env, void* data, void* hint) {
607
437
  CallbackBundle* bundle = static_cast<CallbackBundle*>(data);
608
437
  delete bundle;
609
437
}
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
444
v8::Local<v8::Value> CreateFunctionCallbackData(napi_env env,
615
                                                napi_callback cb,
616
                                                void* data) {
617
444
  CallbackBundle* bundle = new CallbackBundle();
618
444
  bundle->function_or_getter = cb;
619
444
  bundle->cb_data = data;
620
444
  bundle->env = env;
621
444
  v8::Local<v8::Value> cbdata = v8::External::New(env->isolate, bundle);
622
444
  Reference::New(env, cbdata, 0, true, DeleteCallbackBundle, bundle, nullptr);
623
624
444
  return cbdata;
625
}
626
627
enum WrapType {
628
  retrievable,
629
  anonymous
630
};
631
632
template <WrapType wrap_type>
633
1028
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




3084
  NAPI_PREAMBLE(env);
640

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

1028
  RETURN_STATUS_IF_FALSE(env, value->IsObject(), napi_invalid_arg);
646
1028
  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
3075
    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
1027
  v8impl::Reference* reference = nullptr;
660

1027
  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

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

1027
  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
1300
napi_status napi_get_last_error_info(napi_env env,
714
                                     const napi_extended_error_info** result) {
715
1300
  CHECK_ENV(env);
716
1300
  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
1300
  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
1300
  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
2600
  env->last_error.error_message =
732
1300
      error_messages[env->last_error.error_code];
733
734
1300
  *result = &(env->last_error);
735
1300
  return napi_ok;
736
}
737
738
15
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


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

3
    CHECK_NEW_FROM_UTF8_LEN(env, name_string, utf8name, length);
768
3
    return_value->SetName(name_string);
769
6
  }
770
3
771
30
  *result = v8impl::JsValueFromV8LocalValue(return_value);
772
773
15
  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

10
  CHECK_NEW_FROM_UTF8_LEN(env, name_string, utf8name, length);
805
9
  tpl->SetClassName(name_string);
806
16
807
16
  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
21
    STATUS_CALL(v8impl::V8NameFromPropertyDescriptor(env, p, &property_name));
819
820
    v8::PropertyAttribute attributes =
821
21
        v8impl::V8PropertyAttributesFromDescriptor(p);
822
823
    // This code is similar to that in napi_define_properties(); the
824
    // difference is it applies to a template instead of an object,
825
    // and preferred PropertyAttribute for lack of PropertyDescriptor
826
    // support on ObjectTemplate.
827

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

3
    STATUS_CALL(napi_define_properties(env,
886
                                       *result,
887
                                       static_descriptors.size(),
888
                                       static_descriptors.data()));
889
  }
890
891
8
  return GET_RETURN_STATUS(env);
892
}
893
894
8
napi_status napi_get_property_names(napi_env env,
895
                                    napi_value object,
896
                                    napi_value* result) {
897
  return napi_get_all_property_names(
898
      env,
899
      object,
900
      napi_key_include_prototypes,
901
      static_cast<napi_key_filter>(napi_key_enumerable |
902
                                   napi_key_skip_symbols),
903
      napi_key_numbers_to_strings,
904
8
      result);
905
}
906
907
12
napi_status napi_get_all_property_names(napi_env env,
908
                                        napi_value object,
909
                                        napi_key_collection_mode key_mode,
910
                                        napi_key_filter key_filter,
911
                                        napi_key_conversion key_conversion,
912
                                        napi_value* result) {
913


32
  NAPI_PREAMBLE(env);
914
10
  CHECK_ARG(env, result);
915
916
8
  v8::Local<v8::Context> context = env->context();
917
  v8::Local<v8::Object> obj;
918

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

6
  CHECK_MAYBE_EMPTY_WITH_PREAMBLE(
979
      env, maybe_all_propertynames, napi_generic_failure);
980
981
12
  *result =
982
12
      v8impl::JsValueFromV8LocalValue(maybe_all_propertynames.ToLocalChecked());
983
6
  return GET_RETURN_STATUS(env);
984
}
985
986
26
napi_status napi_set_property(napi_env env,
987
                              napi_value object,
988
                              napi_value key,
989
                              napi_value value) {
990


74
  NAPI_PREAMBLE(env);
991
24
  CHECK_ARG(env, key);
992
21
  CHECK_ARG(env, value);
993
994
19
  v8::Local<v8::Context> context = env->context();
995
  v8::Local<v8::Object> obj;
996
997

72
  CHECK_TO_OBJECT(env, context, obj, object);
998
999
17
  v8::Local<v8::Value> k = v8impl::V8LocalValueFromJsValue(key);
1000
17
  v8::Local<v8::Value> val = v8impl::V8LocalValueFromJsValue(value);
1001
1002
17
  v8::Maybe<bool> set_maybe = obj->Set(context, k, val);
1003
1004
34
  RETURN_STATUS_IF_FALSE(env, set_maybe.FromMaybe(false), napi_generic_failure);
1005
17
  return GET_RETURN_STATUS(env);
1006
}
1007
1008
16
napi_status napi_has_property(napi_env env,
1009
                              napi_value object,
1010
                              napi_value key,
1011
                              bool* result) {
1012


44
  NAPI_PREAMBLE(env);
1013
14
  CHECK_ARG(env, result);
1014
12
  CHECK_ARG(env, key);
1015
1016
10
  v8::Local<v8::Context> context = env->context();
1017
  v8::Local<v8::Object> obj;
1018
1019

36
  CHECK_TO_OBJECT(env, context, obj, object);
1020
1021
8
  v8::Local<v8::Value> k = v8impl::V8LocalValueFromJsValue(key);
1022
8
  v8::Maybe<bool> has_maybe = obj->Has(context, k);
1023
1024
8
  CHECK_MAYBE_NOTHING(env, has_maybe, napi_generic_failure);
1025
1026
16
  *result = has_maybe.FromMaybe(false);
1027
8
  return GET_RETURN_STATUS(env);
1028
}
1029
1030
34
napi_status napi_get_property(napi_env env,
1031
                              napi_value object,
1032
                              napi_value key,
1033
                              napi_value* result) {
1034


98
  NAPI_PREAMBLE(env);
1035
32
  CHECK_ARG(env, key);
1036
28
  CHECK_ARG(env, result);
1037
1038
26
  v8::Local<v8::Context> context = env->context();
1039
26
  v8::Local<v8::Value> k = v8impl::V8LocalValueFromJsValue(key);
1040
  v8::Local<v8::Object> obj;
1041
1042

100
  CHECK_TO_OBJECT(env, context, obj, object);
1043
1044
24
  auto get_maybe = obj->Get(context, k);
1045
1046
24
  CHECK_MAYBE_EMPTY(env, get_maybe, napi_generic_failure);
1047
1048
24
  v8::Local<v8::Value> val = get_maybe.ToLocalChecked();
1049
24
  *result = v8impl::JsValueFromV8LocalValue(val);
1050
24
  return GET_RETURN_STATUS(env);
1051
}
1052
1053
9
napi_status napi_delete_property(napi_env env,
1054
                                 napi_value object,
1055
                                 napi_value key,
1056
                                 bool* result) {
1057


25
  NAPI_PREAMBLE(env);
1058
8
  CHECK_ARG(env, key);
1059
1060
7
  v8::Local<v8::Context> context = env->context();
1061
7
  v8::Local<v8::Value> k = v8impl::V8LocalValueFromJsValue(key);
1062
  v8::Local<v8::Object> obj;
1063
1064

26
  CHECK_TO_OBJECT(env, context, obj, object);
1065
6
  v8::Maybe<bool> delete_maybe = obj->Delete(context, k);
1066
6
  CHECK_MAYBE_NOTHING(env, delete_maybe, napi_generic_failure);
1067
1068
6
  if (result != nullptr)
1069
10
    *result = delete_maybe.FromMaybe(false);
1070
1071
6
  return GET_RETURN_STATUS(env);
1072
}
1073
1074
19
napi_status napi_has_own_property(napi_env env,
1075
                                  napi_value object,
1076
                                  napi_value key,
1077
                                  bool* result) {
1078


55
  NAPI_PREAMBLE(env);
1079
18
  CHECK_ARG(env, key);
1080
17
  CHECK_ARG(env, result);
1081
1082
16
  v8::Local<v8::Context> context = env->context();
1083
  v8::Local<v8::Object> obj;
1084
1085

62
  CHECK_TO_OBJECT(env, context, obj, object);
1086
15
  v8::Local<v8::Value> k = v8impl::V8LocalValueFromJsValue(key);
1087
24
  RETURN_STATUS_IF_FALSE(env, k->IsName(), napi_name_expected);
1088
6
  v8::Maybe<bool> has_maybe = obj->HasOwnProperty(context, k.As<v8::Name>());
1089
6
  CHECK_MAYBE_NOTHING(env, has_maybe, napi_generic_failure);
1090
12
  *result = has_maybe.FromMaybe(false);
1091
1092
6
  return GET_RETURN_STATUS(env);
1093
}
1094
1095
153
napi_status napi_set_named_property(napi_env env,
1096
                                    napi_value object,
1097
                                    const char* utf8name,
1098
                                    napi_value value) {
1099


457
  NAPI_PREAMBLE(env);
1100
152
  CHECK_ARG(env, value);
1101
1102
151
  v8::Local<v8::Context> context = env->context();
1103
  v8::Local<v8::Object> obj;
1104
1105

602
  CHECK_TO_OBJECT(env, context, obj, object);
1106
1107
  v8::Local<v8::Name> key;
1108

449
  CHECK_NEW_FROM_UTF8(env, key, utf8name);
1109
1110
149
  v8::Local<v8::Value> val = v8impl::V8LocalValueFromJsValue(value);
1111
1112
149
  v8::Maybe<bool> set_maybe = obj->Set(context, key, val);
1113
1114
298
  RETURN_STATUS_IF_FALSE(env, set_maybe.FromMaybe(false), napi_generic_failure);
1115
149
  return GET_RETURN_STATUS(env);
1116
}
1117
1118
9
napi_status napi_has_named_property(napi_env env,
1119
                                    napi_value object,
1120
                                    const char* utf8name,
1121
                                    bool* result) {
1122


25
  NAPI_PREAMBLE(env);
1123
8
  CHECK_ARG(env, result);
1124
1125
7
  v8::Local<v8::Context> context = env->context();
1126
  v8::Local<v8::Object> obj;
1127
1128

26
  CHECK_TO_OBJECT(env, context, obj, object);
1129
1130
  v8::Local<v8::Name> key;
1131

17
  CHECK_NEW_FROM_UTF8(env, key, utf8name);
1132
1133
5
  v8::Maybe<bool> has_maybe = obj->Has(context, key);
1134
1135
5
  CHECK_MAYBE_NOTHING(env, has_maybe, napi_generic_failure);
1136
1137
10
  *result = has_maybe.FromMaybe(false);
1138
5
  return GET_RETURN_STATUS(env);
1139
}
1140
1141
5
napi_status napi_get_named_property(napi_env env,
1142
                                    napi_value object,
1143
                                    const char* utf8name,
1144
                                    napi_value* result) {
1145


13
  NAPI_PREAMBLE(env);
1146
4
  CHECK_ARG(env, result);
1147
1148
3
  v8::Local<v8::Context> context = env->context();
1149
1150
  v8::Local<v8::Name> key;
1151

8
  CHECK_NEW_FROM_UTF8(env, key, utf8name);
1152
1153
  v8::Local<v8::Object> obj;
1154
1155

7
  CHECK_TO_OBJECT(env, context, obj, object);
1156
1157
1
  auto get_maybe = obj->Get(context, key);
1158
1159
1
  CHECK_MAYBE_EMPTY(env, get_maybe, napi_generic_failure);
1160
1161
1
  v8::Local<v8::Value> val = get_maybe.ToLocalChecked();
1162
1
  *result = v8impl::JsValueFromV8LocalValue(val);
1163
1
  return GET_RETURN_STATUS(env);
1164
}
1165
1166
13
napi_status napi_set_element(napi_env env,
1167
                             napi_value object,
1168
                             uint32_t index,
1169
                             napi_value value) {
1170


37
  NAPI_PREAMBLE(env);
1171
12
  CHECK_ARG(env, value);
1172
1173
12
  v8::Local<v8::Context> context = env->context();
1174
  v8::Local<v8::Object> obj;
1175
1176

46
  CHECK_TO_OBJECT(env, context, obj, object);
1177
1178
11
  v8::Local<v8::Value> val = v8impl::V8LocalValueFromJsValue(value);
1179
11
  auto set_maybe = obj->Set(context, index, val);
1180
1181
22
  RETURN_STATUS_IF_FALSE(env, set_maybe.FromMaybe(false), napi_generic_failure);
1182
1183
11
  return GET_RETURN_STATUS(env);
1184
}
1185
1186
5
napi_status napi_has_element(napi_env env,
1187
                             napi_value object,
1188
                             uint32_t index,
1189
                             bool* result) {
1190


13
  NAPI_PREAMBLE(env);
1191
4
  CHECK_ARG(env, result);
1192
1193
3
  v8::Local<v8::Context> context = env->context();
1194
  v8::Local<v8::Object> obj;
1195
1196

10
  CHECK_TO_OBJECT(env, context, obj, object);
1197
1198
2
  v8::Maybe<bool> has_maybe = obj->Has(context, index);
1199
1200
2
  CHECK_MAYBE_NOTHING(env, has_maybe, napi_generic_failure);
1201
1202
4
  *result = has_maybe.FromMaybe(false);
1203
2
  return GET_RETURN_STATUS(env);
1204
}
1205
1206
28
napi_status napi_get_element(napi_env env,
1207
                             napi_value object,
1208
                             uint32_t index,
1209
                             napi_value* result) {
1210


82
  NAPI_PREAMBLE(env);
1211
27
  CHECK_ARG(env, result);
1212
1213
27
  v8::Local<v8::Context> context = env->context();
1214
  v8::Local<v8::Object> obj;
1215
1216

108
  CHECK_TO_OBJECT(env, context, obj, object);
1217
1218
27
  auto get_maybe = obj->Get(context, index);
1219
1220
27
  CHECK_MAYBE_EMPTY(env, get_maybe, napi_generic_failure);
1221
1222
54
  *result = v8impl::JsValueFromV8LocalValue(get_maybe.ToLocalChecked());
1223
27
  return GET_RETURN_STATUS(env);
1224
}
1225
1226
4
napi_status napi_delete_element(napi_env env,
1227
                                napi_value object,
1228
                                uint32_t index,
1229
                                bool* result) {
1230


10
  NAPI_PREAMBLE(env);
1231
1232
3
  v8::Local<v8::Context> context = env->context();
1233
  v8::Local<v8::Object> obj;
1234
1235

10
  CHECK_TO_OBJECT(env, context, obj, object);
1236
2
  v8::Maybe<bool> delete_maybe = obj->Delete(context, index);
1237
2
  CHECK_MAYBE_NOTHING(env, delete_maybe, napi_generic_failure);
1238
1239
2
  if (result != nullptr)
1240
2
    *result = delete_maybe.FromMaybe(false);
1241
1242
2
  return GET_RETURN_STATUS(env);
1243
}
1244
1245
78
napi_status napi_define_properties(napi_env env,
1246
                                   napi_value object,
1247
                                   size_t property_count,
1248
                                   const napi_property_descriptor* properties) {
1249


232
  NAPI_PREAMBLE(env);
1250
77
  if (property_count > 0) {
1251
77
    CHECK_ARG(env, properties);
1252
  }
1253
1254
74
  v8::Local<v8::Context> context = env->context();
1255
1256
  v8::Local<v8::Object> obj;
1257

294
  CHECK_TO_OBJECT(env, context, obj, object);
1258
1259
974
  for (size_t i = 0; i < property_count; i++) {
1260
414
    const napi_property_descriptor* p = &properties[i];
1261
1262
    v8::Local<v8::Name> property_name;
1263
414
    STATUS_CALL(v8impl::V8NameFromPropertyDescriptor(env, p, &property_name));
1264
1265

414
    if (p->getter != nullptr || p->setter != nullptr) {
1266
      v8::Local<v8::Value> local_getter;
1267
      v8::Local<v8::Value> local_setter;
1268
1269
9
      if (p->getter != nullptr) {
1270
        v8::Local<v8::Value> getter_data =
1271
9
            v8impl::CreateFunctionCallbackData(env, p->getter, p->data);
1272
9
        CHECK_MAYBE_EMPTY(env, getter_data, napi_generic_failure);
1273
1274
        v8::MaybeLocal<v8::Function> maybe_getter =
1275
            v8::Function::New(context,
1276
                              v8impl::FunctionCallbackWrapper::Invoke,
1277
9
                              getter_data);
1278
9
        CHECK_MAYBE_EMPTY(env, maybe_getter, napi_generic_failure);
1279
1280
9
        local_getter = maybe_getter.ToLocalChecked();
1281
      }
1282
9
      if (p->setter != nullptr) {
1283
        v8::Local<v8::Value> setter_data =
1284
2
            v8impl::CreateFunctionCallbackData(env, p->setter, p->data);
1285
2
        CHECK_MAYBE_EMPTY(env, setter_data, napi_generic_failure);
1286
1287
        v8::MaybeLocal<v8::Function> maybe_setter =
1288
            v8::Function::New(context,
1289
                              v8impl::FunctionCallbackWrapper::Invoke,
1290
2
                              setter_data);
1291
2
        CHECK_MAYBE_EMPTY(env, maybe_setter, napi_generic_failure);
1292
2
        local_setter = maybe_setter.ToLocalChecked();
1293
      }
1294
1295
18
      v8::PropertyDescriptor descriptor(local_getter, local_setter);
1296
9
      descriptor.set_enumerable((p->attributes & napi_enumerable) != 0);
1297
9
      descriptor.set_configurable((p->attributes & napi_configurable) != 0);
1298
1299
      auto define_maybe = obj->DefineProperty(context,
1300
                                              property_name,
1301
9
                                              descriptor);
1302
1303
18
      if (!define_maybe.FromMaybe(false)) {
1304
        return napi_set_last_error(env, napi_invalid_arg);
1305
9
      }
1306
405
    } else if (p->method != nullptr) {
1307
      v8::Local<v8::Value> cbdata =
1308
389
          v8impl::CreateFunctionCallbackData(env, p->method, p->data);
1309
1310
389
      CHECK_MAYBE_EMPTY(env, cbdata, napi_generic_failure);
1311
1312
      v8::MaybeLocal<v8::Function> maybe_fn =
1313
          v8::Function::New(context,
1314
                            v8impl::FunctionCallbackWrapper::Invoke,
1315
389
                            cbdata);
1316
1317
389
      CHECK_MAYBE_EMPTY(env, maybe_fn, napi_generic_failure);
1318
1319
      v8::PropertyDescriptor descriptor(maybe_fn.ToLocalChecked(),
1320
1167
                                        (p->attributes & napi_writable) != 0);
1321
389
      descriptor.set_enumerable((p->attributes & napi_enumerable) != 0);
1322
389
      descriptor.set_configurable((p->attributes & napi_configurable) != 0);
1323
1324
      auto define_maybe = obj->DefineProperty(context,
1325
                                              property_name,
1326
389
                                              descriptor);
1327
1328
778
      if (!define_maybe.FromMaybe(false)) {
1329
        return napi_set_last_error(env, napi_generic_failure);
1330
      }
1331
    } else {
1332
16
      v8::Local<v8::Value> value = v8impl::V8LocalValueFromJsValue(p->value);
1333
1334
      v8::PropertyDescriptor descriptor(value,
1335
32
                                        (p->attributes & napi_writable) != 0);
1336
16
      descriptor.set_enumerable((p->attributes & napi_enumerable) != 0);
1337
16
      descriptor.set_configurable((p->attributes & napi_configurable) != 0);
1338
1339
      auto define_maybe =
1340
16
          obj->DefineProperty(context, property_name, descriptor);
1341
1342
32
      if (!define_maybe.FromMaybe(false)) {
1343
        return napi_set_last_error(env, napi_invalid_arg);
1344
      }
1345
    }
1346
  }
1347
1348
73
  return GET_RETURN_STATUS(env);
1349
}
1350
1351
1
napi_status napi_object_freeze(napi_env env,
1352
                               napi_value object) {
1353


3
  NAPI_PREAMBLE(env);
1354
1355
1
  v8::Local<v8::Context> context = env->context();
1356
  v8::Local<v8::Object> obj;
1357
1358

4
  CHECK_TO_OBJECT(env, context, obj, object);
1359
1360
  v8::Maybe<bool> set_frozen =
1361
1
    obj->SetIntegrityLevel(context, v8::IntegrityLevel::kFrozen);
1362
1363

2
  RETURN_STATUS_IF_FALSE_WITH_PREAMBLE(env,
1364
    set_frozen.FromMaybe(false), napi_generic_failure);
1365
1366
1
  return GET_RETURN_STATUS(env);
1367
}
1368
1369
1
napi_status napi_object_seal(napi_env env,
1370
                             napi_value object) {
1371


3
  NAPI_PREAMBLE(env);
1372
1373
1
  v8::Local<v8::Context> context = env->context();
1374
  v8::Local<v8::Object> obj;
1375
1376

4
  CHECK_TO_OBJECT(env, context, obj, object);
1377
1378
  v8::Maybe<bool> set_sealed =
1379
1
    obj->SetIntegrityLevel(context, v8::IntegrityLevel::kSealed);
1380
1381

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


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


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


19
  NAPI_PREAMBLE(env);
1434
6
  CHECK_ARG(env, result);
1435
1436
5
  v8::Local<v8::Context> context = env->context();
1437
1438
  v8::Local<v8::Object> obj;
1439

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

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

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

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


39
  NAPI_PREAMBLE(env);
1621
13
  CHECK_ARG(env, words);
1622
13
  CHECK_ARG(env, result);
1623
1624
13
  v8::Local<v8::Context> context = env->context();
1625
1626
13
  RETURN_STATUS_IF_FALSE(
1627
      env, word_count <= INT_MAX, napi_invalid_arg);
1628
1629
  v8::MaybeLocal<v8::BigInt> b = v8::BigInt::NewFromWords(
1630
12
      context, sign_bit, word_count, words);
1631
1632

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

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

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


1963
  NAPI_PREAMBLE(env);
1877
653
  CHECK_ARG(env, recv);
1878
653
  if (argc > 0) {
1879
602
    CHECK_ARG(env, argv);
1880
  }
1881
1882
653
  v8::Local<v8::Context> context = env->context();
1883
1884
653
  v8::Local<v8::Value> v8recv = v8impl::V8LocalValueFromJsValue(recv);
1885
1886
  v8::Local<v8::Function> v8func;
1887

1959
  CHECK_TO_FUNCTION(env, v8func, func);
1888
1889
  auto maybe = v8func->Call(context, v8recv, argc,
1890
1306
    reinterpret_cast<v8::Local<v8::Value>*>(const_cast<napi_value*>(argv)));
1891
1892
653
  if (try_catch.HasCaught()) {
1893
6
    return napi_set_last_error(env, napi_pending_exception);
1894
  } else {
1895
647
    if (result != nullptr) {
1896
7
      CHECK_MAYBE_EMPTY(env, maybe, napi_generic_failure);
1897
7
      *result = v8impl::JsValueFromV8LocalValue(maybe.ToLocalChecked());
1898
    }
1899
647
    return napi_clear_last_error(env);
1900
  }
1901
}
1902
1903
10
napi_status napi_get_global(napi_env env, napi_value* result) {
1904
10
  CHECK_ENV(env);
1905
10
  CHECK_ARG(env, result);
1906
1907
30
  *result = v8impl::JsValueFromV8LocalValue(env->context()->Global());
1908
1909
10
  return napi_clear_last_error(env);
1910
}
1911
1912
12
napi_status napi_throw(napi_env env, napi_value error) {
1913


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


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

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


270
  NAPI_PREAMBLE(env);
1946
1947
90
  v8::Isolate* isolate = env->isolate;
1948
  v8::Local<v8::String> str;
1949

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


66
  NAPI_PREAMBLE(env);
1964
1965
22
  v8::Isolate* isolate = env->isolate;
1966
  v8::Local<v8::String> str;
1967

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

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


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


49
GEN_COERCE_FUNCTION(OBJECT, Object, object)
2327


69
GEN_COERCE_FUNCTION(STRING, String, string)
2328


67
2329

35
#undef GEN_COERCE_FUNCTION
2330

48
2331

1089
napi_status napi_wrap(napi_env env,
2332

63
                      napi_value js_object,
2333

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


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


6
  NAPI_PREAMBLE(env);
2384
2
  v8::Local<v8::Context> context = env->context();
2385
  v8::Local<v8::Object> obj;
2386


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

2
  CHECK_ARG_WITH_PREAMBLE(env, type_tag);
2388
2389
2
  auto key = NAPI_PRIVATE_KEY(context, type_tag);
2390
2
  auto maybe_has = obj->HasPrivate(context, key);
2391

2
  CHECK_MAYBE_NOTHING_WITH_PREAMBLE(env, maybe_has, napi_generic_failure);
2392

2
  RETURN_STATUS_IF_FALSE_WITH_PREAMBLE(env,
2393
                                       !maybe_has.FromJust(),
2394
                                       napi_invalid_arg);
2395
2396
  auto tag = v8::BigInt::NewFromWords(context,
2397
                                   0,
2398
                                   2,
2399
2
                                   reinterpret_cast<const uint64_t*>(type_tag));
2400

2
  CHECK_MAYBE_EMPTY_WITH_PREAMBLE(env, tag, napi_generic_failure);
2401
2402
2
  auto maybe_set = obj->SetPrivate(context, key, tag.ToLocalChecked());
2403

2
  CHECK_MAYBE_NOTHING_WITH_PREAMBLE(env, maybe_set, napi_generic_failure);
2404

2
  RETURN_STATUS_IF_FALSE_WITH_PREAMBLE(env,
2405
                                       maybe_set.FromJust(),
2406
                                       napi_generic_failure);
2407
2408
2
  return GET_RETURN_STATUS(env);
2409
}
2410
2411
NAPI_EXTERN napi_status
2412
6
napi_check_object_type_tag(napi_env env,
2413
                           napi_value object,
2414
                           const napi_type_tag* type_tag,
2415
                           bool* result) {
2416


18
  NAPI_PREAMBLE(env);
2417
6
  v8::Local<v8::Context> context = env->context();
2418
  v8::Local<v8::Object> obj;
2419


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

6
  CHECK_ARG_WITH_PREAMBLE(env, type_tag);
2421

6
  CHECK_ARG_WITH_PREAMBLE(env, result);
2422
2423
  auto maybe_value = obj->GetPrivate(context,
2424
12
                                     NAPI_PRIVATE_KEY(context, type_tag));
2425

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

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

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

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


21
  NAPI_PREAMBLE(env);
2646
7
  CHECK_ARG(env, constructor);
2647
7
  if (argc > 0) {
2648
7
    CHECK_ARG(env, argv);
2649
  }
2650
7
  CHECK_ARG(env, result);
2651
2652
7
  v8::Local<v8::Context> context = env->context();
2653
2654
  v8::Local<v8::Function> ctor;
2655

21
  CHECK_TO_FUNCTION(env, ctor, constructor);
2656
2657
  auto maybe = ctor->NewInstance(context, argc,
2658
14
    reinterpret_cast<v8::Local<v8::Value>*>(const_cast<napi_value*>(argv)));
2659
2660
7
  CHECK_MAYBE_EMPTY(env, maybe, napi_generic_failure);
2661
2662
14
  *result = v8impl::JsValueFromV8LocalValue(maybe.ToLocalChecked());
2663
7
  return GET_RETURN_STATUS(env);
2664
}
2665
2666
2278
napi_status napi_instanceof(napi_env env,
2667
                            napi_value object,
2668
                            napi_value constructor,
2669
                            bool* result) {
2670


6834
  NAPI_PREAMBLE(env);
2671
2278
  CHECK_ARG(env, object);
2672
2278
  CHECK_ARG(env, result);
2673
2674
2278
  *result = false;
2675
2676
  v8::Local<v8::Object> ctor;
2677
2278
  v8::Local<v8::Context> context = env->context();
2678
2679

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


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


102
  NAPI_PREAMBLE(env);
2828
34
  CHECK_ARG(env, arraybuffer);
2829
34
  CHECK_ARG(env, result);
2830
2831
34
  v8::Local<v8::Value> value = v8impl::V8LocalValueFromJsValue(arraybuffer);
2832
34
  RETURN_STATUS_IF_FALSE(env, value->IsArrayBuffer(), napi_invalid_arg);
2833
2834
34
  v8::Local<v8::ArrayBuffer> buffer = value.As<v8::ArrayBuffer>();
2835
  v8::Local<v8::TypedArray> typedArray;
2836
2837



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

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


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

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


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


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


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


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

104
  *result = value->IsArrayBuffer() &&
3245
104
            value.As<v8::ArrayBuffer>()->GetBackingStore()->Data() == nullptr;
3246
3247
26
  return napi_clear_last_error(env);
3248

14034
}