Skip to content

Commit 18321c5

Browse files
Allow SHARED_MEMORY flag to be used independently. (emscripten-core#22683)
Currently, there are a couple of restrictions on the `SHARED_MEMORY` flag: * Attempting to use the `SHARED_MEMORY` flag without the `PTHREADS` or `WASM_WORKERS` flags simply fails, because we don't have variations of the system libraries that have this flag standalone. Instead, emcc attempts to use the single-threaded system libraries, which are not compatible with the user's build because they don't have the correct wasm feature flags (i.e. -matomics and -mbulk-memory). This PR adds `SHARED_MEMORY`-only variations of the system libraries, which allows users to build with a standalone `SHARED_MEMORY` flag without error. * Currently, `SHARED_MEMORY` also implies `IMPORTED_MEMORY`. However, `IMPORTED_MEMORY` is only important for builds that use the `PTHREADS` or `WASM_WORKERS` flags, since they actually do multi-threading and need to read and write to the same memory across workers. This PR changes this so that if a standalone `SHARED_MEMORY` flag is specified, it can still avoid importing the memory. The use-case for enabling the `SHARED_MEMORY` flag without actually having an actual threading implementation is to be compatible with other modules which may import that memory whose import declaration specifies the memory as shared. This is an important use-case for Flutter, as we want to create two variations of the emscripten-generated module (one single-threaded and one multi-threaded, depending on whether the environment supports it) while keeping the module that imports the emscripten-generated module the same (which means keeping the memory import declaration as shared).
1 parent f13cfcf commit 18321c5

File tree

8 files changed

+91
-59
lines changed

8 files changed

+91
-59
lines changed

system/lib/compiler-rt/stack_limits.S

Lines changed: 3 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -15,14 +15,17 @@
1515
#endif
1616

1717
.globaltype __stack_pointer, PTR
18+
.globl __stack_pointer
1819

1920
.section .globals,"",@
2021

2122
# TODO(sbc): It would be nice if these we initialized directly
2223
# using PTR.const rather than using the `emscripten_stack_init`
2324
.globaltype __stack_end, PTR
2425
__stack_end:
26+
.globl __stack_end
2527
.globaltype __stack_base, PTR
28+
.globl __stack_base
2629
__stack_base:
2730

2831
.section .text,"",@
@@ -82,57 +85,6 @@ emscripten_stack_get_free:
8285
PTR.sub
8386
end_function
8487

85-
#ifdef __EMSCRIPTEN_WASM_WORKERS__
86-
# TODO: Relocate the following to its own file wasm_worker.S, but need to figure out how to reference
87-
# __stack_base and __stack_end globals from a separate file as externs in order for that to work.
88-
.globl _emscripten_wasm_worker_initialize
89-
_emscripten_wasm_worker_initialize:
90-
.functype _emscripten_wasm_worker_initialize (PTR /*stackLowestAddress*/, i32 /*stackSize*/) -> ()
91-
92-
// __stack_end = stackLowestAddress + (__builtin_wasm_tls_size() + 15) & -16;
93-
local.get 0
94-
.globaltype __tls_size, PTR, immutable
95-
global.get __tls_size
96-
PTR.add
97-
PTR.const 0xf
98-
PTR.add
99-
PTR.const -0x10
100-
PTR.and
101-
global.set __stack_end
102-
103-
// __stack_base = stackLowestAddress + stackSize;
104-
local.get 0
105-
local.get 1
106-
#ifdef __wasm64__
107-
i64.extend_i32_u
108-
#endif
109-
PTR.add
110-
global.set __stack_base
111-
112-
// TODO: We'd like to do this here to avoid JS side calls to __set_stack_limits.
113-
// (or even better, we'd like to avoid duplicate versions of the stack variables)
114-
// See https://github.com/emscripten-core/emscripten/issues/16496
115-
// global.get __stack_base
116-
// global.get __stack_end
117-
// .functype __set_stack_limits (PTR, PTR) -> ()
118-
// call __set_stack_limits
119-
120-
// __wasm_init_tls(stackLowestAddress);
121-
local.get 0
122-
.functype __wasm_init_tls (PTR) -> ()
123-
call __wasm_init_tls
124-
125-
// N.b. The function __wasm_init_tls above does not need
126-
// __stack_pointer initialized, and it destroys the value it was set to.
127-
// So we must initialize __stack_pointer only *after* completing __wasm_init_tls:
128-
129-
// __stack_pointer = __stack_base;
130-
global.get __stack_base
131-
global.set __stack_pointer
132-
133-
end_function
134-
#endif
135-
13688
# Add emscripten_stack_init to static ctors
13789
.section .init_array.1,"",@
13890
.p2align ALIGN

system/lib/dlmalloc.c

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,13 +21,12 @@
2121
/* XXX Emscripten Tracing API. This defines away the code if tracing is disabled. */
2222
#include <emscripten/trace.h>
2323

24-
#ifdef __EMSCRIPTEN_WASM_WORKERS__
24+
#ifdef __EMSCRIPTEN_SHARED_MEMORY__
2525
#define USE_LOCKS 1
2626
#endif
2727

2828
/* Make malloc() and free() threadsafe by securing the memory allocations with pthread mutexes. */
2929
#if __EMSCRIPTEN_PTHREADS__
30-
#define USE_LOCKS 1
3130
#define USE_SPIN_LOCKS 0 // Ensure we use pthread_mutex_t.
3231
#endif
3332

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
.extern __stack_pointer
2+
.extern __stack_base
3+
.extern __stack_end
4+
5+
#ifdef __wasm64__
6+
#define PTR i64
7+
#define ALIGN 3
8+
#define PTRSTORE .int64
9+
#else
10+
#define PTR i32
11+
#define ALIGN 2
12+
#define PTRSTORE .int32
13+
#endif
14+
15+
.globaltype __stack_pointer, PTR
16+
.globaltype __stack_end, PTR
17+
.globaltype __stack_base, PTR
18+
19+
.globl _emscripten_wasm_worker_initialize
20+
_emscripten_wasm_worker_initialize:
21+
.functype _emscripten_wasm_worker_initialize (PTR /*stackLowestAddress*/, i32 /*stackSize*/) -> ()
22+
23+
// __stack_end = stackLowestAddress + (__builtin_wasm_tls_size() + 15) & -16;
24+
local.get 0
25+
.globaltype __tls_size, PTR, immutable
26+
global.get __tls_size
27+
PTR.add
28+
PTR.const 0xf
29+
PTR.add
30+
PTR.const -0x10
31+
PTR.and
32+
global.set __stack_end
33+
34+
// __stack_base = stackLowestAddress + stackSize;
35+
local.get 0
36+
local.get 1
37+
#ifdef __wasm64__
38+
i64.extend_i32_u
39+
#endif
40+
PTR.add
41+
global.set __stack_base
42+
43+
// TODO: We'd like to do this here to avoid JS side calls to __set_stack_limits.
44+
// (or even better, we'd like to avoid duplicate versions of the stack variables)
45+
// See https://github.com/emscripten-core/emscripten/issues/16496
46+
// global.get __stack_base
47+
// global.get __stack_end
48+
// .functype __set_stack_limits (PTR, PTR) -> ()
49+
// call __set_stack_limits
50+
51+
// __wasm_init_tls(stackLowestAddress);
52+
local.get 0
53+
.functype __wasm_init_tls (PTR) -> ()
54+
call __wasm_init_tls
55+
56+
// N.b. The function __wasm_init_tls above does not need
57+
// __stack_pointer initialized, and it destroys the value it was set to.
58+
// So we must initialize __stack_pointer only *after* completing __wasm_init_tls:
59+
60+
// __stack_pointer = __stack_base;
61+
global.get __stack_base
62+
global.set __stack_pointer
63+
64+
end_function

test/core/test_dlfcn_self.exports

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,9 @@ __progname_full
99
__sig_actions
1010
__sig_pending
1111
__signgam
12+
__stack_base
1213
__stack_chk_guard
14+
__stack_end
1315
__threwValue
1416
__timezone
1517
__tzname

test/core/test_em_asm_unicode.out

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
hello world…
1+
hello world…

test/core/test_longjmp.out

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
11
first
22
result: 1 1
33
second
4-
result: 2 -1
4+
result: 2 -1

tools/link.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1413,7 +1413,7 @@ def phase_linker_setup(options, state, newargs):
14131413
'removeRunDependency',
14141414
]
14151415

