emnapi 1.4.5 → 1.6.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.
Files changed (42) hide show
  1. package/CMakeLists.txt +34 -0
  2. package/README.md +4 -2
  3. package/common.gypi +11 -0
  4. package/dist/library_napi.js +128 -12
  5. package/emnapi.gyp +18 -0
  6. package/include/node/emnapi.h +2 -2
  7. package/include/node/js_native_api.h +9 -1
  8. package/lib/wasm32/libdlmalloc-mt.a +0 -0
  9. package/lib/wasm32/libdlmalloc.a +0 -0
  10. package/lib/wasm32/libemmalloc-mt.a +0 -0
  11. package/lib/wasm32/libemmalloc.a +0 -0
  12. package/lib/wasm32/libemnapi-basic-mt.a +0 -0
  13. package/lib/wasm32/libemnapi-basic.a +0 -0
  14. package/lib/wasm32/libemnapi.a +0 -0
  15. package/lib/wasm32-emscripten/libemnapi-basic.a +0 -0
  16. package/lib/wasm32-emscripten/libemnapi-mt.a +0 -0
  17. package/lib/wasm32-emscripten/libemnapi.a +0 -0
  18. package/lib/wasm32-wasi/libemnapi-basic-mt.a +0 -0
  19. package/lib/wasm32-wasi/libemnapi-basic.a +0 -0
  20. package/lib/wasm32-wasi/libemnapi.a +0 -0
  21. package/lib/wasm32-wasi-threads/libemnapi-basic-mt.a +0 -0
  22. package/lib/wasm32-wasi-threads/libemnapi-basic-napi-rs-mt.a +0 -0
  23. package/lib/wasm32-wasi-threads/libemnapi-basic.a +0 -0
  24. package/lib/wasm32-wasi-threads/libemnapi-mt.a +0 -0
  25. package/lib/wasm32-wasi-threads/libemnapi-napi-rs-mt.a +0 -0
  26. package/lib/wasm32-wasi-threads/libemnapi.a +0 -0
  27. package/lib/wasm32-wasip1/libemnapi-basic-mt.a +0 -0
  28. package/lib/wasm32-wasip1/libemnapi-basic.a +0 -0
  29. package/lib/wasm32-wasip1/libemnapi.a +0 -0
  30. package/lib/wasm32-wasip1-threads/libemnapi-basic-mt.a +0 -0
  31. package/lib/wasm32-wasip1-threads/libemnapi-basic-napi-rs-mt.a +0 -0
  32. package/lib/wasm32-wasip1-threads/libemnapi-basic.a +0 -0
  33. package/lib/wasm32-wasip1-threads/libemnapi-mt.a +0 -0
  34. package/lib/wasm32-wasip1-threads/libemnapi-napi-rs-mt.a +0 -0
  35. package/lib/wasm32-wasip1-threads/libemnapi.a +0 -0
  36. package/lib/wasm64-emscripten/libemnapi-basic.a +0 -0
  37. package/lib/wasm64-emscripten/libemnapi-mt.a +0 -0
  38. package/lib/wasm64-emscripten/libemnapi.a +0 -0
  39. package/package.json +1 -1
  40. package/src/emnapi_internal.h +7 -0
  41. package/src/threadsafe_function.c +4 -4
  42. package/src/wasi_wait.c +106 -0
package/CMakeLists.txt CHANGED
@@ -44,6 +44,7 @@ set(ENAPI_BASIC_SRC
44
44
  "${CMAKE_CURRENT_SOURCE_DIR}/src/node_api.c"
45
45
  "${CMAKE_CURRENT_SOURCE_DIR}/src/async_cleanup_hook.c"
46
46
  "${CMAKE_CURRENT_SOURCE_DIR}/src/async_context.c"
47
+ "${CMAKE_CURRENT_SOURCE_DIR}/src/wasi_wait.c"
47
48
  )
