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: 1322 1355 97.6 %
Date: 2020-05-27 22:15:15 Branches: 956 1544 61.9 %

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_TO_NUMBER(env, context, result, src) \
14
  CHECK_TO_TYPE((env), Number, (context), (result), (src), napi_number_expected)
15
16
// n-api defines NAPI_AUTO_LENGHTH as the indicator that a string
17
// is null terminated. For V8 the equivalent is -1. The assert
18
// validates that our cast of NAPI_AUTO_LENGTH results in -1 as
19
// needed by V8.
20
#define CHECK_NEW_FROM_UTF8_LEN(env, result, str, len)                   \
21
  do {                                                                   \
22
    static_assert(static_cast<int>(NAPI_AUTO_LENGTH) == -1,              \
23
                  "Casting NAPI_AUTO_LENGTH to int must result in -1");  \
24
    RETURN_STATUS_IF_FALSE((env),                                        \
25
        (len == NAPI_AUTO_LENGTH) || len <= INT_MAX,                     \
26
        napi_invalid_arg);                                               \
27
    RETURN_STATUS_IF_FALSE((env),                                        \
28
        (str) != nullptr,                                                \
29
        napi_invalid_arg);                                               \
30
    auto str_maybe = v8::String::NewFromUtf8(                            \
31
        (env)->isolate, (str), v8::NewStringType::kInternalized,         \
32
        static_cast<int>(len));                                          \
33
    CHECK_MAYBE_EMPTY((env), str_maybe, napi_generic_failure);           \
34
    (result) = str_maybe.ToLocalChecked();                               \
35
  } while (0)
36
37
#define CHECK_NEW_FROM_UTF8(env, result, str) \
38
  CHECK_NEW_FROM_UTF8_LEN((env), (result), (str), NAPI_AUTO_LENGTH)
39
40
#define CREATE_TYPED_ARRAY(                                                    \
41
    env, type, size_of_element, buffer, byte_offset, length, out)              \