1416-
if settings.SHARED_MEMORY or settings.RELOCATABLE or settings.ASYNCIFY_LAZY_LOAD_CODE:
1416+
if settings.PTHREADS or settings.WASM_WORKERS or settings.RELOCATABLE or settings.ASYNCIFY_LAZY_LOAD_CODE:
14171417
settings.IMPORTED_MEMORY = 1
14181418

14191419
set_initial_memory()

tools/system_libs.py

Lines changed: 18 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -742,12 +742,17 @@ def vary_on(cls):
742742

743743
@classmethod
744744
def get_default_variation(cls, **kwargs):
745-
return super().get_default_variation(is_mt=settings.PTHREADS, is_ww=settings.WASM_WORKERS and not settings.PTHREADS, **kwargs)
745+
return super().get_default_variation(
746+
is_mt=settings.PTHREADS,
747+
is_ww=settings.SHARED_MEMORY and not settings.PTHREADS,
748+
**kwargs
749+
)
746750

747751
@classmethod
748752
def variations(cls):
749753
combos = super(MTLibrary, cls).variations()
750-
# To save on # of variations, pthreads and Wasm workers when used together, just use pthreads variation.
754+
755+
# These are mutually exclusive, only one flag will be set at any give time.
751756
return [combo for combo in combos if not combo['is_mt'] or not combo['is_ww']]
752757

753758

@@ -1452,9 +1457,19 @@ def get_default_variation(cls, **kwargs):
14521457
return super().get_default_variation(stub=not settings.WASM_WORKERS, **kwargs)
14531458

14541459
def get_files(self):
1460+
files = []
1461+
if self.is_stub:
1462+
files = [
1463+
'library_wasm_worker_stub.c'
1464+
]
1465+
else:
1466+
files = [
1467+
'library_wasm_worker.c',
1468+
'wasm_worker_initialize.S',
1469+
]
14551470
return files_in_path(
14561471
path='system/lib/wasm_worker',
1457-
filenames=['library_wasm_worker_stub.c' if self.is_stub else 'library_wasm_worker.c'])
1472+
filenames=files)
14581473

14591474
def can_use(self):
14601475
# see src/library_wasm_worker.js

0 commit comments

Comments
 (0)