1818#include < type_traits>
1919#include < utility>
2020
21+ // TODO(gabrielschulhof): Remove this and remove the wrapping at the call sites
22+ // (i.e., at the call site, `TSFN_FINALIZER(x)` should be changed back to `x`)
23+ // after https://github.com/nodejs/node/pull/51801 has landed.
24+ #if (defined(NAPI_EXPERIMENTAL) && \
25+ defined (NODE_API_EXPERIMENTAL_HAS_POST_FINALIZER))
26+ #define TSFN_FINALIZER (fini ) reinterpret_cast <node_api_nogc_finalize>(fini)
27+ #else
28+ #define TSFN_FINALIZER (fini ) fini
29+ #endif
30+
2131namespace Napi {
2232
2333#ifdef NAPI_CPP_CUSTOM_NAMESPACE
@@ -31,6 +41,23 @@ namespace details {
3141// Node.js releases. Only necessary when they are used in napi.h and napi-inl.h.
3242constexpr int napi_no_external_buffers_allowed = 22 ;
3343
44+ #if (defined(NAPI_EXPERIMENTAL) && \
45+ defined (NODE_API_EXPERIMENTAL_HAS_POST_FINALIZER))
46+ template <napi_finalize finalizer>
47+ inline void PostFinalizerWrapper(node_api_nogc_env nogc_env,
48+ void * data,
49+ void * hint) {
50+ napi_status status = node_api_post_finalizer (nogc_env, finalizer, data, hint);
51+ NAPI_FATAL_IF_FAILED (
52+ status, " PostFinalizerWrapper" , " node_api_post_finalizer failed" );
53+ }
54+ #else
55+ template <napi_finalize finalizer>
56+ inline void PostFinalizerWrapper (napi_env env, void * data, void * hint) {
57+ finalizer (env, data, hint);
58+ }
59+ #endif
60+
3461template <typename FreeType>
3562inline void default_finalizer (napi_env /* env*/ , void * data, void * /* hint*/ ) {
3663 delete static_cast <FreeType*>(data);
@@ -65,7 +92,8 @@ inline napi_status AttachData(napi_env env,
6592 }
6693 }
6794#else // NAPI_VERSION >= 5
68- status = napi_add_finalizer (env, obj, data, finalizer, hint, nullptr );
95+ status = napi_add_finalizer (
96+ env, obj, data, details::PostFinalizerWrapper<finalizer>, hint, nullptr );
6997#endif
7098 return status;
7199}
@@ -1774,7 +1802,8 @@ inline External<T> External<T>::New(napi_env env,
17741802 napi_status status =
17751803 napi_create_external (env,
17761804 data,
1777- details::FinalizeData<T, Finalizer>::Wrapper,
1805+ details::PostFinalizerWrapper<
1806+ details::FinalizeData<T, Finalizer>::Wrapper>,
17781807 finalizeData,
17791808 &value);
17801809 if (status != napi_ok) {
@@ -1797,7 +1826,8 @@ inline External<T> External<T>::New(napi_env env,
17971826 napi_status status = napi_create_external (
17981827 env,
17991828 data,
1800- details::FinalizeData<T, Finalizer, Hint>::WrapperWithHint,
1829+ details::PostFinalizerWrapper<
1830+ details::FinalizeData<T, Finalizer, Hint>::WrapperWithHint>,
18011831 finalizeData,
18021832 &value);
18031833 if (status != napi_ok) {
@@ -1910,7 +1940,8 @@ inline ArrayBuffer ArrayBuffer::New(napi_env env,
19101940 env,
19111941 externalData,
19121942 byteLength,
1913- details::FinalizeData<void , Finalizer>::Wrapper,
1943+ details::PostFinalizerWrapper<
1944+ details::FinalizeData<void , Finalizer>::Wrapper>,
19141945 finalizeData,
19151946 &value);
19161947 if (status != napi_ok) {
@@ -1935,7 +1966,8 @@ inline ArrayBuffer ArrayBuffer::New(napi_env env,
19351966 env,
19361967 externalData,
19371968 byteLength,
1938- details::FinalizeData<void , Finalizer, Hint>::WrapperWithHint,
1969+ details::PostFinalizerWrapper<
1970+ details::FinalizeData<void , Finalizer, Hint>::WrapperWithHint>,
19391971 finalizeData,
19401972 &value);
19411973 if (status != napi_ok) {
@@ -2652,13 +2684,14 @@ inline Buffer<T> Buffer<T>::New(napi_env env,
26522684 details::FinalizeData<T, Finalizer>* finalizeData =
26532685 new details::FinalizeData<T, Finalizer>(
26542686 {std::move (finalizeCallback), nullptr });
2655- napi_status status =
2656- napi_create_external_buffer (env,
2657- length * sizeof (T),
2658- data,
2659- details::FinalizeData<T, Finalizer>::Wrapper,
2660- finalizeData,
2661- &value);
2687+ napi_status status = napi_create_external_buffer (
2688+ env,
2689+ length * sizeof (T),
2690+ data,
2691+ details::PostFinalizerWrapper<
2692+ details::FinalizeData<T, Finalizer>::Wrapper>,
2693+ finalizeData,
2694+ &value);
26622695 if (status != napi_ok) {
26632696 delete finalizeData;
26642697 NAPI_THROW_IF_FAILED (env, status, Buffer ());
@@ -2681,7 +2714,8 @@ inline Buffer<T> Buffer<T>::New(napi_env env,
26812714 env,
26822715 length * sizeof (T),
26832716 data,
2684- details::FinalizeData<T, Finalizer, Hint>::WrapperWithHint,
2717+ details::PostFinalizerWrapper<
2718+ details::FinalizeData<T, Finalizer, Hint>::WrapperWithHint>,
26852719 finalizeData,
26862720 &value);
26872721 if (status != napi_ok) {
@@ -2720,13 +2754,14 @@ inline Buffer<T> Buffer<T>::NewOrCopy(napi_env env,
27202754 {std::move (finalizeCallback), nullptr });
27212755#ifndef NODE_API_NO_EXTERNAL_BUFFERS_ALLOWED
27222756 napi_value value;
2723- napi_status status =
2724- napi_create_external_buffer (env,
2725- length * sizeof (T),
2726- data,
2727- details::FinalizeData<T, Finalizer>::Wrapper,
2728- finalizeData,
2729- &value);
2757+ napi_status status = napi_create_external_buffer (
2758+ env,
2759+ length * sizeof (T),
2760+ data,
2761+ details::PostFinalizerWrapper<
2762+ details::FinalizeData<T, Finalizer>::Wrapper>,
2763+ finalizeData,
2764+ &value);
27302765 if (status == details::napi_no_external_buffers_allowed) {
27312766#endif // NODE_API_NO_EXTERNAL_BUFFERS_ALLOWED
27322767 // If we can't create an external buffer, we'll just copy the data.
@@ -2759,7 +2794,8 @@ inline Buffer<T> Buffer<T>::NewOrCopy(napi_env env,
27592794 env,
27602795 length * sizeof (T),
27612796 data,
2762- details::FinalizeData<T, Finalizer, Hint>::WrapperWithHint,
2797+ details::PostFinalizerWrapper<
2798+ details::FinalizeData<T, Finalizer, Hint>::WrapperWithHint>,
27632799 finalizeData,
27642800 &value);
27652801 if (status == details::napi_no_external_buffers_allowed) {
@@ -3054,7 +3090,12 @@ inline void Error::ThrowAsJavaScriptException() const {
30543090
30553091 status = napi_throw (_env, Value ());
30563092
3057- if (status == napi_pending_exception) {
3093+ #ifdef NAPI_EXPERIMENTAL
3094+ napi_status expected_failure_mode = napi_cannot_run_js;
3095+ #else
3096+ napi_status expected_failure_mode = napi_pending_exception;
3097+ #endif
3098+ if (status == expected_failure_mode) {
30583099 // The environment must be terminating as we checked earlier and there
30593100 // was no pending exception. In this case continuing will result
30603101 // in a fatal error and there is nothing the author has done incorrectly
@@ -4428,7 +4469,12 @@ inline ObjectWrap<T>::ObjectWrap(const Napi::CallbackInfo& callbackInfo) {
44284469 napi_status status;
44294470 napi_ref ref;
44304471 T* instance = static_cast <T*>(this );
4431- status = napi_wrap (env, wrapper, instance, FinalizeCallback, nullptr , &ref);
4472+ status = napi_wrap (env,
4473+ wrapper,
4474+ instance,
4475+ details::PostFinalizerWrapper<FinalizeCallback>,
4476+ nullptr ,
4477+ &ref);
44324478 NAPI_THROW_IF_FAILED_VOID (env, status);
44334479
44344480 Reference<Object>* instanceRef = instance;
@@ -5321,19 +5367,21 @@ TypedThreadSafeFunction<ContextType, DataType, CallJs>::New(
53215367 auto * finalizeData = new details::
53225368 ThreadSafeFinalize<ContextType, Finalizer, FinalizerDataType>(
53235369 {data, finalizeCallback});
5324- napi_status status = napi_create_threadsafe_function (
5325- env,
5326- nullptr ,
5327- nullptr ,
5328- String::From (env, resourceName),
5329- maxQueueSize,
5330- initialThreadCount,
5331- finalizeData,
5370+ auto fini =
53325371 details::ThreadSafeFinalize<ContextType, Finalizer, FinalizerDataType>::
5333- FinalizeFinalizeWrapperWithDataAndContext,
5334- context,
5335- CallJsInternal,
5336- &tsfn._tsfn );
5372+ FinalizeFinalizeWrapperWithDataAndContext;
5373+ napi_status status =
5374+ napi_create_threadsafe_function (env,
5375+ nullptr ,
5376+ nullptr ,
5377+ String::From (env, resourceName),
5378+ maxQueueSize,
5379+ initialThreadCount,
5380+ finalizeData,
5381+ TSFN_FINALIZER (fini),
5382+ context,
5383+ CallJsInternal,
5384+ &tsfn._tsfn );
53375385 if (status != napi_ok) {
53385386 delete finalizeData;
53395387 NAPI_THROW_IF_FAILED (
@@ -5365,19 +5413,21 @@ TypedThreadSafeFunction<ContextType, DataType, CallJs>::New(
53655413 auto * finalizeData = new details::
53665414 ThreadSafeFinalize<ContextType, Finalizer, FinalizerDataType>(
53675415 {data, finalizeCallback});
5368- napi_status status = napi_create_threadsafe_function (
5369- env,
5370- nullptr ,
5371- resource,
5372- String::From (env, resourceName),
5373- maxQueueSize,
5374- initialThreadCount,
5375- finalizeData,
5416+ auto fini =
53765417 details::ThreadSafeFinalize<ContextType, Finalizer, FinalizerDataType>::
5377- FinalizeFinalizeWrapperWithDataAndContext,
5378- context,
5379- CallJsInternal,
5380- &tsfn._tsfn );
5418+ FinalizeFinalizeWrapperWithDataAndContext;
5419+ napi_status status =
5420+ napi_create_threadsafe_function (env,
5421+ nullptr ,
5422+ resource,
5423+ String::From (env, resourceName),
5424+ maxQueueSize,
5425+ initialThreadCount,
5426+ finalizeData,
5427+ TSFN_FINALIZER (fini),
5428+ context,
5429+ CallJsInternal,
5430+ &tsfn._tsfn );
53815431 if (status != napi_ok) {
53825432 delete finalizeData;
53835433 NAPI_THROW_IF_FAILED (
@@ -5481,19 +5531,21 @@ TypedThreadSafeFunction<ContextType, DataType, CallJs>::New(
54815531 auto * finalizeData = new details::
54825532 ThreadSafeFinalize<ContextType, Finalizer, FinalizerDataType>(
54835533 {data, finalizeCallback});
5484- napi_status status = napi_create_threadsafe_function (
5485- env,
5486- callback,
5487- nullptr ,
5488- String::From (env, resourceName),
5489- maxQueueSize,
5490- initialThreadCount,
5491- finalizeData,
5534+ auto fini =
54925535 details::ThreadSafeFinalize<ContextType, Finalizer, FinalizerDataType>::
5493- FinalizeFinalizeWrapperWithDataAndContext,
5494- context,
5495- CallJsInternal,
5496- &tsfn._tsfn );
5536+ FinalizeFinalizeWrapperWithDataAndContext;
5537+ napi_status status =
5538+ napi_create_threadsafe_function (env,
5539+ callback,
5540+ nullptr ,
5541+ String::From (env, resourceName),
5542+ maxQueueSize,
5543+ initialThreadCount,
5544+ finalizeData,
5545+ TSFN_FINALIZER (fini),
5546+ context,
5547+ CallJsInternal,
5548+ &tsfn._tsfn );
54975549 if (status != napi_ok) {
54985550 delete finalizeData;
54995551 NAPI_THROW_IF_FAILED (
@@ -5527,6 +5579,9 @@ TypedThreadSafeFunction<ContextType, DataType, CallJs>::New(
55275579 auto * finalizeData = new details::
55285580 ThreadSafeFinalize<ContextType, Finalizer, FinalizerDataType>(
55295581 {data, finalizeCallback});
5582+ auto fini =
5583+ details::ThreadSafeFinalize<ContextType, Finalizer, FinalizerDataType>::
5584+ FinalizeFinalizeWrapperWithDataAndContext;
55305585 napi_status status = napi_create_threadsafe_function (
55315586 env,
55325587 details::DefaultCallbackWrapper<
@@ -5538,8 +5593,7 @@ TypedThreadSafeFunction<ContextType, DataType, CallJs>::New(
55385593 maxQueueSize,
55395594 initialThreadCount,
55405595 finalizeData,
5541- details::ThreadSafeFinalize<ContextType, Finalizer, FinalizerDataType>::
5542- FinalizeFinalizeWrapperWithDataAndContext,
5596+ TSFN_FINALIZER (fini),
55435597 context,
55445598 CallJsInternal,
55455599 &tsfn._tsfn );
@@ -6078,7 +6132,7 @@ inline ThreadSafeFunction ThreadSafeFunction::New(napi_env env,
60786132 maxQueueSize,
60796133 initialThreadCount,
60806134 finalizeData,
6081- wrapper,
6135+ TSFN_FINALIZER ( wrapper) ,
60826136 context,
60836137 CallJS,
60846138 &tsfn._tsfn );
0 commit comments