Skip to content

Commit 74b10a1

Browse files
committed
Use HandleAllocator for wasm workers. NFC
Similar to what we have been doing to other APIs. For example, see \#19337 and #19054
1 parent 347262a commit 74b10a1

File tree

6 files changed

+84
-52
lines changed

6 files changed

+84
-52
lines changed

src/library.js

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -3661,21 +3661,21 @@ mergeInto(LibraryManager.library, {
36613661
// Reserve slot 0 so that 0 is always an invalid handle
36623662
this.allocated = [undefined];
36633663
this.freelist = [];
3664-
this.get = function(id) {
3664+
// Hack to save on codesize: use arrow functions here even though it
3665+
// means that `this` gets statically bound to the constrcuted object.
3666+
this.get = (id) => {
36653667
#if ASSERTIONS
36663668
assert(this.allocated[id] !== undefined, 'invalid handle: ' + id);
36673669
#endif
36683670
return this.allocated[id];
36693671
};
3670-
this.has = function(id) {
3671-
return this.allocated[id] !== undefined;
3672-
};
3673-
this.allocate = function(handle) {
3672+
this.has = (id) => this.allocated[id] !== undefined;
3673+
this.allocate = (handle) => {
36743674
var id = this.freelist.pop() || this.allocated.length;
36753675
this.allocated[id] = handle;
36763676
return id;
36773677
};
3678-
this.free = function(id) {
3678+
this.free = (id) => {
36793679
#if ASSERTIONS
36803680
assert(this.allocated[id] !== undefined);
36813681
#endif

src/library_wasm_worker.js

Lines changed: 36 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -30,8 +30,7 @@
3030

3131

3232
mergeInto(LibraryManager.library, {
33-
$_wasmWorkers: {},
34-
$_wasmWorkersID: 1,
33+
$_wasmWorkers: undefined,
3534

3635
// Starting up a Wasm Worker is an asynchronous operation, hence if the parent thread performs any
3736
// postMessage()-based wasm function calls s to the Worker, they must be delayed until the async
@@ -105,17 +104,20 @@ mergeInto(LibraryManager.library, {
105104
$_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'}))",
106105
#endif
107106

108-
_emscripten_create_wasm_worker__deps: ['$_wasmWorkers', '$_wasmWorkersID', '$_wasmWorkerAppendToQueue', '$_wasmWorkerRunPostMessage'
107+
_emscripten_create_wasm_worker__deps: ['$_wasmWorkers', '$_wasmWorkerAppendToQueue',
108+
'$_wasmWorkerRunPostMessage', '$HandleAllocator',
109109
#if WASM_WORKERS == 2
110-
, '$_wasmWorkerBlobUrl'
110+
'$_wasmWorkerBlobUrl',
111111
#endif
112112
],
113-
_emscripten_create_wasm_worker__postset: 'if (ENVIRONMENT_IS_WASM_WORKER) {\n'
114-
+ '_wasmWorkers[0] = this;\n'
115-
+ 'addEventListener("message", _wasmWorkerAppendToQueue);\n'
116-
+ '}\n',
113+
_emscripten_create_wasm_worker__postset: `
114+
_wasmWorkers = new HandleAllocator();
115+
if (ENVIRONMENT_IS_WASM_WORKER) {
116+
_wasmWorkers.allocated[0] = this;
117+
addEventListener('message', _wasmWorkerAppendToQueue);
118+
}`,
117119
_emscripten_create_wasm_worker: function(stackLowestAddress, stackSize) {
118-
let worker = _wasmWorkers[_wasmWorkersID] = new Worker(
120+
let worker = new Worker(
119121
#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)
120122
_wasmWorkerBlobUrl
121123
#elif MINIMAL_RUNTIME // MINIMAL_RUNTIME has a structure where the .ww.js file is loaded from the main HTML file in parallel to all other files for best performance
@@ -124,9 +126,13 @@ mergeInto(LibraryManager.library, {
124126
locateFile('{{{ WASM_WORKER_FILE }}}')
125127
#endif
126128
);
129+
var id = _wasmWorkers.allocate(worker);
130+
#if RUNTIME_DEBUG
131+
dbg('new wasm worker -> ' + id);
132+
#endif
127133
// Craft the Module object for the Wasm Worker scope:
128134
worker.postMessage({
129-
'$ww': _wasmWorkersID, // Signal with a non-zero value that this Worker will be a Wasm Worker, and not the main browser thread.
135+
'$ww': id, // Signal with a non-zero value that this Worker will be a Wasm Worker, and not the main browser thread.
130136
#if MINIMAL_RUNTIME
131137
'wasm': Module['wasm'],
132138
'js': Module['js'],
@@ -140,27 +146,35 @@ mergeInto(LibraryManager.library, {
140146
'sz': stackSize, // sz = stack size
141147
});
142148
worker.onmessage = _wasmWorkerRunPostMessage;
143-
return _wasmWorkersID++;
149+
return id;
144150
},
145151

146152
emscripten_terminate_wasm_worker: function(id) {
147153
#if ASSERTIONS
148154
assert(id != 0, 'emscripten_terminate_wasm_worker() cannot be called with id=0!');
149155
#endif
150-
if (_wasmWorkers[id]) {
151-
_wasmWorkers[id].terminate();
152-
delete _wasmWorkers[id];
156+
if (_wasmWorkers.has(id)) {
157+
#if RUNTIME_DEBUG
158+
dbg('terminating wasm worker -> ' + id);
159+
#endif
160+
_wasmWorkers.get(id).terminate();
161+
_wasmWorkers.free(id);
153162
}
154163
},
155164

156165
emscripten_terminate_all_wasm_workers: function() {
157166
#if ASSERTIONS
158167
assert(!ENVIRONMENT_IS_WASM_WORKER, 'emscripten_terminate_all_wasm_workers() cannot be called from a Wasm Worker: only the main browser thread has visibility to terminate all Workers!');
159168
#endif
160-
Object.values(_wasmWorkers).forEach((worker) => {
161-
worker.terminate();
169+
#if RUNTIME_DEBUG
170+
dbg('emscripten_terminate_all_wasm_workers');
171+
#endif
172+
Object.values(_wasmWorkers.allocated).forEach((worker) => {
173+
if (typeof worker !== 'undefined') {
174+
worker.terminate();
175+
}
162176
});
163-
_wasmWorkers = {};
177+
_wasmWorkers = new HandleAllocator();
164178
},
165179

166180
emscripten_current_thread_is_wasm_worker: function() {
@@ -176,27 +190,27 @@ mergeInto(LibraryManager.library, {
176190
},
177191

178192
emscripten_wasm_worker_post_function_v: function(id, funcPtr) {
179-
_wasmWorkers[id].postMessage({'_wsc': funcPtr, 'x': [] }); // "WaSm Call"
193+
_wasmWorkers.get(id).postMessage({'_wsc': funcPtr, 'x': [] }); // "WaSm Call"
180194
},
181195

182196
$_wasmWorkerPostFunction1__sig: 'vipd',
183197
$_wasmWorkerPostFunction1: function(id, funcPtr, arg0) {
184-
_wasmWorkers[id].postMessage({'_wsc': funcPtr, 'x': [arg0] }); // "WaSm Call"
198+
_wasmWorkers.get(id).postMessage({'_wsc': funcPtr, 'x': [arg0] }); // "WaSm Call"
185199
},
186200

187201
emscripten_wasm_worker_post_function_vi: '$_wasmWorkerPostFunction1',
188202
emscripten_wasm_worker_post_function_vd: '$_wasmWorkerPostFunction1',
189203

190204
$_wasmWorkerPostFunction2__sig: 'vipdd',
191205
$_wasmWorkerPostFunction2: function(id, funcPtr, arg0, arg1) {
192-
_wasmWorkers[id].postMessage({'_wsc': funcPtr, 'x': [arg0, arg1] }); // "WaSm Call"
206+
_wasmWorkers.get(id).postMessage({'_wsc': funcPtr, 'x': [arg0, arg1] }); // "WaSm Call"
193207
},
194208
emscripten_wasm_worker_post_function_vii: '$_wasmWorkerPostFunction2',
195209
emscripten_wasm_worker_post_function_vdd: '$_wasmWorkerPostFunction2',
196210

197211
$_wasmWorkerPostFunction3__sig: 'vipddd',
198212
$_wasmWorkerPostFunction3: function(id, funcPtr, arg0, arg1, arg2) {
199-
_wasmWorkers[id].postMessage({'_wsc': funcPtr, 'x': [arg0, arg1, arg2] }); // "WaSm Call"
213+
_wasmWorkers.get(id).postMessage({'_wsc': funcPtr, 'x': [arg0, arg1, arg2] }); // "WaSm Call"
200214
},
201215
emscripten_wasm_worker_post_function_viii: '$_wasmWorkerPostFunction3',
202216
emscripten_wasm_worker_post_function_vddd: '$_wasmWorkerPostFunction3',
@@ -210,7 +224,7 @@ mergeInto(LibraryManager.library, {
210224
assert(UTF8ToString(sigPtr)[0] != 'v', 'Do NOT specify the return argument in the signature string for a call to emscripten_wasm_worker_post_function_sig(), just pass the function arguments.');
211225
assert(varargs);
212226
#endif
213-
_wasmWorkers[id].postMessage({'_wsc': funcPtr, 'x': readEmAsmArgs(sigPtr, varargs) });
227+
_wasmWorkers.get(id).postMessage({'_wsc': funcPtr, 'x': readEmAsmArgs(sigPtr, varargs) });
214228
},
215229

216230
$atomicWaitStates: "['ok', 'not-equal', 'timed-out']",

src/library_webaudio.js

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -123,7 +123,7 @@ let LibraryWebAudio = {
123123

124124
#if AUDIO_WORKLET
125125
emscripten_start_wasm_audio_worklet_thread_async__deps: [
126-
'$_wasmWorkersID',
126+
'$_wasmWorkers',
127127
'$_EmAudioDispatchProcessorCallback'],
128128
emscripten_start_wasm_audio_worklet_thread_async: function(contextHandle, stackLowestAddress, stackSize, callback, userData) {
129129

@@ -173,9 +173,11 @@ let LibraryWebAudio = {
173173
#if WEBAUDIO_DEBUG
174174
console.log(`emscripten_start_wasm_audio_worklet_thread_async() addModule('audioworklet.js') completed`);
175175
#endif
176+
// Assign the loaded AudioWorkletGlobalScope a Wasm Worker ID so that it can utilized its own TLS slots, and it is recognized to not be the main browser thread.
177+
var id = _wasmWorkers.allocate({});
176178
audioWorklet.bootstrapMessage = new AudioWorkletNode(audioContext, 'message', {
177179
processorOptions: {
178-
'$ww': _wasmWorkersID++, // Assign the loaded AudioWorkletGlobalScope a Wasm Worker ID so that it can utilized its own TLS slots, and it is recognized to not be the main browser thread.
180+
'$ww': id,
179181
#if MINIMAL_RUNTIME
180182
'wasm': Module['wasm'],
181183
'mem': wasmMemory,
Lines changed: 30 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,42 +1,54 @@
1-
var b = Module, c = b.$ww, f, e = b.mem || new WebAssembly.Memory({
1+
var b = Module, d = b.$ww, f, e = b.mem || new WebAssembly.Memory({
22
initial: 256,
33
maximum: 256,
44
shared: !0
5-
}), g = e.buffer, h = [], m = {}, n = 1, p, q;
5+
}), g = e.buffer, h = [], n = void 0, p, q;
66

77
function k(a) {
88
a = a.data;
9-
let d = a._wsc;
10-
d && f.get(d)(...a.x);
9+
let c = a._wsc;
10+
c && f.get(c)(...a.x);
1111
}
1212

13-
function l(a) {
13+
function m(a) {
1414
h.push(a);
1515
}
1616

17-
c && (m[0] = this, addEventListener("message", l));
17+
n = new function() {
18+
this.j = [ void 0 ];
19+
this.m = [];
20+
this.get = a => this.j[a];
21+
this.has = a => void 0 !== this.j[a];
22+
this.l = a => {
23+
var c = this.m.pop() || this.j.length;
24+
this.j[c] = a;
25+
return c;
26+
};
27+
};
28+
29+
d && (n.j[0] = this, addEventListener("message", m));
1830

1931
WebAssembly.instantiate(b.wasm, {
2032
a: {
21-
b: function(a, d) {
22-
let r = m[n] = new Worker(b.$wb);
23-
r.postMessage({
24-
$ww: n,
33+
b: function(a, c) {
34+
let l = new Worker(b.$wb), r = n.l(l);
35+
l.postMessage({
36+
$ww: r,
2537
wasm: b.wasm,
2638
js: b.js,
2739
mem: e,
2840
sb: a,
29-
sz: d
41+
sz: c
3042
});
31-
r.onmessage = k;
32-
return n++;
43+
l.onmessage = k;
44+
return r;
3345
},
3446
c: function() {
3547
return !1;
3648
},
37-
d: function(a, d) {
38-
m[a].postMessage({
39-
_wsc: d,
49+
d: function(a, c) {
50+
n.get(a).postMessage({
51+
_wsc: c,
4052
x: []
4153
});
4254
},
@@ -50,7 +62,7 @@ WebAssembly.instantiate(b.wasm, {
5062
p = a.g;
5163
q = a.i;
5264
f = a.h;
53-
c ? (a = b, q(a.sb, a.sz), removeEventListener("message", l), h = h.forEach(k),
65+
d ? (a = b, q(a.sb, a.sz), removeEventListener("message", m), h = h.forEach(k),
5466
addEventListener("message", k)) : a.f();
55-
c || p();
67+
d || p();
5668
}));
Lines changed: 4 additions & 4 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": 715,
5-
"a.js.gz": 465,
4+
"a.js": 887,
5+
"a.js.gz": 538,
66
"a.wasm": 1862,
77
"a.wasm.gz": 1040,
8-
"total": 3314,
9-
"total_gz": 1938
8+
"total": 3486,
9+
"total_gz": 2011
1010
}

test/wasm_worker/terminate_wasm_worker.c

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,11 +45,15 @@ char stack[1024];
4545
int should_throw(void(*func)())
4646
{
4747
int threw = EM_ASM_INT({
48+
var oldAbort = abort;
49+
abort = () => { throw 'abort' };
4850
try {
4951
dynCall('v', $0);
5052
} catch(e) {
5153
console.error('Threw an exception like expected: ' + e);
5254
return 1;
55+
} finally {
56+
abort = oldAbort;
5357
}
5458
console.error('Function was expected to throw, but did not!');
5559
return 0;

0 commit comments

Comments
 (0)