Skip to content

Commit d828324

Browse files
committed
[Wasm64] Add support for threads
Testing wasm64 with threads requires a nightly build of node (since it depends on some very recent fixes on the v8 side).
1 parent eb31d86 commit d828324

File tree

17 files changed

+68
-41
lines changed

17 files changed

+68
-41
lines changed

.circleci/config.yml

Lines changed: 26 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -75,24 +75,38 @@ commands:
7575
node_version:
7676
description: "version of node to install"
7777
type: string
78+
canary:
79+
description: "install a canary version of node"
80+
type: boolean
81+
default: false
7882
steps:
7983
- run:
8084
name: setup node v<< parameters.node_version >>
8185
command: |
8286
cd $HOME
8387
version=<< parameters.node_version >>
84-
wget https://nodejs.org/dist/v${version}/node-v${version}-linux-x64.tar.xz
88+
if [[ << parameters.canary >> == "true" ]]; then
89+
wget https://nodejs.org/download/v8-canary/v${version}/node-v${version}-linux-x64.tar.xz
90+
else
91+
wget https://nodejs.org/dist/v${version}/node-v${version}-linux-x64.tar.xz
92+
fi
8593
tar xf node-v${version}-linux-x64.tar.xz
8694
echo "NODE_JS = [os.path.expanduser('~/node-v${version}-linux-x64/bin/node')]" >> ~/emsdk/.emscripten
8795
echo "JS_ENGINES = [NODE_JS]" >> ~/emsdk/.emscripten
8896
echo "if os.path.exists(V8_ENGINE[0]): JS_ENGINES.append(V8_ENGINE)" >> ~/emsdk/.emscripten
8997
cat ~/emsdk/.emscripten
9098
echo "export PATH=\"$HOME/node-v${version}-linux-x64/bin:\$PATH\"" >> $BASH_ENV
91-
install-latest-node:
99+
install-node-latest:
92100
description: "install latest version of node"
93101
steps:
94102
- install-node-version:
95103
node_version: "19.0.0"
104+
install-node-canary:
105+
description: "install canary version of node"
106+
steps:
107+
- install-node-version:
108+
node_version: "20.0.0-v8-canary202212266b2b946a63"
109+
canary: true
96110
install-v8:
97111
description: "install v8 using jsvu"
98112
steps:
@@ -532,7 +546,7 @@ jobs:
532546
- run-tests:
533547
title: "wasm64l"
534548
test_targets: "wasm64l"
535-
- install-latest-node
549+
- install-node-canary
536550
- run-tests:
537551
title: "wasm64"
538552
test_targets: "wasm64"
@@ -548,6 +562,14 @@ jobs:
548562
command: git submodule update --init
549563
- pip-install
550564
- build
565+
- install-node-canary
566+
- run-tests:
567+
title: "selected subset"
568+
test_targets: "
569+
other.test_gen_struct_info
570+
other.test_native_call_before_init
571+
other.test_node_unhandled_rejection
572+
core2.test_hello_world"
551573
# Run some basic tests with the minimum version of node that we currently
552574
# support.
553575
- install-node-version:
@@ -562,7 +584,7 @@ jobs:
562584
# Run a few test with the most recent version of node
563585
# In particular we have some tests that require node flags on older
564586
# versions of node but not with the most recent version.
565-
- install-latest-node
587+
- install-node-latest
566588
- run-tests:
567589
# Run tests that on older versions of node would require flags, but
568590
# those flags should not be injected on newer versions.

emscripten.py

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -865,6 +865,13 @@ def create_wasm64_wrappers(metadata):
865865
'__cxa_can_catch': '_ppp',
866866
'_wasmfs_write_file': '_ppp',
867867
'__dl_seterr': '_pp',
868+
'emscripten_run_in_main_runtime_thread_js': '___p_',
869+
'_emscripten_proxy_execute_task_queue': '_p',
870+
'_emscripten_thread_exit': '_p',
871+
'_emscripten_thread_init': '_p____',
872+
'_emscripten_thread_free_data': '_p',
873+
'_emscripten_dlsync_self_async': '_p',
874+
'_emscripten_proxy_dlsync_async': '_pp',
868875
}
869876

