Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

Commit 3537229

Browse filesBrowse files
committed
implement atomic.fence, add wait/notify edge case tests
1 parent 7fb4187 commit 3537229
Copy full SHA for 3537229

File tree

10 files changed

+82
-2
lines changed
Filter options

10 files changed

+82
-2
lines changed

‎interpreter/binary/decode.ml

Copy file name to clipboardExpand all lines: interpreter/binary/decode.ml
+1Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -466,6 +466,7 @@ let rec instr s =
466466
| 0x00 -> let a, o = memop s in memory_atomic_notify a o
467467
| 0x01 -> let a, o = memop s in memory_atomic_wait32 a o
468468
| 0x02 -> let a, o = memop s in memory_atomic_wait64 a o
469+
| 0x03 -> expect 0x00 s "zero flag expected"; atomic_fence
469470

470471
| 0x10 -> let a, o = memop s in i32_atomic_load a o
471472
| 0x11 -> let a, o = memop s in i64_atomic_load a o

‎interpreter/binary/encode.ml

Copy file name to clipboardExpand all lines: interpreter/binary/encode.ml
+3Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -221,6 +221,9 @@ let encode m =
221221
assert false
222222
| MemoryAtomicWait {ty = F32Type | F64Type; _} -> assert false
223223

224+
| AtomicFence ->
225+
op 0xfe; op 0x03; op 0x00
226+
224227
| AtomicLoad ({ty = I32Type; sz = None; _} as mo) ->
225228
op 0xfe; op 0x10; memop mo
226229
| AtomicLoad ({ty = I64Type; sz = None; _} as mo) ->

‎interpreter/exec/eval.ml

Copy file name to clipboardExpand all lines: interpreter/exec/eval.ml
+15-1Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -132,6 +132,10 @@ let check_align addr ty sz at =
132132
if not (Memory.is_aligned addr ty sz) then
133133
Trap.error at "unaligned atomic memory access"
134134

135+
let check_shared mem at =
136+
if (shared_memory_type (Memory.type_of mem)) != Shared then
137+
Trap.error at "expected shared memory"
138+
135139

136140
(* Evaluation *)
137141

@@ -319,18 +323,28 @@ let rec step_thread (t : thread) : thread =
319323
(try
320324
assert (sz = None);
321325
check_align addr ty sz e.at;
326+
check_shared mem e.at;
322327
let v = Memory.load_value mem addr offset ty in
323328
if v = ve then
324329
assert false (* TODO *)
325330
else
326331
I32 1l :: vs', [] (* Not equal *)
327332
with exn -> vs', [Trapping (memory_error e.at exn) @@ e.at])
328333

329-
| MemoryAtomicNotify x, I32 count :: I32 i :: vs' ->
334+
| MemoryAtomicNotify {offset; ty; sz; _}, I32 count :: I32 i :: vs' ->
335+
let mem = memory frame.inst (0l @@ e.at) in
336+
let addr = I64_convert.extend_i32_u i in
337+
(try
338+
check_align addr ty sz e.at;
339+
let _ = Memory.load_value mem addr offset ty in
330340
if count = 0l then
331341
I32 0l :: vs', [] (* Trivial case waking 0 waiters *)
332342
else
333343
assert false (* TODO *)
344+
with exn -> vs', [Trapping (memory_error e.at exn) @@ e.at])
345+
346+
| AtomicFence, vs ->
347+
vs, []
334348

335349
| MemorySize, vs ->
336350
let mem = memory frame.inst (0l @@ e.at) in

‎interpreter/syntax/ast.ml

Copy file name to clipboardExpand all lines: interpreter/syntax/ast.ml
+1Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -106,6 +106,7 @@ and instr' =
106106
| Convert of cvtop (* conversion *)
107107
| MemoryAtomicWait of atomicop (* atomically wait for notification at address *)
108108
| MemoryAtomicNotify of atomicop (* atomically notify all waiters at address *)
109+
| AtomicFence (* perform an atomic fence *)
109110
| AtomicLoad of atomicop (* atomically read memory at address *)
110111
| AtomicStore of atomicop (* atomically write memory at address *)
111112
| AtomicRmw of rmwop * atomicop (* atomically read, modify, write memory at address *)

‎interpreter/syntax/operators.ml

Copy file name to clipboardExpand all lines: interpreter/syntax/operators.ml
+3Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,9 @@ let memory_atomic_wait32 align offset =
7878
let memory_atomic_wait64 align offset =
7979
MemoryAtomicWait {ty = I64Type; align; offset; sz = None}
8080

81+
let atomic_fence =
82+
AtomicFence
83+
8184
let i32_atomic_load align offset =
8285
AtomicLoad {ty = I32Type; align; offset; sz = None}
8386
let i64_atomic_load align offset =

‎interpreter/text/arrange.ml

Copy file name to clipboardExpand all lines: interpreter/text/arrange.ml
+1Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -311,6 +311,7 @@ let rec instr e =
311311
| Convert op -> cvtop op, []
312312
| MemoryAtomicWait op -> memoryatomicwaitop op, []
313313
| MemoryAtomicNotify op -> memoryatomicnotifyop op, []
314+
| AtomicFence -> "atomic.fence", []
314315
| AtomicLoad op -> atomicloadop op, []
315316
| AtomicStore op -> atomicstoreop op, []
316317
| AtomicRmw (rmwop, op) -> atomicrmwop op rmwop, []

‎interpreter/text/lexer.mll

Copy file name to clipboardExpand all lines: interpreter/text/lexer.mll
+1Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -259,6 +259,7 @@ rule token = parse
259259
intop ("i" ^ sz)
260260
(memory_atomic_wait32 (opt a 2))
261261
(memory_atomic_wait64 (opt a 3)) o) }
262+
| "atomic.fence" { ATOMIC_FENCE }
262263
| (ixx as t)".atomic.load"
263264
{ ATOMIC_LOAD (fun a o ->
264265
intop t (i32_atomic_load (opt a 2)) (i64_atomic_load (opt a 3)) o) }

