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: 1348 1381 97.6 %
Date: 2020-02-19 22:14:06 Branches: 971 1570 61.8 %

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

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

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


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

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

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

2452
    if (_delete_self || is_env_teardown) {
282
2448
      Delete(this);
283
    } else {
284
4
      _finalize_ran = true;
285
    }
286
2452
  }
287
288
 private:
289
  uint32_t _refcount;
290
  bool _delete_self;
291
};
292
293
8938
class Reference : public RefBase {
294
 protected:
295
  template <typename... Args>
296
2985
  Reference(napi_env env,
297
            v8::Local<v8::Value> value,
298
            Args&&... args)
299
14925
      : RefBase(env, std::forward<Args>(args)...),
300
14925
            _persistent(env->isolate, value) {
301

2985
    if (RefCount() == 0) {
302
2448
      _persistent.SetWeak(
303
          this, FinalizeCallback, v8::WeakCallbackType::kParameter);
304
    }
305
2985
  }
306
307
 public:
308
2980
  static inline Reference* New(napi_env env,
309
                             v8::Local<v8::Value> value,
310
                             uint32_t initial_refcount,
311
                             bool delete_self,
312
                             napi_finalize finalize_callback = nullptr,
313
                             void* finalize_data = nullptr,
314
                             void* finalize_hint = nullptr) {
315
    return new Reference(env,
316
                         value,
317
                         initial_refcount,
318
                         delete_self,
319
                         finalize_callback,
320
                         finalize_data,
321
2980
                         finalize_hint);
322
  }
323
324
1
  inline uint32_t Ref() {
325
1
    uint32_t refcount = RefBase::Ref();
326
1
    if (refcount == 1) {
327
      _persistent.ClearWeak();
328
    }
329
1
    return refcount;
330
  }
331
332
2
  inline uint32_t Unref() {
333
2
    uint32_t old_refcount = RefCount();
334
2
    uint32_t refcount = RefBase::Unref();
335

2
    if (old_refcount == 1 && refcount == 0) {
336
1
      _persistent.SetWeak(
337
          this, FinalizeCallback, v8::WeakCallbackType::kParameter);
338
    }
339
2
    return refcount;
340
  }
341
342
1554
  inline v8::Local<v8::Value> Get() {
343
3108
    if (_persistent.IsEmpty()) {
344
1001
      return v8::Local<v8::Value>();
345
    } else {
346
1106
      return v8::Local<v8::Value>::New(_env->isolate, _persistent);
347
    }
348
  }
349
350
 private:
351
  // The N-API finalizer callback may make calls into the engine. V8's heap is
352
  // not in a consistent state during the weak callback, and therefore it does
353
  // not support calls back into it. However, it provides a mechanism for adding
354
  // a finalizer which may make calls back into the engine by allowing us to
355
  // attach such a second-pass finalizer from the first pass finalizer. Thus,
356
  // we do that here to ensure that the N-API finalizer callback is free to call
357
  // into the engine.
358
2016
  static void FinalizeCallback(const v8::WeakCallbackInfo<Reference>& data) {
359
2016
    Reference* reference = data.GetParameter();
360
361
    // The reference must be reset during the first pass.
362
2016
    reference->_persistent.Reset();
363
364
2016
    data.SetSecondPassCallback(SecondPassCallback);
365
2016
  }
366
367
2016
  static void SecondPassCallback(const v8::WeakCallbackInfo<Reference>& data) {
368
2016
    data.GetParameter()->Finalize();
369
2016
  }
370
371
  v8impl::Persistent<v8::Value> _persistent;
372
};
373
374
10
class ArrayBufferReference final : public Reference {
375
 public:
376
  // Same signatures for ctor and New() as Reference, except this only works
377
  // with ArrayBuffers:
378
  template <typename... Args>
379
5
  explicit ArrayBufferReference(napi_env env,
380
                                v8::Local<v8::ArrayBuffer> value,
381
                                Args&&... args)
382
10
    : Reference(env, value, std::forward<Args>(args)...) {}
383
384
  template <typename... Args>
385
5
  static ArrayBufferReference* New(napi_env env,
386
                                   v8::Local<v8::ArrayBuffer> value,
387
                                   Args&&... args) {
388
5
    return new ArrayBufferReference(env, value, std::forward<Args>(args)...);
389
  }
390
391
 private:
392
5
  inline void Finalize(bool is_env_teardown) override {
393
5
    if (is_env_teardown) {
394
10
      v8::HandleScope handle_scope(_env->isolate);
395
5
      v8::Local<v8::Value> ab = Get();
396
5
      CHECK(!ab.IsEmpty());
397
5
      CHECK(ab->IsArrayBuffer());
398
10
      ab.As<v8::ArrayBuffer>()->Detach();
399
    }
400
401
5
    Reference::Finalize(is_env_teardown);
402
5
  }
403
};
404
405
enum UnwrapAction {
406
  KeepWrap,
407
  RemoveWrap
408
};
409
410
29
inline static napi_status Unwrap(napi_env env,
411
                                 napi_value js_object,
412
                                 void** result,
413
                                 UnwrapAction action) {
414


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




3072
  NAPI_PREAMBLE(env);
673

1024
  CHECK_ARG(env, js_object);
674
675
1024
  v8::Local<v8::Context> context = env->context();
676
677
1024
  v8::Local<v8::Value> value = v8impl::V8LocalValueFromJsValue(js_object);
678

1024
  RETURN_STATUS_IF_FALSE(env, value->IsObject(), napi_invalid_arg);
679
1024
  v8::Local<v8::Object> obj = value.As<v8::Object>();
680
681
  if (wrap_type == retrievable) {
682
    // If we've already wrapped this object, we error out.
683
3063
    RETURN_STATUS_IF_FALSE(env,
684
        !obj->HasPrivate(context, NAPI_PRIVATE_KEY(context, wrapper))
685
            .FromJust(),
686
        napi_invalid_arg);
687
  } else if (wrap_type == anonymous) {
688
    // If no finalize callback is provided, we error out.
689
3
    CHECK_ARG(env, finalize_cb);
690
  }
691
692
1023
  v8impl::Reference* reference = nullptr;
693

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

8
    CHECK_ARG(env, finalize_cb);
699
16
    reference = v8impl::Reference::New(
700
        env, obj, 0, false, finalize_cb, native_object, finalize_hint);
701
8
    *result = reinterpret_cast<napi_ref>(reference);
702
  } else {
703
    // Create a self-deleting reference.
704

2030
    reference = v8impl::Reference::New(env, obj, 0, true, finalize_cb,
705
1015
        native_object, finalize_cb == nullptr ? nullptr : finalize_hint);
706
  }
707
708
  if (wrap_type == retrievable) {
709
4080
    CHECK(obj->SetPrivate(context, NAPI_PRIVATE_KEY(context, wrapper),
710
          v8::External::New(env->isolate, reference)).FromJust());
711
  }
712
713

1023
  return GET_RETURN_STATUS(env);
