Skip to content

Commit f5f6174

Browse files
authored
Add wast parsing support for threads proposal (#1248)
* Add wast parsing support for threads proposal Add support for the new `(thread ...)` and `(wait ...)` constructs added in the upstream threads proposal. * Remove commented code
1 parent 2d8ea0a commit f5f6174

42 files changed

Lines changed: 1082 additions & 2 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

crates/wast/src/lib.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -529,6 +529,8 @@ pub mod kw {
529529
custom_keyword!(needed);
530530
custom_keyword!(export_info = "export-info");
531531
custom_keyword!(import_info = "import-info");
532+
custom_keyword!(thread);
533+
custom_keyword!(wait);
532534
}
533535

534536
/// Common annotations used to parse WebAssembly text files.

crates/wast/src/wast.rs

Lines changed: 56 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -102,6 +102,11 @@ pub enum WastDirective<'a> {
102102
span: Span,
103103
exec: WastExecute<'a>,
104104
},
105+
Thread(WastThread<'a>),
106+
Wait {
107+
span: Span,
108+
thread: Id<'a>,
109+
},
105110
}
106111

107112
impl WastDirective<'_> {
@@ -119,8 +124,10 @@ impl WastDirective<'_> {
119124
| WastDirective::AssertExhaustion { span, .. }
120125
| WastDirective::AssertUnlinkable { span, .. }
121126
| WastDirective::AssertInvalid { span, .. }
122-
| WastDirective::AssertException { span, .. } => *span,
127+
| WastDirective::AssertException { span, .. }
128+
| WastDirective::Wait { span, .. } => *span,
123129
WastDirective::Invoke(i) => i.span,
130+
WastDirective::Thread(t) => t.span,
124131
}
125132
}
126133
}
@@ -192,6 +199,14 @@ impl<'a> Parse<'a> for WastDirective<'a> {
192199
span,
193200
exec: parser.parens(|p| p.parse())?,
194201
})
202+
} else if l.peek::<kw::thread>()? {
203+
Ok(WastDirective::Thread(parser.parse()?))
204+
} else if l.peek::<kw::wait>()? {
205+
let span = parser.parse::<kw::wait>()?.0;
206+
Ok(WastDirective::Wait {
207+
span,
208+
thread: parser.parse()?,
209+
})
195210
} else {
196211
Err(l.error())
197212
}
@@ -363,3 +378,43 @@ impl<'a> Parse<'a> for WastRet<'a> {
363378
}
364379
}
365380
}
381+
382+
#[derive(Debug)]
383+
#[allow(missing_docs)]
384+
pub struct WastThread<'a> {
385+
pub span: Span,
386+
pub name: Id<'a>,
387+
pub shared_module: Option<Id<'a>>,
388+
pub directives: Vec<WastDirective<'a>>,
389+
}
390+
391+
impl<'a> Parse<'a> for WastThread<'a> {
392+
fn parse(parser: Parser<'a>) -> Result<Self> {
393+
parser.depth_check()?;
394+
let span = parser.parse::<kw::thread>()?.0;
395+
let name = parser.parse()?;
396+
397+
let shared_module = if parser.peek2::<kw::shared>()? {
398+
let name = parser.parens(|p| {
399+
p.parse::<kw::shared>()?;
400+
p.parens(|p| {
401+
p.parse::<kw::module>()?;
402+
p.parse()
403+
})
404+
})?;
405+
Some(name)
406+
} else {
407+
None
408+
};
409+
let mut directives = Vec::new();
410+
while !parser.is_empty() {
411+
directives.push(parser.parens(|p| p.parse())?);
412+
}
413+
Ok(WastThread {
414+
span,
415+
name,
416+
shared_module,
417+
directives,
418+
})
419+
}
420+
}
Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
(module $Mem
2+
(memory (export "shared") 1 1 shared)
3+
)
4+
5+
(thread $T1 (shared (module $Mem))
6+
(register "mem" $Mem)
7+
(module
8+
(memory (import "mem" "shared") 1 10 shared)
9+
(func (export "run")
10+
(local i32)
11+
(i32.load (i32.const 4))
12+
(local.set 0)
13+
(i32.store (i32.const 0) (i32.const 1))
14+
15+
;; store results for checking
16+
(i32.store (i32.const 24) (local.get 0))
17+
)
18+
)
19+
(invoke "run")
20+
)
21+
22+
(thread $T2 (shared (module $Mem))
23+
(register "mem" $Mem)
24+
(module
25+
(memory (import "mem" "shared") 1 1 shared)
26+
(func (export "run")
27+
(local i32)
28+
(i32.load (i32.const 0))
29+
(local.set 0)
30+
(i32.store (i32.const 4) (i32.const 1))
31+
32+
;; store results for checking
33+
(i32.store (i32.const 32) (local.get 0))
34+
)
35+
)
36+
37+
(invoke "run")
38+
)
39+
40+
(wait $T1)
41+
(wait $T2)
42+
43+
(module $Check
44+
(memory (import "mem" "shared") 1 1 shared)
45+
46+
(func (export "check") (result i32)
47+
(local i32 i32)
48+
(i32.load (i32.const 24))
49+
(local.set 0)
50+
(i32.load (i32.const 32))
51+
(local.set 1)
52+
53+
;; allowed results: (L_0 = 0 || L_0 = 1) && (L_1 = 0 || L_1 = 1)
54+
55+
(i32.or (i32.eq (local.get 0) (i32.const 1)) (i32.eq (local.get 0) (i32.const 0)))
56+
(i32.or (i32.eq (local.get 1) (i32.const 1)) (i32.eq (local.get 0) (i32.const 0)))
57+
(i32.and)
58+
(return)
59+
)
60+
)
61+
62+
(assert_return (invoke $Check "check") (i32.const 1))
Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
(module $Mem
2+
(memory (export "shared") 1 1 shared)
3+
)
4+
5+
(thread $T1 (shared (module $Mem))
6+
(register "mem" $Mem)
7+
(module
8+
(memory (import "mem" "shared") 1 10 shared)
9+
(func (export "run")
10+
(local i32)
11+
(i32.atomic.load (i32.const 4))
12+
(local.set 0)
13+
(i32.atomic.store (i32.const 0) (i32.const 1))
14+
15+
;; store results for checking
16+
(i32.store (i32.const 24) (local.get 0))
17+
)
18+
)
19+
(invoke "run")
20+
)
21+
22+
(thread $T2 (shared (module $Mem))
23+
(register "mem" $Mem)
24+
(module
25+
(memory (import "mem" "shared") 1 1 shared)
26+
(func (export "run")
27+
(local i32)
28+
(i32.atomic.load (i32.const 0))
29+
(local.set 0)
30+
(i32.atomic.store (i32.const 4) (i32.const 1))
31+
32+
;; store results for checking
33+
(i32.store (i32.const 32) (local.get 0))
34+
)
35+
)
36+
37+
(invoke "run")
38+
)
39+
40+
(wait $T1)
41+
(wait $T2)
42+
43+
(module $Check
44+
(memory (import "mem" "shared") 1 1 shared)
45+
46+
(func (export "check") (result i32)
47+
(local i32 i32)
48+
(i32.load (i32.const 24))
49+
(local.set 0)
50+
(i32.load (i32.const 32))
51+
(local.set 1)
52+
53+
;; allowed results: (L_0 = 0 && L_1 = 0) || (L_0 = 0 && L_1 = 1) || (L_0 = 1 && L_1 = 0)
54+
55+
(i32.and (i32.eq (local.get 0) (i32.const 0)) (i32.eq (local.get 1) (i32.const 0)))
56+
(i32.and (i32.eq (local.get 0) (i32.const 0)) (i32.eq (local.get 1) (i32.const 1)))
57+
(i32.and (i32.eq (local.get 0) (i32.const 1)) (i32.eq (local.get 1) (i32.const 0)))
58+
(i32.or)
59+
(i32.or)
60+
(return)
61+
)
62+
)
63+
64+
(assert_return (invoke $Check "check") (i32.const 1))
Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
(module $Mem
2+
(memory (export "shared") 1 1 shared)
3+
)
4+
5+
(thread $T1 (shared (module $Mem))
6+
(register "mem" $Mem)
7+
(module
8+
(memory (import "mem" "shared") 1 10 shared)
9+
(func (export "run")
10+
(i32.store (i32.const 0) (i32.const 42))
11+
(i32.store (i32.const 4) (i32.const 1))
12+
)
13+
)
14+
(invoke "run")
15+
)
16+
17+
(thread $T2 (shared (module $Mem))
18+
(register "mem" $Mem)
19+
(module
20+
(memory (import "mem" "shared") 1 1 shared)
21+
(func (export "run")
22+
(local i32 i32)
23+
(i32.load (i32.const 4))
24+
(local.set 0)
25+
(i32.load (i32.const 0))
26+
(local.set 1)
27+
28+
;; store results for checking
29+
(i32.store (i32.const 24) (local.get 0))
30+
(i32.store (i32.const 32) (local.get 1))
31+
)
32+
)
33+
34+
(invoke "run")
35+
)
36+
37+
(wait $T1)
38+
(wait $T2)
39+
40+
(module $Check
41+
(memory (import "mem" "shared") 1 1 shared)
42+
43+
(func (export "check") (result i32)
44+
(local i32 i32)
45+
(i32.load (i32.const 24))
46+
(local.set 0)
47+
(i32.load (i32.const 32))
48+
(local.set 1)
49+
50+
;; allowed results: (L_0 = 0 || L_0 = 1) && (L_1 = 0 || L_1 = 42)
51+
52+
(i32.or (i32.eq (local.get 0) (i32.const 1)) (i32.eq (local.get 0) (i32.const 0)))
53+
(i32.or (i32.eq (local.get 1) (i32.const 42)) (i32.eq (local.get 0) (i32.const 0)))
54+
(i32.and)
55+
(return)
56+
)
57+
)
58+
59+
(assert_return (invoke $Check "check") (i32.const 1))
Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
(module $Mem
2+
(memory (export "shared") 1 1 shared)
3+
)
4+
5+
(thread $T1 (shared (module $Mem))
6+
(register "mem" $Mem)
7+
(module
8+
(memory (import "mem" "shared") 1 10 shared)
9+
(func (export "run")
10+
(i32.atomic.store (i32.const 0) (i32.const 42))
11+
(i32.atomic.store (i32.const 4) (i32.const 1))
12+
)
13+
)
14+
(invoke "run")
15+
)
16+
17+
(thread $T2 (shared (module $Mem))
18+
(register "mem" $Mem)
19+
(module
20+
(memory (import "mem" "shared") 1 1 shared)
21+
(func (export "run")
22+
(local i32 i32)
23+
(i32.atomic.load (i32.const 4))
24+
(local.set 0)
25+
(i32.atomic.load (i32.const 0))
26+
(local.set 1)
27+
28+
;; store results for checking
29+
(i32.store (i32.const 24) (local.get 0))
30+
(i32.store (i32.const 32) (local.get 1))
31+
)
32+
)
33+
34+
(invoke "run")
35+
)
36+
37+
(wait $T1)
38+
(wait $T2)
39+
40+
(module $Check
41+
(memory (import "mem" "shared") 1 1 shared)
42+
43+
(func (export "check") (result i32)
44+
(local i32 i32)
45+
(i32.load (i32.const 24))
46+
(local.set 0)
47+
(i32.load (i32.const 32))
48+
(local.set 1)
49+
50+
;; allowed results: (L_0 = 1 && L_1 = 42) || (L_0 = 0 && L_1 = 0) || (L_0 = 0 && L_1 = 42)
51+
52+
(i32.and (i32.eq (local.get 0) (i32.const 1)) (i32.eq (local.get 1) (i32.const 42)))
53+
(i32.and (i32.eq (local.get 0) (i32.const 0)) (i32.eq (local.get 1) (i32.const 0)))
54+
(i32.and (i32.eq (local.get 0) (i32.const 0)) (i32.eq (local.get 1) (i32.const 42)))
55+
(i32.or)
56+
(i32.or)
57+
(return)
58+
)
59+
)
60+
61+
(assert_return (invoke $Check "check") (i32.const 1))

0 commit comments

Comments
 (0)