GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: node_api.cc Lines: 531 578 91.9 %
Date: 2022-03-21 03:14:50 Branches: 238 390 61.0 %

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

54
      handles_closing(false) {
141
18
    ref.Reset(env->isolate, func);
142
18
    node::AddEnvironmentCleanupHook(env->isolate, Cleanup, this);
143
18
    env->Ref();
144
18
  }
145
146
108
  ~ThreadSafeFunction() override {
147
36
    node::RemoveEnvironmentCleanupHook(env->isolate, Cleanup, this);
148
36
    env->Unref();
149
72
  }
150
151
  // These methods can be called from any thread.
152
153
2958562
  napi_status Push(void* data, napi_threadsafe_function_call_mode mode) {
154
5917124
    node::Mutex::ScopedLock lock(this->mutex);
155
156
3010527
    while (queue.size() >= max_queue_size &&
157

5906371
        max_queue_size > 0 &&
158
2895844
        !is_closing) {
159
2895841
      if (mode == napi_tsfn_nonblocking) {
160
2843876
        return napi_queue_full;
161
      }
162
51965
      cond->Wait(lock);
163
    }
164
165
114686
    if (is_closing) {
166
5
      if (thread_count == 0) {
167
        return napi_invalid_arg;
168
      } else {
169
5
        thread_count--;
170
5
        return napi_closing;
171
      }
172
    } else {
173
114681
      queue.push(data);
174
114681
      Send();
175
114681
      return napi_ok;
176
    }
177
  }
178
179
4
  napi_status Acquire() {
180
8
    node::Mutex::ScopedLock lock(this->mutex);
181
182
4
    if (is_closing) {
183
      return napi_closing;
184
    }
185
186
4
    thread_count++;
187
188
4
    return napi_ok;
189
  }
190
191
33
  napi_status Release(napi_threadsafe_function_release_mode mode) {
192
66
    node::Mutex::ScopedLock lock(this->mutex);
193
194
33
    if (thread_count == 0) {
195
      return napi_invalid_arg;
196
    }
197
198
33
    thread_count--;
199
200

33
    if (thread_count == 0 || mode == napi_tsfn_abort) {
201
16
      if (!is_closing) {
202
16
        is_closing = (mode == napi_tsfn_abort);
203

16
        if (is_closing && max_queue_size > 0) {
204
2
          cond->Signal(lock);
205
        }
206
16
        Send();
207
      }
208
    }
209
210
33
    return napi_ok;
211
  }
212
213
25
  void EmptyQueueAndDelete() {
214
25
    for (; !queue.empty() ; queue.pop()) {
215
7
      call_js_cb(nullptr, nullptr, context, queue.front());
216
    }
217
18
    delete this;
218
18
  }
219
220
  // These methods must only be called from the loop thread.