714
}
715
716
}  // end of anonymous namespace
717
718
}  // end of namespace v8impl
719
720
// Warning: Keep in-sync with napi_status enum
721
static
722
const char* error_messages[] = {nullptr,
723
                                "Invalid argument",
724
                                "An object was expected",
725
                                "A string was expected",
726
                                "A string or symbol was expected",
727
                                "A function was expected",
728
                                "A number was expected",
729
                                "A boolean was expected",
730
                                "An array was expected",
731
                                "Unknown failure",
732
                                "An exception is pending",
733
                                "The async work item was cancelled",
734
                                "napi_escape_handle already called on scope",
735
                                "Invalid handle scope usage",
736
                                "Invalid callback scope usage",
737
                                "Thread-safe function queue is full",
738
                                "Thread-safe function handle is closing",
739
                                "A bigint was expected",
740
                                "A date was expected",
741
                                "An arraybuffer was expected",
742
                                "A detachable arraybuffer was expected",
743
};
744
745
1277
napi_status napi_get_last_error_info(napi_env env,
746
                                     const napi_extended_error_info** result) {
747
1277
  CHECK_ENV(env);
748
1277
  CHECK_ARG(env, result);
749
750
  // The value of the constant below must be updated to reference the last
751
  // message in the `napi_status` enum each time a new error message is added.
752
  // We don't have a napi_status_last as this would result in an ABI
753
  // change each time a message was added.
754
1277
  const int last_status = napi_detachable_arraybuffer_expected;
755
756
  static_assert(
757
      NAPI_ARRAYSIZE(error_messages) == last_status + 1,
758
      "Count of error messages must match count of error values");
759
1277
  CHECK_LE(env->last_error.error_code, last_status);
760
761
  // Wait until someone requests the last error information to fetch the error
762
  // message string
763
2554
  env->last_error.error_message =
764
1277
      error_messages[env->last_error.error_code];
765
766
1277
  *result = &(env->last_error);
767
1277
  return napi_ok;
768
}
769
770
10
napi_status napi_create_function(napi_env env,
771
                                 const char* utf8name,
772
                                 size_t length,
773
                                 napi_callback cb,
774
                                 void* callback_data,
775
                                 napi_value* result) {
776


30
  NAPI_PREAMBLE(env);
777
10
  CHECK_ARG(env, result);
778
10
  CHECK_ARG(env, cb);
779
780
10
  v8::Isolate* isolate = env->isolate;
781
  v8::Local<v8::Function> return_value;
782
10
  v8::EscapableHandleScope scope(isolate);
783
  v8::Local<v8::Value> cbdata =
784
10
      v8impl::CreateFunctionCallbackData(env, cb, callback_data);
785
786
10
  RETURN_STATUS_IF_FALSE(env, !cbdata.IsEmpty(), napi_generic_failure);
787
788
10
  v8::Local<v8::Context> context = env->context();
789
  v8::MaybeLocal<v8::Function> maybe_function =
790
      v8::Function::New(context,
791
                        v8impl::FunctionCallbackWrapper::Invoke,
792
10
                        cbdata);
793
10
  CHECK_MAYBE_EMPTY(env, maybe_function, napi_generic_failure);
794
795
10
  return_value = scope.Escape(maybe_function.ToLocalChecked());
796
797
10
  if (utf8name != nullptr) {
798
    v8::Local<v8::String> name_string;
799


9
    CHECK_NEW_FROM_UTF8_LEN(env, name_string, utf8name, length);
800
3
    return_value->SetName(name_string);
801
  }
802
803
20
  *result = v8impl::JsValueFromV8LocalValue(return_value);
804
805
10
  return GET_RETURN_STATUS(env);
806
}
807
808
13
napi_status napi_define_class(napi_env env,
809
                              const char* utf8name,
810
                              size_t length,
811
                              napi_callback constructor,
812
                              void* callback_data,
813
                              size_t property_count,
814
                              const napi_property_descriptor* properties,
815
                              napi_value* result) {
816


37
  NAPI_PREAMBLE(env);
817
12
  CHECK_ARG(env, result);
818
11
  CHECK_ARG(env, constructor);
819
820
10
  if (property_count > 0) {
821
7
    CHECK_ARG(env, properties);
822
  }
823
824
9
  v8::Isolate* isolate = env->isolate;
825
826
9
  v8::EscapableHandleScope scope(isolate);
827
  v8::Local<v8::Value> cbdata =
828
9
      v8impl::CreateFunctionCallbackData(env, constructor, callback_data);
829
830
9
  RETURN_STATUS_IF_FALSE(env, !cbdata.IsEmpty(), napi_generic_failure);
831
832
  v8::Local<v8::FunctionTemplate> tpl = v8::FunctionTemplate::New(
833
9
      isolate, v8impl::FunctionCallbackWrapper::Invoke, cbdata);
834
835
  v8::Local<v8::String> name_string;
836


26
  CHECK_NEW_FROM_UTF8_LEN(env, name_string, utf8name, length);
837
8
  tpl->SetClassName(name_string);
838
839
8
  size_t static_property_count = 0;
840
72
  for (size_t i = 0; i < property_count; i++) {
841
28
    const napi_property_descriptor* p = properties + i;
842
843
28
    if ((p->attributes & napi_static) != 0) {
844
      // Static properties are handled separately below.
845
7
      static_property_count++;
846
7
      continue;
847
    }
848
849
    v8::Local<v8::Name> property_name;
850
    napi_status status =
851
21
        v8impl::V8NameFromPropertyDescriptor(env, p, &property_name);
852
853
21
    if (status != napi_ok) {
854
      return napi_set_last_error(env, status);
855
    }
856
857
    v8::PropertyAttribute attributes =
858
21
        v8impl::V8PropertyAttributesFromDescriptor(p);
859
860
    // This code is similar to that in napi_define_properties(); the
861
    // difference is it applies to a template instead of an object,
862
    // and preferred PropertyAttribute for lack of PropertyDescriptor
863
    // support on ObjectTemplate.
864

21
    if (p->getter != nullptr || p->setter != nullptr) {
865
      v8::Local<v8::FunctionTemplate> getter_tpl;
866
      v8::Local<v8::FunctionTemplate> setter_tpl;
867
10
      if (p->getter != nullptr) {
868
        v8::Local<v8::Value> getter_data =
869
10
            v8impl::CreateFunctionCallbackData(env, p->getter, p->data);
870
871
        getter_tpl = v8::FunctionTemplate::New(
872
10
            isolate, v8impl::FunctionCallbackWrapper::Invoke, getter_data);
873
      }
874
10
      if (p->setter != nullptr) {
875
        v8::Local<v8::Value> setter_data =
876
5
            v8impl::CreateFunctionCallbackData(env, p->setter, p->data);
877
878
        setter_tpl = v8::FunctionTemplate::New(
879
5
            isolate, v8impl::FunctionCallbackWrapper::Invoke, setter_data);
880
      }
881
882
30
      tpl->PrototypeTemplate()->SetAccessorProperty(
883
        property_name,
884
        getter_tpl,
885
        setter_tpl,
886
        attributes,
887
20
        v8::AccessControl::DEFAULT);
888
11
    } else if (p->method != nullptr) {
889
      v8::Local<v8::Value> cbdata =
890
5
          v8impl::CreateFunctionCallbackData(env, p->method, p->data);
891
892
5
      RETURN_STATUS_IF_FALSE(env, !cbdata.IsEmpty(), napi_generic_failure);
893
894
      v8::Local<v8::FunctionTemplate> t =
895
        v8::FunctionTemplate::New(isolate,
896
          v8impl::FunctionCallbackWrapper::Invoke,
897
          cbdata,
898
5
          v8::Signature::New(isolate, tpl));
899
900
10
      tpl->PrototypeTemplate()->Set(property_name, t, attributes);
901
    } else {
902
6
      v8::Local<v8::Value> value = v8impl::V8LocalValueFromJsValue(p->value);
903
12
      tpl->PrototypeTemplate()->Set(property_name, value, attributes);
904
    }
905
  }
906
907
8
  v8::Local<v8::Context> context = env->context();
908
16
  *result = v8impl::JsValueFromV8LocalValue(
909
16
      scope.Escape(tpl->GetFunction(context).ToLocalChecked()));
910
911
8
  if (static_property_count > 0) {
912
6
    std::vector<napi_property_descriptor> static_descriptors;
913
3
    static_descriptors.reserve(static_property_count);
914
915
26
    for (size_t i = 0; i < property_count; i++) {
916
23
      const napi_property_descriptor* p = properties + i;
917
23
      if ((p->attributes & napi_static) != 0) {
918
7
        static_descriptors.push_back(*p);
919
      }
920
    }
921
922
    napi_status status =
923
3
        napi_define_properties(env,
924
                               *result,
925
                               static_descriptors.size(),
926
6
                               static_descriptors.data());
927

3
    if (status != napi_ok) return status;
928
  }
929
930
8
  return GET_RETURN_STATUS(env);
931
}
932
933
8
napi_status napi_get_property_names(napi_env env,
934
                                    napi_value object,
935
                                    napi_value* result) {
936
  return napi_get_all_property_names(
937
      env,
938
      object,
939
      napi_key_include_prototypes,
940
      static_cast<napi_key_filter>(napi_key_enumerable |
941
                                   napi_key_skip_symbols),
942
      napi_key_numbers_to_strings,
943
8
      result);
944
}
945
946
12
napi_status napi_get_all_property_names(napi_env env,
947
                                        napi_value object,
948
                                        napi_key_collection_mode key_mode,
949
                                        napi_key_filter key_filter,
950
                                        napi_key_conversion key_conversion,
951
                                        napi_value* result) {
952


32
  NAPI_PREAMBLE(env);
953
10
  CHECK_ARG(env, result);
954
955
8
  v8::Local<v8::Context> context = env->context();
956
  v8::Local<v8::Object> obj;
957

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

6
  CHECK_MAYBE_EMPTY_WITH_PREAMBLE(
1018
      env, maybe_all_propertynames, napi_generic_failure);
1019
1020
12
  *result =
1021
12
      v8impl::JsValueFromV8LocalValue(maybe_all_propertynames.ToLocalChecked());
1022
6
  return GET_RETURN_STATUS(env);
1023
}
1024
1025
24
napi_status napi_set_property(napi_env env,
1026
                              napi_value object,
1027
                              napi_value key,
1028
                              napi_value value) {
1029


68
  NAPI_PREAMBLE(env);
1030
22
  CHECK_ARG(env, key);
1031
19
  CHECK_ARG(env, value);
1032
1033
17
  v8::Local<v8::Context> context = env->context();
1034
  v8::Local<v8::Object> obj;
1035
1036

64
  CHECK_TO_OBJECT(env, context, obj, object);
1037
1038
15
  v8::Local<v8::Value> k = v8impl::V8LocalValueFromJsValue(key);
1039
15
  v8::Local<v8::Value> val = v8impl::V8LocalValueFromJsValue(value);
1040
1041
15
  v8::Maybe<bool> set_maybe = obj->Set(context, k, val);
1042
1043
30
  RETURN_STATUS_IF_FALSE(env, set_maybe.FromMaybe(false), napi_generic_failure);
1044
15
  return GET_RETURN_STATUS(env);
1045
}
1046
1047
16
napi_status napi_has_property(napi_env env,
1048
                              napi_value object,
1049
                              napi_value key,
1050
                              bool* result) {
1051


44
  NAPI_PREAMBLE(env);
1052
14
  CHECK_ARG(env, result);
1053
12
  CHECK_ARG(env, key);
1054
1055
10
  v8::Local<v8::Context> context = env->context();
1056
  v8::Local<v8::Object> obj;
1057
1058

36
  CHECK_TO_OBJECT(env, context, obj, object);
1059
1060
8
  v8::Local<v8::Value> k = v8impl::V8LocalValueFromJsValue(key);
1061
8
  v8::Maybe<bool> has_maybe = obj->Has(context, k);
1062
1063
8
  CHECK_MAYBE_NOTHING(env, has_maybe, napi_generic_failure);
1064
1065
16
  *result = has_maybe.FromMaybe(false);
1066
8
  return GET_RETURN_STATUS(env);
1067
}
1068
1069
34
napi_status napi_get_property(napi_env env,
1070
                              napi_value object,
1071
                              napi_value key,
1072
                              napi_value* result) {
1073


98
  NAPI_PREAMBLE(env);
1074
32
  CHECK_ARG(env, key);
1075
28
  CHECK_ARG(env, result);
1076
1077
26
  v8::Local<v8::Context> context = env->context();
1078
26
  v8::Local<v8::Value> k = v8impl::V8LocalValueFromJsValue(key);
1079
  v8::Local<v8::Object> obj;
1080
1081

100
  CHECK_TO_OBJECT(env, context, obj, object);
1082
1083
24
  auto get_maybe = obj->Get(context, k);
1084
1085
24
  CHECK_MAYBE_EMPTY(env, get_maybe, napi_generic_failure);
1086
1087
24
  v8::Local<v8::Value> val = get_maybe.ToLocalChecked();
1088
24
  *result = v8impl::JsValueFromV8LocalValue(val);
1089
24
  return GET_RETURN_STATUS(env);
1090
}
1091
1092
9
napi_status napi_delete_property(napi_env env,
1093
                                 napi_value object,
1094
                                 napi_value key,
1095
                                 bool* result) {
1096


25
  NAPI_PREAMBLE(env);
1097
8
  CHECK_ARG(env, key);
1098
1099
7
  v8::Local<v8::Context> context = env->context();
1100
7
  v8::Local<v8::Value> k = v8impl::V8LocalValueFromJsValue(key);
1101
  v8::Local<v8::Object> obj;
1102
1103

26
  CHECK_TO_OBJECT(env, context, obj, object);
1104
6
  v8::Maybe<bool> delete_maybe = obj->Delete(context, k);
1105
6
  CHECK_MAYBE_NOTHING(env, delete_maybe, napi_generic_failure);
1106
1107
6
  if (result != nullptr)
1108
10
    *result = delete_maybe.FromMaybe(false);
1109
1110
6
  return GET_RETURN_STATUS(env);
1111
}
1112
1113
19
napi_status napi_has_own_property(napi_env env,
1114
                                  napi_value object,
1115
                                  napi_value key,
1116
                                  bool* result) {
1117


55
  NAPI_PREAMBLE(env);
1118
18
  CHECK_ARG(env, key);
1119
17
  CHECK_ARG(env, result);
1120
1121
16
  v8::Local<v8::Context> context = env->context();
1122
  v8::Local<v8::Object> obj;
1123
1124

62
  CHECK_TO_OBJECT(env, context, obj, object);
1125
15
  v8::Local<v8::Value> k = v8impl::V8LocalValueFromJsValue(key);
1126
24
  RETURN_STATUS_IF_FALSE(env, k->IsName(), napi_name_expected);
1127
6
  v8::Maybe<bool> has_maybe = obj->HasOwnProperty(context, k.As<v8::Name>());
1128
6
  CHECK_MAYBE_NOTHING(env, has_maybe, napi_generic_failure);
1129
12
  *result = has_maybe.FromMaybe(false);
1130
1131
6
  return GET_RETURN_STATUS(env);
1132
}
1133
1134
103
napi_status napi_set_named_property(napi_env env,
1135
                                    napi_value object,
1136
                                    const char* utf8name,
1137
                                    napi_value value) {
1138


307
  NAPI_PREAMBLE(env);
1139
102
  CHECK_ARG(env, value);
1140
1141
101
  v8::Local<v8::Context> context = env->context();
1142
  v8::Local<v8::Object> obj;
1143
1144

402
  CHECK_TO_OBJECT(env, context, obj, object);
1145
1146
  v8::Local<v8::Name> key;
1147

299
  CHECK_NEW_FROM_UTF8(env, key, utf8name);
1148
1149
99
  v8::Local<v8::Value> val = v8impl::V8LocalValueFromJsValue(value);
1150
1151
99
  v8::Maybe<bool> set_maybe = obj->Set(context, key, val);
1152
1153
198
  RETURN_STATUS_IF_FALSE(env, set_maybe.FromMaybe(false), napi_generic_failure);
1154
99
  return GET_RETURN_STATUS(env);
1155
}
1156
1157
9
napi_status napi_has_named_property(napi_env env,
1158
                                    napi_value object,
1159
                                    const char* utf8name,
1160
                                    bool* result) {
1161


25
  NAPI_PREAMBLE(env);
1162
8
  CHECK_ARG(env, result);
1163
1164
7
  v8::Local<v8::Context> context = env->context();
1165
  v8::Local<v8::Object> obj;
1166
1167

26
  CHECK_TO_OBJECT(env, context, obj, object);
1168
1169
  v8::Local<v8::Name> key;
1170

17
  CHECK_NEW_FROM_UTF8(env, key, utf8name);
1171
1172
5
  v8::Maybe<bool> has_maybe = obj->Has(context, key);
1173
1174
5
  CHECK_MAYBE_NOTHING(env, has_maybe, napi_generic_failure);
1175
1176
10
  *result = has_maybe.FromMaybe(false);
1177
5
  return GET_RETURN_STATUS(env);
1178
}
1179
1180
5
napi_status napi_get_named_property(napi_env env,
1181
                                    napi_value object,
1182
                                    const char* utf8name,
1183
                                    napi_value* result) {
1184


13
  NAPI_PREAMBLE(env);
1185
4
  CHECK_ARG(env, result);
1186
1187
3
  v8::Local<v8::Context> context = env->context();
1188
1189
  v8::Local<v8::Name> key;
1190

8
  CHECK_NEW_FROM_UTF8(env, key, utf8name);
1191
1192
  v8::Local<v8::Object> obj;
1193
1194

7
  CHECK_TO_OBJECT(env, context, obj, object);
1195
1196
1
  auto get_maybe = obj->Get(context, key);
1197
1198
1
  CHECK_MAYBE_EMPTY(env, get_maybe, napi_generic_failure);
1199
1200
1
  v8::Local<v8::Value> val = get_maybe.ToLocalChecked();
1201
1
  *result = v8impl::JsValueFromV8LocalValue(val);
1202
1
  return GET_RETURN_STATUS(env);
1203
}
1204
1205
13
napi_status napi_set_element(napi_env env,
1206
                             napi_value object,
1207
                             uint32_t index,
1208
                             napi_value value) {
1209


37
  NAPI_PREAMBLE(env);
1210
12
  CHECK_ARG(env, value);
1211
1212
12
  v8::Local<v8::Context> context = env->context();
1213
  v8::Local<v8::Object> obj;
1214
1215

46
  CHECK_TO_OBJECT(env, context, obj, object);
1216
1217
11
  v8::Local<v8::Value> val = v8impl::V8LocalValueFromJsValue(value);
1218
11
  auto set_maybe = obj->Set(context, index, val);
1219
1220
22
  RETURN_STATUS_IF_FALSE(env, set_maybe.FromMaybe(false), napi_generic_failure);
1221
1222
11
  return GET_RETURN_STATUS(env);
1223
}
1224
1225
5
napi_status napi_has_element(napi_env env,
1226
                             napi_value object,
1227
                             uint32_t index,
1228
                             bool* result) {
1229


13
  NAPI_PREAMBLE(env);
1230
4
  CHECK_ARG(env, result);
1231
1232
3
  v8::Local<v8::Context> context = env->context();
1233
  v8::Local<v8::Object> obj;
1234
1235

10
  CHECK_TO_OBJECT(env, context, obj, object);
1236
1237
2
  v8::Maybe<bool> has_maybe = obj->Has(context, index);
1238
1239
2
  CHECK_MAYBE_NOTHING(env, has_maybe, napi_generic_failure);
1240
1241
4
  *result = has_maybe.FromMaybe(false);
1242
2
  return GET_RETURN_STATUS(env);
1243
}
1244
1245
28
napi_status napi_get_element(napi_env env,
1246
                             napi_value object,
1247
                             uint32_t index,
1248
                             napi_value* result) {
1249


82
  NAPI_PREAMBLE(env);
1250
27
  CHECK_ARG(env, result);
1251
1252
27
  v8::Local<v8::Context> context = env->context();
1253
  v8::Local<v8::Object> obj;
1254
1255

108
  CHECK_TO_OBJECT(env, context, obj, object);
1256
1257
27
  auto get_maybe = obj->Get(context, index);
1258
1259
27
  CHECK_MAYBE_EMPTY(env, get_maybe, napi_generic_failure);
1260
1261
54
  *result = v8impl::JsValueFromV8LocalValue(get_maybe.ToLocalChecked());
1262
27
  return GET_RETURN_STATUS(env);
1263
}
1264
1265
4
napi_status napi_delete_element(napi_env env,
1266
                                napi_value object,
1267
                                uint32_t index,
1268
                                bool* result) {
1269


10
  NAPI_PREAMBLE(env);
1270
1271
3
  v8::Local<v8::Context> context = env->context();
1272
  v8::Local<v8::Object> obj;
1273
1274

10
  CHECK_TO_OBJECT(env, context, obj, object);
1275
2
  v8::Maybe<bool> delete_maybe = obj->Delete(context, index);
1276
2
  CHECK_MAYBE_NOTHING(env, delete_maybe, napi_generic_failure);
1277
1278
2
  if (result != nullptr)
1279
2
    *result = delete_maybe.FromMaybe(false);
1280
1281
2
  return GET_RETURN_STATUS(env);
1282
}
1283
1284
74
napi_status napi_define_properties(napi_env env,
1285
                                   napi_value object,
1286
                                   size_t property_count,
1287
                                   const napi_property_descriptor* properties) {
1288


220
  NAPI_PREAMBLE(env);
1289
73
  if (property_count > 0) {
1290
73
    CHECK_ARG(env, properties);
1291
  }
1292
1293
70
  v8::Local<v8::Context> context = env->context();
1294
1295
  v8::Local<v8::Object> obj;
1296

278
  CHECK_TO_OBJECT(env, context, obj, object);
1297
1298
912
  for (size_t i = 0; i < property_count; i++) {
1299
387
    const napi_property_descriptor* p = &properties[i];
1300
1301
    v8::Local<v8::Name> property_name;
1302
    napi_status status =
1303
387
        v8impl::V8NameFromPropertyDescriptor(env, p, &property_name);
1304
1305
387
    if (status != napi_ok) {
1306
      return napi_set_last_error(env, status);
1307
    }
1308
1309

387
    if (p->getter != nullptr || p->setter != nullptr) {
1310
      v8::Local<v8::Value> local_getter;
1311
      v8::Local<v8::Value> local_setter;
1312
1313
9
      if (p->getter != nullptr) {
1314
        v8::Local<v8::Value> getter_data =
1315
9
            v8impl::CreateFunctionCallbackData(env, p->getter, p->data);
1316
9
        CHECK_MAYBE_EMPTY(env, getter_data, napi_generic_failure);
1317
1318
        v8::MaybeLocal<v8::Function> maybe_getter =
1319
            v8::Function::New(context,
1320
                              v8impl::FunctionCallbackWrapper::Invoke,
1321
9
                              getter_data);
1322
9
        CHECK_MAYBE_EMPTY(env, maybe_getter, napi_generic_failure);
1323
1324
9
        local_getter = maybe_getter.ToLocalChecked();
1325
      }
1326
9
      if (p->setter != nullptr) {
1327
        v8::Local<v8::Value> setter_data =
1328
2
            v8impl::CreateFunctionCallbackData(env, p->setter, p->data);
1329
2
        CHECK_MAYBE_EMPTY(env, setter_data, napi_generic_failure);
1330
1331
        v8::MaybeLocal<v8::Function> maybe_setter =
1332
            v8::Function::New(context,
1333
                              v8impl::FunctionCallbackWrapper::Invoke,
1334
2
                              setter_data);
1335
2
        CHECK_MAYBE_EMPTY(env, maybe_setter, napi_generic_failure);
1336
2
        local_setter = maybe_setter.ToLocalChecked();
1337
      }
1338
1339
18
      v8::PropertyDescriptor descriptor(local_getter, local_setter);
1340
9
      descriptor.set_enumerable((p->attributes & napi_enumerable) != 0);
1341
9
      descriptor.set_configurable((p->attributes & napi_configurable) != 0);
1342
1343
      auto define_maybe = obj->DefineProperty(context,
1344
                                              property_name,
1345
9
                                              descriptor);
1346
1347
18
      if (!define_maybe.FromMaybe(false)) {
1348
        return napi_set_last_error(env, napi_invalid_arg);
1349
9
      }
1350
378
    } else if (p->method != nullptr) {
1351
      v8::Local<v8::Value> cbdata =
1352
363
          v8impl::CreateFunctionCallbackData(env, p->method, p->data);
1353
1354
363
      CHECK_MAYBE_EMPTY(env, cbdata, napi_generic_failure);
1355
1356
      v8::MaybeLocal<v8::Function> maybe_fn =
1357
          v8::Function::New(context,
1358
                            v8impl::FunctionCallbackWrapper::Invoke,
1359
363
                            cbdata);
1360
1361
363
      CHECK_MAYBE_EMPTY(env, maybe_fn, napi_generic_failure);
1362
1363
      v8::PropertyDescriptor descriptor(maybe_fn.ToLocalChecked(),
1364
1089
                                        (p->attributes & napi_writable) != 0);
1365
363
      descriptor.set_enumerable((p->attributes & napi_enumerable) != 0);
1366
363
      descriptor.set_configurable((p->attributes & napi_configurable) != 0);
1367
1368
      auto define_maybe = obj->DefineProperty(context,
1369
                                              property_name,
1370
363
                                              descriptor);
1371
1372
726
      if (!define_maybe.FromMaybe(false)) {
1373
        return napi_set_last_error(env, napi_generic_failure);
1374
      }
1375
    } else {
1376
15
      v8::Local<v8::Value> value = v8impl::V8LocalValueFromJsValue(p->value);
1377
1378
      v8::PropertyDescriptor descriptor(value,
1379
30
                                        (p->attributes & napi_writable) != 0);
1380
15
      descriptor.set_enumerable((p->attributes & napi_enumerable) != 0);
1381
15
      descriptor.set_configurable((p->attributes & napi_configurable) != 0);
1382
1383
      auto define_maybe =
1384
15
          obj->DefineProperty(context, property_name, descriptor);
1385
1386
30
      if (!define_maybe.FromMaybe(false)) {
1387
        return napi_set_last_error(env, napi_invalid_arg);
1388
      }
1389
    }
1390
  }
1391
1392
69
  return GET_RETURN_STATUS(env);
1393
}
1394
1395
11
napi_status napi_is_array(napi_env env, napi_value value, bool* result) {
1396
11
  CHECK_ENV(env);
1397
11
  CHECK_ARG(env, value);
1398
11
  CHECK_ARG(env, result);
1399
1400
11
  v8::Local<v8::Value> val = v8impl::V8LocalValueFromJsValue(value);
1401
1402
22
  *result = val->IsArray();
1403
11
  return napi_clear_last_error(env);
1404
}
1405
1406
13
napi_status napi_get_array_length(napi_env env,
1407
                                  napi_value value,
1408
                                  uint32_t* result) {
1409


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


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


19
  NAPI_PREAMBLE(env);
1442
6
  CHECK_ARG(env, result);
1443
1444
5
  v8::Local<v8::Context> context = env->context();
1445
1446
  v8::Local<v8::Object> obj;
1447

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

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

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

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


36
  NAPI_PREAMBLE(env);
1629
12
  CHECK_ARG(env, words);
1630
12
  CHECK_ARG(env, result);
1631
1632
12
  v8::Local<v8::Context> context = env->context();
1633
1634
12
  RETURN_STATUS_IF_FALSE(
1635
      env, word_count <= INT_MAX, napi_invalid_arg);
1636
1637
  v8::MaybeLocal<v8::BigInt> b = v8::BigInt::NewFromWords(
1638
11
      context, sign_bit, word_count, words);
1639
1640
11
  if (try_catch.HasCaught()) {
1641
    return napi_set_last_error(env, napi_pending_exception);
1642
  } else {
1643
11
    CHECK_MAYBE_EMPTY(env, b, napi_generic_failure);
1644
22
    *result = v8impl::JsValueFromV8LocalValue(b.ToLocalChecked());
1645
11
    return napi_clear_last_error(env);
1646
  }
1647
}
1648
1649
1262
napi_status napi_get_boolean(napi_env env, bool value, napi_value* result) {
1650
1262
  CHECK_ENV(env);
1651
1262
  CHECK_ARG(env, result);
1652
1653
1262
  v8::Isolate* isolate = env->isolate;
1654
1655
1262
  if (value) {
1656
1434
    *result = v8impl::JsValueFromV8LocalValue(v8::True(isolate));
1657
  } else {
1658
1090
    *result = v8impl::JsValueFromV8LocalValue(v8::False(isolate));
1659
  }
1660
1661
1262
  return napi_clear_last_error(env);
1662
}
1663
1664
13
napi_status napi_create_symbol(napi_env env,
1665
                               napi_value description,
1666
                               napi_value* result) {
1667
13
  CHECK_ENV(env);
1668
13
  CHECK_ARG(env, result);
1669
1670
13
  v8::Isolate* isolate = env->isolate;
1671
1672
13
  if (description == nullptr) {
1673
6
    *result = v8impl::JsValueFromV8LocalValue(v8::Symbol::New(isolate));
1674
  } else {
1675
11
    v8::Local<v8::Value> desc = v8impl::V8LocalValueFromJsValue(description);
1676
22
    RETURN_STATUS_IF_FALSE(env, desc->IsString(), napi_string_expected);
1677
1678
33
    *result = v8impl::JsValueFromV8LocalValue(
1679
      v8::Symbol::New(isolate, desc.As<v8::String>()));
1680
  }
1681
1682
13
  return napi_clear_last_error(env);
1683
}
1684
1685
205
static inline napi_status set_error_code(napi_env env,
1686
                                         v8::Local<v8::Value> error,
1687
                                         napi_value code,
1688
                                         const char* code_cstring) {
1689

205
  if ((code != nullptr) || (code_cstring != nullptr)) {
1690
115
    v8::Local<v8::Context> context = env->context();
1691
115
    v8::Local<v8::Object> err_object = error.As<v8::Object>();
1692
1693
115
    v8::Local<v8::Value> code_value = v8impl::V8LocalValueFromJsValue(code);
1694
115
    if (code != nullptr) {
1695
4
      code_value = v8impl::V8LocalValueFromJsValue(code);
1696
8
      RETURN_STATUS_IF_FALSE(env, code_value->IsString(), napi_string_expected);
1697
    } else {
1698

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


1963
  NAPI_PREAMBLE(env);
1891
653
  CHECK_ARG(env, recv);
1892
653
  if (argc > 0) {
1893
602
    CHECK_ARG(env, argv);
1894
  }
1895
1896
653
  v8::Local<v8::Context> context = env->context();
1897
1898
653
  v8::Local<v8::Value> v8recv = v8impl::V8LocalValueFromJsValue(recv);
1899
1900
  v8::Local<v8::Function> v8func;
1901

1959
  CHECK_TO_FUNCTION(env, v8func, func);
1902
1903
  auto maybe = v8func->Call(context, v8recv, argc,
1904
1306
    reinterpret_cast<v8::Local<v8::Value>*>(const_cast<napi_value*>(argv)));
1905
1906
653
  if (try_catch.HasCaught()) {
1907
6
    return napi_set_last_error(env, napi_pending_exception);
1908
  } else {
1909
647
    if (result != nullptr) {
1910
7
      CHECK_MAYBE_EMPTY(env, maybe, napi_generic_failure);
1911
7
      *result = v8impl::JsValueFromV8LocalValue(maybe.ToLocalChecked());
1912
    }
1913
647
    return napi_clear_last_error(env);
1914
  }
1915
}
1916
1917
10
napi_status napi_get_global(napi_env env, napi_value* result) {
1918
10
  CHECK_ENV(env);
1919
10
  CHECK_ARG(env, result);
1920
1921
30
  *result = v8impl::JsValueFromV8LocalValue(env->context()->Global());
1922
1923
10
  return napi_clear_last_error(env);
1924
}
1925
1926
11
napi_status napi_throw(napi_env env, napi_value error) {
1927


33
  NAPI_PREAMBLE(env);
1928
11
  CHECK_ARG(env, error);
1929
1930
11
  v8::Isolate* isolate = env->isolate;
1931
1932
11
  isolate->ThrowException(v8impl::V8LocalValueFromJsValue(error));
1933
  // any VM calls after this point and before returning
1934
  // to the javascript invoker will fail
1935
11
  return napi_clear_last_error(env);
1936
}
1937
1938
88
napi_status napi_throw_error(napi_env env,
1939
                             const char* code,
1940
                             const char* msg) {
1941


261
  NAPI_PREAMBLE(env);
1942
1943
85
  v8::Isolate* isolate = env->isolate;
1944
  v8::Local<v8::String> str;
1945

255
  CHECK_NEW_FROM_UTF8(env, str, msg);
1946
1947
85
  v8::Local<v8::Value> error_obj = v8::Exception::Error(str);
1948
85
  napi_status status = set_error_code(env, error_obj, nullptr, code);
1949
85
  if (status != napi_ok) return status;
1950
1951
85
  isolate->ThrowException(error_obj);
1952
  // any VM calls after this point and before returning
1953
  // to the javascript invoker will fail
1954
85
  return napi_clear_last_error(env);
1955
}
1956
1957
90
napi_status napi_throw_type_error(napi_env env,
1958
                                  const char* code,
1959
                                  const char* msg) {
1960


270
  NAPI_PREAMBLE(env);
1961
1962
90
  v8::Isolate* isolate = env->isolate;
1963
  v8::Local<v8::String> str;
1964

270
  CHECK_NEW_FROM_UTF8(env, str, msg);
1965
1966
90
  v8::Local<v8::Value> error_obj = v8::Exception::TypeError(str);
1967
90
  napi_status status = set_error_code(env, error_obj, nullptr, code);
1968
90
  if (status != napi_ok) return status;
1969
1970
90
  isolate->ThrowException(error_obj);
1971
  // any VM calls after this point and before returning
1972
  // to the javascript invoker will fail
1973
90
  return napi_clear_last_error(env);
1974
}
1975
1976
22
napi_status napi_throw_range_error(napi_env env,
1977
                                   const char* code,
1978
                                   const char* msg) {
1979


66
  NAPI_PREAMBLE(env);
1980
1981
22
  v8::Isolate* isolate = env->isolate;
1982
  v8::Local<v8::String> str;
1983

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

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


42
  NAPI_PREAMBLE(env);
2309
14
  CHECK_ARG(env, value);
2310
14
  CHECK_ARG(env, result);
2311
2312
14
  v8::Isolate* isolate = env->isolate;
2313
  v8::Local<v8::Boolean> b =
2314
28
    v8impl::V8LocalValueFromJsValue(value)->ToBoolean(isolate);
2315
28
  *result = v8impl::JsValueFromV8LocalValue(b);
2316
14
  return GET_RETURN_STATUS(env);
2317
}
2318
2319
#define GEN_COERCE_FUNCTION(UpperCaseName, MixedCaseName, LowerCaseName)      \
2320
  napi_status napi_coerce_to_##LowerCaseName(napi_env env,                    \
2321
                                             napi_value value,                \
2322
                                             napi_value* result) {            \
2323
    NAPI_PREAMBLE(env);                                                       \
2324
    CHECK_ARG(env, value);                                                    \
2325
    CHECK_ARG(env, result);                                                   \
2326
                                                                              \
2327
    v8::Local<v8::Context> context = env->context();                          \
2328
    v8::Local<v8::MixedCaseName> str;                                         \
2329
                                                                              \
2330
    CHECK_TO_##UpperCaseName(env, context, str, value);                       \
2331
                                                                              \
2332
    *result = v8impl::JsValueFromV8LocalValue(str);                           \
2333
    return GET_RETURN_STATUS(env);                                            \
2334
  }
2335
2336




103
GEN_COERCE_FUNCTION(NUMBER, Number, number)
2337




105
GEN_COERCE_FUNCTION(OBJECT, Object, object)
2338




96
GEN_COERCE_FUNCTION(STRING, String, string)
2339
2340
#undef GEN_COERCE_FUNCTION
2341
2342
1021
napi_status napi_wrap(napi_env env,
2343
                      napi_value js_object,
2344
                      void* native_object,
2345
                      napi_finalize finalize_cb,
2346
                      void* finalize_hint,
2347
                      napi_ref* result) {
2348
  return v8impl::Wrap<v8impl::retrievable>(env,
2349
                                           js_object,
2350
                                           native_object,
2351
                                           finalize_cb,
2352
                                           finalize_hint,
2353
1021
                                           result);
2354
}
2355
2356
25
napi_status napi_unwrap(napi_env env, napi_value obj, void** result) {
2357
25
  return v8impl::Unwrap(env, obj, result, v8impl::KeepWrap);
2358
}
2359
2360
4
napi_status napi_remove_wrap(napi_env env, napi_value obj, void** result) {
2361
4
  return v8impl::Unwrap(env, obj, result, v8impl::RemoveWrap);
2362
}
2363
2364
6
napi_status napi_create_external(napi_env env,
2365
                                 void* data,
2366
                                 napi_finalize finalize_cb,
2367
                                 void* finalize_hint,
2368
                                 napi_value* result) {
2369


18
  NAPI_PREAMBLE(env);
2370
6
  CHECK_ARG(env, result);
2371
2372
6
  v8::Isolate* isolate = env->isolate;
2373
2374
6
  v8::Local<v8::Value> external_value = v8::External::New(isolate, data);
2375
2376
  // The Reference object will delete itself after invoking the finalizer
2377
  // callback.
2378
  v8impl::Reference::New(env,
2379
      external_value,
2380
      0,
2381
      true,
2382
      finalize_cb,
2383
      data,
2384
6
      finalize_hint);
2385
2386
6
  *result = v8impl::JsValueFromV8LocalValue(external_value);
2387
2388
6
  return napi_clear_last_error(env);
2389
}
2390
2391
2
napi_status napi_get_value_external(napi_env env,
2392
                                    napi_value value,
2393
                                    void** result) {
2394
2
  CHECK_ENV(env);
2395
2
  CHECK_ARG(env, value);
2396
2
  CHECK_ARG(env, result);
2397
2398
2
  v8::Local<v8::Value> val = v8impl::V8LocalValueFromJsValue(value);
2399
2
  RETURN_STATUS_IF_FALSE(env, val->IsExternal(), napi_invalid_arg);
2400
2401
2
  v8::Local<v8::External> external_value = val.As<v8::External>();
2402
4
  *result = external_value->Value();
2403
2404
2
  return napi_clear_last_error(env);
2405
}
2406
2407
// Set initial_refcount to 0 for a weak reference, >0 for a strong reference.
2408
1538
napi_status napi_create_reference(napi_env env,
2409
                                  napi_value value,
2410
                                  uint32_t initial_refcount,
2411
                                  napi_ref* result) {
2412
  // Omit NAPI_PREAMBLE and GET_RETURN_STATUS because V8 calls here cannot throw
2413
  // JS exceptions.
2414
1538
  CHECK_ENV(env);
2415
1538
  CHECK_ARG(env, value);
2416
1538
  CHECK_ARG(env, result);
2417
2418
1538
  v8::Local<v8::Value> v8_value = v8impl::V8LocalValueFromJsValue(value);
2419
2420

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


21
  NAPI_PREAMBLE(env);
2591
7
  CHECK_ARG(env, constructor);
2592
7
  if (argc > 0) {
2593
7
    CHECK_ARG(env, argv);
2594
  }
2595
7
  CHECK_ARG(env, result);
2596
2597
7
  v8::Local<v8::Context> context = env->context();
2598
2599
  v8::Local<v8::Function> ctor;
2600

21
  CHECK_TO_FUNCTION(env, ctor, constructor);
2601
2602
  auto maybe = ctor->NewInstance(context, argc,
2603
14
    reinterpret_cast<v8::Local<v8::Value>*>(const_cast<napi_value*>(argv)));
2604
2605
7
  CHECK_MAYBE_EMPTY(env, maybe, napi_generic_failure);
2606
2607
14
  *result = v8impl::JsValueFromV8LocalValue(maybe.ToLocalChecked());
2608
7
  return GET_RETURN_STATUS(env);
2609
}
2610
2611
2278
napi_status napi_instanceof(napi_env env,
2612
                            napi_value object,
2613
                            napi_value constructor,
2614
                            bool* result) {
2615


6834
  NAPI_PREAMBLE(env);
2616
2278
  CHECK_ARG(env, object);
2617
2278
  CHECK_ARG(env, result);
2618
2619
2278
  *result = false;
2620
2621
  v8::Local<v8::Object> ctor;
2622
2278
  v8::Local<v8::Context> context = env->context();
2623
2624

9112
  CHECK_TO_OBJECT(env, context, ctor, constructor);
2625
2626
2278
  if (!ctor->IsFunction()) {
2627
    napi_throw_type_error(env,
2628
                          "ERR_NAPI_CONS_FUNCTION",
2629
88
                          "Constructor must be a function");
2630
2631
88
    return napi_set_last_error(env, napi_function_expected);
2632
  }
2633
2634
2190
  napi_status status = napi_generic_failure;
2635
2636
2190
  v8::Local<v8::Value> val = v8impl::V8LocalValueFromJsValue(object);
2637
2190
  auto maybe_result = val->InstanceOf(context, ctor);
2638
2190
  CHECK_MAYBE_NOTHING(env, maybe_result, status);
2639
2332
  *result = maybe_result.FromJust();
2640
1166
  return GET_RETURN_STATUS(env);
2641
}
2642
2643
// Methods to support catching exceptions
2644
1238
napi_status napi_is_exception_pending(napi_env env, bool* result) {
2645
  // NAPI_PREAMBLE is not used here: this function must execute when there is a
2646
  // pending exception.
2647
1238
  CHECK_ENV(env);
2648
1238
  CHECK_ARG(env, result);
2649
2650
2476
  *result = !env->last_exception.IsEmpty();
2651
1238
  return napi_clear_last_error(env);
2652
}
2653
2654
1
napi_status napi_get_and_clear_last_exception(napi_env env,
2655
                                              napi_value* result) {
2656
  // NAPI_PREAMBLE is not used here: this function must execute when there is a
2657
  // pending exception.
2658
1
  CHECK_ENV(env);
2659
1
  CHECK_ARG(env, result);
2660
2661
2
  if (env->last_exception.IsEmpty()) {
2662
    return napi_get_undefined(env, result);
2663
  } else {
2664
2
    *result = v8impl::JsValueFromV8LocalValue(
2665
1
      v8::Local<v8::Value>::New(env->isolate, env->last_exception));
2666
1
    env->last_exception.Reset();
2667
  }
2668
2669
1
  return napi_clear_last_error(env);
2670
}
2671
2672
35
napi_status napi_is_arraybuffer(napi_env env, napi_value value, bool* result) {
2673
35
  CHECK_ENV(env);
2674
35
  CHECK_ARG(env, value);
2675
35
  CHECK_ARG(env, result);
2676
2677
35
  v8::Local<v8::Value> val = v8impl::V8LocalValueFromJsValue(value);
2678
70
  *result = val->IsArrayBuffer();
2679
2680
35
  return napi_clear_last_error(env);
2681
}
2682
2683
2
napi_status napi_create_arraybuffer(napi_env env,
2684
                                    size_t byte_length,
2685
                                    void** data,
2686
                                    napi_value* result) {
2687


6
  NAPI_PREAMBLE(env);
2688
2
  CHECK_ARG(env, result);
2689
2690
2
  v8::Isolate* isolate = env->isolate;
2691
  v8::Local<v8::ArrayBuffer> buffer =
2692
2
      v8::ArrayBuffer::New(isolate, byte_length);
2693
2694
  // Optionally return a pointer to the buffer's data, to avoid another call to
2695
  // retrieve it.
2696
2
  if (data != nullptr) {
2697
2
    *data = buffer->GetBackingStore()->Data();
2698
  }
2699
2700
4
  *result = v8impl::JsValueFromV8LocalValue(buffer);
2701
2
  return GET_RETURN_STATUS(env);
2702
}
2703
2704
6
napi_status napi_create_external_arraybuffer(napi_env env,
2705
                                             void* external_data,
2706
                                             size_t byte_length,
2707
                                             napi_finalize finalize_cb,
2708
                                             void* finalize_hint,
2709
                                             napi_value* result) {
2710


18
  NAPI_PREAMBLE(env);
2711
6
  CHECK_ARG(env, result);
2712
2713
6
  v8::Isolate* isolate = env->isolate;
2714
  // The buffer will be freed with v8impl::ArrayBufferReference::New()
2715
  // below, hence this BackingStore does not need to free the buffer.
2716
  std::unique_ptr<v8::BackingStore> backing =
2717
      v8::ArrayBuffer::NewBackingStore(external_data,
2718
                                       byte_length,
2719
16
                                       [](void*, size_t, void*){},
2720
12
                                       nullptr);
2721
  v8::Local<v8::ArrayBuffer> buffer =
2722
6
      v8::ArrayBuffer::New(isolate, std::move(backing));
2723
  // TODO(thangktran): drop this check when V8 is pumped to 8.0 .
2724
6
  if (!buffer->IsExternal())
2725
12
    buffer->Externalize(buffer->GetBackingStore());
2726
6
  v8::Maybe<bool> marked = env->mark_arraybuffer_as_untransferable(buffer);
2727
6
  CHECK_MAYBE_NOTHING(env, marked, napi_generic_failure);
2728
2729
6
  if (finalize_cb != nullptr) {
2730
    // Create a self-deleting weak reference that invokes the finalizer
2731
    // callback and detaches the ArrayBuffer if it still exists on Environment
2732
    // teardown.
2733
10
    v8impl::ArrayBufferReference::New(env,
2734
        buffer,
2735
        0,
2736
        true,
2737
        finalize_cb,
2738
        external_data,
2739
5
        finalize_hint);
2740
  }
2741
2742
12
  *result = v8impl::JsValueFromV8LocalValue(buffer);
2743
6
  return GET_RETURN_STATUS(env);
2744
}
2745
2746
2
napi_status napi_get_arraybuffer_info(napi_env env,
2747
                                      napi_value arraybuffer,
2748
                                      void** data,
2749
                                      size_t* byte_length) {
2750
2
  CHECK_ENV(env);
2751
2
  CHECK_ARG(env, arraybuffer);
2752
2753
2
  v8::Local<v8::Value> value = v8impl::V8LocalValueFromJsValue(arraybuffer);
2754
2
  RETURN_STATUS_IF_FALSE(env, value->IsArrayBuffer(), napi_invalid_arg);
2755
2756
  std::shared_ptr<v8::BackingStore> backing_store =
2757
6
      value.As<v8::ArrayBuffer>()->GetBackingStore();
2758
2759
2
  if (data != nullptr) {
2760
2
    *data = backing_store->Data();
2761
  }
2762
2763
2
  if (byte_length != nullptr) {
2764
2
    *byte_length = backing_store->ByteLength();
2765
  }
2766
2767
2
  return napi_clear_last_error(env);
2768
}
2769
2770
44
napi_status napi_is_typedarray(napi_env env, napi_value value, bool* result) {
2771
44
  CHECK_ENV(env);
2772
44
  CHECK_ARG(env, value);
2773
44
  CHECK_ARG(env, result);
2774
2775
44
  v8::Local<v8::Value> val = v8impl::V8LocalValueFromJsValue(value);
2776
88
  *result = val->IsTypedArray();
2777
2778
44
  return napi_clear_last_error(env);
2779
}
2780
2781
34
napi_status napi_create_typedarray(napi_env env,
2782
                                   napi_typedarray_type type,
2783
                                   size_t length,
2784
                                   napi_value arraybuffer,
2785
                                   size_t byte_offset,
2786
                                   napi_value* result) {
2787


102
  NAPI_PREAMBLE(env);
2788
34
  CHECK_ARG(env, arraybuffer);
2789
34
  CHECK_ARG(env, result);
2790
2791
34
  v8::Local<v8::Value> value = v8impl::V8LocalValueFromJsValue(arraybuffer);
2792
34
  RETURN_STATUS_IF_FALSE(env, value->IsArrayBuffer(), napi_invalid_arg);
2793
2794
34
  v8::Local<v8::ArrayBuffer> buffer = value.As<v8::ArrayBuffer>();
2795
  v8::Local<v8::TypedArray> typedArray;
2796
2797



34
  switch (type) {
2798
    case napi_int8_array:
2799
11
      CREATE_TYPED_ARRAY(
2800
          env, Int8Array, 1, buffer, byte_offset, length, typedArray);
2801
3
      break;
2802
    case napi_uint8_array:
2803
8
      CREATE_TYPED_ARRAY(
2804
          env, Uint8Array, 1, buffer, byte_offset, length, typedArray);
2805
2
      break;
2806
    case napi_uint8_clamped_array:
2807
5
      CREATE_TYPED_ARRAY(
2808
          env, Uint8ClampedArray, 1, buffer, byte_offset, length, typedArray);
2809
1
      break;
2810
    case napi_int16_array:
2811

6
      CREATE_TYPED_ARRAY(
2812
          env, Int16Array, 2, buffer, byte_offset, length, typedArray);
2813
1
      break;
2814
    case napi_uint16_array:
2815

6
      CREATE_TYPED_ARRAY(
2816
          env, Uint16Array, 2, buffer, byte_offset, length, typedArray);
2817
1
      break;
2818
    case napi_int32_array:
2819

6
      CREATE_TYPED_ARRAY(
2820
          env, Int32Array, 4, buffer, byte_offset, length, typedArray);
2821
1
      break;
2822
    case napi_uint32_array:
2823

6
      CREATE_TYPED_ARRAY(
2824
          env, Uint32Array, 4, buffer, byte_offset, length, typedArray);
2825
1
      break;
2826
    case napi_float32_array:
2827

6
      CREATE_TYPED_ARRAY(
2828
          env, Float32Array, 4, buffer, byte_offset, length, typedArray);
2829
1
      break;
2830
    case napi_float64_array:
2831

9
      CREATE_TYPED_ARRAY(
2832
          env, Float64Array, 8, buffer, byte_offset, length, typedArray);
2833
2
      break;
2834
    case napi_bigint64_array:
2835

6
      CREATE_TYPED_ARRAY(
2836
          env, BigInt64Array, 8, buffer, byte_offset, length, typedArray);
2837
1
      break;
2838
    case napi_biguint64_array:
2839

6
      CREATE_TYPED_ARRAY(
2840
          env, BigUint64Array, 8, buffer, byte_offset, length, typedArray);
2841
1
      break;
2842
    default:
2843
      return napi_set_last_error(env, napi_invalid_arg);
2844
  }
2845
2846
30
  *result = v8impl::JsValueFromV8LocalValue(typedArray);
2847
15
  return GET_RETURN_STATUS(env);
2848
}
2849
2850
44
napi_status napi_get_typedarray_info(napi_env env,
2851
                                     napi_value typedarray,
2852
                                     napi_typedarray_type* type,
2853
                                     size_t* length,
2854
                                     void** data,
2855
                                     napi_value* arraybuffer,
2856
                                     size_t* byte_offset) {
2857
44
  CHECK_ENV(env);
2858
44
  CHECK_ARG(env, typedarray);
2859
2860
44
  v8::Local<v8::Value> value = v8impl::V8LocalValueFromJsValue(typedarray);
2861
44
  RETURN_STATUS_IF_FALSE(env, value->IsTypedArray(), napi_invalid_arg);
2862
2863
44
  v8::Local<v8::TypedArray> array = value.As<v8::TypedArray>();
2864
2865
44
  if (type != nullptr) {
2866
32
    if (value->IsInt8Array()) {
2867
2
      *type = napi_int8_array;
2868
30
    } else if (value->IsUint8Array()) {
2869
3
      *type = napi_uint8_array;
2870
27
    } else if (value->IsUint8ClampedArray()) {
2871
2
      *type = napi_uint8_clamped_array;
2872
25
    } else if (value->IsInt16Array()) {
2873
3
      *type = napi_int16_array;
2874
22
    } else if (value->IsUint16Array()) {
2875
3
      *type = napi_uint16_array;
2876
19
    } else if (value->IsInt32Array()) {
2877
3
      *type = napi_int32_array;
2878
16
    } else if (value->IsUint32Array()) {
2879
3
      *type = napi_uint32_array;
2880
13
    } else if (value->IsFloat32Array()) {
2881
3
      *type = napi_float32_array;
2882
10
    } else if (value->IsFloat64Array()) {
2883
4
      *type = napi_float64_array;
2884
6
    } else if (value->IsBigInt64Array()) {
2885
3
      *type = napi_bigint64_array;
2886
3
    } else if (value->IsBigUint64Array()) {
2887
3
      *type = napi_biguint64_array;
2888
    }
2889
  }
2890
2891
44
  if (length != nullptr) {
2892
32
    *length = array->Length();
2893
  }
2894
2895
  v8::Local<v8::ArrayBuffer> buffer;
2896

44
  if (data != nullptr || arraybuffer != nullptr) {
2897
    // Calling Buffer() may have the side effect of allocating the buffer,
2898
    // so only do this when it’s needed.
2899
44
    buffer = array->Buffer();
2900
  }
2901
2902
44
  if (data != nullptr) {
2903
    *data = static_cast<uint8_t*>(buffer->GetBackingStore()->Data()) +
2904
            array->ByteOffset();
2905
  }
2906
2907
44
  if (arraybuffer != nullptr) {
2908
44
    *arraybuffer = v8impl::JsValueFromV8LocalValue(buffer);
2909
  }
2910
2911
44
  if (byte_offset != nullptr) {
2912
32
    *byte_offset = array->ByteOffset();
2913
  }
2914
2915
44
  return napi_clear_last_error(env);
2916
}
2917
2918
2
napi_status napi_create_dataview(napi_env env,
2919
                                 size_t byte_length,
2920
                                 napi_value arraybuffer,
2921
                                 size_t byte_offset,
2922
                                 napi_value* result) {
2923


6
  NAPI_PREAMBLE(env);
2924
2
  CHECK_ARG(env, arraybuffer);
2925
2
  CHECK_ARG(env, result);
2926
2927
2
  v8::Local<v8::Value> value = v8impl::V8LocalValueFromJsValue(arraybuffer);
2928
2
  RETURN_STATUS_IF_FALSE(env, value->IsArrayBuffer(), napi_invalid_arg);
2929
2930
2
  v8::Local<v8::ArrayBuffer> buffer = value.As<v8::ArrayBuffer>();
2931
4
  if (byte_length + byte_offset > buffer->ByteLength()) {
2932
    napi_throw_range_error(
2933
        env,
2934
        "ERR_NAPI_INVALID_DATAVIEW_ARGS",
2935
        "byte_offset + byte_length should be less than or "
2936
1
        "equal to the size in bytes of the array passed in");
2937
1
    return napi_set_last_error(env, napi_pending_exception);
2938
  }
2939
  v8::Local<v8::DataView> DataView = v8::DataView::New(buffer, byte_offset,
2940
1
                                                       byte_length);
2941
2942
2
  *result = v8impl::JsValueFromV8LocalValue(DataView);
2943
1
  return GET_RETURN_STATUS(env);
2944
}
2945
2946
1
napi_status napi_is_dataview(napi_env env, napi_value value, bool* result) {
2947
1
  CHECK_ENV(env);
2948
1
  CHECK_ARG(env, value);
2949
1
  CHECK_ARG(env, result);
2950
2951
1
  v8::Local<v8::Value> val = v8impl::V8LocalValueFromJsValue(value);
2952
2
  *result = val->IsDataView();
2953
2954
1
  return napi_clear_last_error(env);
2955
}
2956
2957
1
napi_status napi_get_dataview_info(napi_env env,
2958
                                   napi_value dataview,
2959
                                   size_t* byte_length,
2960
                                   void** data,
2961
                                   napi_value* arraybuffer,
2962
                                   size_t* byte_offset) {
2963
1
  CHECK_ENV(env);
2964
1
  CHECK_ARG(env, dataview);
2965
2966
1
  v8::Local<v8::Value> value = v8impl::V8LocalValueFromJsValue(dataview);
2967
1
  RETURN_STATUS_IF_FALSE(env, value->IsDataView(), napi_invalid_arg);
2968
2969
1
  v8::Local<v8::DataView> array = value.As<v8::DataView>();
2970
2971
1
  if (byte_length != nullptr) {
2972
1
    *byte_length = array->ByteLength();
2973
  }
2974
2975
  v8::Local<v8::ArrayBuffer> buffer;
2976

1
  if (data != nullptr || arraybuffer != nullptr) {
2977
    // Calling Buffer() may have the side effect of allocating the buffer,
2978
    // so only do this when it’s needed.
2979
1
    buffer = array->Buffer();
2980
  }
2981
2982
1
  if (data != nullptr) {
2983
    *data = static_cast<uint8_t*>(buffer->GetBackingStore()->Data()) +
2984
            array->ByteOffset();
2985
  }
2986
2987
1
  if (arraybuffer != nullptr) {
2988
1
    *arraybuffer = v8impl::JsValueFromV8LocalValue(buffer);
2989
  }
2990
2991
1
  if (byte_offset != nullptr) {
2992
1
    *byte_offset = array->ByteOffset();
2993
  }
2994
2995
1
  return napi_clear_last_error(env);
2996
}
2997
2998
1
napi_status napi_get_version(napi_env env, uint32_t* result) {
2999
1
  CHECK_ENV(env);
3000
1
  CHECK_ARG(env, result);
3001
1
  *result = NAPI_VERSION;
3002
1
  return napi_clear_last_error(env);
3003
}
3004
3005
5
napi_status napi_create_promise(napi_env env,
3006
                                napi_deferred* deferred,
3007
                                napi_value* promise) {
3008


15
  NAPI_PREAMBLE(env);
3009
5
  CHECK_ARG(env, deferred);
3010
5
  CHECK_ARG(env, promise);
3011
3012
5
  auto maybe = v8::Promise::Resolver::New(env->context());
3013
5
  CHECK_MAYBE_EMPTY(env, maybe, napi_generic_failure);
3014
3015
5
  auto v8_resolver = maybe.ToLocalChecked();
3016
10
  auto v8_deferred = new v8impl::Persistent<v8::Value>();
3017
5
  v8_deferred->Reset(env->isolate, v8_resolver);
3018
3019
5
  *deferred = v8impl::JsDeferredFromNodePersistent(v8_deferred);
3020
15
  *promise = v8impl::JsValueFromV8LocalValue(v8_resolver->GetPromise());
3021
5
  return GET_RETURN_STATUS(env);
3022
}
3023
3024
4
napi_status napi_resolve_deferred(napi_env env,
3025
                                  napi_deferred deferred,
3026
                                  napi_value resolution) {
3027
4
  return v8impl::ConcludeDeferred(env, deferred, resolution, true);
3028
}
3029
3030
1
napi_status napi_reject_deferred(napi_env env,
3031
                                 napi_deferred deferred,
3032
                                 napi_value resolution) {
3033
1
  return v8impl::ConcludeDeferred(env, deferred, resolution, false);
3034
}
3035
3036
7
napi_status napi_is_promise(napi_env env,
3037
                            napi_value value,
3038
                            bool* is_promise) {
3039
7
  CHECK_ENV(env);
3040
7
  CHECK_ARG(env, value);
3041
7
  CHECK_ARG(env, is_promise);
3042
3043
14
  *is_promise = v8impl::V8LocalValueFromJsValue(value)->IsPromise();
3044
3045
7
  return napi_clear_last_error(env);
3046
}
3047
3048
1
napi_status napi_create_date(napi_env env,
3049
                             double time,
3050
                             napi_value* result) {
3051


3
  NAPI_PREAMBLE(env);
3052
1
  CHECK_ARG(env, result);
3053
3054
1
  v8::MaybeLocal<v8::Value> maybe_date = v8::Date::New(env->context(), time);
3055
1
  CHECK_MAYBE_EMPTY(env, maybe_date, napi_generic_failure);
3056
3057
2
  *result = v8impl::JsValueFromV8LocalValue(maybe_date.ToLocalChecked());
3058
3059
1
  return GET_RETURN_STATUS(env);
3060
}
3061
3062
7
napi_status napi_is_date(napi_env env,
3063
                         napi_value value,
3064
                         bool* is_date) {
3065
7
  CHECK_ENV(env);
3066
7
  CHECK_ARG(env, value);
3067
7
  CHECK_ARG(env, is_date);
3068
3069
14
  *is_date = v8impl::V8LocalValueFromJsValue(value)->IsDate();
3070
3071
7
  return napi_clear_last_error(env);
3072
}
3073
3074
1
napi_status napi_get_date_value(napi_env env,
3075
                                napi_value value,
3076
                                double* result) {
3077


3
  NAPI_PREAMBLE(env);
3078
1
  CHECK_ARG(env, value);
3079
1
  CHECK_ARG(env, result);
3080
3081
1
  v8::Local<v8::Value> val = v8impl::V8LocalValueFromJsValue(value);
3082
1
  RETURN_STATUS_IF_FALSE(env, val->IsDate(), napi_date_expected);
3083
3084
1
  v8::Local<v8::Date> date = val.As<v8::Date>();
3085
2
  *result = date->ValueOf();
3086
3087
1
  return GET_RETURN_STATUS(env);
3088
}
3089
3090
2
napi_status napi_run_script(napi_env env,
3091
                            napi_value script,
3092
                            napi_value* result) {
3093


6
  NAPI_PREAMBLE(env);
3094
2
  CHECK_ARG(env, script);
3095
2
  CHECK_ARG(env, result);
3096
3097
2
  v8::Local<v8::Value> v8_script = v8impl::V8LocalValueFromJsValue(script);
3098
3099
4
  if (!v8_script->IsString()) {
3100
1
    return napi_set_last_error(env, napi_string_expected);
3101
  }
3102
3103
1
  v8::Local<v8::Context> context = env->context();
3104
3105
  auto maybe_script = v8::Script::Compile(context,
3106
1
      v8::Local<v8::String>::Cast(v8_script));
3107
1
  CHECK_MAYBE_EMPTY(env, maybe_script, napi_generic_failure);
3108
3109
  auto script_result =
3110
2
      maybe_script.ToLocalChecked()->Run(context);
3111
1
  CHECK_MAYBE_EMPTY(env, script_result, napi_generic_failure);
3112
3113
2
  *result = v8impl::JsValueFromV8LocalValue(script_result.ToLocalChecked());
3114
1
  return GET_RETURN_STATUS(env);
3115
}
3116
3117
3
napi_status napi_add_finalizer(napi_env env,
3118
                               napi_value js_object,
3119
                               void* native_object,
3120
                               napi_finalize finalize_cb,
3121
                               void* finalize_hint,
3122
                               napi_ref* result) {
3123
  return v8impl::Wrap<v8impl::anonymous>(env,
3124
                                         js_object,
3125
                                         native_object,
3126
                                         finalize_cb,
3127
                                         finalize_hint,
3128
3
                                         result);
3129
}
3130
3131
1
napi_status napi_adjust_external_memory(napi_env env,
3132
                                        int64_t change_in_bytes,
3133
                                        int64_t* adjusted_value) {
3134
1
  CHECK_ENV(env);
3135
1
  CHECK_ARG(env, adjusted_value);
3136
3137
2
  *adjusted_value = env->isolate->AdjustAmountOfExternalAllocatedMemory(
3138
      change_in_bytes);
3139
3140
1
  return napi_clear_last_error(env);
3141
}
3142
3143
6
napi_status napi_set_instance_data(napi_env env,
3144
                                   void* data,
3145
                                   napi_finalize finalize_cb,
3146
                                   void* finalize_hint) {
3147
6
  CHECK_ENV(env);
3148
3149
6
  v8impl::RefBase* old_data = static_cast<v8impl::RefBase*>(env->instance_data);
3150
6
  if (old_data != nullptr) {
3151
    // Our contract so far has been to not finalize any old data there may be.
3152
    // So we simply delete it.
3153
    v8impl::RefBase::Delete(old_data);
3154
  }
3155
3156
6
  env->instance_data = v8impl::RefBase::New(env,
3157
                                            0,
3158
                                            true,
3159
                                            finalize_cb,
3160
                                            data,
3161
                                            finalize_hint);
3162
3163
6
  return napi_clear_last_error(env);
3164
}
3165
3166
22
napi_status napi_get_instance_data(napi_env env,
3167
                                   void** data) {
3168
22
  CHECK_ENV(env);
3169
22
  CHECK_ARG(env, data);
3170
3171
22
  v8impl::RefBase* idata = static_cast<v8impl::RefBase*>(env->instance_data);
3172
3173
22
  *data = (idata == nullptr ? nullptr : idata->Data());
3174
3175
22
  return napi_clear_last_error(env);
3176
}
3177
3178
12
napi_status napi_detach_arraybuffer(napi_env env, napi_value arraybuffer) {
3179
12
  CHECK_ENV(env);
3180
12
  CHECK_ARG(env, arraybuffer);
3181
3182
12
  v8::Local<v8::Value> value = v8impl::V8LocalValueFromJsValue(arraybuffer);
3183
12
  RETURN_STATUS_IF_FALSE(
3184
      env, value->IsArrayBuffer(), napi_arraybuffer_expected);
3185
3186
12
  v8::Local<v8::ArrayBuffer> it = value.As<v8::ArrayBuffer>();
3187
  // TODO(addaleax): Remove the first condition once we have V8 8.0.
3188
12
  RETURN_STATUS_IF_FALSE(
3189
      env, it->IsExternal(), napi_detachable_arraybuffer_expected);
3190
1
  RETURN_STATUS_IF_FALSE(
3191
      env, it->IsDetachable(), napi_detachable_arraybuffer_expected);
3192
3193
1
  it->Detach();
3194
3195
1
  return napi_clear_last_error(env);
3196
}
3197
3198
4
napi_status napi_is_detached_arraybuffer(napi_env env,
3199
                                         napi_value arraybuffer,
3200
                                         bool* result) {
3201
4
  CHECK_ENV(env);
3202
4
  CHECK_ARG(env, arraybuffer);
3203
4
  CHECK_ARG(env, result);
3204
3205
4
  v8::Local<v8::Value> value = v8impl::V8LocalValueFromJsValue(arraybuffer);
3206
3207

16
  *result = value->IsArrayBuffer() &&
3208
16
            value.As<v8::ArrayBuffer>()->GetBackingStore()->Data() == nullptr;
3209
3210
4
  return napi_clear_last_error(env);
3211
}