870877
wasm64_wrappers = '''

src/library_dylink.js

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1081,11 +1081,11 @@ var LibraryDylink = {
10811081
var filename = UTF8ToString({{{ makeGetValue('handle', C_STRUCTS.dso.name, '*') }}});
10821082
dlSetError('Could not load dynamic lib: ' + filename + '\n' + e);
10831083
{{{ runtimeKeepalivePop() }}}
1084-
callUserCallback(function () { {{{ makeDynCall('vii', 'onerror') }}}(handle, user_data); });
1084+
callUserCallback(function () { {{{ makeDynCall('vpp', 'onerror') }}}(handle, user_data); });
10851085
}
10861086
function successCallback() {
10871087
{{{ runtimeKeepalivePop() }}}
1088-
callUserCallback(function () { {{{ makeDynCall('vii', 'onsuccess') }}}(handle, user_data); });
1088+
callUserCallback(function () { {{{ makeDynCall('vpp', 'onsuccess') }}}(handle, user_data); });
10891089
}
10901090

10911091
{{{ runtimeKeepalivePush() }}}
@@ -1115,7 +1115,7 @@ var LibraryDylink = {
11151115

11161116
// void* dlsym(void* handle, const char* symbol);
11171117
_dlsym_js__deps: ['$dlSetError', '$getFunctionAddress', '$addFunction'],
1118-
_dlsym_js__sig: 'ppp',
1118+
_dlsym_js__sig: 'pppp',
11191119
_dlsym_js: function(handle, symbol, symbolIndex) {
11201120
// void *dlsym(void *restrict handle, const char *restrict name);
11211121
// http://pubs.opengroup.org/onlinepubs/009695399/functions/dlsym.html

src/library_pthread.js

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -539,6 +539,7 @@ var LibraryPThread = {
539539
worker.pthread_ptr = 0;
540540
},
541541

542+
__emscripten_thread_cleanup__sig: 'vp',
542543
__emscripten_thread_cleanup: function(thread) {
543544
// Called when a thread needs to be cleaned up so it can be reused.
544545
// A thread is considered reusable when it either returns from its
@@ -708,7 +709,7 @@ var LibraryPThread = {
708709
// allocations from __pthread_create_js we could also remove this.
709710
__pthread_create_js__noleakcheck: true,
710711
#endif
711-
__pthread_create_js__sig: 'iiiii',
712+
__pthread_create_js__sig: 'ipppp',
712713
__pthread_create_js__deps: ['$spawnThread', 'pthread_self', '$pthreadCreateProxied',
713714
#if OFFSCREENCANVAS_SUPPORT
714715
'malloc',
@@ -975,6 +976,7 @@ var LibraryPThread = {
975976

976977
emscripten_receive_on_main_thread_js_callArgs: '=[]',
977978

979+
emscripten_receive_on_main_thread_js__sig: 'diip',
978980
emscripten_receive_on_main_thread_js__deps: [
979981
'emscripten_proxy_to_main_thread_js',
980982
'emscripten_receive_on_main_thread_js_callArgs'],
@@ -1078,7 +1080,7 @@ var LibraryPThread = {
10781080
// *ThreadMain(void *arg) form, or try linking with the Emscripten linker
10791081
// flag -sEMULATE_FUNCTION_POINTER_CASTS to add in emulation for this x86
10801082
// ABI extension.
1081-
var result = {{{ makeDynCall('ii', 'ptr') }}}(arg);
1083+
var result = {{{ makeDynCall('pp', 'ptr') }}}(arg);
10821084
#if STACK_OVERFLOW_CHECK
10831085
checkStackCookie();
10841086
#endif
@@ -1097,6 +1099,7 @@ var LibraryPThread = {
10971099
},
10981100

10991101
#if MAIN_MODULE
1102+
_emscripten_thread_exit_joinable__sig: 'vp',
11001103
_emscripten_thread_exit_joinable: function(thread) {
11011104
// Called when a thread exits and is joinable. We mark these threads
11021105
// as finished, which means that are in state where are no longer actually
@@ -1207,6 +1210,7 @@ var LibraryPThread = {
12071210
},
12081211

12091212
_emscripten_notify_task_queue__deps: ['$executeNotifiedProxyingQueue'],
1213+
_emscripten_notify_task_queue__sig: 'vpppp',
12101214
_emscripten_notify_task_queue: function(targetThreadId, currThreadId, mainThreadId, queue) {
12111215
if (targetThreadId == currThreadId) {
12121216
setTimeout(() => executeNotifiedProxyingQueue(queue));

src/preamble.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1049,7 +1049,7 @@ function createWasm() {
10491049
#else // singlethreaded build:
10501050
removeRunDependency('wasm-instantiate');
10511051
#endif // ~USE_PTHREADS
1052-
1052+
return exports;
10531053
}
10541054
// wait for the pthread pool (if any)
10551055
addRunDependency('wasm-instantiate');

src/worker.js

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -95,16 +95,16 @@ Module['instantiateWasm'] = (info, receiveInstance) => {
9595
// We can just use sync instantiation in the worker.
9696
var instance = new WebAssembly.Instance(Module['wasmModule'], info);
9797
#if RELOCATABLE || MAIN_MODULE
98-
receiveInstance(instance, Module['wasmModule']);
98+
var exports = receiveInstance(instance, Module['wasmModule']);
9999
#else
100100
// TODO: Due to Closure regression https://github.com/google/closure-compiler/issues/3193,
101101
// the above line no longer optimizes out down to the following line.
102102
// When the regression is fixed, we can remove this if/else.
103-
receiveInstance(instance);
103+
var exports = receiveInstance(instance);
104104
#endif
105105
// We don't need the module anymore; new threads will be spawned from the main thread.
106106
Module['wasmModule'] = null;
107-
return instance.exports;
107+
return exports;
108108
}
109109
#endif
110110

system/lib/compiler-rt/stack_limits.S

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -89,9 +89,6 @@ emscripten_wasm_worker_initialize:
8989
local.get 0
9090
.globaltype __tls_size, PTR, immutable
9191
global.get __tls_size
92-
#ifdef __wasm64__
93-
i64.extend_i32_u
94-
#endif
9592
PTR.add
9693
PTR.const 0xf
9794
PTR.add

system/lib/libc/musl/arch/emscripten/bits/alltypes.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -93,7 +93,7 @@ typedef struct {
9393
union {
9494
int __i[10];
9595
volatile int __vi[10];
96-
unsigned __s[10];
96+
unsigned long __s[10];
9797
} __u;
9898
#ifdef __EMSCRIPTEN__
9999
// For canvas transfer implementation in Emscripten, use an extra control field

system/lib/pthread/library_pthread.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -190,7 +190,7 @@ static void _do_call(void* arg) {
190190
break;
191191
case EM_PROXIED_JS_FUNCTION:
192192
q->returnValue.d =
193-
emscripten_receive_on_main_thread_js((int)(size_t)q->functionPtr, q->args[0].i, &q->args[1].d);
193+
emscripten_receive_on_main_thread_js((intptr_t)q->functionPtr, q->args[0].i, &q->args[1].d);
194194
break;
195195
case EM_FUNC_SIG_V:
196196
((em_func_v)q->functionPtr)();
@@ -435,7 +435,7 @@ double emscripten_run_in_main_runtime_thread_js(int index, int num_args, int64_t
435435
c->calleeDelete = 1-sync;
436436
c->functionEnum = EM_PROXIED_JS_FUNCTION;
437437
// Index not needed to ever be more than 32-bit.
438-
c->functionPtr = (void*)(size_t)index;
438+
c->functionPtr = (void*)(intptr_t)index;
439439
assert(num_args+1 <= EM_QUEUED_JS_CALL_MAX_ARGS);
440440
// The types are only known at runtime in these calls, so we store values that
441441
// must be able to contain any valid JS value, including a 64-bit BigInt if

test/common.py

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -513,8 +513,6 @@ def setup_node_pthreads(self):
513513
self.require_node()
514514
self.set_setting('USE_PTHREADS')
515515
self.emcc_args += ['-Wno-pthreads-mem-growth']
516-
if self.get_setting('MEMORY64'):
517-
self.skipTest('node pthreads not yet supported with MEMORY64')
518516
if self.get_setting('MINIMAL_RUNTIME'):
519517
self.skipTest('node pthreads not yet supported with MINIMAL_RUNTIME')
520518
self.js_engines = [config.NODE_JS]

0 commit comments

Comments
 (0)