‎interpreter/text/parser.mly

Copy file name to clipboardExpand all lines: interpreter/text/parser.mly
+2-1Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -169,7 +169,7 @@ let inline_type_explicit (c : context) x ft at =
169169
%token CALL CALL_INDIRECT RETURN
170170
%token LOCAL_GET LOCAL_SET LOCAL_TEE GLOBAL_GET GLOBAL_SET
171171
%token LOAD STORE OFFSET_EQ_NAT ALIGN_EQ_NAT
172-
%token MEMORY_ATOMIC_WAIT MEMORY_ATOMIC_NOTIFY
172+
%token MEMORY_ATOMIC_WAIT MEMORY_ATOMIC_NOTIFY ATOMIC_FENCE
173173
%token ATOMIC_LOAD ATOMIC_STORE ATOMIC_RMW ATOMIC_RMW_CMPXCHG
174174
%token CONST UNARY BINARY TEST COMPARE CONVERT
175175
%token UNREACHABLE MEMORY_SIZE MEMORY_GROW
@@ -358,6 +358,7 @@ plain_instr :
358358
| CONVERT { fun c -> $1 }
359359
| MEMORY_ATOMIC_WAIT offset_opt align_opt { fun c -> $1 $3 $2 }
360360
| MEMORY_ATOMIC_NOTIFY offset_opt align_opt { fun c -> $1 $3 $2 }
361+
| ATOMIC_FENCE { fun c -> atomic_fence }
361362
| ATOMIC_LOAD offset_opt align_opt { fun c -> $1 $3 $2 }
362363
| ATOMIC_STORE offset_opt align_opt { fun c -> $1 $3 $2 }
363364
| ATOMIC_RMW offset_opt align_opt { fun c -> $1 $3 $2 }

‎interpreter/valid/valid.ml

Copy file name to clipboardExpand all lines: interpreter/valid/valid.ml
+3Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -308,6 +308,9 @@ let rec check_instr (c : context) (e : instr) (s : infer_stack_type) : op_type =
308308
check_memop c memop (fun sz -> sz) e.at;
309309
[I32Type; memop.ty; I64Type] --> [I32Type]
310310

311+
| AtomicFence ->
312+
[] --> []
313+
311314
| AtomicLoad memop ->
312315
check_memop c memop (fun sz -> sz) e.at;
313316
[I32Type] --> [memop.ty]

‎test/core/atomic.wast

Copy file name to clipboardExpand all lines: test/core/atomic.wast
+52Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -417,6 +417,7 @@
417417
(assert_trap (invoke "i64.atomic.rmw16.cmpxchg_u" (i32.const 1) (i64.const 0) (i64.const 0)) "unaligned atomic")
418418
(assert_trap (invoke "i64.atomic.rmw32.cmpxchg_u" (i32.const 1) (i64.const 0) (i64.const 0)) "unaligned atomic")
419419

