Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
548 changes: 548 additions & 0 deletions test/core/atomic.wast

Large diffs are not rendered by default.

108 changes: 108 additions & 0 deletions test/core/atomic_wait_notify.wast
Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@
;; wait/notify
(module
(memory 1 1 shared)

(func (export "init") (param $value i64) (i64.store (i32.const 0) (local.get $value)))

(func (export "memory.atomic.notify") (param $addr i32) (param $count i32) (result i32)
(memory.atomic.notify (local.get 0) (local.get 1)))
(func (export "memory.atomic.wait32") (param $addr i32) (param $expected i32) (param $timeout i64) (result i32)
(memory.atomic.wait32 (local.get 0) (local.get 1) (local.get 2)))
(func (export "memory.atomic.wait64") (param $addr i32) (param $expected i64) (param $timeout i64) (result i32)
(memory.atomic.wait64 (local.get 0) (local.get 1) (local.get 2)))
)

(invoke "init" (i64.const 0xffffffffffff))

;; wait returns immediately if values do not match
(assert_return (invoke "memory.atomic.wait32" (i32.const 0) (i32.const 0) (i64.const 0)) (i32.const 1))
(assert_return (invoke "memory.atomic.wait64" (i32.const 0) (i64.const 0) (i64.const 0)) (i32.const 1))

;; wait times out if values do match and timeout is small
(assert_return (invoke "memory.atomic.wait32" (i32.const 0) (i32.const 0xffffffff) (i64.const 10)) (i32.const 2))
(assert_return (invoke "memory.atomic.wait64" (i32.const 0) (i64.const 0xffffffffffff) (i64.const 10)) (i32.const 2))

;; notify always returns
(assert_return (invoke "memory.atomic.notify" (i32.const 0) (i32.const 0)) (i32.const 0))
(assert_return (invoke "memory.atomic.notify" (i32.const 0) (i32.const 10)) (i32.const 0))

;; OOB wait and notify always trap
(assert_trap (invoke "memory.atomic.wait32" (i32.const 65536) (i32.const 0) (i64.const 0)) "out of bounds memory access")
(assert_trap (invoke "memory.atomic.wait64" (i32.const 65536) (i64.const 0) (i64.const 0)) "out of bounds memory access")

;; in particular, notify always traps even if waking 0 threads
(assert_trap (invoke "memory.atomic.notify" (i32.const 65536) (i32.const 0)) "out of bounds memory access")

;; similarly, unaligned wait and notify always trap
(assert_trap (invoke "memory.atomic.wait32" (i32.const 65531) (i32.const 0) (i64.const 0)) "unaligned atomic")
(assert_trap (invoke "memory.atomic.wait64" (i32.const 65524) (i64.const 0) (i64.const 0)) "unaligned atomic")

(assert_trap (invoke "memory.atomic.notify" (i32.const 65531) (i32.const 0)) "unaligned atomic")

;; atomic.wait traps on unshared memory even if it wouldn't block
(module
(memory 1 1)

(func (export "init") (param $value i64) (i64.store (i32.const 0) (local.get $value)))

(func (export "memory.atomic.notify") (param $addr i32) (param $count i32) (result i32)
(memory.atomic.notify (local.get 0) (local.get 1)))
(func (export "memory.atomic.wait32") (param $addr i32) (param $expected i32) (param $timeout i64) (result i32)
(memory.atomic.wait32 (local.get 0) (local.get 1) (local.get 2)))
(func (export "memory.atomic.wait64") (param $addr i32) (param $expected i64) (param $timeout i64) (result i32)
(memory.atomic.wait64 (local.get 0) (local.get 1) (local.get 2)))
)

(invoke "init" (i64.const 0xffffffffffff))

(assert_trap (invoke "memory.atomic.wait32" (i32.const 0) (i32.const 0) (i64.const 0)) "expected shared memory")
(assert_trap (invoke "memory.atomic.wait64" (i32.const 0) (i64.const 0) (i64.const 0)) "expected shared memory")

;; notify still works
(assert_return (invoke "memory.atomic.notify" (i32.const 0) (i32.const 0)) (i32.const 0))

;; OOB and unaligned notify still trap
(assert_trap (invoke "memory.atomic.notify" (i32.const 65536) (i32.const 0)) "out of bounds memory access")
(assert_trap (invoke "memory.atomic.notify" (i32.const 65531) (i32.const 0)) "unaligned atomic")

;; test that looping notify eventually unblocks a parallel waiting thread
(module $Mem
(memory (export "shared") 1 1 shared)
)