48
49
  set(EMNAPI_THREADS_SRC
49
50
  "${CMAKE_CURRENT_SOURCE_DIR}/src/async_work.c"
@@ -70,6 +71,10 @@ set(EMNAPI_BASIC_TARGET_NAME "emnapi-basic")
70
71
  set(EMNAPI_BASIC_MT_TARGET_NAME "emnapi-basic-mt")
71
72
  set(EMNAPI_TARGET_NAME "emnapi")
72
73
  set(EMNAPI_MT_TARGET_NAME "emnapi-mt")
74
+
75
+ set(EMNAPI_BASIC_NAPI_RS_MT_TARGET_NAME "emnapi-basic-napi-rs-mt")
76
+ set(EMNAPI_NAPI_RS_MT_TARGET_NAME "emnapi-napi-rs-mt")
77
+
73
78
  set(DLMALLOC_TARGET_NAME "dlmalloc")
74
79
  set(DLMALLOC_MT_TARGET_NAME "dlmalloc-mt")
75
80
  set(EMMALLOC_TARGET_NAME "emmalloc")
@@ -155,6 +160,31 @@ else()
155
160
  set(EMNAPI_BUILD_BASIC_MT OFF)
156
161
  endif()
157
162
 
163
+ if(IS_WASM32_WASIP1_THREADS)
164
+ set(EMNAPI_BUILD_FOR_NAPI_RS ON)
165
+ else()
166
+ set(EMNAPI_BUILD_FOR_NAPI_RS OFF)
167
+ endif()
168
+
169
+ if(EMNAPI_BUILD_FOR_NAPI_RS)
170
+ add_library(${EMNAPI_NAPI_RS_MT_TARGET_NAME} STATIC ${EMNAPI_SRC} ${UV_SRC})
171
+ target_include_directories(${EMNAPI_NAPI_RS_MT_TARGET_NAME} PUBLIC ${EMNAPI_INCLUDE})
172
+ target_compile_definitions(${EMNAPI_NAPI_RS_MT_TARGET_NAME}
173
+ PUBLIC ${EMNAPI_DEFINES} "NAPI_EXTERN=__attribute__((__import_module__(\"env\")))"
174
+ )
175
+
176
+ add_library(${EMNAPI_BASIC_NAPI_RS_MT_TARGET_NAME} STATIC
177
+ ${ENAPI_BASIC_SRC}
178
+ "${CMAKE_CURRENT_SOURCE_DIR}/src/thread/async_worker_create.c"
179
+ "${CMAKE_CURRENT_SOURCE_DIR}/src/thread/async_worker_init.S"
180
+ )
181
+ target_include_directories(${EMNAPI_BASIC_NAPI_RS_MT_TARGET_NAME} PUBLIC ${EMNAPI_INCLUDE})
182
+ target_compile_definitions(${EMNAPI_BASIC_NAPI_RS_MT_TARGET_NAME}
183
+ PUBLIC ${EMNAPI_DEFINES} "NAPI_EXTERN=__attribute__((__import_module__(\"env\")))"
184
+ PRIVATE "EMNAPI_DISABLE_UV"
185
+ )
186
+ endif()
187
+
158
188
  if(EMNAPI_BUILD_BASIC_MT)
159
189
  add_library(${EMNAPI_BASIC_MT_TARGET_NAME} STATIC
160
190
  ${ENAPI_BASIC_SRC}
@@ -222,6 +252,10 @@ if(LIB_ARCH)
222
252
  if(EMNAPI_BUILD_BASIC_MT)
223
253
  install(TARGETS ${EMNAPI_BASIC_MT_TARGET_NAME} DESTINATION "lib/${LIB_ARCH}")
224
254
  endif()
255
+ if(EMNAPI_BUILD_FOR_NAPI_RS)
256
+ install(TARGETS ${EMNAPI_NAPI_RS_MT_TARGET_NAME} DESTINATION "lib/${LIB_ARCH}")
257
+ install(TARGETS ${EMNAPI_BASIC_NAPI_RS_MT_TARGET_NAME} DESTINATION "lib/${LIB_ARCH}")
258
+ endif()
225
259
  if(IS_WASM32)
226
260
  install(TARGETS ${DLMALLOC_TARGET_NAME} DESTINATION "lib/${LIB_ARCH}")
227
261
  install(TARGETS ${DLMALLOC_MT_TARGET_NAME} DESTINATION "lib/${LIB_ARCH}")
package/README.md CHANGED
@@ -816,8 +816,9 @@ Now emnapi has 3 implementations of async work and 2 implementations of TSFN:
816
816
  There are some limitations on browser about wasi-libc's pthread implementation, for example
817
817
  `pthread_mutex_lock` may call `__builtin_wasm_memory_atomic_wait32`(`memory.atomic.wait32`)
818
818
  which is disallowed in browser JS main thread. While Emscripten's pthread implementation
819
- has considered usage in browser. If you need to run your addon with multithreaded features on browser,
820
- we recommend you use Emscripten A & D, or bare wasm32 C & E.
819
+ has considered usage in browser. This issue can be solved by upgrading `wasi-sdk` to v26+
820
+ and emnapi v1.5.0+ then pass `--export=emnapi_thread_crashed` to the linker. If you need to
821
+ run your addon with multithreaded features, we recommend you use A & D or C & E.
821
822
 
822
823
  Note: For browsers, all the multithreaded features relying on Web Workers (Emscripten pthread also relying on Web Workers)
823
824
  require cross-origin isolation to enable `SharedArrayBuffer`. You can make a page cross-origin isolated
@@ -879,6 +880,7 @@ elseif(CMAKE_C_COMPILER_TARGET STREQUAL "wasm32-wasi-threads")
879
880
  "-Wl,--export-if-defined=node_api_module_get_api_version_v1"
880
881
  "-Wl,--export=malloc"
881
882
  "-Wl,--export=free"
883
+ "-Wl,--export=emnapi_thread_crashed"
882
884
  "-Wl,--import-undefined"
883
885
  "-Wl,--export-table"
884
886
  )
package/common.gypi CHANGED
@@ -308,6 +308,7 @@
308
308
  'src/async_cleanup_hook.c',
309
309
  'src/async_context.c',
310
310
  'src/async_work.c',
311
+ 'src/wasi_wait.c',
311
312
  'src/threadsafe_function.c',
312
313
  'src/uv/uv-common.c',
313
314
  'src/uv/threadpool.c',
@@ -370,6 +371,16 @@
370
371
  ]
