Skip to content

Commit 8fffa49

Browse files
authored
fix(napi): resuse threads worker on Node.js (#2399)
1 parent 3d62aca commit 8fffa49

File tree

30 files changed

+321
-102
lines changed

30 files changed

+321
-102
lines changed

.cargo/config.toml

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,7 @@
11
[target.'cfg(target_family = "wasm")']
2-
rustflags = ["-C", "target-feature=+atomics,+bulk-memory"]
2+
rustflags = [
3+
"--cfg",
4+
"tokio_unstable",
5+
"-C",
6+
"target-feature=+atomics,+bulk-memory",
7+
]

.github/workflows/test-release.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -153,7 +153,7 @@ jobs:
153153
- name: 'Install dependencies'
154154
shell: bash
155155
run: |
156-
yarn config set supportedArchitectures.cpu --json '["current", "x64", "x86"]'
156+
yarn config set supportedArchitectures.cpu --json '["current", "x64", "ia32", "wasm32"]'
157157
yarn install --mode=skip-build --immutable
158158
159159
- name: Check build

.yarnrc.yml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,8 @@
11
nodeLinker: node-modules
22

33
yarnPath: .yarn/releases/yarn-4.5.3.cjs
4+
5+
supportedArchitectures:
6+
cpu:
7+
- current
8+
- wasm32

cli/cli.mjs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ import { resolve } from 'path'
55
import { fileURLToPath } from 'url'
66

77
execSync(
8-
`node --loader ts-node/esm/transpile-only ${resolve(
8+
`node --import @oxc-node/core/register ${resolve(
99
fileURLToPath(import.meta.url),
1010
'../src/cli.ts',
1111
)} ${process.argv.slice(2).join(' ')}`,

cli/esbuild.mjs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
1-
import * as esbuild from 'esbuild'
1+
import { build} from 'esbuild'
22
import { pull } from 'lodash-es'
33

44
import packageJson from './package.json' assert { type: 'json' }
55

6-
await esbuild.build({
6+
await build({
77
entryPoints: ['./dist/index.js'],
88
outfile: './dist/index.cjs',
99
bundle: true,

cli/src/api/templates/load-wasi-template.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ const __wasi = new __WASI({
1515
fs: __fs,
1616
preopens: {
1717
'/': '/',
18-
}
18+
},
1919
})`
2020
: `
2121
const __wasi = new __WASI({
@@ -147,11 +147,11 @@ const { instance: __napiInstance, module: __wasiModule, napiModule: __napiModule
147147
return 4
148148
}
149149
})(),
150+
reuseWorker: true,
150151
wasi: __wasi,
151152
onCreateWorker() {
152153
const worker = new Worker(__nodePath.join(__dirname, 'wasi-worker.mjs'), {
153154
env: process.env,
154-
execArgv: ['--experimental-wasi-unstable-preview1'],
155155
})
156156
worker.onmessage = ({ data }) => {
157157
__wasmCreateOnMessageForFsProxy(__nodeFs)(data)

crates/backend/src/codegen/fn.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -79,7 +79,7 @@ impl TryToTokens for NapiFn {
7979

8080
#(#refs)*
8181

82-
#[cfg(debug_assert)]
82+
#[cfg(debug_assertions)]
8383
{
8484
for a in &_args_array {
8585
assert!(!a.is_null(), "failed to initialize napi ref");

crates/build/src/wasi.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,4 +25,9 @@ pub fn setup() {
2525
println!("cargo:rustc-link-search={setjmp_link_dir}");
2626
println!("cargo:rustc-link-lib=static=setjmp-mt");
2727
}
28+
if let Ok(wasi_sdk_path) = env::var("WASI_SDK_PATH") {
29+
println!(
30+
"cargo:rustc-link-search={wasi_sdk_path}/share/wasi-sysroot/lib/wasm32-wasip1-threads"
31+
);
32+
}
2833
}

crates/napi/src/bindgen_runtime/module_register.rs

Lines changed: 18 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -6,12 +6,6 @@ use std::ffi::CStr;
66
use std::mem::MaybeUninit;
77
#[cfg(not(feature = "noop"))]
88
use std::ptr;
9-
#[cfg(all(
10-
not(any(target_os = "macos", target_family = "wasm")),
11-
feature = "napi4",
12-
feature = "tokio_rt"
13-
))]
14-
use std::sync::atomic::AtomicUsize;
159
#[cfg(not(feature = "noop"))]
1610
use std::sync::atomic::{AtomicBool, Ordering};
1711
use std::sync::{LazyLock, RwLock};
@@ -411,13 +405,13 @@ pub unsafe extern "C" fn napi_register_module_v1(
411405
}
412406
}
413407
});
408+
});
414409

415-
REGISTERED_CLASSES.borrow_mut(|map| {
416-
map.insert(
417-
std::thread::current().id(),
418-
PersistedPerInstanceHashMap::from_hashmap(registered_classes),
419-
)
420-
});
410+
REGISTERED_CLASSES.borrow_mut(|map| {
411+
map.insert(
412+
std::thread::current().id(),
413+
PersistedPerInstanceHashMap::from_hashmap(registered_classes),
414+
)
421415
});
422416

423417
#[cfg(feature = "compat-mode")]
@@ -430,23 +424,25 @@ pub unsafe extern "C" fn napi_register_module_v1(
430424
})
431425
}
432426

433-
#[cfg(all(
434-
not(any(target_os = "macos", target_family = "wasm")),
435-
feature = "napi4",
436-
feature = "tokio_rt"
437-
))]
427+
#[cfg(all(feature = "napi4", feature = "tokio_rt"))]
438428
{
439429
crate::tokio_runtime::ensure_runtime();
440430

441-
static init_counter: AtomicUsize = AtomicUsize::new(0);
442-
let cleanup_hook_payload =
443-
init_counter.fetch_add(1, Ordering::Relaxed) as *mut std::ffi::c_void;
444-
431+
#[cfg(not(target_family = "wasm"))]
445432
unsafe {
446433
sys::napi_add_env_cleanup_hook(
447434
env,
448435
Some(crate::tokio_runtime::drop_runtime),
449-
cleanup_hook_payload,
436+
ptr::null_mut(),
437+
)
438+
};
439+
440+
#[cfg(target_family = "wasm")]
441+
unsafe {
442+
crate::napi_add_env_cleanup_hook(
443+
env,
444+
Some(crate::tokio_runtime::drop_runtime),
445+
ptr::null_mut(),
450446
)
451447
};
452448
}

crates/napi/src/env.rs

Lines changed: 24 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1011,13 +1011,27 @@ impl Env {
10111011
hook: Box::new(cleanup_fn),
10121012
};
10131013
let hook_ref = Box::leak(Box::new(hook));
1014-
check_status!(unsafe {
1015-
sys::napi_add_env_cleanup_hook(
1016-
self.0,
1017-
Some(cleanup_env::<T>),
1018-
hook_ref as *mut CleanupEnvHookData<T> as *mut _,
1019-
)
1020-
})?;
1014+
#[cfg(not(target_family = "wasm"))]
1015+
{
1016+
check_status!(unsafe {
1017+
sys::napi_add_env_cleanup_hook(
1018+
self.0,
1019+
Some(cleanup_env::<T>),
1020+
(hook_ref as *mut CleanupEnvHookData<T>).cast(),
1021+
)
1022+
})?;
1023+
}
1024+
1025+
#[cfg(target_family = "wasm")]
1026+
{
1027+
check_status!(unsafe {
1028+
crate::napi_add_env_cleanup_hook(
1029+
self.0,
1030+
Some(cleanup_env::<T>),
1031+
(hook_ref as *mut CleanupEnvHookData<T>).cast(),
1032+
)
1033+
})?;
1034+
}
10211035
Ok(CleanupEnvHook(hook_ref))
10221036
}
10231037

@@ -1146,8 +1160,7 @@ impl Env {
11461160
check_status!(unsafe {
11471161
sys::napi_set_instance_data(
11481162
self.0,
1149-
Box::leak(Box::new((TaggedObject::new(native), finalize_cb))) as *mut (TaggedObject<T>, F)
1150-
as *mut c_void,
1163+
Box::into_raw(Box::new((TaggedObject::new(native), finalize_cb))).cast(),
11511164
Some(
11521165
set_instance_finalize_callback::<T, Hint, F>
11531166
as unsafe extern "C" fn(
@@ -1156,7 +1169,7 @@ impl Env {
11561169
finalize_hint: *mut c_void,
11571170
),
11581171
),
1159-
Box::leak(Box::new(hint)) as *mut Hint as *mut c_void,
1172+
Box::into_raw(Box::new(hint)).cast(),
11601173
)
11611174
})
11621175
}
@@ -1377,6 +1390,7 @@ unsafe extern "C" fn drop_buffer(
13771390
mem::drop(unsafe { Vec::from_raw_parts(finalize_data as *mut u8, length, cap) });
13781391
}
13791392

1393+
#[cfg_attr(target_family = "wasm", allow(unused_variables))]
13801394
pub(crate) unsafe extern "C" fn raw_finalize<T>(
13811395
env: sys::napi_env,
13821396
finalize_data: *mut c_void,

0 commit comments

Comments
 (0)