420+
;; wait/notify
420421
(module
421422
(memory 1 1 shared)
422423

@@ -431,10 +432,54 @@
431432
)
432433

433434
(invoke "init" (i64.const 0xffffffffffff))
435+
436+
;; wait returns immediately if values do not match
434437
(assert_return (invoke "memory.atomic.wait32" (i32.const 0) (i32.const 0) (i64.const 0)) (i32.const 1))
435438
(assert_return (invoke "memory.atomic.wait64" (i32.const 0) (i64.const 0) (i64.const 0)) (i32.const 1))
439+
440+
;; notify always returns
441+
(assert_return (invoke "memory.atomic.notify" (i32.const 0) (i32.const 0)) (i32.const 0))
442+
443+
;; OOB wait and notify always trap
444+
(assert_trap (invoke "memory.atomic.wait32" (i32.const 65536) (i32.const 0) (i64.const 0)) "out of bounds memory access")
445+
(assert_trap (invoke "memory.atomic.wait64" (i32.const 65536) (i64.const 0) (i64.const 0)) "out of bounds memory access")
446+
447+
;; in particular, notify always traps even if waking 0 threads
448+
(assert_trap (invoke "memory.atomic.notify" (i32.const 65536) (i32.const 0)) "out of bounds memory access")
449+
450+
;; similarly, unaligned wait and notify always trap
451+
(assert_trap (invoke "memory.atomic.wait32" (i32.const 65531) (i32.const 0) (i64.const 0)) "unaligned atomic")
452+
(assert_trap (invoke "memory.atomic.wait64" (i32.const 65524) (i64.const 0) (i64.const 0)) "unaligned atomic")
453+
454+
(assert_trap (invoke "memory.atomic.notify" (i32.const 65531) (i32.const 0)) "unaligned atomic")
455+
456+
;; atomic.wait traps on unshared memory even if it wouldn't block
457+
(module
458+
(memory 1 1)
459+
460+
(func (export "init") (param $value i64) (i64.store (i32.const 0) (local.get $value)))
461+
462+
(func (export "memory.atomic.notify") (param $addr i32) (param $count i32) (result i32)
463+
(memory.atomic.notify (local.get 0) (local.get 1)))
464+
(func (export "memory.atomic.wait32") (param $addr i32) (param $expected i32) (param $timeout i64) (result i32)
465+
(memory.atomic.wait32 (local.get 0) (local.get 1) (local.get 2)))
466+
(func (export "memory.atomic.wait64") (param $addr i32) (param $expected i64) (param $timeout i64) (result i32)
467+
(memory.atomic.wait64 (local.get 0) (local.get 1) (local.get 2)))
468+
)
469+
470+
(invoke "init" (i64.const 0xffffffffffff))
471+
472+
(assert_trap (invoke "memory.atomic.wait32" (i32.const 0) (i32.const 0) (i64.const 0)) "expected shared memory")
473+
(assert_trap (invoke "memory.atomic.wait64" (i32.const 0) (i64.const 0) (i64.const 0)) "expected shared memory")
474+
475+
;; notify still works
436476
(assert_return (invoke "memory.atomic.notify" (i32.const 0) (i32.const 0)) (i32.const 0))
437477

478+
;; OOB and unaligned notify still trap
479+
(assert_trap (invoke "memory.atomic.notify" (i32.const 65536) (i32.const 0)) "out of bounds memory access")
480+
(assert_trap (invoke "memory.atomic.notify" (i32.const 65531) (i32.const 0)) "unaligned atomic")
481+
482+
438483
;; unshared memory is OK
439484
(module
440485
(memory 1 1)
@@ -488,6 +533,13 @@
488533
(func (drop (i64.atomic.rmw32.cmpxchg_u (i32.const 0) (i64.const 0) (i64.const 0))))
489534
)
490535

536+
;; atomic.fence: no memory is ok
537+
(module
538+
(func (export "fence") (atomic.fence))
539+
)
540+
541+
(assert_return (invoke "fence"))
542+
491543
;; Fails with no memory
492544
(assert_invalid (module (func (drop (memory.atomic.notify (i32.const 0) (i32.const 0))))) "unknown memory")
493545
(assert_invalid (module (func (drop (memory.atomic.wait32 (i32.const 0) (i32.const 0) (i64.const 0))))) "unknown memory")

0 commit comments

Comments
0 (0)
Morty Proxy This is a proxified and sanitized view of the page, visit original site.