GCC Code Coverage Report
Directory: ../ Exec Total Coverage
File: /home/iojs/build/workspace/node-test-commit-linux-coverage-daily/nodes/benchmark/out/../src/node_api.cc Lines: 543 588 92.3 %
Date: 2021-06-04 04:12:13 Branches: 235 388 60.6 %

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_binding.h"
8
#include "node_buffer.h"
9
#include "node_errors.h"
10
#include "node_internals.h"
11
#include "threadpoolwork-inl.h"
12
#include "tracing/traced_value.h"
13
#include "util-inl.h"
14
15
#include <atomic>
16
#include <memory>
17
18
166
struct node_napi_env__ : public napi_env__ {
19
85
  explicit node_napi_env__(v8::Local<v8::Context> context,
20
85
                           const std::string& module_filename):
21
85
      napi_env__(context), filename(module_filename) {
22
85
    CHECK_NOT_NULL(node_env());
23
85
  }
24
25
120239
  inline node::Environment* node_env() const {
26
120239
    return node::Environment::GetCurrent(context());
27
  }
28
29
117879
  bool can_call_into_js() const override {
30
117879
    return node_env()->can_call_into_js();
31
  }
32
33
  v8::Maybe<bool> mark_arraybuffer_as_untransferable(
34
      v8::Local<v8::ArrayBuffer> ab) const override {
35
    return ab->SetPrivate(
36
        context(),
37
        node_env()->untransferable_object_private_symbol(),
38
        v8::True(isolate));
39
  }
40
41
1013
  void CallFinalizer(napi_finalize cb, void* data, void* hint) override {
42
    // we need to keep the env live until the finalizer has been run
43
    // EnvRefHolder provides an exception safe wrapper to Ref and then
44
    // Unref once the lamba is freed
45
2026
    EnvRefHolder liveEnv(static_cast<napi_env>(this));
46
5065
    node_env()->SetImmediate([=, liveEnv = std::move(liveEnv)]
47
1013
        (node::Environment* node_env) {
48
1013
      napi_env env = liveEnv.env();
49
2026
      v8::HandleScope handle_scope(env->isolate);
50
1013
      v8::Context::Scope context_scope(env->context());
51
3039
      env->CallIntoModule([&](napi_env env) {
52
1013
        cb(env, data, hint);
53
2026
      });
54
2026
    });
55
1013
  }
56
57
1
  const char* GetFilename() const { return filename.c_str(); }
58
59
  std::string filename;
60
};
61
62
typedef node_napi_env__* node_napi_env;
63
64
namespace v8impl {
65
66
namespace {
67
68
class BufferFinalizer : private Finalizer {
69
 public:
70
  // node::Buffer::FreeCallback
71
13
  static void FinalizeBufferCallback(char* data, void* hint) {
72
    std::unique_ptr<BufferFinalizer, Deleter> finalizer{
73
26
        static_cast<BufferFinalizer*>(hint)};
74
13
    finalizer->_finalize_data = data;
75
76
    node::Environment* node_env =
77
13
        static_cast<node_napi_env>(finalizer->_env)->node_env();
78
26
    node_env->SetImmediate(
79
65
        [finalizer = std::move(finalizer)](node::Environment* env) {
80
13
      if (finalizer->_finalize_callback == nullptr) return;
81
82
24
      v8::HandleScope handle_scope(finalizer->_env->isolate);
83
12
      v8::Context::Scope context_scope(finalizer->_env->context());
84
85
36
      finalizer->_env->CallIntoModule([&](napi_env env) {
86
36
        finalizer->_finalize_callback(
87
            env,
88
12
            finalizer->_finalize_data,
89
24
            finalizer->_finalize_hint);
90
24
      });
91
13
    });
92
13
  }
93
94
  struct Deleter {
95
13
    void operator()(BufferFinalizer* finalizer) {
96
13
      Finalizer::Delete(finalizer);
97
13
    }
98
  };
99
};
100
101
static inline napi_env
102
85
NewEnv(v8::Local<v8::Context> context, const std::string& module_filename) {
103
  node_napi_env result;
104
105
85
  result = new node_napi_env__(context, module_filename);
106
  // TODO(addaleax): There was previously code that tried to delete the
107
  // napi_env when its v8::Context was garbage collected;
108
  // However, as long as N-API addons using this napi_env are in place,
109
  // the Context needs to be accessible and alive.
110
  // Ideally, we'd want an on-addon-unload hook that takes care of this
111
  // once all N-API addons using this napi_env are unloaded.
112
  // For now, a per-Environment cleanup hook is the best we can do.
113
170
  result->node_env()->AddCleanupHook(
114
251
      [](void* arg) {
115
83
        static_cast<napi_env>(arg)->Unref();
116
251
      },
117
85
      static_cast<void*>(result));
118
119
85
  return result;
120
}
121
122
3
static inline void trigger_fatal_exception(
123
    napi_env env, v8::Local<v8::Value> local_err) {
124
  v8::Local<v8::Message> local_msg =
125
3
    v8::Exception::CreateMessage(env->isolate, local_err);
126
3
  node::errors::TriggerUncaughtException(env->isolate, local_err, local_msg);
127
2
}
128
129
class ThreadSafeFunction : public node::AsyncResource {
130
 public:
131
18
  ThreadSafeFunction(v8::Local<v8::Function> func,
132
                     v8::Local<v8::Object> resource,
133
                     v8::Local<v8::String> name,
134
                     size_t thread_count_,
135
                     void* context_,
136
                     size_t max_queue_size_,
137
                     node_napi_env env_,
138
                     void* finalize_data_,
139
                     napi_finalize finalize_cb_,
140
18
                     napi_threadsafe_function_call_js call_js_cb_):
141
18
                     AsyncResource(env_->isolate,
142
                                   resource,
143
36
                                   *v8::String::Utf8Value(env_->isolate, name)),
144
      thread_count(thread_count_),
145
      is_closing(false),
146
      dispatch_state(kDispatchIdle),
147
      context(context_),
148
      max_queue_size(max_queue_size_),
149
      env(env_),
150
      finalize_data(finalize_data_),
151
      finalize_cb(finalize_cb_),
152
18
      call_js_cb(call_js_cb_ == nullptr ? CallJs : call_js_cb_),
153
72
      handles_closing(false) {
154
18
    ref.Reset(env->isolate, func);
155
18
    node::AddEnvironmentCleanupHook(env->isolate, Cleanup, this);
156
18
    env->Ref();
157
18
  }
158
159
72
  ~ThreadSafeFunction() override {
160
18
    node::RemoveEnvironmentCleanupHook(env->isolate, Cleanup, this);
161
18
    env->Unref();
162
36
  }
163
164
  // These methods can be called from any thread.
165
166
11901803
  napi_status Push(void* data, napi_threadsafe_function_call_mode mode) {
167
23803606
    node::Mutex::ScopedLock lock(this->mutex);
168
169

35706118
    while (queue.size() >= max_queue_size &&
170

23736387
        max_queue_size > 0 &&
171
11811622
        !is_closing) {
172
11811619
      if (mode == napi_tsfn_nonblocking) {
173
11788657
        return napi_queue_full;
174
      }
175
22962
      cond->Wait(lock);
176
    }
177
178
113146
    if (is_closing) {
179
5
      if (thread_count == 0) {
180
        return napi_invalid_arg;
181
      } else {
182
5
        thread_count--;
183
5
        return napi_closing;
184
      }
185
    } else {
186
113141
      queue.push(data);
187
113141
      Send();
188
113141
      return napi_ok;
189
    }
190
  }
191
192
4
  napi_status Acquire() {
193
8
    node::Mutex::ScopedLock lock(this->mutex);
194
195
4
    if (is_closing) {
196
      return napi_closing;
197
    }
198
199
4
    thread_count++;
200
201
4
    return napi_ok;
202
  }
203
204
33
  napi_status Release(napi_threadsafe_function_release_mode mode) {
205
66
    node::Mutex::ScopedLock lock(this->mutex);
206
207
33
    if (thread_count == 0) {
208
      return napi_invalid_arg;
209
    }
210
211
33
    thread_count--;
212
213

33
    if (thread_count == 0 || mode == napi_tsfn_abort) {
214
16
      if (!is_closing) {
215
16
        is_closing = (mode == napi_tsfn_abort);
216

16
        if (is_closing && max_queue_size > 0) {
217
2
          cond->Signal(lock);
218
        }
219
16
        Send();
220
      }
221
    }
222
223
33
    return napi_ok;
224
  }
225
226
25
  void EmptyQueueAndDelete() {
227
32
    for (; !queue.empty() ; queue.pop()) {
228
7
      call_js_cb(nullptr, nullptr, context, queue.front());
229
    }
230
18
    delete this;
231
18
  }
232
233
  // These methods must only be called from the loop thread.
234
235
18
  napi_status Init() {
236
18
    ThreadSafeFunction* ts_fn = this;
237
18
    uv_loop_t* loop = env->node_env()->event_loop();
238
239
18
    if (uv_async_init(loop, &async, AsyncCb) == 0) {
240
18
      if (max_queue_size > 0) {
241
12
        cond = std::make_unique<node::ConditionVariable>();
242
      }
243

18
      if (max_queue_size == 0 || cond) {
244
18
        return napi_ok;
245
      }
246
247
      env->node_env()->CloseHandle(
248
          reinterpret_cast<uv_handle_t*>(&async),
249
          [](uv_handle_t* handle) -> void {
250
            ThreadSafeFunction* ts_fn =
251
                node::ContainerOf(&ThreadSafeFunction::async,
252
                                  reinterpret_cast<uv_async_t*>(handle));
253
            delete ts_fn;
254
          });
255
256
      // Prevent the thread-safe function from being deleted here, because
257
      // the callback above will delete it.
258
      ts_fn = nullptr;
259
    }
260
261
    delete ts_fn;
262
263
    return napi_generic_failure;
264
  }
265
266
2
  napi_status Unref() {
267
2
    uv_unref(reinterpret_cast<uv_handle_t*>(&async));
268
269
2
    return napi_ok;
270
  }
271
272
  napi_status Ref() {
273
    uv_ref(reinterpret_cast<uv_handle_t*>(&async));
274
275
    return napi_ok;
276
  }
277
278
16
  inline void* Context() {
279
16
    return context;
280
  }
281
282
 protected:
283
8817
  void Dispatch() {
284
8817
    bool has_more = true;
285
286
    // Limit maximum synchronous iteration count to prevent event loop
287
    // starvation. See `src/node_messaging.cc` for an inspiration.
288
8817
    unsigned int iterations_left = kMaxIterationCount;
289

235113
    while (has_more && --iterations_left != 0) {
290
113148
      dispatch_state = kDispatchRunning;
291
113148
      has_more = DispatchOne();
292
293
      // Send() was called while we were executing the JS function
294
226296
      if (dispatch_state.exchange(kDispatchIdle) != kDispatchRunning) {
295
48148
        has_more = true;
296
      }
297
    }
298
299
8817
    if (has_more) {
300
42
      Send();
301
    }
302
8817
  }
303
304
113148
  bool DispatchOne() {
305
113148
    void* data = nullptr;
306
113148
    bool popped_value = false;
307
113148
    bool has_more = false;
308
309
    {
310
226296
      node::Mutex::ScopedLock lock(this->mutex);
311
113148
      if (is_closing) {
312
3
        CloseHandlesAndMaybeDelete();
313
      } else {
314
113145
        size_t size = queue.size();
315
113145
        if (size > 0) {
316
113134
          data = queue.front();
317
113134
          queue.pop();
318
113134
          popped_value = true;
319

113134
          if (size == max_queue_size && max_queue_size > 0) {
320
51259
            cond->Signal(lock);
321
          }
322
113134
          size--;
323
        }
324
325
113145
        if (size == 0) {
326
31839
          if (thread_count == 0) {
327
13
            is_closing = true;
328
13
            if (max_queue_size > 0) {
329
9
              cond->Signal(lock);
330
            }
331
13
            CloseHandlesAndMaybeDelete();
332
          }
333
        } else {
334
81306
          has_more = true;
335
        }
336
      }
337
    }
338
339
113148
    if (popped_value) {
340
226268
      v8::HandleScope scope(env->isolate);
341
226268
      CallbackScope cb_scope(this);
342
113134
      napi_value js_callback = nullptr;
343
226268
      if (!ref.IsEmpty()) {
344
        v8::Local<v8::Function> js_cb =
345
206264
          v8::Local<v8::Function>::New(env->isolate, ref);
346
103132
        js_callback = v8impl::JsValueFromV8LocalValue(js_cb);
347
      }
348
339402
      env->CallIntoModule([&](napi_env env) {
349
113134
        call_js_cb(env, js_callback, context, data);
350
226268
      });
351
    }
352
353
113148
    return has_more;
354
  }
355
356
18
  void Finalize() {
357
36
    v8::HandleScope scope(env->isolate);
358
18
    if (finalize_cb) {
359
36
      CallbackScope cb_scope(this);
360
54
      env->CallIntoModule([&](napi_env env) {
361
18
        finalize_cb(env, finalize_data, context);
362
36
      });
363
    }
364
18
    EmptyQueueAndDelete();
365
18
  }
366
367
18
  void CloseHandlesAndMaybeDelete(bool set_closing = false) {
368
36
    v8::HandleScope scope(env->isolate);
369
18
    if (set_closing) {
370
4
      node::Mutex::ScopedLock lock(this->mutex);
371
2
      is_closing = true;
372
2
      if (max_queue_size > 0) {
373
1
        cond->Signal(lock);
374
      }
375
    }
376
18
    if (handles_closing) {
377
      return;
378
    }
379
18
    handles_closing = true;
380
36
    env->node_env()->CloseHandle(
381
18
        reinterpret_cast<uv_handle_t*>(&async),
382
18
        [](uv_handle_t* handle) -> void {
383
          ThreadSafeFunction* ts_fn =
384
36
              node::ContainerOf(&ThreadSafeFunction::async,
385
18
                                reinterpret_cast<uv_async_t*>(handle));
386
18
          ts_fn->Finalize();
387
36
        });
388
  }
389
390
113199
  void Send() {
391
    // Ask currently running Dispatch() to make one more iteration
392
226398
    unsigned char current_state = dispatch_state.fetch_or(kDispatchPending);
393
113199
    if ((current_state & kDispatchRunning) == kDispatchRunning) {
394
76669
      return;
395
    }
396
397
36530
    CHECK_EQ(0, uv_async_send(&async));
398
  }
399
400
  // Default way of calling into JavaScript. Used when ThreadSafeFunction is
401
  //  without a call_js_cb_.
402
10000
  static void CallJs(napi_env env, napi_value cb, void* context, void* data) {
403

10000
    if (!(env == nullptr || cb == nullptr)) {
404
      napi_value recv;
405
      napi_status status;
406
407
10000
      status = napi_get_undefined(env, &recv);
408
10000
      if (status != napi_ok) {
409
        napi_throw_error(env, "ERR_NAPI_TSFN_GET_UNDEFINED",
410
            "Failed to retrieve undefined value");
411
        return;
412
      }
413
414
10000
      status = napi_call_function(env, recv, cb, 0, nullptr, nullptr);
415

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

425
  if (module->ToObject(context).ToLocal(&modobj) &&
604

425
      modobj->Get(context, node_env->filename_string()).ToLocal(&filename_js) &&
605
170
      filename_js->IsString()) {
606
166
    node::Utf8Value filename(node_env->isolate(), filename_js);  // Cast
607
608
    // Turn the absolute path into a URL. Currently the absolute path is always
609
    // a file system path.
610
    // TODO(gabrielschulhof): Pass the `filename` through unchanged if/when we
611
    // receive it as a URL already.
612
83
    module_filename = std::string("file://") + (*filename);
613
  }
614
615
  // Create a new napi_env for this specific module.
616
85
  napi_env env = v8impl::NewEnv(context, module_filename);
617
618
  napi_value _exports;
619
255
  env->CallIntoModule([&](napi_env env) {
620
170
    _exports = init(env, v8impl::JsValueFromV8LocalValue(exports));
621
170
  });
622
623
  // If register function returned a non-null exports object different from
624
  // the exports object we passed it, set that as the "exports" property of
625
  // the module.
626

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


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

44
    CHECK_TO_OBJECT(env, context, v8_resource, async_resource);
827
11
    externally_managed_resource = true;
828
  } else {
829
2
    v8_resource = v8::Object::New(isolate);
830
2
    externally_managed_resource = false;
831
  }
832
833
  v8::Local<v8::String> v8_resource_name;
834

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


75
  NAPI_PREAMBLE(env);
868
25
  CHECK_ARG(env, recv);
869
25
  if (argc > 0) {
870
4
    CHECK_ARG(env, argv);
871
  }
872
873
25
  v8::Local<v8::Context> context = env->context();
874
875
  v8::Local<v8::Object> v8recv;
876

100
  CHECK_TO_OBJECT(env, context, v8recv, recv);
877
878
  v8::Local<v8::Function> v8func;
879

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


3
  NAPI_PREAMBLE(env);
919
1
  CHECK_ARG(env, result);
920
921
1
  v8::MaybeLocal<v8::Object> maybe = node::Buffer::New(env->isolate, length);
922
923
1
  CHECK_MAYBE_EMPTY(env, maybe, napi_generic_failure);
924
925
1
  v8::Local<v8::Object> buffer = maybe.ToLocalChecked();
926
927
2
  *result = v8impl::JsValueFromV8LocalValue(buffer);
928
929
1
  if (data != nullptr) {
930
1
    *data = node::Buffer::Data(buffer);
931
  }
932
933
1
  return GET_RETURN_STATUS(env);
934
}
935
936
13
napi_status napi_create_external_buffer(napi_env env,
937
                                        size_t length,
938
                                        void* data,
939
                                        napi_finalize finalize_cb,
940
                                        void* finalize_hint,
941
                                        napi_value* result) {
942


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


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

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

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

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

45
    CHECK_TO_FUNCTION(env, v8_func, func);
1233
  }
1234
1235
18
  v8::Local<v8::Context> v8_context = env->context();
1236
1237
  v8::Local<v8::Object> v8_resource;
1238
18
  if (async_resource == nullptr) {
1239
18
    v8_resource = v8::Object::New(env->isolate);
1240
  } else {
1241
    CHECK_TO_OBJECT(env, v8_context, v8_resource, async_resource);
1242
  }
1243
1244
  v8::Local<v8::String> v8_name;
1245

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

14532
}