Skip to content

Commit ed8acb3

Browse files
authored
Remove WASM_WORKERS_NO_TLS option (#16476)
* Remove WASM_WORKERS_NO_TLS option, and simplify Wasm Worker TLS creation by hiding it as an implementation detail - TLS block will be grafted onto the memory area set for the thread stack. Also fix MINIMAL_RUNTIME+WASM_WORKERS+WASM=0 build combination and add a test for that. * Update test doc * Remove wasm_worker_init_tls() * Update code size test * Rebaseline wasm2js tests.
1 parent f6a122b commit ed8acb3

38 files changed

+110
-157
lines changed

site/source/docs/api_reference/wasm_workers.rst

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -33,9 +33,8 @@ which shares the same WebAssembly.Module and WebAssembly.Memory object. Then a
3333
``postMessage()`` is passed to the Worker to ask it to execute the function
3434
``run_in_worker()`` to print a string.
3535

36-
For more complex threading scenarios, see the functions ``emscripten_create_wasm_worker_with_tls()``
37-
and ``emscripten_create_wasm_worker_no_tls()`` on how to manage the memory resources that
38-
the thread will use.
36+
To explicitly control the memory allocation placement when creating a worker, use the
37+
function ``emscripten_create_wasm_worker()``.
3938

4039
Introduction
4140
============

src/library_wasm_worker.js

Lines changed: 5 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -56,11 +56,7 @@ mergeInto(LibraryManager.library, {
5656
#endif
5757

5858
// Run the C side Worker initialization for stack and TLS.
59-
_emscripten_wasm_worker_initialize(m['sb'], m['sz']
60-
#if !WASM_WORKERS_NO_TLS
61-
, m['tb']
62-
#endif
63-
);
59+
_emscripten_wasm_worker_initialize(m['sb'], m['sz']);
6460
// The above function initializes the stack for this Worker, but C code cannot
6561
// call to extern __set_stack_limits() function, or Binaryen breaks with
6662
// "Fatal: Module::addFunction: __set_stack_limits already exists".
@@ -87,20 +83,16 @@ mergeInto(LibraryManager.library, {
8783
_wasmWorkerBlobUrl: "URL.createObjectURL(new Blob(['onmessage=function(d){onmessage=null;d=d.data;{{{ captureModuleArg() }}}{{{ instantiateWasm() }}}importScripts(d.js);{{{ instantiateModule() }}}d.wasm=d.mem=d.js=0;}'],{type:'application/javascript'}))",
8884
#endif
8985

90-
_emscripten_create_wasm_worker_with_tls__deps: ['wasm_workers', 'wasm_workers_id', '_wasm_worker_appendToQueue', '_wasm_worker_runPostMessage'
86+
_emscripten_create_wasm_worker__deps: ['wasm_workers', 'wasm_workers_id', '_wasm_worker_appendToQueue', '_wasm_worker_runPostMessage'
9187
#if WASM_WORKERS == 2
9288
, '_wasmWorkerBlobUrl'
9389
#endif
9490
],
95-
_emscripten_create_wasm_worker_with_tls__postset: 'if (ENVIRONMENT_IS_WASM_WORKER) {\n'
91+
_emscripten_create_wasm_worker__postset: 'if (ENVIRONMENT_IS_WASM_WORKER) {\n'
9692
+ '_wasm_workers[0] = this;\n'
9793
+ 'addEventListener("message", __wasm_worker_appendToQueue);\n'
9894
+ '}\n',
99-
_emscripten_create_wasm_worker_with_tls: function(stackLowestAddress, stackSize, tlsAddress) {
100-
#if ASSERTIONS
101-
assert(stackLowestAddress % 16 == 0);
102-
assert(stackSize % 16 == 0);
103-
#endif
95+
_emscripten_create_wasm_worker: function(stackLowestAddress, stackSize) {
10496
let worker = _wasm_workers[_wasm_workers_id] = new Worker(
10597
#if WASM_WORKERS == 2 // WASM_WORKERS=2 mode embeds .ww.js file contents into the main .js file as a Blob URL. (convenient, but not CSP security safe, since this is eval-like)
10698
__wasmWorkerBlobUrl
@@ -122,19 +114,12 @@ mergeInto(LibraryManager.library, {
122114
'js': Module['mainScriptUrlOrBlob'] || _scriptDir,
123115
'wasmMemory': wasmMemory,
124116
#endif
125-
'sb': stackLowestAddress, // sb = stack base
117+
'sb': stackLowestAddress, // sb = stack bottom (lowest stack address, SP points at this when stack is full)
126118
'sz': stackSize, // sz = stack size
127-
#if !WASM_WORKERS_NO_TLS
128-
'tb': tlsAddress, // tb = TLS base
129-
#endif
130119
});
131120
worker.addEventListener('message', __wasm_worker_runPostMessage);
132121
return _wasm_workers_id++;
133122
},
134-
_emscripten_create_wasm_worker_no_tls__deps: ['_emscripten_create_wasm_worker_with_tls'],
135-
_emscripten_create_wasm_worker_no_tls: function(stackLowestAddress, stackSize) {
136-
return __emscripten_create_wasm_worker_with_tls(stackLowestAddress, stackSize, 0, 0);
137-
},
138123

139124
emscripten_terminate_wasm_worker: function(id) {
140125
#if ASSERTIONS

src/settings.js

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1480,12 +1480,6 @@ var USE_PTHREADS = 0;
14801480
// [compile+link] - affects user code at compile and system libraries at link.
14811481
var WASM_WORKERS = 0;
14821482

1483-
// Wasm Worker option: set to 1 to disable TLS for small code size gain when
1484-
// not using TLS. This setting can be used to verify that there is no leftover
1485-
// state stored in a Worker when manually implementing thread pooling in Workers.
1486-
// [link]
1487-
var WASM_WORKERS_NO_TLS = 0;
1488-
14891483
// In web browsers, Workers cannot be created while the main browser thread
14901484
// is executing JS/Wasm code, but the main thread must regularly yield back
14911485
// to the browser event loop for Worker initialization to occur.

system/include/emscripten/wasm_worker.h

Lines changed: 4 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -17,28 +17,16 @@ extern "C" {
1717
behaves, the dynamically allocated memory can never be freed, so use this function
1818
only in scenarios where the page does not need to deinitialize/tear itself down.
1919
20-
emscripten_create_wasm_worker_no_tls: Creates a Wasm Worker on the given placed stack address area, but no TLS.
21-
Use this function on codebase that explicitly do not have any TLS state,
22-
e.g. when the Worker is being reset to reinit execution at runtime, or to micro-
23-
optimize code size when TLS is not needed. This function will assert() fail if
24-
the compiled code does have any TLS uses in it. This function does not use any
25-
dynamic memory allocation.
26-
27-
emscripten_create_wasm_worker_with_tls: Creates a Wasm Worker on given placed stack address and TLS area.
28-
Use the Wasm built-in functions __builtin_wasm_tls_align() and
29-
__builtin_wasm_tls_size() to obtain the needed memory size for the TLS area
30-
(though note that __builtin_wasm_tls_align() can return zero when the TLS size
31-
is zero, so be careful to avoid a divide by zero if/when rounding to this alignment)
32-
Use this function to manually manage the memory that a Worker should use.
33-
This function does not use any dynamic memory allocation.
20+
emscripten_create_wasm_worker: Creates a Wasm Worker on given placed stack address.
21+
Use this function to manually manage the memory that a Worker should use.
22+
This function does not use any dynamic memory allocation.
3423
3524
Returns an ID that represents the given Worker. If not building with Wasm workers enabled (-s WASM_WORKERS=0),
3625
these functions will return 0 to denote failure.
3726
Note that the Worker will be loaded up asynchronously, and initially will not be executing any code. Use
3827
emscripten_wasm_worker_post_function_*() set of functions to start executing code on the Worker. */
3928
emscripten_wasm_worker_t emscripten_malloc_wasm_worker(uint32_t stackSize);
40-
emscripten_wasm_worker_t emscripten_create_wasm_worker_no_tls(void *stackLowestAddress, uint32_t stackSize);
41-
emscripten_wasm_worker_t emscripten_create_wasm_worker_with_tls(void *stackLowestAddress, uint32_t stackSize, void *tlsAddress, uint32_t tlsSize);
29+
emscripten_wasm_worker_t emscripten_create_wasm_worker(void *stackLowestAddress, uint32_t stackSize);
4230

4331
// Terminates the given Wasm Worker some time after it has finished executing its current, or possibly some subsequent
4432
// posted functions. Note that this function is not C++ RAII safe, but you must manually coordinate to release any

system/lib/compiler-rt/stack_limits.S

Lines changed: 22 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -82,27 +82,44 @@ emscripten_stack_get_free:
8282
# __stack_base and __stack_end globals from a separate file as externs in order for that to work.
8383
.globl emscripten_wasm_worker_initialize
8484
emscripten_wasm_worker_initialize:
85-
.functype emscripten_wasm_worker_initialize (PTR, i32, PTR) -> ()
85+
.functype emscripten_wasm_worker_initialize (PTR /*stackLowestAddress*/, i32 /*stackSize*/) -> ()
8686

87+
// __stack_end = stackLowestAddress + (__builtin_wasm_tls_size() + 15) & -16;
8788
local.get 0
89+
.globaltype __tls_size, PTR, immutable
90+
global.get __tls_size
91+
#ifdef __wasm64__
92+
i64.extend_i32_u
93+
#endif
94+
PTR.add
95+
PTR.const 0xf
96+
PTR.add
97+
PTR.const -0x10
98+
PTR.and
8899
global.set __stack_end
89100

101+
// __stack_base = stackLowestAddress + stackSize;
90102
local.get 0
91103
local.get 1
92104
#ifdef __wasm64__
93105
i64.extend_i32_u
94106
#endif
95107
PTR.add
96-
local.tee 0
97108
global.set __stack_base
98109

110+
// __wasm_init_tls(stackLowestAddress);
99111
local.get 0
100-
global.set __stack_pointer
101-
102-
local.get 2
103112
.functype __wasm_init_tls (PTR) -> ()
104113
call __wasm_init_tls
105114

115+
// N.b. The function __wasm_init_tls above does not need
116+
// __stack_pointer initialized, and it destroys the value it was set to.
117+
// So we must initialize __stack_pointer only *after* completing __wasm_init_tls:
118+
119+
// __stack_pointer = __stack_base;
120+
global.get __stack_base
121+
global.set __stack_pointer
122+
106123
end_function
107124
#endif
108125

system/lib/wasm_worker/library_wasm_worker.c

Lines changed: 19 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -2,68 +2,54 @@
22
#include <emscripten/wasm_worker.h>
33
#include <emscripten/threading.h>
44
#include <emscripten/heap.h>
5+
#include <emscripten/stack.h>
56
#include <malloc.h>
67

78
#ifndef __EMSCRIPTEN_WASM_WORKERS__
89
#error __EMSCRIPTEN_WASM_WORKERS__ should be defined when building this file!
910
#endif
1011

1112
// Options:
12-
// #define WASM_WORKER_NO_TLS 0/1 : set to 1 to disable TLS compilation support for a small code size gain
1313
// #define STACK_OVERFLOW_CHECK 0/1/2 : set to the current stack overflow check mode
1414

1515
// Internal implementation function in JavaScript side that emscripten_create_wasm_worker() calls to
1616
// to perform the wasm worker creation.
17-
emscripten_wasm_worker_t _emscripten_create_wasm_worker_with_tls(void *stackLowestAddress, uint32_t stackSize, void *tlsAddress);
18-
emscripten_wasm_worker_t _emscripten_create_wasm_worker_no_tls(void *stackLowestAddress, uint32_t stackSize);
17+
emscripten_wasm_worker_t _emscripten_create_wasm_worker(void *stackLowestAddress, uint32_t stackSize);
1918

2019
void __wasm_init_tls(void *memory);
2120

22-
#if !WASM_WORKER_NO_TLS
2321
__attribute__((constructor(48)))
2422
static void emscripten_wasm_worker_main_thread_initialize() {
2523
uintptr_t* sbrk_ptr = emscripten_get_sbrk_ptr();
2624
__wasm_init_tls((void*)*sbrk_ptr);
2725
*sbrk_ptr += __builtin_wasm_tls_size();
2826
}
29-
#endif
3027

31-
emscripten_wasm_worker_t emscripten_create_wasm_worker_with_tls(void *stackLowestAddress, uint32_t stackSize, void *tlsAddress, uint32_t tlsSize)
28+
emscripten_wasm_worker_t emscripten_create_wasm_worker(void *stackLowestAddress, uint32_t stackSize)
3229
{
33-
#if WASM_WORKER_NO_TLS
34-
return emscripten_create_wasm_worker_no_tls(stackLowestAddress, stackSize);
35-
#else
30+
assert(stackLowestAddress != 0);
3631
assert((uintptr_t)stackLowestAddress % 16 == 0);
32+
assert(stackSize > 0);
3733
assert(stackSize % 16 == 0);
38-
assert(__builtin_wasm_tls_align() != 0 || __builtin_wasm_tls_size() == 0); // Internal consistency check: Clang can report __builtin_wasm_tls_align to be zero if there is no TLS used - double check it never reports zero if it is used.
39-
assert(__builtin_wasm_tls_align() == 0 || (uintptr_t)tlsAddress % __builtin_wasm_tls_align() == 0 && "TLS memory address not aligned in a call to emscripten_create_wasm_worker_with_tls()! Please allocate memory with alignment from __builtin_wasm_tls_align() when creating a Wasm Worker!");
40-
assert(tlsSize != 0 || __builtin_wasm_tls_size() == 0 && "Program code contains TLS: please use function emscripten_create_wasm_worker_with_tls() to create a Wasm Worker!");
41-
assert(tlsSize == __builtin_wasm_tls_size() && "TLS size mismatch! Please reserve exactly __builtin_wasm_tls_size() TLS memory in a call to emscripten_create_wasm_worker_with_tls()");
42-
assert(tlsAddress != 0 || tlsSize == 0);
43-
return _emscripten_create_wasm_worker_with_tls((void*)stackLowestAddress, stackSize, tlsAddress);
44-
#endif
45-
}
4634

47-
emscripten_wasm_worker_t emscripten_create_wasm_worker_no_tls(void *stackLowestAddress, uint32_t stackSize)
48-
{
49-
#if !WASM_WORKER_NO_TLS
50-
return emscripten_create_wasm_worker_with_tls(stackLowestAddress, stackSize, 0, 0);
51-
#else
52-
assert((uintptr_t)stackLowestAddress % 16 == 0);
53-
assert(stackSize % 16 == 0);
54-
assert(__builtin_wasm_tls_size() == 0 && "Cannot disable TLS with -sWASM_WORKERS_NO_TLS=1 when compiling code that does require TLS! Rebuild with -sWASM_WORKERS_NO_TLS=1 removed, or remove uses of TLS from the codebase.");
55-
return _emscripten_create_wasm_worker_no_tls((void*)stackLowestAddress, stackSize);
56-
#endif
35+
// Guard against a programming oopsie: The target Worker's stack cannot be part of the calling
36+
// thread's stack.
37+
assert(emscripten_stack_get_base() <= (uintptr_t)stackLowestAddress || emscripten_stack_get_end() >= (uintptr_t)stackLowestAddress + stackSize
38+
&& "When creating a Wasm Worker, its stack should be located either in global data or on the heap, not on the calling thread's own stack!");
39+
40+
// The Worker's TLS area will be spliced off from the stack region.
41+
// We expect TLS area to need to be at most 16 bytes aligned
42+
assert(__builtin_wasm_tls_align() == 0 || 16 % __builtin_wasm_tls_align() == 0);
43+
44+
uint32_t tlsSize = (__builtin_wasm_tls_size() + 15) & -16;
45+
assert(stackSize > tlsSize);
46+
47+
return _emscripten_create_wasm_worker(stackLowestAddress, stackSize);
5748
}
5849

5950
emscripten_wasm_worker_t emscripten_malloc_wasm_worker(uint32_t stackSize)
6051
{
61-
#if WASM_WORKER_NO_TLS
62-
return emscripten_create_wasm_worker_no_tls(memalign(16, stackSize), stackSize);
63-
#else
64-
uint32_t tlsSize = __builtin_wasm_tls_size();
65-
return emscripten_create_wasm_worker_with_tls(memalign(16, stackSize), stackSize, tlsSize ? memalign(__builtin_wasm_tls_align(), tlsSize) : 0, tlsSize);
66-
#endif
52+
return emscripten_create_wasm_worker(memalign(16, stackSize), stackSize);
6753
}
6854

6955
void emscripten_wasm_worker_sleep(int64_t nsecs)

system/lib/wasm_worker/library_wasm_worker_stub.c

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -8,11 +8,7 @@
88
#error __EMSCRIPTEN_WASM_WORKERS__ should not be defined when building this file!
99
#endif
1010

11-
emscripten_wasm_worker_t emscripten_create_wasm_worker_with_tls(void *stackLowestAddress, uint32_t stackSize, void *tlsAddress, uint32_t tlsSize) {
12-
return 0;
13-
}
14-
15-
emscripten_wasm_worker_t emscripten_create_wasm_worker_no_tls(void *stackLowestAddress, uint32_t stackSize) {
11+
emscripten_wasm_worker_t emscripten_create_wasm_worker(void *stackLowestAddress, uint32_t stackSize) {
1612
return 0;
1713
}
1814

tests/code_size/hello_wasm_worker_wasm.js

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -30,16 +30,15 @@ var p, q;
3030

3131
WebAssembly.instantiate(b.wasm, {
3232
a: {
33-
b: function(a, d, t) {
33+
b: function(a, d) {
3434
let r = h[k] = new Worker(b.$wb);
3535
r.postMessage({
3636
$ww: k,
3737
wasm: b.wasm,
3838
js: b.js,
3939
mem: e,
4040
sb: a,
41-
sz: d,
42-
tb: t
41+
sz: d
4342
});
4443
r.addEventListener("message", n);
4544
return k++;
@@ -63,7 +62,7 @@ WebAssembly.instantiate(b.wasm, {
6362
p = a.g;
6463
q = a.i;
6564
f = a.h;
66-
c ? (a = b, q(a.sb, a.sz, a.tb), removeEventListener("message", l), m = m.forEach(n),
65+
c ? (a = b, q(a.sb, a.sz), removeEventListener("message", l), m = m.forEach(n),
6766
addEventListener("message", n)) : a.f();
6867
c || p();
6968
}));
Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
11
{
22
"a.html": 737,
33
"a.html.gz": 433,
4-
"a.js": 765,
5-
"a.js.gz": 475,
6-
"a.wasm": 1792,
7-
"a.wasm.gz": 989,
8-
"total": 3294,
9-
"total_gz": 1897
4+
"a.js": 753,
5+
"a.js.gz": 468,
6+
"a.wasm": 1800,
7+
"a.wasm.gz": 994,
8+
"total": 3290,
9+
"total_gz": 1895
1010
}
Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
11
{
2-
"a.html": 594,
3-
"a.html.gz": 389,
2+
"a.html": 567,
3+
"a.html.gz": 379,
44
"a.js": 20046,
55
"a.js.gz": 8213,
66
"a.mem": 3171,
77
"a.mem.gz": 2714,
8-
"total": 23811,
9-
"total_gz": 11316
8+
"total": 23784,
9+
"total_gz": 11306
1010
}

0 commit comments

Comments
 (0)