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: 1407 1441 97.6 %
Date: 2021-04-25 04:11:48 Branches: 1070 1708 62.6 %

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

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

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


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

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

4052
        (reference->_delete_self) ||
247
1018
        (reference->_finalize_ran)) {
248
3022
      delete reference;
249
    } else {
250
      // defer until finalizer runs as
251
      // it may alread be queued
252
12
      reference->_delete_self = true;
253
    }
254
3034
  }
255
256
3
  inline uint32_t Ref() {
257
3
    return ++_refcount;
258
  }
259
260
3
  inline uint32_t Unref() {
261
3
    if (_refcount == 0) {
262
        return 0;
263
    }
264
3
    return --_refcount;
265
  }
266
267
6531
  inline uint32_t RefCount() {
268
6531
    return _refcount;
269
  }
270
271
 protected:
272
2488
  inline void Finalize(bool is_env_teardown = false) override {
273
    // In addition to being called during environment teardown, this method is
274
    // also the entry point for the garbage collector. During environment
275
    // teardown we have to remove the garbage collector's reference to this
276
    // method so that, if, as part of the user's callback, JS gets executed,
277
    // resulting in a garbage collection pass, this method is not re-entered as
278
    // part of that pass, because that'll cause a double free (as seen in
279
    // https://github.com/nodejs/node/issues/37236).
280
    //
281
    // Since this class does not have access to the V8 persistent reference,
282
    // this method is overridden in the `Reference` class below. Therein the
283
    // weak callback is removed, ensuring that the garbage collector does not
284
    // re-enter this method, and the method chains up to continue the process of
285
    // environment-teardown-induced finalization.
286
287
    // During environment teardown we have to convert a strong reference to
288
    // a weak reference to force the deferring behavior if the user's finalizer
289
    // happens to delete this reference so that the code in this function that
290
    // follows the call to the user's finalizer may safely access variables from
291
    // this instance.
292

2488
    if (is_env_teardown && RefCount() > 0) _refcount = 0;
293
294
2488
    if (_finalize_callback != nullptr) {
295
      // This ensures that we never call the finalizer twice.
296
1470
      napi_finalize fini = _finalize_callback;
297
1470
      _finalize_callback = nullptr;
298
1470
      _env->CallFinalizer(fini, _finalize_data, _finalize_hint);
299
    }
300
301
    // this is safe because if a request to delete the reference
302
    // is made in the finalize_callback it will defer deletion
303
    // to this block and set _delete_self to true
304

2488
    if (_delete_self || is_env_teardown) {
305
1482
      Delete(this);
306
    } else {
307
1006
      _finalize_ran = true;
308
    }
309
2488
  }
310
311
 private:
312
  uint32_t _refcount;
313
  bool _delete_self;
