GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: node_api.cc Lines: 529 573 92.3 %
Date: 2022-08-12 04:19:25 Branches: 257 410 62.7 %

Line Branch Exec Source
1
#include "async_wrap-inl.h"
2
#include "env-inl.h"
3
#define NAPI_EXPERIMENTAL
4
#include "js_native_api_v8.h"
5
#include "memory_tracker-inl.h"
6
#include "node_api.h"
7
#include "node_api_internals.h"
8
#include "node_binding.h"
9
#include "node_buffer.h"
10
#include "node_errors.h"
11
#include "node_internals.h"
12
#include "node_process.h"
13
#include "node_url.h"
14
#include "threadpoolwork-inl.h"
15
#include "tracing/traced_value.h"
16
#include "util-inl.h"
17
18
#include <atomic>
19
#include <memory>
20
21
96
node_napi_env__::node_napi_env__(v8::Local<v8::Context> context,
22
96
                                 const std::string& module_filename)
23
96
    : napi_env__(context), filename(module_filename) {
24
96
  CHECK_NOT_NULL(node_env());
25
96
}
26
27
376
node_napi_env__::~node_napi_env__() {
28
188
  destructing = true;
29
188
  FinalizeAll();
30
376
}
31
32
119803
bool node_napi_env__::can_call_into_js() const {
33
119803
  return node_env()->can_call_into_js();
34
}
35
36
v8::Maybe<bool> node_napi_env__::mark_arraybuffer_as_untransferable(
37
    v8::Local<v8::ArrayBuffer> ab) const {
38
  return ab->SetPrivate(context(),
39
                        node_env()->untransferable_object_private_symbol(),
40
                        v8::True(isolate));
41
}
42
43
1576
void node_napi_env__::CallFinalizer(napi_finalize cb, void* data, void* hint) {
44
1576
  CallFinalizer<true>(cb, data, hint);
45
1576
}
46
47
template <bool enforceUncaughtExceptionPolicy>
48
1576
void node_napi_env__::CallFinalizer(napi_finalize cb, void* data, void* hint) {
49
1576
  if (destructing) {
50
    // we can not defer finalizers when the environment is being destructed.
51
1098
    v8::HandleScope handle_scope(isolate);
52
549
    v8::Context::Scope context_scope(context());
53
549
    CallbackIntoModule<enforceUncaughtExceptionPolicy>(
54
549
        [&](napi_env env) { cb(env, data, hint); });
55
549
    return;
56
  }
57
  // we need to keep the env live until the finalizer has been run
58
  // EnvRefHolder provides an exception safe wrapper to Ref and then
59
  // Unref once the lambda is freed
60
1027
  EnvRefHolder liveEnv(static_cast<napi_env>(this));
61
2054
  node_env()->SetImmediate(
62
1027
      [=, liveEnv = std::move(liveEnv)](node::Environment* node_env) {
63
1027
        node_napi_env__* env = static_cast<node_napi_env__*>(liveEnv.env());
64
2053
        v8::HandleScope handle_scope(env->isolate);
65
1027
        v8::Context::Scope context_scope(env->context());
66
1027
        env->CallbackIntoModule<enforceUncaughtExceptionPolicy>(
67
1027
            [&](napi_env env) { cb(env, data, hint); });
68
      });
69
}
70
71
8
void node_napi_env__::trigger_fatal_exception(v8::Local<v8::Value> local_err) {
72
  v8::Local<v8::Message> local_msg =
73
8
      v8::Exception::CreateMessage(isolate, local_err);
74
8
  node::errors::TriggerUncaughtException(isolate, local_err, local_msg);
75
6
}
76
77
// option enforceUncaughtExceptionPolicy is added for not breaking existing
78
// running n-api add-ons, and should be deprecated in the next major Node.js
79
// release.
80
template <bool enforceUncaughtExceptionPolicy, typename T>
81
234222
void node_napi_env__::CallbackIntoModule(T&& call) {
82
234231
  CallIntoModule(call, [](napi_env env_, v8::Local<v8::Value> local_err) {
83
9
    node_napi_env__* env = static_cast<node_napi_env__*>(env_);
84
9
    node::Environment* node_env = env->node_env();
85




9
    if (!node_env->options()->force_node_api_uncaught_exceptions_policy &&
86
        !enforceUncaughtExceptionPolicy) {
87
2
      ProcessEmitDeprecationWarning(
88
          node_env,
89
          "Uncaught N-API callback exception detected, please run node "
90
          "with option --force-node-api-uncaught-exceptions-policy=true"
91
          "to handle those exceptions properly.",
92
          "DEP0XXX");
93
2
      return;
94
    }
95
    // If there was an unhandled exception in the complete callback,
96
    // report it as a fatal exception. (There is no JavaScript on the
97
    // callstack that can possibly handle it.)
98
7
    env->trigger_fatal_exception(local_err);
99
  });
100
234218
}
101
102
namespace v8impl {
103
104
namespace {
105
106
class BufferFinalizer : private Finalizer {
107
 public:
108
  // node::Buffer::FreeCallback
109
14
  static void FinalizeBufferCallback(char* data, void* hint) {
110
    std::unique_ptr<BufferFinalizer, Deleter> finalizer{
111
14
        static_cast<BufferFinalizer*>(hint)};
112
14
    finalizer->_finalize_data = data;
113
114
14
    if (finalizer->_finalize_callback == nullptr) return;
115
26
    finalizer->_env->CallFinalizer(finalizer->_finalize_callback,
116
13
                                   finalizer->_finalize_data,
117
13
                                   finalizer->_finalize_hint);
118
  }
119
120
  struct Deleter {
121
14
    void operator()(BufferFinalizer* finalizer) {
122
14
      Finalizer::Delete(finalizer);
123
14
    }
124
  };
125
};
126
127
96
static inline napi_env NewEnv(v8::Local<v8::Context> context,
128
                              const std::string& module_filename) {
129
  node_napi_env result;
130
131
96
  result = new node_napi_env__(context, module_filename);
132
  // TODO(addaleax): There was previously code that tried to delete the
133
  // napi_env when its v8::Context was garbage collected;
134
  // However, as long as N-API addons using this napi_env are in place,
135
  // the Context needs to be accessible and alive.
136
  // Ideally, we'd want an on-addon-unload hook that takes care of this
137
  // once all N-API addons using this napi_env are unloaded.
138
  // For now, a per-Environment cleanup hook is the best we can do.
139
96
  result->node_env()->AddCleanupHook(
140
94
      [](void* arg) { static_cast<napi_env>(arg)->Unref(); },
141
      static_cast<void*>(result));
142
143
96
  return result;
144
}
145
146
class ThreadSafeFunction : public node::AsyncResource {
147
 public:
148
20
  ThreadSafeFunction(v8::Local<v8::Function> func,
149
                     v8::Local<v8::Object> resource,
150
                     v8::Local<v8::String> name,
151
                     size_t thread_count_,
152
                     void* context_,
153
                     size_t max_queue_size_,
154
                     node_napi_env env_,
155
                     void* finalize_data_,
156
                     napi_finalize finalize_cb_,
157
                     napi_threadsafe_function_call_js call_js_cb_)
158
40
      : AsyncResource(env_->isolate,
159
                      resource,
160
40
                      *v8::String::Utf8Value(env_->isolate, name)),
161
        thread_count(thread_count_),
162
        is_closing(false),
163
        dispatch_state(kDispatchIdle),
164
        context(context_),
165
        max_queue_size(max_queue_size_),
166
        env(env_),
167
        finalize_data(finalize_data_),
168
        finalize_cb(finalize_cb_),
169
20
        call_js_cb(call_js_cb_ == nullptr ? CallJs : call_js_cb_),
170

60
        handles_closing(false) {
171
20
    ref.Reset(env->isolate, func);
172
20
    node::AddEnvironmentCleanupHook(env->isolate, Cleanup, this);
173
20
    env->Ref();
174
20
  }
175
176
120
  ~ThreadSafeFunction() override {
177
40
    node::RemoveEnvironmentCleanupHook(env->isolate, Cleanup, this);
178
40
    env->Unref();
179
80
  }
180
181
  // These methods can be called from any thread.
182
183
3352457
  napi_status Push(void* data, napi_threadsafe_function_call_mode mode) {
184
6704914
    node::Mutex::ScopedLock lock(this->mutex);
185
186

6688292
    while (queue.size() >= max_queue_size && max_queue_size > 0 &&
187
3286640
           !is_closing) {
188
3286637
      if (mode == napi_tsfn_nonblocking) {
189
3237442
        return napi_queue_full;
190
      }
191
49195
      cond->Wait(lock);
192
    }
193
194
115015
    if (is_closing) {
195
5
      if (thread_count == 0) {
196
        return napi_invalid_arg;
197
      } else {
198
5
        thread_count--;
199
5
        return napi_closing;
200
      }
201
    } else {
202
115010
      queue.push(data);
203
115010
      Send();
204
115010
      return napi_ok;
205
    }
206
  }
207
208
4
  napi_status Acquire() {
209
8
    node::Mutex::ScopedLock lock(this->mutex);
210
211
4
    if (is_closing) {
212
      return napi_closing;
213
    }
214
215
4
    thread_count++;
216
217
4
    return napi_ok;
218
  }
219
220
35
  napi_status Release(napi_threadsafe_function_release_mode mode) {
221
70
    node::Mutex::ScopedLock lock(this->mutex);
222
223
35
    if (thread_count == 0) {
224
      return napi_invalid_arg;
225
    }
226
227
35
    thread_count--;
228
229

35
    if (thread_count == 0 || mode == napi_tsfn_abort) {
230
18
      if (!is_closing) {
231
18
        is_closing = (mode == napi_tsfn_abort);
232

18
        if (is_closing && max_queue_size > 0) {
233
2
          cond->Signal(lock);
234
        }
235
18
        Send();
236
      }
237
    }
238
239
35
    return napi_ok;
240
  }
241
242
27
  void EmptyQueueAndDelete() {
243
27
    for (; !queue.empty(); queue.pop()) {
244
7
      call_js_cb(nullptr, nullptr, context, queue.front());
245
    }
246
20
    delete this;
247
20
  }
248
249
  // These methods must only be called from the loop thread.
250
251
20
  napi_status Init() {
252
20
    ThreadSafeFunction* ts_fn = this;
253
20
    uv_loop_t* loop = env->node_env()->event_loop();
254
255
20
    if (uv_async_init(loop, &async, AsyncCb) == 0) {
256
20
      if (max_queue_size > 0) {
257
12
        cond = std::make_unique<node::ConditionVariable>();
258
      }
259

20
      if (max_queue_size == 0 || cond) {
260
20
        return napi_ok;
261
      }
262
263
      env->node_env()->CloseHandle(
264
          reinterpret_cast<uv_handle_t*>(&async),
265
          [](uv_handle_t* handle) -> void {
266
            ThreadSafeFunction* ts_fn =
267
                node::ContainerOf(&ThreadSafeFunction::async,
268
                                  reinterpret_cast<uv_async_t*>(handle));
269
            delete ts_fn;
270
          });
271
272
      // Prevent the thread-safe function from being deleted here, because
273
      // the callback above will delete it.
274
      ts_fn = nullptr;
275
    }
276
277
    delete ts_fn;
278
279
    return napi_generic_failure;
280
  }
281
282
2
  napi_status Unref() {
283
2
    uv_unref(reinterpret_cast<uv_handle_t*>(&async));
284
285
2
    return napi_ok;
286
  }
287
288
  napi_status Ref() {
289
    uv_ref(reinterpret_cast<uv_handle_t*>(&async));
290
291
    return napi_ok;
292
  }
293
294
16
  inline void* Context() { return context; }
295
296
 protected:
297
171
  void Dispatch() {
298
171
    bool has_more = true;
299
300
    // Limit maximum synchronous iteration count to prevent event loop
301
    // starvation. See `src/node_messaging.cc` for an inspiration.
302
171
    unsigned int iterations_left = kMaxIterationCount;
303

115184
    while (has_more && --iterations_left != 0) {
304
115013
      dispatch_state = kDispatchRunning;
305
115013
      has_more = DispatchOne();
306
307
      // Send() was called while we were executing the JS function
308
115013
      if (dispatch_state.exchange(kDispatchIdle) != kDispatchRunning) {
309
87041
        has_more = true;
310
      }
311
    }
312
313
171
    if (has_more) {
314
105
      Send();
315
    }
316
171
  }
317
318
115013
  bool DispatchOne() {
319
115013
    void* data = nullptr;
320
115013
    bool popped_value = false;
321
115013
    bool has_more = false;
322
323
    {
324
230026
      node::Mutex::ScopedLock lock(this->mutex);
325
115013
      if (is_closing) {
326
3
        CloseHandlesAndMaybeDelete();
327
      } else {
328
115010
        size_t size = queue.size();
329
115010
        if (size > 0) {
330
115003
          data = queue.front();
331
115003
          queue.pop();
332
115003
          popped_value = true;
333

115003
          if (size == max_queue_size && max_queue_size > 0) {
334
87712
            cond->Signal(lock);
335
          }
336
115003
          size--;
337
        }
338
339
115010
        if (size == 0) {
340
322
          if (thread_count == 0) {
341
15
            is_closing = true;
342
15
            if (max_queue_size > 0) {
343
9
              cond->Signal(lock);
344
            }
345
15
            CloseHandlesAndMaybeDelete();
346
          }
347
        } else {
348
114688
          has_more = true;
349
        }
350
      }
351
    }
352
353
115013
    if (popped_value) {
354
230006
      v8::HandleScope scope(env->isolate);
355
115003
      CallbackScope cb_scope(this);
356
115003
      napi_value js_callback = nullptr;
357
115003
      if (!ref.IsEmpty()) {
358
        v8::Local<v8::Function> js_cb =
359
210002
            v8::Local<v8::Function>::New(env->isolate, ref);
360
105001
        js_callback = v8impl::JsValueFromV8LocalValue(js_cb);
361
      }
362
115003
      env->CallbackIntoModule<false>(
363
115003
          [&](napi_env env) { call_js_cb(env, js_callback, context, data); });
364
    }
365
366
115013
    return has_more;
367
  }
368
369
20
  void Finalize() {
370
40
    v8::HandleScope scope(env->isolate);
371
20
    if (finalize_cb) {
372
20
      CallbackScope cb_scope(this);
373
      // Do not use CallFinalizer since it will defer the invocation, which
374
      // would lead to accessing a deleted ThreadSafeFunction.
375
20
      env->CallbackIntoModule<false>(
376
20
          [&](napi_env env) { finalize_cb(env, finalize_data, context); });
377
    }
378
20
    EmptyQueueAndDelete();
379
20
  }
380
381
20
  void CloseHandlesAndMaybeDelete(bool set_closing = false) {
382
20
    v8::HandleScope scope(env->isolate);
383
20
    if (set_closing) {
384
4
      node::Mutex::ScopedLock lock(this->mutex);
385
2
      is_closing = true;
386
2
      if (max_queue_size > 0) {
387
1
        cond->Signal(lock);
388
      }
389
    }
390
20
    if (handles_closing) {
391
      return;
392
    }
393
20
    handles_closing = true;
394
20
    env->node_env()->CloseHandle(
395
20
        reinterpret_cast<uv_handle_t*>(&async),
396
20
        [](uv_handle_t* handle) -> void {
397
          ThreadSafeFunction* ts_fn =
398
20
              node::ContainerOf(&ThreadSafeFunction::async,
399
20
                                reinterpret_cast<uv_async_t*>(handle));
400
20
          ts_fn->Finalize();
401
20
        });
402
  }
403
404
115133
  void Send() {
405
    // Ask currently running Dispatch() to make one more iteration
406
115133
    unsigned char current_state = dispatch_state.fetch_or(kDispatchPending);
407
115133
    if ((current_state & kDispatchRunning) == kDispatchRunning) {
408
105723
      return;
409
    }
410
411
9410
    CHECK_EQ(0, uv_async_send(&async));
412
  }
413
414
  // Default way of calling into JavaScript. Used when ThreadSafeFunction is
415
  //  without a call_js_cb_.
416
10002
  static void CallJs(napi_env env, napi_value cb, void* context, void* data) {
417

10002
    if (!(env == nullptr || cb == nullptr)) {
418
      napi_value recv;
419
      napi_status status;
420
421
10002
      status = napi_get_undefined(env, &recv);
422
10002
      if (status != napi_ok) {
423
        napi_throw_error(env,
424
                         "ERR_NAPI_TSFN_GET_UNDEFINED",
425
                         "Failed to retrieve undefined value");
426
        return;
427
      }
428
429
10002
      status = napi_call_function(env, recv, cb, 0, nullptr, nullptr);
430

10002
      if (status != napi_ok && status != napi_pending_exception) {
431
        napi_throw_error(
432
            env, "ERR_NAPI_TSFN_CALL_JS", "Failed to call JS callback");
433
        return;
434
      }
435
    }
436
  }
437
438
171
  static void AsyncCb(uv_async_t* async) {
439
    ThreadSafeFunction* ts_fn =
440
171
        node::ContainerOf(&ThreadSafeFunction::async, async);
441
171
    ts_fn->Dispatch();
442
171
  }
443
444
2
  static void Cleanup(void* data) {
445
2
    reinterpret_cast<ThreadSafeFunction*>(data)->CloseHandlesAndMaybeDelete(
446
        true);
447
2
  }
448
449
 private:
450
  static const unsigned char kDispatchIdle = 0;
451
  static const unsigned char kDispatchRunning = 1 << 0;
452
  static const unsigned char kDispatchPending = 1 << 1;
453
454
  static const unsigned int kMaxIterationCount = 1000;
455
456
  // These are variables protected by the mutex.
457
  node::Mutex mutex;
458
  std::unique_ptr<node::ConditionVariable> cond;
459
  std::queue<void*> queue;
460
  uv_async_t async;
461
  size_t thread_count;
462
  bool is_closing;
463
  std::atomic_uchar dispatch_state;
464
465
  // These are variables set once, upon creation, and then never again, which
466
  // means we don't need the mutex to read them.
467
  void* context;
468
  size_t max_queue_size;
469
470
  // These are variables accessed only from the loop thread.
471
  v8impl::Persistent<v8::Function> ref;
472
  node_napi_env env;
473
  void* finalize_data;
474
  napi_finalize finalize_cb;
475
  napi_threadsafe_function_call_js call_js_cb;
476
  bool handles_closing;
477
};
478
479
/**
480
 * Compared to node::AsyncResource, the resource object in AsyncContext is
481
 * gc-able. AsyncContext holds a weak reference to the resource object.
482
 * AsyncContext::MakeCallback doesn't implicitly set the receiver of the
483
 * callback to the resource object.
484
 */
485
class AsyncContext {
486
 public:
487
13
  AsyncContext(node_napi_env env,
488
               v8::Local<v8::Object> resource_object,
489
               const v8::Local<v8::String> resource_name,
490
               bool externally_managed_resource)
491
13
      : env_(env) {
492
13
    async_id_ = node_env()->new_async_id();
493
13
    trigger_async_id_ = node_env()->get_default_trigger_async_id();
494
13
    resource_.Reset(node_env()->isolate(), resource_object);
495
13
    lost_reference_ = false;
496
13
    if (externally_managed_resource) {
497
11
      resource_.SetWeak(
498
          this, AsyncContext::WeakCallback, v8::WeakCallbackType::kParameter);
499
    }
500
501
13
    node::AsyncWrap::EmitAsyncInit(node_env(),
502
                                   resource_object,
503
                                   resource_name,
504
                                   async_id_,
505
                                   trigger_async_id_);
506
13
  }
507
508
13
  ~AsyncContext() {
509
13
    resource_.Reset();
510
13
    lost_reference_ = true;
511
13
    node::AsyncWrap::EmitDestroy(node_env(), async_id_);
512
13
  }
513
514
8
  inline v8::MaybeLocal<v8::Value> MakeCallback(
515
      v8::Local<v8::Object> recv,
516
      const v8::Local<v8::Function> callback,
517
      int argc,
518
      v8::Local<v8::Value> argv[]) {
519
8
    EnsureReference();
520
    return node::InternalMakeCallback(node_env(),
521
                                      resource(),
522
                                      recv,
523
                                      callback,
524
                                      argc,
525
                                      argv,
526
8
                                      {async_id_, trigger_async_id_});
527
  }
528
529
4
  inline napi_callback_scope OpenCallbackScope() {
530
4
    EnsureReference();
531
    napi_callback_scope it =
532
4
        reinterpret_cast<napi_callback_scope>(new CallbackScope(this));
533
4
    env_->open_callback_scopes++;
534
4
    return it;
535
  }
536
537
12
  inline void EnsureReference() {
538
12
    if (lost_reference_) {
539
1
      const v8::HandleScope handle_scope(node_env()->isolate());
540
1
      resource_.Reset(node_env()->isolate(),
541
1
                      v8::Object::New(node_env()->isolate()));
542
1
      lost_reference_ = false;
543
    }
544
12
  }
545
546
92
  inline node::Environment* node_env() { return env_->node_env(); }
547
8
  inline v8::Local<v8::Object> resource() {
548
16
    return resource_.Get(node_env()->isolate());
549
  }
550
4
  inline node::async_context async_context() {
551
4
    return {async_id_, trigger_async_id_};
552
  }
553
554
4
  static inline void CloseCallbackScope(node_napi_env env,
555
                                        napi_callback_scope s) {
556
4
    CallbackScope* callback_scope = reinterpret_cast<CallbackScope*>(s);
557
4
    delete callback_scope;
558
4
    env->open_callback_scopes--;
559
4
  }
560
561
2
  static void WeakCallback(const v8::WeakCallbackInfo<AsyncContext>& data) {
562
2
    AsyncContext* async_context = data.GetParameter();
563
2
    async_context->resource_.Reset();
564
2
    async_context->lost_reference_ = true;
565
2
  }
566
567
 private:
568
  class CallbackScope : public node::CallbackScope {
569
   public:
570
4
    explicit CallbackScope(AsyncContext* async_context)
571
4
        : node::CallbackScope(async_context->node_env(),
572
                              async_context->resource_.Get(
573
                                  async_context->node_env()->isolate()),
574
8
                              async_context->async_context()) {}
575
  };
576
577
  node_napi_env env_;
578
  double async_id_;
579
  double trigger_async_id_;
580
  v8::Global<v8::Object> resource_;
581
  bool lost_reference_;
582
};
583
584
}  // end of anonymous namespace
585
586
}  // end of namespace v8impl
587
588
// Intercepts the Node-V8 module registration callback. Converts parameters
589
// to NAPI equivalents and then calls the registration callback specified
590
// by the NAPI module.
591
92
static void napi_module_register_cb(v8::Local<v8::Object> exports,
592
                                    v8::Local<v8::Value> module,
593
                                    v8::Local<v8::Context> context,
594
                                    void* priv) {
595
92
  napi_module_register_by_symbol(
596
      exports,
597
      module,
598
      context,
599
92
      static_cast<const napi_module*>(priv)->nm_register_func);
600
92
}
601
602
97
void napi_module_register_by_symbol(v8::Local<v8::Object> exports,
603
                                    v8::Local<v8::Value> module,
604
                                    v8::Local<v8::Context> context,
605
                                    napi_addon_register_func init) {
606
97
  node::Environment* node_env = node::Environment::GetCurrent(context);
607
97
  std::string module_filename = "";
608
97
  if (init == nullptr) {
609
1
    CHECK_NOT_NULL(node_env);
610
1
    node_env->ThrowError("Module has no declared entry point.");
611
1
    return;
612
  }
613
614
  // We set `env->filename` from `module.filename` here, but we could just as
615
  // easily add a private property to `exports` in `process.dlopen`, which
616
  // receives the file name from JS, and retrieve *that* here. Thus, we are not
617
  // endorsing commonjs here by making use of `module.filename`.
618
  v8::Local<v8::Value> filename_js;
619
  v8::Local<v8::Object> modobj;
620
96
  if (module->ToObject(context).ToLocal(&modobj) &&
621

480
      modobj->Get(context, node_env->filename_string()).ToLocal(&filename_js) &&
622
192
      filename_js->IsString()) {
623
91
    node::Utf8Value filename(node_env->isolate(), filename_js);
624
625
    // Turn the absolute path into a URL. Currently the absolute path is always
626
    // a file system path.
627
    // TODO(gabrielschulhof): Pass the `filename` through unchanged if/when we
628
    // receive it as a URL already.
629
91
    module_filename = node::url::URL::FromFilePath(filename.ToString()).href();
630
  }
631
632
  // Create a new napi_env for this specific module.
633
96
  napi_env env = v8impl::NewEnv(context, module_filename);
634
635
  napi_value _exports;
636
96
  env->CallIntoModule([&](napi_env env) {
637
96
    _exports = init(env, v8impl::JsValueFromV8LocalValue(exports));
638
96
  });
639
640
  // If register function returned a non-null exports object different from
641
  // the exports object we passed it, set that as the "exports" property of
642
  // the module.
643
186
  if (_exports != nullptr &&
644

186
      _exports != v8impl::JsValueFromV8LocalValue(exports)) {
645
4
    napi_value _module = v8impl::JsValueFromV8LocalValue(module);
646
4
    napi_set_named_property(env, _module, "exports", _exports);
647
  }
648
}
649
650
namespace node {
651
91
node_module napi_module_to_node_module(const napi_module* mod) {
652
  return {
653
      -1,
654
91
      mod->nm_flags | NM_F_DELETEME,
655
      nullptr,
656
91
      mod->nm_filename,
657
      nullptr,
658
      napi_module_register_cb,
659
91
      mod->nm_modname,
660
      const_cast<napi_module*>(mod),  // priv
661
      nullptr,
662
91
  };
663
}
664
}  // namespace node
665
666
// Registers a NAPI module.
667
88
void NAPI_CDECL napi_module_register(napi_module* mod) {
668
  node::node_module* nm =
669
88
      new node::node_module(node::napi_module_to_node_module(mod));
670
88
  node::node_module_register(nm);
671
88
}
672
673
2
napi_status NAPI_CDECL napi_add_env_cleanup_hook(
674
    napi_env env, void(NAPI_CDECL* fun)(void* arg), void* arg) {
675
2
  CHECK_ENV(env);
676
2
  CHECK_ARG(env, fun);
677
678
2
  node::AddEnvironmentCleanupHook(env->isolate, fun, arg);
679
680
2
  return napi_ok;
681
}
682
683
1
napi_status NAPI_CDECL napi_remove_env_cleanup_hook(
684
    napi_env env, void(NAPI_CDECL* fun)(void* arg), void* arg) {
685
1
  CHECK_ENV(env);
686
1
  CHECK_ARG(env, fun);
687
688
1
  node::RemoveEnvironmentCleanupHook(env->isolate, fun, arg);
689
690
1
  return napi_ok;
691
}
692
693
struct napi_async_cleanup_hook_handle__ {
694
6
  napi_async_cleanup_hook_handle__(napi_env env,
695
                                   napi_async_cleanup_hook user_hook,
696
                                   void* user_data)
697
6
      : env_(env), user_hook_(user_hook), user_data_(user_data) {
698
6
    handle_ = node::AddEnvironmentCleanupHook(env->isolate, Hook, this);
699
6
    env->Ref();
700
6
  }
701
702
18
  ~napi_async_cleanup_hook_handle__() {
703
6
    node::RemoveEnvironmentCleanupHook(std::move(handle_));
704
6
    if (done_cb_ != nullptr) done_cb_(done_data_);
705
706
    // Release the `env` handle asynchronously since it would be surprising if
707
    // a call to a N-API function would destroy `env` synchronously.
708
12
    static_cast<node_napi_env>(env_)->node_env()->SetImmediate(
709
12
        [env = env_](node::Environment*) { env->Unref(); });
710
6
  }
711
712
4
  static void Hook(void* data, void (*done_cb)(void*), void* done_data) {
713
4
    napi_async_cleanup_hook_handle__* handle =
714
        static_cast<napi_async_cleanup_hook_handle__*>(data);
715
4
    handle->done_cb_ = done_cb;
716
4
    handle->done_data_ = done_data;
717
4
    handle->user_hook_(handle, handle->user_data_);
718
4
  }
719
720
  node::AsyncCleanupHookHandle handle_;
721
  napi_env env_ = nullptr;
722
  napi_async_cleanup_hook user_hook_ = nullptr;
723
  void* user_data_ = nullptr;
724
  void (*done_cb_)(void*) = nullptr;
725
  void* done_data_ = nullptr;
726
};
727
728
napi_status NAPI_CDECL
729
6
napi_add_async_cleanup_hook(napi_env env,
730
                            napi_async_cleanup_hook hook,
731
                            void* arg,
732
                            napi_async_cleanup_hook_handle* remove_handle) {
733
6
  CHECK_ENV(env);
734
6
  CHECK_ARG(env, hook);
735
736
  napi_async_cleanup_hook_handle__* handle =
737
6
      new napi_async_cleanup_hook_handle__(env, hook, arg);
738
739
6
  if (remove_handle != nullptr) *remove_handle = handle;
740
741
6
  return napi_clear_last_error(env);
742
}
743
744
napi_status NAPI_CDECL
745
6
napi_remove_async_cleanup_hook(napi_async_cleanup_hook_handle remove_handle) {
746
6
  if (remove_handle == nullptr) return napi_invalid_arg;
747
748
6
  delete remove_handle;
749
750
6
  return napi_ok;
751
}
752
753
1
napi_status NAPI_CDECL napi_fatal_exception(napi_env env, napi_value err) {
754


2
  NAPI_PREAMBLE(env);
755
1
  CHECK_ARG(env, err);
756
757
1
  v8::Local<v8::Value> local_err = v8impl::V8LocalValueFromJsValue(err);
758
1
  static_cast<node_napi_env>(env)->trigger_fatal_exception(local_err);
759
760
1
  return napi_clear_last_error(env);
761
}
762
763
NAPI_NO_RETURN void NAPI_CDECL napi_fatal_error(const char* location,
764
                                                size_t location_len,
765
                                                const char* message,
766
                                                size_t message_len) {
767
  std::string location_string;
768
  std::string message_string;
769
770
  if (location_len != NAPI_AUTO_LENGTH) {
771
    location_string.assign(const_cast<char*>(location), location_len);
772
  } else {
773
    location_string.assign(const_cast<char*>(location), strlen(location));
774
  }
775
776
  if (message_len != NAPI_AUTO_LENGTH) {
777
    message_string.assign(const_cast<char*>(message), message_len);
778
  } else {
779
    message_string.assign(const_cast<char*>(message), strlen(message));
780
  }
781
782
  node::FatalError(location_string.c_str(), message_string.c_str());
783
}
784
785
napi_status NAPI_CDECL
786
4
napi_open_callback_scope(napi_env env,
787
                         napi_value /** ignored */,
788
                         napi_async_context async_context_handle,
789
                         napi_callback_scope* result) {
790
  // Omit NAPI_PREAMBLE and GET_RETURN_STATUS because V8 calls here cannot throw
791
  // JS exceptions.
792
4
  CHECK_ENV(env);
793
4
  CHECK_ARG(env, result);
794
795
4
  v8impl::AsyncContext* node_async_context =
796
      reinterpret_cast<v8impl::AsyncContext*>(async_context_handle);
797
798
4
  *result = node_async_context->OpenCallbackScope();
799
800
4
  return napi_clear_last_error(env);
801
}
802
803
4
napi_status NAPI_CDECL napi_close_callback_scope(napi_env env,
804
                                                 napi_callback_scope scope) {
805
  // Omit NAPI_PREAMBLE and GET_RETURN_STATUS because V8 calls here cannot throw
806
  // JS exceptions.
807
4
  CHECK_ENV(env);
808
4
  CHECK_ARG(env, scope);
809
4
  if (env->open_callback_scopes == 0) {
810
    return napi_callback_scope_mismatch;
811
  }
812
813
4
  v8impl::AsyncContext::CloseCallbackScope(reinterpret_cast<node_napi_env>(env),
814
                                           scope);
815
816
4
  return napi_clear_last_error(env);
817
}
818
819
13
napi_status NAPI_CDECL napi_async_init(napi_env env,
820
                                       napi_value async_resource,
821
                                       napi_value async_resource_name,
822
                                       napi_async_context* result) {
823
13
  CHECK_ENV(env);
824
13
  CHECK_ARG(env, async_resource_name);
825
13
  CHECK_ARG(env, result);
826
827
13
  v8::Isolate* isolate = env->isolate;
828
13
  v8::Local<v8::Context> context = env->context();
829
830
  v8::Local<v8::Object> v8_resource;
831
  bool externally_managed_resource;
832
13
  if (async_resource != nullptr) {
833

22
    CHECK_TO_OBJECT(env, context, v8_resource, async_resource);
834
11
    externally_managed_resource = true;
835
  } else {
836
2
    v8_resource = v8::Object::New(isolate);
837
2
    externally_managed_resource = false;
838
  }
839
840
  v8::Local<v8::String> v8_resource_name;
841

26
  CHECK_TO_STRING(env, context, v8_resource_name, async_resource_name);
842
843
  v8impl::AsyncContext* async_context =
844
      new v8impl::AsyncContext(reinterpret_cast<node_napi_env>(env),
845
                               v8_resource,
846
                               v8_resource_name,
847
13
                               externally_managed_resource);
848
849
13
  *result = reinterpret_cast<napi_async_context>(async_context);
850
851
13
  return napi_clear_last_error(env);
852
}
853
854
13
napi_status NAPI_CDECL napi_async_destroy(napi_env env,
855
                                          napi_async_context async_context) {
856
13
  CHECK_ENV(env);
857
13
  CHECK_ARG(env, async_context);
858
859
13
  v8impl::AsyncContext* node_async_context =
860
      reinterpret_cast<v8impl::AsyncContext*>(async_context);
861
862
13
  delete node_async_context;
863
864
13
  return napi_clear_last_error(env);
865
}
866
867
25
napi_status NAPI_CDECL napi_make_callback(napi_env env,
868
                                          napi_async_context async_context,
869
                                          napi_value recv,
870
                                          napi_value func,
871
                                          size_t argc,
872
                                          const napi_value* argv,
873
                                          napi_value* result) {
874


50
  NAPI_PREAMBLE(env);
875
25
  CHECK_ARG(env, recv);
876
25
  if (argc > 0) {
877
4
    CHECK_ARG(env, argv);
878
  }
879
880
25
  v8::Local<v8::Context> context = env->context();
881
882
  v8::Local<v8::Object> v8recv;
883

75
  CHECK_TO_OBJECT(env, context, v8recv, recv);
884
885
  v8::Local<v8::Function> v8func;
886

75
  CHECK_TO_FUNCTION(env, v8func, func);
887
888
  v8::MaybeLocal<v8::Value> callback_result;
889
890
25
  if (async_context == nullptr) {
891
    callback_result = node::MakeCallback(
892
17
        env->isolate,
893
        v8recv,
894
        v8func,
895
        argc,
896
        reinterpret_cast<v8::Local<v8::Value>*>(const_cast<napi_value*>(argv)),
897
17
        {0, 0});
898
  } else {
899
8
    v8impl::AsyncContext* node_async_context =
900
        reinterpret_cast<v8impl::AsyncContext*>(async_context);
901
    callback_result = node_async_context->MakeCallback(
902
        v8recv,
903
        v8func,
904
        argc,
905
8
        reinterpret_cast<v8::Local<v8::Value>*>(const_cast<napi_value*>(argv)));
906
  }
907
908
25
  if (try_catch.HasCaught()) {
909
4
    return napi_set_last_error(env, napi_pending_exception);
910
  } else {
911
21
    CHECK_MAYBE_EMPTY(env, callback_result, napi_generic_failure);
912
21
    if (result != nullptr) {
913
8
      *result =
914
8
          v8impl::JsValueFromV8LocalValue(callback_result.ToLocalChecked());
915
    }
916
  }
917
918
21
  return GET_RETURN_STATUS(env);
919
}
920
921
1
napi_status NAPI_CDECL napi_create_buffer(napi_env env,
922
                                          size_t length,
923
                                          void** data,
924
                                          napi_value* result) {
925


2
  NAPI_PREAMBLE(env);
926
1
  CHECK_ARG(env, result);
927
928
1
  v8::MaybeLocal<v8::Object> maybe = node::Buffer::New(env->isolate, length);
929
930
1
  CHECK_MAYBE_EMPTY(env, maybe, napi_generic_failure);
931
932
1
  v8::Local<v8::Object> buffer = maybe.ToLocalChecked();
933
934
1
  *result = v8impl::JsValueFromV8LocalValue(buffer);
935
936
1
  if (data != nullptr) {
937
1
    *data = node::Buffer::Data(buffer);
938
  }
939
940
1
  return GET_RETURN_STATUS(env);
941
}
942
943
14
napi_status NAPI_CDECL napi_create_external_buffer(napi_env env,
944
                                                   size_t length,
945
                                                   void* data,
946
                                                   napi_finalize finalize_cb,
947
                                                   void* finalize_hint,
948
                                                   napi_value* result) {
949


28
  NAPI_PREAMBLE(env);
950
14
  CHECK_ARG(env, result);
951
952
14
  v8::Isolate* isolate = env->isolate;
953
954
  // The finalizer object will delete itself after invoking the callback.
955
  v8impl::Finalizer* finalizer =
956
14
      v8impl::Finalizer::New(env,
957
                             finalize_cb,
958
                             nullptr,
959
                             finalize_hint,
960
                             v8impl::Finalizer::kKeepEnvReference);
961
962
  v8::MaybeLocal<v8::Object> maybe =
963
      node::Buffer::New(isolate,
964
                        static_cast<char*>(data),
965
                        length,
966
                        v8impl::BufferFinalizer::FinalizeBufferCallback,
967
14
                        finalizer);
968
969
14
  CHECK_MAYBE_EMPTY(env, maybe, napi_generic_failure);
970
971
14
  *result = v8impl::JsValueFromV8LocalValue(maybe.ToLocalChecked());
972
14
  return GET_RETURN_STATUS(env);
973
  // Tell coverity that 'finalizer' should not be freed when we return
974
  // as it will be deleted when the buffer to which it is associated
975
  // is finalized.
976
  // coverity[leaked_storage]
977
}
978
979
1
napi_status NAPI_CDECL napi_create_buffer_copy(napi_env env,
980
                                               size_t length,
981
                                               const void* data,
982
                                               void** result_data,
983
                                               napi_value* result) {
984


2
  NAPI_PREAMBLE(env);
985
1
  CHECK_ARG(env, result);
986
987
  v8::MaybeLocal<v8::Object> maybe =
988
1
      node::Buffer::Copy(env->isolate, static_cast<const char*>(data), length);
989
990
1
  CHECK_MAYBE_EMPTY(env, maybe, napi_generic_failure);
991
992
1
  v8::Local<v8::Object> buffer = maybe.ToLocalChecked();
993
1
  *result = v8impl::JsValueFromV8LocalValue(buffer);
994
995
1
  if (result_data != nullptr) {
996
    *result_data = node::Buffer::Data(buffer);
997
  }
998
999
1
  return GET_RETURN_STATUS(env);
1000
}
1001
1002
1
napi_status NAPI_CDECL napi_is_buffer(napi_env env,
1003
                                      napi_value value,
1004
                                      bool* result) {
1005
1
  CHECK_ENV(env);
1006
1
  CHECK_ARG(env, value);
1007
1
  CHECK_ARG(env, result);
1008
1009
1
  *result = node::Buffer::HasInstance(v8impl::V8LocalValueFromJsValue(value));
1010
1
  return napi_clear_last_error(env);
1011
}
1012
1013
1
napi_status NAPI_CDECL napi_get_buffer_info(napi_env env,
1014
                                            napi_value value,
1015
                                            void** data,
1016
                                            size_t* length) {
1017
1
  CHECK_ENV(env);
1018
1
  CHECK_ARG(env, value);
1019
1020
1
  v8::Local<v8::Value> buffer = v8impl::V8LocalValueFromJsValue(value);
1021
1022
1
  if (data != nullptr) {
1023
1
    *data = node::Buffer::Data(buffer);
1024
  }
1025
1
  if (length != nullptr) {
1026
1
    *length = node::Buffer::Length(buffer);
1027
  }
1028
1029
1
  return napi_clear_last_error(env);
1030
}
1031
1032
1
napi_status NAPI_CDECL napi_get_node_version(napi_env env,
1033
                                             const napi_node_version** result) {
1034
1
  CHECK_ENV(env);
1035
1
  CHECK_ARG(env, result);
1036
  static const napi_node_version version = {
1037
      NODE_MAJOR_VERSION, NODE_MINOR_VERSION, NODE_PATCH_VERSION, NODE_RELEASE};
1038
1
  *result = &version;
1039
1
  return napi_clear_last_error(env);
1040
}
1041
1042
namespace {
1043
namespace uvimpl {
1044
1045
513
static napi_status ConvertUVErrorCode(int code) {
1046

513
  switch (code) {
1047
512
    case 0:
1048
512
      return napi_ok;
1049
    case UV_EINVAL:
1050
      return napi_invalid_arg;
1051
1
    case UV_ECANCELED:
1052
1
      return napi_cancelled;
1053
    default:
1054
      return napi_generic_failure;
1055
  }
1056
}
1057
1058
// Wrapper around uv_work_t which calls user-provided callbacks.
1059
class Work : public node::AsyncResource, public node::ThreadPoolWork {
1060
 private:
1061
512
  explicit Work(node_napi_env env,
1062
                v8::Local<v8::Object> async_resource,
1063
                v8::Local<v8::String> async_resource_name,
1064
                napi_async_execute_callback execute,
1065
                napi_async_complete_callback complete = nullptr,
1066
                void* data = nullptr)
1067
512
      : AsyncResource(
1068
512
            env->isolate,
1069
            async_resource,
1070
1024
            *v8::String::Utf8Value(env->isolate, async_resource_name)),
1071
        ThreadPoolWork(env->node_env()),
1072
        _env(env),
1073
        _data(data),
1074
        _execute(execute),
1075
1536
        _complete(complete) {}
1076
1077
2032
  ~Work() override = default;
1078
1079
 public:
1080
512
  static Work* New(node_napi_env env,
1081
                   v8::Local<v8::Object> async_resource,
1082
                   v8::Local<v8::String> async_resource_name,
1083
                   napi_async_execute_callback execute,
1084
                   napi_async_complete_callback complete,
1085
                   void* data) {
1086
    return new Work(
1087
512
        env, async_resource, async_resource_name, execute, complete, data);
1088
  }
1089
1090
508
  static void Delete(Work* work) { delete work; }
1091
1092
511
  void DoThreadPoolWork() override { _execute(_env, _data); }
1093
1094
512
  void AfterThreadPoolWork(int status) override {
1095
512
    if (_complete == nullptr) return;
1096
1097
    // Establish a handle scope here so that every callback doesn't have to.
1098
    // Also it is needed for the exception-handling below.
1099
1023
    v8::HandleScope scope(_env->isolate);
1100
1101
512
    CallbackScope callback_scope(this);
1102
1103
512
    _env->CallbackIntoModule<true>([&](napi_env env) {
1104
512
      _complete(env, ConvertUVErrorCode(status), _data);
1105
512
    });
1106
1107
    // Note: Don't access `work` after this point because it was
1108
    // likely deleted by the complete callback.
1109
  }
1110
1111
 private:
1112
  node_napi_env _env;
1113
  void* _data;
1114
  napi_async_execute_callback _execute;
1115
  napi_async_complete_callback _complete;
1116
};
1117
1118
}  // end of namespace uvimpl
1119
}  // end of anonymous namespace
1120
1121
#define CALL_UV(env, condition)                                                \
1122
  do {                                                                         \
1123
    int result = (condition);                                                  \
1124
    napi_status status = uvimpl::ConvertUVErrorCode(result);                   \
1125
    if (status != napi_ok) {                                                   \
1126
      return napi_set_last_error(env, status, result);                         \
1127
    }                                                                          \
1128
  } while (0)
