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
node_napi_env__(v8::Local<v8::Context> context,const std::string & module_filename)19 node_napi_env__::node_napi_env__(v8::Local<v8::Context> context,
20 const std::string& module_filename)
21 : napi_env__(context), filename(module_filename) {
22 CHECK_NOT_NULL(node_env());
23 }
24
can_call_into_js() const25 bool node_napi_env__::can_call_into_js() const {
26 return node_env()->can_call_into_js();
27 }
28
mark_arraybuffer_as_untransferable(v8::Local<v8::ArrayBuffer> ab) const29 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
CallFinalizer(napi_finalize cb,void * data,void * hint)36 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 EnvRefHolder liveEnv(static_cast<napi_env>(this));
41 node_env()->SetImmediate(
42 [=, liveEnv = std::move(liveEnv)](node::Environment* node_env) {
43 napi_env env = liveEnv.env();
44 v8::HandleScope handle_scope(env->isolate);
45 v8::Context::Scope context_scope(env->context());
46 env->CallIntoModule([&](napi_env env) { cb(env, data, hint); });
47 });
48 }
49
50 namespace v8impl {
51
52 namespace {
53
54 class BufferFinalizer : private Finalizer {
55 public:
56 // node::Buffer::FreeCallback
FinalizeBufferCallback(char * data,void * hint)57 static void FinalizeBufferCallback(char* data, void* hint) {
58 std::unique_ptr<BufferFinalizer, Deleter> finalizer{
59 static_cast<BufferFinalizer*>(hint)};
60 finalizer->_finalize_data = data;
61
62 node::Environment* node_env =
63 static_cast<node_napi_env>(finalizer->_env)->node_env();
64 node_env->SetImmediate(
65 [finalizer = std::move(finalizer)](node::Environment* env) {
66 if (finalizer->_finalize_callback == nullptr) return;
67
68 v8::HandleScope handle_scope(finalizer->_env->isolate);
69 v8::Context::Scope context_scope(finalizer->_env->context());
70
71 finalizer->_env->CallIntoModule([&](napi_env env) {
72 finalizer->_finalize_callback(
73 env,
74 finalizer->_finalize_data,
75 finalizer->_finalize_hint);
76 });
77 });
78 }
79
80 struct Deleter {
operator ()v8impl::__anonb7e957610311::BufferFinalizer::Deleter81 void operator()(BufferFinalizer* finalizer) {
82 Finalizer::Delete(finalizer);
83 }
84 };
85 };
86
87 static inline napi_env
NewEnv(v8::Local<v8::Context> context,const std::string & module_filename)88 NewEnv(v8::Local<v8::Context> context, const std::string& module_filename) {
89 node_napi_env result;
90
91 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 result->node_env()->AddCleanupHook(
100 [](void* arg) {
101 static_cast<napi_env>(arg)->Unref();
102 },
103 static_cast<void*>(result));
104
105 return result;
106 }
107
trigger_fatal_exception(napi_env env,v8::Local<v8::Value> local_err)108 static inline void trigger_fatal_exception(
109 napi_env env, v8::Local<v8::Value> local_err) {
110 v8::Local<v8::Message> local_msg =
111 v8::Exception::CreateMessage(env->isolate, local_err);
112 node::errors::TriggerUncaughtException(env->isolate, local_err, local_msg);
113 }
114
115 class ThreadSafeFunction : public node::AsyncResource {
116 public:
ThreadSafeFunction(v8::Local<v8::Function> func,v8::Local<v8::Object> resource,v8::Local<v8::String> name,size_t thread_count_,void * context_,size_t max_queue_size_,node_napi_env env_,void * finalize_data_,napi_finalize finalize_cb_,napi_threadsafe_function_call_js call_js_cb_)117 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 napi_threadsafe_function_call_js call_js_cb_):
127 AsyncResource(env_->isolate,
128 resource,
129 *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 call_js_cb(call_js_cb_ == nullptr ? CallJs : call_js_cb_),
139 handles_closing(false) {
140 ref.Reset(env->isolate, func);
141 node::AddEnvironmentCleanupHook(env->isolate, Cleanup, this);
142 env->Ref();
143 }
144
~ThreadSafeFunction()145 ~ThreadSafeFunction() override {
146 node::RemoveEnvironmentCleanupHook(env->isolate, Cleanup, this);
147 env->Unref();
148 }
149
150 // These methods can be called from any thread.
151
Push(void * data,napi_threadsafe_function_call_mode mode)152 napi_status Push(void* data, napi_threadsafe_function_call_mode mode) {
153 node::Mutex::ScopedLock lock(this->mutex);
154
155 while (queue.size() >= max_queue_size &&
156 max_queue_size > 0 &&
157 !is_closing) {
158 if (mode == napi_tsfn_nonblocking) {
159 return napi_queue_full;
160 }
161 cond->Wait(lock);
162 }
163
164 if (is_closing) {
165 if (thread_count == 0) {
166 return napi_invalid_arg;
167 } else {
168 thread_count--;
169 return napi_closing;
170 }
171 } else {
172 queue.push(data);
173 Send();
174 return napi_ok;
175 }
176 }
177
Acquire()178 napi_status Acquire() {
179 node::Mutex::ScopedLock lock(this->mutex);
180
181 if (is_closing) {
182 return napi_closing;
183 }
184
185 thread_count++;
186
187 return napi_ok;
188 }
189
Release(napi_threadsafe_function_release_mode mode)190 napi_status Release(napi_threadsafe_function_release_mode mode) {
191 node::Mutex::ScopedLock lock(this->mutex);
192
193 if (thread_count == 0) {
194 return napi_invalid_arg;
195 }
196
197 thread_count--;
198
199 if (thread_count == 0 || mode == napi_tsfn_abort) {
200 if (!is_closing) {
201 is_closing = (mode == napi_tsfn_abort);
202 if (is_closing && max_queue_size > 0) {
203 cond->Signal(lock);
204 }
205 Send();
206 }
207 }
208
209 return napi_ok;
210 }
211
EmptyQueueAndDelete()212 void EmptyQueueAndDelete() {
213 for (; !queue.empty() ; queue.pop()) {
214 call_js_cb(nullptr, nullptr, context, queue.front());
215 }
216 delete this;
217 }
218
219 // These methods must only be called from the loop thread.
220
Init()221 napi_status Init() {
222 ThreadSafeFunction* ts_fn = this;
223 uv_loop_t* loop = env->node_env()->event_loop();
224
225 if (uv_async_init(loop, &async, AsyncCb) == 0) {
226 if (max_queue_size > 0) {
227 cond = std::make_unique<node::ConditionVariable>();
228 }
229 if (max_queue_size == 0 || cond) {
230 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
Unref()252 napi_status Unref() {
253 uv_unref(reinterpret_cast<uv_handle_t*>(&async));
254
255 return napi_ok;
256 }
257
Ref()258 napi_status Ref() {
259 uv_ref(reinterpret_cast<uv_handle_t*>(&async));
260
261 return napi_ok;
262 }
263
Context()264 inline void* Context() {
265 return context;
266 }
267
268 protected:
Dispatch()269 void Dispatch() {
270 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 unsigned int iterations_left = kMaxIterationCount;
275 while (has_more && --iterations_left != 0) {
276 dispatch_state = kDispatchRunning;
277 has_more = DispatchOne();
278
279 // Send() was called while we were executing the JS function
280 if (dispatch_state.exchange(kDispatchIdle) != kDispatchRunning) {
281 has_more = true;
282 }
283 }
284
285 if (has_more) {
286 Send();
287 }
288 }
289
DispatchOne()290 bool DispatchOne() {
291 void* data = nullptr;
292 bool popped_value = false;
293 bool has_more = false;
294
295 {
296 node::Mutex::ScopedLock lock(this->mutex);
297 if (is_closing) {
298 CloseHandlesAndMaybeDelete();
299 } else {
300 size_t size = queue.size();
301 if (size > 0) {
302 data = queue.front();
303 queue.pop();
304 popped_value = true;
305 if (size == max_queue_size && max_queue_size > 0) {
306 cond->Signal(lock);
307 }
308 size--;
309 }
310
311 if (size == 0) {
312 if (thread_count == 0) {
313 is_closing = true;
314 if (max_queue_size > 0) {
315 cond->Signal(lock);
316 }
317 CloseHandlesAndMaybeDelete();
318 }
319 } else {
320 has_more = true;
321 }
322 }
323 }
324
325 if (popped_value) {
326 v8::HandleScope scope(env->isolate);
327 CallbackScope cb_scope(this);
328 napi_value js_callback = nullptr;
329 if (!ref.IsEmpty()) {
330 v8::Local<v8::Function> js_cb =
331 v8::Local<v8::Function>::New(env->isolate, ref);
332 js_callback = v8impl::JsValueFromV8LocalValue(js_cb);
333 }
334 env->CallIntoModule([&](napi_env env) {
335 call_js_cb(env, js_callback, context, data);
336 });
337 }
338
339 return has_more;
340 }
341
Finalize()342 void Finalize() {
343 v8::HandleScope scope(env->isolate);
344 if (finalize_cb) {
345 CallbackScope cb_scope(this);
346 env->CallIntoModule([&](napi_env env) {
347 finalize_cb(env, finalize_data, context);
348 });
349 }
350 EmptyQueueAndDelete();
351 }
352
CloseHandlesAndMaybeDelete(bool set_closing=false)353 void CloseHandlesAndMaybeDelete(bool set_closing = false) {
354 v8::HandleScope scope(env->isolate);
355 if (set_closing) {
356 node::Mutex::ScopedLock lock(this->mutex);
357 is_closing = true;
358 if (max_queue_size > 0) {
359 cond->Signal(lock);
360 }
361 }
362 if (handles_closing) {
363 return;
364 }
365 handles_closing = true;
366 env->node_env()->CloseHandle(
367 reinterpret_cast<uv_handle_t*>(&async),
368 [](uv_handle_t* handle) -> void {
369 ThreadSafeFunction* ts_fn =
370 node::ContainerOf(&ThreadSafeFunction::async,
371 reinterpret_cast<uv_async_t*>(handle));
372 ts_fn->Finalize();
373 });
374 }
375
Send()376 void Send() {
377 // Ask currently running Dispatch() to make one more iteration
378 unsigned char current_state = dispatch_state.fetch_or(kDispatchPending);
379 if ((current_state & kDispatchRunning) == kDispatchRunning) {
380 return;
381 }
382
383 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_.
CallJs(napi_env env,napi_value cb,void * context,void * data)388 static void CallJs(napi_env env, napi_value cb, void* context, void* data) {
389 if (!(env == nullptr || cb == nullptr)) {
390 napi_value recv;
391 napi_status status;
392
393 status = napi_get_undefined(env, &recv);
394 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 status = napi_call_function(env, recv, cb, 0, nullptr, nullptr);
401 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
AsyncCb(uv_async_t * async)409 static void AsyncCb(uv_async_t* async) {
410 ThreadSafeFunction* ts_fn =
411 node::ContainerOf(&ThreadSafeFunction::async, async);
412 ts_fn->Dispatch();
413 }
414
Cleanup(void * data)415 static void Cleanup(void* data) {
416 reinterpret_cast<ThreadSafeFunction*>(data)
417 ->CloseHandlesAndMaybeDelete(true);
418 }
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:
AsyncContext(node_napi_env env,v8::Local<v8::Object> resource_object,const v8::Local<v8::String> resource_name,bool externally_managed_resource)458 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 : env_(env) {
463 async_id_ = node_env()->new_async_id();
464 trigger_async_id_ = node_env()->get_default_trigger_async_id();
465 resource_.Reset(node_env()->isolate(), resource_object);
466 lost_reference_ = false;
467 if (externally_managed_resource) {
468 resource_.SetWeak(
469 this, AsyncContext::WeakCallback, v8::WeakCallbackType::kParameter);
470 }
471
472 node::AsyncWrap::EmitAsyncInit(node_env(),
473 resource_object,
474 resource_name,
475 async_id_,
476 trigger_async_id_);
477 }
478
~AsyncContext()479 ~AsyncContext() {
480 resource_.Reset();
481 lost_reference_ = true;
482 node::AsyncWrap::EmitDestroy(node_env(), async_id_);
483 }
484
MakeCallback(v8::Local<v8::Object> recv,const v8::Local<v8::Function> callback,int argc,v8::Local<v8::Value> argv[])485 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 EnsureReference();
491 return node::InternalMakeCallback(node_env(),
492 resource(),
493 recv,
494 callback,
495 argc,
496 argv,
497 {async_id_, trigger_async_id_});
498 }
499
OpenCallbackScope()500 inline napi_callback_scope OpenCallbackScope() {
501 EnsureReference();
502 napi_callback_scope it =
503 reinterpret_cast<napi_callback_scope>(new CallbackScope(this));
504 env_->open_callback_scopes++;
505 return it;
506 }
507
EnsureReference()508 inline void EnsureReference() {
509 if (lost_reference_) {
510 const v8::HandleScope handle_scope(node_env()->isolate());
511 resource_.Reset(node_env()->isolate(),
512 v8::Object::New(node_env()->isolate()));
513 lost_reference_ = false;
514 }
515 }
516
node_env()517 inline node::Environment* node_env() { return env_->node_env(); }
resource()518 inline v8::Local<v8::Object> resource() {
519 return resource_.Get(node_env()->isolate());
520 }
async_context()521 inline node::async_context async_context() {
522 return {async_id_, trigger_async_id_};
523 }
524
CloseCallbackScope(node_napi_env env,napi_callback_scope s)525 static inline void CloseCallbackScope(node_napi_env env,
526 napi_callback_scope s) {
527 CallbackScope* callback_scope = reinterpret_cast<CallbackScope*>(s);
528 delete callback_scope;
529 env->open_callback_scopes--;
530 }
531
WeakCallback(const v8::WeakCallbackInfo<AsyncContext> & data)532 static void WeakCallback(const v8::WeakCallbackInfo<AsyncContext>& data) {
533 AsyncContext* async_context = data.GetParameter();
534 async_context->resource_.Reset();
535 async_context->lost_reference_ = true;
536 }
537
538 private:
539 class CallbackScope : public node::CallbackScope {
540 public:
CallbackScope(AsyncContext * async_context)541 explicit CallbackScope(AsyncContext* async_context)
542 : node::CallbackScope(async_context->node_env(),
543 async_context->resource_.Get(
544 async_context->node_env()->isolate()),
545 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.
napi_module_register_cb(v8::Local<v8::Object> exports,v8::Local<v8::Value> module,v8::Local<v8::Context> context,void * priv)562 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 napi_module_register_by_symbol(exports, module, context,
567 static_cast<const napi_module*>(priv)->nm_register_func);
568 }
569
napi_module_register_by_symbol(v8::Local<v8::Object> exports,v8::Local<v8::Value> module,v8::Local<v8::Context> context,napi_addon_register_func init)570 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 node::Environment* node_env = node::Environment::GetCurrent(context);
575 std::string module_filename = "";
576 if (init == nullptr) {
577 CHECK_NOT_NULL(node_env);
578 node_env->ThrowError(
579 "Module has no declared entry point.");
580 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 if (module->ToObject(context).ToLocal(&modobj) &&
590 modobj->Get(context, node_env->filename_string()).ToLocal(&filename_js) &&
591 filename_js->IsString()) {
592 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 module_filename = std::string("file://") + (*filename);
599 }
600
601 // Create a new napi_env for this specific module.
602 napi_env env = v8impl::NewEnv(context, module_filename);
603
604 napi_value _exports;
605 env->CallIntoModule([&](napi_env env) {
606 _exports = init(env, v8impl::JsValueFromV8LocalValue(exports));
607 });
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 if (_exports != nullptr &&
613 _exports != v8impl::JsValueFromV8LocalValue(exports)) {
614 napi_value _module = v8impl::JsValueFromV8LocalValue(module);
615 napi_set_named_property(env, _module, "exports", _exports);
616 }
617 }
618
619 namespace node {
napi_module_to_node_module(const napi_module * mod)620 node_module napi_module_to_node_module(const napi_module* mod) {
621 return {
622 -1,
623 mod->nm_flags | NM_F_DELETEME,
624 nullptr,
625 mod->nm_filename,
626 nullptr,
627 napi_module_register_cb,
628 mod->nm_modname,
629 const_cast<napi_module*>(mod), // priv
630 nullptr,
631 };
632 }
633 } // namespace node
634
635 // Registers a NAPI module.
napi_module_register(napi_module * mod)636 void napi_module_register(napi_module* mod) {
637 node::node_module* nm = new node::node_module(
638 node::napi_module_to_node_module(mod));
639 node::node_module_register(nm);
640 }
641
napi_add_env_cleanup_hook(napi_env env,void (* fun)(void * arg),void * arg)642 napi_status napi_add_env_cleanup_hook(napi_env env,
643 void (*fun)(void* arg),
644 void* arg) {
645 CHECK_ENV(env);
646 CHECK_ARG(env, fun);
647
648 node::AddEnvironmentCleanupHook(env->isolate, fun, arg);
649
650 return napi_ok;
651 }
652
napi_remove_env_cleanup_hook(napi_env env,void (* fun)(void * arg),void * arg)653 napi_status napi_remove_env_cleanup_hook(napi_env env,
654 void (*fun)(void* arg),
655 void* arg) {
656 CHECK_ENV(env);
657 CHECK_ARG(env, fun);
658
659 node::RemoveEnvironmentCleanupHook(env->isolate, fun, arg);
660
661 return napi_ok;
662 }
663
664 struct napi_async_cleanup_hook_handle__ {
napi_async_cleanup_hook_handle__napi_async_cleanup_hook_handle__665 napi_async_cleanup_hook_handle__(napi_env env,
666 napi_async_cleanup_hook user_hook,
667 void* user_data):
668 env_(env),
669 user_hook_(user_hook),
670 user_data_(user_data) {
671 handle_ = node::AddEnvironmentCleanupHook(env->isolate, Hook, this);
672 env->Ref();
673 }
674
~napi_async_cleanup_hook_handle__napi_async_cleanup_hook_handle__675 ~napi_async_cleanup_hook_handle__() {
676 node::RemoveEnvironmentCleanupHook(std::move(handle_));
677 if (done_cb_ != nullptr)
678 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 static_cast<node_napi_env>(env_)->node_env()
683 ->SetImmediate([env = env_](node::Environment*) { env->Unref(); });
684 }
685
Hooknapi_async_cleanup_hook_handle__686 static void Hook(void* data, void (*done_cb)(void*), void* done_data) {
687 napi_async_cleanup_hook_handle__* handle =
688 static_cast<napi_async_cleanup_hook_handle__*>(data);
689 handle->done_cb_ = done_cb;
690 handle->done_data_ = done_data;
691 handle->user_hook_(handle, handle->user_data_);
692 }
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
napi_add_async_cleanup_hook(napi_env env,napi_async_cleanup_hook hook,void * arg,napi_async_cleanup_hook_handle * remove_handle)702 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 CHECK_ENV(env);
708 CHECK_ARG(env, hook);
709
710 napi_async_cleanup_hook_handle__* handle =
711 new napi_async_cleanup_hook_handle__(env, hook, arg);
712
713 if (remove_handle != nullptr)
714 *remove_handle = handle;
715
716 return napi_clear_last_error(env);
717 }
718
napi_remove_async_cleanup_hook(napi_async_cleanup_hook_handle remove_handle)719 napi_status napi_remove_async_cleanup_hook(
720 napi_async_cleanup_hook_handle remove_handle) {
721
722 if (remove_handle == nullptr)
723 return napi_invalid_arg;
724
725 delete remove_handle;
726
727 return napi_ok;
728 }
729
napi_fatal_exception(napi_env env,napi_value err)730 napi_status napi_fatal_exception(napi_env env, napi_value err) {
731 NAPI_PREAMBLE(env);
732 CHECK_ARG(env, err);
733
734 v8::Local<v8::Value> local_err = v8impl::V8LocalValueFromJsValue(err);
735 v8impl::trigger_fatal_exception(env, local_err);
736
737 return napi_clear_last_error(env);
738 }
739
napi_fatal_error(const char * location,size_t location_len,const char * message,size_t message_len)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
napi_open_callback_scope(napi_env env,napi_value,napi_async_context async_context_handle,napi_callback_scope * result)766 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 CHECK_ENV(env);
773 CHECK_ARG(env, result);
774
775 v8impl::AsyncContext* node_async_context =
776 reinterpret_cast<v8impl::AsyncContext*>(async_context_handle);
777
778 *result = node_async_context->OpenCallbackScope();
779
780 return napi_clear_last_error(env);
781 }
782
napi_close_callback_scope(napi_env env,napi_callback_scope scope)783 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 CHECK_ENV(env);
787 CHECK_ARG(env, scope);
788 if (env->open_callback_scopes == 0) {
789 return napi_callback_scope_mismatch;
790 }
791
792 v8impl::AsyncContext::CloseCallbackScope(reinterpret_cast<node_napi_env>(env),
793 scope);
794
795 return napi_clear_last_error(env);
796 }
797
napi_async_init(napi_env env,napi_value async_resource,napi_value async_resource_name,napi_async_context * result)798 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 CHECK_ENV(env);
803 CHECK_ARG(env, async_resource_name);
804 CHECK_ARG(env, result);
805
806 v8::Isolate* isolate = env->isolate;
807 v8::Local<v8::Context> context = env->context();
808
809 v8::Local<v8::Object> v8_resource;
810 bool externally_managed_resource;
811 if (async_resource != nullptr) {
812 CHECK_TO_OBJECT(env, context, v8_resource, async_resource);
813 externally_managed_resource = true;
814 } else {
815 v8_resource = v8::Object::New(isolate);
816 externally_managed_resource = false;
817 }
818
819 v8::Local<v8::String> v8_resource_name;
820 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 externally_managed_resource);
827
828 *result = reinterpret_cast<napi_async_context>(async_context);
829
830 return napi_clear_last_error(env);
831 }
832
napi_async_destroy(napi_env env,napi_async_context async_context)833 napi_status napi_async_destroy(napi_env env,
834 napi_async_context async_context) {
835 CHECK_ENV(env);
836 CHECK_ARG(env, async_context);
837
838 v8impl::AsyncContext* node_async_context =
839 reinterpret_cast<v8impl::AsyncContext*>(async_context);
840
841 delete node_async_context;
842
843 return napi_clear_last_error(env);
844 }
845
napi_make_callback(napi_env env,napi_async_context async_context,napi_value recv,napi_value func,size_t argc,const napi_value * argv,napi_value * result)846 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 NAPI_PREAMBLE(env);
854 CHECK_ARG(env, recv);
855 if (argc > 0) {
856 CHECK_ARG(env, argv);
857 }
858
859 v8::Local<v8::Context> context = env->context();
860
861 v8::Local<v8::Object> v8recv;
862 CHECK_TO_OBJECT(env, context, v8recv, recv);
863
864 v8::Local<v8::Function> v8func;
865 CHECK_TO_FUNCTION(env, v8func, func);
866
867 v8::MaybeLocal<v8::Value> callback_result;
868
869 if (async_context == nullptr) {
870 callback_result = node::MakeCallback(
871 env->isolate,
872 v8recv,
873 v8func,
874 argc,
875 reinterpret_cast<v8::Local<v8::Value>*>(const_cast<napi_value*>(argv)),
876 {0, 0});
877 } else {
878 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 reinterpret_cast<v8::Local<v8::Value>*>(const_cast<napi_value*>(argv)));
885 }
886
887 if (try_catch.HasCaught()) {
888 return napi_set_last_error(env, napi_pending_exception);
889 } else {
890 CHECK_MAYBE_EMPTY(env, callback_result, napi_generic_failure);
891 if (result != nullptr) {
892 *result = v8impl::JsValueFromV8LocalValue(
893 callback_result.ToLocalChecked());
894 }
895 }
896
897 return GET_RETURN_STATUS(env);
898 }
899
napi_create_buffer(napi_env env,size_t length,void ** data,napi_value * result)900 napi_status napi_create_buffer(napi_env env,
901 size_t length,
902 void** data,
903 napi_value* result) {
904 NAPI_PREAMBLE(env);
905 CHECK_ARG(env, result);
906
907 v8::MaybeLocal<v8::Object> maybe = node::Buffer::New(env->isolate, length);
908
909 CHECK_MAYBE_EMPTY(env, maybe, napi_generic_failure);
910
911 v8::Local<v8::Object> buffer = maybe.ToLocalChecked();
912
913 *result = v8impl::JsValueFromV8LocalValue(buffer);
914
915 if (data != nullptr) {
916 *data = node::Buffer::Data(buffer);
917 }
918
919 return GET_RETURN_STATUS(env);
920 }
921
napi_create_external_buffer(napi_env env,size_t length,void * data,napi_finalize finalize_cb,void * finalize_hint,napi_value * result)922 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 NAPI_PREAMBLE(env);
929 CHECK_ARG(env, result);
930
931 v8::Isolate* isolate = env->isolate;
932
933 // The finalizer object will delete itself after invoking the callback.
934 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 finalizer);
944
945 CHECK_MAYBE_EMPTY(env, maybe, napi_generic_failure);
946
947 *result = v8impl::JsValueFromV8LocalValue(maybe.ToLocalChecked());
948 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
napi_create_buffer_copy(napi_env env,size_t length,const void * data,void ** result_data,napi_value * result)955 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 NAPI_PREAMBLE(env);
961 CHECK_ARG(env, result);
962
963 v8::MaybeLocal<v8::Object> maybe = node::Buffer::Copy(
964 env->isolate,
965 static_cast<const char*>(data), length);
966
967 CHECK_MAYBE_EMPTY(env, maybe, napi_generic_failure);
968
969 v8::Local<v8::Object> buffer = maybe.ToLocalChecked();
970 *result = v8impl::JsValueFromV8LocalValue(buffer);
971
972 if (result_data != nullptr) {
973 *result_data = node::Buffer::Data(buffer);
974 }
975
976 return GET_RETURN_STATUS(env);
977 }
978
napi_is_buffer(napi_env env,napi_value value,bool * result)979 napi_status napi_is_buffer(napi_env env, napi_value value, bool* result) {
980 CHECK_ENV(env);
981 CHECK_ARG(env, value);
982 CHECK_ARG(env, result);
983
984 *result = node::Buffer::HasInstance(v8impl::V8LocalValueFromJsValue(value));
985 return napi_clear_last_error(env);
986 }
987
napi_get_buffer_info(napi_env env,napi_value value,void ** data,size_t * length)988 napi_status napi_get_buffer_info(napi_env env,
989 napi_value value,
990 void** data,
991 size_t* length) {
992 CHECK_ENV(env);
993 CHECK_ARG(env, value);
994
995 v8::Local<v8::Value> buffer = v8impl::V8LocalValueFromJsValue(value);
996
997 if (data != nullptr) {
998 *data = node::Buffer::Data(buffer);
999 }
1000 if (length != nullptr) {
1001 *length = node::Buffer::Length(buffer);
1002 }
1003
1004 return napi_clear_last_error(env);
1005 }
1006
napi_get_node_version(napi_env env,const napi_node_version ** result)1007 napi_status napi_get_node_version(napi_env env,
1008 const napi_node_version** result) {
1009 CHECK_ENV(env);
1010 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 *result = &version;
1018 return napi_clear_last_error(env);
1019 }
1020
1021 namespace {
1022 namespace uvimpl {
1023
ConvertUVErrorCode(int code)1024 static napi_status ConvertUVErrorCode(int code) {
1025 switch (code) {
1026 case 0:
1027 return napi_ok;
1028 case UV_EINVAL:
1029 return napi_invalid_arg;
1030 case UV_ECANCELED:
1031 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:
Work(node_napi_env env,v8::Local<v8::Object> async_resource,v8::Local<v8::String> async_resource_name,napi_async_execute_callback execute,napi_async_complete_callback complete=nullptr,void * data=nullptr)1040 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 : AsyncResource(env->isolate,
1047 async_resource,
1048 *v8::String::Utf8Value(env->isolate, async_resource_name)),
1049 ThreadPoolWork(env->node_env()),
1050 _env(env),
1051 _data(data),
1052 _execute(execute),
1053 _complete(complete) {
1054 }
1055
1056 ~Work() override = default;
1057
1058 public:
New(node_napi_env env,v8::Local<v8::Object> async_resource,v8::Local<v8::String> async_resource_name,napi_async_execute_callback execute,napi_async_complete_callback complete,void * data)1059 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 execute, complete, data);
1067 }
1068
Delete(Work * work)1069 static void Delete(Work* work) {
1070 delete work;
1071 }
1072
DoThreadPoolWork()1073 void DoThreadPoolWork() override {
1074 _execute(_env, _data);
1075 }
1076
AfterThreadPoolWork(int status)1077 void AfterThreadPoolWork(int status) override {
1078 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 v8::HandleScope scope(_env->isolate);
1084
1085 CallbackScope callback_scope(this);
1086
1087 _env->CallIntoModule([&](napi_env env) {
1088 _complete(env, ConvertUVErrorCode(status), _data);
1089 }, [](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 v8impl::trigger_fatal_exception(env, local_err);
1094 });
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
napi_create_async_work(napi_env env,napi_value async_resource,napi_value async_resource_name,napi_async_execute_callback execute,napi_async_complete_callback complete,void * data,napi_async_work * result)1119 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 CHECK_ENV(env);
1127 CHECK_ARG(env, execute);
1128 CHECK_ARG(env, result);
1129
1130 v8::Local<v8::Context> context = env->context();
1131
1132 v8::Local<v8::Object> resource;
1133 if (async_resource != nullptr) {
1134 CHECK_TO_OBJECT(env, context, resource, async_resource);
1135 } else {
1136 resource = v8::Object::New(env->isolate);
1137 }
1138
1139 v8::Local<v8::String> resource_name;
1140 CHECK_TO_STRING(env, context, resource_name, async_resource_name);
1141
1142 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 *result = reinterpret_cast<napi_async_work>(work);
1150
1151 return napi_clear_last_error(env);
1152 }
1153
napi_delete_async_work(napi_env env,napi_async_work work)1154 napi_status napi_delete_async_work(napi_env env, napi_async_work work) {
1155 CHECK_ENV(env);
1156 CHECK_ARG(env, work);
1157
1158 uvimpl::Work::Delete(reinterpret_cast<uvimpl::Work*>(work));
1159
1160 return napi_clear_last_error(env);
1161 }
1162
napi_get_uv_event_loop(napi_env env,uv_loop_t ** loop)1163 napi_status napi_get_uv_event_loop(napi_env env, uv_loop_t** loop) {
1164 CHECK_ENV(env);
1165 CHECK_ARG(env, loop);
1166 *loop = reinterpret_cast<node_napi_env>(env)->node_env()->event_loop();
1167 return napi_clear_last_error(env);
1168 }
1169
napi_queue_async_work(napi_env env,napi_async_work work)1170 napi_status napi_queue_async_work(napi_env env, napi_async_work work) {
1171 CHECK_ENV(env);
1172 CHECK_ARG(env, work);
1173
1174 uv_loop_t* event_loop = nullptr;
1175 STATUS_CALL(napi_get_uv_event_loop(env, &event_loop));
1176
1177 uvimpl::Work* w = reinterpret_cast<uvimpl::Work*>(work);
1178
1179 w->ScheduleWork();
1180
1181 return napi_clear_last_error(env);
1182 }
1183
napi_cancel_async_work(napi_env env,napi_async_work work)1184 napi_status napi_cancel_async_work(napi_env env, napi_async_work work) {
1185 CHECK_ENV(env);
1186 CHECK_ARG(env, work);
1187
1188 uvimpl::Work* w = reinterpret_cast<uvimpl::Work*>(work);
1189
1190 CALL_UV(env, w->CancelWork());
1191
1192 return napi_clear_last_error(env);
1193 }
1194
1195 napi_status
napi_create_threadsafe_function(napi_env env,napi_value func,napi_value async_resource,napi_value async_resource_name,size_t max_queue_size,size_t initial_thread_count,void * thread_finalize_data,napi_finalize thread_finalize_cb,void * context,napi_threadsafe_function_call_js call_js_cb,napi_threadsafe_function * result)1196 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 CHECK_ENV(env);
1208 CHECK_ARG(env, async_resource_name);
1209 RETURN_STATUS_IF_FALSE(env, initial_thread_count > 0, napi_invalid_arg);
1210 CHECK_ARG(env, result);
1211
1212 napi_status status = napi_ok;
1213
1214 v8::Local<v8::Function> v8_func;
1215 if (func == nullptr) {
1216 CHECK_ARG(env, call_js_cb);
1217 } else {
1218 CHECK_TO_FUNCTION(env, v8_func, func);
1219 }
1220
1221 v8::Local<v8::Context> v8_context = env->context();
1222
1223 v8::Local<v8::Object> v8_resource;
1224 if (async_resource == nullptr) {
1225 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 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 call_js_cb);
1244
1245 if (ts_fn == nullptr) {
1246 status = napi_generic_failure;
1247 } else {
1248 // Init deletes ts_fn upon failure.
1249 status = ts_fn->Init();
1250 if (status == napi_ok) {
1251 *result = reinterpret_cast<napi_threadsafe_function>(ts_fn);
1252 }
1253 }
1254
1255 return napi_set_last_error(env, status);
1256 }
1257
1258 napi_status
napi_get_threadsafe_function_context(napi_threadsafe_function func,void ** result)1259 napi_get_threadsafe_function_context(napi_threadsafe_function func,
1260 void** result) {
1261 CHECK_NOT_NULL(func);
1262 CHECK_NOT_NULL(result);
1263
1264 *result = reinterpret_cast<v8impl::ThreadSafeFunction*>(func)->Context();
1265 return napi_ok;
1266 }
1267
1268 napi_status
napi_call_threadsafe_function(napi_threadsafe_function func,void * data,napi_threadsafe_function_call_mode is_blocking)1269 napi_call_threadsafe_function(napi_threadsafe_function func,
1270 void* data,
1271 napi_threadsafe_function_call_mode is_blocking) {
1272 CHECK_NOT_NULL(func);
1273 return reinterpret_cast<v8impl::ThreadSafeFunction*>(func)->Push(data,
1274 is_blocking);
1275 }
1276
1277 napi_status
napi_acquire_threadsafe_function(napi_threadsafe_function func)1278 napi_acquire_threadsafe_function(napi_threadsafe_function func) {
1279 CHECK_NOT_NULL(func);
1280 return reinterpret_cast<v8impl::ThreadSafeFunction*>(func)->Acquire();
1281 }
1282
1283 napi_status
napi_release_threadsafe_function(napi_threadsafe_function func,napi_threadsafe_function_release_mode mode)1284 napi_release_threadsafe_function(napi_threadsafe_function func,
1285 napi_threadsafe_function_release_mode mode) {
1286 CHECK_NOT_NULL(func);
1287 return reinterpret_cast<v8impl::ThreadSafeFunction*>(func)->Release(mode);
1288 }
1289
1290 napi_status
napi_unref_threadsafe_function(napi_env env,napi_threadsafe_function func)1291 napi_unref_threadsafe_function(napi_env env, napi_threadsafe_function func) {
1292 CHECK_NOT_NULL(func);
1293 return reinterpret_cast<v8impl::ThreadSafeFunction*>(func)->Unref();
1294 }
1295
1296 napi_status
napi_ref_threadsafe_function(napi_env env,napi_threadsafe_function func)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
node_api_get_module_file_name(napi_env env,const char ** result)1302 napi_status node_api_get_module_file_name(napi_env env, const char** result) {
1303 CHECK_ENV(env);
1304 CHECK_ARG(env, result);
1305
1306 *result = static_cast<node_napi_env>(env)->GetFilename();
1307 return napi_clear_last_error(env);
1308 }
1309