314
};
315
316
class Reference : public RefBase {
317
  using SecondPassCallParameterRef = Reference*;
318
319
 protected:
320
  template <typename... Args>
321
3023
  Reference(napi_env env, v8::Local<v8::Value> value, Args&&... args)
322
15115
      : RefBase(env, std::forward<Args>(args)...),
323
3023
        _persistent(env->isolate, value),
324
21161
        _secondPassParameter(new SecondPassCallParameterRef(this)) {
325
3023
    if (RefCount() == 0) {
326
2485
      SetWeak();
327
    }
328
3023
  }
329
330
 public:
331
3023
  static inline Reference* New(napi_env env,
332
                             v8::Local<v8::Value> value,
333
                             uint32_t initial_refcount,
334
                             bool delete_self,
335
                             napi_finalize finalize_callback = nullptr,
336
                             void* finalize_data = nullptr,
337
                             void* finalize_hint = nullptr) {
338
    return new Reference(env,
339
                         value,
340
                         initial_refcount,
341
                         delete_self,
342
                         finalize_callback,
343
                         finalize_data,
344
3023
                         finalize_hint);
345
  }
346
347
12060
  virtual ~Reference() {
348
    // If the second pass callback is scheduled, it will delete the
349
    // parameter passed to it, otherwise it will never be scheduled
350
    // and we need to delete it here.
351
3015
    if (_secondPassParameter != nullptr) {
352
995
      delete _secondPassParameter;
353
    }
354
6030
  }
355
356
3
  inline uint32_t Ref() {
357
3
    uint32_t refcount = RefBase::Ref();
358
3
    if (refcount == 1) {
359
2
      ClearWeak();
360
    }
361
3
    return refcount;
362
  }
363
364
3
  inline uint32_t Unref() {
365
3
    uint32_t old_refcount = RefCount();
366
3
    uint32_t refcount = RefBase::Unref();
367

3
    if (old_refcount == 1 && refcount == 0) {
368
2
      SetWeak();
369
    }
370
3
    return refcount;
371
  }
372
373
1550
  inline v8::Local<v8::Value> Get() {
374
3100
    if (_persistent.IsEmpty()) {
375
1002
      return v8::Local<v8::Value>();
376
    } else {
377
1096
      return v8::Local<v8::Value>::New(_env->isolate, _persistent);
378
    }
379
  }
380
381
 protected:
382
2481
  inline void Finalize(bool is_env_teardown = false) override {
383
2481
    if (is_env_teardown) env_teardown_finalize_started_ = true;
384

2481
    if (!is_env_teardown && env_teardown_finalize_started_) return;
385
386
    // During env teardown, `~napi_env()` alone is responsible for finalizing.
387
    // Thus, we don't want any stray gc passes to trigger a second call to
388
    // `RefBase::Finalize()`. ClearWeak will ensure that even if the
389
    // gc is in progress no Finalization will be run for this Reference
390
    // by the gc.
391
2481
    if (is_env_teardown) {
392
461
      ClearWeak();
393
    }
394
395
    // Chain up to perform the rest of the finalization.
396
2481
    RefBase::Finalize(is_env_teardown);
397
  }
398
399
 private:
400
  // ClearWeak is marking the Reference so that the gc should not
401
  // collect it, but it is possible that a second pass callback
402
  // may have been scheduled already if we are in shutdown. We clear
403
  // the secondPassParameter so that even if it has been
404
  // secheduled no Finalization will be run.
405
463
  inline void ClearWeak() {
406
926
    if (!_persistent.IsEmpty()) {
407
463
      _persistent.ClearWeak();
408
    }
409
463
    if (_secondPassParameter != nullptr) {
410
463
      *_secondPassParameter = nullptr;
411
    }
412
463
  }
413
414
  // Mark the reference as weak and eligible for collection
415
  // by the gc.
416
2487
  inline void SetWeak() {
417
2487
    if (_secondPassParameter == nullptr) {
418
      // This means that the Reference has already been processed
419
      // by the second pass calback, so its already been Finalized, do
420
      // nothing
421
      return;
422
    }
423
2487
    _persistent.SetWeak(
424
        _secondPassParameter, FinalizeCallback,
425
        v8::WeakCallbackType::kParameter);
426
2487
    *_secondPassParameter = this;
427
  }
428
429
  // The N-API finalizer callback may make calls into the engine. V8's heap is
430
  // not in a consistent state during the weak callback, and therefore it does
431
  // not support calls back into it. However, it provides a mechanism for adding
432
  // a finalizer which may make calls back into the engine by allowing us to
433
  // attach such a second-pass finalizer from the first pass finalizer. Thus,
434
  // we do that here to ensure that the N-API finalizer callback is free to call
435
  // into the engine.
436
2020
  static void FinalizeCallback(
437
      const v8::WeakCallbackInfo<SecondPassCallParameterRef>& data) {
438
2020
    SecondPassCallParameterRef* parameter = data.GetParameter();
439
2020
    Reference* reference = *parameter;
440
2020
    if (reference == nullptr) {
441
      return;
442
    }
443
444
    // The reference must be reset during the first pass.
445
2020
    reference->_persistent.Reset();
446
    // Mark the parameter not delete-able until the second pass callback is
447
    // invoked.
448
2020
    reference->_secondPassParameter = nullptr;
449
450
2020
    data.SetSecondPassCallback(SecondPassCallback);
451
  }
452
453
  // Second pass callbacks are scheduled with platform tasks. At env teardown,
454
  // the tasks may have already be scheduled and we are unable to cancel the
455
  // second pass callback task. We have to make sure that parameter is kept
456
  // alive until the second pass callback is been invoked. In order to do
457
  // this and still allow our code to Finalize/delete the Reference during
458
  // shutdown we have to use a seperately allocated parameter instead
459
  // of a parameter within the Reference object itself. This is what
460
  // is stored in _secondPassParameter and it is alocated in the
461
  // constructor for the Reference.
462
2020
  static void SecondPassCallback(
463
      const v8::WeakCallbackInfo<SecondPassCallParameterRef>& data) {
464
2020
    SecondPassCallParameterRef* parameter = data.GetParameter();
465
2020
    Reference* reference = *parameter;
466
2020
    delete parameter;
467
2020
    if (reference == nullptr) {
468
      // the reference itself has already been deleted so nothing to do
469
      return;
470
    }
471
2020
    reference->Finalize();
472
  }
473
474
  bool env_teardown_finalize_started_ = false;
475
  v8impl::Persistent<v8::Value> _persistent;
476
  SecondPassCallParameterRef* _secondPassParameter;
477
};
478
479
enum UnwrapAction {
480
  KeepWrap,
481
  RemoveWrap
482
};
483
484
35
inline static napi_status Unwrap(napi_env env,
485
                                 napi_value js_object,
486
                                 void** result,
487
                                 UnwrapAction action) {
488


105
  NAPI_PREAMBLE(env);
489
35
  CHECK_ARG(env, js_object);
490
35
  if (action == KeepWrap) {
491
27
    CHECK_ARG(env, result);
492
  }
493
494
35
  v8::Local<v8::Context> context = env->context();
495
496
35
  v8::Local<v8::Value> value = v8impl::V8LocalValueFromJsValue(js_object);
497
35
  RETURN_STATUS_IF_FALSE(env, value->IsObject(), napi_invalid_arg);
498
35
  v8::Local<v8::Object> obj = value.As<v8::Object>();
499
500
105
  auto val = obj->GetPrivate(context, NAPI_PRIVATE_KEY(context, wrapper))
501
35
      .ToLocalChecked();
502
35
  RETURN_STATUS_IF_FALSE(env, val->IsExternal(), napi_invalid_arg);
503
  Reference* reference =
504
70
      static_cast<v8impl::Reference*>(val.As<v8::External>()->Value());
505
506
35
  if (result) {
507
35
    *result = reference->Data();
508
  }
509
510
35
  if (action == RemoveWrap) {
511
24
    CHECK(obj->DeletePrivate(context, NAPI_PRIVATE_KEY(context, wrapper))
512
        .FromJust());
513
8
    Reference::Delete(reference);
514
  }
515
516
35
  return GET_RETURN_STATUS(env);
517
}
518
519
//=== Function napi_callback wrapper =================================
520
521
// Use this data structure to associate callback data with each N-API function
522
// exposed to JavaScript. The structure is stored in a v8::External which gets
523
// passed into our callback wrapper. This reduces the performance impact of
524
// calling through N-API.
525
// Ref: benchmark/misc/function_call
526
// Discussion (incl. perf. data): https://github.com/nodejs/node/pull/21072
527
class CallbackBundle {
528
 public:
529
  // Creates an object to be made available to the static function callback
530
  // wrapper, used to retrieve the native callback function and data pointer.
531
  static inline v8::Local<v8::Value>
532
447
  New(napi_env env, napi_callback cb, void* data) {
533
447
    CallbackBundle* bundle = new CallbackBundle();
534
447
    bundle->cb = cb;
535
447
    bundle->cb_data = data;
536
447
    bundle->env = env;
537
538
447
    v8::Local<v8::Value> cbdata = v8::External::New(env->isolate, bundle);
539
447
    Reference::New(env, cbdata, 0, true, Delete, bundle, nullptr);
540
447
    return cbdata;
541
  }
542
  napi_env       env;      // Necessary to invoke C++ NAPI callback
543
  void*          cb_data;  // The user provided callback data
544
  napi_callback  cb;
545
 private:
546
440
  static void Delete(napi_env env, void* data, void* hint) {
547
440
    CallbackBundle* bundle = static_cast<CallbackBundle*>(data);
548
440
    delete bundle;
549
440
  }
550
};
551
552
// Base class extended by classes that wrap V8 function and property callback
553
// info.
554
class CallbackWrapper {
555
 public:
556
4635
  inline CallbackWrapper(napi_value this_arg, size_t args_length, void* data)
557
4635
      : _this(this_arg), _args_length(args_length), _data(data) {}
558
559
  virtual napi_value GetNewTarget() = 0;
560
  virtual void Args(napi_value* buffer, size_t bufferlength) = 0;
561
  virtual void SetReturnValue(napi_value value) = 0;
562
563
42
  napi_value This() { return _this; }
564
565
4477
  size_t ArgsLength() { return _args_length; }
566
567
6
  void* Data() { return _data; }
568
569
 protected:
570
  const napi_value _this;
571
  const size_t _args_length;
572
  void* _data;
573
};
574
575
class CallbackWrapperBase : public CallbackWrapper {
576
 public:
577
4635
  inline CallbackWrapperBase(const v8::FunctionCallbackInfo<v8::Value>& cbinfo,
578
                             const size_t args_length)
579
4635
      : CallbackWrapper(JsValueFromV8LocalValue(cbinfo.This()),
580
                        args_length,
581
                        nullptr),
582
4635
        _cbinfo(cbinfo) {
583
4635
    _bundle = reinterpret_cast<CallbackBundle*>(
584
13905
        v8::Local<v8::External>::Cast(cbinfo.Data())->Value());
585
4635
    _data = _bundle->cb_data;
586
4635
  }
587
588
 protected:
589
4635
  inline void InvokeCallback() {
590
    napi_callback_info cbinfo_wrapper = reinterpret_cast<napi_callback_info>(
591
4635
        static_cast<CallbackWrapper*>(this));
592
593
    // All other pointers we need are stored in `_bundle`
594
4635
    napi_env env = _bundle->env;
595
4635
    napi_callback cb = _bundle->cb;
596
597
    napi_value result;
598
13905
    env->CallIntoModule([&](napi_env env) {
599
4635
      result = cb(env, cbinfo_wrapper);
600
9270
    });
601
602
4635
    if (result != nullptr) {
603
2809
      this->SetReturnValue(result);
604
    }
605
4635
  }
606
607
  const v8::FunctionCallbackInfo<v8::Value>& _cbinfo;
608
  CallbackBundle* _bundle;
609
};
610
611
class FunctionCallbackWrapper
612
    : public CallbackWrapperBase {
613
 public:
614
4635
  static void Invoke(const v8::FunctionCallbackInfo<v8::Value>& info) {
615
4635
    FunctionCallbackWrapper cbwrapper(info);
616
4635
    cbwrapper.InvokeCallback();
617
4635
  }
618
619
416
  static inline napi_status NewFunction(napi_env env,
620
                                        napi_callback cb,
621
                                        void* cb_data,
622
                                        v8::Local<v8::Function>* result) {
623
416
    v8::Local<v8::Value> cbdata = v8impl::CallbackBundle::New(env, cb, cb_data);
624
416
    RETURN_STATUS_IF_FALSE(env, !cbdata.IsEmpty(), napi_generic_failure);
625
626
    v8::MaybeLocal<v8::Function> maybe_function =
627
416
        v8::Function::New(env->context(), Invoke, cbdata);
628
416
    CHECK_MAYBE_EMPTY(env, maybe_function, napi_generic_failure);
629
630
416
    *result = maybe_function.ToLocalChecked();
631
416
    return napi_clear_last_error(env);
632
  }
633
634
31
  static inline napi_status NewTemplate(napi_env env,
635
                    napi_callback cb,
636
                    void* cb_data,
637
                    v8::Local<v8::FunctionTemplate>* result,
638
                    v8::Local<v8::Signature> sig = v8::Local<v8::Signature>()) {
639
31
    v8::Local<v8::Value> cbdata = v8impl::CallbackBundle::New(env, cb, cb_data);
640
31
    RETURN_STATUS_IF_FALSE(env, !cbdata.IsEmpty(), napi_generic_failure);
641
642
31
    *result = v8::FunctionTemplate::New(env->isolate, Invoke, cbdata, sig);
643
31
    return napi_clear_last_error(env);
644
  }
645
646
4635
  explicit FunctionCallbackWrapper(
647
      const v8::FunctionCallbackInfo<v8::Value>& cbinfo)
648
9270
      : CallbackWrapperBase(cbinfo, cbinfo.Length()) {}
649
650
8
  napi_value GetNewTarget() override {
651
16
    if (_cbinfo.IsConstructCall()) {
652
14
      return v8impl::JsValueFromV8LocalValue(_cbinfo.NewTarget());
653
    } else {
654
1
      return nullptr;
655
    }
656
  }
657
658
  /*virtual*/
659
4465
  void Args(napi_value* buffer, size_t buffer_length) override {
660
4465
    size_t i = 0;
661
4465
    size_t min = std::min(buffer_length, _args_length);
662
663
18545
    for (; i < min; i += 1) {
664
14080
      buffer[i] = v8impl::JsValueFromV8LocalValue(_cbinfo[i]);
665
    }
666
667
4465
    if (i < buffer_length) {
668
      napi_value undefined =
669
75
          v8impl::JsValueFromV8LocalValue(v8::Undefined(_cbinfo.GetIsolate()));
670
181
      for (; i < buffer_length; i += 1) {
671
78
        buffer[i] = undefined;
672
      }
673
    }
674
4465
  }
675
676
  /*virtual*/
677
2809
  void SetReturnValue(napi_value value) override {
678
2809
    v8::Local<v8::Value> val = v8impl::V8LocalValueFromJsValue(value);
679
8427
    _cbinfo.GetReturnValue().Set(val);
680
2809
  }
681
};
682
683
enum WrapType {
684
  retrievable,
685
  anonymous
686
};
687
688
template <WrapType wrap_type>
689
1031
inline napi_status Wrap(napi_env env,
690
                        napi_value js_object,
691
                        void* native_object,
692
                        napi_finalize finalize_cb,
693
                        void* finalize_hint,
694
                        napi_ref* result) {
695




3093
  NAPI_PREAMBLE(env);
696

1031
  CHECK_ARG(env, js_object);
697
698
1031
  v8::Local<v8::Context> context = env->context();
699
700
1031
  v8::Local<v8::Value> value = v8impl::V8LocalValueFromJsValue(js_object);
701

1031
  RETURN_STATUS_IF_FALSE(env, value->IsObject(), napi_invalid_arg);
702
1031
  v8::Local<v8::Object> obj = value.As<v8::Object>();
703
704
  if (wrap_type == retrievable) {
705
    // If we've already wrapped this object, we error out.
706
3084
    RETURN_STATUS_IF_FALSE(env,
707
        !obj->HasPrivate(context, NAPI_PRIVATE_KEY(context, wrapper))
708
            .FromJust(),
709
        napi_invalid_arg);
710
  } else if (wrap_type == anonymous) {
711
    // If no finalize callback is provided, we error out.
712
3
    CHECK_ARG(env, finalize_cb);
713
  }
714
715
1030
  v8impl::Reference* reference = nullptr;
716

1030
  if (result != nullptr) {
717
    // The returned reference should be deleted via napi_delete_reference()
718
    // ONLY in response to the finalize callback invocation. (If it is deleted
719
    // before then, then the finalize callback will never be invoked.)
720
    // Therefore a finalize callback is required when returning a reference.
721

11
    CHECK_ARG(env, finalize_cb);
722
22
    reference = v8impl::Reference::New(
723
        env, obj, 0, false, finalize_cb, native_object, finalize_hint);
724
11
    *result = reinterpret_cast<napi_ref>(reference);
725
  } else {
726
    // Create a self-deleting reference.
727

2038
    reference = v8impl::Reference::New(env, obj, 0, true, finalize_cb,
728
1019
        native_object, finalize_cb == nullptr ? nullptr : finalize_hint);
729
  }
730
731
  if (wrap_type == retrievable) {
732
4108
    CHECK(obj->SetPrivate(context, NAPI_PRIVATE_KEY(context, wrapper),
733
          v8::External::New(env->isolate, reference)).FromJust());
734
  }
735
736

1030
  return GET_RETURN_STATUS(env);
737
}
738
739
}  // end of anonymous namespace
740
741
}  // end of namespace v8impl
742
743
// Warning: Keep in-sync with napi_status enum
744
static
745
const char* error_messages[] = {nullptr,
746
                                "Invalid argument",
747
                                "An object was expected",
748
                                "A string was expected",
749
                                "A string or symbol was expected",
750
                                "A function was expected",
751
                                "A number was expected",
752
                                "A boolean was expected",
753
                                "An array was expected",
754
                                "Unknown failure",
755
                                "An exception is pending",
756
                                "The async work item was cancelled",
757
                                "napi_escape_handle already called on scope",
758
                                "Invalid handle scope usage",
759
                                "Invalid callback scope usage",
760
                                "Thread-safe function queue is full",
761
                                "Thread-safe function handle is closing",
762
                                "A bigint was expected",
763
                                "A date was expected",
764
                                "An arraybuffer was expected",
765
                                "A detachable arraybuffer was expected",
766
                                "Main thread would deadlock",
767
};
768
769
1300
napi_status napi_get_last_error_info(napi_env env,
770
                                     const napi_extended_error_info** result) {
771
1300
  CHECK_ENV(env);
772
1300
  CHECK_ARG(env, result);
773
774
  // The value of the constant below must be updated to reference the last
775
  // message in the `napi_status` enum each time a new error message is added.
776
  // We don't have a napi_status_last as this would result in an ABI
777
  // change each time a message was added.
778
1300
  const int last_status = napi_would_deadlock;
779
780
  static_assert(
781
      NAPI_ARRAYSIZE(error_messages) == last_status + 1,
782
      "Count of error messages must match count of error values");
783
1300
  CHECK_LE(env->last_error.error_code, last_status);
784
785
  // Wait until someone requests the last error information to fetch the error
786
  // message string
787
2600
  env->last_error.error_message =
788
1300
      error_messages[env->last_error.error_code];
789
790
1300
  *result = &(env->last_error);
791
1300
  return napi_ok;
792
}
793
794
15
napi_status napi_create_function(napi_env env,
795
                                 const char* utf8name,
796
                                 size_t length,
797
                                 napi_callback cb,
798
                                 void* callback_data,
799
                                 napi_value* result) {
800


45
  NAPI_PREAMBLE(env);
801
15
  CHECK_ARG(env, result);
802
15
  CHECK_ARG(env, cb);
803
804
  v8::Local<v8::Function> return_value;
805
15
  v8::EscapableHandleScope scope(env->isolate);
806
  v8::Local<v8::Function> fn;
807
15
  STATUS_CALL(v8impl::FunctionCallbackWrapper::NewFunction(
808
      env, cb, callback_data, &fn));
809
15
  return_value = scope.Escape(fn);
810
811
15
  if (utf8name != nullptr) {
812
    v8::Local<v8::String> name_string;
813

3
    CHECK_NEW_FROM_UTF8_LEN(env, name_string, utf8name, length);
814
3
    return_value->SetName(name_string);
815
6
  }
816
3
817
30
  *result = v8impl::JsValueFromV8LocalValue(return_value);
818
819
15
  return GET_RETURN_STATUS(env);
820
}
821
822
15
napi_status napi_define_class(napi_env env,
823
                              const char* utf8name,
824
                              size_t length,
825
                              napi_callback constructor,
826
                              void* callback_data,
827
                              size_t property_count,
828
                              const napi_property_descriptor* properties,
829
                              napi_value* result) {
830


43
  NAPI_PREAMBLE(env);
831
14
  CHECK_ARG(env, result);
832
13
  CHECK_ARG(env, constructor);
833
834
12
  if (property_count > 0) {
835
7
    CHECK_ARG(env, properties);
836
  }
837
838
11
  v8::Isolate* isolate = env->isolate;
839
840
11
  v8::EscapableHandleScope scope(isolate);
841
  v8::Local<v8::FunctionTemplate> tpl;
842
11
  STATUS_CALL(v8impl::FunctionCallbackWrapper::NewTemplate(
843
      env, constructor, callback_data, &tpl));
844
845
  v8::Local<v8::String> name_string;
846

12
  CHECK_NEW_FROM_UTF8_LEN(env, name_string, utf8name, length);
847
11
  tpl->SetClassName(name_string);
848
20
849
20
  size_t static_property_count = 0;
850
76
  for (size_t i = 0; i < property_count; i++) {
851
28
    const napi_property_descriptor* p = properties + i;
852
853
28
    if ((p->attributes & napi_static) != 0) {
854
      // Static properties are handled separately below.
855
7
      static_property_count++;
856
7
      continue;
857
    }
858
859
    v8::Local<v8::Name> property_name;
860
21
    STATUS_CALL(v8impl::V8NameFromPropertyDescriptor(env, p, &property_name));
861
862
    v8::PropertyAttribute attributes =
863
21
        v8impl::V8PropertyAttributesFromDescriptor(p);
864
865
    // This code is similar to that in napi_define_properties(); the
866
    // difference is it applies to a template instead of an object,
867
    // and preferred PropertyAttribute for lack of PropertyDescriptor
868
    // support on ObjectTemplate.
869

21
    if (p->getter != nullptr || p->setter != nullptr) {
870
      v8::Local<v8::FunctionTemplate> getter_tpl;
871
      v8::Local<v8::FunctionTemplate> setter_tpl;
872
10
      if (p->getter != nullptr) {
873
10
        STATUS_CALL(v8impl::FunctionCallbackWrapper::NewTemplate(
874
            env, p->getter, p->data, &getter_tpl));
875
      }
876
10
      if (p->setter != nullptr) {
877
5
        STATUS_CALL(v8impl::FunctionCallbackWrapper::NewTemplate(
878
            env, p->setter, p->data, &setter_tpl));
879
      }
880
881
30
      tpl->PrototypeTemplate()->SetAccessorProperty(
882
        property_name,
883
        getter_tpl,
884
        setter_tpl,
885
        attributes,
886
20
        v8::AccessControl::DEFAULT);
887
11
    } else if (p->method != nullptr) {
888
      v8::Local<v8::FunctionTemplate> t;
889
5
      STATUS_CALL(v8impl::FunctionCallbackWrapper::NewTemplate(
890
          env, p->method, p->data, &t, v8::Signature::New(isolate, tpl)));
891
892
10
      tpl->PrototypeTemplate()->Set(property_name, t, attributes);
893
    } else {
894
6
      v8::Local<v8::Value> value = v8impl::V8LocalValueFromJsValue(p->value);
895
12
      tpl->PrototypeTemplate()->Set(property_name, value, attributes);
896
    }
897
  }
898
899
10
  v8::Local<v8::Context> context = env->context();
900
20
  *result = v8impl::JsValueFromV8LocalValue(
901
20
      scope.Escape(tpl->GetFunction(context).ToLocalChecked()));
902
903
10
  if (static_property_count > 0) {
904
6
    std::vector<napi_property_descriptor> static_descriptors;
905
3
    static_descriptors.reserve(static_property_count);
906
907
26
    for (size_t i = 0; i < property_count; i++) {
908
23
      const napi_property_descriptor* p = properties + i;
909
23
      if ((p->attributes & napi_static) != 0) {
910
7
        static_descriptors.push_back(*p);
911
      }
912
    }
913
914

3
    STATUS_CALL(napi_define_properties(env,
915
                                       *result,
916
                                       static_descriptors.size(),
917
                                       static_descriptors.data()));
918
  }
919
920
10
  return GET_RETURN_STATUS(env);
921
}
922
923
8
napi_status napi_get_property_names(napi_env env,
924
                                    napi_value object,
925
                                    napi_value* result) {
926
  return napi_get_all_property_names(
927
      env,
928
      object,
929
      napi_key_include_prototypes,
930
      static_cast<napi_key_filter>(napi_key_enumerable |
931
                                   napi_key_skip_symbols),
932
      napi_key_numbers_to_strings,
933
8
      result);
934
}
935
936
12
napi_status napi_get_all_property_names(napi_env env,
937
                                        napi_value object,
938
                                        napi_key_collection_mode key_mode,
939
                                        napi_key_filter key_filter,
940
                                        napi_key_conversion key_conversion,
941
                                        napi_value* result) {
942


32
  NAPI_PREAMBLE(env);
943
10
  CHECK_ARG(env, result);
944
945
8
  v8::Local<v8::Context> context = env->context();
946
  v8::Local<v8::Object> obj;
947

28
  CHECK_TO_OBJECT(env, context, obj, object);
948
949
6
  v8::PropertyFilter filter = v8::PropertyFilter::ALL_PROPERTIES;
950
6
  if (key_filter & napi_key_writable) {
951
    filter =
952
        static_cast<v8::PropertyFilter>(filter |
953
                                        v8::PropertyFilter::ONLY_WRITABLE);
954
  }
955
6
  if (key_filter & napi_key_enumerable) {
956
5
    filter =
957
5
        static_cast<v8::PropertyFilter>(filter |
958
                                        v8::PropertyFilter::ONLY_ENUMERABLE);
959
  }
960
6
  if (key_filter & napi_key_configurable) {
961
    filter =
962
        static_cast<v8::PropertyFilter>(filter |
963
                                        v8::PropertyFilter::ONLY_WRITABLE);
964
  }
965
6
  if (key_filter & napi_key_skip_strings) {
966
1
    filter =
967
1
        static_cast<v8::PropertyFilter>(filter |
968
                                        v8::PropertyFilter::SKIP_STRINGS);
969
  }
970
6
  if (key_filter & napi_key_skip_symbols) {
971
5
    filter =
972
5
        static_cast<v8::PropertyFilter>(filter |
973
                                        v8::PropertyFilter::SKIP_SYMBOLS);
974
  }
975
  v8::KeyCollectionMode collection_mode;
976
  v8::KeyConversionMode conversion_mode;
977
978
6
  switch (key_mode) {
979
    case napi_key_include_prototypes:
980
6
      collection_mode = v8::KeyCollectionMode::kIncludePrototypes;
981
6
      break;
982
    case napi_key_own_only:
983
      collection_mode = v8::KeyCollectionMode::kOwnOnly;
984
      break;
985
    default:
986
      return napi_set_last_error(env, napi_invalid_arg);
987
  }
988
989
6
  switch (key_conversion) {
990
    case napi_key_keep_numbers:
991
      conversion_mode = v8::KeyConversionMode::kKeepNumbers;
992
      break;
993
    case napi_key_numbers_to_strings:
994
6
      conversion_mode = v8::KeyConversionMode::kConvertToString;
995
6
      break;
996
    default:
997
      return napi_set_last_error(env, napi_invalid_arg);
998
  }
999
1000
  v8::MaybeLocal<v8::Array> maybe_all_propertynames =
1001
      obj->GetPropertyNames(context,
1002
                            collection_mode,
1003
                            filter,
1004
                            v8::IndexFilter::kIncludeIndices,
1005
6
                            conversion_mode);
1006
1007

6
  CHECK_MAYBE_EMPTY_WITH_PREAMBLE(
1008
      env, maybe_all_propertynames, napi_generic_failure);
1009
1010
12
  *result =
1011
12
      v8impl::JsValueFromV8LocalValue(maybe_all_propertynames.ToLocalChecked());
1012
6
  return GET_RETURN_STATUS(env);
1013
}
1014
1015
26
napi_status napi_set_property(napi_env env,
1016
                              napi_value object,
1017
                              napi_value key,
1018
                              napi_value value) {
1019


74
  NAPI_PREAMBLE(env);
1020
24
  CHECK_ARG(env, key);
1021
21
  CHECK_ARG(env, value);
1022
1023
19
  v8::Local<v8::Context> context = env->context();
1024
  v8::Local<v8::Object> obj;
1025
1026

72
  CHECK_TO_OBJECT(env, context, obj, object);
1027
1028
17
  v8::Local<v8::Value> k = v8impl::V8LocalValueFromJsValue(key);
1029
17
  v8::Local<v8::Value> val = v8impl::V8LocalValueFromJsValue(value);
1030
1031
17
  v8::Maybe<bool> set_maybe = obj->Set(context, k, val);
1032
1033
34
  RETURN_STATUS_IF_FALSE(env, set_maybe.FromMaybe(false), napi_generic_failure);
1034
17
  return GET_RETURN_STATUS(env);
1035
}
1036
1037
16
napi_status napi_has_property(napi_env env,
1038
                              napi_value object,
1039
                              napi_value key,
1040
                              bool* result) {
1041


44
  NAPI_PREAMBLE(env);
1042
14
  CHECK_ARG(env, result);
1043
12
  CHECK_ARG(env, key);
1044
1045
10
  v8::Local<v8::Context> context = env->context();
1046
  v8::Local<v8::Object> obj;
1047
1048

36
  CHECK_TO_OBJECT(env, context, obj, object);
1049
1050
8
  v8::Local<v8::Value> k = v8impl::V8LocalValueFromJsValue(key);
1051
8
  v8::Maybe<bool> has_maybe = obj->Has(context, k);
1052
1053
8
  CHECK_MAYBE_NOTHING(env, has_maybe, napi_generic_failure);
1054
1055
16
  *result = has_maybe.FromMaybe(false);
1056
8
  return GET_RETURN_STATUS(env);
1057
}
1058
1059
34
napi_status napi_get_property(napi_env env,
1060
                              napi_value object,
1061
                              napi_value key,
1062
                              napi_value* result) {
1063


98
  NAPI_PREAMBLE(env);
1064
32
  CHECK_ARG(env, key);
1065
28
  CHECK_ARG(env, result);
1066
1067
26
  v8::Local<v8::Context> context = env->context();
1068
26
  v8::Local<v8::Value> k = v8impl::V8LocalValueFromJsValue(key);
1069
  v8::Local<v8::Object> obj;
1070
1071

100
  CHECK_TO_OBJECT(env, context, obj, object);
1072
1073
24
  auto get_maybe = obj->Get(context, k);
1074
1075
24
  CHECK_MAYBE_EMPTY(env, get_maybe, napi_generic_failure);
1076
1077
24
  v8::Local<v8::Value> val = get_maybe.ToLocalChecked();
1078
24
  *result = v8impl::JsValueFromV8LocalValue(val);
1079
24
  return GET_RETURN_STATUS(env);
1080
}
1081
1082
9
napi_status napi_delete_property(napi_env env,
1083
                                 napi_value object,
1084
                                 napi_value key,
1085
                                 bool* result) {
1086


25
  NAPI_PREAMBLE(env);
1087
8
  CHECK_ARG(env, key);
1088
1089
7
  v8::Local<v8::Context> context = env->context();
1090
7
  v8::Local<v8::Value> k = v8impl::V8LocalValueFromJsValue(key);
1091
  v8::Local<v8::Object> obj;
1092
1093

26
  CHECK_TO_OBJECT(env, context, obj, object);
1094
6
  v8::Maybe<bool> delete_maybe = obj->Delete(context, k);
1095
6
  CHECK_MAYBE_NOTHING(env, delete_maybe, napi_generic_failure);
1096
1097
6
  if (result != nullptr)
1098
10
    *result = delete_maybe.FromMaybe(false);
1099
1100
6
  return GET_RETURN_STATUS(env);
1101
}
1102
1103
19
napi_status napi_has_own_property(napi_env env,
1104
                                  napi_value object,
1105
                                  napi_value key,
1106
                                  bool* result) {
1107


55
  NAPI_PREAMBLE(env);
1108
18
  CHECK_ARG(env, key);
1109
17
  CHECK_ARG(env, result);
1110
1111
16
  v8::Local<v8::Context> context = env->context();
1112
  v8::Local<v8::Object> obj;
1113
1114

62
  CHECK_TO_OBJECT(env, context, obj, object);
1115
15
  v8::Local<v8::Value> k = v8impl::V8LocalValueFromJsValue(key);
1116
24
  RETURN_STATUS_IF_FALSE(env, k->IsName(), napi_name_expected);
1117
6
  v8::Maybe<bool> has_maybe = obj->HasOwnProperty(context, k.As<v8::Name>());
1118
6
  CHECK_MAYBE_NOTHING(env, has_maybe, napi_generic_failure);
1119
12
  *result = has_maybe.FromMaybe(false);
1120
1121
6
  return GET_RETURN_STATUS(env);
1122
}
1123
1124
155
napi_status napi_set_named_property(napi_env env,
1125
                                    napi_value object,
1126
                                    const char* utf8name,
1127
                                    napi_value value) {
1128


463
  NAPI_PREAMBLE(env);
1129
154
  CHECK_ARG(env, value);
1130
1131
153
  v8::Local<v8::Context> context = env->context();
1132
  v8::Local<v8::Object> obj;
1133
1134

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

455
  CHECK_NEW_FROM_UTF8(env, key, utf8name);
1138
1139
151
  v8::Local<v8::Value> val = v8impl::V8LocalValueFromJsValue(value);
1140
1141
151
  v8::Maybe<bool> set_maybe = obj->Set(context, key, val);
1142
1143
302
  RETURN_STATUS_IF_FALSE(env, set_maybe.FromMaybe(false), napi_generic_failure);
1144
151
  return GET_RETURN_STATUS(env);
1145
}
1146
1147
9
napi_status napi_has_named_property(napi_env env,
1148
                                    napi_value object,
1149
                                    const char* utf8name,
1150
                                    bool* result) {
1151


25
  NAPI_PREAMBLE(env);
1152
8
  CHECK_ARG(env, result);
1153
1154
7
  v8::Local<v8::Context> context = env->context();
1155
  v8::Local<v8::Object> obj;
1156
1157

26
  CHECK_TO_OBJECT(env, context, obj, object);
1158
1159
  v8::Local<v8::Name> key;
1160

17
  CHECK_NEW_FROM_UTF8(env, key, utf8name);
1161
1162
5
  v8::Maybe<bool> has_maybe = obj->Has(context, key);
1163
1164
5
  CHECK_MAYBE_NOTHING(env, has_maybe, napi_generic_failure);
1165
1166
10
  *result = has_maybe.FromMaybe(false);
1167
5
  return GET_RETURN_STATUS(env);
1168
}
1169
1170
6
napi_status napi_get_named_property(napi_env env,
1171
                                    napi_value object,
1172
                                    const char* utf8name,
1173
                                    napi_value* result) {
1174


16
  NAPI_PREAMBLE(env);
1175
5
  CHECK_ARG(env, result);
1176
1177
4
  v8::Local<v8::Context> context = env->context();
1178
1179
  v8::Local<v8::Name> key;
1180

11
  CHECK_NEW_FROM_UTF8(env, key, utf8name);
1181
1182
  v8::Local<v8::Object> obj;
1183
1184

11
  CHECK_TO_OBJECT(env, context, obj, object);
1185
1186
2
  auto get_maybe = obj->Get(context, key);
1187
1188
2
  CHECK_MAYBE_EMPTY(env, get_maybe, napi_generic_failure);
1189
1190
2
  v8::Local<v8::Value> val = get_maybe.ToLocalChecked();
1191
2
  *result = v8impl::JsValueFromV8LocalValue(val);
1192
2
  return GET_RETURN_STATUS(env);
1193
}
1194
1195
13
napi_status napi_set_element(napi_env env,
1196
                             napi_value object,
1197
                             uint32_t index,
1198
                             napi_value value) {
1199


37
  NAPI_PREAMBLE(env);
1200
12
  CHECK_ARG(env, value);
1201
1202
12
  v8::Local<v8::Context> context = env->context();
1203
  v8::Local<v8::Object> obj;
1204
1205

46
  CHECK_TO_OBJECT(env, context, obj, object);
1206
1207
11
  v8::Local<v8::Value> val = v8impl::V8LocalValueFromJsValue(value);
1208
11
  auto set_maybe = obj->Set(context, index, val);
1209
1210
22
  RETURN_STATUS_IF_FALSE(env, set_maybe.FromMaybe(false), napi_generic_failure);
1211
1212
11
  return GET_RETURN_STATUS(env);
1213
}
1214
1215
5
napi_status napi_has_element(napi_env env,
1216
                             napi_value object,
1217
                             uint32_t index,
1218
                             bool* result) {
1219


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

10
  CHECK_TO_OBJECT(env, context, obj, object);
1226
1227
2
  v8::Maybe<bool> has_maybe = obj->Has(context, index);
1228
1229
2
  CHECK_MAYBE_NOTHING(env, has_maybe, napi_generic_failure);
1230
1231
4
  *result = has_maybe.FromMaybe(false);
1232
2
  return GET_RETURN_STATUS(env);
1233
}
1234
1235
28
napi_status napi_get_element(napi_env env,
1236
                             napi_value object,
1237
                             uint32_t index,
1238
                             napi_value* result) {
1239


82
  NAPI_PREAMBLE(env);
1240
27
  CHECK_ARG(env, result);
1241
1242
27
  v8::Local<v8::Context> context = env->context();
1243
  v8::Local<v8::Object> obj;
1244
1245

108
  CHECK_TO_OBJECT(env, context, obj, object);
1246
1247
27
  auto get_maybe = obj->Get(context, index);
1248
1249
27
  CHECK_MAYBE_EMPTY(env, get_maybe, napi_generic_failure);
1250
1251
54
  *result = v8impl::JsValueFromV8LocalValue(get_maybe.ToLocalChecked());
1252
27
  return GET_RETURN_STATUS(env);
1253
}
1254
1255
4
napi_status napi_delete_element(napi_env env,
1256
                                napi_value object,
1257
                                uint32_t index,
1258
                                bool* result) {
1259


10
  NAPI_PREAMBLE(env);
1260
1261
3
  v8::Local<v8::Context> context = env->context();
1262
  v8::Local<v8::Object> obj;
1263
1264

10
  CHECK_TO_OBJECT(env, context, obj, object);
1265
2
  v8::Maybe<bool> delete_maybe = obj->Delete(context, index);
1266
2
  CHECK_MAYBE_NOTHING(env, delete_maybe, napi_generic_failure);
1267
1268
2
  if (result != nullptr)
1269
2
    *result = delete_maybe.FromMaybe(false);
1270
1271
2
  return GET_RETURN_STATUS(env);
1272
}
1273
1274
78
napi_status napi_define_properties(napi_env env,
1275
                                   napi_value object,
1276
                                   size_t property_count,
1277
                                   const napi_property_descriptor* properties) {
1278


232
  NAPI_PREAMBLE(env);
1279
77
  if (property_count > 0) {
1280
77
    CHECK_ARG(env, properties);
1281
  }
1282
1283
74
  v8::Local<v8::Context> context = env->context();
1284
1285
  v8::Local<v8::Object> obj;
1286

294
  CHECK_TO_OBJECT(env, context, obj, object);
1287
1288
976
  for (size_t i = 0; i < property_count; i++) {
1289
415
    const napi_property_descriptor* p = &properties[i];
1290
1291
    v8::Local<v8::Name> property_name;
1292
415
    STATUS_CALL(v8impl::V8NameFromPropertyDescriptor(env, p, &property_name));
1293
1294

415
    if (p->getter != nullptr || p->setter != nullptr) {
1295
      v8::Local<v8::Function> local_getter;
1296
      v8::Local<v8::Function> local_setter;
1297
1298
10
      if (p->getter != nullptr) {
1299
10
        STATUS_CALL(v8impl::FunctionCallbackWrapper::NewFunction(
1300
            env, p->getter, p->data, &local_getter));
1301
      }
1302
10
      if (p->setter != nullptr) {
1303
2
        STATUS_CALL(v8impl::FunctionCallbackWrapper::NewFunction(
1304
            env, p->setter, p->data, &local_setter));
1305
      }
1306
1307
20
      v8::PropertyDescriptor descriptor(local_getter, local_setter);
1308
10
      descriptor.set_enumerable((p->attributes & napi_enumerable) != 0);
1309
10
      descriptor.set_configurable((p->attributes & napi_configurable) != 0);
1310
1311
      auto define_maybe = obj->DefineProperty(context,
1312
                                              property_name,
1313
10
                                              descriptor);
1314
1315
20
      if (!define_maybe.FromMaybe(false)) {
1316
        return napi_set_last_error(env, napi_invalid_arg);
1317
10
      }
1318
405
    } else if (p->method != nullptr) {
1319
      v8::Local<v8::Function> method;
1320
389
      STATUS_CALL(v8impl::FunctionCallbackWrapper::NewFunction(
1321
          env, p->method, p->data, &method));
1322
      v8::PropertyDescriptor descriptor(method,
1323
1167
                                        (p->attributes & napi_writable) != 0);
1324
389
      descriptor.set_enumerable((p->attributes & napi_enumerable) != 0);
1325
389
      descriptor.set_configurable((p->attributes & napi_configurable) != 0);
1326
1327
      auto define_maybe = obj->DefineProperty(context,
1328
                                              property_name,
1329
389
                                              descriptor);
1330
1331
778
      if (!define_maybe.FromMaybe(false)) {
1332
        return napi_set_last_error(env, napi_generic_failure);
1333
      }
1334
    } else {
1335
16
      v8::Local<v8::Value> value = v8impl::V8LocalValueFromJsValue(p->value);
1336
1337
      v8::PropertyDescriptor descriptor(value,
1338
32
                                        (p->attributes & napi_writable) != 0);
1339
16
      descriptor.set_enumerable((p->attributes & napi_enumerable) != 0);
1340
16
      descriptor.set_configurable((p->attributes & napi_configurable) != 0);
1341
1342
      auto define_maybe =
1343
16
          obj->DefineProperty(context, property_name, descriptor);
1344
1345
32
      if (!define_maybe.FromMaybe(false)) {
1346
        return napi_set_last_error(env, napi_invalid_arg);
1347
      }
1348
    }
1349
  }
1350
1351
73
  return GET_RETURN_STATUS(env);
1352
}
1353
1354
1
napi_status napi_object_freeze(napi_env env,
1355
                               napi_value object) {
1356


3
  NAPI_PREAMBLE(env);
1357
1358
1
  v8::Local<v8::Context> context = env->context();
1359
  v8::Local<v8::Object> obj;
1360
1361

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

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


3
  NAPI_PREAMBLE(env);
1375
1376
1
  v8::Local<v8::Context> context = env->context();
1377
  v8::Local<v8::Object> obj;
1378
1379

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

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


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


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


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

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

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

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

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


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

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

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

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


1966
  NAPI_PREAMBLE(env);
1880
654
  CHECK_ARG(env, recv);
1881
654
  if (argc > 0) {
1882
602
    CHECK_ARG(env, argv);
1883
  }
1884
1885
654
  v8::Local<v8::Context> context = env->context();
1886
1887
654
  v8::Local<v8::Value> v8recv = v8impl::V8LocalValueFromJsValue(recv);
1888
1889
  v8::Local<v8::Function> v8func;
1890

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


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


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

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


270
  NAPI_PREAMBLE(env);
1949
1950
90
  v8::Isolate* isolate = env->isolate;
1951
  v8::Local<v8::String> str;
1952

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


66
  NAPI_PREAMBLE(env);
1967
1968
22
  v8::Isolate* isolate = env->isolate;
1969
  v8::Local<v8::String> str;
1970

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

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


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


49
GEN_COERCE_FUNCTION(OBJECT, Object, object)
2330


69
GEN_COERCE_FUNCTION(STRING, String, string)
2331


67
2332

35
#undef GEN_COERCE_FUNCTION
2333

48
2334

1092
napi_status napi_wrap(napi_env env,
2335

63
                      napi_value js_object,
2336

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


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


6
  NAPI_PREAMBLE(env);
2387
2
  v8::Local<v8::Context> context = env->context();
2388
  v8::Local<v8::Object> obj;
2389


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

2
  CHECK_ARG_WITH_PREAMBLE(env, type_tag);
2391
2392
2
  auto key = NAPI_PRIVATE_KEY(context, type_tag);
2393
2
  auto maybe_has = obj->HasPrivate(context, key);
2394

2
  CHECK_MAYBE_NOTHING_WITH_PREAMBLE(env, maybe_has, napi_generic_failure);
2395

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

2
  CHECK_MAYBE_EMPTY_WITH_PREAMBLE(env, tag, napi_generic_failure);
2404
2405
2
  auto maybe_set = obj->SetPrivate(context, key, tag.ToLocalChecked());
2406

2
  CHECK_MAYBE_NOTHING_WITH_PREAMBLE(env, maybe_set, napi_generic_failure);
2407

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


18
  NAPI_PREAMBLE(env);
2420
6
  v8::Local<v8::Context> context = env->context();
2421
  v8::Local<v8::Object> obj;
2422


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

6
  CHECK_ARG_WITH_PREAMBLE(env, type_tag);
2424

6
  CHECK_ARG_WITH_PREAMBLE(env, result);
2425
2426
  auto maybe_value = obj->GetPrivate(context,
2427
12
                                     NAPI_PRIVATE_KEY(context, type_tag));
2428

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

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

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

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


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

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


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

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


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


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



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

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


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

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


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


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


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


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

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

14316
}