221
222
18
  napi_status Init() {
223
18
    ThreadSafeFunction* ts_fn = this;
224
18
    uv_loop_t* loop = env->node_env()->event_loop();
225
226
18
    if (uv_async_init(loop, &async, AsyncCb) == 0) {
227
18
      if (max_queue_size > 0) {
228
12
        cond = std::make_unique<node::ConditionVariable>();
229
      }
230

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

114850
    while (has_more && --iterations_left != 0) {
277
114686
      dispatch_state = kDispatchRunning;
278
114686
      has_more = DispatchOne();
279
280
      // Send() was called while we were executing the JS function
281
114686
      if (dispatch_state.exchange(kDispatchIdle) != kDispatchRunning) {
282
84889
        has_more = true;
283
      }
284
    }
285
286
164
    if (has_more) {
287
107
      Send();
288
    }
289
164
  }
290
291
114686
  bool DispatchOne() {
292
114686
    void* data = nullptr;
293
114686
    bool popped_value = false;
294
114686
    bool has_more = false;
295
296
    {
297
229372
      node::Mutex::ScopedLock lock(this->mutex);
298
114686
      if (is_closing) {
299
3
        CloseHandlesAndMaybeDelete();
300
      } else {
301
114683
        size_t size = queue.size();
302
114683
        if (size > 0) {
303
114674
          data = queue.front();
304
114674
          queue.pop();
305
114674
          popped_value = true;
306

114674
          if (size == max_queue_size && max_queue_size > 0) {
307
87633
            cond->Signal(lock);
308
          }
309
114674
          size--;
310
        }
311
312
114683
        if (size == 0) {
313
73
          if (thread_count == 0) {
314
13
            is_closing = true;
315
13
            if (max_queue_size > 0) {
316
9
              cond->Signal(lock);
317
            }
318
13
            CloseHandlesAndMaybeDelete();
319
          }
320
        } else {
321
114610
          has_more = true;
322
        }
323
      }
324
    }
325
326
114686
    if (popped_value) {
327
229348
      v8::HandleScope scope(env->isolate);
328
114674
      CallbackScope cb_scope(this);
329
114674
      napi_value js_callback = nullptr;
330
114674
      if (!ref.IsEmpty()) {
331
        v8::Local<v8::Function> js_cb =
332
209344
          v8::Local<v8::Function>::New(env->isolate, ref);
333
104672
        js_callback = v8impl::JsValueFromV8LocalValue(js_cb);
334
      }
335
114674
      env->CallIntoModule([&](napi_env env) {
336
114674
        call_js_cb(env, js_callback, context, data);
337
114674
      });
338
    }
339
340
114686
    return has_more;
341
  }
342
343
18
  void Finalize() {
344
36
    v8::HandleScope scope(env->isolate);
345
18
    if (finalize_cb) {
346
18
      CallbackScope cb_scope(this);
347
18
      env->CallIntoModule([&](napi_env env) {
348
18
        finalize_cb(env, finalize_data, context);
349
18
      });
350
    }
351
18
    EmptyQueueAndDelete();
352
18
  }
353
354
18
  void CloseHandlesAndMaybeDelete(bool set_closing = false) {
355
18
    v8::HandleScope scope(env->isolate);
356
18
    if (set_closing) {
357
4
      node::Mutex::ScopedLock lock(this->mutex);
358
2
      is_closing = true;
359
2
      if (max_queue_size > 0) {
360
1
        cond->Signal(lock);
361
      }
362
    }
363
18
    if (handles_closing) {
364
      return;
365
    }
366
18
    handles_closing = true;
367
18
    env->node_env()->CloseHandle(
368
18
        reinterpret_cast<uv_handle_t*>(&async),
369
18
        [](uv_handle_t* handle) -> void {
370
          ThreadSafeFunction* ts_fn =
371
18
              node::ContainerOf(&ThreadSafeFunction::async,
372
18
                                reinterpret_cast<uv_async_t*>(handle));
373
18
          ts_fn->Finalize();
374
18
        });
375
  }
376
377
114804
  void Send() {
378
    // Ask currently running Dispatch() to make one more iteration
379
114804
    unsigned char current_state = dispatch_state.fetch_or(kDispatchPending);
380
114804
    if ((current_state & kDispatchRunning) == kDispatchRunning) {
381
104301
      return;
382
    }
383
384
10503
    CHECK_EQ(0, uv_async_send(&async));
385
  }
386
387
  // Default way of calling into JavaScript. Used when ThreadSafeFunction is
388
  //  without a call_js_cb_.
389
10000
  static void CallJs(napi_env env, napi_value cb, void* context, void* data) {
390

10000
    if (!(env == nullptr || cb == nullptr)) {
391
      napi_value recv;
392
      napi_status status;
393
394
10000
      status = napi_get_undefined(env, &recv);
395
10000
      if (status != napi_ok) {
396
        napi_throw_error(env, "ERR_NAPI_TSFN_GET_UNDEFINED",
397
            "Failed to retrieve undefined value");
398
        return;
399
      }
400
401
10000
      status = napi_call_function(env, recv, cb, 0, nullptr, nullptr);
402

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

455
      modobj->Get(context, node_env->filename_string()).ToLocal(&filename_js) &&
592
182
      filename_js->IsString()) {
593
86
    node::Utf8Value filename(node_env->isolate(), filename_js);
594
595
    // Turn the absolute path into a URL. Currently the absolute path is always
596
    // a file system path.
597
    // TODO(gabrielschulhof): Pass the `filename` through unchanged if/when we
598
    // receive it as a URL already.
599
86
    module_filename = node::url::URL::FromFilePath(filename.ToString()).href();
600
  }
601
602
  // Create a new napi_env for this specific module.
603
91
  napi_env env = v8impl::NewEnv(context, module_filename);
604
605
  napi_value _exports;
606
91
  env->CallIntoModule([&](napi_env env) {
607
91
    _exports = init(env, v8impl::JsValueFromV8LocalValue(exports));
608
91
  });
609
610
  // If register function returned a non-null exports object different from
611
  // the exports object we passed it, set that as the "exports" property of
612
  // the module.
613
176
  if (_exports != nullptr &&
614

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


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

22
    CHECK_TO_OBJECT(env, context, v8_resource, async_resource);
814
11
    externally_managed_resource = true;
815
  } else {
816
2
    v8_resource = v8::Object::New(isolate);
817
2
    externally_managed_resource = false;
818
  }
819
820
  v8::Local<v8::String> v8_resource_name;
821

26
  CHECK_TO_STRING(env, context, v8_resource_name, async_resource_name);
822
823
  v8impl::AsyncContext* async_context =
824
      new v8impl::AsyncContext(reinterpret_cast<node_napi_env>(env),
825
                               v8_resource,
826
                               v8_resource_name,
827
13
                               externally_managed_resource);
828
829
13
  *result = reinterpret_cast<napi_async_context>(async_context);
830
831
13
  return napi_clear_last_error(env);
832
}
833
834
13
napi_status napi_async_destroy(napi_env env,
835
                               napi_async_context async_context) {
836
13
  CHECK_ENV(env);
837
13
  CHECK_ARG(env, async_context);
838
839
13
  v8impl::AsyncContext* node_async_context =
840
      reinterpret_cast<v8impl::AsyncContext*>(async_context);
841
842
13
  delete node_async_context;
843
844
13
  return napi_clear_last_error(env);
845
}
846
847
25
napi_status napi_make_callback(napi_env env,
848
                               napi_async_context async_context,
849
                               napi_value recv,
850
                               napi_value func,
851
                               size_t argc,
852
                               const napi_value* argv,
853
                               napi_value* result) {
854


50
  NAPI_PREAMBLE(env);
855
25
  CHECK_ARG(env, recv);
856
25
  if (argc > 0) {
857
4
    CHECK_ARG(env, argv);
858
  }
859
860
25
  v8::Local<v8::Context> context = env->context();
861
862
  v8::Local<v8::Object> v8recv;
863

75
  CHECK_TO_OBJECT(env, context, v8recv, recv);
864
865
  v8::Local<v8::Function> v8func;
866

75
  CHECK_TO_FUNCTION(env, v8func, func);
867
868
  v8::MaybeLocal<v8::Value> callback_result;
869
870
25
  if (async_context == nullptr) {
871
    callback_result = node::MakeCallback(
872
17
        env->isolate,
873
        v8recv,
874
        v8func,
875
        argc,
876
        reinterpret_cast<v8::Local<v8::Value>*>(const_cast<napi_value*>(argv)),
877
17
        {0, 0});
878
  } else {
879
8
    v8impl::AsyncContext* node_async_context =
880
        reinterpret_cast<v8impl::AsyncContext*>(async_context);
881
    callback_result = node_async_context->MakeCallback(
882
        v8recv,
883
        v8func,
884
        argc,
885
8
        reinterpret_cast<v8::Local<v8::Value>*>(const_cast<napi_value*>(argv)));
886
  }
887
888
25
  if (try_catch.HasCaught()) {
889
4
    return napi_set_last_error(env, napi_pending_exception);
890
  } else {
891
21
    CHECK_MAYBE_EMPTY(env, callback_result, napi_generic_failure);
892
21
    if (result != nullptr) {
893
8
      *result = v8impl::JsValueFromV8LocalValue(
894
          callback_result.ToLocalChecked());
895
    }
896
  }
897
898
21
  return GET_RETURN_STATUS(env);
899
}
900
901
1
napi_status napi_create_buffer(napi_env env,
902
                               size_t length,
903
                               void** data,
904
                               napi_value* result) {
905


2
  NAPI_PREAMBLE(env);
906
1
  CHECK_ARG(env, result);
907
908
1
  v8::MaybeLocal<v8::Object> maybe = node::Buffer::New(env->isolate, length);
909
910
1
  CHECK_MAYBE_EMPTY(env, maybe, napi_generic_failure);
911
912
1
  v8::Local<v8::Object> buffer = maybe.ToLocalChecked();
913
914
1
  *result = v8impl::JsValueFromV8LocalValue(buffer);
915
916
1
  if (data != nullptr) {
917
1
    *data = node::Buffer::Data(buffer);
918
  }
919
920
1
  return GET_RETURN_STATUS(env);
921
}
922
923
13
napi_status napi_create_external_buffer(napi_env env,
924
                                        size_t length,
925
                                        void* data,
926
                                        napi_finalize finalize_cb,
927
                                        void* finalize_hint,
928
                                        napi_value* result) {
929


26
  NAPI_PREAMBLE(env);
930
13
  CHECK_ARG(env, result);
931
932
13
  v8::Isolate* isolate = env->isolate;
933
934
  // The finalizer object will delete itself after invoking the callback.
935
13
  v8impl::Finalizer* finalizer = v8impl::Finalizer::New(
936
      env, finalize_cb, nullptr, finalize_hint,
937
      v8impl::Finalizer::kKeepEnvReference);
938
939
  v8::MaybeLocal<v8::Object> maybe = node::Buffer::New(
940
      isolate,
941
      static_cast<char*>(data),
942
      length,
943
      v8impl::BufferFinalizer::FinalizeBufferCallback,
944
13
      finalizer);
945
946
13
  CHECK_MAYBE_EMPTY(env, maybe, napi_generic_failure);
947
948
13
  *result = v8impl::JsValueFromV8LocalValue(maybe.ToLocalChecked());
949
13
  return GET_RETURN_STATUS(env);
950
  // Tell coverity that 'finalizer' should not be freed when we return
951
  // as it will be deleted when the buffer to which it is associated
952
  // is finalized.
953
  // coverity[leaked_storage]
954
}
955
956
1
napi_status napi_create_buffer_copy(napi_env env,
957
                                    size_t length,
958
                                    const void* data,
959
                                    void** result_data,
960
                                    napi_value* result) {
961


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

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

12
    CHECK_TO_OBJECT(env, context, resource, async_resource);
1136
  } else {
1137
508
    resource = v8::Object::New(env->isolate);
1138
  }
1139
1140
  v8::Local<v8::String> resource_name;
1141

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

45
    CHECK_TO_FUNCTION(env, v8_func, func);
1220
  }
