Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

src: restore ability to run under NAPI_EXPERIMENTAL #1409

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 5 additions & 2 deletions .github/workflows/ci-win.yml
Original file line number Diff line number Diff line change
Expand Up @@ -12,13 +12,16 @@ jobs:
test:
timeout-minutes: 30
strategy:
fail-fast: false
KevinEady marked this conversation as resolved.
Show resolved Hide resolved
matrix:
node-version: [ 18.x, 20.x, 21.x, 22.x ]
node-version:
- 18.x
- 20.x
- 22.x
architecture: [x64, x86]
os:
- windows-2019
- windows-2022
fail-fast: false # Don't cancel other jobs when one job fails
runs-on: ${{ matrix.os }}
steps:
- uses: actions/checkout@a5ac7e51b41094c92402da3b24376905380afc29 # v4.1.6
Expand Down
12 changes: 11 additions & 1 deletion .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,15 @@ jobs:
test:
timeout-minutes: 30
strategy:
fail-fast: false
matrix:
node-version: [ 18.x, 20.x, 21.x, 22.x ]
api_version:
- standard
- experimental
node-version:
- 18.x
- 20.x
- 22.x
os:
- macos-latest
- ubuntu-latest
Expand Down Expand Up @@ -43,6 +50,9 @@ jobs:
npm install
- name: npm test
run: |
if [ "${{ matrix.api_version }}" = "experimental" ]; then
export NAPI_VERSION=2147483647
fi
if [ "${{ matrix.compiler }}" = "gcc" ]; then
export CC="gcc" CXX="g++"
fi
Expand Down
1 change: 1 addition & 0 deletions common.gypi
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
},
'conditions': [
['NAPI_VERSION!=""', { 'defines': ['NAPI_VERSION=<@(NAPI_VERSION)'] } ],
['NAPI_VERSION==2147483647', { 'defines': ['NAPI_EXPERIMENTAL'] } ],
KevinEady marked this conversation as resolved.
Show resolved Hide resolved
['disable_deprecated=="true"', {
'defines': ['NODE_ADDON_API_DISABLE_DEPRECATED']
}],
Expand Down
166 changes: 105 additions & 61 deletions napi-inl.h
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,23 @@ namespace details {
// Node.js releases. Only necessary when they are used in napi.h and napi-inl.h.
constexpr int napi_no_external_buffers_allowed = 22;

#if (defined(NAPI_EXPERIMENTAL) && \
defined(NODE_API_EXPERIMENTAL_HAS_POST_FINALIZER))
template <napi_finalize finalizer>
inline void PostFinalizerWrapper(node_api_nogc_env nogc_env,
void* data,
void* hint) {
napi_status status = node_api_post_finalizer(nogc_env, finalizer, data, hint);
NAPI_FATAL_IF_FAILED(
status, "PostFinalizerWrapper", "node_api_post_finalizer failed");
}
#else
template <napi_finalize finalizer>
inline void PostFinalizerWrapper(napi_env env, void* data, void* hint) {
finalizer(env, data, hint);
}
#endif

template <typename FreeType>
inline void default_finalizer(napi_env /*env*/, void* data, void* /*hint*/) {
delete static_cast<FreeType*>(data);
Expand Down Expand Up @@ -65,7 +82,8 @@ inline napi_status AttachData(napi_env env,
}
}
#else // NAPI_VERSION >= 5
status = napi_add_finalizer(env, obj, data, finalizer, hint, nullptr);
status = napi_add_finalizer(
env, obj, data, details::PostFinalizerWrapper<finalizer>, hint, nullptr);
#endif
return status;
}
Expand Down Expand Up @@ -1777,7 +1795,8 @@ inline External<T> External<T>::New(napi_env env,
napi_status status =
napi_create_external(env,
data,
details::FinalizeData<T, Finalizer>::Wrapper,
details::PostFinalizerWrapper<
details::FinalizeData<T, Finalizer>::Wrapper>,
finalizeData,
&value);
if (status != napi_ok) {
Expand All @@ -1800,7 +1819,8 @@ inline External<T> External<T>::New(napi_env env,
napi_status status = napi_create_external(
env,
data,
details::FinalizeData<T, Finalizer, Hint>::WrapperWithHint,
details::PostFinalizerWrapper<
details::FinalizeData<T, Finalizer, Hint>::WrapperWithHint>,
finalizeData,
&value);
if (status != napi_ok) {
Expand Down Expand Up @@ -1913,7 +1933,8 @@ inline ArrayBuffer ArrayBuffer::New(napi_env env,
env,
externalData,
byteLength,
details::FinalizeData<void, Finalizer>::Wrapper,
details::PostFinalizerWrapper<
details::FinalizeData<void, Finalizer>::Wrapper>,
finalizeData,
&value);
if (status != napi_ok) {
Expand All @@ -1938,7 +1959,8 @@ inline ArrayBuffer ArrayBuffer::New(napi_env env,
env,
externalData,
byteLength,
details::FinalizeData<void, Finalizer, Hint>::WrapperWithHint,
details::PostFinalizerWrapper<
details::FinalizeData<void, Finalizer, Hint>::WrapperWithHint>,
finalizeData,
&value);
if (status != napi_ok) {
Expand Down Expand Up @@ -2655,13 +2677,14 @@ inline Buffer<T> Buffer<T>::New(napi_env env,
details::FinalizeData<T, Finalizer>* finalizeData =
new details::FinalizeData<T, Finalizer>(
{std::move(finalizeCallback), nullptr});
napi_status status =
napi_create_external_buffer(env,
length * sizeof(T),
data,
details::FinalizeData<T, Finalizer>::Wrapper,
finalizeData,
&value);
napi_status status = napi_create_external_buffer(
env,
length * sizeof(T),
data,
details::PostFinalizerWrapper<
details::FinalizeData<T, Finalizer>::Wrapper>,
finalizeData,
&value);
if (status != napi_ok) {
delete finalizeData;
NAPI_THROW_IF_FAILED(env, status, Buffer());
Expand All @@ -2684,7 +2707,8 @@ inline Buffer<T> Buffer<T>::New(napi_env env,
env,
length * sizeof(T),
data,
details::FinalizeData<T, Finalizer, Hint>::WrapperWithHint,
details::PostFinalizerWrapper<
details::FinalizeData<T, Finalizer, Hint>::WrapperWithHint>,
finalizeData,
&value);
if (status != napi_ok) {
Expand Down Expand Up @@ -2723,13 +2747,14 @@ inline Buffer<T> Buffer<T>::NewOrCopy(napi_env env,
{std::move(finalizeCallback), nullptr});
#ifndef NODE_API_NO_EXTERNAL_BUFFERS_ALLOWED
napi_value value;
napi_status status =
napi_create_external_buffer(env,
length * sizeof(T),
data,
details::FinalizeData<T, Finalizer>::Wrapper,
finalizeData,
&value);
napi_status status = napi_create_external_buffer(
env,
length * sizeof(T),
data,
details::PostFinalizerWrapper<
details::FinalizeData<T, Finalizer>::Wrapper>,
finalizeData,
&value);
if (status == details::napi_no_external_buffers_allowed) {
#endif // NODE_API_NO_EXTERNAL_BUFFERS_ALLOWED
// If we can't create an external buffer, we'll just copy the data.
Expand Down Expand Up @@ -2762,7 +2787,8 @@ inline Buffer<T> Buffer<T>::NewOrCopy(napi_env env,
env,
length * sizeof(T),
data,
details::FinalizeData<T, Finalizer, Hint>::WrapperWithHint,
details::PostFinalizerWrapper<
details::FinalizeData<T, Finalizer, Hint>::WrapperWithHint>,
finalizeData,
&value);
if (status == details::napi_no_external_buffers_allowed) {
Expand Down Expand Up @@ -3057,7 +3083,12 @@ inline void Error::ThrowAsJavaScriptException() const {

status = napi_throw(_env, Value());

if (status == napi_pending_exception) {
#ifdef NAPI_EXPERIMENTAL
napi_status expected_failure_mode = napi_cannot_run_js;
#else
napi_status expected_failure_mode = napi_pending_exception;
#endif
if (status == expected_failure_mode) {
// The environment must be terminating as we checked earlier and there
// was no pending exception. In this case continuing will result
// in a fatal error and there is nothing the author has done incorrectly
Expand Down Expand Up @@ -4431,7 +4462,12 @@ inline ObjectWrap<T>::ObjectWrap(const Napi::CallbackInfo& callbackInfo) {
napi_status status;
napi_ref ref;
T* instance = static_cast<T*>(this);
status = napi_wrap(env, wrapper, instance, FinalizeCallback, nullptr, &ref);
status = napi_wrap(env,
wrapper,
instance,
details::PostFinalizerWrapper<FinalizeCallback>,
nullptr,
&ref);
NAPI_THROW_IF_FAILED_VOID(env, status);

Reference<Object>* instanceRef = instance;
Expand Down Expand Up @@ -5327,19 +5363,21 @@ TypedThreadSafeFunction<ContextType, DataType, CallJs>::New(
auto* finalizeData = new details::
ThreadSafeFinalize<ContextType, Finalizer, FinalizerDataType>(
{data, finalizeCallback});
napi_status status = napi_create_threadsafe_function(
env,
nullptr,
nullptr,
String::From(env, resourceName),
maxQueueSize,
initialThreadCount,
finalizeData,
auto fini =
details::ThreadSafeFinalize<ContextType, Finalizer, FinalizerDataType>::
FinalizeFinalizeWrapperWithDataAndContext,
context,
CallJsInternal,
&tsfn._tsfn);
FinalizeFinalizeWrapperWithDataAndContext;
napi_status status =
napi_create_threadsafe_function(env,
nullptr,
nullptr,
String::From(env, resourceName),
maxQueueSize,
initialThreadCount,
finalizeData,
fini,
context,
CallJsInternal,
&tsfn._tsfn);
if (status != napi_ok) {
delete finalizeData;
NAPI_THROW_IF_FAILED(
Expand Down Expand Up @@ -5371,19 +5409,21 @@ TypedThreadSafeFunction<ContextType, DataType, CallJs>::New(
auto* finalizeData = new details::
ThreadSafeFinalize<ContextType, Finalizer, FinalizerDataType>(
{data, finalizeCallback});
napi_status status = napi_create_threadsafe_function(
env,
nullptr,
resource,
String::From(env, resourceName),
maxQueueSize,
initialThreadCount,
finalizeData,
auto fini =
details::ThreadSafeFinalize<ContextType, Finalizer, FinalizerDataType>::
FinalizeFinalizeWrapperWithDataAndContext,
context,
CallJsInternal,
&tsfn._tsfn);
FinalizeFinalizeWrapperWithDataAndContext;
napi_status status =
napi_create_threadsafe_function(env,
nullptr,
resource,
String::From(env, resourceName),
maxQueueSize,
initialThreadCount,
finalizeData,
fini,
context,
CallJsInternal,
&tsfn._tsfn);
if (status != napi_ok) {
delete finalizeData;
NAPI_THROW_IF_FAILED(
Expand Down Expand Up @@ -5487,19 +5527,21 @@ TypedThreadSafeFunction<ContextType, DataType, CallJs>::New(
auto* finalizeData = new details::
ThreadSafeFinalize<ContextType, Finalizer, FinalizerDataType>(
{data, finalizeCallback});
napi_status status = napi_create_threadsafe_function(
env,
callback,
nullptr,
String::From(env, resourceName),
maxQueueSize,
initialThreadCount,
finalizeData,
auto fini =
details::ThreadSafeFinalize<ContextType, Finalizer, FinalizerDataType>::
FinalizeFinalizeWrapperWithDataAndContext,
context,
CallJsInternal,
&tsfn._tsfn);
FinalizeFinalizeWrapperWithDataAndContext;
napi_status status =
napi_create_threadsafe_function(env,
callback,
nullptr,
String::From(env, resourceName),
maxQueueSize,
initialThreadCount,
finalizeData,
fini,
context,
CallJsInternal,
&tsfn._tsfn);
if (status != napi_ok) {
delete finalizeData;
NAPI_THROW_IF_FAILED(
Expand Down Expand Up @@ -5533,6 +5575,9 @@ TypedThreadSafeFunction<ContextType, DataType, CallJs>::New(
auto* finalizeData = new details::
ThreadSafeFinalize<ContextType, Finalizer, FinalizerDataType>(
{data, finalizeCallback});
auto fini =
details::ThreadSafeFinalize<ContextType, Finalizer, FinalizerDataType>::
FinalizeFinalizeWrapperWithDataAndContext;
napi_status status = napi_create_threadsafe_function(
env,
details::DefaultCallbackWrapper<
Expand All @@ -5544,8 +5589,7 @@ TypedThreadSafeFunction<ContextType, DataType, CallJs>::New(
maxQueueSize,
initialThreadCount,
finalizeData,
details::ThreadSafeFinalize<ContextType, Finalizer, FinalizerDataType>::
FinalizeFinalizeWrapperWithDataAndContext,
fini,
context,
CallJsInternal,
&tsfn._tsfn);
Expand Down
1 change: 1 addition & 0 deletions test/addon_build/tpl/binding.gyp
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
},
'conditions': [
['NAPI_VERSION!=""', { 'defines': ['NAPI_VERSION=<@(NAPI_VERSION)'] } ],
['NAPI_VERSION==2147483647', { 'defines': ['NAPI_EXPERIMENTAL'] } ],
['disable_deprecated=="true"', {
'defines': ['NODE_ADDON_API_DISABLE_DEPRECATED']
}],
Expand Down