18
18
#include < type_traits>
19
19
#include < utility>
20
20
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
+
21
31
namespace Napi {
22
32
23
33
#ifdef NAPI_CPP_CUSTOM_NAMESPACE
@@ -31,6 +41,23 @@ namespace details {
31
41
// Node.js releases. Only necessary when they are used in napi.h and napi-inl.h.
32
42
constexpr int napi_no_external_buffers_allowed = 22 ;
33
43
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
+
34
61
template <typename FreeType>
35
62
inline void default_finalizer (napi_env /* env*/ , void * data, void * /* hint*/ ) {
36
63
delete static_cast <FreeType*>(data);
@@ -65,7 +92,8 @@ inline napi_status AttachData(napi_env env,
65
92
}
66
93
}
67
94
#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 );
69
97
#endif
70
98
return status;
71
99
}
@@ -1774,7 +1802,8 @@ inline External<T> External<T>::New(napi_env env,
1774
1802
napi_status status =
1775
1803
napi_create_external (env,
1776
1804
data,
1777
- details::FinalizeData<T, Finalizer>::Wrapper,
1805
+ details::PostFinalizerWrapper<
1806
+ details::FinalizeData<T, Finalizer>::Wrapper>,
1778
1807
finalizeData,
1779
1808
&value);
1780
1809
if (status != napi_ok) {
@@ -1797,7 +1826,8 @@ inline External<T> External<T>::New(napi_env env,
1797
1826
napi_status status = napi_create_external (
1798
1827
env,
1799
1828
data,
1800
- details::FinalizeData<T, Finalizer, Hint>::WrapperWithHint,
1829
+ details::PostFinalizerWrapper<
1830
+ details::FinalizeData<T, Finalizer, Hint>::WrapperWithHint>,
1801
1831
finalizeData,
1802
1832
&value);
1803
1833
if (status != napi_ok) {
@@ -1910,7 +1940,8 @@ inline ArrayBuffer ArrayBuffer::New(napi_env env,
1910
1940
env,
1911
1941
externalData,
1912
1942
byteLength,
1913
- details::FinalizeData<void , Finalizer>::Wrapper,
1943
+ details::PostFinalizerWrapper<
1944
+ details::FinalizeData<void , Finalizer>::Wrapper>,
1914
1945
finalizeData,
1915
1946
&value);
1916
1947
if (status != napi_ok) {
@@ -1935,7 +1966,8 @@ inline ArrayBuffer ArrayBuffer::New(napi_env env,
1935
1966
env,
1936
1967
externalData,
1937
1968
byteLength,
1938
- details::FinalizeData<void , Finalizer, Hint>::WrapperWithHint,
1969
+ details::PostFinalizerWrapper<
1970
+ details::FinalizeData<void , Finalizer, Hint>::WrapperWithHint>,
1939
1971
finalizeData,
1940
1972
&value);
1941
1973
if (status != napi_ok) {
@@ -2652,13 +2684,14 @@ inline Buffer<T> Buffer<T>::New(napi_env env,
2652
2684
details::FinalizeData<T, Finalizer>* finalizeData =
2653
2685
new details::FinalizeData<T, Finalizer>(
2654
2686
{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);
2662
2695
if (status != napi_ok) {
2663
2696
delete finalizeData;
2664
2697
NAPI_THROW_IF_FAILED (env, status, Buffer ());
@@ -2681,7 +2714,8 @@ inline Buffer<T> Buffer<T>::New(napi_env env,
2681
2714
env,
2682
2715
length * sizeof (T),
2683
2716
data,
2684
- details::FinalizeData<T, Finalizer, Hint>::WrapperWithHint,
2717
+ details::PostFinalizerWrapper<
2718
+ details::FinalizeData<T, Finalizer, Hint>::WrapperWithHint>,
2685
2719
finalizeData,
2686
2720
&value);
2687
2721
if (status != napi_ok) {
@@ -2720,13 +2754,14 @@ inline Buffer<T> Buffer<T>::NewOrCopy(napi_env env,
2720
2754
{std::move (finalizeCallback), nullptr });
2721
2755
#ifndef NODE_API_NO_EXTERNAL_BUFFERS_ALLOWED
2722
2756
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);
2730
2765
if (status == details::napi_no_external_buffers_allowed) {
2731
2766
#endif // NODE_API_NO_EXTERNAL_BUFFERS_ALLOWED
2732
2767
// 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,
2759
2794
env,
2760
2795
length * sizeof (T),
2761
2796
data,
2762
- details::FinalizeData<T, Finalizer, Hint>::WrapperWithHint,
2797
+ details::PostFinalizerWrapper<
2798
+ details::FinalizeData<T, Finalizer, Hint>::WrapperWithHint>,
2763
2799
finalizeData,
2764
2800
&value);
2765
2801
if (status == details::napi_no_external_buffers_allowed) {
@@ -3054,7 +3090,12 @@ inline void Error::ThrowAsJavaScriptException() const {
3054
3090
3055
3091
status = napi_throw (_env, Value ());
3056
3092
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) {
3058
3099
// The environment must be terminating as we checked earlier and there
3059
3100
// was no pending exception. In this case continuing will result
3060
3101
// 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) {
4428
4469
napi_status status;
4429
4470
napi_ref ref;
4430
4471
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);
4432
4478
NAPI_THROW_IF_FAILED_VOID (env, status);
4433
4479
4434
4480
Reference<Object>* instanceRef = instance;
@@ -5321,19 +5367,21 @@ TypedThreadSafeFunction<ContextType, DataType, CallJs>::New(
5321
5367
auto * finalizeData = new details::
5322
5368
ThreadSafeFinalize<ContextType, Finalizer, FinalizerDataType>(
5323
5369
{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 =
5332
5371
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 );
5337
5385
if (status != napi_ok) {
5338
5386
delete finalizeData;
5339
5387
NAPI_THROW_IF_FAILED (
@@ -5365,19 +5413,21 @@ TypedThreadSafeFunction<ContextType, DataType, CallJs>::New(
5365
5413
auto * finalizeData = new details::
5366
5414
ThreadSafeFinalize<ContextType, Finalizer, FinalizerDataType>(
5367
5415
{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 =
5376
5417
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 );
5381
5431
if (status != napi_ok) {
5382
5432
delete finalizeData;
5383
5433
NAPI_THROW_IF_FAILED (
@@ -5481,19 +5531,21 @@ TypedThreadSafeFunction<ContextType, DataType, CallJs>::New(
5481
5531
auto * finalizeData = new details::
5482
5532
ThreadSafeFinalize<ContextType, Finalizer, FinalizerDataType>(
5483
5533
{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 =
5492
5535
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 );
5497
5549
if (status != napi_ok) {
5498
5550
delete finalizeData;
5499
5551
NAPI_THROW_IF_FAILED (
@@ -5527,6 +5579,9 @@ TypedThreadSafeFunction<ContextType, DataType, CallJs>::New(
5527
5579
auto * finalizeData = new details::
5528
5580
ThreadSafeFinalize<ContextType, Finalizer, FinalizerDataType>(
5529
5581
{data, finalizeCallback});
5582
+ auto fini =
5583
+ details::ThreadSafeFinalize<ContextType, Finalizer, FinalizerDataType>::
5584
+ FinalizeFinalizeWrapperWithDataAndContext;
5530
5585
napi_status status = napi_create_threadsafe_function (
5531
5586
env,
5532
5587
details::DefaultCallbackWrapper<
@@ -5538,8 +5593,7 @@ TypedThreadSafeFunction<ContextType, DataType, CallJs>::New(
5538
5593
maxQueueSize,
5539
5594
initialThreadCount,
5540
5595
finalizeData,
5541
- details::ThreadSafeFinalize<ContextType, Finalizer, FinalizerDataType>::
5542
- FinalizeFinalizeWrapperWithDataAndContext,
5596
+ TSFN_FINALIZER (fini),
5543
5597
context,
5544
5598
CallJsInternal,
5545
5599
&tsfn._tsfn );
@@ -6078,7 +6132,7 @@ inline ThreadSafeFunction ThreadSafeFunction::New(napi_env env,
6078
6132
maxQueueSize,
6079
6133
initialThreadCount,
6080
6134
finalizeData,
6081
- wrapper,
6135
+ TSFN_FINALIZER ( wrapper) ,
6082
6136
context,
6083
6137
CallJS,
6084
6138
&tsfn._tsfn );
0 commit comments