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: 1327 1365 97.2 %
Date: 2020-06-24 22:13:30 Branches: 962 1556 61.8 %

Line Branch Exec Source
1
#include <climits>  // INT_MAX
2
#include <cmath>
3
#include <algorithm>
4
#define NAPI_EXPERIMENTAL
5
#include "env-inl.h"
6
#include "js_native_api_v8.h"
7
#include "js_native_api.h"
8
#include "util-inl.h"
9
10
#define CHECK_MAYBE_NOTHING(env, maybe, status) \
11
  RETURN_STATUS_IF_FALSE((env), !((maybe).IsNothing()), (status))
12
13
#define CHECK_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
410
V8NameFromPropertyDescriptor(napi_env env,
62
                             const napi_property_descriptor* p,
63
                             v8::Local<v8::Name>* result) {
64
410
  if (p->utf8name != nullptr) {
65

1224
    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
410
  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
2992
class RefBase : protected Finalizer, RefTracker {
190
 protected:
191
2990
  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
2990
       : Finalizer(env, finalize_callback, finalize_data, finalize_hint),
198
        _refcount(initial_refcount),
199
2990
        _delete_self(delete_self) {
200
2990
    Link(finalize_callback == nullptr
201
        ? &env->reflist
202
2990
        : &env->finalizing_reflist);
203
2990
  }
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
3992
  static inline void Delete(RefBase* reference) {
240
3992
    reference->Unlink();
241

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

5002
        (reference->_delete_self) ||
243
1010
        (reference->_finalize_ran)) {
244
2986
      delete reference;
245
    } else {
246
      // defer until finalizer runs as
247
      // it may alread be queued
248
1006
      reference->_delete_self = true;
249
    }
250
3992
  }
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
6980
  inline uint32_t RefCount() {
264
6980
    return _refcount;
265
  }
266
267
 protected:
268
2451
  inline void Finalize(bool is_env_teardown = false) override {
269
2451
    if (_finalize_callback != nullptr) {
270
2880
      v8::HandleScope handle_scope(_env->isolate);
271
4320
      _env->CallIntoModule([&](napi_env env) {
272
1440
        _finalize_callback(
273
            env,
274
            _finalize_data,
275
1440
            _finalize_hint);
276
2880
      });
277
    }
278
279
    // this is safe because if a request to delete the reference
280
    // is made in the finalize_callback it will defer deletion
281
    // to this block and set _delete_self to true
282

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

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


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




3075
  NAPI_PREAMBLE(env);
643

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

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

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

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

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

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


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


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


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


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

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

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


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

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

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


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

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


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

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


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

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


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

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


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

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


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

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

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


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

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

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


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

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

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


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

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


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

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


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

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


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

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


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

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

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


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


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


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

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

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

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

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


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

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

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


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

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


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


232
  NAPI_PREAMBLE(env);
1913
1914
74
  v8::Isolate* isolate = env->isolate;
1915
  v8::Local<v8::String> str;
1916

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


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

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


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

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

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


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




103
GEN_COERCE_FUNCTION(NUMBER, Number, number)
2314




105
GEN_COERCE_FUNCTION(OBJECT, Object, object)
2315




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


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

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


21
  NAPI_PREAMBLE(env);
2568
7
  CHECK_ARG(env, constructor);
2569
7
  if (argc > 0) {
2570
7
    CHECK_ARG(env, argv);
2571
  }
2572
7
  CHECK_ARG(env, result);
2573
2574
7
  v8::Local<v8::Context> context = env->context();
2575
2576
  v8::Local<v8::Function> ctor;
2577

21
  CHECK_TO_FUNCTION(env, ctor, constructor);
2578
2579
  auto maybe = ctor->NewInstance(context, argc,
2580
14
    reinterpret_cast<v8::Local<v8::Value>*>(const_cast<napi_value*>(argv)));
2581
2582
7
  CHECK_MAYBE_EMPTY(env, maybe, napi_generic_failure);
2583
2584
14
  *result = v8impl::JsValueFromV8LocalValue(maybe.ToLocalChecked());
2585
7
  return GET_RETURN_STATUS(env);
2586
}
2587
2588
2278
napi_status napi_instanceof(napi_env env,
2589
                            napi_value object,
2590
                            napi_value constructor,
2591
                            bool* result) {
2592


6834
  NAPI_PREAMBLE(env);
2593
2278
  CHECK_ARG(env, object);
2594
2278
  CHECK_ARG(env, result);
2595
2596
2278
  *result = false;
2597
2598
  v8::Local<v8::Object> ctor;
2599
2278
  v8::Local<v8::Context> context = env->context();
2600
2601

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


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


102
  NAPI_PREAMBLE(env);
2752
34
  CHECK_ARG(env, arraybuffer);
2753
34
  CHECK_ARG(env, result);
2754
2755
34
  v8::Local<v8::Value> value = v8impl::V8LocalValueFromJsValue(arraybuffer);
2756
34
  RETURN_STATUS_IF_FALSE(env, value->IsArrayBuffer(), napi_invalid_arg);
2757
2758
34
  v8::Local<v8::ArrayBuffer> buffer = value.As<v8::ArrayBuffer>();
2759
  v8::Local<v8::TypedArray> typedArray;
2760
2761



34
  switch (type) {
2762
    case napi_int8_array:
2763
11
      CREATE_TYPED_ARRAY(
2764
          env, Int8Array, 1, buffer, byte_offset, length, typedArray);
2765
3
      break;
2766
    case napi_uint8_array:
2767
8
      CREATE_TYPED_ARRAY(
2768
          env, Uint8Array, 1, buffer, byte_offset, length, typedArray);
2769
2
      break;
2770
    case napi_uint8_clamped_array:
2771
5
      CREATE_TYPED_ARRAY(
2772
          env, Uint8ClampedArray, 1, buffer, byte_offset, length, typedArray);
2773
1
      break;
2774
    case napi_int16_array:
2775

6
      CREATE_TYPED_ARRAY(
2776
          env, Int16Array, 2, buffer, byte_offset, length, typedArray);
2777
1
      break;
2778
    case napi_uint16_array:
2779

6
      CREATE_TYPED_ARRAY(
2780
          env, Uint16Array, 2, buffer, byte_offset, length, typedArray);
2781
1
      break;
2782
    case napi_int32_array:
2783

6
      CREATE_TYPED_ARRAY(
2784
          env, Int32Array, 4, buffer, byte_offset, length, typedArray);
2785
1
      break;
2786
    case napi_uint32_array:
2787

6
      CREATE_TYPED_ARRAY(
2788
          env, Uint32Array, 4, buffer, byte_offset, length, typedArray);
2789
1
      break;
2790
    case napi_float32_array:
2791

6
      CREATE_TYPED_ARRAY(
2792
          env, Float32Array, 4, buffer, byte_offset, length, typedArray);
2793
1
      break;
2794
    case napi_float64_array:
2795

9
      CREATE_TYPED_ARRAY(
2796
          env, Float64Array, 8, buffer, byte_offset, length, typedArray);
2797
2
      break;
2798
    case napi_bigint64_array:
2799

6
      CREATE_TYPED_ARRAY(
2800
          env, BigInt64Array, 8, buffer, byte_offset, length, typedArray);
2801
1
      break;
2802
    case napi_biguint64_array:
2803

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

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


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

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


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


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


3
  NAPI_PREAMBLE(env);
3042
1
  CHECK_ARG(env, value);
3043
1
  CHECK_ARG(env, result);
3044
3045
1
  v8::Local<v8::Value> val = v8impl::V8LocalValueFromJsValue(value);
3046
1
  RETURN_STATUS_IF_FALSE(env, val->IsDate(), napi_date_expected);
3047
3048
1
  v8::Local<v8::Date> date = val.As<v8::Date>();
3049
2
  *result = date->ValueOf();
3050
3051
1
  return GET_RETURN_STATUS(env);
3052
}
3053
3054
2
napi_status napi_run_script(napi_env env,
3055
                            napi_value script,
3056
                            napi_value* result) {
3057


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

104
  *result = value->IsArrayBuffer() &&
3169
104
            value.As<v8::ArrayBuffer>()->GetBackingStore()->Data() == nullptr;
3170
3171
26
  return napi_clear_last_error(env);
3172
}