1221
1222
18
  v8::Local<v8::Context> v8_context = env->context();
1223
1224
  v8::Local<v8::Object> v8_resource;
1225
18
  if (async_resource == nullptr) {
1226
18
    v8_resource = v8::Object::New(env->isolate);
1227
  } else {
1228
    CHECK_TO_OBJECT(env, v8_context, v8_resource, async_resource);
1229
  }
1230
1231
  v8::Local<v8::String> v8_name;
1232

36
  CHECK_TO_STRING(env, v8_context, v8_name, async_resource_name);
1233
1234
  v8impl::ThreadSafeFunction* ts_fn =
1235
      new v8impl::ThreadSafeFunction(v8_func,
1236
                                     v8_resource,
1237
                                     v8_name,
1238
                                     initial_thread_count,
1239
                                     context,
1240
                                     max_queue_size,
1241
                                     reinterpret_cast<node_napi_env>(env),
1242
                                     thread_finalize_data,
1243
                                     thread_finalize_cb,
1244
18
                                     call_js_cb);
1245
1246
18
  if (ts_fn == nullptr) {
1247
    status = napi_generic_failure;
1248
  } else {
1249
    // Init deletes ts_fn upon failure.
1250
18
    status = ts_fn->Init();
1251
18
    if (status == napi_ok) {
1252
18
      *result = reinterpret_cast<napi_threadsafe_function>(ts_fn);
1253
    }
1254
  }
