GCC Code Coverage Report
Directory: ../ Exec Total Coverage
File: /home/iojs/build/workspace/node-test-commit-linux-coverage/nodes/benchmark/out/../src/node_api.cc Lines: 1427 1495 95.5 %
Date: 2017-12-18 Branches: 774 1362 56.8 %

Line Branch Exec Source
1
/******************************************************************************
2
 * Experimental prototype for demonstrating VM agnostic and ABI stable API
3
 * for native modules to use instead of using Nan and V8 APIs directly.
4
 *
5
 * The current status is "Experimental" and should not be used for
6
 * production applications.  The API is still subject to change
7
 * and as an experimental feature is NOT subject to semver.
8
 *
9
 ******************************************************************************/
10
11
#include <node_buffer.h>
12
#include <node_object_wrap.h>
13
#include <limits.h>  // INT_MAX
14
#include <string.h>
15
#include <algorithm>
16
#include <cmath>
17
#include <vector>
18
#include "node_api.h"
19
#include "node_internals.h"
20
21
#define NAPI_VERSION  2
22
23
static
24
napi_status napi_set_last_error(napi_env env, napi_status error_code,
25
                                uint32_t engine_error_code = 0,
26
                                void* engine_reserved = nullptr);
27
static
28
napi_status napi_clear_last_error(napi_env env);
29
30
struct napi_env__ {
31
43
  explicit napi_env__(v8::Isolate* _isolate, uv_loop_t* _loop)
32
      : isolate(_isolate),
33
        last_error(),
34
215
        loop(_loop) {}
35
  ~napi_env__() {
36
    last_exception.Reset();
37
    wrap_template.Reset();
38
    function_data_template.Reset();
39
    accessor_data_template.Reset();
40
  }
41
  v8::Isolate* isolate;
42
  v8::Persistent<v8::Value> last_exception;
43
  v8::Persistent<v8::ObjectTemplate> wrap_template;
44
  v8::Persistent<v8::ObjectTemplate> function_data_template;
45
  v8::Persistent<v8::ObjectTemplate> accessor_data_template;
46
  napi_extended_error_info last_error;
47
  int open_handle_scopes = 0;
48
  uv_loop_t* loop = nullptr;
49
};
50
51
#define ENV_OBJECT_TEMPLATE(env, prefix, destination, field_count) \
52
  do {                                                             \
53
    if ((env)->prefix ## _template.IsEmpty()) {                    \
54
      (destination) = v8::ObjectTemplate::New(isolate);            \
55
      (destination)->SetInternalFieldCount((field_count));         \
56
      (env)->prefix ## _template.Reset(isolate, (destination));    \
57
    } else {                                                       \
58
      (destination) = v8::Local<v8::ObjectTemplate>::New(          \
59
          isolate, env->prefix ## _template);                      \
60
    }                                                              \
61
  } while (0)
62
63
64
#define RETURN_STATUS_IF_FALSE(env, condition, status)                  \
65
  do {                                                                  \
66
    if (!(condition)) {                                                 \
67
      return napi_set_last_error((env), (status));                      \
68
    }                                                                   \
69
  } while (0)
70
71
#define CHECK_ENV(env)        \
72
  if ((env) == nullptr) {     \
73
    return napi_invalid_arg;  \
74
  }
75
76
#define CHECK_ARG(env, arg) \
77
  RETURN_STATUS_IF_FALSE((env), ((arg) != nullptr), napi_invalid_arg)
78
79
#define CHECK_MAYBE_EMPTY(env, maybe, status) \
80
  RETURN_STATUS_IF_FALSE((env), !((maybe).IsEmpty()), (status))
81
82
#define CHECK_MAYBE_NOTHING(env, maybe, status) \
83
  RETURN_STATUS_IF_FALSE((env), !((maybe).IsNothing()), (status))
84
85
// NAPI_PREAMBLE is not wrapped in do..while: try_catch must have function scope
86
#define NAPI_PREAMBLE(env)                                       \
87
  CHECK_ENV((env));                                              \
88
  RETURN_STATUS_IF_FALSE((env), (env)->last_exception.IsEmpty(), \
89
                         napi_pending_exception);                \
90
  napi_clear_last_error((env));                                  \
91
  v8impl::TryCatch try_catch((env))
92
93
#define CHECK_TO_TYPE(env, type, context, result, src, status)                \
94
  do {                                                                        \
95
    CHECK_ARG((env), (src));                                                  \
96
    auto maybe = v8impl::V8LocalValueFromJsValue((src))->To##type((context)); \
97
    CHECK_MAYBE_EMPTY((env), maybe, (status));                                \
98
    (result) = maybe.ToLocalChecked();                                        \
99
  } while (0)
100
101
#define CHECK_TO_FUNCTION(env, result, src)                                 \
102
  do {                                                                      \
103
    CHECK_ARG((env), (src));                                                \
104
    v8::Local<v8::Value> v8value = v8impl::V8LocalValueFromJsValue((src));  \
105
    RETURN_STATUS_IF_FALSE((env), v8value->IsFunction(), napi_invalid_arg); \
106
    (result) = v8value.As<v8::Function>();                                  \
107
  } while (0)
108
109
#define CHECK_TO_OBJECT(env, context, result, src) \
110
  CHECK_TO_TYPE((env), Object, (context), (result), (src), napi_object_expected)
111
112
#define CHECK_TO_STRING(env, context, result, src) \
113
  CHECK_TO_TYPE((env), String, (context), (result), (src), napi_string_expected)
114
115
#define CHECK_TO_NUMBER(env, context, result, src) \
116
  CHECK_TO_TYPE((env), Number, (context), (result), (src), napi_number_expected)
117
118
#define CHECK_TO_BOOL(env, context, result, src)            \
119
  CHECK_TO_TYPE((env), Boolean, (context), (result), (src), \
120
    napi_boolean_expected)
121
122
// n-api defines NAPI_AUTO_LENGHTH as the indicator that a string
123
// is null terminated. For V8 the equivalent is -1. The assert
124
// validates that our cast of NAPI_AUTO_LENGTH results in -1 as
125
// needed by V8.
126
#define CHECK_NEW_FROM_UTF8_LEN(env, result, str, len)                   \
127
  do {                                                                   \
128
    static_assert(static_cast<int>(NAPI_AUTO_LENGTH) == -1,              \
129
                  "Casting NAPI_AUTO_LENGTH to int must result in -1");  \
130
    RETURN_STATUS_IF_FALSE((env),                                        \
131
        (len == NAPI_AUTO_LENGTH) || len <= INT_MAX,                     \
132
        napi_invalid_arg);                                               \
133
    auto str_maybe = v8::String::NewFromUtf8(                            \
134
        (env)->isolate, (str), v8::NewStringType::kInternalized,         \
135
        static_cast<int>(len));                                          \
136
    CHECK_MAYBE_EMPTY((env), str_maybe, napi_generic_failure);           \
137
    (result) = str_maybe.ToLocalChecked();                               \
138
  } while (0)
139
140
#define CHECK_NEW_FROM_UTF8(env, result, str) \
141
  CHECK_NEW_FROM_UTF8_LEN((env), (result), (str), NAPI_AUTO_LENGTH)
142
143
#define GET_RETURN_STATUS(env)      \
144
  (!try_catch.HasCaught() ? napi_ok \
145
                         : napi_set_last_error((env), napi_pending_exception))
146
147
namespace {
148
namespace v8impl {
149
150
// convert from n-api property attributes to v8::PropertyAttribute
151
208
static inline v8::PropertyAttribute V8PropertyAttributesFromDescriptor(
152
    const napi_property_descriptor* descriptor) {
153
208
  unsigned int attribute_flags = v8::PropertyAttribute::None;
154
155

208
  if (descriptor->getter != nullptr || descriptor->setter != nullptr) {
156
    // The napi_writable attribute is ignored for accessor descriptors, but
157
    // V8 requires the ReadOnly attribute to match nonexistence of a setter.
158
12
    attribute_flags |= (descriptor->setter == nullptr ?
159
12
      v8::PropertyAttribute::ReadOnly : v8::PropertyAttribute::None);
160
196
  } else if ((descriptor->attributes & napi_writable) == 0) {
161
194
    attribute_flags |= v8::PropertyAttribute::ReadOnly;
162
  }
163
164
208
  if ((descriptor->attributes & napi_enumerable) == 0) {
165
200
    attribute_flags |= v8::PropertyAttribute::DontEnum;
166
  }
167
208
  if ((descriptor->attributes & napi_configurable) == 0) {
168
208
    attribute_flags |= v8::PropertyAttribute::DontDelete;
169
  }
170
171
208
  return static_cast<v8::PropertyAttribute>(attribute_flags);
172
}
173
174
3
class HandleScopeWrapper {
175
 public:
176
3
  explicit HandleScopeWrapper(v8::Isolate* isolate) : scope(isolate) {}
177
178
 private:
179
  v8::HandleScope scope;
180
};
181
182
// In node v0.10 version of v8, there is no EscapableHandleScope and the
183
// node v0.10 port use HandleScope::Close(Local<T> v) to mimic the behavior
184
// of a EscapableHandleScope::Escape(Local<T> v), but it is not the same
185
// semantics. This is an example of where the api abstraction fail to work
186
// across different versions.
187
4
class EscapableHandleScopeWrapper {
188
 public:
189
2
  explicit EscapableHandleScopeWrapper(v8::Isolate* isolate)
190
2
      : scope(isolate), escape_called_(false) {}
191
3
  bool escape_called() const {
192
3
    return escape_called_;
193
  }
194
  template <typename T>
195
2
  v8::Local<T> Escape(v8::Local<T> handle) {
196
2
    escape_called_ = true;
197
4
    return scope.Escape(handle);
198
  }
199
200
 private:
201
  v8::EscapableHandleScope scope;
202
  bool escape_called_;
203
};
204
205
static
206
3
napi_handle_scope JsHandleScopeFromV8HandleScope(HandleScopeWrapper* s) {
207
3
  return reinterpret_cast<napi_handle_scope>(s);
208
}
209
210
static
211
3
HandleScopeWrapper* V8HandleScopeFromJsHandleScope(napi_handle_scope s) {
212
3
  return reinterpret_cast<HandleScopeWrapper*>(s);
213
}
214
215
static
216
2
napi_escapable_handle_scope JsEscapableHandleScopeFromV8EscapableHandleScope(
217
    EscapableHandleScopeWrapper* s) {
218
2
  return reinterpret_cast<napi_escapable_handle_scope>(s);
219
}
220
221
static
222
EscapableHandleScopeWrapper*
223
5
V8EscapableHandleScopeFromJsEscapableHandleScope(
224
    napi_escapable_handle_scope s) {
225
5
  return reinterpret_cast<EscapableHandleScopeWrapper*>(s);
226
}
227
228
//=== Conversion between V8 Handles and napi_value ========================
229
230
// This asserts v8::Local<> will always be implemented with a single
231
// pointer field so that we can pass it around as a void*.
232
static_assert(sizeof(v8::Local<v8::Value>) == sizeof(napi_value),
233
  "Cannot convert between v8::Local<v8::Value> and napi_value");
234
235
static
236
4
napi_deferred JsDeferredFromV8Persistent(v8::Persistent<v8::Value>* local) {
237
4
  return reinterpret_cast<napi_deferred>(local);
238
}
239
240
static
241
3
v8::Persistent<v8::Value>* V8PersistentFromJsDeferred(napi_deferred local) {
242
3
  return reinterpret_cast<v8::Persistent<v8::Value>*>(local);
243
}
244
245
static
246
9760
napi_value JsValueFromV8LocalValue(v8::Local<v8::Value> local) {
247
9760
  return reinterpret_cast<napi_value>(*local);
248
}
249
250
static
251
7270
v8::Local<v8::Value> V8LocalValueFromJsValue(napi_value v) {
252
  v8::Local<v8::Value> local;
253
7270
  memcpy(&local, &v, sizeof(v));
254
7270
  return local;
255
}
256
257
208
static inline napi_status V8NameFromPropertyDescriptor(napi_env env,
258
                                         const napi_property_descriptor* p,
259
                                         v8::Local<v8::Name>* result) {
260
208
  if (p->utf8name != nullptr) {
261
618
    CHECK_NEW_FROM_UTF8(env, *result, p->utf8name);
262
  } else {
263
    v8::Local<v8::Value> property_value =
264
2
      v8impl::V8LocalValueFromJsValue(p->name);
265
266
2
    RETURN_STATUS_IF_FALSE(env, property_value->IsName(), napi_name_expected);
267
2
    *result = property_value.As<v8::Name>();
268
  }
269
270
208
  return napi_ok;
271
}
272
273
// Adapter for napi_finalize callbacks.
274
class Finalizer {
275
 protected:
276
77
  Finalizer(napi_env env,
277
             napi_finalize finalize_callback,
278
             void* finalize_data,
279
             void* finalize_hint)
280
    : _env(env),
281
      _finalize_callback(finalize_callback),
282
      _finalize_data(finalize_data),
283
77
      _finalize_hint(finalize_hint) {
284
77
  }
285
286
17
  ~Finalizer() {
287
17
  }
288
289
 public:
290
2
  static Finalizer* New(napi_env env,
291
                        napi_finalize finalize_callback = nullptr,
292
                        void* finalize_data = nullptr,
293
                        void* finalize_hint = nullptr) {
294
    return new Finalizer(
295
2
      env, finalize_callback, finalize_data, finalize_hint);
296
  }
297
298
2
  static void Delete(Finalizer* finalizer) {
299
2
    delete finalizer;
300
2
  }
301
302
  // node::Buffer::FreeCallback
303
2
  static void FinalizeBufferCallback(char* data, void* hint) {
304
2
    Finalizer* finalizer = static_cast<Finalizer*>(hint);
305
2
    if (finalizer->_finalize_callback != nullptr) {
306
      finalizer->_finalize_callback(
307
        finalizer->_env,
308
        data,
309
2
        finalizer->_finalize_hint);
310
    }
311
312
2
    Delete(finalizer);
313
2
  }
314
315
 protected:
316
  napi_env _env;
317
  napi_finalize _finalize_callback;
318
  void* _finalize_data;
319
  void* _finalize_hint;
320
};
321
322
// Wrapper around v8::Persistent that implements reference counting.
323
class Reference : private Finalizer {
324
 private:
325
75
  Reference(napi_env env,
326
            v8::Local<v8::Value> value,
327
            uint32_t initial_refcount,
328
            bool delete_self,
329
            napi_finalize finalize_callback,
330
            void* finalize_data,
331
            void* finalize_hint)
332
       : Finalizer(env, finalize_callback, finalize_data, finalize_hint),
333
        _persistent(env->isolate, value),
334
        _refcount(initial_refcount),
335
150
        _delete_self(delete_self) {
336
75
    if (initial_refcount == 0) {
337
      _persistent.SetWeak(
338
63
          this, FinalizeCallback, v8::WeakCallbackType::kParameter);
339
63
      _persistent.MarkIndependent();
340
    }
341
75
  }
342
343
30
  ~Reference() {
344
    // The V8 Persistent class currently does not reset in its destructor:
345
    // see NonCopyablePersistentTraits::kResetInDestructor = false.
346
    // (Comments there claim that might change in the future.)
347
    // To avoid memory leaks, it is better to reset at this time, however
348
    // care must be taken to avoid attempting this after the Isolate has
349
    // shut down, for example via a static (atexit) destructor.
350
15
    _persistent.Reset();
351
15
  }
352
353
 public:
354
75
  static Reference* New(napi_env env,
355
                        v8::Local<v8::Value> value,
356
                        uint32_t initial_refcount,
357
                        bool delete_self,
358
                        napi_finalize finalize_callback = nullptr,
359
                        void* finalize_data = nullptr,
360
                        void* finalize_hint = nullptr) {
361
    return new Reference(env,
362
      value,
363
      initial_refcount,
364
      delete_self,
365
      finalize_callback,
366
      finalize_data,
367
75
      finalize_hint);
368
  }
369
370
15
  static void Delete(Reference* reference) {
371
15
    delete reference;
372
15
  }
373
374
1
  uint32_t Ref() {
375
1
    if (++_refcount == 1) {
376
      _persistent.ClearWeak();
377
    }
378
379
1
    return _refcount;
380
  }
381
382
2
  uint32_t Unref() {
383
2
    if (_refcount == 0) {
384
        return 0;
385
    }
386
2
    if (--_refcount == 0) {
387
      _persistent.SetWeak(
388
1
          this, FinalizeCallback, v8::WeakCallbackType::kParameter);
389
1
      _persistent.MarkIndependent();
390
    }
391
392
2
    return _refcount;
393
  }
394
395
2
  uint32_t RefCount() {
396
2
    return _refcount;
397
  }
398
399
15
  v8::Local<v8::Value> Get() {
400
30
    if (_persistent.IsEmpty()) {
401
1
      return v8::Local<v8::Value>();
402
    } else {
403
28
      return v8::Local<v8::Value>::New(_env->isolate, _persistent);
404
    }
405
  }
406
407
 private:
408
8
  static void FinalizeCallback(const v8::WeakCallbackInfo<Reference>& data) {
409
8
    Reference* reference = data.GetParameter();
410
8
    reference->_persistent.Reset();
411
412
    // Check before calling the finalize callback, because the callback might
413
    // delete it.
414
8
    bool delete_self = reference->_delete_self;
415
416
8
    if (reference->_finalize_callback != nullptr) {
417
      reference->_finalize_callback(
418
          reference->_env,
419
          reference->_finalize_data,
420
5
          reference->_finalize_hint);
421
    }
422
423
8
    if (delete_self) {
424
6
      Delete(reference);
425
    }
426
8
  }
427
428
  v8::Persistent<v8::Value> _persistent;
429
  uint32_t _refcount;
430
  bool _delete_self;
431
};
432
433
class TryCatch : public v8::TryCatch {
434
 public:
435
2807
  explicit TryCatch(napi_env env)
436
2807
      : v8::TryCatch(env->isolate), _env(env) {}
437
438
5614
  ~TryCatch() {
439
2807
    if (HasCaught()) {
440
2392
      _env->last_exception.Reset(_env->isolate, Exception());
441
    }
442
2807
  }
443
444
 private:
445
  napi_env _env;
446
};
447
448
//=== Function napi_callback wrapper =================================
449
450
static const int kDataIndex = 0;
451
static const int kEnvIndex = 1;
452
453
static const int kFunctionIndex = 2;
454
static const int kFunctionFieldCount = 3;
455
456
static const int kGetterIndex = 2;
457
static const int kSetterIndex = 3;
458
static const int kAccessorFieldCount = 4;
459
460
// Base class extended by classes that wrap V8 function and property callback
461
// info.
462
class CallbackWrapper {
463
 public:
464
2815
  CallbackWrapper(napi_value this_arg, size_t args_length, void* data)
465
2815
      : _this(this_arg), _args_length(args_length), _data(data) {}
466
467
  virtual napi_value GetNewTarget() = 0;
468
  virtual void Args(napi_value* buffer, size_t bufferlength) = 0;
469
  virtual void SetReturnValue(napi_value value) = 0;
470
471
32
  napi_value This() { return _this; }
472
473
2727
  size_t ArgsLength() { return _args_length; }
474
475
5
  void* Data() { return _data; }
476
477
 protected:
478
  const napi_value _this;
479
  const size_t _args_length;
480
  void* _data;
481
};
482
483
template <typename Info, int kInternalFieldIndex>
484
class CallbackWrapperBase : public CallbackWrapper {
485
 public:
486
2815
  CallbackWrapperBase(const Info& cbinfo, const size_t args_length)
487
      : CallbackWrapper(JsValueFromV8LocalValue(cbinfo.This()),
488
                        args_length,
489
                        nullptr),
490
        _cbinfo(cbinfo),
491
5630
        _cbdata(v8::Local<v8::Object>::Cast(cbinfo.Data())) {
492
8445
    _data = v8::Local<v8::External>::Cast(_cbdata->GetInternalField(kDataIndex))
493
8445
                ->Value();
494
2815
  }
495
496
  napi_value GetNewTarget() override { return nullptr; }
497
498
 protected:
499
2815
  void InvokeCallback() {
500
    napi_callback_info cbinfo_wrapper = reinterpret_cast<napi_callback_info>(
501
2815
        static_cast<CallbackWrapper*>(this));
502
    napi_callback cb = reinterpret_cast<napi_callback>(
503
        v8::Local<v8::External>::Cast(
504
11260
            _cbdata->GetInternalField(kInternalFieldIndex))->Value());
505
5630
    v8::Isolate* isolate = _cbinfo.GetIsolate();
506
507
    napi_env env = static_cast<napi_env>(
508
        v8::Local<v8::External>::Cast(
509
11260
            _cbdata->GetInternalField(kEnvIndex))->Value());
510
511
    // Make sure any errors encountered last time we were in N-API are gone.
512
2815
    napi_clear_last_error(env);
513
514
2815
    int open_handle_scopes = env->open_handle_scopes;
515
516
2815
    napi_value result = cb(env, cbinfo_wrapper);
517
518

2815
    if (result != nullptr) {
519
1580
      this->SetReturnValue(result);
520
    }
521
522

2815
    CHECK_EQ(env->open_handle_scopes, open_handle_scopes);
523
524

5630
    if (!env->last_exception.IsEmpty()) {
525
1194
      isolate->ThrowException(
526
1194
          v8::Local<v8::Value>::New(isolate, env->last_exception));
527
1194
      env->last_exception.Reset();
528
    }
529
2815
  }
530
531
  const Info& _cbinfo;
532
  const v8::Local<v8::Object> _cbdata;
533
};
534
535
class FunctionCallbackWrapper
536
    : public CallbackWrapperBase<v8::FunctionCallbackInfo<v8::Value>,
537
                                 kFunctionIndex> {
538
 public:
539
2777
  static void Invoke(const v8::FunctionCallbackInfo<v8::Value>& info) {
540
2777
    FunctionCallbackWrapper cbwrapper(info);
541
2777
    cbwrapper.InvokeCallback();
542
2777
  }
543
544
2777
  explicit FunctionCallbackWrapper(
545
      const v8::FunctionCallbackInfo<v8::Value>& cbinfo)
546
2777
      : CallbackWrapperBase(cbinfo, cbinfo.Length()) {}
547
548
4
  napi_value GetNewTarget() override {
549
8
    if (_cbinfo.IsConstructCall()) {
550
8
      return v8impl::JsValueFromV8LocalValue(_cbinfo.NewTarget());
551
    } else {
552
      return nullptr;
553
    }
554
  }
555
556
  /*virtual*/
557
2713
  void Args(napi_value* buffer, size_t buffer_length) override {
558
2713
    size_t i = 0;
559
2713
    size_t min = std::min(buffer_length, _args_length);
560
561
7825
    for (; i < min; i += 1) {
562
10224
      buffer[i] = v8impl::JsValueFromV8LocalValue(_cbinfo[i]);
563
    }
564
565
2713
    if (i < buffer_length) {
566
      napi_value undefined =
567
42
          v8impl::JsValueFromV8LocalValue(v8::Undefined(_cbinfo.GetIsolate()));
568
94
      for (; i < buffer_length; i += 1) {
569
80
        buffer[i] = undefined;
570
      }
571
    }
572
2713
  }
573
574
  /*virtual*/
575
1548
  void SetReturnValue(napi_value value) override {
576
1548
    v8::Local<v8::Value> val = v8impl::V8LocalValueFromJsValue(value);
577
4644
    _cbinfo.GetReturnValue().Set(val);
578
1548
  }
579
};
580
581
class GetterCallbackWrapper
582
    : public CallbackWrapperBase<v8::PropertyCallbackInfo<v8::Value>,
583
                                 kGetterIndex> {
584
 public:
585
33
  static void Invoke(v8::Local<v8::Name> property,
586
                     const v8::PropertyCallbackInfo<v8::Value>& info) {
587
33
    GetterCallbackWrapper cbwrapper(info);
588
33
    cbwrapper.InvokeCallback();
589
33
  }
590
591
33
  explicit GetterCallbackWrapper(
592
      const v8::PropertyCallbackInfo<v8::Value>& cbinfo)
593
33
      : CallbackWrapperBase(cbinfo, 0) {}
594
595
  /*virtual*/
596
  void Args(napi_value* buffer, size_t buffer_length) override {
597
    if (buffer_length > 0) {
598
      napi_value undefined =
599
          v8impl::JsValueFromV8LocalValue(v8::Undefined(_cbinfo.GetIsolate()));
600
      for (size_t i = 0; i < buffer_length; i += 1) {
601
        buffer[i] = undefined;
602
      }
603
    }
604
  }
605
606
  /*virtual*/
607
32
  void SetReturnValue(napi_value value) override {
608
32
    v8::Local<v8::Value> val = v8impl::V8LocalValueFromJsValue(value);
609
96
    _cbinfo.GetReturnValue().Set(val);
610
32
  }
611
};
612
613
class SetterCallbackWrapper
614
    : public CallbackWrapperBase<v8::PropertyCallbackInfo<void>, kSetterIndex> {
615
 public:
616
5
  static void Invoke(v8::Local<v8::Name> property,
617
                     v8::Local<v8::Value> value,
618
                     const v8::PropertyCallbackInfo<void>& info) {
619
5
    SetterCallbackWrapper cbwrapper(info, value);
620
5
    cbwrapper.InvokeCallback();
621
5
  }
622
623
5
  SetterCallbackWrapper(const v8::PropertyCallbackInfo<void>& cbinfo,
624
                        const v8::Local<v8::Value>& value)
625
5
      : CallbackWrapperBase(cbinfo, 1), _value(value) {}
626
627
  /*virtual*/
628
5
  void Args(napi_value* buffer, size_t buffer_length) override {
629
5
    if (buffer_length > 0) {
630
5
      buffer[0] = v8impl::JsValueFromV8LocalValue(_value);
631
632
5
      if (buffer_length > 1) {
633
        napi_value undefined = v8impl::JsValueFromV8LocalValue(
634
            v8::Undefined(_cbinfo.GetIsolate()));
635
        for (size_t i = 1; i < buffer_length; i += 1) {
636
          buffer[i] = undefined;
637
        }
638
      }
639
    }
640
5
  }
641
642
  /*virtual*/
643
  void SetReturnValue(napi_value value) override {
644
    // Ignore any value returned from a setter callback.
645
  }
646
647
 private:
648
  const v8::Local<v8::Value>& _value;
649
};
650
651
// Creates an object to be made available to the static function callback
652
// wrapper, used to retrieve the native callback function and data pointer.
653
static
654
203
v8::Local<v8::Object> CreateFunctionCallbackData(napi_env env,
655
                                                 napi_callback cb,
656
                                                 void* data) {
657
203
  v8::Isolate* isolate = env->isolate;
658
203
  v8::Local<v8::Context> context = isolate->GetCurrentContext();
659
660
  v8::Local<v8::ObjectTemplate> otpl;
661
812
  ENV_OBJECT_TEMPLATE(env, function_data, otpl, v8impl::kFunctionFieldCount);
662
406
  v8::Local<v8::Object> cbdata = otpl->NewInstance(context).ToLocalChecked();
663
664
  cbdata->SetInternalField(
665
      v8impl::kEnvIndex,
666
406
      v8::External::New(isolate, static_cast<void*>(env)));
667
  cbdata->SetInternalField(
668
      v8impl::kFunctionIndex,
669
406
      v8::External::New(isolate, reinterpret_cast<void*>(cb)));
670
  cbdata->SetInternalField(
671
      v8impl::kDataIndex,
672
406
      v8::External::New(isolate, data));
673
203
  return cbdata;
674
}
675
676
// Creates an object to be made available to the static getter/setter
677
// callback wrapper, used to retrieve the native getter/setter callback
678
// function and data pointer.
679
static
680
12
v8::Local<v8::Object> CreateAccessorCallbackData(napi_env env,
681
                                                 napi_callback getter,
682
                                                 napi_callback setter,
683
                                                 void* data) {
684
12
  v8::Isolate* isolate = env->isolate;
685
12
  v8::Local<v8::Context> context = isolate->GetCurrentContext();
686
687
  v8::Local<v8::ObjectTemplate> otpl;
688
48
  ENV_OBJECT_TEMPLATE(env, accessor_data, otpl, v8impl::kAccessorFieldCount);
689
24
  v8::Local<v8::Object> cbdata = otpl->NewInstance(context).ToLocalChecked();
690
691
  cbdata->SetInternalField(
692
      v8impl::kEnvIndex,
693
24
      v8::External::New(isolate, static_cast<void*>(env)));
694
695
12
  if (getter != nullptr) {
696
    cbdata->SetInternalField(
697
        v8impl::kGetterIndex,
698
24
        v8::External::New(isolate, reinterpret_cast<void*>(getter)));
699
  }
700
701
12
  if (setter != nullptr) {
702
    cbdata->SetInternalField(
703
        v8impl::kSetterIndex,
704
10
        v8::External::New(isolate, reinterpret_cast<void*>(setter)));
705
  }
706
707
  cbdata->SetInternalField(
708
      v8impl::kDataIndex,
709
24
      v8::External::New(isolate, data));
710
12
  return cbdata;
711
}
712
713
int kWrapperFields = 3;
714
715
// Pointer used to identify items wrapped by N-API. Used by FindWrapper and
716
// napi_wrap().
717
const char napi_wrap_name[] = "N-API Wrapper";
718
719
// Search the object's prototype chain for the wrapper object. Usually the
720
// wrapper would be the first in the chain, but it is OK for other objects to
721
// be inserted in the prototype chain.
722
static
723
42
bool FindWrapper(v8::Local<v8::Object> obj,
724
                 v8::Local<v8::Object>* result = nullptr,
725
                 v8::Local<v8::Object>* parent = nullptr) {
726
42
  v8::Local<v8::Object> wrapper = obj;
727
728
  do {
729
69
    v8::Local<v8::Value> proto = wrapper->GetPrototype();
730

138
    if (proto.IsEmpty() || !proto->IsObject()) {
731
16
      return false;
732
    }
733
53
    if (parent != nullptr) {
734
2
      *parent = wrapper;
735
    }
736
53
    wrapper = proto.As<v8::Object>();
737
53
    if (wrapper->InternalFieldCount() == kWrapperFields) {
738
52
      v8::Local<v8::Value> external = wrapper->GetInternalField(1);
739

130
      if (external->IsExternal() &&
740
104
          external.As<v8::External>()->Value() == v8impl::napi_wrap_name) {
741
26
        break;
742
      }
743
    }
744
  } while (true);
745
746
26
  if (result != nullptr) {
747
25
    *result = wrapper;
748
  }
749
53
  return true;
750
}
751
752
static void DeleteEnv(napi_env env, void* data, void* hint) {
753
  delete env;
754
}
755
756
static
757
45
napi_env GetEnv(v8::Local<v8::Context> context) {
758
  napi_env result;
759
760
45
  auto isolate = context->GetIsolate();
761
45
  auto global = context->Global();
762
763
  // In the case of the string for which we grab the private and the value of
764
  // the private on the global object we can call .ToLocalChecked() directly
765
  // because we need to stop hard if either of them is empty.
766
  //
767
  // Re https://github.com/nodejs/node/pull/14217#discussion_r128775149
768
  auto key = v8::Private::ForApi(isolate,
769
      v8::String::NewFromOneByte(isolate,
770
          reinterpret_cast<const uint8_t*>("N-API Environment"),
771
90
          v8::NewStringType::kInternalized).ToLocalChecked());
772
90
  auto value = global->GetPrivate(context, key).ToLocalChecked();
773
774
45
  if (value->IsExternal()) {
775
4
    result = static_cast<napi_env>(value.As<v8::External>()->Value());
776
  } else {
777
43
    result = new napi_env__(isolate, node::GetCurrentEventLoop(isolate));
778
43
    auto external = v8::External::New(isolate, result);
779
780
    // We must also stop hard if the result of assigning the env to the global
781
    // is either nothing or false.
782
86
    CHECK(global->SetPrivate(context, key, external).FromJust());
783
784
    // Create a self-destructing reference to external that will get rid of the
785
    // napi_env when external goes out of scope.
786
43
    Reference::New(result, external, 0, true, DeleteEnv, nullptr, nullptr);
787
  }
788
789
45
  return result;
790
}
791
792
static
793
25
napi_status Unwrap(napi_env env,
794
                   napi_value js_object,
795
                   void** result,
796
                   v8::Local<v8::Object>* wrapper,
797
                   v8::Local<v8::Object>* parent = nullptr) {
798
25
  CHECK_ARG(env, js_object);
799
25
  CHECK_ARG(env, result);
800
801
25
  v8::Local<v8::Value> value = v8impl::V8LocalValueFromJsValue(js_object);
802
25
  RETURN_STATUS_IF_FALSE(env, value->IsObject(), napi_invalid_arg);
803
25
  v8::Local<v8::Object> obj = value.As<v8::Object>();
804
805
25
  RETURN_STATUS_IF_FALSE(
806
    env, v8impl::FindWrapper(obj, wrapper, parent), napi_invalid_arg);
807
808
50
  v8::Local<v8::Value> unwrappedValue = (*wrapper)->GetInternalField(0);
809
25
  RETURN_STATUS_IF_FALSE(env, unwrappedValue->IsExternal(), napi_invalid_arg);
810
811
50
  *result = unwrappedValue.As<v8::External>()->Value();
812
813
25
  return napi_ok;
814
}
815
816
static
817
3
napi_status ConcludeDeferred(napi_env env,
818
                             napi_deferred deferred,
819
                             napi_value result,
820
                             bool is_resolved) {
821

6
  NAPI_PREAMBLE(env);
822
3
  CHECK_ARG(env, result);
823
824
3
  v8::Local<v8::Context> context = env->isolate->GetCurrentContext();
825
  v8::Persistent<v8::Value>* deferred_ref =
826
3
      V8PersistentFromJsDeferred(deferred);
827
  v8::Local<v8::Value> v8_deferred =
828
6
      v8::Local<v8::Value>::New(env->isolate, *deferred_ref);
829
830
3
  auto v8_resolver = v8::Local<v8::Promise::Resolver>::Cast(v8_deferred);
831
832
  v8::Maybe<bool> success = is_resolved ?
833
4
      v8_resolver->Resolve(context, v8impl::V8LocalValueFromJsValue(result)) :
834
6
      v8_resolver->Reject(context, v8impl::V8LocalValueFromJsValue(result));
835
836
3
  deferred_ref->Reset();
837
3
  delete deferred_ref;
838
839
6
  RETURN_STATUS_IF_FALSE(env, success.FromMaybe(false), napi_generic_failure);
840
841
3
  return GET_RETURN_STATUS(env);
842
}
843
844
}  // end of namespace v8impl
845
846
// Intercepts the Node-V8 module registration callback. Converts parameters
847
// to NAPI equivalents and then calls the registration callback specified
848
// by the NAPI module.
849
45
void napi_module_register_cb(v8::Local<v8::Object> exports,
850
                             v8::Local<v8::Value> module,
851
                             v8::Local<v8::Context> context,
852
                             void* priv) {
853
45
  napi_module* mod = static_cast<napi_module*>(priv);
854
855
  // Create a new napi_env for this module or reference one if a pre-existing
856
  // one is found.
857
45
  napi_env env = v8impl::GetEnv(context);
858
859
  napi_value _exports =
860
90
      mod->nm_register_func(env, v8impl::JsValueFromV8LocalValue(exports));
861
862
  // If register function returned a non-null exports object different from
863
  // the exports object we passed it, set that as the "exports" property of
864
  // the module.
865

180
  if (_exports != nullptr &&
866
135
      _exports != v8impl::JsValueFromV8LocalValue(exports)) {
867
9
    napi_value _module = v8impl::JsValueFromV8LocalValue(module);
868
9
    napi_set_named_property(env, _module, "exports", _exports);
869
  }
870
45
}
871
872
}  // end of anonymous namespace
873
874
// Registers a NAPI module.
875
45
void napi_module_register(napi_module* mod) {
876
  node::node_module* nm = new node::node_module {
877
    -1,
878
    mod->nm_flags,
879
    nullptr,
880
    mod->nm_filename,
881
    nullptr,
882
    napi_module_register_cb,
883
    mod->nm_modname,
884
    mod,  // priv
885
    nullptr,
886
45
  };
887
45
  node::node_module_register(nm);
888
45
}
889
890
// Warning: Keep in-sync with napi_status enum
891
static
892
const char* error_messages[] = {nullptr,
893
                                "Invalid argument",
894
                                "An object was expected",
895
                                "A string was expected",
896
                                "A string or symbol was expected",
897
                                "A function was expected",
898
                                "A number was expected",
899
                                "A boolean was expected",
900
                                "An array was expected",
901
                                "Unknown failure",
902
                                "An exception is pending",
903
                                "The async work item was cancelled",
904
                                "napi_escape_handle already called on scope",
905
                                "Invalid handle scope usage"};
906
907
11821
static inline napi_status napi_clear_last_error(napi_env env) {
908
11821
  env->last_error.error_code = napi_ok;
909
910
  // TODO(boingoing): Should this be a callback?
911
11821
  env->last_error.engine_error_code = 0;
912
11821
  env->last_error.engine_reserved = nullptr;
913
11821
  return napi_ok;
914
}
915
916
static inline
917
1212
napi_status napi_set_last_error(napi_env env, napi_status error_code,
918
                                uint32_t engine_error_code,
919
                                void* engine_reserved) {
920
1212
  env->last_error.error_code = error_code;
921
1212
  env->last_error.engine_error_code = engine_error_code;
922
1212
  env->last_error.engine_reserved = engine_reserved;
923
1212
  return error_code;
924
}
925
926
1182
napi_status napi_get_last_error_info(napi_env env,
927
                                     const napi_extended_error_info** result) {
928
1182
  CHECK_ENV(env);
929
1182
  CHECK_ARG(env, result);
930
931
  // you must update this assert to reference the last message
932
  // in the napi_status enum each time a new error message is added.
933
  // We don't have a napi_status_last as this would result in an ABI
934
  // change each time a message was added.
935
  static_assert(
936
      node::arraysize(error_messages) == napi_handle_scope_mismatch + 1,
937
      "Count of error messages must match count of error values");
938
1182
  CHECK_LE(env->last_error.error_code, napi_handle_scope_mismatch);
939
940
  // Wait until someone requests the last error information to fetch the error
941
  // message string
942
  env->last_error.error_message =
943
1182
      error_messages[env->last_error.error_code];
944
945
1182
  *result = &(env->last_error);
946
1182
  return napi_ok;
947
}
948
949
NAPI_NO_RETURN void napi_fatal_error(const char* location,
950
                                     size_t location_len,
951
                                     const char* message,
952
                                     size_t message_len) {
953
  std::string location_string;
954
  std::string message_string;
955
956
  if (location_len != NAPI_AUTO_LENGTH) {
957
    location_string.assign(
958
        const_cast<char*>(location), location_len);
959
  } else {
960
    location_string.assign(
961
        const_cast<char*>(location), strlen(location));
962
  }
963
964
  if (message_len != NAPI_AUTO_LENGTH) {
965
    message_string.assign(
966
        const_cast<char*>(message), message_len);
967
  } else {
968
    message_string.assign(
969
        const_cast<char*>(message), strlen(message));
970
  }
971
972
  node::FatalError(location_string.c_str(), message_string.c_str());
973
}
974
975
10
napi_status napi_create_function(napi_env env,
976
                                 const char* utf8name,
977
                                 size_t length,
978
                                 napi_callback cb,
979
                                 void* callback_data,
980
                                 napi_value* result) {
981

20
  NAPI_PREAMBLE(env);
982
10
  CHECK_ARG(env, result);
983
10
  CHECK_ARG(env, cb);
984
985
10
  v8::Isolate* isolate = env->isolate;
986
  v8::Local<v8::Function> return_value;
987
10
  v8::EscapableHandleScope scope(isolate);
988
  v8::Local<v8::Object> cbdata =
989
10
      v8impl::CreateFunctionCallbackData(env, cb, callback_data);
990
991
10
  RETURN_STATUS_IF_FALSE(env, !cbdata.IsEmpty(), napi_generic_failure);
992
993
  v8::Local<v8::FunctionTemplate> tpl = v8::FunctionTemplate::New(
994
10
      isolate, v8impl::FunctionCallbackWrapper::Invoke, cbdata);
995
996
10
  v8::Local<v8::Context> context = isolate->GetCurrentContext();
997
10
  v8::MaybeLocal<v8::Function> maybe_function = tpl->GetFunction(context);
998
10
  CHECK_MAYBE_EMPTY(env, maybe_function, napi_generic_failure);
999
1000
10
  return_value = scope.Escape(maybe_function.ToLocalChecked());
1001
1002
10
  if (utf8name != nullptr) {
1003
    v8::Local<v8::String> name_string;
1004

21
    CHECK_NEW_FROM_UTF8_LEN(env, name_string, utf8name, length);
1005
7
    return_value->SetName(name_string);
1006
  }
1007
1008
10
  *result = v8impl::JsValueFromV8LocalValue(return_value);
1009
1010
20
  return GET_RETURN_STATUS(env);
1011
}
1012
1013
5
napi_status napi_define_class(napi_env env,
1014
                              const char* utf8name,
1015
                              size_t length,
1016
                              napi_callback constructor,
1017
                              void* callback_data,
1018
                              size_t property_count,
1019
                              const napi_property_descriptor* properties,
1020
                              napi_value* result) {
1021

10
  NAPI_PREAMBLE(env);
1022
5
  CHECK_ARG(env, result);
1023
5
  CHECK_ARG(env, constructor);
1024
1025
5
  v8::Isolate* isolate = env->isolate;
1026
1027
5
  v8::EscapableHandleScope scope(isolate);
1028
  v8::Local<v8::Object> cbdata =
1029
5
      v8impl::CreateFunctionCallbackData(env, constructor, callback_data);
1030
1031
5
  RETURN_STATUS_IF_FALSE(env, !cbdata.IsEmpty(), napi_generic_failure);
1032
1033
  v8::Local<v8::FunctionTemplate> tpl = v8::FunctionTemplate::New(
1034
5
      isolate, v8impl::FunctionCallbackWrapper::Invoke, cbdata);
1035
1036
  v8::Local<v8::String> name_string;
1037

15
  CHECK_NEW_FROM_UTF8_LEN(env, name_string, utf8name, length);
1038
5
  tpl->SetClassName(name_string);
1039
1040
5
  size_t static_property_count = 0;
1041
18
  for (size_t i = 0; i < property_count; i++) {
1042
13
    const napi_property_descriptor* p = properties + i;
1043
1044
13
    if ((p->attributes & napi_static) != 0) {
1045
      // Static properties are handled separately below.
1046
1
      static_property_count++;
1047
1
      continue;
1048
    }
1049
1050
    v8::Local<v8::Name> property_name;
1051
    napi_status status =
1052
12
        v8impl::V8NameFromPropertyDescriptor(env, p, &property_name);
1053
1054
12
    if (status != napi_ok) {
1055
      return napi_set_last_error(env, status);
1056
    }
1057
1058
    v8::PropertyAttribute attributes =
1059
12
        v8impl::V8PropertyAttributesFromDescriptor(p);
1060
1061
    // This code is similar to that in napi_define_properties(); the
1062
    // difference is it applies to a template instead of an object.
1063

12
    if (p->getter != nullptr || p->setter != nullptr) {
1064
      v8::Local<v8::Object> cbdata = v8impl::CreateAccessorCallbackData(
1065
5
        env, p->getter, p->setter, p->data);
1066
1067
5
      tpl->PrototypeTemplate()->SetAccessor(
1068
        property_name,
1069
        p->getter ? v8impl::GetterCallbackWrapper::Invoke : nullptr,
1070
        p->setter ? v8impl::SetterCallbackWrapper::Invoke : nullptr,
1071
        cbdata,
1072
        v8::AccessControl::DEFAULT,
1073

15
        attributes);
1074
7
    } else if (p->method != nullptr) {
1075
      v8::Local<v8::Object> cbdata =
1076
4
          v8impl::CreateFunctionCallbackData(env, p->method, p->data);
1077
1078
4
      RETURN_STATUS_IF_FALSE(env, !cbdata.IsEmpty(), napi_generic_failure);
1079
1080
      v8::Local<v8::FunctionTemplate> t =
1081
        v8::FunctionTemplate::New(isolate,
1082
          v8impl::FunctionCallbackWrapper::Invoke,
1083
          cbdata,
1084
8
          v8::Signature::New(isolate, tpl));
1085
1086
8
      tpl->PrototypeTemplate()->Set(property_name, t, attributes);
1087
    } else {
1088
3
      v8::Local<v8::Value> value = v8impl::V8LocalValueFromJsValue(p->value);
1089
6
      tpl->PrototypeTemplate()->Set(property_name, value, attributes);
1090
    }
1091
  }
1092
1093
10
  *result = v8impl::JsValueFromV8LocalValue(scope.Escape(tpl->GetFunction()));
1094
1095
5
  if (static_property_count > 0) {
1096
1
    std::vector<napi_property_descriptor> static_descriptors;
1097
1
    static_descriptors.reserve(static_property_count);
1098
1099
10
    for (size_t i = 0; i < property_count; i++) {
1100
9
      const napi_property_descriptor* p = properties + i;
1101
9
      if ((p->attributes & napi_static) != 0) {
1102
1
        static_descriptors.push_back(*p);
1103
      }
1104
    }
1105
1106
    napi_status status =
1107
        napi_define_properties(env,
1108
                               *result,
1109
                               static_descriptors.size(),
1110
1
                               static_descriptors.data());
1111

1
    if (status != napi_ok) return status;
1112
  }
1113
1114
10
  return GET_RETURN_STATUS(env);
1115
}
1116
1117
4
napi_status napi_get_property_names(napi_env env,
1118
                                    napi_value object,
1119
                                    napi_value* result) {
1120

8
  NAPI_PREAMBLE(env);
1121
4
  CHECK_ARG(env, result);
1122
1123
4
  v8::Isolate* isolate = env->isolate;
1124
4
  v8::Local<v8::Context> context = isolate->GetCurrentContext();
1125
  v8::Local<v8::Object> obj;
1126

16
  CHECK_TO_OBJECT(env, context, obj, object);
1127
1128
4
  auto maybe_propertynames = obj->GetPropertyNames(context);
1129
1130
4
  CHECK_MAYBE_EMPTY(env, maybe_propertynames, napi_generic_failure);
1131
1132
  *result = v8impl::JsValueFromV8LocalValue(
1133
4
      maybe_propertynames.ToLocalChecked());
1134
4
  return GET_RETURN_STATUS(env);
1135
}
1136
1137
15
napi_status napi_set_property(napi_env env,
1138
                              napi_value object,
1139
                              napi_value key,
1140
                              napi_value value) {
1141

30
  NAPI_PREAMBLE(env);
1142
15
  CHECK_ARG(env, key);
1143
15
  CHECK_ARG(env, value);
1144
1145
15
  v8::Isolate* isolate = env->isolate;
1146
15
  v8::Local<v8::Context> context = isolate->GetCurrentContext();
1147
  v8::Local<v8::Object> obj;
1148
1149

60
  CHECK_TO_OBJECT(env, context, obj, object);
1150
1151
15
  v8::Local<v8::Value> k = v8impl::V8LocalValueFromJsValue(key);
1152
15
  v8::Local<v8::Value> val = v8impl::V8LocalValueFromJsValue(value);
1153
1154
15
  v8::Maybe<bool> set_maybe = obj->Set(context, k, val);
1155
1156
30
  RETURN_STATUS_IF_FALSE(env, set_maybe.FromMaybe(false), napi_generic_failure);
1157
15
  return GET_RETURN_STATUS(env);
1158
}
1159
1160
8
napi_status napi_has_property(napi_env env,
1161
                              napi_value object,
1162
                              napi_value key,
1163
                              bool* result) {
1164

16
  NAPI_PREAMBLE(env);
1165
8
  CHECK_ARG(env, result);
1166
8
  CHECK_ARG(env, key);
1167
1168
8
  v8::Isolate* isolate = env->isolate;
1169
8
  v8::Local<v8::Context> context = isolate->GetCurrentContext();
1170
  v8::Local<v8::Object> obj;
1171
1172

32
  CHECK_TO_OBJECT(env, context, obj, object);
1173
1174
8
  v8::Local<v8::Value> k = v8impl::V8LocalValueFromJsValue(key);
1175
8
  v8::Maybe<bool> has_maybe = obj->Has(context, k);
1176
1177
8
  CHECK_MAYBE_NOTHING(env, has_maybe, napi_generic_failure);
1178
1179
16
  *result = has_maybe.FromMaybe(false);
1180
8
  return GET_RETURN_STATUS(env);
1181
}
1182
1183
24
napi_status napi_get_property(napi_env env,
1184
                              napi_value object,
1185
                              napi_value key,
1186
                              napi_value* result) {
1187

48
  NAPI_PREAMBLE(env);
1188
24
  CHECK_ARG(env, key);
1189
24
  CHECK_ARG(env, result);
1190
1191
24
  v8::Isolate* isolate = env->isolate;
1192
24
  v8::Local<v8::Context> context = isolate->GetCurrentContext();
1193
24
  v8::Local<v8::Value> k = v8impl::V8LocalValueFromJsValue(key);
1194
  v8::Local<v8::Object> obj;
1195
1196

96
  CHECK_TO_OBJECT(env, context, obj, object);
1197
1198
24
  auto get_maybe = obj->Get(context, k);
1199
1200
24
  CHECK_MAYBE_EMPTY(env, get_maybe, napi_generic_failure);
1201
1202
24
  v8::Local<v8::Value> val = get_maybe.ToLocalChecked();
1203
24
  *result = v8impl::JsValueFromV8LocalValue(val);
1204
24
  return GET_RETURN_STATUS(env);
1205
}
1206
1207
5
napi_status napi_delete_property(napi_env env,
1208
                                 napi_value object,
1209
                                 napi_value key,
1210
                                 bool* result) {
1211

10
  NAPI_PREAMBLE(env);
1212
5
  CHECK_ARG(env, key);
1213
1214
5
  v8::Isolate* isolate = env->isolate;
1215
5
  v8::Local<v8::Context> context = isolate->GetCurrentContext();
1216
5
  v8::Local<v8::Value> k = v8impl::V8LocalValueFromJsValue(key);
1217
  v8::Local<v8::Object> obj;
1218
1219

20
  CHECK_TO_OBJECT(env, context, obj, object);
1220
5
  v8::Maybe<bool> delete_maybe = obj->Delete(context, k);
1221
5
  CHECK_MAYBE_NOTHING(env, delete_maybe, napi_generic_failure);
1222
1223
5
  if (result != nullptr)
1224
10
    *result = delete_maybe.FromMaybe(false);
1225
1226
5
  return GET_RETURN_STATUS(env);
1227
}
1228
1229
15
napi_status napi_has_own_property(napi_env env,
1230
                                  napi_value object,
1231
                                  napi_value key,
1232
                                  bool* result) {
1233

30
  NAPI_PREAMBLE(env);
1234
15
  CHECK_ARG(env, key);
1235
1236
15
  v8::Isolate* isolate = env->isolate;
1237
15
  v8::Local<v8::Context> context = isolate->GetCurrentContext();
1238
  v8::Local<v8::Object> obj;
1239
1240

60
  CHECK_TO_OBJECT(env, context, obj, object);
1241
15
  v8::Local<v8::Value> k = v8impl::V8LocalValueFromJsValue(key);
1242
24
  RETURN_STATUS_IF_FALSE(env, k->IsName(), napi_name_expected);
1243
6
  v8::Maybe<bool> has_maybe = obj->HasOwnProperty(context, k.As<v8::Name>());
1244
6
  CHECK_MAYBE_NOTHING(env, has_maybe, napi_generic_failure);
1245
12
  *result = has_maybe.FromMaybe(false);
1246
1247
6
  return GET_RETURN_STATUS(env);
1248
}
1249
1250
20
napi_status napi_set_named_property(napi_env env,
1251
                                    napi_value object,
1252
                                    const char* utf8name,
1253
                                    napi_value value) {
1254

40
  NAPI_PREAMBLE(env);
1255
20
  CHECK_ARG(env, value);
1256
1257
20
  v8::Isolate* isolate = env->isolate;
1258
20
  v8::Local<v8::Context> context = isolate->GetCurrentContext();
1259
  v8::Local<v8::Object> obj;
1260
1261

80
  CHECK_TO_OBJECT(env, context, obj, object);
1262
1263
  v8::Local<v8::Name> key;
1264
60
  CHECK_NEW_FROM_UTF8(env, key, utf8name);
1265
1266
20
  v8::Local<v8::Value> val = v8impl::V8LocalValueFromJsValue(value);
1267
1268
20
  v8::Maybe<bool> set_maybe = obj->Set(context, key, val);
1269
1270
40
  RETURN_STATUS_IF_FALSE(env, set_maybe.FromMaybe(false), napi_generic_failure);
1271
20
  return GET_RETURN_STATUS(env);
1272
}
1273
1274
3
napi_status napi_has_named_property(napi_env env,
1275
                                    napi_value object,
1276
                                    const char* utf8name,
1277
                                    bool* result) {
1278

6
  NAPI_PREAMBLE(env);
1279
3
  CHECK_ARG(env, result);
1280
1281
3
  v8::Isolate* isolate = env->isolate;
1282
3
  v8::Local<v8::Context> context = isolate->GetCurrentContext();
1283
  v8::Local<v8::Object> obj;
1284
1285

12
  CHECK_TO_OBJECT(env, context, obj, object);
1286
1287
  v8::Local<v8::Name> key;
1288
9
  CHECK_NEW_FROM_UTF8(env, key, utf8name);
1289
1290
3
  v8::Maybe<bool> has_maybe = obj->Has(context, key);
1291
1292
3
  CHECK_MAYBE_NOTHING(env, has_maybe, napi_generic_failure);
1293
1294
6
  *result = has_maybe.FromMaybe(false);
1295
3
  return GET_RETURN_STATUS(env);
1296
}
1297
1298
napi_status napi_get_named_property(napi_env env,
1299
                                    napi_value object,
1300
                                    const char* utf8name,
1301
                                    napi_value* result) {
1302
  NAPI_PREAMBLE(env);
1303
  CHECK_ARG(env, result);
1304
1305
  v8::Isolate* isolate = env->isolate;
1306
  v8::Local<v8::Context> context = isolate->GetCurrentContext();
1307
1308
  v8::Local<v8::Name> key;
1309
  CHECK_NEW_FROM_UTF8(env, key, utf8name);
1310
1311
  v8::Local<v8::Object> obj;
1312
1313
  CHECK_TO_OBJECT(env, context, obj, object);
1314
1315
  auto get_maybe = obj->Get(context, key);
1316
1317
  CHECK_MAYBE_EMPTY(env, get_maybe, napi_generic_failure);
1318
1319
  v8::Local<v8::Value> val = get_maybe.ToLocalChecked();
1320
  *result = v8impl::JsValueFromV8LocalValue(val);
1321
  return GET_RETURN_STATUS(env);
1322
}
1323
1324
11
napi_status napi_set_element(napi_env env,
1325
                             napi_value object,
1326
                             uint32_t index,
1327
                             napi_value value) {
1328

22
  NAPI_PREAMBLE(env);
1329
11
  CHECK_ARG(env, value);
1330
1331
11
  v8::Isolate* isolate = env->isolate;
1332
11
  v8::Local<v8::Context> context = isolate->GetCurrentContext();
1333
  v8::Local<v8::Object> obj;
1334
1335

44
  CHECK_TO_OBJECT(env, context, obj, object);
1336
1337
11
  v8::Local<v8::Value> val = v8impl::V8LocalValueFromJsValue(value);
1338
11
  auto set_maybe = obj->Set(context, index, val);
1339
1340
22
  RETURN_STATUS_IF_FALSE(env, set_maybe.FromMaybe(false), napi_generic_failure);
1341
1342
11
  return GET_RETURN_STATUS(env);
1343
}
1344
1345
2
napi_status napi_has_element(napi_env env,
1346
                             napi_value object,
1347
                             uint32_t index,
1348
                             bool* result) {
1349

4
  NAPI_PREAMBLE(env);
1350
2
  CHECK_ARG(env, result);
1351
1352
2
  v8::Isolate* isolate = env->isolate;
1353
2
  v8::Local<v8::Context> context = isolate->GetCurrentContext();
1354
  v8::Local<v8::Object> obj;
1355
1356

8
  CHECK_TO_OBJECT(env, context, obj, object);
1357
1358
2
  v8::Maybe<bool> has_maybe = obj->Has(context, index);
1359
1360
2
  CHECK_MAYBE_NOTHING(env, has_maybe, napi_generic_failure);
1361
1362
4
  *result = has_maybe.FromMaybe(false);
1363
2
  return GET_RETURN_STATUS(env);
1364
}
1365
1366
27
napi_status napi_get_element(napi_env env,
1367
                             napi_value object,
1368
                             uint32_t index,
1369
                             napi_value* result) {
1370

54
  NAPI_PREAMBLE(env);
1371
27
  CHECK_ARG(env, result);
1372
1373
27
  v8::Isolate* isolate = env->isolate;
1374
27
  v8::Local<v8::Context> context = isolate->GetCurrentContext();
1375
  v8::Local<v8::Object> obj;
1376
1377

108
  CHECK_TO_OBJECT(env, context, obj, object);
1378
1379
27
  auto get_maybe = obj->Get(context, index);
1380
1381
27
  CHECK_MAYBE_EMPTY(env, get_maybe, napi_generic_failure);
1382
1383
27
  *result = v8impl::JsValueFromV8LocalValue(get_maybe.ToLocalChecked());
1384
27
  return GET_RETURN_STATUS(env);
1385
}
1386
1387
1
napi_status napi_delete_element(napi_env env,
1388
                                napi_value object,
1389
                                uint32_t index,
1390
                                bool* result) {
1391

2
  NAPI_PREAMBLE(env);
1392
1393
1
  v8::Isolate* isolate = env->isolate;
1394
1
  v8::Local<v8::Context> context = isolate->GetCurrentContext();
1395
  v8::Local<v8::Object> obj;
1396
1397

4
  CHECK_TO_OBJECT(env, context, obj, object);
1398
1
  v8::Maybe<bool> delete_maybe = obj->Delete(context, index);
1399
1
  CHECK_MAYBE_NOTHING(env, delete_maybe, napi_generic_failure);
1400
1401
1
  if (result != nullptr)
1402
2
    *result = delete_maybe.FromMaybe(false);
1403
1404
1
  return GET_RETURN_STATUS(env);
1405
}
1406
1407
33
napi_status napi_define_properties(napi_env env,
1408
                                   napi_value object,
1409
                                   size_t property_count,
1410
                                   const napi_property_descriptor* properties) {
1411

66
  NAPI_PREAMBLE(env);
1412
33
  if (property_count > 0) {
1413
33
    CHECK_ARG(env, properties);
1414
  }
1415
1416
33
  v8::Isolate* isolate = env->isolate;
1417
33
  v8::Local<v8::Context> context = isolate->GetCurrentContext();
1418
1419
  v8::Local<v8::Object> obj;
1420

132
  CHECK_TO_OBJECT(env, context, obj, object);
1421
1422
458
  for (size_t i = 0; i < property_count; i++) {
1423
196
    const napi_property_descriptor* p = &properties[i];
1424
1425
    v8::Local<v8::Name> property_name;
1426
    napi_status status =
1427
196
        v8impl::V8NameFromPropertyDescriptor(env, p, &property_name);
1428
1429
196
    if (status != napi_ok) {
1430
      return napi_set_last_error(env, status);
1431
    }
1432
1433
    v8::PropertyAttribute attributes =
1434
196
        v8impl::V8PropertyAttributesFromDescriptor(p);
1435
1436

196
    if (p->getter != nullptr || p->setter != nullptr) {
1437
      v8::Local<v8::Object> cbdata = v8impl::CreateAccessorCallbackData(
1438
        env,
1439
        p->getter,
1440
        p->setter,
1441
7
        p->data);
1442
1443
      auto set_maybe = obj->SetAccessor(
1444
        context,
1445
        property_name,
1446
        p->getter ? v8impl::GetterCallbackWrapper::Invoke : nullptr,
1447
        p->setter ? v8impl::SetterCallbackWrapper::Invoke : nullptr,
1448
        cbdata,
1449
        v8::AccessControl::DEFAULT,
1450

14
        attributes);
1451
1452
14
      if (!set_maybe.FromMaybe(false)) {
1453
        return napi_set_last_error(env, napi_invalid_arg);
1454
7
      }
1455
189
    } else if (p->method != nullptr) {
1456
      v8::Local<v8::Object> cbdata =
1457
184
          v8impl::CreateFunctionCallbackData(env, p->method, p->data);
1458
1459
184
      RETURN_STATUS_IF_FALSE(env, !cbdata.IsEmpty(), napi_generic_failure);
1460
1461
      v8::Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New(
1462
184
          isolate, v8impl::FunctionCallbackWrapper::Invoke, cbdata);
1463
1464
      auto define_maybe = obj->DefineOwnProperty(
1465
368
        context, property_name, t->GetFunction(), attributes);
1466
1467
368
      if (!define_maybe.FromMaybe(false)) {
1468
        return napi_set_last_error(env, napi_generic_failure);
1469
      }
1470
    } else {
1471
5
      v8::Local<v8::Value> value = v8impl::V8LocalValueFromJsValue(p->value);
1472
1473
      auto define_maybe =
1474
5
          obj->DefineOwnProperty(context, property_name, value, attributes);
1475
1476
10
      if (!define_maybe.FromMaybe(false)) {
1477
        return napi_set_last_error(env, napi_invalid_arg);
1478
      }
1479
    }
1480
  }
1481
1482
33
  return GET_RETURN_STATUS(env);
1483
}
1484
1485
11
napi_status napi_is_array(napi_env env, napi_value value, bool* result) {
1486
11
  CHECK_ENV(env);
1487
11
  CHECK_ARG(env, value);
1488
11
  CHECK_ARG(env, result);
1489
1490
11
  v8::Local<v8::Value> val = v8impl::V8LocalValueFromJsValue(value);
1491
1492
11
  *result = val->IsArray();
1493
11
  return napi_clear_last_error(env);
1494
}
1495
1496
13
napi_status napi_get_array_length(napi_env env,
1497
                                  napi_value value,
1498
                                  uint32_t* result) {
1499

26
  NAPI_PREAMBLE(env);
1500
13
  CHECK_ARG(env, value);
1501
13
  CHECK_ARG(env, result);
1502
1503
13
  v8::Local<v8::Value> val = v8impl::V8LocalValueFromJsValue(value);
1504
13
  RETURN_STATUS_IF_FALSE(env, val->IsArray(), napi_array_expected);
1505
1506
13
  v8::Local<v8::Array> arr = val.As<v8::Array>();
1507
13
  *result = arr->Length();
1508
1509
13
  return GET_RETURN_STATUS(env);
1510
}
1511
1512
3
napi_status napi_strict_equals(napi_env env,
1513
                               napi_value lhs,
1514
                               napi_value rhs,
1515
                               bool* result) {
1516

6
  NAPI_PREAMBLE(env);
1517
3
  CHECK_ARG(env, lhs);
1518
3
  CHECK_ARG(env, rhs);
1519
3
  CHECK_ARG(env, result);
1520
1521
3
  v8::Local<v8::Value> a = v8impl::V8LocalValueFromJsValue(lhs);
1522
3
  v8::Local<v8::Value> b = v8impl::V8LocalValueFromJsValue(rhs);
1523
1524
3
  *result = a->StrictEquals(b);
1525
3
  return GET_RETURN_STATUS(env);
1526
}
1527
1528
4
napi_status napi_get_prototype(napi_env env,
1529
                               napi_value object,
1530
                               napi_value* result) {
1531

8
  NAPI_PREAMBLE(env);
1532
4
  CHECK_ARG(env, result);
1533
1534
4
  v8::Isolate* isolate = env->isolate;
1535
4
  v8::Local<v8::Context> context = isolate->GetCurrentContext();
1536
1537
  v8::Local<v8::Object> obj;
1538

16
  CHECK_TO_OBJECT(env, context, obj, object);
1539
1540
4
  v8::Local<v8::Value> val = obj->GetPrototype();
1541
4
  *result = v8impl::JsValueFromV8LocalValue(val);
1542
4
  return GET_RETURN_STATUS(env);
1543
}
1544
1545
7
napi_status napi_create_object(napi_env env, napi_value* result) {
1546
7
  CHECK_ENV(env);
1547
7
  CHECK_ARG(env, result);
1548
1549
  *result = v8impl::JsValueFromV8LocalValue(
1550
14
      v8::Object::New(env->isolate));
1551
1552
7
  return napi_clear_last_error(env);
1553
}
1554
1555
1
napi_status napi_create_array(napi_env env, napi_value* result) {
1556
1
  CHECK_ENV(env);
1557
1
  CHECK_ARG(env, result);
1558
1559
  *result = v8impl::JsValueFromV8LocalValue(
1560
2
      v8::Array::New(env->isolate));
1561
1562
1
  return napi_clear_last_error(env);
1563
}
1564
1565
4
napi_status napi_create_array_with_length(napi_env env,
1566
                                          size_t length,
1567
                                          napi_value* result) {
1568
4
  CHECK_ENV(env);
1569
4
  CHECK_ARG(env, result);
1570
1571
  *result = v8impl::JsValueFromV8LocalValue(
1572
8
      v8::Array::New(env->isolate, length));
1573
1574
4
  return napi_clear_last_error(env);
1575
}
1576
1577
11
napi_status napi_create_string_latin1(napi_env env,
1578
                                      const char* str,
1579
                                      size_t length,
1580
                                      napi_value* result) {
1581
11
  CHECK_ENV(env);
1582
11
  CHECK_ARG(env, result);
1583
1584
11
  auto isolate = env->isolate;
1585
  auto str_maybe =
1586
      v8::String::NewFromOneByte(isolate,
1587
                                 reinterpret_cast<const uint8_t*>(str),
1588
                                 v8::NewStringType::kInternalized,
1589
11
                                 length);
1590
11
  CHECK_MAYBE_EMPTY(env, str_maybe, napi_generic_failure);
1591
1592
11
  *result = v8impl::JsValueFromV8LocalValue(str_maybe.ToLocalChecked());
1593
11
  return napi_clear_last_error(env);
1594
}
1595
1596
53
napi_status napi_create_string_utf8(napi_env env,
1597
                                    const char* str,
1598
                                    size_t length,
1599
                                    napi_value* result) {
1600
53
  CHECK_ENV(env);
1601
53
  CHECK_ARG(env, result);
1602
1603
  v8::Local<v8::String> s;
1604

158
  CHECK_NEW_FROM_UTF8_LEN(env, s, str, length);
1605
1606
52
  *result = v8impl::JsValueFromV8LocalValue(s);
1607
52
  return napi_clear_last_error(env);
1608
}
1609
1610
13
napi_status napi_create_string_utf16(napi_env env,
1611
                                     const char16_t* str,
1612
                                     size_t length,
1613
                                     napi_value* result) {
1614
13
  CHECK_ENV(env);
1615
13
  CHECK_ARG(env, result);
1616
1617
13
  auto isolate = env->isolate;
1618
  auto str_maybe =
1619
      v8::String::NewFromTwoByte(isolate,
1620
                                 reinterpret_cast<const uint16_t*>(str),
1621
                                 v8::NewStringType::kInternalized,
1622
13
                                 length);
1623
13
  CHECK_MAYBE_EMPTY(env, str_maybe, napi_generic_failure);
1624
1625
13
  *result = v8impl::JsValueFromV8LocalValue(str_maybe.ToLocalChecked());
1626
13
  return napi_clear_last_error(env);
1627
}
1628
1629
63
napi_status napi_create_double(napi_env env,
1630
                               double value,
1631
                               napi_value* result) {
1632
63
  CHECK_ENV(env);
1633
63
  CHECK_ARG(env, result);
1634
1635
  *result = v8impl::JsValueFromV8LocalValue(
1636
126
      v8::Number::New(env->isolate, value));
1637
1638
63
  return napi_clear_last_error(env);
1639
}
1640
1641
35
napi_status napi_create_int32(napi_env env,
1642
                              int32_t value,
1643
                              napi_value* result) {
1644
35
  CHECK_ENV(env);
1645
35
  CHECK_ARG(env, result);
1646
1647
  *result = v8impl::JsValueFromV8LocalValue(
1648
70
      v8::Integer::New(env->isolate, value));
1649
1650
35
  return napi_clear_last_error(env);
1651
}
1652
1653
38
napi_status napi_create_uint32(napi_env env,
1654
                               uint32_t value,
1655
                               napi_value* result) {
1656
38
  CHECK_ENV(env);
1657
38
  CHECK_ARG(env, result);
1658
1659
  *result = v8impl::JsValueFromV8LocalValue(
1660
76
      v8::Integer::NewFromUnsigned(env->isolate, value));
1661
1662
38
  return napi_clear_last_error(env);
1663
}
1664
1665
9
napi_status napi_create_int64(napi_env env,
1666
                              int64_t value,
1667
                              napi_value* result) {
1668
9
  CHECK_ENV(env);
1669
9
  CHECK_ARG(env, result);
1670
1671
  *result = v8impl::JsValueFromV8LocalValue(
1672
18
      v8::Number::New(env->isolate, static_cast<double>(value)));
1673
1674
9
  return napi_clear_last_error(env);
1675
}
1676
1677
1226
napi_status napi_get_boolean(napi_env env, bool value, napi_value* result) {
1678
1226
  CHECK_ENV(env);
1679
1226
  CHECK_ARG(env, result);
1680
1681
1226
  v8::Isolate* isolate = env->isolate;
1682
1683
1226
  if (value) {
1684
695
    *result = v8impl::JsValueFromV8LocalValue(v8::True(isolate));
1685
  } else {
1686
531
    *result = v8impl::JsValueFromV8LocalValue(v8::False(isolate));
1687
  }
1688
1689
1226
  return napi_clear_last_error(env);
1690
}
1691
1692
13
napi_status napi_create_symbol(napi_env env,
1693
                               napi_value description,
1694
                               napi_value* result) {
1695
13
  CHECK_ENV(env);
1696
13
  CHECK_ARG(env, result);
1697
1698
13
  v8::Isolate* isolate = env->isolate;
1699
1700
13
  if (description == nullptr) {
1701
4
    *result = v8impl::JsValueFromV8LocalValue(v8::Symbol::New(isolate));
1702
  } else {
1703
11
    v8::Local<v8::Value> desc = v8impl::V8LocalValueFromJsValue(description);
1704
22
    RETURN_STATUS_IF_FALSE(env, desc->IsString(), napi_string_expected);
1705
1706
    *result = v8impl::JsValueFromV8LocalValue(
1707
22
      v8::Symbol::New(isolate, desc.As<v8::String>()));
1708
  }
1709
1710
13
  return napi_clear_last_error(env);
1711
}
1712
1713
168
static napi_status set_error_code(napi_env env,
1714
                                  v8::Local<v8::Value> error,
1715
                                  napi_value code,
1716
                                  const char* code_cstring) {
1717

168
  if ((code != nullptr) || (code_cstring != nullptr)) {
1718
94
    v8::Isolate* isolate = env->isolate;
1719
94
    v8::Local<v8::Context> context = isolate->GetCurrentContext();
1720
94
    v8::Local<v8::Object> err_object = error.As<v8::Object>();
1721
1722
94
    v8::Local<v8::Value> code_value = v8impl::V8LocalValueFromJsValue(code);
1723
94
    if (code != nullptr) {
1724
3
      code_value = v8impl::V8LocalValueFromJsValue(code);
1725
6
      RETURN_STATUS_IF_FALSE(env, code_value->IsString(), napi_string_expected);
1726
    } else {
1727
273
      CHECK_NEW_FROM_UTF8(env, code_value, code_cstring);
1728
    }
1729
1730
    v8::Local<v8::Name> code_key;
1731
282
    CHECK_NEW_FROM_UTF8(env, code_key, "code");
1732
1733
94
    v8::Maybe<bool> set_maybe = err_object->Set(context, code_key, code_value);
1734
188
    RETURN_STATUS_IF_FALSE(env,
1735
                           set_maybe.FromMaybe(false),
1736
                           napi_generic_failure);
1737
1738
    // now update the name to be "name [code]" where name is the
1739
    // original name and code is the code associated with the Error
1740
    v8::Local<v8::String> name_string;
1741
282
    CHECK_NEW_FROM_UTF8(env, name_string, "");
1742
    v8::Local<v8::Name> name_key;
1743
282
    CHECK_NEW_FROM_UTF8(env, name_key, "name");
1744
1745
94
    auto maybe_name = err_object->Get(context, name_key);
1746
94
    if (!maybe_name.IsEmpty()) {
1747
94
      v8::Local<v8::Value> name = maybe_name.ToLocalChecked();
1748
188
      if (name->IsString()) {
1749
94
        name_string = v8::String::Concat(name_string, name.As<v8::String>());
1750
      }
1751
    }
1752
    name_string = v8::String::Concat(name_string,
1753
94
                                     FIXED_ONE_BYTE_STRING(isolate, " ["));
1754
94
    name_string = v8::String::Concat(name_string, code_value.As<v8::String>());
1755
    name_string = v8::String::Concat(name_string,
1756
94
                                     FIXED_ONE_BYTE_STRING(isolate, "]"));
1757
1758
94
    set_maybe = err_object->Set(context, name_key, name_string);
1759
188
    RETURN_STATUS_IF_FALSE(env,
1760
                           set_maybe.FromMaybe(false),
1761
                           napi_generic_failure);
1762
  }
1763
168
  return napi_ok;
1764
}
1765
1766
3
napi_status napi_create_error(napi_env env,
1767
                              napi_value code,
1768
                              napi_value msg,
1769
                              napi_value* result) {
1770
3
  CHECK_ENV(env);
1771
3
  CHECK_ARG(env, msg);
1772
3
  CHECK_ARG(env, result);
1773
1774
3
  v8::Local<v8::Value> message_value = v8impl::V8LocalValueFromJsValue(msg);
1775
6
  RETURN_STATUS_IF_FALSE(env, message_value->IsString(), napi_string_expected);
1776
1777
  v8::Local<v8::Value> error_obj =
1778
3
      v8::Exception::Error(message_value.As<v8::String>());
1779
3
  napi_status status = set_error_code(env, error_obj, code, nullptr);
1780
3
  if (status != napi_ok) return status;
1781
1782
3
  *result = v8impl::JsValueFromV8LocalValue(error_obj);
1783
1784
3
  return napi_clear_last_error(env);
1785
}
1786
1787
2
napi_status napi_create_type_error(napi_env env,
1788
                                   napi_value code,
1789
                                   napi_value msg,
1790
                                   napi_value* result) {
1791
2
  CHECK_ENV(env);
1792
2
  CHECK_ARG(env, msg);
1793
2
  CHECK_ARG(env, result);
1794
1795
2
  v8::Local<v8::Value> message_value = v8impl::V8LocalValueFromJsValue(msg);
1796
4
  RETURN_STATUS_IF_FALSE(env, message_value->IsString(), napi_string_expected);
1797
1798
  v8::Local<v8::Value> error_obj =
1799
2
      v8::Exception::TypeError(message_value.As<v8::String>());
1800
2
  napi_status status = set_error_code(env, error_obj, code, nullptr);
1801
2
  if (status != napi_ok) return status;
1802
1803
2
  *result = v8impl::JsValueFromV8LocalValue(error_obj);
1804
1805
2
  return napi_clear_last_error(env);
1806
}
1807
1808
2
napi_status napi_create_range_error(napi_env env,
1809
                                    napi_value code,
1810
                                    napi_value msg,
1811
                                    napi_value* result) {
1812
2
  CHECK_ENV(env);
1813
2
  CHECK_ARG(env, msg);
1814
2
  CHECK_ARG(env, result);
1815
1816
2
  v8::Local<v8::Value> message_value = v8impl::V8LocalValueFromJsValue(msg);
1817
4
  RETURN_STATUS_IF_FALSE(env, message_value->IsString(), napi_string_expected);
1818
1819
  v8::Local<v8::Value> error_obj =
1820
2
      v8::Exception::RangeError(message_value.As<v8::String>());
1821
2
  napi_status status = set_error_code(env, error_obj, code, nullptr);
1822
2
  if (status != napi_ok) return status;
1823
1824
2
  *result = v8impl::JsValueFromV8LocalValue(error_obj);
1825
1826
2
  return napi_clear_last_error(env);
1827
}
1828
1829
246
napi_status napi_typeof(napi_env env,
1830
                        napi_value value,
1831
                        napi_valuetype* result) {
1832
  // Omit NAPI_PREAMBLE and GET_RETURN_STATUS because V8 calls here cannot throw
1833
  // JS exceptions.
1834
246
  CHECK_ENV(env);
1835
246
  CHECK_ARG(env, value);
1836
246
  CHECK_ARG(env, result);
1837
1838
246
  v8::Local<v8::Value> v = v8impl::V8LocalValueFromJsValue(value);
1839
1840
246
  if (v->IsNumber()) {
1841
51
    *result = napi_number;
1842
390
  } else if (v->IsString()) {
1843
80
    *result = napi_string;
1844
115
  } else if (v->IsFunction()) {
1845
    // This test has to come before IsObject because IsFunction
1846
    // implies IsObject
1847
16
    *result = napi_function;
1848
99
  } else if (v->IsExternal()) {
1849
    // This test has to come before IsObject because IsExternal
1850
    // implies IsObject
1851
2
    *result = napi_external;
1852
97
  } else if (v->IsObject()) {
1853
84
    *result = napi_object;
1854
13
  } else if (v->IsBoolean()) {
1855
1
    *result = napi_boolean;
1856
24
  } else if (v->IsUndefined()) {
1857
2
    *result = napi_undefined;
1858
10
  } else if (v->IsSymbol()) {
1859
9
    *result = napi_symbol;
1860
2
  } else if (v->IsNull()) {
1861
1
    *result = napi_null;
1862
  } else {
1863
    // Should not get here unless V8 has added some new kind of value.
1864
    return napi_set_last_error(env, napi_invalid_arg);
1865
  }
1866
1867
246
  return napi_clear_last_error(env);
1868
}
1869
1870
2
napi_status napi_get_undefined(napi_env env, napi_value* result) {
1871
2
  CHECK_ENV(env);
1872
2
  CHECK_ARG(env, result);
1873
1874
  *result = v8impl::JsValueFromV8LocalValue(
1875
4
      v8::Undefined(env->isolate));
1876
1877
2
  return napi_clear_last_error(env);
1878
}
1879
1880
4
napi_status napi_get_null(napi_env env, napi_value* result) {
1881
4
  CHECK_ENV(env);
1882
4
  CHECK_ARG(env, result);
1883
1884
  *result = v8impl::JsValueFromV8LocalValue(
1885
8
        v8::Null(env->isolate));
1886
1887
4
  return napi_clear_last_error(env);
1888
}
1889
1890
// Gets all callback info in a single call. (Ugly, but faster.)
1891
2742
napi_status napi_get_cb_info(
1892
    napi_env env,               // [in] NAPI environment handle
1893
    napi_callback_info cbinfo,  // [in] Opaque callback-info handle
1894
    size_t* argc,      // [in-out] Specifies the size of the provided argv array
1895
                       // and receives the actual count of args.
1896
    napi_value* argv,  // [out] Array of values
1897
    napi_value* this_arg,  // [out] Receives the JS 'this' arg for the call
1898
    void** data) {         // [out] Receives the data pointer for the callback.
1899
2742
  CHECK_ENV(env);
1900
2742
  CHECK_ARG(env, cbinfo);
1901
1902
  v8impl::CallbackWrapper* info =
1903
2742
      reinterpret_cast<v8impl::CallbackWrapper*>(cbinfo);
1904
1905
2742
  if (argv != nullptr) {
1906
2718
    CHECK_ARG(env, argc);
1907
2718
    info->Args(argv, *argc);
1908
  }
1909
2742
  if (argc != nullptr) {
1910
2727
    *argc = info->ArgsLength();
1911
  }
1912
2742
  if (this_arg != nullptr) {
1913
32
    *this_arg = info->This();
1914
  }
1915
2742
  if (data != nullptr) {
1916
5
    *data = info->Data();
1917
  }
1918
1919
2742
  return napi_clear_last_error(env);
1920
}
1921
1922
4
napi_status napi_get_new_target(napi_env env,
1923
                                napi_callback_info cbinfo,
1924
                                napi_value* result) {
1925
4
  CHECK_ENV(env);
1926
4
  CHECK_ARG(env, cbinfo);
1927
4
  CHECK_ARG(env, result);
1928
1929
  v8impl::CallbackWrapper* info =
1930
4
      reinterpret_cast<v8impl::CallbackWrapper*>(cbinfo);
1931
1932
4
  *result = info->GetNewTarget();
1933
4
  return napi_clear_last_error(env);
1934
}
1935
1936
22
napi_status napi_call_function(napi_env env,
1937
                               napi_value recv,
1938
                               napi_value func,
1939
                               size_t argc,
1940
                               const napi_value* argv,
1941
                               napi_value* result) {
1942

44
  NAPI_PREAMBLE(env);
1943
22
  CHECK_ARG(env, recv);
1944
22
  if (argc > 0) {
1945
6
    CHECK_ARG(env, argv);
1946
  }
1947
1948
22
  v8::Isolate* isolate = env->isolate;
1949
22
  v8::Local<v8::Context> context = isolate->GetCurrentContext();
1950
1951
22
  v8::Local<v8::Value> v8recv = v8impl::V8LocalValueFromJsValue(recv);
1952
1953
  v8::Local<v8::Function> v8func;
1954

66
  CHECK_TO_FUNCTION(env, v8func, func);
1955
1956
  auto maybe = v8func->Call(context, v8recv, argc,
1957
44
    reinterpret_cast<v8::Local<v8::Value>*>(const_cast<napi_value*>(argv)));
1958
1959
22
  if (try_catch.HasCaught()) {
1960
4
    return napi_set_last_error(env, napi_pending_exception);
1961
  } else {
1962
18
    if (result != nullptr) {
1963
9
      CHECK_MAYBE_EMPTY(env, maybe, napi_generic_failure);
1964
9
      *result = v8impl::JsValueFromV8LocalValue(maybe.ToLocalChecked());
1965
    }
1966
18
    return napi_clear_last_error(env);
1967
22
  }
1968
}
1969
1970
13
napi_status napi_get_global(napi_env env, napi_value* result) {
1971
13
  CHECK_ENV(env);
1972
13
  CHECK_ARG(env, result);
1973
1974
13
  v8::Isolate* isolate = env->isolate;
1975
  // TODO(ianhall): what if we need the global object from a different
1976
  // context in the same isolate?
1977
  // Should napi_env be the current context rather than the current isolate?
1978
13
  v8::Local<v8::Context> context = isolate->GetCurrentContext();
1979
26
  *result = v8impl::JsValueFromV8LocalValue(context->Global());
1980
1981
13
  return napi_clear_last_error(env);
1982
}
1983
1984
1
napi_status napi_throw(napi_env env, napi_value error) {
1985

2
  NAPI_PREAMBLE(env);
1986
1
  CHECK_ARG(env, error);
1987
1988
1
  v8::Isolate* isolate = env->isolate;
1989
1990
1
  isolate->ThrowException(v8impl::V8LocalValueFromJsValue(error));
1991
  // any VM calls after this point and before returning
1992
  // to the javascript invoker will fail
1993
1
  return napi_clear_last_error(env);
1994
}
1995
1996
69
napi_status napi_throw_error(napi_env env,
1997
                             const char* code,
1998
                             const char* msg) {
1999

138
  NAPI_PREAMBLE(env);
2000
2001
69
  v8::Isolate* isolate = env->isolate;
2002
  v8::Local<v8::String> str;
2003
207
  CHECK_NEW_FROM_UTF8(env, str, msg);
2004
2005
69
  v8::Local<v8::Value> error_obj = v8::Exception::Error(str);
2006
69
  napi_status status = set_error_code(env, error_obj, nullptr, code);
2007
69
  if (status != napi_ok) return status;
2008
2009
69
  isolate->ThrowException(error_obj);
2010
  // any VM calls after this point and before returning
2011
  // to the javascript invoker will fail
2012
69
  return napi_clear_last_error(env);
2013
}
2014
2015
90
napi_status napi_throw_type_error(napi_env env,
2016
                                  const char* code,
2017
                                  const char* msg) {
2018

180
  NAPI_PREAMBLE(env);
2019
2020
90
  v8::Isolate* isolate = env->isolate;
2021
  v8::Local<v8::String> str;
2022
270
  CHECK_NEW_FROM_UTF8(env, str, msg);
2023
2024
90
  v8::Local<v8::Value> error_obj = v8::Exception::TypeError(str);
2025
90
  napi_status status = set_error_code(env, error_obj, nullptr, code);
2026
90
  if (status != napi_ok) return status;
2027
2028
90
  isolate->ThrowException(error_obj);
2029
  // any VM calls after this point and before returning
2030
  // to the javascript invoker will fail
2031
90
  return napi_clear_last_error(env);
2032
}
2033
2034
2
napi_status napi_throw_range_error(napi_env env,
2035
                                   const char* code,
2036
                                   const char* msg) {
2037

4
  NAPI_PREAMBLE(env);
2038
2039
2
  v8::Isolate* isolate = env->isolate;
2040
  v8::Local<v8::String> str;
2041
6
  CHECK_NEW_FROM_UTF8(env, str, msg);
2042
2043
2
  v8::Local<v8::Value> error_obj = v8::Exception::RangeError(str);
2044
2
  napi_status status = set_error_code(env, error_obj, nullptr, code);
2045
2
  if (status != napi_ok) return status;
2046
2047
2
  isolate->ThrowException(error_obj);
2048
  // any VM calls after this point and before returning
2049
  // to the javascript invoker will fail
2050
2
  return napi_clear_last_error(env);
2051
}
2052
2053
10
napi_status napi_is_error(napi_env env, napi_value value, bool* result) {
2054
  // Omit NAPI_PREAMBLE and GET_RETURN_STATUS because V8 calls here cannot
2055
  // throw JS exceptions.
2056
10
  CHECK_ENV(env);
2057
10
  CHECK_ARG(env, value);
2058
10
  CHECK_ARG(env, result);
2059
2060
10
  v8::Local<v8::Value> val = v8impl::V8LocalValueFromJsValue(value);
2061
10
  *result = val->IsNativeError();
2062
2063
10
  return napi_clear_last_error(env);
2064
}
2065
2066
64
napi_status napi_get_value_double(napi_env env,
2067
                                  napi_value value,
2068
                                  double* result) {
2069
  // Omit NAPI_PREAMBLE and GET_RETURN_STATUS because V8 calls here cannot throw
2070
  // JS exceptions.
2071
64
  CHECK_ENV(env);
2072
64
  CHECK_ARG(env, value);
2073
64
  CHECK_ARG(env, result);
2074
2075
64
  v8::Local<v8::Value> val = v8impl::V8LocalValueFromJsValue(value);
2076
64
  RETURN_STATUS_IF_FALSE(env, val->IsNumber(), napi_number_expected);
2077
2078
110
  *result = val.As<v8::Number>()->Value();
2079
2080
55
  return napi_clear_last_error(env);
2081
}
2082
2083
39
napi_status napi_get_value_int32(napi_env env,
2084
                                 napi_value value,
2085
                                 int32_t* result) {
2086
  // Omit NAPI_PREAMBLE and GET_RETURN_STATUS because V8 calls here cannot throw
2087
  // JS exceptions.
2088
39
  CHECK_ENV(env);
2089
39
  CHECK_ARG(env, value);
2090
39
  CHECK_ARG(env, result);
2091
2092
39
  v8::Local<v8::Value> val = v8impl::V8LocalValueFromJsValue(value);
2093
2094
39
  if (val->IsInt32()) {
2095
42
    *result = val.As<v8::Int32>()->Value();
2096
  } else {
2097
18
    RETURN_STATUS_IF_FALSE(env, val->IsNumber(), napi_number_expected);
2098
2099
    // Empty context: https://github.com/nodejs/node/issues/14379
2100
    v8::Local<v8::Context> context;
2101
20
    *result = val->Int32Value(context).FromJust();
2102
  }
2103
2104
31
  return napi_clear_last_error(env);
2105
}
2106
2107
22
napi_status napi_get_value_uint32(napi_env env,
2108
                                  napi_value value,
2109
                                  uint32_t* result) {
2110
  // Omit NAPI_PREAMBLE and GET_RETURN_STATUS because V8 calls here cannot throw
2111
  // JS exceptions.
2112
22
  CHECK_ENV(env);
2113
22
  CHECK_ARG(env, value);
2114
22
  CHECK_ARG(env, result);
2115
2116
22
  v8::Local<v8::Value> val = v8impl::V8LocalValueFromJsValue(value);
2117
2118
22
  if (val->IsUint32()) {
2119
16
    *result = val.As<v8::Uint32>()->Value();
2120
  } else {
2121
14
    RETURN_STATUS_IF_FALSE(env, val->IsNumber(), napi_number_expected);
2122
2123
    // Empty context: https://github.com/nodejs/node/issues/14379
2124
    v8::Local<v8::Context> context;
2125
12
    *result = val->Uint32Value(context).FromJust();
2126
  }
2127
2128
14
  return napi_clear_last_error(env);
2129
}
2130
2131
17
napi_status napi_get_value_int64(napi_env env,
2132
                                 napi_value value,
2133
                                 int64_t* result) {
2134
  // Omit NAPI_PREAMBLE and GET_RETURN_STATUS because V8 calls here cannot throw
2135
  // JS exceptions.
2136
17
  CHECK_ENV(env);
2137
17
  CHECK_ARG(env, value);
2138
17
  CHECK_ARG(env, result);
2139
2140
17
  v8::Local<v8::Value> val = v8impl::V8LocalValueFromJsValue(value);
2141
2142
  // This is still a fast path very likely to be taken.
2143
17
  if (val->IsInt32()) {
2144
8
    *result = val.As<v8::Int32>()->Value();
2145
4
    return napi_clear_last_error(env);
2146
  }
2147
2148
13
  RETURN_STATUS_IF_FALSE(env, val->IsNumber(), napi_number_expected);
2149
2150
  // v8::Value::IntegerValue() converts NaN to INT64_MIN, inconsistent with
2151
  // v8::Value::Int32Value() that converts NaN to 0. So special-case NaN here.
2152
10
  double doubleValue = val.As<v8::Number>()->Value();
2153
5
  if (std::isnan(doubleValue)) {
2154
1
    *result = 0;
2155
  } else {
2156
    // Empty context: https://github.com/nodejs/node/issues/14379
2157
    v8::Local<v8::Context> context;
2158
8
    *result = val->IntegerValue(context).FromJust();
2159
  }
2160
2161
5
  return napi_clear_last_error(env);
2162
}
2163
2164
17
napi_status napi_get_value_bool(napi_env env, napi_value value, bool* result) {
2165
  // Omit NAPI_PREAMBLE and GET_RETURN_STATUS because V8 calls here cannot throw
2166
  // JS exceptions.
2167
17
  CHECK_ENV(env);
2168
17
  CHECK_ARG(env, value);
2169
17
  CHECK_ARG(env, result);
2170
2171
17
  v8::Local<v8::Value> val = v8impl::V8LocalValueFromJsValue(value);
2172
17
  RETURN_STATUS_IF_FALSE(env, val->IsBoolean(), napi_boolean_expected);
2173
2174
10
  *result = val.As<v8::Boolean>()->Value();
2175
2176
5
  return napi_clear_last_error(env);
2177
}
2178
2179
// Copies a JavaScript string into a LATIN-1 string buffer. The result is the
2180
// number of bytes (excluding the null terminator) copied into buf.
2181
// A sufficient buffer size should be greater than the length of string,
2182
// reserving space for null terminator.
2183
// If bufsize is insufficient, the string will be truncated and null terminated.
2184
// If buf is NULL, this method returns the length of the string (in bytes)
2185
// via the result parameter.
2186
// The result argument is optional unless buf is NULL.
2187
11
napi_status napi_get_value_string_latin1(napi_env env,
2188
                                         napi_value value,
2189
                                         char* buf,
2190
                                         size_t bufsize,
2191
                                         size_t* result) {
2192
11
  CHECK_ENV(env);
2193
11
  CHECK_ARG(env, value);
2194
2195
11
  v8::Local<v8::Value> val = v8impl::V8LocalValueFromJsValue(value);
2196
22
  RETURN_STATUS_IF_FALSE(env, val->IsString(), napi_string_expected);
2197
2198
11
  if (!buf) {
2199
    CHECK_ARG(env, result);
2200
    *result = val.As<v8::String>()->Length();
2201
  } else {
2202
    int copied = val.As<v8::String>()->WriteOneByte(
2203
      reinterpret_cast<uint8_t*>(buf), 0, bufsize - 1,
2204
33
      v8::String::NO_NULL_TERMINATION);
2205
2206
11
    buf[copied] = '\0';
2207
11
    if (result != nullptr) {
2208
11
      *result = copied;
2209
    }
2210
  }
2211
2212
11
  return napi_clear_last_error(env);
2213
}
2214
2215
// Copies a JavaScript string into a UTF-8 string buffer. The result is the
2216
// number of bytes (excluding the null terminator) copied into buf.
2217
// A sufficient buffer size should be greater than the length of string,
2218
// reserving space for null terminator.
2219
// If bufsize is insufficient, the string will be truncated and null terminated.
2220
// If buf is NULL, this method returns the length of the string (in bytes)
2221
// via the result parameter.
2222
// The result argument is optional unless buf is NULL.
2223
34
napi_status napi_get_value_string_utf8(napi_env env,
2224
                                       napi_value value,
2225
                                       char* buf,
2226
                                       size_t bufsize,
2227
                                       size_t* result) {
2228
34
  CHECK_ENV(env);
2229
34
  CHECK_ARG(env, value);
2230
2231
34
  v8::Local<v8::Value> val = v8impl::V8LocalValueFromJsValue(value);
2232
68
  RETURN_STATUS_IF_FALSE(env, val->IsString(), napi_string_expected);
2233
2234
25
  if (!buf) {
2235
7
    CHECK_ARG(env, result);
2236
14
    *result = val.As<v8::String>()->Utf8Length();
2237
  } else {
2238
    int copied = val.As<v8::String>()->WriteUtf8(
2239
      buf, bufsize - 1, nullptr, v8::String::REPLACE_INVALID_UTF8 |
2240
54
      v8::String::NO_NULL_TERMINATION);
2241
2242
18
    buf[copied] = '\0';
2243
18
    if (result != nullptr) {
2244
16
      *result = copied;
2245
    }
2246
  }
2247
2248
25
  return napi_clear_last_error(env);
2249
}
2250
2251
// Copies a JavaScript string into a UTF-16 string buffer. The result is the
2252
// number of 2-byte code units (excluding the null terminator) copied into buf.
2253
// A sufficient buffer size should be greater than the length of string,
2254
// reserving space for null terminator.
2255
// If bufsize is insufficient, the string will be truncated and null terminated.
2256
// If buf is NULL, this method returns the length of the string (in 2-byte
2257
// code units) via the result parameter.
2258
// The result argument is optional unless buf is NULL.
2259
20
napi_status napi_get_value_string_utf16(napi_env env,
2260
                                        napi_value value,
2261
                                        char16_t* buf,
2262
                                        size_t bufsize,
2263
                                        size_t* result) {
2264
20
  CHECK_ENV(env);
2265
20
  CHECK_ARG(env, value);
2266
2267
20
  v8::Local<v8::Value> val = v8impl::V8LocalValueFromJsValue(value);
2268
40
  RETURN_STATUS_IF_FALSE(env, val->IsString(), napi_string_expected);
2269
2270
20
  if (!buf) {
2271
7
    CHECK_ARG(env, result);
2272
    // V8 assumes UTF-16 length is the same as the number of characters.
2273
14
    *result = val.As<v8::String>()->Length();
2274
  } else {
2275
    int copied = val.As<v8::String>()->Write(
2276
      reinterpret_cast<uint16_t*>(buf), 0, bufsize - 1,
2277
39
      v8::String::NO_NULL_TERMINATION);
2278
2279
13
    buf[copied] = '\0';
2280
13
    if (result != nullptr) {
2281
13
      *result = copied;
2282
    }
2283
  }
2284
2285
20
  return napi_clear_last_error(env);
2286
}
2287
2288
15
napi_status napi_coerce_to_object(napi_env env,
2289
                                  napi_value value,
2290
                                  napi_value* result) {
2291

30
  NAPI_PREAMBLE(env);
2292
15
  CHECK_ARG(env, value);
2293
15
  CHECK_ARG(env, result);
2294
2295
15
  v8::Isolate* isolate = env->isolate;
2296
15
  v8::Local<v8::Context> context = isolate->GetCurrentContext();
2297
  v8::Local<v8::Object> obj;
2298

60
  CHECK_TO_OBJECT(env, context, obj, value);
2299
2300
15
  *result = v8impl::JsValueFromV8LocalValue(obj);
2301
15
  return GET_RETURN_STATUS(env);
2302
}
2303
2304
14
napi_status napi_coerce_to_bool(napi_env env,
2305
                                napi_value value,
2306
                                napi_value* result) {
2307

28
  NAPI_PREAMBLE(env);
2308
14
  CHECK_ARG(env, value);
2309
14
  CHECK_ARG(env, result);
2310
2311
14
  v8::Isolate* isolate = env->isolate;
2312
14
  v8::Local<v8::Context> context = isolate->GetCurrentContext();
2313
  v8::Local<v8::Boolean> b;
2314
2315

56
  CHECK_TO_BOOL(env, context, b, value);
2316
2317
14
  *result = v8impl::JsValueFromV8LocalValue(b);
2318
14
  return GET_RETURN_STATUS(env);
2319
}
2320
2321
15
napi_status napi_coerce_to_number(napi_env env,
2322
                                  napi_value value,
2323
                                  napi_value* result) {
2324

30
  NAPI_PREAMBLE(env);
2325
15
  CHECK_ARG(env, value);
2326
15
  CHECK_ARG(env, result);
2327
2328
15
  v8::Isolate* isolate = env->isolate;
2329
15
  v8::Local<v8::Context> context = isolate->GetCurrentContext();
2330
  v8::Local<v8::Number> num;
2331
2332

60
  CHECK_TO_NUMBER(env, context, num, value);
2333
2334
14
  *result = v8impl::JsValueFromV8LocalValue(num);
2335
14
  return GET_RETURN_STATUS(env);
2336
}
2337
2338
14
napi_status napi_coerce_to_string(napi_env env,
2339
                                  napi_value value,
2340
                                  napi_value* result) {
2341

28
  NAPI_PREAMBLE(env);
2342
14
  CHECK_ARG(env, value);
2343
14
  CHECK_ARG(env, result);
2344
2345
14
  v8::Isolate* isolate = env->isolate;
2346
14
  v8::Local<v8::Context> context = isolate->GetCurrentContext();
2347
  v8::Local<v8::String> str;
2348
2349

56
  CHECK_TO_STRING(env, context, str, value);
2350
2351
13
  *result = v8impl::JsValueFromV8LocalValue(str);
2352
13
  return GET_RETURN_STATUS(env);
2353
}
2354
2355
17
napi_status napi_wrap(napi_env env,
2356
                      napi_value js_object,
2357
                      void* native_object,
2358
                      napi_finalize finalize_cb,
2359
                      void* finalize_hint,
2360
                      napi_ref* result) {
2361

34
  NAPI_PREAMBLE(env);
2362
17
  CHECK_ARG(env, js_object);
2363
2364
17
  v8::Isolate* isolate = env->isolate;
2365
17
  v8::Local<v8::Context> context = isolate->GetCurrentContext();
2366
2367
17
  v8::Local<v8::Value> value = v8impl::V8LocalValueFromJsValue(js_object);
2368
17
  RETURN_STATUS_IF_FALSE(env, value->IsObject(), napi_invalid_arg);
2369
17
  v8::Local<v8::Object> obj = value.As<v8::Object>();
2370
2371
  // If we've already wrapped this object, we error out.
2372
17
  RETURN_STATUS_IF_FALSE(env, !v8impl::FindWrapper(obj), napi_invalid_arg);
2373
2374
  // Create a wrapper object with an internal field to hold the wrapped pointer
2375
  // and a second internal field to identify the owner as N-API.
2376
  v8::Local<v8::ObjectTemplate> wrapper_template;
2377
64
  ENV_OBJECT_TEMPLATE(env, wrap, wrapper_template, v8impl::kWrapperFields);
2378
2379
16
  auto maybe_object = wrapper_template->NewInstance(context);
2380
16
  CHECK_MAYBE_EMPTY(env, maybe_object, napi_generic_failure);
2381
16
  v8::Local<v8::Object> wrapper = maybe_object.ToLocalChecked();
2382
2383
  // Store the pointer as an external in the wrapper.
2384
32
  wrapper->SetInternalField(0, v8::External::New(isolate, native_object));
2385
  wrapper->SetInternalField(1, v8::External::New(isolate,
2386
32
    reinterpret_cast<void*>(const_cast<char*>(v8impl::napi_wrap_name))));
2387
2388
  // Insert the wrapper into the object's prototype chain.
2389
16
  v8::Local<v8::Value> proto = obj->GetPrototype();
2390
32
  CHECK(wrapper->SetPrototype(context, proto).FromJust());
2391
32
  CHECK(obj->SetPrototype(context, wrapper).FromJust());
2392
2393
16
  v8impl::Reference* reference = nullptr;
2394
16
  if (result != nullptr) {
2395
    // The returned reference should be deleted via napi_delete_reference()
2396
    // ONLY in response to the finalize callback invocation. (If it is deleted
2397
    // before then, then the finalize callback will never be invoked.)
2398
    // Therefore a finalize callback is required when returning a reference.
2399
8
    CHECK_ARG(env, finalize_cb);
2400
    reference = v8impl::Reference::New(
2401
8
        env, obj, 0, false, finalize_cb, native_object, finalize_hint);
2402
8
    *result = reinterpret_cast<napi_ref>(reference);
2403
8
  } else if (finalize_cb != nullptr) {
2404
    // Create a self-deleting reference just for the finalize callback.
2405
    reference = v8impl::Reference::New(
2406
5
        env, obj, 0, true, finalize_cb, native_object, finalize_hint);
2407
  }
2408
2409
16
  if (reference != nullptr) {
2410
26
    wrapper->SetInternalField(2, v8::External::New(isolate, reference));
2411
  }
2412
2413
16
  return GET_RETURN_STATUS(env);
2414
}
2415
2416
23
napi_status napi_unwrap(napi_env env, napi_value obj, void** result) {
2417
  // Omit NAPI_PREAMBLE and GET_RETURN_STATUS because V8 calls here cannot throw
2418
  // JS exceptions.
2419
23
  CHECK_ENV(env);
2420
  v8::Local<v8::Object> wrapper;
2421
23
  return napi_set_last_error(env, v8impl::Unwrap(env, obj, result, &wrapper));
2422
}
2423
2424
2
napi_status napi_remove_wrap(napi_env env, napi_value obj, void** result) {
2425

4
  NAPI_PREAMBLE(env);
2426
  v8::Local<v8::Object> wrapper;
2427
  v8::Local<v8::Object> parent;
2428
2
  napi_status status = v8impl::Unwrap(env, obj, result, &wrapper, &parent);
2429
2
  if (status != napi_ok) {
2430
    return napi_set_last_error(env, status);
2431
  }
2432
2433
4
  v8::Local<v8::Value> external = wrapper->GetInternalField(2);
2434
2
  if (external->IsExternal()) {
2435
    v8impl::Reference::Delete(
2436
4
        static_cast<v8impl::Reference*>(external.As<v8::External>()->Value()));
2437
  }
2438
2439
2
  if (!parent.IsEmpty()) {
2440
    v8::Maybe<bool> maybe = parent->SetPrototype(
2441
4
        env->isolate->GetCurrentContext(), wrapper->GetPrototype());
2442
2
    CHECK_MAYBE_NOTHING(env, maybe, napi_generic_failure);
2443
4
    if (!maybe.FromMaybe(false)) {
2444
      return napi_set_last_error(env, napi_generic_failure);
2445
    }
2446
  }
2447
2448
2
  return GET_RETURN_STATUS(env);
2449
}
2450
2451
6
napi_status napi_create_external(napi_env env,
2452
                                 void* data,
2453
                                 napi_finalize finalize_cb,
2454
                                 void* finalize_hint,
2455
                                 napi_value* result) {
2456

12
  NAPI_PREAMBLE(env);
2457
6
  CHECK_ARG(env, result);
2458
2459
6
  v8::Isolate* isolate = env->isolate;
2460
2461
6
  v8::Local<v8::Value> external_value = v8::External::New(isolate, data);
2462
2463
  // The Reference object will delete itself after invoking the finalizer
2464
  // callback.
2465
  v8impl::Reference::New(env,
2466
      external_value,
2467
      0,
2468
      true,
2469
      finalize_cb,
2470
      data,
2471
6
      finalize_hint);
2472
2473
6
  *result = v8impl::JsValueFromV8LocalValue(external_value);
2474
2475
6
  return napi_clear_last_error(env);
2476
}
2477
2478
3
napi_status napi_get_value_external(napi_env env,
2479
                                    napi_value value,
2480
                                    void** result) {
2481
3
  CHECK_ENV(env);
2482
3
  CHECK_ARG(env, value);
2483
3
  CHECK_ARG(env, result);
2484
2485
3
  v8::Local<v8::Value> val = v8impl::V8LocalValueFromJsValue(value);
2486
3
  RETURN_STATUS_IF_FALSE(env, val->IsExternal(), napi_invalid_arg);
2487
2488
3
  v8::Local<v8::External> external_value = val.As<v8::External>();
2489
3
  *result = external_value->Value();
2490
2491
3
  return napi_clear_last_error(env);
2492
}
2493
2494
// Set initial_refcount to 0 for a weak reference, >0 for a strong reference.
2495
13
napi_status napi_create_reference(napi_env env,
2496
                                  napi_value value,
2497
                                  uint32_t initial_refcount,
2498
                                  napi_ref* result) {
2499
  // Omit NAPI_PREAMBLE and GET_RETURN_STATUS because V8 calls here cannot throw
2500
  // JS exceptions.
2501
13
  CHECK_ENV(env);
2502
13
  CHECK_ARG(env, value);
2503
13
  CHECK_ARG(env, result);
2504
2505
13
  v8::Local<v8::Value> v8_value = v8impl::V8LocalValueFromJsValue(value);
2506
2507

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

14
  NAPI_PREAMBLE(env);
2678
7
  CHECK_ARG(env, constructor);
2679
7
  if (argc > 0) {
2680
7
    CHECK_ARG(env, argv);
2681
  }
2682
7
  CHECK_ARG(env, result);
2683
2684
7
  v8::Isolate* isolate = env->isolate;
2685
7
  v8::Local<v8::Context> context = isolate->GetCurrentContext();
2686
2687
  v8::Local<v8::Function> ctor;
2688

21
  CHECK_TO_FUNCTION(env, ctor, constructor);
2689
2690
  auto maybe = ctor->NewInstance(context, argc,
2691
14
    reinterpret_cast<v8::Local<v8::Value>*>(const_cast<napi_value*>(argv)));
2692
2693
7
  CHECK_MAYBE_EMPTY(env, maybe, napi_generic_failure);
2694
2695
7
  *result = v8impl::JsValueFromV8LocalValue(maybe.ToLocalChecked());
2696
7
  return GET_RETURN_STATUS(env);
2697
}
2698
2699
2278
napi_status napi_instanceof(napi_env env,
2700
                            napi_value object,
2701
                            napi_value constructor,
2702
                            bool* result) {
2703

4556
  NAPI_PREAMBLE(env);
2704
2278
  CHECK_ARG(env, object);
2705
2278
  CHECK_ARG(env, result);
2706
2707
2278
  *result = false;
2708
2709
  v8::Local<v8::Object> ctor;
2710
2278
  v8::Isolate* isolate = env->isolate;
2711
2278
  v8::Local<v8::Context> context = isolate->GetCurrentContext();
2712
2713

9112
  CHECK_TO_OBJECT(env, context, ctor, constructor);
2714
2715
2278
  if (!ctor->IsFunction()) {
2716
    napi_throw_type_error(env,
2717
                          "ERR_NAPI_CONS_FUNCTION",
2718
88
                          "Constructor must be a function");
2719
2720
88
    return napi_set_last_error(env, napi_function_expected);
2721
  }
2722
2723
2190
  napi_status status = napi_generic_failure;
2724
2725
2190
  v8::Local<v8::Value> val = v8impl::V8LocalValueFromJsValue(object);
2726
2190
  auto maybe_result = val->InstanceOf(context, ctor);
2727
2190
  CHECK_MAYBE_NOTHING(env, maybe_result, status);
2728
1166
  *result = maybe_result.FromJust();
2729
1166
  return GET_RETURN_STATUS(env);
2730
}
2731
2732
6
napi_status napi_async_init(napi_env env,
2733
                            napi_value async_resource,
2734
                            napi_value async_resource_name,
2735
                            napi_async_context* result) {
2736
6
  CHECK_ENV(env);
2737
6
  CHECK_ARG(env, async_resource_name);
2738
6
  CHECK_ARG(env, result);
2739
2740
6
  v8::Isolate* isolate = env->isolate;
2741
6
  v8::Local<v8::Context> context = isolate->GetCurrentContext();
2742
2743
  v8::Local<v8::Object> v8_resource;
2744
6
  if (async_resource != nullptr) {
2745

24
    CHECK_TO_OBJECT(env, context, v8_resource, async_resource);
2746
  } else {
2747
    v8_resource = v8::Object::New(isolate);
2748
  }
2749
2750
  v8::Local<v8::String> v8_resource_name;
2751

24
  CHECK_TO_STRING(env, context, v8_resource_name, async_resource_name);
2752
2753
  // TODO(jasongin): Consider avoiding allocation here by using
2754
  // a tagged pointer with 2×31 bit fields instead.
2755
6
  node::async_context* async_context = new node::async_context();
2756
2757
6
  *async_context = node::EmitAsyncInit(isolate, v8_resource, v8_resource_name);
2758
6
  *result = reinterpret_cast<napi_async_context>(async_context);
2759
2760
6
  return napi_clear_last_error(env);
2761
}
2762
2763
6
napi_status napi_async_destroy(napi_env env,
2764
                               napi_async_context async_context) {
2765
6
  CHECK_ENV(env);
2766
6
  CHECK_ARG(env, async_context);
2767
2768
6
  v8::Isolate* isolate = env->isolate;
2769
  node::async_context* node_async_context =
2770
6
      reinterpret_cast<node::async_context*>(async_context);
2771
6
  node::EmitAsyncDestroy(isolate, *node_async_context);
2772
2773
6
  delete node_async_context;
2774
2775
6
  return napi_clear_last_error(env);
2776
}
2777
2778
23
napi_status napi_make_callback(napi_env env,
2779
                               napi_async_context async_context,
2780
                               napi_value recv,
2781
                               napi_value func,
2782
                               size_t argc,
2783
                               const napi_value* argv,
2784
                               napi_value* result) {
2785

46
  NAPI_PREAMBLE(env);
2786
23
  CHECK_ARG(env, recv);
2787
23
  if (argc > 0) {
2788
4
    CHECK_ARG(env, argv);
2789
  }
2790
2791
23
  v8::Isolate* isolate = env->isolate;
2792
23
  v8::Local<v8::Context> context = isolate->GetCurrentContext();
2793
2794
  v8::Local<v8::Object> v8recv;
2795

92
  CHECK_TO_OBJECT(env, context, v8recv, recv);
2796
2797
  v8::Local<v8::Function> v8func;
2798

69
  CHECK_TO_FUNCTION(env, v8func, func);
2799
2800
  node::async_context* node_async_context =
2801
23
    reinterpret_cast<node::async_context*>(async_context);
2802
23
  if (node_async_context == nullptr) {
2803
    static node::async_context empty_context = { 0, 0 };
2804
17
    node_async_context = &empty_context;
2805
  }
2806
2807
  v8::MaybeLocal<v8::Value> callback_result = node::MakeCallback(
2808
      isolate, v8recv, v8func, argc,
2809
      reinterpret_cast<v8::Local<v8::Value>*>(const_cast<napi_value*>(argv)),
2810
23
      *node_async_context);
2811
23
  CHECK_MAYBE_EMPTY(env, callback_result, napi_generic_failure);
2812
2813
19
  if (result != nullptr) {
2814
    *result = v8impl::JsValueFromV8LocalValue(
2815
6
        callback_result.ToLocalChecked());
2816
  }
2817
2818
19
  return GET_RETURN_STATUS(env);
2819
}
2820
2821
// Methods to support catching exceptions
2822
1182
napi_status napi_is_exception_pending(napi_env env, bool* result) {
2823
  // NAPI_PREAMBLE is not used here: this function must execute when there is a
2824
  // pending exception.
2825
1182
  CHECK_ENV(env);
2826
1182
  CHECK_ARG(env, result);
2827
2828
2364
  *result = !env->last_exception.IsEmpty();
2829
1182
  return napi_clear_last_error(env);
2830
}
2831
2832
1
napi_status napi_get_and_clear_last_exception(napi_env env,
2833
                                              napi_value* result) {
2834
  // NAPI_PREAMBLE is not used here: this function must execute when there is a
2835
  // pending exception.
2836
1
  CHECK_ENV(env);
2837
1
  CHECK_ARG(env, result);
2838
2839
2
  if (env->last_exception.IsEmpty()) {
2840
    return napi_get_undefined(env, result);
2841
  } else {
2842
    *result = v8impl::JsValueFromV8LocalValue(
2843
2
      v8::Local<v8::Value>::New(env->isolate, env->last_exception));
2844
1
    env->last_exception.Reset();
2845
  }
2846
2847
1
  return napi_clear_last_error(env);
2848
}
2849
2850
1
napi_status napi_create_buffer(napi_env env,
2851
                               size_t length,
2852
                               void** data,
2853
                               napi_value* result) {
2854

2
  NAPI_PREAMBLE(env);
2855
1
  CHECK_ARG(env, result);
2856
2857
1
  auto maybe = node::Buffer::New(env->isolate, length);
2858
2859
1
  CHECK_MAYBE_EMPTY(env, maybe, napi_generic_failure);
2860
2861
1
  v8::Local<v8::Object> buffer = maybe.ToLocalChecked();
2862
2863
1
  *result = v8impl::JsValueFromV8LocalValue(buffer);
2864
2865
1
  if (data != nullptr) {
2866
1
    *data = node::Buffer::Data(buffer);
2867
  }
2868
2869
1
  return GET_RETURN_STATUS(env);
2870
}
2871
2872
2
napi_status napi_create_external_buffer(napi_env env,
2873
                                        size_t length,
2874
                                        void* data,
2875
                                        napi_finalize finalize_cb,
2876
                                        void* finalize_hint,
2877
                                        napi_value* result) {
2878

4
  NAPI_PREAMBLE(env);
2879
2
  CHECK_ARG(env, result);
2880
2881
2
  v8::Isolate* isolate = env->isolate;
2882
2883
  // The finalizer object will delete itself after invoking the callback.
2884
  v8impl::Finalizer* finalizer = v8impl::Finalizer::New(
2885
2
    env, finalize_cb, nullptr, finalize_hint);
2886
2887
  auto maybe = node::Buffer::New(isolate,
2888
                                 static_cast<char*>(data),
2889
                                 length,
2890
                                 v8impl::Finalizer::FinalizeBufferCallback,
2891
2
                                 finalizer);
2892
2893
2
  CHECK_MAYBE_EMPTY(env, maybe, napi_generic_failure);
2894
2895
2
  *result = v8impl::JsValueFromV8LocalValue(maybe.ToLocalChecked());
2896
2
  return GET_RETURN_STATUS(env);
2897
  // Tell coverity that 'finalizer' should not be freed when we return
2898
  // as it will be deleted when the buffer to which it is associated
2899
  // is finalized.
2900
  // coverity[leaked_storage]
2901
}
2902
2903
1
napi_status napi_create_buffer_copy(napi_env env,
2904
                                    size_t length,
2905
                                    const void* data,
2906
                                    void** result_data,
2907
                                    napi_value* result) {
2908

2
  NAPI_PREAMBLE(env);
2909
1
  CHECK_ARG(env, result);
2910
2911
  auto maybe = node::Buffer::Copy(env->isolate,
2912
1
    static_cast<const char*>(data), length);
2913
2914
1
  CHECK_MAYBE_EMPTY(env, maybe, napi_generic_failure);
2915
2916
1
  v8::Local<v8::Object> buffer = maybe.ToLocalChecked();
2917
1
  *result = v8impl::JsValueFromV8LocalValue(buffer);
2918
2919
1
  if (result_data != nullptr) {
2920
    *result_data = node::Buffer::Data(buffer);
2921
  }
2922
2923
1
  return GET_RETURN_STATUS(env);
2924
}
2925
2926
1
napi_status napi_is_buffer(napi_env env, napi_value value, bool* result) {
2927
1
  CHECK_ENV(env);
2928
1
  CHECK_ARG(env, value);
2929
1
  CHECK_ARG(env, result);
2930
2931
1
  *result = node::Buffer::HasInstance(v8impl::V8LocalValueFromJsValue(value));
2932
1
  return napi_clear_last_error(env);
2933
}
2934
2935
1
napi_status napi_get_buffer_info(napi_env env,
2936
                                 napi_value value,
2937
                                 void** data,
2938
                                 size_t* length) {
2939
1
  CHECK_ENV(env);
2940
1
  CHECK_ARG(env, value);
2941
2942
1
  v8::Local<v8::Value> buffer = v8impl::V8LocalValueFromJsValue(value);
2943
2944
1
  if (data != nullptr) {
2945
1
    *data = node::Buffer::Data(buffer);
2946
  }
2947
1
  if (length != nullptr) {
2948
1
    *length = node::Buffer::Length(buffer);
2949
  }
2950
2951
1
  return napi_clear_last_error(env);
2952
}
2953
2954
9
napi_status napi_is_arraybuffer(napi_env env, napi_value value, bool* result) {
2955
9
  CHECK_ENV(env);
2956
9
  CHECK_ARG(env, value);
2957
9
  CHECK_ARG(env, result);
2958
2959
9
  v8::Local<v8::Value> val = v8impl::V8LocalValueFromJsValue(value);
2960
9
  *result = val->IsArrayBuffer();
2961
2962
9
  return napi_clear_last_error(env);
2963
}
2964
2965
2
napi_status napi_create_arraybuffer(napi_env env,
2966
                                    size_t byte_length,
2967
                                    void** data,
2968
                                    napi_value* result) {
2969

4
  NAPI_PREAMBLE(env);
2970
2
  CHECK_ARG(env, result);
2971
2972
2
  v8::Isolate* isolate = env->isolate;
2973
  v8::Local<v8::ArrayBuffer> buffer =
2974
2
      v8::ArrayBuffer::New(isolate, byte_length);
2975
2976
  // Optionally return a pointer to the buffer's data, to avoid another call to
2977
  // retrieve it.
2978
2
  if (data != nullptr) {
2979
2
    *data = buffer->GetContents().Data();
2980
  }
2981
2982
2
  *result = v8impl::JsValueFromV8LocalValue(buffer);
2983
2
  return GET_RETURN_STATUS(env);
2984
}
2985
2986
1
napi_status napi_create_external_arraybuffer(napi_env env,
2987
                                             void* external_data,
2988
                                             size_t byte_length,
2989
                                             napi_finalize finalize_cb,
2990
                                             void* finalize_hint,
2991
                                             napi_value* result) {
2992

2
  NAPI_PREAMBLE(env);
2993
1
  CHECK_ARG(env, result);
2994
2995
1
  v8::Isolate* isolate = env->isolate;
2996
  v8::Local<v8::ArrayBuffer> buffer =
2997
1
      v8::ArrayBuffer::New(isolate, external_data, byte_length);
2998
2999
1
  if (finalize_cb != nullptr) {
3000
    // Create a self-deleting weak reference that invokes the finalizer
3001
    // callback.
3002
    v8impl::Reference::New(env,
3003
        buffer,
3004
        0,
3005
        true,
3006
        finalize_cb,
3007
        external_data,
3008
        finalize_hint);
3009
  }
3010
3011
1
  *result = v8impl::JsValueFromV8LocalValue(buffer);
3012
1
  return GET_RETURN_STATUS(env);
3013
}
3014
3015
2
napi_status napi_get_arraybuffer_info(napi_env env,
3016
                                      napi_value arraybuffer,
3017
                                      void** data,
3018
                                      size_t* byte_length) {
3019
2
  CHECK_ENV(env);
3020
2
  CHECK_ARG(env, arraybuffer);
3021
3022
2
  v8::Local<v8::Value> value = v8impl::V8LocalValueFromJsValue(arraybuffer);
3023
2
  RETURN_STATUS_IF_FALSE(env, value->IsArrayBuffer(), napi_invalid_arg);
3024
3025
  v8::ArrayBuffer::Contents contents =
3026
4
      value.As<v8::ArrayBuffer>()->GetContents();
3027
3028
2
  if (data != nullptr) {
3029
2
    *data = contents.Data();
3030
  }
3031
3032
2
  if (byte_length != nullptr) {
3033
2
    *byte_length = contents.ByteLength();
3034
  }
3035
3036
2
  return napi_clear_last_error(env);
3037
}
3038
3039
11
napi_status napi_is_typedarray(napi_env env, napi_value value, bool* result) {
3040
11
  CHECK_ENV(env);
3041
11
  CHECK_ARG(env, value);
3042
11
  CHECK_ARG(env, result);
3043
3044
11
  v8::Local<v8::Value> val = v8impl::V8LocalValueFromJsValue(value);
3045
11
  *result = val->IsTypedArray();
3046
3047
11
  return napi_clear_last_error(env);
3048
}
3049
3050
12
napi_status napi_create_typedarray(napi_env env,
3051
                                   napi_typedarray_type type,
3052
                                   size_t length,
3053
                                   napi_value arraybuffer,
3054
                                   size_t byte_offset,
3055
                                   napi_value* result) {
3056

24
  NAPI_PREAMBLE(env);
3057
12
  CHECK_ARG(env, arraybuffer);
3058
12
  CHECK_ARG(env, result);
3059
3060
12
  v8::Local<v8::Value> value = v8impl::V8LocalValueFromJsValue(arraybuffer);
3061
12
  RETURN_STATUS_IF_FALSE(env, value->IsArrayBuffer(), napi_invalid_arg);
3062
3063
12
  v8::Local<v8::ArrayBuffer> buffer = value.As<v8::ArrayBuffer>();
3064
  v8::Local<v8::TypedArray> typedArray;
3065
3066


12
  switch (type) {
3067
    case napi_int8_array:
3068
4
      typedArray = v8::Int8Array::New(buffer, byte_offset, length);
3069
2
      break;
3070
    case napi_uint8_array:
3071
4
      typedArray = v8::Uint8Array::New(buffer, byte_offset, length);
3072
2
      break;
3073
    case napi_uint8_clamped_array:
3074
2
      typedArray = v8::Uint8ClampedArray::New(buffer, byte_offset, length);
3075
1
      break;
3076
    case napi_int16_array:
3077
2
      typedArray = v8::Int16Array::New(buffer, byte_offset, length);
3078
1
      break;
3079
    case napi_uint16_array:
3080
2
      typedArray = v8::Uint16Array::New(buffer, byte_offset, length);
3081
1
      break;
3082
    case napi_int32_array:
3083
2
      typedArray = v8::Int32Array::New(buffer, byte_offset, length);
3084
1
      break;
3085
    case napi_uint32_array:
3086
2
      typedArray = v8::Uint32Array::New(buffer, byte_offset, length);
3087
1
      break;
3088
    case napi_float32_array:
3089
2
      typedArray = v8::Float32Array::New(buffer, byte_offset, length);
3090
1
      break;
3091
    case napi_float64_array:
3092
4
      typedArray = v8::Float64Array::New(buffer, byte_offset, length);
3093
2
      break;
3094
    default:
3095
      return napi_set_last_error(env, napi_invalid_arg);
3096
  }
3097
3098
12
  *result = v8impl::JsValueFromV8LocalValue(typedArray);
3099
12
  return GET_RETURN_STATUS(env);
3100
}
3101
3102
11
napi_status napi_get_typedarray_info(napi_env env,
3103
                                     napi_value typedarray,
3104
                                     napi_typedarray_type* type,
3105
                                     size_t* length,
3106
                                     void** data,
3107
                                     napi_value* arraybuffer,
3108
                                     size_t* byte_offset) {
3109
11
  CHECK_ENV(env);
3110
11
  CHECK_ARG(env, typedarray);
3111
3112
11
  v8::Local<v8::Value> value = v8impl::V8LocalValueFromJsValue(typedarray);
3113
11
  RETURN_STATUS_IF_FALSE(env, value->IsTypedArray(), napi_invalid_arg);
3114
3115
11
  v8::Local<v8::TypedArray> array = value.As<v8::TypedArray>();
3116
3117
11
  if (type != nullptr) {
3118
11
    if (value->IsInt8Array()) {
3119
1
      *type = napi_int8_array;
3120
10
    } else if (value->IsUint8Array()) {
3121
2
      *type = napi_uint8_array;
3122
8
    } else if (value->IsUint8ClampedArray()) {
3123
1
      *type = napi_uint8_clamped_array;
3124
7
    } else if (value->IsInt16Array()) {
3125
1
      *type = napi_int16_array;
3126
6
    } else if (value->IsUint16Array()) {
3127
1
      *type = napi_uint16_array;
3128
5
    } else if (value->IsInt32Array()) {
3129
1
      *type = napi_int32_array;
3130
4
    } else if (value->IsUint32Array()) {
3131
1
      *type = napi_uint32_array;
3132
3
    } else if (value->IsFloat32Array()) {
3133
1
      *type = napi_float32_array;
3134
2
    } else if (value->IsFloat64Array()) {
3135
2
      *type = napi_float64_array;
3136
    }
3137
  }
3138
3139
11
  if (length != nullptr) {
3140
11
    *length = array->Length();
3141
  }
3142
3143
11
  v8::Local<v8::ArrayBuffer> buffer = array->Buffer();
3144
11
  if (data != nullptr) {
3145
    *data = static_cast<uint8_t*>(buffer->GetContents().Data()) +
3146
            array->ByteOffset();
3147
  }
3148
3149
11
  if (arraybuffer != nullptr) {
3150
11
    *arraybuffer = v8impl::JsValueFromV8LocalValue(buffer);
3151
  }
3152
3153
11
  if (byte_offset != nullptr) {
3154
11
    *byte_offset = array->ByteOffset();
3155
  }
3156
3157
11
  return napi_clear_last_error(env);
3158
}
3159
3160
1
napi_status napi_create_dataview(napi_env env,
3161
                                 size_t byte_length,
3162
                                 napi_value arraybuffer,
3163
                                 size_t byte_offset,
3164
                                 napi_value* result) {
3165

2
  NAPI_PREAMBLE(env);
3166
1
  CHECK_ARG(env, arraybuffer);
3167
1
  CHECK_ARG(env, result);
3168
3169
1
  v8::Local<v8::Value> value = v8impl::V8LocalValueFromJsValue(arraybuffer);
3170
1
  RETURN_STATUS_IF_FALSE(env, value->IsArrayBuffer(), napi_invalid_arg);
3171
3172
1
  v8::Local<v8::ArrayBuffer> buffer = value.As<v8::ArrayBuffer>();
3173
  v8::Local<v8::DataView> DataView = v8::DataView::New(buffer, byte_offset,
3174
1
                                                       byte_length);
3175
3176
1
  *result = v8impl::JsValueFromV8LocalValue(DataView);
3177
1
  return GET_RETURN_STATUS(env);
3178
}
3179
3180
1
napi_status napi_is_dataview(napi_env env, napi_value value, bool* result) {
3181
1
  CHECK_ENV(env);
3182
1
  CHECK_ARG(env, value);
3183
1
  CHECK_ARG(env, result);
3184
3185
1
  v8::Local<v8::Value> val = v8impl::V8LocalValueFromJsValue(value);
3186
1
  *result = val->IsDataView();
3187
3188
1
  return napi_clear_last_error(env);
3189
}
3190
3191
1
napi_status napi_get_dataview_info(napi_env env,
3192
                                   napi_value dataview,
3193
                                   size_t* byte_length,
3194
                                   void** data,
3195
                                   napi_value* arraybuffer,
3196
                                   size_t* byte_offset) {
3197
1
  CHECK_ENV(env);
3198
1
  CHECK_ARG(env, dataview);
3199
3200
1
  v8::Local<v8::Value> value = v8impl::V8LocalValueFromJsValue(dataview);
3201
1
  RETURN_STATUS_IF_FALSE(env, value->IsDataView(), napi_invalid_arg);
3202
3203
1
  v8::Local<v8::DataView> array = value.As<v8::DataView>();
3204
3205
1
  if (byte_length != nullptr) {
3206
1
    *byte_length = array->ByteLength();
3207
  }
3208
3209
1
  v8::Local<v8::ArrayBuffer> buffer = array->Buffer();
3210
1
  if (data != nullptr) {
3211
    *data = static_cast<uint8_t*>(buffer->GetContents().Data()) +
3212
            array->ByteOffset();
3213
  }
3214
3215
1
  if (arraybuffer != nullptr) {
3216
1
    *arraybuffer = v8impl::JsValueFromV8LocalValue(buffer);
3217
  }
3218
3219
1
  if (byte_offset != nullptr) {
3220
1
    *byte_offset = array->ByteOffset();
3221
  }
3222
3223
1
  return napi_clear_last_error(env);
3224
}
3225
3226
1
napi_status napi_get_version(napi_env env, uint32_t* result) {
3227
1
  CHECK_ENV(env);
3228
1
  CHECK_ARG(env, result);
3229
1
  *result = NAPI_VERSION;
3230
1
  return napi_clear_last_error(env);
3231
}
3232
3233
1
napi_status napi_get_node_version(napi_env env,
3234
                                  const napi_node_version** result) {
3235
1
  CHECK_ENV(env);
3236
1
  CHECK_ARG(env, result);
3237
  static const napi_node_version version = {
3238
    NODE_MAJOR_VERSION,
3239
    NODE_MINOR_VERSION,
3240
    NODE_PATCH_VERSION,
3241
    NODE_RELEASE
3242
  };
3243
1
  *result = &version;
3244
1
  return napi_clear_last_error(env);
3245
}
3246
3247
1
napi_status napi_adjust_external_memory(napi_env env,
3248
                                        int64_t change_in_bytes,
3249
                                        int64_t* adjusted_value) {
3250
1
  CHECK_ENV(env);
3251
1
  CHECK_ARG(env, adjusted_value);
3252
3253
  *adjusted_value = env->isolate->AdjustAmountOfExternalAllocatedMemory(
3254
2
      change_in_bytes);
3255
3256
1
  return napi_clear_last_error(env);
3257
}
3258
3259
namespace {
3260
namespace uvimpl {
3261
3262
19
static napi_status ConvertUVErrorCode(int code) {
3263

19
  switch (code) {
3264
  case 0:
3265
18
    return napi_ok;
3266
  case UV_EINVAL:
3267
    return napi_invalid_arg;
3268
  case UV_ECANCELED:
3269
1
    return napi_cancelled;
3270
  }
3271
3272
  return napi_generic_failure;
3273
}
3274
3275
// Wrapper around uv_work_t which calls user-provided callbacks.
3276
class Work : public node::AsyncResource {
3277
 private:
3278
9
  explicit Work(napi_env env,
3279
                v8::Local<v8::Object> async_resource,
3280
                v8::Local<v8::String> async_resource_name,
3281
                napi_async_execute_callback execute,
3282
                napi_async_complete_callback complete = nullptr,
3283
                void* data = nullptr)
3284
    : AsyncResource(env->isolate,
3285
                    async_resource,
3286
18
                    *v8::String::Utf8Value(async_resource_name)),
3287
    _env(env),
3288
    _data(data),
3289
    _execute(execute),
3290
18
    _complete(complete) {
3291
9
    memset(&_request, 0, sizeof(_request));
3292
9
    _request.data = this;
3293
9
  }
3294
3295
8
  ~Work() { }
3296
3297
 public:
3298
9
  static Work* New(napi_env env,
3299
                   v8::Local<v8::Object> async_resource,
3300
                   v8::Local<v8::String> async_resource_name,
3301
                   napi_async_execute_callback execute,
3302
                   napi_async_complete_callback complete,
3303
                   void* data) {
3304
    return new Work(env, async_resource, async_resource_name,
3305
9
                    execute, complete, data);
3306
  }
3307
3308
8
  static void Delete(Work* work) {
3309
8
    delete work;
3310
8
  }
3311
3312
8
  static void ExecuteCallback(uv_work_t* req) {
3313
8
    Work* work = static_cast<Work*>(req->data);
3314
8
    work->_execute(work->_env, work->_data);
3315
8
  }
3316
3317
9
  static void CompleteCallback(uv_work_t* req, int status) {
3318
9
    Work* work = static_cast<Work*>(req->data);
3319
3320
9
    if (work->_complete != nullptr) {
3321
9
      napi_env env = work->_env;
3322
3323
      // Establish a handle scope here so that every callback doesn't have to.
3324
      // Also it is needed for the exception-handling below.
3325
9
      v8::HandleScope scope(env->isolate);
3326
17
      CallbackScope callback_scope(work);
3327
3328
9
      work->_complete(env, ConvertUVErrorCode(status), work->_data);
3329
3330
      // Note: Don't access `work` after this point because it was
3331
      // likely deleted by the complete callback.
3332
3333
      // If there was an unhandled exception in the complete callback,
3334
      // report it as a fatal exception. (There is no JavaScript on the
3335
      // callstack that can possibly handle it.)
3336
18
      if (!env->last_exception.IsEmpty()) {
3337
1
        v8::TryCatch try_catch(env->isolate);
3338
        env->isolate->ThrowException(
3339
2
          v8::Local<v8::Value>::New(env->isolate, env->last_exception));
3340
1
        node::FatalException(env->isolate, try_catch);
3341
8
      }
3342
    }
3343
8
  }
3344
3345
10
  uv_work_t* Request() {
3346
10
    return &_request;
3347
  }
3348
3349
 private:
3350
  napi_env _env;
3351
  void* _data;
3352
  uv_work_t _request;
3353
  napi_async_execute_callback _execute;
3354
  napi_async_complete_callback _complete;
3355
};
3356
3357
}  // end of namespace uvimpl
3358
}  // end of anonymous namespace
3359
3360
#define CALL_UV(env, condition)                                         \
3361
  do {                                                                  \
3362
    int result = (condition);                                           \
3363
    napi_status status = uvimpl::ConvertUVErrorCode(result);            \
3364
    if (status != napi_ok) {                                            \
3365
      return napi_set_last_error(env, status, result);                  \
3366
    }                                                                   \
3367
  } while (0)
3368
3369
9
napi_status napi_create_async_work(napi_env env,
3370
                                   napi_value async_resource,
3371
                                   napi_value async_resource_name,
3372
                                   napi_async_execute_callback execute,
3373
                                   napi_async_complete_callback complete,
3374
                                   void* data,
3375
                                   napi_async_work* result) {
3376
9
  CHECK_ENV(env);
3377
9
  CHECK_ARG(env, execute);
3378
9
  CHECK_ARG(env, result);
3379
3380
9
  v8::Local<v8::Context> context = env->isolate->GetCurrentContext();
3381
3382
  v8::Local<v8::Object> resource;
3383
9
  if (async_resource != nullptr) {
3384

12
    CHECK_TO_OBJECT(env, context, resource, async_resource);
3385
  } else {
3386
6
    resource = v8::Object::New(env->isolate);
3387
  }
3388
3389
  v8::Local<v8::String> resource_name;
3390

36
  CHECK_TO_STRING(env, context, resource_name, async_resource_name);
3391
3392
  uvimpl::Work* work =
3393
      uvimpl::Work::New(env, resource, resource_name,
3394
9
                        execute, complete, data);
3395
3396
9
  *result = reinterpret_cast<napi_async_work>(work);
3397
3398
9
  return napi_clear_last_error(env);
3399
}
3400
3401
8
napi_status napi_delete_async_work(napi_env env, napi_async_work work) {
3402
8
  CHECK_ENV(env);
3403
8
  CHECK_ARG(env, work);
3404
3405
8
  uvimpl::Work::Delete(reinterpret_cast<uvimpl::Work*>(work));
3406
3407
8
  return napi_clear_last_error(env);
3408
}
3409
3410
10
napi_status napi_get_uv_event_loop(napi_env env, uv_loop_t** loop) {
3411
10
  CHECK_ENV(env);
3412
10
  CHECK_ARG(env, loop);
3413
10
  *loop = env->loop;
3414
10
  return napi_clear_last_error(env);
3415
}
3416
3417
9
napi_status napi_queue_async_work(napi_env env, napi_async_work work) {
3418
9
  CHECK_ENV(env);
3419
9
  CHECK_ARG(env, work);
3420
3421
  napi_status status;
3422
9
  uv_loop_t* event_loop = nullptr;
3423
9
  status = napi_get_uv_event_loop(env, &event_loop);
3424
9
  if (status != napi_ok)
3425
    return napi_set_last_error(env, status);
3426
3427
9
  uvimpl::Work* w = reinterpret_cast<uvimpl::Work*>(work);
3428
3429
9
  CALL_UV(env, uv_queue_work(event_loop,
3430
                             w->Request(),
3431
                             uvimpl::Work::ExecuteCallback,
3432
                             uvimpl::Work::CompleteCallback));
3433
3434
9
  return napi_clear_last_error(env);
3435