Skip to content

Commit c818a19

Browse files
authored
Add some test/async/ WASTs (#761)
1 parent 01e5463 commit c818a19

3 files changed

Lines changed: 471 additions & 0 deletions

File tree

Lines changed: 158 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,158 @@
1+
;; A destructor called by `resource.drop` runs on a fresh thread, so its
2+
;; `context.get` is always zero on entry, even when the destructor is
3+
;; reentered recursively or another thread of its instance is blocked.
4+
5+
;; The destructor recursively reenters itself via donut wrapping
6+
(component
7+
(core module $Indirect
8+
(table (export "tbl") 1 funcref)
9+
(func (export "dtor") (param i32)
10+
(call_indirect (param i32) (local.get 0) (i32.const 0))))
11+
(core instance $indirect (instantiate $Indirect))
12+
(type $R (resource (rep i32) (dtor (core func $indirect "dtor"))))
13+
(canon resource.new $R (core func $resource.new))
14+
(canon context.get i32 0 (core func $context.get))
15+
(canon context.set i32 0 (core func $context.set))
16+
17+
(component $C
18+
(import "r" (type $R (sub resource)))
19+
(canon resource.drop $R (core func $resource.drop))
20+
(func (export "drop") (param "r" (own $R)) (canon lift (core func $resource.drop))))
21+
(instance $c (instantiate $C (with "r" (type $R))))
22+
(canon lower (func $c "drop") (core func $drop))
23+
24+
(core module $M
25+
(import "" "tbl" (table 1 funcref))
26+
(import "" "resource.new" (func $resource.new (param i32) (result i32)))
27+
(import "" "drop" (func $drop (param i32)))
28+
(import "" "context.get" (func $context.get (result i32)))
29+
(import "" "context.set" (func $context.set (param i32)))
30+
;; dtor(n) sets its context to n+1, then (if n > 0) has $C drop a new
31+
;; resource with rep n-1, which calls back into dtor(n-1)
32+
(func $dtor (param $n i32)
33+
(if (call $context.get) (then unreachable))
34+
(call $context.set (i32.add (local.get $n) (i32.const 1)))
35+
(if (local.get $n) (then
36+
(call $drop (call $resource.new (i32.sub (local.get $n) (i32.const 1))))))
37+
(if (i32.ne (call $context.get) (i32.add (local.get $n) (i32.const 1)))
38+
(then unreachable)))
39+
(elem (i32.const 0) $dtor)
40+
(func (export "run") (param $n i32)
41+
(call $context.set (i32.const 100))
42+
(call $drop (call $resource.new (local.get $n)))
43+
(if (i32.ne (call $context.get) (i32.const 100)) (then unreachable)))
44+
)
45+
(core instance $m (instantiate $M (with "" (instance
46+
(export "tbl" (table $indirect "tbl"))
47+
(export "resource.new" (func $resource.new))
48+
(export "drop" (func $drop))
49+
(export "context.get" (func $context.get))
50+
(export "context.set" (func $context.set))))))
51+
(func (export "run") (param "n" u32) (canon lift (core func $m "run")))
52+
)
53+
(assert_return (invoke "run" (u32.const 3)))
54+
55+
;; The destructor is called while another thread of its instance is blocked
56+
;; inside an async callback, holding the instance's exclusive lock
57+
(component
58+
(component $P
59+
(core module $Memory (memory (export "mem") 1))
60+
(core instance $memory (instantiate $Memory))
61+
(type $FT (future))
62+
(canon context.get i32 0 (core func $context.get))
63+
(canon context.set i32 0 (core func $context.set))
64+
(canon future.read $FT (memory (core memory $memory "mem")) (core func $future.read))
65+
(canon task.return (core func $task.return))
66+
(core module $M
67+
(import "" "context.get" (func $context.get (result i32)))
68+
(import "" "context.set" (func $context.set (param i32)))
69+
(import "" "future.read" (func $future.read (param i32 i32) (result i32)))
70+
(import "" "task.return" (func $task.return))
71+
(func (export "dtor") (param i32)
72+
(if (call $context.get) (then unreachable))
73+
(call $context.set (i32.const 2)))
74+
;; blocks (holding the exclusive lock) until the caller writes $fut
75+
(func (export "hold") (param $fut i32) (result i32)
76+
(call $context.set (i32.const 1))
77+
(if (call $future.read (local.get $fut) (i32.const 0)) (then unreachable))
78+
(if (i32.ne (call $context.get) (i32.const 1)) (then unreachable))
79+
(call $task.return)
80+
(i32.const 0 (; EXIT ;)))
81+
(func (export "cb") (param i32 i32 i32) (result i32) unreachable)
82+
)
83+
(core instance $m (instantiate $M (with "" (instance
84+
(export "context.get" (func $context.get))
85+
(export "context.set" (func $context.set))
86+
(export "future.read" (func $future.read))
87+
(export "task.return" (func $task.return))))))
88+
(type $R (resource (rep i32) (dtor (core func $m "dtor"))))
89+
(export $R' "r" (type $R))
90+
(canon resource.new $R (core func $resource.new))
91+
(func (export "make") (param "rep" u32) (result (own $R'))
92+
(canon lift (core func $resource.new)))
93+
(func (export "hold") async (param "fut" $FT)
94+
(canon lift (core func $m "hold") async (callback (core func $m "cb"))))
95+
)
96+
97+
(component $D
98+
(import "r" (type $R (sub resource)))
99+
(type $FT (future))
100+
(import "make" (func $make (param "rep" u32) (result (own $R))))
101+
(import "hold" (func $hold async (param "fut" $FT)))
102+
(core module $Memory (memory (export "mem") 1))
103+
(core instance $memory (instantiate $Memory))
104+
(canon lower (func $make) (core func $make))
105+
(canon lower (func $hold) async (core func $hold))
106+
(canon resource.drop $R (core func $resource.drop))
107+
(canon future.new $FT (core func $future.new))
108+
(canon future.write $FT (memory (core memory $memory "mem")) (core func $future.write))
109+
(canon waitable-set.new (core func $waitable-set.new))
110+
(canon waitable.join (core func $waitable.join))
111+
(canon waitable-set.wait (memory (core memory $memory "mem")) (core func $waitable-set.wait))
112+
(core module $M
113+
(import "" "make" (func $make (param i32) (result i32)))
114+
(import "" "hold" (func $hold (param i32) (result i32)))
115+
(import "" "resource.drop" (func $resource.drop (param i32)))
116+
(import "" "future.new" (func $future.new (result i64)))
117+
(import "" "future.write" (func $future.write (param i32 i32) (result i32)))
118+
(import "" "waitable-set.new" (func $waitable-set.new (result i32)))
119+
(import "" "waitable.join" (func $waitable.join (param i32 i32)))
120+
(import "" "waitable-set.wait" (func $waitable-set.wait (param i32 i32) (result i32)))
121+
(func (export "run") (result i32)
122+
(local $r i32) (local $fut i64) (local $ret i32) (local $ws i32)
123+
(local.set $r (call $make (i32.const 0)))
124+
(local.set $fut (call $future.new))
125+
(local.set $ret (call $hold (i32.wrap_i64 (local.get $fut))))
126+
(if (i32.ne (i32.and (local.get $ret) (i32.const 0xf)) (i32.const 1 (; STARTED ;)))
127+
(then unreachable))
128+
;; "hold" is now blocked, so this dtor call overlaps it
129+
(call $resource.drop (local.get $r))
130+
;; unblock "hold" and wait for it to finish its checks
131+
(if (call $future.write (i32.wrap_i64 (i64.shr_u (local.get $fut) (i64.const 32))) (i32.const 0))
132+
(then unreachable))
133+
(local.set $ws (call $waitable-set.new))
134+
(call $waitable.join (i32.shr_u (local.get $ret) (i32.const 4)) (local.get $ws))
135+
(if (i32.ne (call $waitable-set.wait (local.get $ws) (i32.const 0)) (i32.const 1 (; SUBTASK ;)))
136+
(then unreachable))
137+
(i32.const 42))
138+
)
139+
(core instance $m (instantiate $M (with "" (instance
140+
(export "make" (func $make))
141+
(export "hold" (func $hold))
142+
(export "resource.drop" (func $resource.drop))
143+
(export "future.new" (func $future.new))
144+
(export "future.write" (func $future.write))
145+
(export "waitable-set.new" (func $waitable-set.new))
146+
(export "waitable.join" (func $waitable.join))
147+
(export "waitable-set.wait" (func $waitable-set.wait))))))
148+
(func (export "run") async (result u32) (canon lift (core func $m "run")))
149+
)
150+
151+
(instance $p (instantiate $P))
152+
(instance $d (instantiate $D
153+
(with "r" (type $p "r"))
154+
(with "make" (func $p "make"))
155+
(with "hold" (func $p "hold"))))
156+
(func (export "run") (alias export $d "run"))
157+
)
158+
(assert_return (invoke "run") (u32.const 42))

0 commit comments

Comments
 (0)