emnapi 0.34.0 → 0.36.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CMakeLists.txt +43 -1
- package/README.md +156 -59
- package/cmake/wasm32.cmake +2 -0
- package/dist/library_napi.js +163 -119
- package/lib/wasm32/libdlmalloc-mt.a +0 -0
- package/lib/wasm32/libemmalloc-mt.a +0 -0
- package/lib/wasm32/libemnapi-basic-mt.a +0 -0
- package/lib/wasm32-emscripten/libemnapi-basic.a +0 -0
- package/lib/wasm32-emscripten/libemnapi-mt.a +0 -0
- package/lib/wasm32-emscripten/libemnapi.a +0 -0
- package/lib/wasm32-emscripten.txt +2 -2
- package/lib/wasm32-wasi/libemnapi-basic-mt.a +0 -0
- package/package.json +1 -1
- package/src/thread/async_worker_create.c +76 -0
- package/src/thread/async_worker_init.S +33 -0
- package/src/uv/threadpool.c +9 -3
- package/src/uv/unix/async.c +17 -1
package/CMakeLists.txt
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
cmake_minimum_required(VERSION 3.13)
|
|
2
2
|
|
|
3
|
-
project(emnapi)
|
|
3
|
+
project(emnapi LANGUAGES C ASM)
|
|
4
4
|
|
|
5
5
|
option(EMNAPI_INSTALL_SRC "EMNAPI_INSTALL_SRC" OFF)
|
|
6
6
|
option(EMNAPI_FIND_NODE_ADDON_API "EMNAPI_FIND_NODE_ADDON_API" OFF)
|
|
@@ -50,10 +50,13 @@ else()
|
|
|
50
50
|
endif()
|
|
51
51
|
|
|
52
52
|
set(EMNAPI_BASIC_TARGET_NAME "emnapi-basic")
|
|
53
|
+
set(EMNAPI_BASIC_MT_TARGET_NAME "emnapi-basic-mt")
|
|
53
54
|
set(EMNAPI_TARGET_NAME "emnapi")
|
|
54
55
|
set(EMNAPI_MT_TARGET_NAME "emnapi-mt")
|
|
55
56
|
set(DLMALLOC_TARGET_NAME "dlmalloc")
|
|
57
|
+
set(DLMALLOC_MT_TARGET_NAME "dlmalloc-mt")
|
|
56
58
|
set(EMMALLOC_TARGET_NAME "emmalloc")
|
|
59
|
+
set(EMMALLOC_MT_TARGET_NAME "emmalloc-mt")
|
|
57
60
|
|
|
58
61
|
if(EMNAPI_FIND_NODE_ADDON_API)
|
|
59
62
|
execute_process(
|
|
@@ -82,11 +85,26 @@ if(IS_WASM32)
|
|
|
82
85
|
"${CMAKE_CURRENT_SOURCE_DIR}/src/malloc/dlmalloc/dlmalloc.c"
|
|
83
86
|
)
|
|
84
87
|
target_compile_definitions(${DLMALLOC_TARGET_NAME} PRIVATE "PAGESIZE=65536")
|
|
88
|
+
|
|
89
|
+
add_library(${DLMALLOC_MT_TARGET_NAME} STATIC
|
|
90
|
+
${MALLOC_PUBLIC_SOURCES}
|
|
91
|
+
"${CMAKE_CURRENT_SOURCE_DIR}/src/malloc/dlmalloc/dlmalloc.c"
|
|
92
|
+
)
|
|
93
|
+
target_compile_options(${DLMALLOC_MT_TARGET_NAME} PUBLIC "-matomics" "-mbulk-memory")
|
|
94
|
+
target_compile_definitions(${DLMALLOC_MT_TARGET_NAME} PRIVATE "PAGESIZE=65536" "USE_LOCKS=1")
|
|
95
|
+
|
|
85
96
|
add_library(${EMMALLOC_TARGET_NAME} STATIC
|
|
86
97
|
${MALLOC_PUBLIC_SOURCES}
|
|
87
98
|
"${CMAKE_CURRENT_SOURCE_DIR}/src/malloc/emmalloc/emmalloc.c"
|
|
88
99
|
)
|
|
89
100
|
target_compile_definitions(${EMMALLOC_TARGET_NAME} PRIVATE "PAGESIZE=65536")
|
|
101
|
+
|
|
102
|
+
add_library(${EMMALLOC_MT_TARGET_NAME} STATIC
|
|
103
|
+
${MALLOC_PUBLIC_SOURCES}
|
|
104
|
+
"${CMAKE_CURRENT_SOURCE_DIR}/src/malloc/emmalloc/emmalloc.c"
|
|
105
|
+
)
|
|
106
|
+
target_compile_options(${EMMALLOC_MT_TARGET_NAME} PUBLIC "-matomics" "-mbulk-memory")
|
|
107
|
+
target_compile_definitions(${EMMALLOC_MT_TARGET_NAME} PRIVATE "PAGESIZE=65536" "__EMSCRIPTEN_SHARED_MEMORY__=1")
|
|
90
108
|
endif()
|
|
91
109
|
|
|
92
110
|
add_library(${EMNAPI_TARGET_NAME} STATIC ${EMNAPI_SRC} ${UV_SRC})
|
|
@@ -101,6 +119,22 @@ if(IS_EMSCRIPTEN)
|
|
|
101
119
|
target_link_options(${EMNAPI_BASIC_TARGET_NAME} INTERFACE "--js-library=${EMNAPI_JS_LIB}")
|
|
102
120
|
endif()
|
|
103
121
|
|
|
122
|
+
if(IS_WASM32 OR (CMAKE_C_COMPILER_TARGET STREQUAL "wasm32-wasi") OR (CMAKE_C_COMPILER_TARGET STREQUAL "wasm32-wasi-threads"))
|
|
123
|
+
set(EMNAPI_BUILD_BASIC_MT ON)
|
|
124
|
+
else()
|
|
125
|
+
set(EMNAPI_BUILD_BASIC_MT OFF)
|
|
126
|
+
endif()
|
|
127
|
+
|
|
128
|
+
if(EMNAPI_BUILD_BASIC_MT)
|
|
129
|
+
add_library(${EMNAPI_BASIC_MT_TARGET_NAME} STATIC
|
|
130
|
+
${ENAPI_BASIC_SRC}
|
|
131
|
+
"${CMAKE_CURRENT_SOURCE_DIR}/src/thread/async_worker_create.c"
|
|
132
|
+
"${CMAKE_CURRENT_SOURCE_DIR}/src/thread/async_worker_init.S"
|
|
133
|
+
)
|
|
134
|
+
target_compile_options(${EMNAPI_BASIC_MT_TARGET_NAME} PUBLIC "-matomics" "-mbulk-memory")
|
|
135
|
+
target_include_directories(${EMNAPI_BASIC_MT_TARGET_NAME} PUBLIC ${EMNAPI_INCLUDE})
|
|
136
|
+
endif()
|
|
137
|
+
|
|
104
138
|
if(IS_EMSCRIPTEN OR (CMAKE_C_COMPILER_TARGET STREQUAL "wasm32-wasi-threads"))
|
|
105
139
|
set(EMNAPI_BUILD_MT ON)
|
|
106
140
|
else()
|
|
@@ -141,9 +175,14 @@ if(LIB_ARCH)
|
|
|
141
175
|
if(EMNAPI_BUILD_MT)
|
|
142
176
|
install(TARGETS ${EMNAPI_MT_TARGET_NAME} DESTINATION "lib/${LIB_ARCH}")
|
|
143
177
|
endif()
|
|
178
|
+
if(EMNAPI_BUILD_BASIC_MT)
|
|
179
|
+
install(TARGETS ${EMNAPI_BASIC_MT_TARGET_NAME} DESTINATION "lib/${LIB_ARCH}")
|
|
180
|
+
endif()
|
|
144
181
|
if(IS_WASM32)
|
|
145
182
|
install(TARGETS ${DLMALLOC_TARGET_NAME} DESTINATION "lib/${LIB_ARCH}")
|
|
183
|
+
install(TARGETS ${DLMALLOC_MT_TARGET_NAME} DESTINATION "lib/${LIB_ARCH}")
|
|
146
184
|
install(TARGETS ${EMMALLOC_TARGET_NAME} DESTINATION "lib/${LIB_ARCH}")
|
|
185
|
+
install(TARGETS ${EMMALLOC_MT_TARGET_NAME} DESTINATION "lib/${LIB_ARCH}")
|
|
147
186
|
endif()
|
|
148
187
|
endif()
|
|
149
188
|
|
|
@@ -178,4 +217,7 @@ if(EMNAPI_INSTALL_SRC)
|
|
|
178
217
|
install(DIRECTORY
|
|
179
218
|
${CMAKE_CURRENT_SOURCE_DIR}/src/malloc
|
|
180
219
|
DESTINATION "src/${PROJECT_NAME}")
|
|
220
|
+
install(DIRECTORY
|
|
221
|
+
${CMAKE_CURRENT_SOURCE_DIR}/src/thread
|
|
222
|
+
DESTINATION "src/${PROJECT_NAME}")
|
|
181
223
|
endif()
|
package/README.md
CHANGED
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
|
|
7
7
|
[](https://github.com/toyobayashi/emnapi/actions/workflows/main.yml)
|
|
8
8
|
|
|
9
|
-
[Node-API](https://nodejs.org/docs/latest/api/n-api.html) implementation for [Emscripten](https://emscripten.org/index.html), [wasi-sdk](https://github.com/WebAssembly/wasi-sdk) and clang with wasm support.
|
|
9
|
+
[Node-API](https://nodejs.org/docs/latest/api/n-api.html) implementation for [Emscripten](https://emscripten.org/index.html), [wasi-sdk](https://github.com/WebAssembly/wasi-sdk) and clang with wasm support. napi-rs support is comming soon.
|
|
10
10
|
|
|
11
11
|
This project aims to
|
|
12
12
|
|
|
@@ -25,16 +25,6 @@ See documentation for more details:
|
|
|
25
25
|
|
|
26
26
|
[How to build Node-API official examples](https://github.com/toyobayashi/node-addon-examples)
|
|
27
27
|
|
|
28
|
-
Emscripten is the first class support target. If your target is running addon on browser,
|
|
29
|
-
we strongly recommend you to use Emscripten instead of wasi-sdk. Async works and threadsafe
|
|
30
|
-
functions related APIs are only available on Emscripten or `wasm32-wasi-threads` target since
|
|
31
|
-
they are relying on pthread. Though today we have [WASI browser polyfill](https://github.com/toyobayashi/wasm-util),
|
|
32
|
-
`wasm32-wasi-threads` is in very early stage and WASI itself is not designed for browser.
|
|
33
|
-
There are some limitations on browser about wasi-libc's pthread implementation, for example
|
|
34
|
-
`pthread_mutex_lock` may call `__builtin_wasm_memory_atomic_wait32`(`memory.atomic.wait32`)
|
|
35
|
-
which is disallowed in browser JS main thread. While Emscripten's pthread implementation
|
|
36
|
-
has considered usage in browser.
|
|
37
|
-
|
|
38
28
|
## Prerequests
|
|
39
29
|
|
|
40
30
|
You will need to install:
|
|
@@ -174,7 +164,7 @@ emcc -O3 \
|
|
|
174
164
|
-I./node_modules/emnapi/include \
|
|
175
165
|
-L./node_modules/emnapi/lib/wasm32-emscripten \
|
|
176
166
|
--js-library=./node_modules/emnapi/dist/library_napi.js \
|
|
177
|
-
-sEXPORTED_FUNCTIONS="['_malloc','_free']" \
|
|
167
|
+
-sEXPORTED_FUNCTIONS="['_napi_register_wasm_v1','_malloc','_free']" \
|
|
178
168
|
-o hello.js \
|
|
179
169
|
hello.c \
|
|
180
170
|
-lemnapi
|
|
@@ -275,6 +265,9 @@ declare namespace Module {
|
|
|
275
265
|
* napi_create_async_work and napi_create_threadsafe_function
|
|
276
266
|
*/
|
|
277
267
|
nodeBinding?: typeof import('@emnapi/node-binding')
|
|
268
|
+
|
|
269
|
+
/** See Multithread part */
|
|
270
|
+
asyncWorkPoolSize?: number
|
|
278
271
|
}
|
|
279
272
|
export function emnapiInit (options: EmnapiInitOptions): any
|
|
280
273
|
}
|
|
@@ -392,7 +385,7 @@ import { WASI } from '@tybys/wasm-util'
|
|
|
392
385
|
import { Volume, createFsFromVolume } from 'memfs-browser'
|
|
393
386
|
|
|
394
387
|
const fs = createFsFromVolume(Volume.fromJSON({ /* ... */ }))
|
|
395
|
-
|
|
388
|
+
instantiateNapiModule(fetch('./hello.wasm'), {
|
|
396
389
|
wasi: new WASI({ fs, /* ... */ })
|
|
397
390
|
context: getDefaultContext(),
|
|
398
391
|
overwriteImports (importObject) {
|
|
@@ -450,7 +443,7 @@ em++ -O3 \
|
|
|
450
443
|
-I./node_modules/emnapi/include \
|
|
451
444
|
-L./node_modules/emnapi/lib/wasm32-emscripten \
|
|
452
445
|
--js-library=./node_modules/emnapi/dist/library_napi.js \
|
|
453
|
-
-sEXPORTED_FUNCTIONS="['_malloc','_free']" \
|
|
446
|
+
-sEXPORTED_FUNCTIONS="['_napi_register_wasm_v1','_malloc','_free']" \
|
|
454
447
|
-o hello.js \
|
|
455
448
|
hello.cpp \
|
|
456
449
|
-lemnapi
|
|
@@ -548,7 +541,7 @@ add_executable(hello hello.c)
|
|
|
548
541
|
target_link_libraries(hello emnapi)
|
|
549
542
|
if(CMAKE_SYSTEM_NAME STREQUAL "Emscripten")
|
|
550
543
|
target_link_options(hello PRIVATE
|
|
551
|
-
"-sEXPORTED_FUNCTIONS=['_malloc','_free']"
|
|
544
|
+
"-sEXPORTED_FUNCTIONS=['_napi_register_wasm_v1','_malloc','_free']"
|
|
552
545
|
)
|
|
553
546
|
elseif(CMAKE_SYSTEM_NAME STREQUAL "WASI")
|
|
554
547
|
set_target_properties(hello PROPERTIES SUFFIX ".wasm")
|
|
@@ -623,9 +616,9 @@ path = "src/main.rs"
|
|
|
623
616
|
# crate-type = ["cdylib"]
|
|
624
617
|
|
|
625
618
|
[dependencies]
|
|
626
|
-
napi = { version = "2.
|
|
619
|
+
napi = { version = "2.12.1", default-features = false, features = ["napi8"] }
|
|
627
620
|
napi-sys = { version = "2.2.3", features = ["napi8"] }
|
|
628
|
-
napi-derive = "2.
|
|
621
|
+
napi-derive = "2.12.2"
|
|
629
622
|
|
|
630
623
|
[build-dependencies]
|
|
631
624
|
napi-build = "2.0.1"
|
|
@@ -685,71 +678,134 @@ rustflags = [
|
|
|
685
678
|
```rust
|
|
686
679
|
#![no_main]
|
|
687
680
|
|
|
688
|
-
use napi
|
|
689
|
-
|
|
690
|
-
#[cfg(target_arch = "wasm32")]
|
|
691
|
-
use napi::bindgen_prelude::*;
|
|
692
|
-
#[cfg(target_arch = "wasm32")]
|
|
693
|
-
use napi_sys::*;
|
|
681
|
+
use napi_derive::napi;
|
|
694
682
|
|
|
695
|
-
#[
|
|
696
|
-
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
|
|
683
|
+
#[napi]
|
|
684
|
+
fn fibonacci(n: u32) -> u32 {
|
|
685
|
+
match n {
|
|
686
|
+
1 | 2 => 1,
|
|
687
|
+
_ => fibonacci(n - 1) + fibonacci(n - 2),
|
|
688
|
+
}
|
|
700
689
|
}
|
|
690
|
+
```
|
|
701
691
|
|
|
702
|
-
|
|
703
|
-
fn sum_js(ctx: CallContext) -> napi::Result<napi::JsNumber> {
|
|
704
|
-
let arg0 = ctx.get::<napi::JsNumber>(0)?.get_int32()?;
|
|
705
|
-
let arg1 = ctx.get::<napi::JsNumber>(1)?.get_int32()?;
|
|
706
|
-
let ret = sum(arg0, arg1);
|
|
707
|
-
ctx.env.create_int32(ret)
|
|
708
|
-
}
|
|
692
|
+
</details>
|
|
709
693
|
|
|
710
|
-
|
|
711
|
-
|
|
694
|
+
<details>
|
|
695
|
+
<summary>index.js</summary><br />
|
|
712
696
|
|
|
713
|
-
|
|
714
|
-
|
|
697
|
+
```js
|
|
698
|
+
const fs = require('fs')
|
|
699
|
+
const path = require('path')
|
|
700
|
+
const useWASI = false
|
|
715
701
|
|
|
716
|
-
|
|
717
|
-
|
|
718
|
-
|
|
719
|
-
|
|
702
|
+
let wasi
|
|
703
|
+
if (useWASI) {
|
|
704
|
+
const { WASI } = require('wasi')
|
|
705
|
+
wasi = new WASI({ /* ... */ })
|
|
720
706
|
}
|
|
721
707
|
|
|
722
|
-
|
|
723
|
-
|
|
724
|
-
|
|
725
|
-
|
|
726
|
-
|
|
727
|
-
|
|
728
|
-
|
|
708
|
+
const { instantiateNapiModule } = require('@emnapi/core')
|
|
709
|
+
|
|
710
|
+
const wasmBuffer = useWASI
|
|
711
|
+
? fs.readFileSync(path.join(__dirname, './target/wasm32-wasi/release/binding.wasm'))
|
|
712
|
+
: fs.readFileSync(path.join(__dirname, './target/wasm32-unknown-unknown/release/binding.wasm'))
|
|
713
|
+
|
|
714
|
+
instantiateNapiModule(wasmBuffer, {
|
|
715
|
+
context: require('@emnapi/runtime').getDefaultContext(),
|
|
716
|
+
wasi,
|
|
717
|
+
beforeInit ({ instance }) {
|
|
718
|
+
for (const sym in instance.exports) {
|
|
719
|
+
if (sym.startsWith('__napi_register__')) {
|
|
720
|
+
instance.exports[sym]()
|
|
721
|
+
}
|
|
722
|
+
}
|
|
723
|
+
},
|
|
724
|
+
overwriteImports (importObject) {
|
|
725
|
+
importObject.env = {
|
|
726
|
+
...importObject.env,
|
|
727
|
+
...importObject.napi,
|
|
728
|
+
...importObject.emnapi
|
|
729
|
+
}
|
|
730
|
+
}
|
|
731
|
+
}).then(({ instance, napiModule }) => {
|
|
732
|
+
const binding = napiModule.exports
|
|
733
|
+
// output: 5
|
|
734
|
+
console.log(binding.fibonacci(5))
|
|
735
|
+
})
|
|
729
736
|
```
|
|
730
737
|
|
|
731
738
|
</details>
|
|
732
739
|
|
|
733
740
|
### Multithread
|
|
734
741
|
|
|
735
|
-
|
|
736
|
-
|
|
737
|
-
|
|
742
|
+
Related API:
|
|
743
|
+
|
|
744
|
+
- [napi_*_async_work](https://nodejs.org/dist/latest/docs/api/n-api.html#napi_create_async_work)
|
|
745
|
+
- [napi_*_threadsafe_function](https://nodejs.org/dist/latest/docs/api/n-api.html#asynchronous-thread-safe-function-calls)
|
|
746
|
+
|
|
747
|
+
They are available in emnapi, but you need to know more details before you start to use them.
|
|
748
|
+
Now emnapi has 3 implementations of async work and 2 implementations of TSFN:
|
|
738
749
|
|
|
739
|
-
|
|
750
|
+
- Async work
|
|
751
|
+
- A. Libuv threadpool and pthread based implementation in C
|
|
752
|
+
- B. Single thread mock in JavaScript
|
|
753
|
+
- C. Web worker based implementation in C (stack allocation) and JavaScript
|
|
754
|
+
- TSFN
|
|
755
|
+
- D. Libuv and pthread based implementation in C
|
|
756
|
+
- E. Web worker based implementation in JavaScript
|
|
757
|
+
|
|
758
|
+
| | Library to Link | `wasm32-emscripten` | `wasm32` | `wasm32-wasi` | `wasm32-wasi-threads` |
|
|
759
|
+
|---|------------------------|---------------------|----------|---------------|-----------------------|
|
|
760
|
+
| A | libemnapi-mt.a | ✅ | ❌ | ❌ | ✅ |
|
|
761
|
+
| B | libemnapi-basic(-mt).a | ✅ | ✅ | ✅ | ✅ |
|
|
762
|
+
| C | libemnapi-basic-mt.a | ❌ | ✅ | ❌ | ✅ |
|
|
763
|
+
| D | libemnapi-mt.a | ✅ | ❌ | ❌ | ✅ |
|
|
764
|
+
| E | libemnapi-basic(-mt).a | ✅ | ✅ | ✅ | ✅ |
|
|
765
|
+
|
|
766
|
+
There are some limitations on browser about wasi-libc's pthread implementation, for example
|
|
767
|
+
`pthread_mutex_lock` may call `__builtin_wasm_memory_atomic_wait32`(`memory.atomic.wait32`)
|
|
768
|
+
which is disallowed in browser JS main thread. While Emscripten's pthread implementation
|
|
769
|
+
has considered usage in browser. If you need to run your addon with multithreaded features on browser,
|
|
770
|
+
we recommend you use Emscripten A & D, or bare wasm32 C & E.
|
|
771
|
+
|
|
772
|
+
Note: For browsers, all the multithreaded features relying on Web Workers (Emscripten pthread also relying on Web Workers)
|
|
773
|
+
require cross-origin isolation to enable `SharedArrayBuffer`. You can make a page cross-origin isolated
|
|
774
|
+
by serving the page with these headers:
|
|
775
|
+
|
|
776
|
+
```
|
|
777
|
+
Cross-Origin-Embedder-Policy: require-corp
|
|
778
|
+
Cross-Origin-Opener-Policy: same-origin
|
|
779
|
+
```
|
|
780
|
+
|
|
781
|
+
#### About Prebuilt Libraries
|
|
782
|
+
|
|
783
|
+
Prebuilt libraries can be found in the `lib` directory in `emnapi` npm package.
|
|
784
|
+
|
|
785
|
+
| Library | Description | `wasm32-emscripten` | `wasm32` | `wasm32-wasi` | `wasm32-wasi-threads` |
|
|
786
|
+
|----------------------|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|---------------------|----------|---------------|-----------------------------------------|
|
|
787
|
+
| libemnapi.a | no atomics feature.<br/><br/> no libuv port.<br/><br/> `napi_*_async_work` and `napi_*_threadsafe_function` always return `napi_generic_failure`. | ✅ | ✅ | ✅ | waiting wasi-sdk release thread support |
|
|
788
|
+
| libemnapi-mt.a | atomics feature enabled.<br/><br/> `napi_*_async_work` and `napi_*_threadsafe_function` are based on pthread and libuv port. | ✅ | ❌ | ❌ | waiting wasi-sdk release thread support |
|
|
789
|
+
| libemnapi-basic.a | no atomics feature.<br/><br/> no libuv port.<br/><br/> `napi_*_async_work` and `napi_*_threadsafe_function` are imported from JavaScript land. | ✅ | ✅ | ✅ | waiting wasi-sdk release thread support |
|
|
790
|
+
| libemnapi-basic-mt.a | atomics feature enabled.<br/><br/> no libuv port.<br/><br/> `napi_*_async_work` and `napi_*_threadsafe_function` are imported from JavaScript land.<br/><br/> include `emnapi_async_worker_create` and `emnapi_async_worker_init` for WebWorker based async work implementation. | ❌ | ✅ | ✅ | waiting wasi-sdk release thread support |
|
|
791
|
+
| libdlmalloc.a | no atomics feature, no thread safe garanteed. | ❌ | ✅ | ❌ | ❌ |
|
|
792
|
+
| libdlmalloc-mt.a | atomics feature enabled, thread safe. | ❌ | ✅ | ❌ | ❌ |
|
|
793
|
+
| libemmalloc.a | no atomics feature, no thread safe garanteed. | ❌ | ✅ | ❌ | ❌ |
|
|
794
|
+
| libemmalloc-mt.a | atomics feature enabled, thread safe. | ❌ | ✅ | ❌ | ❌ |
|
|
795
|
+
|
|
796
|
+
#### Usage
|
|
740
797
|
|
|
741
798
|
```cmake
|
|
742
799
|
add_subdirectory("${CMAKE_CURRENT_SOURCE_DIR}/node_modules/emnapi")
|
|
743
800
|
|
|
744
801
|
add_executable(hello hello.c)
|
|
745
802
|
|
|
746
|
-
target_link_libraries(hello emnapi-mt)
|
|
747
|
-
|
|
748
803
|
if(CMAKE_SYSTEM_NAME STREQUAL "Emscripten")
|
|
804
|
+
target_link_libraries(hello emnapi-mt)
|
|
749
805
|
target_compile_options(hello PRIVATE "-pthread")
|
|
750
806
|
target_link_options(hello PRIVATE
|
|
751
807
|
"-sALLOW_MEMORY_GROWTH=1"
|
|
752
|
-
"-sEXPORTED_FUNCTIONS=['_malloc','_free']"
|
|
808
|
+
"-sEXPORTED_FUNCTIONS=['_napi_register_wasm_v1','_malloc','_free']"
|
|
753
809
|
"-pthread"
|
|
754
810
|
"-sPTHREAD_POOL_SIZE=4"
|
|
755
811
|
# try to specify stack size if you experience pthread errors
|
|
@@ -758,6 +814,7 @@ if(CMAKE_SYSTEM_NAME STREQUAL "Emscripten")
|
|
|
758
814
|
)
|
|
759
815
|
elseif(CMAKE_C_COMPILER_TARGET STREQUAL "wasm32-wasi-threads")
|
|
760
816
|
# Experimental
|
|
817
|
+
target_link_libraries(hello emnapi-mt)
|
|
761
818
|
set_target_properties(hello PROPERTIES SUFFIX ".wasm")
|
|
762
819
|
target_compile_options(hello PRIVATE "-fno-exceptions" "-pthread")
|
|
763
820
|
target_link_options(hello PRIVATE
|
|
@@ -771,6 +828,19 @@ elseif(CMAKE_C_COMPILER_TARGET STREQUAL "wasm32-wasi-threads")
|
|
|
771
828
|
"-Wl,--import-undefined"
|
|
772
829
|
"-Wl,--export-table"
|
|
773
830
|
)
|
|
831
|
+
elseif((CMAKE_C_COMPILER_TARGET STREQUAL "wasm32") OR (CMAKE_C_COMPILER_TARGET STREQUAL "wasm32-unknown-unknown"))
|
|
832
|
+
target_link_libraries(hello emnapi-basic-mt)
|
|
833
|
+
set_target_properties(hello PROPERTIES SUFFIX ".wasm")
|
|
834
|
+
target_compile_options(hello PRIVATE "-fno-exceptions" "-matomics" "-mbulk-memory")
|
|
835
|
+
target_link_options(hello PRIVATE
|
|
836
|
+
"-nostdlib"
|
|
837
|
+
"-Wl,--no-entry"
|
|
838
|
+
"-Wl,--export=napi_register_wasm_v1"
|
|
839
|
+
"-Wl,--export=emnapi_async_worker_create"
|
|
840
|
+
"-Wl,--export=emnapi_async_worker_init"
|
|
841
|
+
"-Wl,--import-memory,--shared-memory,--max-memory=2147483648,--import-undefined"
|
|
842
|
+
"-Wl,--export-dynamic,--export=malloc,--export=free,--export-table"
|
|
843
|
+
)
|
|
774
844
|
endif()
|
|
775
845
|
```
|
|
776
846
|
|
|
@@ -784,6 +854,11 @@ cmake -DCMAKE_TOOLCHAIN_FILE=$WASI_SDK_PATH/share/cmake/wasi-sdk-pthread.cmake \
|
|
|
784
854
|
-DCMAKE_BUILD_TYPE=Release \
|
|
785
855
|
-G Ninja -H. -Bbuild
|
|
786
856
|
|
|
857
|
+
cmake -DCMAKE_TOOLCHAIN_FILE=node_modules/emnapi/cmake/wasm32.cmake \
|
|
858
|
+
-DLLVM_PREFIX=$WASI_SDK_PATH \
|
|
859
|
+
-DCMAKE_BUILD_TYPE=Release \
|
|
860
|
+
-G Ninja -H. -Bbuild
|
|
861
|
+
|
|
787
862
|
cmake --build build
|
|
788
863
|
```
|
|
789
864
|
|
|
@@ -793,6 +868,15 @@ And additional work is required during instantiating wasm compiled with non-emsc
|
|
|
793
868
|
// emnapi main thread (could be in a Worker)
|
|
794
869
|
instantiateNapiModule(input, {
|
|
795
870
|
context: getDefaultContext(),
|
|
871
|
+
/**
|
|
872
|
+
* emscripten
|
|
873
|
+
* 0: no effect
|
|
874
|
+
* > 0: the same effect to UV_THREADPOOL_SIZE
|
|
875
|
+
* non-emscripten
|
|
876
|
+
* 0: single thread mock
|
|
877
|
+
* > 0 schedule async work in web worker
|
|
878
|
+
*/
|
|
879
|
+
asyncWorkPoolSize: 4, // 0: single thread mock, > 0: schedule async work in web worker
|
|
796
880
|
wasi: new WASI(/* ... */),
|
|
797
881
|
// reuseWorker: true,
|
|
798
882
|
onCreateWorker () {
|
|
@@ -890,17 +974,30 @@ instantiateNapiModule(input, {
|
|
|
890
974
|
|
|
891
975
|
### `-DEMNAPI_WORKER_POOL_SIZE=4`
|
|
892
976
|
|
|
893
|
-
This is [`UV_THREADPOOL_SIZE`](http://docs.libuv.org/en/v1.x/threadpool.html?highlight=UV_THREADPOOL_SIZE) equivalent at compile time, if not predefined, emnapi will read `UV_THREADPOOL_SIZE` from Emscripten [environment variable](https://emscripten.org/docs/porting/connecting_cpp_and_javascript/Interacting-with-code.html#interacting-with-code-environment-variables) at runtime
|
|
977
|
+
This is [`UV_THREADPOOL_SIZE`](http://docs.libuv.org/en/v1.x/threadpool.html?highlight=UV_THREADPOOL_SIZE) equivalent at compile time, if not predefined, emnapi will read `asyncWorkPoolSize` option or `UV_THREADPOOL_SIZE` from Emscripten [environment variable](https://emscripten.org/docs/porting/connecting_cpp_and_javascript/Interacting-with-code.html#interacting-with-code-environment-variables) at runtime:
|
|
894
978
|
|
|
895
979
|
```js
|
|
980
|
+
Module.init({
|
|
981
|
+
// ...
|
|
982
|
+
asyncWorkPoolSize: 2
|
|
983
|
+
})
|
|
984
|
+
|
|
985
|
+
// if asyncWorkPoolSize is not specified
|
|
896
986
|
Module.preRun = Module.preRun || [];
|
|
897
987
|
Module.preRun.push(function () {
|
|
898
988
|
if (typeof ENV !== 'undefined') {
|
|
899
989
|
ENV.UV_THREADPOOL_SIZE = '2';
|
|
900
990
|
}
|
|
901
991
|
});
|
|
992
|
+
```
|
|
902
993
|
|
|
994
|
+
```js
|
|
903
995
|
// wasi
|
|
996
|
+
instantiateNapiModule({
|
|
997
|
+
// ...
|
|
998
|
+
asyncWorkPoolSize: 2
|
|
999
|
+
})
|
|
1000
|
+
// if asyncWorkPoolSize is not specified
|
|
904
1001
|
new WASI({
|
|
905
1002
|
env: {
|
|
906
1003
|
UV_THREADPOOL_SIZE: '2'
|
|
@@ -908,7 +1005,7 @@ new WASI({
|
|
|
908
1005
|
})
|
|
909
1006
|
```
|
|
910
1007
|
|
|
911
|
-
It represent max of `EMNAPI_WORKER_POOL_SIZE` async work (`napi_queue_async_work`) can be executed in parallel. Default is not defined
|
|
1008
|
+
It represent max of `EMNAPI_WORKER_POOL_SIZE` async work (`napi_queue_async_work`) can be executed in parallel. Default is not defined.
|
|
912
1009
|
|
|
913
1010
|
You can set both `PTHREAD_POOL_SIZE` and `EMNAPI_WORKER_POOL_SIZE` to `number of CPU cores` in general.
|
|
914
1011
|
If you use another library function which may create `N` child threads in async work,
|
package/cmake/wasm32.cmake
CHANGED
|
@@ -16,10 +16,12 @@ endif()
|
|
|
16
16
|
|
|
17
17
|
set(CMAKE_C_COMPILER ${LLVM_PREFIX}/bin/clang${WASM_HOST_EXE_SUFFIX})
|
|
18
18
|
set(CMAKE_CXX_COMPILER ${LLVM_PREFIX}/bin/clang++${WASM_HOST_EXE_SUFFIX})
|
|
19
|
+
set(CMAKE_ASM_COMPILER ${LLVM_PREFIX}/bin/clang${WASI_HOST_EXE_SUFFIX})
|
|
19
20
|
set(CMAKE_AR ${LLVM_PREFIX}/bin/llvm-ar${WASM_HOST_EXE_SUFFIX})
|
|
20
21
|
set(CMAKE_RANLIB ${LLVM_PREFIX}/bin/llvm-ranlib${WASM_HOST_EXE_SUFFIX})
|
|
21
22
|
set(CMAKE_C_COMPILER_TARGET ${triple})
|
|
22
23
|
set(CMAKE_CXX_COMPILER_TARGET ${triple})
|
|
24
|
+
set(CMAKE_ASM_COMPILER_TARGET ${triple})
|
|
23
25
|
|
|
24
26
|
# Don't look in the sysroot for executables to run during the build
|
|
25
27
|
set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER)
|
package/dist/library_napi.js
CHANGED
|
@@ -1,37 +1,33 @@
|
|
|
1
1
|
{{{ ((DEFAULT_LIBRARY_FUNCS_TO_INCLUDE.indexOf("$emnapiInit") === -1 ? DEFAULT_LIBRARY_FUNCS_TO_INCLUDE.push("$emnapiInit") : undefined), "") }}}
|
|
2
2
|
{{{ ((EXPORTED_RUNTIME_METHODS.indexOf("emnapiInit") === -1 ? EXPORTED_RUNTIME_METHODS.push("emnapiInit") : undefined), "") }}}
|
|
3
|
-
|
|
4
|
-
function emnapiCreateIdGenerator() {
|
|
5
|
-
var obj = {
|
|
6
|
-
nextId: 1,
|
|
7
|
-
list: [],
|
|
8
|
-
generate: function () {
|
|
9
|
-
var id;
|
|
10
|
-
if (obj.list.length) {
|
|
11
|
-
id = obj.list.shift();
|
|
12
|
-
}
|
|
13
|
-
else {
|
|
14
|
-
id = obj.nextId;
|
|
15
|
-
obj.nextId++;
|
|
16
|
-
}
|
|
17
|
-
return id;
|
|
18
|
-
},
|
|
19
|
-
reuse: function (id) {
|
|
20
|
-
obj.list.push(id);
|
|
21
|
-
}
|
|
22
|
-
};
|
|
23
|
-
return obj;
|
|
24
|
-
}
|
|
25
|
-
var emnapiAsyncWork = {
|
|
3
|
+
var emnapiAWST = {
|
|
26
4
|
idGen: {},
|
|
27
5
|
values: [undefined],
|
|
28
6
|
queued: new Set(),
|
|
29
7
|
pending: [],
|
|
30
8
|
init: function () {
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
9
|
+
var idGen = {
|
|
10
|
+
nextId: 1,
|
|
11
|
+
list: [],
|
|
12
|
+
generate: function () {
|
|
13
|
+
var id;
|
|
14
|
+
if (idGen.list.length) {
|
|
15
|
+
id = idGen.list.shift();
|
|
16
|
+
}
|
|
17
|
+
else {
|
|
18
|
+
id = idGen.nextId;
|
|
19
|
+
idGen.nextId++;
|
|
20
|
+
}
|
|
21
|
+
return id;
|
|
22
|
+
},
|
|
23
|
+
reuse: function (id) {
|
|
24
|
+
idGen.list.push(id);
|
|
25
|
+
}
|
|
26
|
+
};
|
|
27
|
+
emnapiAWST.idGen = idGen;
|
|
28
|
+
emnapiAWST.values = [undefined];
|
|
29
|
+
emnapiAWST.queued = new Set();
|
|
30
|
+
emnapiAWST.pending = [];
|
|
35
31
|
},
|
|
36
32
|
create: function (env, resource, resourceName, execute, complete, data) {
|
|
37
33
|
var asyncId = 0;
|
|
@@ -41,12 +37,11 @@ var emnapiAsyncWork = {
|
|
|
41
37
|
asyncId = asyncContext.asyncId;
|
|
42
38
|
triggerAsyncId = asyncContext.triggerAsyncId;
|
|
43
39
|
}
|
|
44
|
-
var id =
|
|
45
|
-
|
|
40
|
+
var id = emnapiAWST.idGen.generate();
|
|
41
|
+
emnapiAWST.values[id] = {
|
|
46
42
|
env: env,
|
|
47
43
|
id: id,
|
|
48
44
|
resource: resource,
|
|
49
|
-
resourceName: resourceName,
|
|
50
45
|
asyncId: asyncId,
|
|
51
46
|
triggerAsyncId: triggerAsyncId,
|
|
52
47
|
status: 0,
|
|
@@ -62,6 +57,8 @@ var emnapiAsyncWork = {
|
|
|
62
57
|
var env = work.env;
|
|
63
58
|
var data = work.data;
|
|
64
59
|
var callback = function () {
|
|
60
|
+
if (!complete)
|
|
61
|
+
return;
|
|
65
62
|
var envObject = emnapiCtx.envStore.get(env);
|
|
66
63
|
var scope = emnapiCtx.openScope(envObject);
|
|
67
64
|
try {
|
|
@@ -84,16 +81,16 @@ var emnapiAsyncWork = {
|
|
|
84
81
|
}
|
|
85
82
|
},
|
|
86
83
|
queue: function (id) {
|
|
87
|
-
var work =
|
|
84
|
+
var work = emnapiAWST.values[id];
|
|
88
85
|
if (!work)
|
|
89
86
|
return;
|
|
90
87
|
if (work.status === 0) {
|
|
91
88
|
work.status = 1;
|
|
92
|
-
if (
|
|
93
|
-
|
|
89
|
+
if (emnapiAWST.queued.size >= (Math.abs(emnapiAsyncWorkPoolSize) || 4)) {
|
|
90
|
+
emnapiAWST.pending.push(id);
|
|
94
91
|
return;
|
|
95
92
|
}
|
|
96
|
-
|
|
93
|
+
emnapiAWST.queued.add(id);
|
|
97
94
|
var env_1 = work.env;
|
|
98
95
|
var data_1 = work.data;
|
|
99
96
|
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
@@ -101,25 +98,29 @@ var emnapiAsyncWork = {
|
|
|
101
98
|
work.status = 2;
|
|
102
99
|
emnapiCtx.feature.setImmediate(function () {
|
|
103
100
|
{{{ makeDynCall('vpp', 'execute') }}}(env_1, data_1);
|
|
104
|
-
|
|
101
|
+
emnapiAWST.queued.delete(id);
|
|
105
102
|
work.status = 3;
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
103
|
+
emnapiCtx.feature.setImmediate(function () {
|
|
104
|
+
emnapiAWST.callComplete(work, 0 /* napi_status.napi_ok */);
|
|
105
|
+
});
|
|
106
|
+
if (emnapiAWST.pending.length > 0) {
|
|
107
|
+
var nextWorkId = emnapiAWST.pending.shift();
|
|
108
|
+
emnapiAWST.values[nextWorkId].status = 0;
|
|
109
|
+
emnapiAWST.queue(nextWorkId);
|
|
111
110
|
}
|
|
112
111
|
});
|
|
113
112
|
}
|
|
114
113
|
},
|
|
115
114
|
cancel: function (id) {
|
|
116
|
-
var index =
|
|
115
|
+
var index = emnapiAWST.pending.indexOf(id);
|
|
117
116
|
if (index !== -1) {
|
|
118
|
-
var
|
|
119
|
-
if (
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
117
|
+
var work_1 = emnapiAWST.values[id];
|
|
118
|
+
if (work_1 && (work_1.status === 1)) {
|
|
119
|
+
work_1.status = 4;
|
|
120
|
+
emnapiAWST.pending.splice(index, 1);
|
|
121
|
+
emnapiCtx.feature.setImmediate(function () {
|
|
122
|
+
emnapiAWST.callComplete(work_1, 11 /* napi_status.napi_cancelled */);
|
|
123
|
+
});
|
|
123
124
|
return 0 /* napi_status.napi_ok */;
|
|
124
125
|
}
|
|
125
126
|
else {
|
|
@@ -129,7 +130,7 @@ var emnapiAsyncWork = {
|
|
|
129
130
|
return 9 /* napi_status.napi_generic_failure */;
|
|
130
131
|
},
|
|
131
132
|
remove: function (id) {
|
|
132
|
-
var work =
|
|
133
|
+
var work = emnapiAWST.values[id];
|
|
133
134
|
if (!work)
|
|
134
135
|
return;
|
|
135
136
|
if (emnapiNodeBinding) {
|
|
@@ -138,68 +139,11 @@ var emnapiAsyncWork = {
|
|
|
138
139
|
triggerAsyncId: work.triggerAsyncId
|
|
139
140
|
});
|
|
140
141
|
}
|
|
141
|
-
|
|
142
|
-
|
|
142
|
+
emnapiAWST.values[id] = undefined;
|
|
143
|
+
emnapiAWST.idGen.reuse(id);
|
|
143
144
|
}
|
|
144
145
|
};
|
|
145
|
-
|
|
146
|
-
if (env == 0)
|
|
147
|
-
return 1 /* napi_status.napi_invalid_arg */;
|
|
148
|
-
var envObject = emnapiCtx.envStore.get(env);
|
|
149
|
-
if (execute == 0)
|
|
150
|
-
return envObject.setLastError(1 /* napi_status.napi_invalid_arg */);
|
|
151
|
-
if (result == 0)
|
|
152
|
-
return envObject.setLastError(1 /* napi_status.napi_invalid_arg */);
|
|
153
|
-
var resourceObject;
|
|
154
|
-
if (resource) {
|
|
155
|
-
resourceObject = Object(emnapiCtx.handleStore.get(resource).value);
|
|
156
|
-
}
|
|
157
|
-
else {
|
|
158
|
-
resourceObject = {};
|
|
159
|
-
}
|
|
160
|
-
if (resource_name == 0)
|
|
161
|
-
return envObject.setLastError(1 /* napi_status.napi_invalid_arg */);
|
|
162
|
-
var resourceName = String(emnapiCtx.handleStore.get(resource_name).value);
|
|
163
|
-
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
164
|
-
var id = emnapiAsyncWork.create(env, resourceObject, resourceName, execute, complete, data);
|
|
165
|
-
{{{ makeSetValue('result', 0, 'id', '*') }}};
|
|
166
|
-
return envObject.clearLastError();
|
|
167
|
-
}
|
|
168
|
-
function _napi_delete_async_work(env, work) {
|
|
169
|
-
if (env == 0)
|
|
170
|
-
return 1 /* napi_status.napi_invalid_arg */;
|
|
171
|
-
var envObject = emnapiCtx.envStore.get(env);
|
|
172
|
-
if (work == 0)
|
|
173
|
-
return envObject.setLastError(1 /* napi_status.napi_invalid_arg */);
|
|
174
|
-
emnapiAsyncWork.remove(work);
|
|
175
|
-
return envObject.clearLastError();
|
|
176
|
-
}
|
|
177
|
-
function _napi_queue_async_work(env, work) {
|
|
178
|
-
if (env == 0)
|
|
179
|
-
return 1 /* napi_status.napi_invalid_arg */;
|
|
180
|
-
var envObject = emnapiCtx.envStore.get(env);
|
|
181
|
-
if (work == 0)
|
|
182
|
-
return envObject.setLastError(1 /* napi_status.napi_invalid_arg */);
|
|
183
|
-
emnapiAsyncWork.queue(work);
|
|
184
|
-
return envObject.clearLastError();
|
|
185
|
-
}
|
|
186
|
-
function _napi_cancel_async_work(env, work) {
|
|
187
|
-
if (env == 0)
|
|
188
|
-
return 1 /* napi_status.napi_invalid_arg */;
|
|
189
|
-
var envObject = emnapiCtx.envStore.get(env);
|
|
190
|
-
if (work == 0)
|
|
191
|
-
return envObject.setLastError(1 /* napi_status.napi_invalid_arg */);
|
|
192
|
-
var status = emnapiAsyncWork.cancel(work);
|
|
193
|
-
if (status === 0 /* napi_status.napi_ok */)
|
|
194
|
-
return envObject.clearLastError();
|
|
195
|
-
return envObject.setLastError(status);
|
|
196
|
-
}
|
|
197
|
-
emnapiImplementHelper('$emnapiCreateIdGenerator', undefined, emnapiCreateIdGenerator, []);
|
|
198
|
-
emnapiDefineVar('$emnapiAsyncWork', emnapiAsyncWork, ['$emnapiCreateIdGenerator'], 'emnapiAsyncWork.init();');
|
|
199
|
-
emnapiImplement('napi_create_async_work', 'ippppppp', _napi_create_async_work, ['$emnapiAsyncWork']);
|
|
200
|
-
emnapiImplement('napi_delete_async_work', 'ipp', _napi_delete_async_work, ['$emnapiAsyncWork']);
|
|
201
|
-
emnapiImplement('napi_queue_async_work', 'ipp', _napi_queue_async_work, ['$emnapiAsyncWork']);
|
|
202
|
-
emnapiImplement('napi_cancel_async_work', 'ipp', _napi_cancel_async_work, ['$emnapiAsyncWork']);
|
|
146
|
+
emnapiDefineVar('$emnapiAWST', emnapiAWST, ['$emnapiAsyncWorkPoolSize'], 'emnapiAWST.init();');
|
|
203
147
|
function _emnapi_create_memory_view(env, typedarray_type, external_data, byte_length, finalize_cb, finalize_hint, result
|
|
204
148
|
// @ts-expect-error
|
|
205
149
|
) {
|
|
@@ -1277,8 +1221,8 @@ function napi_create_reference(env, value, initial_refcount, result) {
|
|
|
1277
1221
|
if (result == 0)
|
|
1278
1222
|
return envObject.setLastError(1 /* napi_status.napi_invalid_arg */);
|
|
1279
1223
|
var handle = emnapiCtx.handleStore.get(value);
|
|
1280
|
-
if (!(handle.isObject() || handle.isFunction())) {
|
|
1281
|
-
return envObject.setLastError(
|
|
1224
|
+
if (!(handle.isObject() || handle.isFunction() || handle.isSymbol())) {
|
|
1225
|
+
return envObject.setLastError(1 /* napi_status.napi_invalid_arg */);
|
|
1282
1226
|
}
|
|
1283
1227
|
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
1284
1228
|
var ref = emnapiCtx.createReference(envObject, handle.id, initial_refcount >>> 0, 1 /* Ownership.kUserland */);
|
|
@@ -4736,17 +4680,22 @@ function napi_create_string_latin1(env, str, length, result) {
|
|
|
4736
4680
|
if (env == 0)
|
|
4737
4681
|
return 1 /* napi_status.napi_invalid_arg */;
|
|
4738
4682
|
var envObject = emnapiCtx.envStore.get(env);
|
|
4683
|
+
{{{ from64('length') }}};
|
|
4684
|
+
var autoLength = length === -1;
|
|
4685
|
+
length = length >>> 0;
|
|
4686
|
+
if (length !== 0) {
|
|
4687
|
+
if (str == 0)
|
|
4688
|
+
return envObject.setLastError(1 /* napi_status.napi_invalid_arg */);
|
|
4689
|
+
}
|
|
4739
4690
|
if (result == 0)
|
|
4740
4691
|
return envObject.setLastError(1 /* napi_status.napi_invalid_arg */);
|
|
4741
4692
|
{{{ from64('str') }}};
|
|
4742
|
-
|
|
4743
|
-
length = length >>> 0;
|
|
4744
|
-
if (!((length === 0xffffffff) || (length <= 2147483647)) || (!str)) {
|
|
4693
|
+
if (!(autoLength || (length <= 2147483647))) {
|
|
4745
4694
|
return envObject.setLastError(1 /* napi_status.napi_invalid_arg */);
|
|
4746
4695
|
}
|
|
4747
4696
|
var latin1String = '';
|
|
4748
4697
|
var len = 0;
|
|
4749
|
-
if (
|
|
4698
|
+
if (autoLength) {
|
|
4750
4699
|
while (true) {
|
|
4751
4700
|
var ch = {{{ makeGetValue('str', 0, 'u8') }}};
|
|
4752
4701
|
if (!ch)
|
|
@@ -4775,11 +4724,17 @@ function napi_create_string_utf16(env, str, length, result) {
|
|
|
4775
4724
|
if (env == 0)
|
|
4776
4725
|
return 1 /* napi_status.napi_invalid_arg */;
|
|
4777
4726
|
var envObject = emnapiCtx.envStore.get(env);
|
|
4727
|
+
{{{ from64('length') }}};
|
|
4728
|
+
var autoLength = length === -1;
|
|
4729
|
+
var sizelength = length >>> 0;
|
|
4730
|
+
if (length !== 0) {
|
|
4731
|
+
if (str == 0)
|
|
4732
|
+
return envObject.setLastError(1 /* napi_status.napi_invalid_arg */);
|
|
4733
|
+
}
|
|
4778
4734
|
if (result == 0)
|
|
4779
4735
|
return envObject.setLastError(1 /* napi_status.napi_invalid_arg */);
|
|
4780
4736
|
{{{ from64('str') }}};
|
|
4781
|
-
|
|
4782
|
-
if (((length < -1) || (length > 2147483647)) || (!str)) {
|
|
4737
|
+
if (!(autoLength || (sizelength <= 2147483647))) {
|
|
4783
4738
|
return envObject.setLastError(1 /* napi_status.napi_invalid_arg */);
|
|
4784
4739
|
}
|
|
4785
4740
|
var utf16String = emnapiUtf16ToString(str, length);
|
|
@@ -4793,11 +4748,17 @@ function napi_create_string_utf8(env, str, length, result) {
|
|
|
4793
4748
|
if (env == 0)
|
|
4794
4749
|
return 1 /* napi_status.napi_invalid_arg */;
|
|
4795
4750
|
var envObject = emnapiCtx.envStore.get(env);
|
|
4751
|
+
{{{ from64('length') }}};
|
|
4752
|
+
var autoLength = length === -1;
|
|
4753
|
+
var sizelength = length >>> 0;
|
|
4754
|
+
if (length !== 0) {
|
|
4755
|
+
if (str == 0)
|
|
4756
|
+
return envObject.setLastError(1 /* napi_status.napi_invalid_arg */);
|
|
4757
|
+
}
|
|
4796
4758
|
if (result == 0)
|
|
4797
4759
|
return envObject.setLastError(1 /* napi_status.napi_invalid_arg */);
|
|
4798
4760
|
{{{ from64('str') }}};
|
|
4799
|
-
|
|
4800
|
-
if (((length < -1) || (length > 2147483647)) || (!str)) {
|
|
4761
|
+
if (!(autoLength || (sizelength <= 2147483647))) {
|
|
4801
4762
|
return envObject.setLastError(1 /* napi_status.napi_invalid_arg */);
|
|
4802
4763
|
}
|
|
4803
4764
|
var utf8String = emnapiUtf8ToString(str, length);
|
|
@@ -5392,7 +5353,13 @@ function node_api_symbol_for(env, utf8description, length, result) {
|
|
|
5392
5353
|
{{{ from64('length') }}};
|
|
5393
5354
|
{{{ from64('utf8description') }}};
|
|
5394
5355
|
{{{ from64('result') }}};
|
|
5395
|
-
|
|
5356
|
+
var autoLength = length === -1;
|
|
5357
|
+
var sizelength = length >>> 0;
|
|
5358
|
+
if (length !== 0) {
|
|
5359
|
+
if (utf8description == 0)
|
|
5360
|
+
return envObject.setLastError(1 /* napi_status.napi_invalid_arg */);
|
|
5361
|
+
}
|
|
5362
|
+
if (!(autoLength || (sizelength <= 2147483647))) {
|
|
5396
5363
|
return envObject.setLastError(1 /* napi_status.napi_invalid_arg */);
|
|
5397
5364
|
}
|
|
5398
5365
|
var descriptionString = emnapiUtf8ToString(utf8description, length);
|
|
@@ -5468,6 +5435,62 @@ emnapiImplement('napi_get_boolean', 'ipip', napi_get_boolean);
|
|
|
5468
5435
|
emnapiImplement('napi_get_global', 'ipp', napi_get_global);
|
|
5469
5436
|
emnapiImplement('napi_get_null', 'ipp', napi_get_null);
|
|
5470
5437
|
emnapiImplement('napi_get_undefined', 'ipp', napi_get_undefined);
|
|
5438
|
+
function _napi_create_async_work(env, resource, resource_name, execute, complete, data, result) {
|
|
5439
|
+
if (env == 0)
|
|
5440
|
+
return 1 /* napi_status.napi_invalid_arg */;
|
|
5441
|
+
var envObject = emnapiCtx.envStore.get(env);
|
|
5442
|
+
if (execute == 0)
|
|
5443
|
+
return envObject.setLastError(1 /* napi_status.napi_invalid_arg */);
|
|
5444
|
+
if (result == 0)
|
|
5445
|
+
return envObject.setLastError(1 /* napi_status.napi_invalid_arg */);
|
|
5446
|
+
var resourceObject;
|
|
5447
|
+
if (resource) {
|
|
5448
|
+
resourceObject = Object(emnapiCtx.handleStore.get(resource).value);
|
|
5449
|
+
}
|
|
5450
|
+
else {
|
|
5451
|
+
resourceObject = {};
|
|
5452
|
+
}
|
|
5453
|
+
if (resource_name == 0)
|
|
5454
|
+
return envObject.setLastError(1 /* napi_status.napi_invalid_arg */);
|
|
5455
|
+
var resourceName = String(emnapiCtx.handleStore.get(resource_name).value);
|
|
5456
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
5457
|
+
var id = emnapiAWST.create(env, resourceObject, resourceName, execute, complete, data);
|
|
5458
|
+
{{{ makeSetValue('result', 0, 'id', '*') }}};
|
|
5459
|
+
return envObject.clearLastError();
|
|
5460
|
+
}
|
|
5461
|
+
function _napi_delete_async_work(env, work) {
|
|
5462
|
+
if (env == 0)
|
|
5463
|
+
return 1 /* napi_status.napi_invalid_arg */;
|
|
5464
|
+
var envObject = emnapiCtx.envStore.get(env);
|
|
5465
|
+
if (work == 0)
|
|
5466
|
+
return envObject.setLastError(1 /* napi_status.napi_invalid_arg */);
|
|
5467
|
+
emnapiAWST.remove(work);
|
|
5468
|
+
return envObject.clearLastError();
|
|
5469
|
+
}
|
|
5470
|
+
function _napi_queue_async_work(env, work) {
|
|
5471
|
+
if (env == 0)
|
|
5472
|
+
return 1 /* napi_status.napi_invalid_arg */;
|
|
5473
|
+
var envObject = emnapiCtx.envStore.get(env);
|
|
5474
|
+
if (work == 0)
|
|
5475
|
+
return envObject.setLastError(1 /* napi_status.napi_invalid_arg */);
|
|
5476
|
+
emnapiAWST.queue(work);
|
|
5477
|
+
return envObject.clearLastError();
|
|
5478
|
+
}
|
|
5479
|
+
function _napi_cancel_async_work(env, work) {
|
|
5480
|
+
if (env == 0)
|
|
5481
|
+
return 1 /* napi_status.napi_invalid_arg */;
|
|
5482
|
+
var envObject = emnapiCtx.envStore.get(env);
|
|
5483
|
+
if (work == 0)
|
|
5484
|
+
return envObject.setLastError(1 /* napi_status.napi_invalid_arg */);
|
|
5485
|
+
var status = emnapiAWST.cancel(work);
|
|
5486
|
+
if (status === 0 /* napi_status.napi_ok */)
|
|
5487
|
+
return envObject.clearLastError();
|
|
5488
|
+
return envObject.setLastError(status);
|
|
5489
|
+
}
|
|
5490
|
+
emnapiImplement('napi_create_async_work', 'ippppppp', _napi_create_async_work, ['$emnapiAWST']);
|
|
5491
|
+
emnapiImplement('napi_delete_async_work', 'ipp', _napi_delete_async_work, ['$emnapiAWST']);
|
|
5492
|
+
emnapiImplement('napi_queue_async_work', 'ipp', _napi_queue_async_work, ['$emnapiAWST']);
|
|
5493
|
+
emnapiImplement('napi_cancel_async_work', 'ipp', _napi_cancel_async_work, ['$emnapiAWST']);
|
|
5471
5494
|
mergeInto(LibraryManager.library, {
|
|
5472
5495
|
_emnapi_worker_unref__sig: 'vp',
|
|
5473
5496
|
_emnapi_worker_unref__deps: ['$PThread'],
|
|
@@ -5618,6 +5641,7 @@ emnapiDefineVar('$emnapiModule', {
|
|
|
5618
5641
|
loaded: false,
|
|
5619
5642
|
filename: ''
|
|
5620
5643
|
});
|
|
5644
|
+
emnapiDefineVar('$emnapiAsyncWorkPoolSize', 0);
|
|
5621
5645
|
function emnapiInit(options) {
|
|
5622
5646
|
if (emnapiModule.loaded)
|
|
5623
5647
|
return emnapiModule.exports;
|
|
@@ -5639,6 +5663,18 @@ function emnapiInit(options) {
|
|
|
5639
5663
|
}
|
|
5640
5664
|
emnapiNodeBinding = nodeBinding;
|
|
5641
5665
|
}
|
|
5666
|
+
if ('asyncWorkPoolSize' in options) {
|
|
5667
|
+
if (typeof options.asyncWorkPoolSize !== 'number') {
|
|
5668
|
+
throw new TypeError('options.asyncWorkPoolSize must be a integer');
|
|
5669
|
+
}
|
|
5670
|
+
emnapiAsyncWorkPoolSize = options.asyncWorkPoolSize >> 0;
|
|
5671
|
+
if (emnapiAsyncWorkPoolSize > 1024) {
|
|
5672
|
+
emnapiAsyncWorkPoolSize = 1024;
|
|
5673
|
+
}
|
|
5674
|
+
else if (emnapiAsyncWorkPoolSize < -1024) {
|
|
5675
|
+
emnapiAsyncWorkPoolSize = -1024;
|
|
5676
|
+
}
|
|
5677
|
+
}
|
|
5642
5678
|
// eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing
|
|
5643
5679
|
var envObject = emnapiModule.envObject || (emnapiModule.envObject = emnapiCtx.createEnv(function (cb) { return {{{ makeDynCall('vppp', 'cb') }}}; }, function (cb) { return {{{ makeDynCall('vp', 'cb') }}}; }));
|
|
5644
5680
|
var scope = emnapiCtx.openScope(envObject);
|
|
@@ -5660,7 +5696,11 @@ function emnapiInit(options) {
|
|
|
5660
5696
|
delete emnapiModule.envObject;
|
|
5661
5697
|
return emnapiModule.exports;
|
|
5662
5698
|
}
|
|
5663
|
-
emnapiImplementHelper('$emnapiInit', undefined, emnapiInit, ['$emnapiModule', '$emnapiCtx', '$emnapiNodeBinding', 'napi_register_wasm_v1']);
|
|
5699
|
+
emnapiImplementHelper('$emnapiInit', undefined, emnapiInit, ['$emnapiModule', '$emnapiCtx', '$emnapiNodeBinding', '$emnapiAsyncWorkPoolSize', 'napi_register_wasm_v1']);
|
|
5700
|
+
function __emnapi_async_work_pool_size() {
|
|
5701
|
+
return Math.abs(emnapiAsyncWorkPoolSize);
|
|
5702
|
+
}
|
|
5703
|
+
emnapiImplementInternal('_emnapi_async_work_pool_size', 'i', __emnapi_async_work_pool_size, ['$emnapiAsyncWorkPoolSize']);
|
|
5664
5704
|
function __emnapi_get_filename(buf, len) {
|
|
5665
5705
|
if (!buf) {
|
|
5666
5706
|
return lengthBytesUTF8(emnapiModule.filename);
|
|
@@ -5746,6 +5786,8 @@ mergeInto(LibraryManager.library, {
|
|
|
5746
5786
|
return UTF8ToString(ptr);
|
|
5747
5787
|
}
|
|
5748
5788
|
length = length >>> 0;
|
|
5789
|
+
if (!length)
|
|
5790
|
+
return '';
|
|
5749
5791
|
return emnapiUtf8Decoder.decode({{{ getUnsharedTextDecoderView('HEAPU8', 'ptr', 'ptr + length') }}});
|
|
5750
5792
|
},
|
|
5751
5793
|
$emnapiUtf16leDecoder__postset: 'emnapiUtf16leDecoder();',
|
|
@@ -5789,6 +5831,8 @@ mergeInto(LibraryManager.library, {
|
|
|
5789
5831
|
return UTF16ToString(ptr);
|
|
5790
5832
|
}
|
|
5791
5833
|
length = length >>> 0;
|
|
5834
|
+
if (!length)
|
|
5835
|
+
return '';
|
|
5792
5836
|
return emnapiUtf16leDecoder.decode({{{ getUnsharedTextDecoderView('HEAPU8', 'ptr', 'ptr + length * 2') }}});
|
|
5793
5837
|
}
|
|
5794
5838
|
});
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
emcc (Emscripten gcc/clang-like replacement + linker emulating GNU ld) 3.1.
|
|
2
|
-
clang version 17.0.0 (https://github.com/llvm/llvm-project
|
|
1
|
+
emcc (Emscripten gcc/clang-like replacement + linker emulating GNU ld) 3.1.34 (57b21b8fdcbe3ebb523178b79465254668eab408)
|
|
2
|
+
clang version 17.0.0 (https://github.com/llvm/llvm-project a031f72187ce495b9faa4ccf99b1e901a3872f4b)
|
|
3
3
|
Target: wasm32-unknown-emscripten
|
|
4
4
|
Thread model: posix
|
|
5
5
|
InstalledDir: /home/runner/work/emnapi/emnapi/emsdk-cache/emsdk-main/upstream/bin
|
|
Binary file
|
package/package.json
CHANGED
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
#include <stddef.h>
|
|
2
|
+
#include <stdint.h>
|
|
3
|
+
|
|
4
|
+
void* calloc(size_t n, size_t size);
|
|
5
|
+
|
|
6
|
+
extern unsigned char __heap_base;
|
|
7
|
+
extern unsigned char __data_end;
|
|
8
|
+
extern unsigned char __global_base;
|
|
9
|
+
extern __attribute__((__weak__)) unsigned char __stack_high;
|
|
10
|
+
extern __attribute__((__weak__)) unsigned char __stack_low;
|
|
11
|
+
|
|
12
|
+
#define ROUND_UP(x, ALIGNMENT) (((x)+ALIGNMENT-1)&-ALIGNMENT)
|
|
13
|
+
#define STACK_ALIGN 16
|
|
14
|
+
#define DEFAULT_STACK_MAX (8<<20)
|
|
15
|
+
|
|
16
|
+
struct worker_args {
|
|
17
|
+
void* stack_base;
|
|
18
|
+
void* tls_base;
|
|
19
|
+
};
|
|
20
|
+
|
|
21
|
+
extern void __wasm_init_tls(void*);
|
|
22
|
+
|
|
23
|
+
void* __copy_tls(unsigned char *mem) {
|
|
24
|
+
size_t tls_align = __builtin_wasm_tls_align();
|
|
25
|
+
volatile void* tls_base = __builtin_wasm_tls_base();
|
|
26
|
+
mem += tls_align;
|
|
27
|
+
mem -= (uintptr_t)mem & (tls_align-1);
|
|
28
|
+
__wasm_init_tls(mem);
|
|
29
|
+
__asm__("local.get %0\n"
|
|
30
|
+
"global.set __tls_base\n"
|
|
31
|
+
:: "r"(tls_base));
|
|
32
|
+
return mem;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
__attribute__((visibility("default")))
|
|
36
|
+
void* emnapi_async_worker_create() {
|
|
37
|
+
size_t args_size = sizeof(struct worker_args);
|
|
38
|
+
size_t size = args_size;
|
|
39
|
+
|
|
40
|
+
size_t tls_size = __builtin_wasm_tls_size();
|
|
41
|
+
|
|
42
|
+
size_t tls_block_size = 0;
|
|
43
|
+
if (tls_size) {
|
|
44
|
+
size_t tls_align = __builtin_wasm_tls_align();
|
|
45
|
+
tls_block_size = ROUND_UP(tls_size + tls_align - 1, tls_align);
|
|
46
|
+
size += tls_block_size;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
ptrdiff_t stack_size = 0;
|
|
50
|
+
if (&__stack_high) {
|
|
51
|
+
stack_size = &__stack_high - &__stack_low;
|
|
52
|
+
} else {
|
|
53
|
+
unsigned char *sp;
|
|
54
|
+
__asm__(
|
|
55
|
+
".globaltype __stack_pointer, i32\n"
|
|
56
|
+
"global.get __stack_pointer\n"
|
|
57
|
+
"local.set %0\n"
|
|
58
|
+
: "=r"(sp));
|
|
59
|
+
stack_size = sp > &__global_base ? &__heap_base - &__data_end : (ptrdiff_t)&__global_base;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
stack_size = ROUND_UP(stack_size, STACK_ALIGN);
|
|
63
|
+
stack_size = stack_size < DEFAULT_STACK_MAX ? stack_size : DEFAULT_STACK_MAX;
|
|
64
|
+
size += stack_size;
|
|
65
|
+
|
|
66
|
+
void* block = calloc(1, size);
|
|
67
|
+
if (!block) return 0;
|
|
68
|
+
|
|
69
|
+
void* tls_base = tls_size ? __copy_tls(block + args_size) : 0;
|
|
70
|
+
|
|
71
|
+
struct worker_args* args = (struct worker_args*)block;
|
|
72
|
+
|
|
73
|
+
args->stack_base = block + args_size + tls_block_size + stack_size;
|
|
74
|
+
args->tls_base = tls_base;
|
|
75
|
+
return block;
|
|
76
|
+
}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
#ifdef __wasm64__
|
|
2
|
+
#define PTR i64
|
|
3
|
+
#else
|
|
4
|
+
#define PTR i32
|
|
5
|
+
#endif
|
|
6
|
+
|
|
7
|
+
.text
|
|
8
|
+
|
|
9
|
+
.export_name emnapi_async_worker_init, emnapi_async_worker_init
|
|
10
|
+
|
|
11
|
+
.globaltype __stack_pointer, PTR
|
|
12
|
+
.globaltype __tls_base, PTR
|
|
13
|
+
|
|
14
|
+
.hidden emnapi_async_worker_init
|
|
15
|
+
.globl emnapi_async_worker_init
|
|
16
|
+
.type emnapi_async_worker_init,@function
|
|
17
|
+
|
|
18
|
+
emnapi_async_worker_init:
|
|
19
|
+
.functype emnapi_async_worker_init (PTR) -> ()
|
|
20
|
+
|
|
21
|
+
local.get 0
|
|
22
|
+
PTR.load 0
|
|
23
|
+
global.set __stack_pointer
|
|
24
|
+
|
|
25
|
+
local.get 0
|
|
26
|
+
#ifdef __wasm64__
|
|
27
|
+
PTR.load 8
|
|
28
|
+
#else
|
|
29
|
+
PTR.load 4
|
|
30
|
+
#endif
|
|
31
|
+
global.set __tls_base
|
|
32
|
+
|
|
33
|
+
end_function
|
package/src/uv/threadpool.c
CHANGED
|
@@ -209,6 +209,7 @@ static void post(QUEUE* q, enum uv__work_kind kind) {
|
|
|
209
209
|
// nthreads = 0;
|
|
210
210
|
// }
|
|
211
211
|
|
|
212
|
+
EMNAPI_EXTERN int _emnapi_async_work_pool_size();
|
|
212
213
|
|
|
213
214
|
static void init_threads(void) {
|
|
214
215
|
unsigned int i;
|
|
@@ -223,9 +224,14 @@ static void init_threads(void) {
|
|
|
223
224
|
nthreads = EMNAPI_WORKER_POOL_SIZE;
|
|
224
225
|
#else
|
|
225
226
|
nthreads = ARRAY_SIZE(default_threads);
|
|
226
|
-
|
|
227
|
-
if (
|
|
228
|
-
nthreads =
|
|
227
|
+
int async_work_pool_size = _emnapi_async_work_pool_size();
|
|
228
|
+
if (async_work_pool_size > 0) {
|
|
229
|
+
nthreads = (unsigned int) async_work_pool_size;
|
|
230
|
+
} else {
|
|
231
|
+
val = getenv("UV_THREADPOOL_SIZE");
|
|
232
|
+
if (val != NULL)
|
|
233
|
+
nthreads = atoi(val);
|
|
234
|
+
}
|
|
229
235
|
#endif
|
|
230
236
|
if (nthreads == 0)
|
|
231
237
|
nthreads = 1;
|
package/src/uv/unix/async.c
CHANGED
|
@@ -151,9 +151,25 @@ static void uv__async_io(uv_loop_t* loop) {
|
|
|
151
151
|
}
|
|
152
152
|
}
|
|
153
153
|
|
|
154
|
+
#if EMNAPI_USE_PROXYING
|
|
155
|
+
|
|
156
|
+
#undef emscripten_main_browser_thread_id
|
|
157
|
+
|
|
158
|
+
__attribute__((weak))
|
|
159
|
+
pthread_t emscripten_main_browser_thread_id(void) {
|
|
160
|
+
return NULL;
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
__attribute__((weak))
|
|
164
|
+
pthread_t emscripten_main_runtime_thread_id(void) {
|
|
165
|
+
return emscripten_main_browser_thread_id();
|
|
166
|
+
}
|
|
167
|
+
#endif
|
|
168
|
+
|
|
154
169
|
static void uv__async_send(uv_loop_t* loop) {
|
|
155
170
|
#if EMNAPI_USE_PROXYING
|
|
156
|
-
pthread_t main_thread =
|
|
171
|
+
pthread_t main_thread = emscripten_main_runtime_thread_id();
|
|
172
|
+
assert(main_thread != NULL);
|
|
157
173
|
if (pthread_equal(main_thread, pthread_self())) {
|
|
158
174
|
NEXT_TICK((void (*)(void *))uv__async_io, loop);
|
|
159
175
|
} else {
|