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: 1419 1486 95.5 %
Date: 2017-11-19 Branches: 771 1356 56.9 %

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  1
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
42
  explicit napi_env__(v8::Isolate* _isolate): isolate(_isolate),
32
210
      last_error() {}
33
  ~napi_env__() {
34
    last_exception.Reset();
35
    wrap_template.Reset();
36
    function_data_template.Reset();
37
    accessor_data_template.Reset();
38
  }
39
  v8::Isolate* isolate;
40
  v8::Persistent<v8::Value> last_exception;
41
  v8::Persistent<v8::ObjectTemplate> wrap_template;
42
  v8::Persistent<v8::ObjectTemplate> function_data_template;
43
  v8::Persistent<v8::ObjectTemplate> accessor_data_template;
44
  napi_extended_error_info last_error;
45
  int open_handle_scopes = 0;
46
};
47
48
#define ENV_OBJECT_TEMPLATE(env, prefix, destination, field_count) \
49
  do {                                                             \
50
    if ((env)->prefix ## _template.IsEmpty()) {                    \
51
      (destination) = v8::ObjectTemplate::New(isolate);            \
52
      (destination)->SetInternalFieldCount((field_count));         \
53
      (env)->prefix ## _template.Reset(isolate, (destination));    \
54
    } else {                                                       \
55
      (destination) = v8::Local<v8::ObjectTemplate>::New(          \
56
          isolate, env->prefix ## _template);                      \
57
    }                                                              \
58
  } while (0)
59
60
61
#define RETURN_STATUS_IF_FALSE(env, condition, status)                  \
62
  do {                                                                  \
63
    if (!(condition)) {                                                 \
64
      return napi_set_last_error((env), (status));                      \
65
    }                                                                   \
66
  } while (0)
67
68
#define CHECK_ENV(env)        \
69
  if ((env) == nullptr) {     \
70
    return napi_invalid_arg;  \
71
  }
72
73
#define CHECK_ARG(env, arg) \
74
  RETURN_STATUS_IF_FALSE((env), ((arg) != nullptr), napi_invalid_arg)
75
76
#define CHECK_MAYBE_EMPTY(env, maybe, status) \
77
  RETURN_STATUS_IF_FALSE((env), !((maybe).IsEmpty()), (status))
78
79
#define CHECK_MAYBE_NOTHING(env, maybe, status) \
80
  RETURN_STATUS_IF_FALSE((env), !((maybe).IsNothing()), (status))
81
82
// NAPI_PREAMBLE is not wrapped in do..while: try_catch must have function scope
83
#define NAPI_PREAMBLE(env)                                       \
84
  CHECK_ENV((env));                                              \
85
  RETURN_STATUS_IF_FALSE((env), (env)->last_exception.IsEmpty(), \
86
                         napi_pending_exception);                \
87
  napi_clear_last_error((env));                                  \
88
  v8impl::TryCatch try_catch((env))
89
90
#define CHECK_TO_TYPE(env, type, context, result, src, status)                \
91
  do {                                                                        \
92
    CHECK_ARG((env), (src));                                                  \
93
    auto maybe = v8impl::V8LocalValueFromJsValue((src))->To##type((context)); \
94
    CHECK_MAYBE_EMPTY((env), maybe, (status));                                \
95
    (result) = maybe.ToLocalChecked();                                        \
96
  } while (0)
97
98
#define CHECK_TO_FUNCTION(env, result, src)                                 \
99
  do {                                                                      \
100
    CHECK_ARG((env), (src));                                                \
101
    v8::Local<v8::Value> v8value = v8impl::V8LocalValueFromJsValue((src));  \
102
    RETURN_STATUS_IF_FALSE((env), v8value->IsFunction(), napi_invalid_arg); \
103
    (result) = v8value.As<v8::Function>();                                  \
104
  } while (0)
105
106
#define CHECK_TO_OBJECT(env, context, result, src) \
107
  CHECK_TO_TYPE((env), Object, (context), (result), (src), napi_object_expected)
108
109
#define CHECK_TO_STRING(env, context, result, src) \
110
  CHECK_TO_TYPE((env), String, (context), (result), (src), napi_string_expected)
111
112
#define CHECK_TO_NUMBER(env, context, result, src) \
113
  CHECK_TO_TYPE((env), Number, (context), (result), (src), napi_number_expected)
114
115
#define CHECK_TO_BOOL(env, context, result, src)            \
116
  CHECK_TO_TYPE((env), Boolean, (context), (result), (src), \
117
    napi_boolean_expected)
118
119
// n-api defines NAPI_AUTO_LENGHTH as the indicator that a string
120
// is null terminated. For V8 the equivalent is -1. The assert
121
// validates that our cast of NAPI_AUTO_LENGTH results in -1 as
122
// needed by V8.
123
#define CHECK_NEW_FROM_UTF8_LEN(env, result, str, len)                   \
124
  do {                                                                   \
125
    static_assert(static_cast<int>(NAPI_AUTO_LENGTH) == -1,              \
126
                  "Casting NAPI_AUTO_LENGTH to int must result in -1");  \
127
    RETURN_STATUS_IF_FALSE((env),                                        \
128
        (len == NAPI_AUTO_LENGTH) || len <= INT_MAX,                     \
129
        napi_invalid_arg);                                               \
130
    auto str_maybe = v8::String::NewFromUtf8(                            \
131
        (env)->isolate, (str), v8::NewStringType::kInternalized,         \
132
        static_cast<int>(len));                                          \
133
    CHECK_MAYBE_EMPTY((env), str_maybe, napi_generic_failure);           \
134
    (result) = str_maybe.ToLocalChecked();                               \
135
  } while (0)
136
137
#define CHECK_NEW_FROM_UTF8(env, result, str) \
138
  CHECK_NEW_FROM_UTF8_LEN((env), (result), (str), NAPI_AUTO_LENGTH)
139
140
#define GET_RETURN_STATUS(env)      \
141
  (!try_catch.HasCaught() ? napi_ok \
142
                         : napi_set_last_error((env), napi_pending_exception))
143
144
namespace {
145
namespace v8impl {
146
147
// convert from n-api property attributes to v8::PropertyAttribute
148
207
static inline v8::PropertyAttribute V8PropertyAttributesFromDescriptor(
149
    const napi_property_descriptor* descriptor) {
150
207
  unsigned int attribute_flags = v8::PropertyAttribute::None;
151
152

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

2814
    if (result != nullptr) {
516
1580
      this->SetReturnValue(result);
517
    }
518
519

2814
    CHECK_EQ(env->open_handle_scopes, open_handle_scopes);
520
521

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

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

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

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

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

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

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

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

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

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

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

1
    if (status != napi_ok) return status;
1108
  }
1109
1110
10
  return GET_RETURN_STATUS(env);
1111
}
1112
1113
4
napi_status napi_get_property_names(napi_env env,
1114
                                    napi_value object,
1115
                                    napi_value* result) {
1116

8
  NAPI_PREAMBLE(env);
1117
4
  CHECK_ARG(env, result);
1118
1119
4
  v8::Isolate* isolate = env->isolate;
1120
4
  v8::Local<v8::Context> context = isolate->GetCurrentContext();
1121
  v8::Local<v8::Object> obj;
1122

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

30
  NAPI_PREAMBLE(env);
1138
15
  CHECK_ARG(env, key);
1139
15
  CHECK_ARG(env, value);
1140
1141
15
  v8::Isolate* isolate = env->isolate;
1142
15
  v8::Local<v8::Context> context = isolate->GetCurrentContext();
1143
  v8::Local<v8::Object> obj;
1144
1145

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

16
  NAPI_PREAMBLE(env);
1161
8
  CHECK_ARG(env, result);
1162
8
  CHECK_ARG(env, key);
1163
1164
8
  v8::Isolate* isolate = env->isolate;
1165
8
  v8::Local<v8::Context> context = isolate->GetCurrentContext();
1166
  v8::Local<v8::Object> obj;
1167
1168

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

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

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

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

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

30
  NAPI_PREAMBLE(env);
1230
15
  CHECK_ARG(env, key);
1231
1232
15
  v8::Isolate* isolate = env->isolate;
1233
15
  v8::Local<v8::Context> context = isolate->GetCurrentContext();
1234
  v8::Local<v8::Object> obj;
1235
1236

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

40
  NAPI_PREAMBLE(env);
1251
20
  CHECK_ARG(env, value);
1252
1253
20
  v8::Isolate* isolate = env->isolate;
1254
20
  v8::Local<v8::Context> context = isolate->GetCurrentContext();
1255
  v8::Local<v8::Object> obj;
1256
1257

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

6
  NAPI_PREAMBLE(env);
1275
3
  CHECK_ARG(env, result);
1276
1277
3
  v8::Isolate* isolate = env->isolate;
1278
3
  v8::Local<v8::Context> context = isolate->GetCurrentContext();
1279
  v8::Local<v8::Object> obj;
1280
1281

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

22
  NAPI_PREAMBLE(env);
1325
11
  CHECK_ARG(env, value);
1326
1327
11
  v8::Isolate* isolate = env->isolate;
1328
11
  v8::Local<v8::Context> context = isolate->GetCurrentContext();
1329
  v8::Local<v8::Object> obj;
1330
1331

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

4
  NAPI_PREAMBLE(env);
1346
2
  CHECK_ARG(env, result);
1347
1348
2
  v8::Isolate* isolate = env->isolate;
1349
2
  v8::Local<v8::Context> context = isolate->GetCurrentContext();
1350
  v8::Local<v8::Object> obj;
1351
1352

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

54
  NAPI_PREAMBLE(env);
1367
27
  CHECK_ARG(env, result);
1368
1369
27
  v8::Isolate* isolate = env->isolate;
1370
27
  v8::Local<v8::Context> context = isolate->GetCurrentContext();
1371
  v8::Local<v8::Object> obj;
1372
1373

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

2
  NAPI_PREAMBLE(env);
1388
1389
1
  v8::Isolate* isolate = env->isolate;
1390
1
  v8::Local<v8::Context> context = isolate->GetCurrentContext();
1391
  v8::Local<v8::Object> obj;
1392
1393

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

64
  NAPI_PREAMBLE(env);
1408
32
  if (property_count > 0) {
1409
32
    CHECK_ARG(env, properties);
1410
  }
1411
1412
32
  v8::Isolate* isolate = env->isolate;
1413
32
  v8::Local<v8::Context> context = isolate->GetCurrentContext();
1414
1415
  v8::Local<v8::Object> obj;
1416

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

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

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

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

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

8
  NAPI_PREAMBLE(env);
1528
4
  CHECK_ARG(env, result);
1529
1530
4
  v8::Isolate* isolate = env->isolate;
1531
4
  v8::Local<v8::Context> context = isolate->GetCurrentContext();
1532
1533
  v8::Local<v8::Object> obj;
1534

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

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

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

42
  NAPI_PREAMBLE(env);
1939
21
  CHECK_ARG(env, recv);
1940
21
  if (argc > 0) {
1941
6
    CHECK_ARG(env, argv);
1942
  }
1943
1944
21
  v8::Isolate* isolate = env->isolate;
1945
21
  v8::Local<v8::Context> context = isolate->GetCurrentContext();
1946
1947
21
  v8::Local<v8::Value> v8recv = v8impl::V8LocalValueFromJsValue(recv);
1948
1949
  v8::Local<v8::Function> v8func;
1950

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

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

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

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

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

30
  NAPI_PREAMBLE(env);
2288
15
  CHECK_ARG(env, value);
2289
15
  CHECK_ARG(env, result);
2290
2291
15
  v8::Isolate* isolate = env->isolate;
2292
15
  v8::Local<v8::Context> context = isolate->GetCurrentContext();
2293
  v8::Local<v8::Object> obj;
2294

60
  CHECK_TO_OBJECT(env, context, obj, value);
2295
2296
15
  *result = v8impl::JsValueFromV8LocalValue(obj);
2297
15
  return GET_RETURN_STATUS(env);
2298
}
2299
2300
14
napi_status napi_coerce_to_bool(napi_env env,
2301
                                napi_value value,
2302
                                napi_value* result) {
2303

28
  NAPI_PREAMBLE(env);
2304
14
  CHECK_ARG(env, value);
2305
14
  CHECK_ARG(env, result);
2306
2307
14
  v8::Isolate* isolate = env->isolate;
2308
14
  v8::Local<v8::Context> context = isolate->GetCurrentContext();
2309
  v8::Local<v8::Boolean> b;
2310
2311

56
  CHECK_TO_BOOL(env, context, b, value);
2312
2313
14
  *result = v8impl::JsValueFromV8LocalValue(b);
2314
14
  return GET_RETURN_STATUS(env);
2315
}
2316
2317
15
napi_status napi_coerce_to_number(napi_env env,
2318
                                  napi_value value,
2319
                                  napi_value* result) {
2320

30
  NAPI_PREAMBLE(env);
2321
15
  CHECK_ARG(env, value);
2322
15
  CHECK_ARG(env, result);
2323
2324
15
  v8::Isolate* isolate = env->isolate;
2325
15
  v8::Local<v8::Context> context = isolate->GetCurrentContext();
2326
  v8::Local<v8::Number> num;
2327
2328

60
  CHECK_TO_NUMBER(env, context, num, value);
2329
2330
14
  *result = v8impl::JsValueFromV8LocalValue(num);
2331
14
  return GET_RETURN_STATUS(env);
2332
}
2333
2334
14
napi_status napi_coerce_to_string(napi_env env,
2335
                                  napi_value value,
2336
                                  napi_value* result) {
2337

28
  NAPI_PREAMBLE(env);
2338
14
  CHECK_ARG(env, value);
2339
14
  CHECK_ARG(env, result);
2340
2341
14
  v8::Isolate* isolate = env->isolate;
2342
14
  v8::Local<v8::Context> context = isolate->GetCurrentContext();
2343
  v8::Local<v8::String> str;
2344
2345

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

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

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

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

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

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

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

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

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

24
    CHECK_TO_OBJECT(env, context, v8_resource, async_resource);
2742
  } else {
2743
    v8_resource = v8::Object::New(isolate);
2744
  }
2745
2746
  v8::Local<v8::String> v8_resource_name;
2747

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

46
  NAPI_PREAMBLE(env);
2780
23
  CHECK_ARG(env, recv);
2781
23
  if (argc > 0) {
2782
4
    CHECK_ARG(env, argv);
2783
  }
2784
2785
23
  v8::Isolate* isolate = env->isolate;
2786
23
  v8::Local<v8::Context> context = isolate->GetCurrentContext();
2787
2788
  v8::Local<v8::Object> v8recv;
2789

92
  CHECK_TO_OBJECT(env, context, v8recv, recv);
2790
2791
  v8::Local<v8::Function> v8func;
2792

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

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

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

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

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

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

24
  NAPI_PREAMBLE(env);
3051
12
  CHECK_ARG(env, arraybuffer);
3052
12
  CHECK_ARG(env, result);
3053
3054
12
  v8::Local<v8::Value> value = v8impl::V8LocalValueFromJsValue(arraybuffer);
3055
12
  RETURN_STATUS_IF_FALSE(env, value->IsArrayBuffer(), napi_invalid_arg);
3056
3057
12
  v8::Local<v8::ArrayBuffer> buffer = value.As<v8::ArrayBuffer>();
3058
  v8::Local<v8::TypedArray> typedArray;
3059
3060


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

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

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

12
    CHECK_TO_OBJECT(env, context, resource, async_resource);
3379
  } else {
3380
6
    resource = v8::Object::New(env->isolate);
3381
  }
3382
3383
  v8::Local<v8::String> resource_name;
3384

36
  CHECK_TO_STRING(env, context, resource_name, async_resource_name);
3385
3386
  uvimpl::Work* work =
3387
      uvimpl::Work::New(env, resource, resource_name,
3388
9
                        execute, complete, data);
3389
3390
9
  *result = reinterpret_cast<napi_async_work>(work);
3391
3392
9
  return napi_clear_last_error(env);
3393
}
3394
3395
8
napi_status napi_delete_async_work(napi_env env, napi_async_work work) {
3396
8
  CHECK_ENV(env);
3397
8
  CHECK_ARG(env, work);
3398
3399
8
  uvimpl::Work::Delete(reinterpret_cast<uvimpl::Work*>(work));
3400
3401
8
  return napi_clear_last_error(env);
3402
}
3403
3404
9
napi_status napi_queue_async_work(napi_env env, napi_async_work work) {
3405
9
  CHECK_ENV(env);
3406
9
  CHECK_ARG(env, work);
3407
3408
  // Consider: Encapsulate the uv_loop_t into an opaque pointer parameter.
3409
  // Currently the environment event loop is the same as the UV default loop.
3410
  // Someday (if node ever supports multiple isolates), it may be better to get
3411
  // the loop from node::Environment::GetCurrent(env->isolate)->event_loop();
3412
9
  uv_loop_t* event_loop = uv_default_loop();
3413
3414
9
  uvimpl::Work* w = reinterpret_cast<uvimpl::Work*>(work);
3415
3416
9
  CALL_UV(env, uv_queue_work(event_loop,
3417
                             w->Request(),
3418
                             uvimpl::Work::ExecuteCallback,
3419
                             uvimpl::Work::CompleteCallback));
3420
3421
9
  return napi_clear_last_error(env);
3422
}
3423
3424
1
napi_status napi_cancel_async_work(napi_env env, napi_async_work work) {
3425
1
  CHECK_ENV(env);
3426
1
  CHECK_ARG(env, work);
3427
3428
1
  uvimpl::Work* w = reinterpret_cast<uvimpl::Work*>(work);
3429
3430
1
  CALL_UV(env, uv_cancel(reinterpret_cast<uv_req_t*>(w->Request())));
3431
3432
1
  return napi_clear_last_error(env);
3433
}
3434
3435