Skip to content

Commit 8f98375

Browse files
authored
[wasm2js] Support nonzero offsets in memory.atomic.wait32 (#5489)
The assertion that the offset is zero does not necessarily hold for code that uses this instruction via the clang builtin. Add support so that Emscripten wasm2js tests pass in the presence of such code.
1 parent 3a315fb commit 8f98375

File tree

7 files changed

+19
-15
lines changed

7 files changed

+19
-15
lines changed

src/abi/js.h

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -82,8 +82,9 @@ inline void ensureHelpers(Module* wasm, IString specific = IString()) {
8282
ensureImport(MEMORY_FILL, {Type::i32, Type::i32, Type::i32}, Type::none);
8383
ensureImport(MEMORY_COPY, {Type::i32, Type::i32, Type::i32}, Type::none);
8484
ensureImport(DATA_DROP, {Type::i32}, Type::none);
85-
ensureImport(
86-
ATOMIC_WAIT_I32, {Type::i32, Type::i32, Type::i32, Type::i32}, Type::i32);
85+
ensureImport(ATOMIC_WAIT_I32,
86+
{Type::i32, Type::i32, Type::i32, Type::i32, Type::i32},
87+
Type::i32);
8788
ensureImport(
8889
ATOMIC_RMW_I64,
8990
{Type::i32, Type::i32, Type::i32, Type::i32, Type::i32, Type::i32},

src/passes/I64ToI32Lowering.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -478,10 +478,10 @@ struct I64ToI32Lowering : public WalkerPass<PostWalker<I64ToI32Lowering>> {
478478

479479
void visitAtomicWait(AtomicWait* curr) {
480480
// The last parameter is an i64, so we cannot leave it as it is
481-
assert(curr->offset == 0);
482481
replaceCurrent(builder->makeCall(
483482
ABI::wasm2js::ATOMIC_WAIT_I32,
484-
{curr->ptr,
483+
{builder->makeConst(int32_t(curr->offset)),
484+
curr->ptr,
485485
curr->expected,
486486
curr->timeout,
487487
builder->makeLocalGet(fetchOutParam(curr->timeout), Type::i32)},

src/wasm2js.h

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2989,15 +2989,16 @@ void Wasm2JSGlue::emitSpecialSupport() {
29892989
)";
29902990
} else if (import->base == ABI::wasm2js::ATOMIC_WAIT_I32) {
29912991
out << R"(
2992-
function wasm2js_atomic_wait_i32(ptr, expected, timeoutLow, timeoutHigh) {
2992+
function wasm2js_atomic_wait_i32(offset, ptr, expected, timeoutLow, timeoutHigh) {
2993+
ptr = (ptr + offset) >> 2;
29932994
var timeout = Infinity;
29942995
if (timeoutHigh >= 0) {
29952996
// Convert from nanoseconds to milliseconds
29962997
// Taken from convertI32PairToI53 in emscripten's library_int53.js
29972998
timeout = ((timeoutLow >>> 0) / 1e6) + timeoutHigh * (4294967296 / 1e6);
29982999
}
29993000
var view = new Int32Array(bufferView.buffer); // TODO cache
3000-
var result = Atomics.wait(view, ptr >> 2, expected, timeout);
3001+
var result = Atomics.wait(view, ptr, expected, timeout);
30013002
if (result == 'ok') return 0;
30023003
if (result == 'not-equal') return 1;
30033004
if (result == 'timed-out') return 2;

test/passes/remove-non-js-ops.txt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@
1414
(type $f64_=>_none (func (param f64)))
1515
(type $i32_i32_i32_i32_=>_none (func (param i32 i32 i32 i32)))
1616
(type $i32_=>_none (func (param i32)))
17-
(type $i32_i32_i32_i32_=>_i32 (func (param i32 i32 i32 i32) (result i32)))
17+
(type $i32_i32_i32_i32_i32_=>_i32 (func (param i32 i32 i32 i32 i32) (result i32)))
1818
(type $i32_i32_i32_i32_i32_i32_=>_i32 (func (param i32 i32 i32 i32 i32 i32) (result i32)))
1919
(type $none_=>_i32 (func (result i32)))
2020
(type $none_=>_none (func))
@@ -28,7 +28,7 @@
2828
(import "env" "wasm2js_memory_fill" (func $wasm2js_memory_fill (param i32 i32 i32)))
2929
(import "env" "wasm2js_memory_copy" (func $wasm2js_memory_copy (param i32 i32 i32)))
3030
(import "env" "wasm2js_data_drop" (func $wasm2js_data_drop (param i32)))
31-
(import "env" "wasm2js_atomic_wait_i32" (func $wasm2js_atomic_wait_i32 (param i32 i32 i32 i32) (result i32)))
31+
(import "env" "wasm2js_atomic_wait_i32" (func $wasm2js_atomic_wait_i32 (param i32 i32 i32 i32 i32) (result i32)))
3232
(import "env" "wasm2js_atomic_rmw_i64" (func $wasm2js_atomic_rmw_i64 (param i32 i32 i32 i32 i32 i32) (result i32)))
3333
(import "env" "wasm2js_get_stashed_bits" (func $wasm2js_get_stashed_bits (result i32)))
3434
(import "env" "wasm2js_trap" (func $wasm2js_trap))

test/wasm2js/atomics_32.2asm.js

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -24,15 +24,16 @@
2424
memorySegments[0] = base64DecodeToExistingUint8Array(new Uint8Array(6), 0, "aGVsbG8s");
2525
memorySegments[1] = base64DecodeToExistingUint8Array(new Uint8Array(6), 0, "d29ybGQh");
2626

27-
function wasm2js_atomic_wait_i32(ptr, expected, timeoutLow, timeoutHigh) {
27+
function wasm2js_atomic_wait_i32(offset, ptr, expected, timeoutLow, timeoutHigh) {
28+
ptr = (ptr + offset) >> 2;
2829
var timeout = Infinity;
2930
if (timeoutHigh >= 0) {
3031
// Convert from nanoseconds to milliseconds
3132
// Taken from convertI32PairToI53 in emscripten's library_int53.js
3233
timeout = ((timeoutLow >>> 0) / 1e6) + timeoutHigh * (4294967296 / 1e6);
3334
}
3435
var view = new Int32Array(bufferView.buffer); // TODO cache
35-
var result = Atomics.wait(view, ptr >> 2, expected, timeout);
36+
var result = Atomics.wait(view, ptr, expected, timeout);
3637
if (result == 'ok') return 0;
3738
if (result == 'not-equal') return 1;
3839
if (result == 'timed-out') return 2;
@@ -119,7 +120,7 @@ function asmFunc(imports) {
119120
Atomics.load(HEAP32, 1028 >> 2) | 0;
120121
Atomics.store(HEAP32, 100 >> 2, 200);
121122
i64toi32_i32$0 = -1;
122-
wasm2js_atomic_wait_i32(4 | 0, 8 | 0, -1 | 0, i64toi32_i32$0 | 0) | 0;
123+
wasm2js_atomic_wait_i32(4 | 0, 8 | 0, 16 | 0, -1 | 0, i64toi32_i32$0 | 0) | 0;
123124
wasm2js_memory_init(0, 512, 0, 4);
124125
wasm2js_memory_init(1, 1024, 4, 2);
125126
Atomics.notify(HEAP32, 4 >> 2, 2);

test/wasm2js/atomics_32.2asm.js.opt

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -24,15 +24,16 @@
2424
memorySegments[0] = base64DecodeToExistingUint8Array(new Uint8Array(6), 0, "aGVsbG8s");
2525
memorySegments[1] = base64DecodeToExistingUint8Array(new Uint8Array(6), 0, "d29ybGQh");
2626

27-
function wasm2js_atomic_wait_i32(ptr, expected, timeoutLow, timeoutHigh) {
27+
function wasm2js_atomic_wait_i32(offset, ptr, expected, timeoutLow, timeoutHigh) {
28+
ptr = (ptr + offset) >> 2;
2829
var timeout = Infinity;
2930
if (timeoutHigh >= 0) {
3031
// Convert from nanoseconds to milliseconds
3132
// Taken from convertI32PairToI53 in emscripten's library_int53.js
3233
timeout = ((timeoutLow >>> 0) / 1e6) + timeoutHigh * (4294967296 / 1e6);
3334
}
3435
var view = new Int32Array(bufferView.buffer); // TODO cache
35-
var result = Atomics.wait(view, ptr >> 2, expected, timeout);
36+
var result = Atomics.wait(view, ptr, expected, timeout);
3637
if (result == 'ok') return 0;
3738
if (result == 'not-equal') return 1;
3839
if (result == 'timed-out') return 2;
@@ -117,7 +118,7 @@ function asmFunc(imports) {
117118
Atomics.load(HEAPU16, 514);
118119
Atomics.load(HEAP32, 257);
119120
Atomics.store(HEAP32, 25, 200);
120-
wasm2js_atomic_wait_i32(4, 8, -1, -1) | 0;
121+
wasm2js_atomic_wait_i32(4, 8, 16, -1, -1) | 0;
121122
wasm2js_memory_init(0, 512, 0, 4);
122123
wasm2js_memory_init(1, 1024, 4, 2);
123124
Atomics.notify(HEAP32, 1, 2);

test/wasm2js/atomics_32.wast

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@
1212
(local.set $x (i32.atomic.load16_u (i32.const 1028)))
1313
(local.set $x (i32.atomic.load (i32.const 1028)))
1414
(i32.atomic.store (i32.const 100) (i32.const 200))
15-
(local.set $x (memory.atomic.wait32 (i32.const 4) (i32.const 8) (i64.const -1)))
15+
(local.set $x (memory.atomic.wait32 offset=4 (i32.const 8) (i32.const 16) (i64.const -1)))
1616
(memory.init 0 (i32.const 512) (i32.const 0) (i32.const 4))
1717
(memory.init 1 (i32.const 1024) (i32.const 4) (i32.const 2))
1818
(local.set $x (memory.atomic.notify (i32.const 4) (i32.const 2)))

0 commit comments

Comments
 (0)