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;
@@ -5324,19 +5370,21 @@ TypedThreadSafeFunction<ContextType, DataType, CallJs>::New(
5324
5370
auto * finalizeData = new details::
5325
5371
ThreadSafeFinalize<ContextType, Finalizer, FinalizerDataType>(
5326
5372
{data, finalizeCallback});
5327
- napi_status status = napi_create_threadsafe_function (
5328
- env,
5329
- nullptr ,
5330
- nullptr ,
5331
- String::From (env, resourceName),
5332
- maxQueueSize,
5333
- initialThreadCount,
5334
- finalizeData,
5373
+ auto fini =
5335
5374
details::ThreadSafeFinalize<ContextType, Finalizer, FinalizerDataType>::
5336
- FinalizeFinalizeWrapperWithDataAndContext,
5337
- context,
5338
- CallJsInternal,
5339
- &tsfn._tsfn );
5375
+ FinalizeFinalizeWrapperWithDataAndContext;
5376
+ napi_status status =
5377
+ napi_create_threadsafe_function (env,
5378
+ nullptr ,
5379
+ nullptr ,
5380
+ String::From (env, resourceName),
5381
+ maxQueueSize,
5382
+ initialThreadCount,
5383
+ finalizeData,
5384
+ TSFN_FINALIZER (fini),
5385
+ context,
5386
+ CallJsInternal,
5387
+ &tsfn._tsfn );
5340
5388
if (status != napi_ok) {
5341
5389
delete finalizeData;
5342
5390
NAPI_THROW_IF_FAILED (
@@ -5368,19 +5416,21 @@ TypedThreadSafeFunction<ContextType, DataType, CallJs>::New(
5368
5416
auto * finalizeData = new details::
5369
5417
ThreadSafeFinalize<ContextType, Finalizer, FinalizerDataType>(
5370
5418
{data, finalizeCallback});
5371
- napi_status status = napi_create_threadsafe_function (
5372
- env,
5373
- nullptr ,
5374
- resource,
5375
- String::From (env, resourceName),
5376
- maxQueueSize,
5377
- initialThreadCount,
5378
- finalizeData,
5419
+ auto fini =
5379
5420
details::ThreadSafeFinalize<ContextType, Finalizer, FinalizerDataType>::
5380
- FinalizeFinalizeWrapperWithDataAndContext,
5381
- context,
5382
- CallJsInternal,
5383
- &tsfn._tsfn );
5421
+ FinalizeFinalizeWrapperWithDataAndContext;
5422
+ napi_status status =
5423
+ napi_create_threadsafe_function (env,
5424
+ nullptr ,
5425
+ resource,
5426
+ String::From (env, resourceName),
5427
+ maxQueueSize,
5428
+ initialThreadCount,
5429
+ finalizeData,
5430
+ TSFN_FINALIZER (fini),
5431
+ context,
5432
+ CallJsInternal,
5433
+ &tsfn._tsfn );
5384
5434
if (status != napi_ok) {
5385
5435
delete finalizeData;
5386
5436
NAPI_THROW_IF_FAILED (
@@ -5484,19 +5534,21 @@ TypedThreadSafeFunction<ContextType, DataType, CallJs>::New(
5484
5534
auto * finalizeData = new details::
5485
5535
ThreadSafeFinalize<ContextType, Finalizer, FinalizerDataType>(
5486
5536
{data, finalizeCallback});
5487
- napi_status status = napi_create_threadsafe_function (
5488
- env,
5489
- callback,
5490
- nullptr ,
5491
- String::From (env, resourceName),
5492
- maxQueueSize,
5493
- initialThreadCount,
5494
- finalizeData,
5537
+ auto fini =
5495
5538
details::ThreadSafeFinalize<ContextType, Finalizer, FinalizerDataType>::
5496
- FinalizeFinalizeWrapperWithDataAndContext,
5497
- context,
5498
- CallJsInternal,
5499
- &tsfn._tsfn );
5539
+ FinalizeFinalizeWrapperWithDataAndContext;
5540
+ napi_status status =
5541
+ napi_create_threadsafe_function (env,
5542
+ callback,
5543
+ nullptr ,
5544
+ String::From (env, resourceName),
5545
+ maxQueueSize,
5546
+ initialThreadCount,
5547
+ finalizeData,
5548
+ TSFN_FINALIZER (fini),
5549
+ context,
5550
+ CallJsInternal,
5551
+ &tsfn._tsfn );
5500
5552
if (status != napi_ok) {
5501
5553
delete finalizeData;
5502
5554
NAPI_THROW_IF_FAILED (
@@ -5530,6 +5582,9 @@ TypedThreadSafeFunction<ContextType, DataType, CallJs>::New(
5530
5582
auto * finalizeData = new details::
5531
5583
ThreadSafeFinalize<ContextType, Finalizer, FinalizerDataType>(
5532
5584
{data, finalizeCallback});
5585
+ auto fini =
5586
+ details::ThreadSafeFinalize<ContextType, Finalizer, FinalizerDataType>::
5587
+ FinalizeFinalizeWrapperWithDataAndContext;
5533
5588
napi_status status = napi_create_threadsafe_function (
5534
5589
env,
5535
5590
details::DefaultCallbackWrapper<
@@ -5541,8 +5596,7 @@ TypedThreadSafeFunction<ContextType, DataType, CallJs>::New(
5541
5596
maxQueueSize,
5542
5597
initialThreadCount,
5543
5598
finalizeData,
5544
- details::ThreadSafeFinalize<ContextType, Finalizer, FinalizerDataType>::
5545
- FinalizeFinalizeWrapperWithDataAndContext,
5599
+ TSFN_FINALIZER (fini),
5546
5600
context,
5547
5601
CallJsInternal,
5548
5602
&tsfn._tsfn );
@@ -6081,7 +6135,7 @@ inline ThreadSafeFunction ThreadSafeFunction::New(napi_env env,
6081
6135
maxQueueSize,
6082
6136
initialThreadCount,
6083
6137
finalizeData,
6084
- wrapper,
6138
+ TSFN_FINALIZER ( wrapper) ,
6085
6139
context,
6086
6140
CallJS,
6087
6141
&tsfn._tsfn );
0 commit comments