42
  do {                                                                         \
43
    if ((size_of_element) > 1) {                                               \
44
      THROW_RANGE_ERROR_IF_FALSE(                                              \
45
          (env), (byte_offset) % (size_of_element) == 0,                       \
46
          "ERR_NAPI_INVALID_TYPEDARRAY_ALIGNMENT",                             \
47
          "start offset of "#type" should be a multiple of "#size_of_element); \
48
    }                                                                          \
49
    THROW_RANGE_ERROR_IF_FALSE((env), (length) * (size_of_element) +           \
50
        (byte_offset) <= buffer->ByteLength(),                                 \
51
        "ERR_NAPI_INVALID_TYPEDARRAY_LENGTH",                                  \
52
        "Invalid typed array length");                                         \
53
    (out) = v8::type::New((buffer), (byte_offset), (length));                  \
54
  } while (0)
55
56
namespace v8impl {
57
58
namespace {
59
60
inline static napi_status
61
408
V8NameFromPropertyDescriptor(napi_env env,
62
                             const napi_property_descriptor* p,
63
                             v8::Local<v8::Name>* result) {
64
408
  if (p->utf8name != nullptr) {
65

1218
    CHECK_NEW_FROM_UTF8(env, *result, p->utf8name);
66
  } else {
67
    v8::Local<v8::Value> property_value =
68
2
      v8impl::V8LocalValueFromJsValue(p->name);
69
70
2
    RETURN_STATUS_IF_FALSE(env, property_value->IsName(), napi_name_expected);
71
2
    *result = property_value.As<v8::Name>();
72
  }
73
74
408
  return napi_ok;
75
}
76
77
// convert from n-api property attributes to v8::PropertyAttribute
78
21
inline static v8::PropertyAttribute V8PropertyAttributesFromDescriptor(
79
    const napi_property_descriptor* descriptor) {
80
21
  unsigned int attribute_flags = v8::PropertyAttribute::None;
81
82
  // The napi_writable attribute is ignored for accessor descriptors, but
83
  // V8 would throw `TypeError`s on assignment with nonexistence of a setter.
84

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


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

11429
    if ((reference->RefCount() != 0) ||
242

4998
        (reference->_delete_self) ||
243
1010
        (reference->_finalize_ran)) {
244
2982
      delete reference;
245
    } else {
246
      // defer until finalizer runs as
247
      // it may alread be queued
248
1006
      reference->_delete_self = true;
249
    }
250
3988
  }
251
252
1
  inline uint32_t Ref() {
253
1
    return ++_refcount;
254
  }
255
256
2
  inline uint32_t Unref() {
257
2
    if (_refcount == 0) {
258
        return 0;
259
    }
260
2
    return --_refcount;
261
  }
262
263
6972
  inline uint32_t RefCount() {
264
6972
    return _refcount;
265
  }
266
267
 protected:
268
2447
  inline void Finalize(bool is_env_teardown = false) override {
269
2447
    if (_finalize_callback != nullptr) {
270
4311
      _env->CallIntoModuleThrow([&](napi_env env) {
271
1437
        _finalize_callback(
272
            env,
273
            _finalize_data,
274
1437
            _finalize_hint);
275
2874
      });
276
    }
277
278
    // this is safe because if a request to delete the reference
279
    // is made in the finalize_callback it will defer deletion
280
    // to this block and set _delete_self to true
281

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

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


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




3072
  NAPI_PREAMBLE(env);
642

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

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

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

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

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

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


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


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


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


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

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

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


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

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

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


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

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


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

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


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

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


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

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


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

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


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

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

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


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

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

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


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

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

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


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

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


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

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


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

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


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

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


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

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

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


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


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


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

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

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

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

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


36
  NAPI_PREAMBLE(env);
1599
12
  CHECK_ARG(env, words);
1600
12
  CHECK_ARG(env, result);
1601
1602
12
  v8::Local<v8::Context> context = env->context();
1603
1604
12
  RETURN_STATUS_IF_FALSE(
1605
      env, word_count <= INT_MAX, napi_invalid_arg);
1606
1607
  v8::MaybeLocal<v8::BigInt> b = v8::BigInt::NewFromWords(
1608
11
      context, sign_bit, word_count, words);
1609
1610
11
  if (try_catch.HasCaught()) {
1611
    return napi_set_last_error(env, napi_pending_exception);
1612
  } else {
1613
11
    CHECK_MAYBE_EMPTY(env, b, napi_generic_failure);
1614
22
    *result = v8impl::JsValueFromV8LocalValue(b.ToLocalChecked());
1615
11
    return napi_clear_last_error(env);
1616
  }
1617
}
1618
1619
1284
napi_status napi_get_boolean(napi_env env, bool value, napi_value* result) {
1620
1284
  CHECK_ENV(env);
1621
1284
  CHECK_ARG(env, result);
1622
1623
1284
  v8::Isolate* isolate = env->isolate;
1624
1625
1284
  if (value) {
1626
1456
    *result = v8impl::JsValueFromV8LocalValue(v8::True(isolate));
1627
  } else {
1628
1112
    *result = v8impl::JsValueFromV8LocalValue(v8::False(isolate));
1629
  }
1630
1631
1284
  return napi_clear_last_error(env);
1632
}
1633
1634
13
napi_status napi_create_symbol(napi_env env,
1635
                               napi_value description,
1636
                               napi_value* result) {
1637
13
  CHECK_ENV(env);
1638
13
  CHECK_ARG(env, result);
1639
1640
13
  v8::Isolate* isolate = env->isolate;
1641
1642
13
  if (description == nullptr) {
1643
6
    *result = v8impl::JsValueFromV8LocalValue(v8::Symbol::New(isolate));
1644
  } else {
1645
11
    v8::Local<v8::Value> desc = v8impl::V8LocalValueFromJsValue(description);
1646
22
    RETURN_STATUS_IF_FALSE(env, desc->IsString(), napi_string_expected);
1647
1648
33
    *result = v8impl::JsValueFromV8LocalValue(
1649
      v8::Symbol::New(isolate, desc.As<v8::String>()));
1650
  }
1651
1652
13
  return napi_clear_last_error(env);
1653
}
1654
1655
193
static inline napi_status set_error_code(napi_env env,
1656
                                         v8::Local<v8::Value> error,
1657
                                         napi_value code,
1658
                                         const char* code_cstring) {
1659

193
  if ((code != nullptr) || (code_cstring != nullptr)) {
1660
115
    v8::Local<v8::Context> context = env->context();
1661
115
    v8::Local<v8::Object> err_object = error.As<v8::Object>();
1662
1663
115
    v8::Local<v8::Value> code_value = v8impl::V8LocalValueFromJsValue(code);
1664
115
    if (code != nullptr) {
1665
4
      code_value = v8impl::V8LocalValueFromJsValue(code);
1666
8
      RETURN_STATUS_IF_FALSE(env, code_value->IsString(), napi_string_expected);
1667
    } else {
1668

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


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

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


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


229
  NAPI_PREAMBLE(env);
1912
1913
73
  v8::Isolate* isolate = env->isolate;
1914
  v8::Local<v8::String> str;
1915

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


270
  NAPI_PREAMBLE(env);
1931
1932
90
  v8::Isolate* isolate = env->isolate;
1933
  v8::Local<v8::String> str;
1934

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


66
  NAPI_PREAMBLE(env);
1950
1951
22
  v8::Isolate* isolate = env->isolate;
1952
  v8::Local<v8::String> str;
1953

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

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


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




103
GEN_COERCE_FUNCTION(NUMBER, Number, number)
2307




105
GEN_COERCE_FUNCTION(OBJECT, Object, object)
2308




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


18
  NAPI_PREAMBLE(env);
2340
6
  CHECK_ARG(env, result);
2341
2342
6
  v8::Isolate* isolate = env->isolate;
2343
2344
6
  v8::Local<v8::Value> external_value = v8::External::New(isolate, data);
2345
2346
  // The Reference object will delete itself after invoking the finalizer
2347
  // callback.
2348
  v8impl::Reference::New(env,
2349
      external_value,
2350
      0,
2351
      true,
2352
      finalize_cb,
2353
      data,
2354
6
      finalize_hint);
2355
2356
6
  *result = v8impl::JsValueFromV8LocalValue(external_value);
2357
2358
6
  return napi_clear_last_error(env);
2359
}
2360
2361
2
napi_status napi_get_value_external(napi_env env,
2362
                                    napi_value value,
2363
                                    void** result) {
2364
2
  CHECK_ENV(env);
2365
2
  CHECK_ARG(env, value);
2366
2
  CHECK_ARG(env, result);
2367
2368
2
  v8::Local<v8::Value> val = v8impl::V8LocalValueFromJsValue(value);
2369
2
  RETURN_STATUS_IF_FALSE(env, val->IsExternal(), napi_invalid_arg);
2370
2371
2
  v8::Local<v8::External> external_value = val.As<v8::External>();
2372
4
  *result = external_value->Value();
2373
2374
2
  return napi_clear_last_error(env);
2375
}
2376
2377
// Set initial_refcount to 0 for a weak reference, >0 for a strong reference.
2378
1538
napi_status napi_create_reference(napi_env env,
2379
                                  napi_value value,
2380
                                  uint32_t initial_refcount,
2381
                                  napi_ref* result) {
2382
  // Omit NAPI_PREAMBLE and GET_RETURN_STATUS because V8 calls here cannot throw
2383
  // JS exceptions.
2384
1538
  CHECK_ENV(env);
2385
1538
  CHECK_ARG(env, value);
2386
1538
  CHECK_ARG(env, result);
2387
2388
1538
  v8::Local<v8::Value> v8_value = v8impl::V8LocalValueFromJsValue(value);
2389
2390

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


21
  NAPI_PREAMBLE(env);
2561
7
  CHECK_ARG(env, constructor);
2562
7
  if (argc > 0) {
2563
7
    CHECK_ARG(env, argv);
2564
  }
2565
7
  CHECK_ARG(env, result);
2566
2567
7
  v8::Local<v8::Context> context = env->context();
2568
2569
  v8::Local<v8::Function> ctor;
2570

21
  CHECK_TO_FUNCTION(env, ctor, constructor);
2571
2572
  auto maybe = ctor->NewInstance(context, argc,
2573
14
    reinterpret_cast<v8::Local<v8::Value>*>(const_cast<napi_value*>(argv)));
2574
2575
7
  CHECK_MAYBE_EMPTY(env, maybe, napi_generic_failure);
2576
2577
14
  *result = v8impl::JsValueFromV8LocalValue(maybe.ToLocalChecked());
2578
7
  return GET_RETURN_STATUS(env);
2579
}
2580
2581
2278
napi_status napi_instanceof(napi_env env,
2582
                            napi_value object,
2583
                            napi_value constructor,
2584
                            bool* result) {
2585


6834
  NAPI_PREAMBLE(env);
2586
2278
  CHECK_ARG(env, object);
2587
2278
  CHECK_ARG(env, result);
2588
2589
2278
  *result = false;
2590
2591
  v8::Local<v8::Object> ctor;
2592
2278
  v8::Local<v8::Context> context = env->context();
2593
2594

9112
  CHECK_TO_OBJECT(env, context, ctor, constructor);
2595
2596
2278
  if (!ctor->IsFunction()) {
2597
    napi_throw_type_error(env,
2598
                          "ERR_NAPI_CONS_FUNCTION",
2599
88
                          "Constructor must be a function");
2600
2601
88
    return napi_set_last_error(env, napi_function_expected);
2602
  }
2603
2604
2190
  napi_status status = napi_generic_failure;
2605
2606
2190
  v8::Local<v8::Value> val = v8impl::V8LocalValueFromJsValue(object);
2607
2190
  auto maybe_result = val->InstanceOf(context, ctor);
2608
2190
  CHECK_MAYBE_NOTHING(env, maybe_result, status);
2609
2332
  *result = maybe_result.FromJust();
2610
1166
  return GET_RETURN_STATUS(env);
2611
}
2612
2613
// Methods to support catching exceptions
2614
1228
napi_status napi_is_exception_pending(napi_env env, bool* result) {
2615
  // NAPI_PREAMBLE is not used here: this function must execute when there is a
2616
  // pending exception.
2617
1228
  CHECK_ENV(env);
2618
1228
  CHECK_ARG(env, result);
2619
2620
2456
  *result = !env->last_exception.IsEmpty();
2621
1228
  return napi_clear_last_error(env);
2622
}
2623
2624
1
napi_status napi_get_and_clear_last_exception(napi_env env,
2625
                                              napi_value* result) {
2626
  // NAPI_PREAMBLE is not used here: this function must execute when there is a
2627
  // pending exception.
2628
1
  CHECK_ENV(env);
2629
1
  CHECK_ARG(env, result);
2630
2631
2
  if (env->last_exception.IsEmpty()) {
2632
    return napi_get_undefined(env, result);
2633
  } else {
2634
2
    *result = v8impl::JsValueFromV8LocalValue(
2635
1
      v8::Local<v8::Value>::New(env->isolate, env->last_exception));
2636
1
    env->last_exception.Reset();
2637
  }
2638
2639
1
  return napi_clear_last_error(env);
2640
}
2641
2642
57
napi_status napi_is_arraybuffer(napi_env env, napi_value value, bool* result) {
2643
57
  CHECK_ENV(env);
2644
57
  CHECK_ARG(env, value);
2645
57
  CHECK_ARG(env, result);
2646
2647
57
  v8::Local<v8::Value> val = v8impl::V8LocalValueFromJsValue(value);
2648
114
  *result = val->IsArrayBuffer();
2649
2650
57
  return napi_clear_last_error(env);
2651
}
2652
2653
2
napi_status napi_create_arraybuffer(napi_env env,
2654
                                    size_t byte_length,
2655
                                    void** data,
2656
                                    napi_value* result) {
2657


6
  NAPI_PREAMBLE(env);
2658
2
  CHECK_ARG(env, result);
2659
2660
2
  v8::Isolate* isolate = env->isolate;
2661
  v8::Local<v8::ArrayBuffer> buffer =
2662
2
      v8::ArrayBuffer::New(isolate, byte_length);
2663
2664
  // Optionally return a pointer to the buffer's data, to avoid another call to
2665
  // retrieve it.
2666
2
  if (data != nullptr) {
2667
2
    *data = buffer->GetBackingStore()->Data();
2668
  }
2669
2670
4
  *result = v8impl::JsValueFromV8LocalValue(buffer);
2671
2
  return GET_RETURN_STATUS(env);
2672
}
2673
2674
6
napi_status napi_create_external_arraybuffer(napi_env env,
2675
                                             void* external_data,
2676
                                             size_t byte_length,
2677
                                             napi_finalize finalize_cb,
2678
                                             void* finalize_hint,
2679
                                             napi_value* result) {
2680
  // The API contract here is that the cleanup function runs on the JS thread,
2681
  // and is able to use napi_env. Implementing that properly is hard, so use the
2682
  // `Buffer` variant for easier implementation.
2683
  napi_value buffer;
2684
  napi_status status;
2685
  status = napi_create_external_buffer(
2686
      env,
2687
      byte_length,
2688
      external_data,
2689
      finalize_cb,
2690
      finalize_hint,
2691
6
      &buffer);
2692
6
  if (status != napi_ok) return status;
2693
6
  return napi_get_typedarray_info(
2694
      env,
2695
      buffer,
2696
      nullptr,
2697
      nullptr,
2698
      nullptr,
2699
      result,
2700
6
      nullptr);
2701
}
2702
2703
2
napi_status napi_get_arraybuffer_info(napi_env env,
2704
                                      napi_value arraybuffer,
2705
                                      void** data,
2706
                                      size_t* byte_length) {
2707
2
  CHECK_ENV(env);
2708
2
  CHECK_ARG(env, arraybuffer);
2709
2710
2
  v8::Local<v8::Value> value = v8impl::V8LocalValueFromJsValue(arraybuffer);
2711
2
  RETURN_STATUS_IF_FALSE(env, value->IsArrayBuffer(), napi_invalid_arg);
2712
2713
  std::shared_ptr<v8::BackingStore> backing_store =
2714
6
      value.As<v8::ArrayBuffer>()->GetBackingStore();
2715
2716
2
  if (data != nullptr) {
2717
2
    *data = backing_store->Data();
2718
  }
2719
2720
2
  if (byte_length != nullptr) {
2721
2
    *byte_length = backing_store->ByteLength();
2722
  }
2723
2724
2
  return napi_clear_last_error(env);
2725
}
2726
2727
44
napi_status napi_is_typedarray(napi_env env, napi_value value, bool* result) {
2728
44
  CHECK_ENV(env);
2729
44
  CHECK_ARG(env, value);
2730
44
  CHECK_ARG(env, result);
2731
2732
44
  v8::Local<v8::Value> val = v8impl::V8LocalValueFromJsValue(value);
2733
88
  *result = val->IsTypedArray();
2734
2735
44
  return napi_clear_last_error(env);
2736
}
2737
2738
34
napi_status napi_create_typedarray(napi_env env,
2739
                                   napi_typedarray_type type,
2740
                                   size_t length,
2741
                                   napi_value arraybuffer,
2742
                                   size_t byte_offset,
2743
                                   napi_value* result) {
2744


102
  NAPI_PREAMBLE(env);
2745
34
  CHECK_ARG(env, arraybuffer);
2746
34
  CHECK_ARG(env, result);
2747
2748
34
  v8::Local<v8::Value> value = v8impl::V8LocalValueFromJsValue(arraybuffer);
2749
34
  RETURN_STATUS_IF_FALSE(env, value->IsArrayBuffer(), napi_invalid_arg);
2750
2751
34
  v8::Local<v8::ArrayBuffer> buffer = value.As<v8::ArrayBuffer>();
2752
  v8::Local<v8::TypedArray> typedArray;
2753
2754



34
  switch (type) {
2755
    case napi_int8_array:
2756
11
      CREATE_TYPED_ARRAY(
2757
          env, Int8Array, 1, buffer, byte_offset, length, typedArray);
2758
3
      break;
2759
    case napi_uint8_array:
2760
8
      CREATE_TYPED_ARRAY(
2761
          env, Uint8Array, 1, buffer, byte_offset, length, typedArray);
2762
2
      break;
2763
    case napi_uint8_clamped_array:
2764
5
      CREATE_TYPED_ARRAY(
2765
          env, Uint8ClampedArray, 1, buffer, byte_offset, length, typedArray);
2766
1
      break;
2767
    case napi_int16_array:
2768

6
      CREATE_TYPED_ARRAY(
2769
          env, Int16Array, 2, buffer, byte_offset, length, typedArray);
2770
1
      break;
2771
    case napi_uint16_array:
2772

6
      CREATE_TYPED_ARRAY(
2773
          env, Uint16Array, 2, buffer, byte_offset, length, typedArray);
2774
1
      break;
2775
    case napi_int32_array:
2776

6
      CREATE_TYPED_ARRAY(
2777
          env, Int32Array, 4, buffer, byte_offset, length, typedArray);
2778
1
      break;
2779
    case napi_uint32_array:
2780

6
      CREATE_TYPED_ARRAY(
2781
          env, Uint32Array, 4, buffer, byte_offset, length, typedArray);
2782
1
      break;
2783
    case napi_float32_array:
2784

6
      CREATE_TYPED_ARRAY(
2785
          env, Float32Array, 4, buffer, byte_offset, length, typedArray);
2786
1
      break;
2787
    case napi_float64_array:
2788

9
      CREATE_TYPED_ARRAY(
2789
          env, Float64Array, 8, buffer, byte_offset, length, typedArray);
2790
2
      break;
2791
    case napi_bigint64_array:
2792

6
      CREATE_TYPED_ARRAY(
2793
          env, BigInt64Array, 8, buffer, byte_offset, length, typedArray);
2794
1
      break;
2795
    case napi_biguint64_array:
2796

6
      CREATE_TYPED_ARRAY(
2797
          env, BigUint64Array, 8, buffer, byte_offset, length, typedArray);
2798
1
      break;
2799
    default:
2800
      return napi_set_last_error(env, napi_invalid_arg);
2801
  }
2802
2803
30
  *result = v8impl::JsValueFromV8LocalValue(typedArray);
2804
15
  return GET_RETURN_STATUS(env);
2805
}
2806
2807
50
napi_status napi_get_typedarray_info(napi_env env,
2808
                                     napi_value typedarray,
2809
                                     napi_typedarray_type* type,
2810
                                     size_t* length,
2811
                                     void** data,
2812
                                     napi_value* arraybuffer,
2813
                                     size_t* byte_offset) {
2814
50
  CHECK_ENV(env);
2815
50
  CHECK_ARG(env, typedarray);
2816
2817
50
  v8::Local<v8::Value> value = v8impl::V8LocalValueFromJsValue(typedarray);
2818
50
  RETURN_STATUS_IF_FALSE(env, value->IsTypedArray(), napi_invalid_arg);
2819
2820
50
  v8::Local<v8::TypedArray> array = value.As<v8::TypedArray>();
2821
2822
50
  if (type != nullptr) {
2823
32
    if (value->IsInt8Array()) {
2824
2
      *type = napi_int8_array;
2825
30
    } else if (value->IsUint8Array()) {
2826
3
      *type = napi_uint8_array;
2827
27
    } else if (value->IsUint8ClampedArray()) {
2828
2
      *type = napi_uint8_clamped_array;
2829
25
    } else if (value->IsInt16Array()) {
2830
3
      *type = napi_int16_array;
2831
22
    } else if (value->IsUint16Array()) {
2832
3
      *type = napi_uint16_array;
2833
19
    } else if (value->IsInt32Array()) {
2834
3
      *type = napi_int32_array;
2835
16
    } else if (value->IsUint32Array()) {
2836
3
      *type = napi_uint32_array;
2837
13
    } else if (value->IsFloat32Array()) {
2838
3
      *type = napi_float32_array;
2839
10
    } else if (value->IsFloat64Array()) {
2840
4
      *type = napi_float64_array;
2841
6
    } else if (value->IsBigInt64Array()) {
2842
3
      *type = napi_bigint64_array;
2843
3
    } else if (value->IsBigUint64Array()) {
2844
3
      *type = napi_biguint64_array;
2845
    }
2846
  }
2847
2848
50
  if (length != nullptr) {
2849
32
    *length = array->Length();
2850
  }
2851
2852
  v8::Local<v8::ArrayBuffer> buffer;
2853

50
  if (data != nullptr || arraybuffer != nullptr) {
2854
    // Calling Buffer() may have the side effect of allocating the buffer,
2855
    // so only do this when it’s needed.
2856
50
    buffer = array->Buffer();
2857
  }
2858
2859
50
  if (data != nullptr) {
2860
    *data = static_cast<uint8_t*>(buffer->GetBackingStore()->Data()) +
2861
            array->ByteOffset();
2862
  }
2863
2864
50
  if (arraybuffer != nullptr) {
2865
50
    *arraybuffer = v8impl::JsValueFromV8LocalValue(buffer);
2866
  }
2867
2868
50
  if (byte_offset != nullptr) {
2869
32
    *byte_offset = array->ByteOffset();
2870
  }
2871
2872
50
  return napi_clear_last_error(env);
2873
}
2874
2875
2
napi_status napi_create_dataview(napi_env env,
2876
                                 size_t byte_length,
2877
                                 napi_value arraybuffer,
2878
                                 size_t byte_offset,
2879
                                 napi_value* result) {
2880


6
  NAPI_PREAMBLE(env);
2881
2
  CHECK_ARG(env, arraybuffer);
2882
2
  CHECK_ARG(env, result);
2883
2884
2
  v8::Local<v8::Value> value = v8impl::V8LocalValueFromJsValue(arraybuffer);
2885
2
  RETURN_STATUS_IF_FALSE(env, value->IsArrayBuffer(), napi_invalid_arg);
2886
2887
2
  v8::Local<v8::ArrayBuffer> buffer = value.As<v8::ArrayBuffer>();
2888
4
  if (byte_length + byte_offset > buffer->ByteLength()) {
2889
    napi_throw_range_error(
2890
        env,
2891
        "ERR_NAPI_INVALID_DATAVIEW_ARGS",
2892
        "byte_offset + byte_length should be less than or "
2893
1
        "equal to the size in bytes of the array passed in");
2894
1
    return napi_set_last_error(env, napi_pending_exception);
2895
  }
2896
  v8::Local<v8::DataView> DataView = v8::DataView::New(buffer, byte_offset,
2897
1
                                                       byte_length);
2898
2899
2
  *result = v8impl::JsValueFromV8LocalValue(DataView);
2900
1
  return GET_RETURN_STATUS(env);
2901
}
2902
2903
1
napi_status napi_is_dataview(napi_env env, napi_value value, bool* result) {
2904
1
  CHECK_ENV(env);
2905
1
  CHECK_ARG(env, value);
2906
1
  CHECK_ARG(env, result);
2907
2908
1
  v8::Local<v8::Value> val = v8impl::V8LocalValueFromJsValue(value);
2909
2
  *result = val->IsDataView();
2910
2911
1
  return napi_clear_last_error(env);
2912
}
2913
2914
1
napi_status napi_get_dataview_info(napi_env env,
2915
                                   napi_value dataview,
2916
                                   size_t* byte_length,
2917
                                   void** data,
2918
                                   napi_value* arraybuffer,
2919
                                   size_t* byte_offset) {
2920
1
  CHECK_ENV(env);
2921
1
  CHECK_ARG(env, dataview);
2922
2923
1
  v8::Local<v8::Value> value = v8impl::V8LocalValueFromJsValue(dataview);
2924
1
  RETURN_STATUS_IF_FALSE(env, value->IsDataView(), napi_invalid_arg);
2925
2926
1
  v8::Local<v8::DataView> array = value.As<v8::DataView>();
2927
2928
1
  if (byte_length != nullptr) {
2929
1
    *byte_length = array->ByteLength();
2930
  }
2931
2932
  v8::Local<v8::ArrayBuffer> buffer;
2933

1
  if (data != nullptr || arraybuffer != nullptr) {
2934
    // Calling Buffer() may have the side effect of allocating the buffer,
2935
    // so only do this when it’s needed.
2936
1
    buffer = array->Buffer();
2937
  }
2938
2939
1
  if (data != nullptr) {
2940
    *data = static_cast<uint8_t*>(buffer->GetBackingStore()->Data()) +
2941
            array->ByteOffset();
2942
  }
2943
2944
1
  if (arraybuffer != nullptr) {
2945
1
    *arraybuffer = v8impl::JsValueFromV8LocalValue(buffer);
2946
  }
2947
2948
1
  if (byte_offset != nullptr) {
2949
1
    *byte_offset = array->ByteOffset();
2950
  }
2951
2952
1
  return napi_clear_last_error(env);
2953
}
2954
2955
1
napi_status napi_get_version(napi_env env, uint32_t* result) {
2956
1
  CHECK_ENV(env);
2957
1
  CHECK_ARG(env, result);
2958
1
  *result = NAPI_VERSION;
2959
1
  return napi_clear_last_error(env);
2960
}
2961
2962
5
napi_status napi_create_promise(napi_env env,
2963
                                napi_deferred* deferred,
2964
                                napi_value* promise) {
2965


15
  NAPI_PREAMBLE(env);
2966
5
  CHECK_ARG(env, deferred);
2967
5
  CHECK_ARG(env, promise);
2968
2969
5
  auto maybe = v8::Promise::Resolver::New(env->context());
2970
5
  CHECK_MAYBE_EMPTY(env, maybe, napi_generic_failure);
2971
2972
5
  auto v8_resolver = maybe.ToLocalChecked();
2973
10
  auto v8_deferred = new v8impl::Persistent<v8::Value>();
2974
5
  v8_deferred->Reset(env->isolate, v8_resolver);
2975
2976
5
  *deferred = v8impl::JsDeferredFromNodePersistent(v8_deferred);
2977
15
  *promise = v8impl::JsValueFromV8LocalValue(v8_resolver->GetPromise());
2978
5
  return GET_RETURN_STATUS(env);
2979
}
2980
2981
4
napi_status napi_resolve_deferred(napi_env env,
2982
                                  napi_deferred deferred,
2983
                                  napi_value resolution) {
2984
4
  return v8impl::ConcludeDeferred(env, deferred, resolution, true);
2985
}
2986
2987
1
napi_status napi_reject_deferred(napi_env env,
2988
                                 napi_deferred deferred,
2989
                                 napi_value resolution) {
2990
1
  return v8impl::ConcludeDeferred(env, deferred, resolution, false);
2991
}
2992
2993
7
napi_status napi_is_promise(napi_env env,
2994
                            napi_value value,
2995
                            bool* is_promise) {
2996
7
  CHECK_ENV(env);
2997
7
  CHECK_ARG(env, value);
2998
7
  CHECK_ARG(env, is_promise);
2999
3000
14
  *is_promise = v8impl::V8LocalValueFromJsValue(value)->IsPromise();
3001
3002
7
  return napi_clear_last_error(env);
3003
}
3004
3005
1
napi_status napi_create_date(napi_env env,
3006
                             double time,
3007
                             napi_value* result) {
3008


3
  NAPI_PREAMBLE(env);
3009
1
  CHECK_ARG(env, result);
3010
3011
1
  v8::MaybeLocal<v8::Value> maybe_date = v8::Date::New(env->context(), time);
3012
1
  CHECK_MAYBE_EMPTY(env, maybe_date, napi_generic_failure);
3013
3014
2
  *result = v8impl::JsValueFromV8LocalValue(maybe_date.ToLocalChecked());
3015
3016
1
  return GET_RETURN_STATUS(env);
3017
}
3018
3019
7
napi_status napi_is_date(napi_env env,
3020
                         napi_value value,
3021
                         bool* is_date) {
3022
7
  CHECK_ENV(env);
3023
7
  CHECK_ARG(env, value);
3024
7
  CHECK_ARG(env, is_date);
3025
3026
14
  *is_date = v8impl::V8LocalValueFromJsValue(value)->IsDate();
3027
3028
7
  return napi_clear_last_error(env);
3029
}
3030
3031
1
napi_status napi_get_date_value(napi_env env,
3032
                                napi_value value,
3033
                                double* result) {
3034


3
  NAPI_PREAMBLE(env);
3035
1
  CHECK_ARG(env, value);
3036
1
  CHECK_ARG(env, result);
3037
3038
1
  v8::Local<v8::Value> val = v8impl::V8LocalValueFromJsValue(value);
3039
1
  RETURN_STATUS_IF_FALSE(env, val->IsDate(), napi_date_expected);
3040
3041
1
  v8::Local<v8::Date> date = val.As<v8::Date>();
3042
2
  *result = date->ValueOf();
3043
3044
1
  return GET_RETURN_STATUS(env);
3045
}
3046
3047
2
napi_status napi_run_script(napi_env env,
3048
                            napi_value script,
3049
                            napi_value* result) {
3050


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

104
  *result = value->IsArrayBuffer() &&
3162
104
            value.As<v8::ArrayBuffer>()->GetBackingStore()->Data() == nullptr;
3163
3164
26
  return napi_clear_last_error(env);
3165
}