Skip to content

Commit 081ac97

Browse files
committed
Inline ww.js file into the main output file
Similar to what we did for pthreads in emscripten-core#21701. This is win for both code size and complexity.
1 parent f163dc2 commit 081ac97

27 files changed

+201
-208
lines changed

site/source/docs/tools_reference/settings_reference.rst

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2507,13 +2507,9 @@ Default value: false
25072507
WASM_WORKERS
25082508
============
25092509

2510-
If 1, enables support for Wasm Workers. Wasm Workers enable applications
2510+
Enables support for Wasm Workers. Wasm Workers enable applications
25112511
to create threads using a lightweight web-specific API that builds on top
2512-
of Wasm SharedArrayBuffer + Atomics API. When enabled, a new build output
2513-
file a.ww.js will be generated to bootstrap the Wasm Worker JS contexts.
2514-
If 2, enables support for Wasm Workers, but without using a separate a.ww.js
2515-
file on the side. This can simplify deployment of builds, but will have a
2516-
downside that the generated build will no longer be csp-eval compliant.
2512+
of Wasm SharedArrayBuffer + Atomics API.
25172513
[compile+link] - affects user code at compile and system libraries at link.
25182514

25192515
Default value: 0

src/audio_worklet.js

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -140,10 +140,14 @@ function createWasmAudioWorkletProcessor(audioParams) {
140140
class BootstrapMessages extends AudioWorkletProcessor {
141141
constructor(arg) {
142142
super();
143+
// Audio worklets need to show up as wasm workers. This is the way we signal
144+
// that.
145+
globalThis.name = 'em-ww';
143146
// Initialize the global Emscripten Module object that contains e.g. the
144147
// Wasm Module and Memory objects. After this we are ready to load in the
145148
// main application JS script, which the main thread will addModule()
146149
// to this scope.
150+
globalThis.wasmWorkerArgs = arg['processorOptions'];
147151
globalThis.Module = arg['processorOptions'];
148152
#if !MINIMAL_RUNTIME
149153
// Default runtime relies on an injected instantiateWasm() function to

src/lib/libwasm_worker.js

Lines changed: 25 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -4,15 +4,6 @@
44
* SPDX-License-Identifier: MIT
55
*/
66

7-
#if WASM_WORKERS == 2
8-
// Helpers for _wasmWorkerBlobUrl used in WASM_WORKERS == 2 mode
9-
{{{
10-
const captureModuleArg = () => MODULARIZE ? '' : 'self.Module=d;';
11-
const instantiateModule = () => MODULARIZE ? `${EXPORT_NAME}(d);` : '';
12-
const instantiateWasm = () => MINIMAL_RUNTIME ? '' : 'd[`instantiateWasm`]=(i,r)=>{var n=new WebAssembly.Instance(d[`wasm`],i);return r(n,d[`wasm`]);};';
13-
}}}
14-
#endif
15-
167
#if WASM_WORKERS
178

189
#if !SHARED_MEMORY
@@ -34,18 +25,28 @@
3425
{{{
3526
const workerSupportsFutexWait = () => AUDIO_WORKLET ? "typeof AudioWorkletGlobalScope === 'undefined'" : '1';
3627
const wasmWorkerJs = `
37-
#if WASM_WORKERS == 2
38-
_wasmWorkerBlobUrl
39-
#elif MINIMAL_RUNTIME
28+
#if MINIMAL_RUNTIME
4029
#if ENVIRONMENT_MAY_BE_NODE
41-
Module['$wb'] || './${WASM_WORKER_FILE}'
30+
Module['$wb'] || './${TARGET_JS_NAME}'
4231
#else
4332
Module['$wb']
4433
#endif
4534
#else
46-
locateFile('${WASM_WORKER_FILE}')
35+
locateFile('${TARGET_JS_NAME}')
4736
#endif
4837
`;
38+
const wasmWorkerOptions = `{
39+
#if ENVIRONMENT_MAY_BE_NODE
40+
// This is the way that we signal to the node worker that it is hosting
41+
// a wasm worker.
42+
'workerData': 'em-ww',
43+
#endif
44+
#if ENVIRONMENT_MAY_BE_WEB || ENVIRONMENT_MAY_BE_WORKER
45+
// This is the way that we signal to the Web Worker that it is hosting
46+
// a pthread.
47+
'name': 'em-ww',
48+
#endif
49+
}`;
4950
}}}
5051

5152
#endif // ~WASM_WORKERS
@@ -87,11 +88,16 @@ addToLibrary({
8788
#endif
8889
],
8990
$_wasmWorkerInitializeRuntime: () => {
90-
let m = Module;
91+
let m = wasmWorkerArgs;
9192
#if ASSERTIONS
93+
assert(m && m['$ww']);
9294
assert(m['sb'] % 16 == 0);
9395
assert(m['sz'] % 16 == 0);
9496
#endif
97+
Module['$ww'] = m['$ww'];
98+
#if RUNTIME_DEBUG
99+
dbg("wasmWorkerInitializeRuntime $ww:", Module['$ww']);
100+
#endif
95101

96102
#if !MINIMAL_RUNTIME && isSymbolNeeded('$noExitRuntime')
97103
// Wasm workers basically never exit their runtime
@@ -146,20 +152,9 @@ addToLibrary({
146152
#endif
147153
},
148154

149-
#if WASM_WORKERS == 2
150-
// In WASM_WORKERS == 2 build mode, we create the Wasm Worker global scope
151-
// script from a string bundled in the main application JS file. This
152-
// simplifies the number of deployed JS files with the app, but has a downside
153-
// that the generated build output will no longer be csp-eval compliant.
154-
// https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Security-Policy/script-src#unsafe_eval_expressions
155-
$_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'}))",
156-
#endif
157155
_emscripten_create_wasm_worker__deps: [
158156
'$_wasmWorkers', '$_wasmWorkersID',
159157
'$_wasmWorkerAppendToQueue', '$_wasmWorkerRunPostMessage',
160-
#if WASM_WORKERS == 2
161-
'$_wasmWorkerBlobUrl',
162-
#endif
163158
#if ASSERTIONS
164159
'emscripten_has_threading_support',
165160
#endif
@@ -171,7 +166,7 @@ if (ENVIRONMENT_IS_WASM_WORKER
171166
&& !ENVIRONMENT_IS_AUDIO_WORKLET
172167
#endif
173168
) {
174-
_wasmWorkers[0] = this;
169+
_wasmWorkers[0] = globalThis;
175170
addEventListener("message", _wasmWorkerAppendToQueue);
176171
}`,
177172
_emscripten_create_wasm_worker: (stackLowestAddress, stackSize) => {
@@ -188,28 +183,21 @@ if (ENVIRONMENT_IS_WASM_WORKER
188183
var p = trustedTypes.createPolicy(
189184
'emscripten#workerPolicy1', { createScriptURL: (ignored) => {{{ wasmWorkerJs }}}}
190185
);
191-
worker = _wasmWorkers[_wasmWorkersID] = new Worker(p.createScriptURL('ignored'));
186+
worker = _wasmWorkers[_wasmWorkersID] = new Worker(p.createScriptURL('ignored'), {{{ wasmWorkerOptions }}});
192187
} else
193188
#endif
194-
worker = _wasmWorkers[_wasmWorkersID] = new Worker({{{ wasmWorkerJs }}});
189+
worker = _wasmWorkers[_wasmWorkersID] = new Worker({{{ wasmWorkerJs }}}, {{{ wasmWorkerOptions }}});
195190
// Craft the Module object for the Wasm Worker scope:
196191
worker.postMessage({
197192
// Signal with a non-zero value that this Worker will be a Wasm Worker,
198193
// and not the main browser thread.
199194
'$ww': _wasmWorkersID,
200195
#if MINIMAL_RUNTIME
201196
'wasm': Module['wasm'],
202-
#if ENVIRONMENT_MAY_BE_NODE
203-
'js': Module['js'] || './{{{ TARGET_JS_NAME }}}',
204-
#else
205-
'js': Module['js'],
206-
#endif
207-
'mem': wasmMemory,
208197
#else
209198
'wasm': wasmModule,
210-
'js': Module['mainScriptUrlOrBlob'] || _scriptName,
211-
'wasmMemory': wasmMemory,
212199
#endif
200+
'mem': wasmMemory,
213201
'sb': stackLowestAddress, // sb = stack bottom (lowest stack address, SP points at this when stack is full)
214202
'sz': stackSize, // sz = stack size
215203
});

src/parseTools.mjs

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1081,10 +1081,6 @@ function getPerformanceNow() {
10811081
}
10821082
}
10831083

1084-
function implicitSelf() {
1085-
return ENVIRONMENT.includes('node') ? 'self.' : '';
1086-
}
1087-
10881084
function ENVIRONMENT_IS_MAIN_THREAD() {
10891085
return `(!${ENVIRONMENT_IS_WORKER_THREAD()})`;
10901086
}
@@ -1143,7 +1139,6 @@ addToCompileTimeContext({
11431139
getPerformanceNow,
11441140
getUnsharedTextDecoderView,
11451141
hasExportedSymbol,
1146-
implicitSelf,
11471142
isSymbolNeeded,
11481143
makeDynCall,
11491144
makeEval,

src/postamble.js

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -145,7 +145,9 @@ function run() {
145145
}
146146

147147
#if PTHREADS || WASM_WORKERS
148+
//dbg("YYYYYYYYYYYYYYYYY");
148149
if ({{{ ENVIRONMENT_IS_WORKER_THREAD() }}}) {
150+
//dbg("XXXXXXXXXXXXXXXXXXX");
149151
#if MODULARIZE
150152
readyPromiseResolve(Module);
151153
#endif

src/postamble_minimal.js

Lines changed: 5 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -95,7 +95,7 @@ var wasmExports;
9595
var wasmModule;
9696
#endif
9797

98-
#if PTHREADS
98+
#if PTHREADS || WASM_WORKERS
9999
function loadModule() {
100100
assignWasmImports();
101101
#endif
@@ -255,12 +255,10 @@ WebAssembly.instantiate(Module['wasm'], imports).then((output) => {
255255
#endif // ASSERTIONS || WASM == 2
256256
);
257257

258-
#if PTHREADS
258+
#if PTHREADS || WASM_WORKERS
259259
}
260260

261-
if (!ENVIRONMENT_IS_PTHREAD) {
262-
// When running in a pthread we delay module loading untill we have
263-
// received the module via postMessage
264-
loadModule();
265-
}
261+
// When running in a background thread we delay module loading until we have
262+
// received the module via postMessage
263+
{{{ runIfMainThread('loadModule();') }}}
266264
#endif

src/preamble.js

Lines changed: 5 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -248,9 +248,7 @@ function exitRuntime() {
248248
#if STACK_OVERFLOW_CHECK
249249
checkStackCookie();
250250
#endif
251-
#if PTHREADS
252-
if (ENVIRONMENT_IS_PTHREAD) return; // PThreads reuse the runtime from the main thread.
253-
#endif
251+
{{{ runIfWorkerThread('return;') }}} // PThreads reuse the runtime from the main thread.
254252
#if !STANDALONE_WASM
255253
___funcs_on_exit(); // Native atexit() functions
256254
#endif
@@ -266,9 +264,7 @@ function postRun() {
266264
#if STACK_OVERFLOW_CHECK
267265
checkStackCookie();
268266
#endif
269-
#if PTHREADS
270-
if (ENVIRONMENT_IS_PTHREAD) return; // PThreads reuse the runtime from the main thread.
271-
#endif
267+
{{{ runIfWorkerThread('return;') }}} // PThreads reuse the runtime from the main thread.
272268

273269
#if expectToReceiveOnModule('postRun')
274270
if (Module['postRun']) {
@@ -823,7 +819,7 @@ async function instantiateAsync(binary, binaryFile, imports) {
823819

824820
#if !WASM_ESM_INTEGRATION
825821
function getWasmImports() {
826-
#if PTHREADS
822+
#if PTHREADS || WASM_WORKERS
827823
assignWasmImports();
828824
#endif
829825
#if ASYNCIFY && (ASSERTIONS || ASYNCIFY == 2)
@@ -1008,8 +1004,8 @@ function getWasmImports() {
10081004
}
10091005
#endif
10101006

1011-
#if PTHREADS
1012-
if (ENVIRONMENT_IS_PTHREAD) {
1007+
#if PTHREADS || WASM_WORKERS
1008+
if ({{{ ENVIRONMENT_IS_WORKER_THREAD() }}}) {
10131009
return new Promise((resolve) => {
10141010
wasmModuleReceived = (module) => {
10151011
// Instantiate from the module posted from the main thread.

src/runtime_debug.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -193,7 +193,7 @@ var runtimeDebug = true; // Switch to false at runtime to disable logging at the
193193
// Used by XXXXX_DEBUG settings to output debug messages.
194194
function dbg(...args) {
195195
if (!runtimeDebug && typeof runtimeDebug != 'undefined') return;
196-
#if ENVIRONMENT_MAY_BE_NODE && PTHREADS
196+
#if ENVIRONMENT_MAY_BE_NODE && (PTHREADS || WASM_WORKERS)
197197
// Avoid using the console for debugging in multi-threaded node applications
198198
// See https://github.com/emscripten-core/emscripten/issues/14804
199199
if (ENVIRONMENT_IS_NODE) {

src/runtime_init_memory.js

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -12,9 +12,10 @@
1212
// check for full engine support (use string 'subarray' to avoid closure compiler confusion)
1313

1414
function initMemory() {
15-
#if PTHREADS
16-
if (ENVIRONMENT_IS_PTHREAD) return;
17-
#endif // PTHREADS
15+
#if AUDIO_WORKLET
16+
if (!ENVIRONMENT_IS_AUDIO_WORKLET)
17+
#endif
18+
{{{ runIfWorkerThread('return') }}}
1819

1920
#if expectToReceiveOnModule('wasmMemory')
2021
if (Module['wasmMemory']) {

src/runtime_pthread.js

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -21,10 +21,6 @@ var sharedModules = {};
2121
#endif
2222

2323
if (ENVIRONMENT_IS_PTHREAD) {
24-
#if !MINIMAL_RUNTIME
25-
var wasmModuleReceived;
26-
#endif
27-
2824
#if ENVIRONMENT_MAY_BE_NODE
2925
// Node.js support
3026
if (ENVIRONMENT_IS_NODE) {

src/runtime_shared.js

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,10 +21,18 @@
2121
#include "runtime_asan.js"
2222
#endif
2323

24+
#if !MINIMAL_RUNTIME && (PTHREADS || WASM_WORKERS)
25+
var wasmModuleReceived;
26+
#endif
27+
2428
#if PTHREADS
2529
#include "runtime_pthread.js"
2630
#endif
2731

32+
#if WASM_WORKERS
33+
#include "wasm_worker.js"
34+
#endif
35+
2836
#if LOAD_SOURCE_MAP
2937
var wasmSourceMap;
3038
#include "source_map_support.js"

src/settings.js

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1637,13 +1637,9 @@ var USE_SQLITE3 = false;
16371637
// [compile+link] - affects user code at compile and system libraries at link.
16381638
var SHARED_MEMORY = false;
16391639

1640-
// If 1, enables support for Wasm Workers. Wasm Workers enable applications
1640+
// Enables support for Wasm Workers. Wasm Workers enable applications
16411641
// to create threads using a lightweight web-specific API that builds on top
1642-
// of Wasm SharedArrayBuffer + Atomics API. When enabled, a new build output
1643-
// file a.ww.js will be generated to bootstrap the Wasm Worker JS contexts.
1644-
// If 2, enables support for Wasm Workers, but without using a separate a.ww.js
1645-
// file on the side. This can simplify deployment of builds, but will have a
1646-
// downside that the generated build will no longer be csp-eval compliant.
1642+
// of Wasm SharedArrayBuffer + Atomics API.
16471643
// [compile+link] - affects user code at compile and system libraries at link.
16481644
var WASM_WORKERS = 0;
16491645

src/settings_internal.js

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -134,9 +134,6 @@ var USER_EXPORTS = [];
134134
// name of the file containing wasm binary, if relevant
135135
var WASM_BINARY_FILE = '';
136136

137-
// name of the file containing the Wasm Worker *.ww.js, if relevant
138-
var WASM_WORKER_FILE = '';
139-
140137
// Base URL the source mapfile, if relevant
141138
var SOURCE_MAP_BASE = '';
142139

src/shell.js

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -102,6 +102,12 @@ if (ENVIRONMENT_IS_PTHREAD) {
102102
#endif
103103
#endif
104104

105+
#if WASM_WORKERS
106+
// The way we signal to a worker that it is hosting a pthread is to construct
107+
// it with a specific name.
108+
var ENVIRONMENT_IS_WASM_WORKER = globalThis.name == 'em-ww';
109+
#endif
110+
105111
#if ENVIRONMENT_MAY_BE_NODE
106112
if (ENVIRONMENT_IS_NODE) {
107113
#if EXPORT_ES6
@@ -121,14 +127,13 @@ if (ENVIRONMENT_IS_NODE) {
121127
// is hosting a pthread.
122128
ENVIRONMENT_IS_PTHREAD = ENVIRONMENT_IS_WORKER && worker_threads['workerData'] == 'em-pthread'
123129
#endif // PTHREADS
130+
#if WASM_WORKERS
131+
ENVIRONMENT_IS_WASM_WORKER = ENVIRONMENT_IS_WORKER && worker_threads['workerData'] == 'em-ww'
132+
#endif
124133
#endif // PTHREADS || WASM_WORKERS
125134
}
126135
#endif // ENVIRONMENT_MAY_BE_NODE
127136

128-
#if WASM_WORKERS
129-
var ENVIRONMENT_IS_WASM_WORKER = !!Module['$ww'];
130-
#endif
131-
132137
// --pre-jses are emitted after the Module integration code, so that they can
133138
// refer to Module (if they choose; they can also define Module)
134139
{{{ preJS() }}}

0 commit comments

Comments
 (0)