(thread $T1 (shared (module $Mem))
(register "mem" $Mem)
(module
(memory (import "mem" "shared") 1 10 shared)
(func (export "run") (result i32)
(memory.atomic.wait32 (i32.const 0) (i32.const 0) (i64.const -1))
)
)
;; test that this thread eventually gets unblocked
(assert_return (invoke "run") (i32.const 0))
)

(thread $T2 (shared (module $Mem))
(register "mem" $Mem)
(module
(memory (import "mem" "shared") 1 1 shared)
(func (export "notify-0") (result i32)
(memory.atomic.notify (i32.const 0) (i32.const 0))
)
(func (export "notify-1-while")
(loop
(i32.const 1)
(memory.atomic.notify (i32.const 0) (i32.const 1))
(i32.ne)
(br_if 0)
)
)
)
;; notifying with a count of 0 will not unblock
(assert_return (invoke "notify-0") (i32.const 0))
;; loop until something is notified
(assert_return (invoke "notify-1-while"))
)

(wait $T1)
(wait $T2)
7 changes: 7 additions & 0 deletions test/core/exports.wast
Original file line number Diff line number Diff line change
Expand Up @@ -201,6 +201,13 @@
(module (export "a" (memory $a)) (memory $a 0))
(module (export "a" (memory $a)) (memory $a 0 1))

(module (memory (export "a") 0 1 shared))
(module (memory 0 1 shared) (export "a" (memory 0)))
(module (memory $a (export "a") 0 1 shared))
(module (memory $a 0 1 shared) (export "a" (memory $a)))
(module (export "a" (memory 0)) (memory 0 1 shared))
(module (export "a" (memory $a)) (memory $a 0 1 shared))

(; TODO: access memory ;)

(assert_invalid
Expand Down
4 changes: 4 additions & 0 deletions test/core/memory.wast
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,10 @@
(module (memory 0 1))
(module (memory 1 256))
(module (memory 0 65536))
(module (memory 0 0 shared))
(module (memory 1 2 shared))

(assert_invalid (module (memory 1 shared)) "shared memory must have maximum")

(assert_invalid (module (memory 0) (memory 0)) "multiple memories")
(assert_invalid (module (memory (import "spectest" "memory") 0) (memory 0)) "multiple memories")
Expand Down
28 changes: 28 additions & 0 deletions test/core/thread.wast
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
(module $Mem
(memory (export "shared") 1 1 shared)
)

(thread $T1 (shared (module $Mem))
(register "mem" $Mem)
(module
(memory (import "mem" "shared") 1 10 shared)
(func (export "run")
(i32.store (i32.const 0) (i32.const 42))
)
)
(invoke "run")
)

(thread $T2 (shared (module $Mem))
(register "mem" $Mem)
(module
(memory (import "mem" "shared") 1 1 shared)
(func (export "run") (result i32)
(i32.load (i32.const 0))
)
)
(assert_return (invoke "run") (either (i32.const 0) (i32.const 42)))
)

(wait $T1)
(wait $T2)
51 changes: 51 additions & 0 deletions test/js-api/memory/constructor.any.js
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,10 @@ test(() => {
assert_throws_js(RangeError, () => new WebAssembly.Memory({ "initial": 10, "maximum": 9 }));
}, "Initial value exceeds maximum");

test(() => {
assert_throws(new TypeError(), () => new WebAssembly.Memory({ "initial": 10, "shared": true }));
}, "Shared memory without maximum");

test(() => {
const proxy = new Proxy({}, {
has(o, x) {
Expand Down Expand Up @@ -120,6 +124,47 @@ test(() => {
]);
}, "Order of evaluation for descriptor");

test(t => {
const order = [];

new WebAssembly.Memory({
get maximum() {
order.push("maximum");
return {
valueOf() {
order.push("maximum valueOf");
return 1;
},
};
},

get initial() {
order.push("initial");
return {
valueOf() {
order.push("initial valueOf");
return 1;
},
};
},

get shared() {
order.push("shared");
return {
valueOf: t.unreached_func("should not call shared valueOf"),
};
},
});

assert_array_equals(order, [
"initial",
"initial valueOf",
"maximum",
"maximum valueOf",
"shared",
]);
}, "Order of evaluation for descriptor (with shared)");

test(() => {
const argument = { "initial": 0 };
const memory = new WebAssembly.Memory(argument);
Expand All @@ -137,3 +182,9 @@ test(() => {
const memory = new WebAssembly.Memory(argument, {});
assert_Memory(memory, { "size": 0 });
}, "Stray argument");

test(() => {
const argument = { "initial": 4, "maximum": 10, shared: true };
const memory = new WebAssembly.Memory(argument);
assert_Memory(memory, { "size": 4, "shared": true });
}, "Shared memory");
Loading