Skip to content

Commit d15011e

Browse files
authored
Revert "Delete the Atomics.waitAsync() polyfill (#25494)" (#25501)
This reverts commit d9e0690. Oops, it looks like we do have several tests that depended on the polyfill: http://clbri.com:8010/api/v2/logs/89393/raw_inline In particular: ``` browser.test_wasm_worker_cancel_all_wait_asyncs browser.test_wasm_worker_cancel_all_wait_asyncs_at_address browser.test_wasm_worker_cancel_all_wait_asyncs_at_address_minimal_runtime browser.test_wasm_worker_cancel_all_wait_asyncs_minimal_runtime browser.test_wasm_worker_cancel_wait_async browser.test_wasm_worker_cancel_wait_async_minimal_runtime browser.test_wasm_worker_wait_async browser.test_wasm_worker_wait_async_minimal_runtime ``` CircleCI just didn't have coverage of these functions on Firefox. Revert this PR until we can reinstate it in a form that applies the polyfill to only these functions.
1 parent fc97ec9 commit d15011e

File tree

2 files changed

+64
-1
lines changed

2 files changed

+64
-1
lines changed

src/lib/libatomic.js

Lines changed: 63 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,14 +7,76 @@
77
assert(SHARED_MEMORY);
88

99
addToLibrary({
10+
// Chrome 87 shipped Atomics.waitAsync:
11+
// https://www.chromestatus.com/feature/6243382101803008
12+
// However its implementation is faulty:
13+
// https://bugs.chromium.org/p/chromium/issues/detail?id=1167541
14+
// Firefox Nightly 86.0a1 (2021-01-15) does not yet have it:
15+
// https://bugzilla.mozilla.org/show_bug.cgi?id=1467846
16+
// And at the time of writing, no other browser has it either.
17+
#if MIN_CHROME_VERSION < 91 || MIN_SAFARI_VERSION != TARGET_NOT_SUPPORTED || MIN_FIREFOX_VERSION != TARGET_NOT_SUPPORTED || ENVIRONMENT_MAY_BE_NODE
18+
// Partially polyfill Atomics.waitAsync() if not available in the browser.
19+
// Also polyfill for old Chrome-based browsers, where Atomics.waitAsync is
20+
// broken until Chrome 91, see:
21+
// https://bugs.chromium.org/p/chromium/issues/detail?id=1167541
22+
// https://github.com/tc39/proposal-atomics-wait-async/blob/master/PROPOSAL.md
23+
// This polyfill performs polling with setTimeout() to observe a change in the
24+
// target memory location.
25+
$polyfillWaitAsync__postset: `if (!Atomics.waitAsync || (globalThis.navigator?.userAgent && Number((navigator.userAgent.match(/Chrom(e|ium)\\/([0-9]+)\\./)||[])[2]) < 91)) {
26+
let __Atomics_waitAsyncAddresses = [/*[i32a, index, value, maxWaitMilliseconds, promiseResolve]*/];
27+
function __Atomics_pollWaitAsyncAddresses() {
28+
let now = performance.now();
29+
let l = __Atomics_waitAsyncAddresses.length;
30+
for (let i = 0; i < l; ++i) {
31+
let a = __Atomics_waitAsyncAddresses[i];
32+
let expired = (now > a[3]);
33+
let awoken = (Atomics.load(a[0], a[1]) != a[2]);
34+
if (expired || awoken) {
35+
__Atomics_waitAsyncAddresses[i--] = __Atomics_waitAsyncAddresses[--l];
36+
__Atomics_waitAsyncAddresses.length = l;
37+
a[4](awoken ? 'ok': 'timed-out');
38+
}
39+
}
40+
if (l) {
41+
// If we still have addresses to wait, loop the timeout handler to continue polling.
42+
setTimeout(__Atomics_pollWaitAsyncAddresses, 10);
43+
}
44+
}
45+
#if ASSERTIONS && WASM_WORKERS
46+
if (!ENVIRONMENT_IS_WASM_WORKER) err('Current environment does not support Atomics.waitAsync(): polyfilling it, but this is going to be suboptimal.');
47+
#endif
48+
/**
49+
* @param {number=} maxWaitMilliseconds
50+
*/
51+
Atomics.waitAsync = (i32a, index, value, maxWaitMilliseconds) => {
52+
let val = Atomics.load(i32a, index);
53+
if (val != value) return { async: false, value: 'not-equal' };
54+
if (maxWaitMilliseconds <= 0) return { async: false, value: 'timed-out' };
55+
maxWaitMilliseconds = performance.now() + (maxWaitMilliseconds || Infinity);
56+
let promiseResolve;
57+
let promise = new Promise((resolve) => { promiseResolve = resolve; });
58+
if (!__Atomics_waitAsyncAddresses[0]) setTimeout(__Atomics_pollWaitAsyncAddresses, 10);
59+
__Atomics_waitAsyncAddresses.push([i32a, index, value, maxWaitMilliseconds, promiseResolve]);
60+
return { async: true, value: promise };
61+
};
62+
}`,
63+
#endif
64+
65+
$polyfillWaitAsync__internal: true,
66+
$polyfillWaitAsync: () => {
67+
// nop, used for its postset to ensure `Atomics.waitAsync()` polyfill is
68+
// included exactly once and only included when needed.
69+
// Any function using Atomics.waitAsync should depend on this.
70+
},
71+
1072
$atomicWaitStates__internal: true,
1173
$atomicWaitStates: ['ok', 'not-equal', 'timed-out'],
1274
$liveAtomicWaitAsyncs: {},
1375
$liveAtomicWaitAsyncs__internal: true,
1476
$liveAtomicWaitAsyncCounter: 0,
1577
$liveAtomicWaitAsyncCounter__internal: true,
1678

17-
emscripten_atomic_wait_async__deps: ['$atomicWaitStates', '$liveAtomicWaitAsyncs', '$liveAtomicWaitAsyncCounter', '$callUserCallback'],
79+
emscripten_atomic_wait_async__deps: ['$atomicWaitStates', '$liveAtomicWaitAsyncs', '$liveAtomicWaitAsyncCounter', '$polyfillWaitAsync', '$callUserCallback'],
1880
emscripten_atomic_wait_async: (addr, val, asyncWaitFinished, userData, maxWaitMilliseconds) => {
1981
let wait = Atomics.waitAsync(HEAP32, {{{ getHeapOffset('addr', 'i32') }}}, val, maxWaitMilliseconds);
2082
if (!wait.async) return atomicWaitStates.indexOf(wait.value);

src/lib/libwasm_worker.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -298,6 +298,7 @@ if (ENVIRONMENT_IS_WASM_WORKER
298298
return Atomics.isLockFree(width);
299299
},
300300

301+
emscripten_lock_async_acquire__deps: ['$polyfillWaitAsync'],
301302
emscripten_lock_async_acquire: (lock, asyncWaitFinished, userData, maxWaitMilliseconds) => {
302303
let dispatch = (val, ret) => {
303304
setTimeout(() => {

0 commit comments

Comments
 (0)