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

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

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

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

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

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

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

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

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

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

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

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


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

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

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


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

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

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


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


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


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

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

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

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

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

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