1129
1130
napi_status NAPI_CDECL
1131
512
napi_create_async_work(napi_env env,
1132
                       napi_value async_resource,
1133
                       napi_value async_resource_name,
1134
                       napi_async_execute_callback execute,
1135
                       napi_async_complete_callback complete,
1136
                       void* data,
1137
                       napi_async_work* result) {
1138
512
  CHECK_ENV(env);
1139
512
  CHECK_ARG(env, execute);
1140
512
  CHECK_ARG(env, result);
1141
1142
512
  v8::Local<v8::Context> context = env->context();
1143
1144
  v8::Local<v8::Object> resource;
1145
512
  if (async_resource != nullptr) {
1146

12
    CHECK_TO_OBJECT(env, context, resource, async_resource);
1147
  } else {
1148
508
    resource = v8::Object::New(env->isolate);
1149
  }
1150
1151
  v8::Local<v8::String> resource_name;
1152

1024
  CHECK_TO_STRING(env, context, resource_name, async_resource_name);
1153
1154
512
  uvimpl::Work* work = uvimpl::Work::New(reinterpret_cast<node_napi_env>(env),
1155
                                         resource,
1156
                                         resource_name,
1157
                                         execute,
1158
                                         complete,
1159
                                         data);
1160
1161
512
  *result = reinterpret_cast<napi_async_work>(work);
1162
1163
512
  return napi_clear_last_error(env);
1164
}
1165
1166
508
napi_status NAPI_CDECL napi_delete_async_work(napi_env env,
1167
                                              napi_async_work work) {
1168
508
  CHECK_ENV(env);
1169
508
  CHECK_ARG(env, work);
1170
1171
508
  uvimpl::Work::Delete(reinterpret_cast<uvimpl::Work*>(work));
1172
1173
508
  return napi_clear_last_error(env);
1174
}
1175
1176
518
napi_status NAPI_CDECL napi_get_uv_event_loop(napi_env env, uv_loop_t** loop) {
1177
518
  CHECK_ENV(env);
1178
518
  CHECK_ARG(env, loop);
1179
518
  *loop = reinterpret_cast<node_napi_env>(env)->node_env()->event_loop();
1180
518
  return napi_clear_last_error(env);
1181
}
1182
1183
512
napi_status NAPI_CDECL napi_queue_async_work(napi_env env,
1184
                                             napi_async_work work) {
1185
512
  CHECK_ENV(env);
1186
512
  CHECK_ARG(env, work);
1187
1188
512
  uv_loop_t* event_loop = nullptr;
1189
512
  STATUS_CALL(napi_get_uv_event_loop(env, &event_loop));
1190
1191
512
  uvimpl::Work* w = reinterpret_cast<uvimpl::Work*>(work);
1192
1193
512
  w->ScheduleWork();
1194
1195
512
  return napi_clear_last_error(env);
1196
}
1197
1198
1
napi_status NAPI_CDECL napi_cancel_async_work(napi_env env,
1199
                                              napi_async_work work) {
1200
1
  CHECK_ENV(env);
1201
1
  CHECK_ARG(env, work);
1202
1203
1
  uvimpl::Work* w = reinterpret_cast<uvimpl::Work*>(work);
1204
1205
1
  CALL_UV(env, w->CancelWork());
1206
1207
1
  return napi_clear_last_error(env);
1208
}
1209
1210
napi_status NAPI_CDECL
1211
20
napi_create_threadsafe_function(napi_env env,
1212
                                napi_value func,
1213
                                napi_value async_resource,
1214
                                napi_value async_resource_name,
1215
                                size_t max_queue_size,
1216
                                size_t initial_thread_count,
1217
                                void* thread_finalize_data,
1218
                                napi_finalize thread_finalize_cb,
1219
                                void* context,
1220
                                napi_threadsafe_function_call_js call_js_cb,
1221
                                napi_threadsafe_function* result) {
1222
20
  CHECK_ENV(env);
1223
20
  CHECK_ARG(env, async_resource_name);
1224
20
  RETURN_STATUS_IF_FALSE(env, initial_thread_count > 0, napi_invalid_arg);
1225
20
  CHECK_ARG(env, result);
1226
1227
20
  napi_status status = napi_ok;
1228
1229
  v8::Local<v8::Function> v8_func;
1230
20
  if (func == nullptr) {
1231
3
    CHECK_ARG(env, call_js_cb);
1232
  } else {
1233

51
    CHECK_TO_FUNCTION(env, v8_func, func);
1234
  }
1235
1236
20
  v8::Local<v8::Context> v8_context = env->context();
1237
1238
  v8::Local<v8::Object> v8_resource;
1239
20
  if (async_resource == nullptr) {
1240
18
    v8_resource = v8::Object::New(env->isolate);
1241
  } else {
1242

6
    CHECK_TO_OBJECT(env, v8_context, v8_resource, async_resource);
1243
  }
1244
1245
  v8::Local<v8::String> v8_name;
1246

40
  CHECK_TO_STRING(env, v8_context, v8_name, async_resource_name);
1247
1248
  v8impl::ThreadSafeFunction* ts_fn =
1249
      new v8impl::ThreadSafeFunction(v8_func,
1250
                                     v8_resource,
1251
                                     v8_name,
1252
                                     initial_thread_count,
1253
                                     context,
1254
                                     max_queue_size,
1255
                                     reinterpret_cast<node_napi_env>(env),
1256
                                     thread_finalize_data,
1257
                                     thread_finalize_cb,
1258
20
                                     call_js_cb);
1259
1260
20
  if (ts_fn == nullptr) {
1261
    status = napi_generic_failure;
1262
  } else {
1263
    // Init deletes ts_fn upon failure.
1264
20
    status = ts_fn->Init();
1265
20
    if (status == napi_ok) {
1266
20
      *result = reinterpret_cast<napi_threadsafe_function>(ts_fn);
1267
    }
1268
  }
1269
1270
20
  return napi_set_last_error(env, status);
1271
}
1272
1273
16
napi_status NAPI_CDECL napi_get_threadsafe_function_context(
1274
    napi_threadsafe_function func, void** result) {
1275
16
  CHECK_NOT_NULL(func);
1276
16
  CHECK_NOT_NULL(result);
1277
1278
16
  *result = reinterpret_cast<v8impl::ThreadSafeFunction*>(func)->Context();
1279
16
  return napi_ok;
1280
}
1281
1282
napi_status NAPI_CDECL
1283
3352457
napi_call_threadsafe_function(napi_threadsafe_function func,
1284
                              void* data,
1285
                              napi_threadsafe_function_call_mode is_blocking) {
1286
3352457
  CHECK_NOT_NULL(func);
1287
3352457
  return reinterpret_cast<v8impl::ThreadSafeFunction*>(func)->Push(data,
1288
3352457
                                                                   is_blocking);
1289
}
1290
1291
napi_status NAPI_CDECL
1292
4
napi_acquire_threadsafe_function(napi_threadsafe_function func) {
1293
4
  CHECK_NOT_NULL(func);
1294
4
  return reinterpret_cast<v8impl::ThreadSafeFunction*>(func)->Acquire();
1295
}
1296
1297
35
napi_status NAPI_CDECL napi_release_threadsafe_function(
1298
    napi_threadsafe_function func, napi_threadsafe_function_release_mode mode) {
1299
35
  CHECK_NOT_NULL(func);
1300
35
  return reinterpret_cast<v8impl::ThreadSafeFunction*>(func)->Release(mode);
1301
}
1302
1303
napi_status NAPI_CDECL
1304
2
napi_unref_threadsafe_function(napi_env env, napi_threadsafe_function func) {
1305
2
  CHECK_NOT_NULL(func);
1306
2
  return reinterpret_cast<v8impl::ThreadSafeFunction*>(func)->Unref();
1307
}
1308
1309
napi_status NAPI_CDECL
1310
napi_ref_threadsafe_function(napi_env env, napi_threadsafe_function func) {
1311
  CHECK_NOT_NULL(func);
1312
  return reinterpret_cast<v8impl::ThreadSafeFunction*>(func)->Ref();
1313
}
1314
1315
2
napi_status NAPI_CDECL node_api_get_module_file_name(napi_env env,
1316
                                                     const char** result) {
1317
2
  CHECK_ENV(env);
1318
2
  CHECK_ARG(env, result);
1319
1320
2
  *result = static_cast<node_napi_env>(env)->GetFilename();
1321
2
  return napi_clear_last_error(env);
1322
}