1255
1256
18
  return napi_set_last_error(env, status);
1257
}
1258
1259
napi_status
1260
16
napi_get_threadsafe_function_context(napi_threadsafe_function func,
1261
                                     void** result) {
1262
16
  CHECK_NOT_NULL(func);
1263
16
  CHECK_NOT_NULL(result);
1264
1265
16
  *result = reinterpret_cast<v8impl::ThreadSafeFunction*>(func)->Context();
1266
16
  return napi_ok;
1267
}
1268
1269
napi_status
1270
2958562
napi_call_threadsafe_function(napi_threadsafe_function func,
1271
                              void* data,
1272
                              napi_threadsafe_function_call_mode is_blocking) {
1273
2958562
  CHECK_NOT_NULL(func);
1274
2958562
  return reinterpret_cast<v8impl::ThreadSafeFunction*>(func)->Push(data,
1275
2958562
                                                                   is_blocking);
1276
}
1277
1278
napi_status
1279
4
napi_acquire_threadsafe_function(napi_threadsafe_function func) {
1280
4
  CHECK_NOT_NULL(func);
1281
4
  return reinterpret_cast<v8impl::ThreadSafeFunction*>(func)->Acquire();
1282
}
1283
1284
napi_status
1285
33
napi_release_threadsafe_function(napi_threadsafe_function func,
1286
                                 napi_threadsafe_function_release_mode mode) {
1287
33
  CHECK_NOT_NULL(func);
1288
33
  return reinterpret_cast<v8impl::ThreadSafeFunction*>(func)->Release(mode);
1289
}
1290
1291
napi_status
1292
2
napi_unref_threadsafe_function(napi_env env, napi_threadsafe_function func) {
1293
2
  CHECK_NOT_NULL(func);
1294
2
  return reinterpret_cast<v8impl::ThreadSafeFunction*>(func)->Unref();
1295
}
1296
1297
napi_status
1298
napi_ref_threadsafe_function(napi_env env, napi_threadsafe_function func) {
1299
  CHECK_NOT_NULL(func);
1300
  return reinterpret_cast<v8impl::ThreadSafeFunction*>(func)->Ref();
1301
}
1302
1303
2
napi_status node_api_get_module_file_name(napi_env env, const char** result) {
1304
2
  CHECK_ENV(env);
1305
2
  CHECK_ARG(env, result);
1306
1307
2
  *result = static_cast<node_napi_env>(env)->GetFilename();
1308
2
  return napi_clear_last_error(env);
1309
}