371
372
  },
372
373
  }],
374
+ ['OS == "wasi"', {
375
+ 'ldflags': [
376
+ '-Wl,--export=emnapi_thread_crashed',
377
+ ],
378
+ 'xcode_settings': {
379
+ 'OTHER_LDFLAGS': [
380
+ '-Wl,--export=emnapi_thread_crashed',
381
+ ],
382
+ },
383
+ }],
373
384
  ['OS != "wasi"', {
374
385
  'defines': [
375
386
  'PAGESIZE=65536'
@@ -61,10 +61,13 @@ function emnapiInit(options) {
61
61
  });
62
62
  }
63
63
  catch (err) {
64
+ if (err !== 'unwind') {
65
+ throw err;
66
+ }
67
+ }
68
+ finally {
64
69
  emnapiCtx.closeScope(envObject, scope);
65
- throw err;
66
70
  }
67
- emnapiCtx.closeScope(envObject, scope);
68
71
  emnapiModule.loaded = true;
69
72
  delete emnapiModule.envObject;
70
73
  return emnapiModule.exports;
@@ -75,7 +78,6 @@ function emnapiInit(options) {
75
78
  function __emnapi_async_work_pool_size() {
76
79
  return Math.abs(emnapiAsyncWorkPoolSize);
77
80
  }
78
- /* eslint-disable @typescript-eslint/indent */
79
81
  /**
80
82
  * @__sig ipiip
81
83
  */
@@ -180,6 +182,31 @@ function __emnapi_ctx_increase_waiting_request_counter() {
180
182
  function __emnapi_ctx_decrease_waiting_request_counter() {
181
183
  emnapiCtx.decreaseWaitingRequestCounter();
182
184
  }
185
+ /**
186
+ * @__sig i
187
+ */
188
+ function __emnapi_is_main_runtime_thread() {
189
+ return ENVIRONMENT_IS_PTHREAD ? 0 : 1;
190
+ }
191
+ /**
192
+ * @__sig i
193
+ */
194
+ function __emnapi_is_main_browser_thread() {
195
+ return (typeof window !== 'undefined' && typeof document !== 'undefined' && !ENVIRONMENT_IS_NODE) ? 1 : 0;
196
+ }
197
+ /**
198
+ * @__sig v
199
+ */
200
+ function __emnapi_unwind() {
201
+ // eslint-disable-next-line @typescript-eslint/no-throw-literal
202
+ throw 'unwind';
203
+ }
204
+ /**
205
+ * @__sig d
206
+ */
207
+ function __emnapi_get_now() {
208
+ return performance.timeOrigin + performance.now();
209
+ }
183
210
  function emnapiSetValueI64(result, numberValue) {
184
211
  var tempDouble;
185
212
  // eslint-disable-next-line @typescript-eslint/no-unused-vars
@@ -190,6 +217,20 @@ function emnapiSetValueI64(result, numberValue) {
190
217
  {{{ makeSetValue('result', 0, 'tempI64[0]', 'i32') }}};
191
218
  {{{ makeSetValue('result', 4, 'tempI64[1]', 'i32') }}};
192
219
  }
220
+ /**
221
+ * @__deps $emnapiCtx
222
+ * @__sig p
223
+ */
224
+ function __emnapi_open_handle_scope() {
225
+ return emnapiCtx.openScope().id;
226
+ }
227
+ /**
228
+ * @__deps $emnapiCtx
229
+ * @__sig vp
230
+ */
231
+ function __emnapi_close_handle_scope(_scope) {
232
+ return emnapiCtx.closeScope();
233
+ }
193
234
  /* eslint-disable eqeqeq */
194
235
  /* eslint-disable @typescript-eslint/no-unused-vars */
195
236
  /* eslint-disable @typescript-eslint/indent */
@@ -942,6 +983,10 @@ var emnapiExternalMemory = {
942
983
  emnapiExternalMemory.table = new WeakMap();
943
984
  emnapiExternalMemory.wasmMemoryViewTable = new WeakMap();
944
985
  },
986
+ isSharedArrayBuffer: function (value) {
987
+ return ((typeof SharedArrayBuffer === 'function' && value instanceof SharedArrayBuffer) ||
988
+ (Object.prototype.toString.call(value) === '[object SharedArrayBuffer]'));
989
+ },
945
990
  isDetachedArrayBuffer: function (arrayBuffer) {
946
991
  if (arrayBuffer.byteLength === 0) {
947
992
  try {
@@ -1083,7 +1128,7 @@ function _napi_get_arraybuffer_info(env, arraybuffer, data, byte_length) {
1083
1128
  if (!arraybuffer)
1084
1129
  return envObject.setLastError(1 /* napi_status.napi_invalid_arg */);
1085
1130
  var handle = emnapiCtx.handleStore.get(arraybuffer);
1086
- if (!handle.isArrayBuffer()) {
1131
+ if (!handle.isArrayBuffer() && !emnapiExternalMemory.isSharedArrayBuffer(handle.value)) {
1087
1132
  return envObject.setLastError(1 /* napi_status.napi_invalid_arg */);
1088
1133
  }
1089
1134
  if (data) {
@@ -2586,7 +2631,7 @@ function emnapiSyncMemory(js_to_wasm, arrayBufferOrView, offset, len) {
2586
2631
  offset = offset !== null && offset !== void 0 ? offset : 0;
2587
2632
  offset = offset >>> 0;
2588
2633
  var view;
2589
- if (arrayBufferOrView instanceof ArrayBuffer) {
2634
+ if (arrayBufferOrView instanceof ArrayBuffer || emnapiExternalMemory.isSharedArrayBuffer(arrayBufferOrView)) {
2590
2635
  var pointer = emnapiExternalMemory.getArrayBufferPointer(arrayBufferOrView, false).address;
2591
2636
  if (!pointer)
2592
2637
  throw new Error('Unknown ArrayBuffer address');
@@ -2654,7 +2699,7 @@ function _emnapi_sync_memory(env, js_to_wasm, arraybuffer_or_view, offset, len)
2654
2699
  {{{ from64('len') }}};
2655
2700
  var handleId = {{{ makeGetValue('arraybuffer_or_view', 0, '*') }}};
2656
2701
  var handle = envObject.ctx.handleStore.get(handleId);
2657
- if (!handle.isArrayBuffer() && !handle.isTypedArray() && !handle.isDataView()) {
2702
+ if (!handle.isArrayBuffer() && !handle.isTypedArray() && !handle.isDataView() && !emnapiExternalMemory.isSharedArrayBuffer(handle.value)) {
2658
2703
  return envObject.setLastError(1 /* napi_status.napi_invalid_arg */);
2659
2704
  }
2660
2705
  var ret = emnapiSyncMemory(Boolean(js_to_wasm), handle.value, offset, len);
@@ -2674,7 +2719,7 @@ function emnapiGetMemoryAddress(arrayBufferOrView) {
2674
2719
  var isArrayBuffer = arrayBufferOrView instanceof ArrayBuffer;
2675
2720
  var isDataView = arrayBufferOrView instanceof DataView;
2676
2721
  var isTypedArray = ArrayBuffer.isView(arrayBufferOrView) && !isDataView;
2677
- if (!isArrayBuffer && !isTypedArray && !isDataView) {
2722
+ if (!isArrayBuffer && !isTypedArray && !isDataView && !emnapiExternalMemory.isSharedArrayBuffer(arrayBufferOrView)) {
2678
2723
  throw new TypeError('emnapiGetMemoryAddress expect ArrayBuffer or ArrayBufferView as first parameter');
2679
2724
  }
2680
2725
  var info;
@@ -2800,10 +2845,10 @@ function _napi_create_array_with_length(env, length, result) {
2800
2845
  {{{ makeSetValue('result', 0, 'value', '*') }}};
2801
2846
  return envObject.clearLastError();
2802
2847
  }
2803
- function emnapiCreateArrayBuffer(byte_length, data) {
2848
+ function emnapiCreateArrayBuffer(byte_length, data, shared) {
2804
2849
  {{{ from64('byte_length') }}};
2805
2850
  byte_length = byte_length >>> 0;
2806
- var arrayBuffer = new ArrayBuffer(byte_length);
2851
+ var arrayBuffer = shared ? new SharedArrayBuffer(byte_length) : new ArrayBuffer(byte_length);
2807
2852
  if (data) {
2808
2853
  {{{ from64('data') }}};
2809
2854
  // eslint-disable-next-line @typescript-eslint/no-unused-vars
@@ -2832,7 +2877,37 @@ function _napi_create_arraybuffer(env, byte_length, data, result) {
2832
2877
  if (!result)
2833
2878
  return envObject.setLastError(1 /* napi_status.napi_invalid_arg */);
2834
2879
  {{{ from64('result') }}};
2835
- var arrayBuffer = emnapiCreateArrayBuffer(byte_length, data);
2880
+ var arrayBuffer = emnapiCreateArrayBuffer(byte_length, data, false);
2881
+ value = emnapiCtx.addToCurrentScope(arrayBuffer).id;
2882
+ {{{ makeSetValue('result', 0, 'value', '*') }}};
2883
+ return envObject.getReturnStatus();
2884
+ }
2885
+ catch (err) {
2886
+ envObject.tryCatch.setError(err);
2887
+ return envObject.setLastError(10 /* napi_status.napi_pending_exception */);
2888
+ }
2889
+ }
2890
+ /**
2891
+ * @__sig ipppp
2892
+ */
2893
+ function _node_api_create_sharedarraybuffer(env, byte_length, data, result) {
2894
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
2895
+ var value;
2896
+ if (!env)
2897
+ return 1 /* napi_status.napi_invalid_arg */;
2898
+ // @ts-expect-error
2899
+ var envObject = emnapiCtx.envStore.get(env);
2900
+ envObject.checkGCAccess();
2901
+ if (!envObject.tryCatch.isEmpty())
2902
+ return envObject.setLastError(10 /* napi_status.napi_pending_exception */);
2903
+ if (!envObject.canCallIntoJs())
2904
+ return envObject.setLastError(envObject.moduleApiVersion >= 10 ? 23 /* napi_status.napi_cannot_run_js */ : 10 /* napi_status.napi_pending_exception */);
2905
+ envObject.clearLastError();
2906
+ try {
2907
+ if (!result)
2908
+ return envObject.setLastError(1 /* napi_status.napi_invalid_arg */);
2909
+ {{{ from64('result') }}};
2910
+ var arrayBuffer = emnapiCreateArrayBuffer(byte_length, data, true);
2836
2911
  value = emnapiCtx.addToCurrentScope(arrayBuffer).id;
2837
2912
  {{{ makeSetValue('result', 0, 'value', '*') }}};
2838
2913
  return envObject.getReturnStatus();
@@ -3205,7 +3280,7 @@ function _napi_create_buffer_copy(env, length, data, result_data, result) {
3205
3280
  if (!Buffer) {
3206
3281
  throw emnapiCtx.createNotSupportBufferError('napi_create_buffer_copy', '');
3207
3282
  }
3208
- var arrayBuffer = emnapiCreateArrayBuffer(length, result_data);
3283
+ var arrayBuffer = emnapiCreateArrayBuffer(length, result_data, false);
3209
3284
  var buffer = Buffer.from(arrayBuffer);
3210
3285
  {{{ from64('data') }}};
3211
3286
  {{{ from64('length') }}};
@@ -6417,6 +6492,27 @@ function _napi_is_arraybuffer(env, value, result) {
6417
6492
  return envObject.clearLastError();
6418
6493
  }
6419
6494
  /** @__sig ippp */
6495
+ function _node_api_is_sharedarraybuffer(env, value, result) {
6496
+ if (!env)
6497
+ return 1 /* napi_status.napi_invalid_arg */;
6498
+ // @ts-expect-error
6499
+ var envObject = emnapiCtx.envStore.get(env);
6500
+ envObject.checkGCAccess();
6501
+ if (!value)
6502
+ return envObject.setLastError(1 /* napi_status.napi_invalid_arg */);
6503
+ if (!result)
6504
+ return envObject.setLastError(1 /* napi_status.napi_invalid_arg */);
6505
+ var h = emnapiCtx.handleStore.get(value);
6506
+ {{{ from64('result') }}};
6507
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
6508
+ var r = ((typeof SharedArrayBuffer === 'function' && h.value instanceof SharedArrayBuffer) ||
6509
+ (Object.prototype.toString.call(h.value) === '[object SharedArrayBuffer]'))
6510
+ ? 1
6511
+ : 0;
6512
+ {{{ makeSetValue('result', 0, 'r', 'i8') }}};
6513
+ return envObject.clearLastError();
6514
+ }
6515
+ /** @__sig ippp */
6420
6516
  function _napi_is_date(env, value, result) {
6421
6517
  if (!env)
6422
6518
  return 1 /* napi_status.napi_invalid_arg */;
@@ -6655,6 +6751,9 @@ function _napi_get_version(env, result) {
6655
6751
  _emnapi_callback_into_module: __emnapi_callback_into_module,
6656
6752
  _emnapi_callback_into_module__deps: ["$emnapiCtx"],
6657
6753
  _emnapi_callback_into_module__sig: "vipppi",
6754
+ _emnapi_close_handle_scope: __emnapi_close_handle_scope,
6755
+ _emnapi_close_handle_scope__deps: ["$emnapiCtx", "$emnapiCtx"],
6756
+ _emnapi_close_handle_scope__sig: "vp",
6658
6757
  _emnapi_ctx_decrease_waiting_request_counter: __emnapi_ctx_decrease_waiting_request_counter,
6659
6758
  _emnapi_ctx_decrease_waiting_request_counter__deps: ["$emnapiCtx"],
6660
6759
  _emnapi_ctx_decrease_waiting_request_counter__sig: "v",
@@ -6681,6 +6780,12 @@ function _napi_get_version(env, result) {
6681
6780
  _emnapi_get_last_error_info__sig: "vpppp",
6682
6781
  _emnapi_get_node_version: __emnapi_get_node_version,
6683
6782
  _emnapi_get_node_version__sig: "vppp",
6783
+ _emnapi_get_now: __emnapi_get_now,
6784
+ _emnapi_get_now__sig: "d",
6785
+ _emnapi_is_main_browser_thread: __emnapi_is_main_browser_thread,
6786
+ _emnapi_is_main_browser_thread__sig: "i",
6787
+ _emnapi_is_main_runtime_thread: __emnapi_is_main_runtime_thread,
6788
+ _emnapi_is_main_runtime_thread__sig: "i",
6684
6789
  _emnapi_node_emit_async_destroy: __emnapi_node_emit_async_destroy,
6685
6790
  _emnapi_node_emit_async_destroy__deps: ["$emnapiNodeBinding"],
6686
6791
  _emnapi_node_emit_async_destroy__sig: "vdd",
@@ -6690,12 +6795,17 @@ function _napi_get_version(env, result) {
6690
6795
  _emnapi_node_make_callback: __emnapi_node_make_callback,
6691
6796
  _emnapi_node_make_callback__deps: ["$emnapiNodeBinding", "$emnapiCtx"],
6692
6797
  _emnapi_node_make_callback__sig: "ipppppddp",
6798
+ _emnapi_open_handle_scope: __emnapi_open_handle_scope,
6799
+ _emnapi_open_handle_scope__deps: ["$emnapiCtx", "$emnapiCtx"],
6800
+ _emnapi_open_handle_scope__sig: "p",
6693
6801
  _emnapi_runtime_keepalive_pop: __emnapi_runtime_keepalive_pop,
6694
6802
  _emnapi_runtime_keepalive_pop__deps: ["$runtimeKeepalivePop"],
6695
6803
  _emnapi_runtime_keepalive_pop__sig: "v",
6696
6804
  _emnapi_runtime_keepalive_push: __emnapi_runtime_keepalive_push,
6697
6805
  _emnapi_runtime_keepalive_push__deps: ["$runtimeKeepalivePush"],
6698
6806
  _emnapi_runtime_keepalive_push__sig: "v",
6807
+ _emnapi_unwind: __emnapi_unwind,
6808
+ _emnapi_unwind__sig: "v",
6699
6809
  _emnapi_worker_unref: __emnapi_worker_unref,
6700
6810
  _emnapi_worker_unref__deps: ["$PThread"],
6701
6811
  _emnapi_worker_unref__sig: "vp",
@@ -6729,7 +6839,7 @@ function _napi_get_version(env, result) {
6729
6839
  emnapi_is_support_weakref__deps: ["$emnapiCtx"],
6730
6840
  emnapi_is_support_weakref__sig: "i",
6731
6841
  emnapi_sync_memory: _emnapi_sync_memory,
6732
- emnapi_sync_memory__deps: ["$emnapiCtx", "$emnapiSyncMemory"],
6842
+ emnapi_sync_memory__deps: ["$emnapiCtx", "$emnapiExternalMemory", "$emnapiSyncMemory"],
6733
6843
  emnapi_sync_memory__sig: "ipippp",
6734
6844
  $emnapiTSFN: emnapiTSFN,
6735
6845
  $emnapiTSFN__deps: ["$emnapiCtx", "_emnapi_runtime_keepalive_pop", "$emnapiNodeBinding", "_emnapi_node_emit_async_destroy", "malloc", "free"],
@@ -7177,9 +7287,15 @@ function _napi_get_version(env, result) {
7177
7287
  node_api_create_property_key_utf8: _node_api_create_property_key_utf8,
7178
7288
  node_api_create_property_key_utf8__deps: ["napi_create_string_utf8"],
7179
7289
  node_api_create_property_key_utf8__sig: "ipppp",
7290
+ node_api_create_sharedarraybuffer: _node_api_create_sharedarraybuffer,
7291
+ node_api_create_sharedarraybuffer__deps: ["$emnapiCtx", "$emnapiCreateArrayBuffer"],
7292
+ node_api_create_sharedarraybuffer__sig: "ipppp",
7180
7293
  node_api_create_syntax_error: _node_api_create_syntax_error,
7181
7294
  node_api_create_syntax_error__deps: ["$emnapiCtx"],
7182
7295
  node_api_create_syntax_error__sig: "ipppp",
7296
+ node_api_is_sharedarraybuffer: _node_api_is_sharedarraybuffer,
7297
+ node_api_is_sharedarraybuffer__deps: ["$emnapiCtx"],
7298
+ node_api_is_sharedarraybuffer__sig: "ippp",
7183
7299
  node_api_post_finalizer: _node_api_post_finalizer,
7184
7300
  node_api_post_finalizer__deps: ["$emnapiCtx"],
7185
7301
  node_api_post_finalizer__sig: "ipppp",
package/emnapi.gyp CHANGED
@@ -55,6 +55,7 @@
55
55
  'src/node_api.c',
56
56
  'src/async_cleanup_hook.c',
57
57
  'src/async_context.c',
58
+ 'src/wasi_wait.c',
58
59
  ],
59
60
  'link_settings': {
60
61
  'target_conditions': [
@@ -88,6 +89,22 @@
88
89
  ]
89
90
  },
90
91
  }],
92
+ ['OS == "wasi"', {
93
+ 'link_settings': {
94
+ 'target_conditions': [
95
+ ['_type == "executable"', {
96
+ 'ldflags': [
97
+ '-Wl,--export=emnapi_thread_crashed',
98
+ ],
99
+ 'xcode_settings': {
100
+ 'OTHER_LDFLAGS': [
101
+ '-Wl,--export=emnapi_thread_crashed',
102
+ ],
103
+ },
104
+ }],
105
+ ]
106
+ },
107
+ }],
91
108
  ]
92
109
  },
93
110
  {
@@ -98,6 +115,7 @@
98
115
  'src/node_api.c',
99
116
  'src/async_cleanup_hook.c',
100
117
  'src/async_context.c',
118
+ 'src/wasi_wait.c',
101
119
 
102
120
  'src/uv/uv-common.c',
103
121
  'src/uv/threadpool.c',
@@ -6,8 +6,8 @@
6
6
  #include "emnapi_common.h"
7
7
 
8
8
  #define EMNAPI_MAJOR_VERSION 1
9
- #define EMNAPI_MINOR_VERSION 4
10
- #define EMNAPI_PATCH_VERSION 5
9
+ #define EMNAPI_MINOR_VERSION 6
10
+ #define EMNAPI_PATCH_VERSION 0
11
11
 
12
12
  typedef enum {
13
13
  emnapi_runtime,
@@ -358,7 +358,7 @@ napi_create_reference(napi_env env,
358
358
 
359
359
  // Deletes a reference. The referenced value is released, and may
360
360
  // be GC'd unless there are other references to it.
361
- NAPI_EXTERN napi_status NAPI_CDECL napi_delete_reference(napi_env env,
361
+ NAPI_EXTERN napi_status NAPI_CDECL napi_delete_reference(node_api_basic_env env,
362
362
  napi_ref ref);
363
363
 
364
364
  // Increments the reference count, optionally returning the resulting count.
@@ -480,6 +480,14 @@ napi_get_dataview_info(napi_env env,
480
480
  napi_value* arraybuffer,
481
481
  size_t* byte_offset);
482
482
 
483
+ #ifdef NAPI_EXPERIMENTAL
484
+ #define NODE_API_EXPERIMENTAL_HAS_SHAREDARRAYBUFFER
485
+ NAPI_EXTERN napi_status NAPI_CDECL
486
+ node_api_is_sharedarraybuffer(napi_env env, napi_value value, bool* result);
487
+ NAPI_EXTERN napi_status NAPI_CDECL node_api_create_sharedarraybuffer(
488
+ napi_env env, size_t byte_length, void** data, napi_value* result);
489
+ #endif // NAPI_EXPERIMENTAL
490
+
483
491
  // version management
484
492
  NAPI_EXTERN napi_status NAPI_CDECL napi_get_version(node_api_basic_env env,
485
493
  uint32_t* result);
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "emnapi",
3
- "version": "1.4.5",
3
+ "version": "1.6.0",
4
4
  "description": "Node-API implementation for Emscripten",
5
5
  "main": "index.js",
6
6
  "gypfile": false,
@@ -98,11 +98,18 @@ EMNAPI_INTERNAL_EXTERN void _emnapi_runtime_keepalive_pop();
98
98
  #define EMNAPI_KEEPALIVE_POP _emnapi_runtime_keepalive_pop
99
99
  #endif
100
100
 
101
+ EMNAPI_INTERNAL_EXTERN napi_handle_scope _emnapi_open_handle_scope();
102
+ EMNAPI_INTERNAL_EXTERN void _emnapi_close_handle_scope(napi_handle_scope scope);
101
103
  EMNAPI_INTERNAL_EXTERN void _emnapi_env_ref(napi_env env);
102
104
  EMNAPI_INTERNAL_EXTERN void _emnapi_env_unref(napi_env env);
103
105
  EMNAPI_INTERNAL_EXTERN void _emnapi_ctx_increase_waiting_request_counter();
104
106
  EMNAPI_INTERNAL_EXTERN void _emnapi_ctx_decrease_waiting_request_counter();
105
107
 
108
+ EMNAPI_INTERNAL_EXTERN int _emnapi_is_main_browser_thread();
109
+ EMNAPI_INTERNAL_EXTERN int _emnapi_is_main_runtime_thread();
110
+ EMNAPI_INTERNAL_EXTERN double _emnapi_get_now();
111
+ EMNAPI_INTERNAL_EXTERN void _emnapi_unwind();
112
+
106
113
  #if defined(__EMSCRIPTEN_PTHREADS__) || defined(_REENTRANT)
107
114
  #define EMNAPI_HAVE_THREADS 1
108
115
  #else
@@ -136,6 +136,8 @@ static void _emnapi_tsfn_destroy(napi_threadsafe_function func) {
136
136
  EMNAPI_ASSERT_CALL(napi_delete_reference(func->env, func->ref));
137
137
  }
138
138
 
139
+ EMNAPI_ASYNC_RESOURCE_DTOR(func->env, (emnapi_async_resource*) func);
140
+
139
141
  EMNAPI_ASSERT_CALL(napi_remove_env_cleanup_hook(func->env, _emnapi_tsfn_cleanup, func));
140
142
  _emnapi_env_unref(func->env);
141
143
  if (func->async_ref) {
@@ -144,7 +146,6 @@ static void _emnapi_tsfn_destroy(napi_threadsafe_function func) {
144
146
  func->async_ref = false;
145
147
  }
146
148
 
147
- EMNAPI_ASYNC_RESOURCE_DTOR(func->env, (emnapi_async_resource*) func);
148
149
  free(func);
149
150
  }
150
151
 
@@ -209,8 +210,7 @@ static napi_value _emnapi_tsfn_finalize_in_callback_scope(napi_env env, napi_cal
209
210
  }
210
211
 
211
212
  static void _emnapi_tsfn_finalize(napi_threadsafe_function func) {
212
- napi_handle_scope scope;
213
- EMNAPI_ASSERT_CALL(napi_open_handle_scope(func->env, &scope));
213
+ napi_handle_scope scope = _emnapi_open_handle_scope();
214
214
  if (func->finalize_cb) {
215
215
  if (emnapi_is_node_binding_available()) {
216
216
  napi_value resource, cb;
@@ -229,7 +229,7 @@ static void _emnapi_tsfn_finalize(napi_threadsafe_function func) {
229
229
  }
230
230
  }
231
231
  _emnapi_tsfn_empty_queue_and_delete(func);
232
- EMNAPI_ASSERT_CALL(napi_close_handle_scope(func->env, scope));
232
+ _emnapi_close_handle_scope(scope);
233
233
  }
234
234
 
235
235
  static void _emnapi_tsfn_do_finalize(uv_handle_t* data) {
@@ -0,0 +1,106 @@
1
+ #if defined(__wasi__)
2
+
3
+ #include <time.h>
4
+ #include <errno.h>
5
+ #include <pthread.h>
6
+ #include <stdio.h>
7
+ #include "emnapi_internal.h"
8
+
9
+ struct __pthread {
10
+ unsigned char _[32];
11
+ volatile int cancel;
12
+ volatile unsigned char canceldisable, cancelasync;
13
+ unsigned char tsd_used:1;
14
+ unsigned char dlerror_flag:1;
15
+ unsigned char __[68];
16
+ };
17
+
18
+ #define INFINITY __builtin_inff()
19
+
20
+ int __wasilibc_futex_wait_atomic_wait(volatile void *addr, int op, int val, int64_t max_wait_ns);
21
+
22
+ static _Atomic pthread_t crashed_thread_id = NULL;
23
+
24
+ __attribute__((visibility("default")))
25
+ void emnapi_thread_crashed() {
26
+ crashed_thread_id = pthread_self();
27
+ }
28
+
29
+ void _emnapi_yield() {
30
+ if (crashed_thread_id) {
31
+ _emnapi_runtime_keepalive_push();
32
+ _emnapi_unwind();
33
+ }
34
+ }
35
+
36
+ static int _emnapi_wait_main_browser_thread(int is_runtime_thread, volatile void *addr, int op, int val, double max_wait_ms) {
37
+ double now = _emnapi_get_now();
38
+ double end = now + max_wait_ms;
39
+
40
+ while (1) {
41
+ now = _emnapi_get_now();
42
+ if (now >= end) {
43
+ return -ETIMEDOUT;
44
+ }
45
+
46
+ if (is_runtime_thread) {
47
+ _emnapi_yield();
48
+ }
49
+
50
+ if (__c11_atomic_load((_Atomic int *)addr, __ATOMIC_SEQ_CST) != val) {
51
+ break;
52
+ }
53
+ }
54
+
55
+ return 0;
56
+ }
57
+
58
+ int _emnapi_wait(int is_runtime_thread, volatile void *addr, int op, int val, double max_wait_ms) {
59
+ if (is_runtime_thread) {
60
+ _emnapi_yield();
61
+ }
62
+
63
+ // https://github.com/WebAssembly/wasi-libc/blob/3f7eb4c7d6ede4dde3c4bffa6ed14e8d656fe93f/libc-top-half/musl/src/thread/wasm32/__wasilibc_busywait.c#L42
64
+ if (!_emnapi_is_main_browser_thread()) {
65
+ int64_t max_wait_ns = -1;
66
+ if (max_wait_ms != INFINITY) {
67
+ max_wait_ns = (int64_t)(max_wait_ms*1000*1000);
68
+ }
69
+ return __wasilibc_futex_wait_atomic_wait(addr, op, val, max_wait_ns);
70
+ }
71
+
72
+ return _emnapi_wait_main_browser_thread(is_runtime_thread, addr, op, val, max_wait_ms);
73
+ }
74
+
75
+ int __wasilibc_futex_wait_maybe_busy(volatile void *addr, int op, int val, int64_t max_wait_ns) {
76
+ // https://github.com/emscripten-core/emscripten/blob/89ce854a99238d04116a3d9b5afe241eec90c6c3/system/lib/libc/musl/src/thread/__timedwait.c#L60
77
+ int r = 0;
78
+ double msecsToSleep = max_wait_ns >= 0 ? (max_wait_ns / 1000000.0) : INFINITY;
79
+ int is_runtime_thread = _emnapi_is_main_runtime_thread();
80
+ double max_ms_slice_to_sleep = is_runtime_thread ? 1 : 100;
81
+
82
+ if (is_runtime_thread ||
83
+ pthread_self()->canceldisable != PTHREAD_CANCEL_DISABLE ||
84
+ pthread_self()->cancelasync) {
85
+ double sleepUntilTime = _emnapi_get_now() + msecsToSleep;
86
+ do {
87
+ if (pthread_self()->cancel) {
88
+ pthread_testcancel();
89
+ return ECANCELED;
90
+ }
91
+ msecsToSleep = sleepUntilTime - _emnapi_get_now();
92
+ if (msecsToSleep <= 0) {
93
+ r = ETIMEDOUT;
94
+ break;
95
+ }
96
+ if (msecsToSleep > max_ms_slice_to_sleep)
97
+ msecsToSleep = max_ms_slice_to_sleep;
98
+ r = -_emnapi_wait(is_runtime_thread, (void*)addr, op, val, msecsToSleep);
99
+ } while (r == ETIMEDOUT);
100
+ } else {
101
+ r = -_emnapi_wait(is_runtime_thread, (void*)addr, op, val, msecsToSleep);
102
+ }
103
+ return r;
104
+ }
105
+
106
+ #endif