Skip to content

Commit 7c5b3c0

Browse files
keithwalexcrichton
andauthored
wasmprinter: add option to print instructions in folded form (#1790)
* Annotate for_each_operator entries with arity; check in validator Co-authored-by: Alex Crichton <[email protected]> * wasmprinter: add support to print in folded form Co-authored-by: Alex Crichton <[email protected]> --------- Co-authored-by: Alex Crichton <[email protected]>
1 parent c6c6792 commit 7c5b3c0

File tree

169 files changed

+15588
-784
lines changed

Some content is hidden

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

169 files changed

+15588
-784
lines changed

crates/wasm-encoder/src/reencode.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1538,7 +1538,7 @@ pub mod utils {
15381538
use crate::Instruction;
15391539

15401540
macro_rules! translate {
1541-
($( @$proposal:ident $op:ident $({ $($arg:ident: $argty:ty),* })? => $visit:ident)*) => {
1541+
($( @$proposal:ident $op:ident $({ $($arg:ident: $argty:ty),* })? => $visit:ident ($($ann:tt)*))*) => {
15421542
Ok(match arg {
15431543
$(
15441544
wasmparser::Operator::$op $({ $($arg),* })? => {

crates/wasmparser/benches/benchmark.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -326,7 +326,7 @@ criterion_main!(benchmark);
326326
struct NopVisit;
327327

328328
macro_rules! define_visit_operator {
329-
($(@$proposal:ident $op:ident $({ $($arg:ident: $argty:ty),* })? => $visit:ident)*) => {
329+
($(@$proposal:ident $op:ident $({ $($arg:ident: $argty:ty),* })? => $visit:ident ($($ann:tt)*))*) => {
330330
$(
331331
fn $visit(&mut self $($(,$arg: $argty)*)?) {
332332
define_visit_operator!(@visit $op $( $($arg)* )?);

crates/wasmparser/src/arity.rs

Lines changed: 258 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,258 @@
1+
/* Copyright 2024 Mozilla Foundation
2+
*
3+
* Licensed under the Apache License, Version 2.0 (the "License");
4+
* you may not use this file except in compliance with the License.
5+
* You may obtain a copy of the License at
6+
*
7+
* http://www.apache.org/licenses/LICENSE-2.0
8+
*
9+
* Unless required by applicable law or agreed to in writing, software
10+
* distributed under the License is distributed on an "AS IS" BASIS,
11+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
* See the License for the specific language governing permissions and
13+
* limitations under the License.
14+
*/
15+
16+
use crate::{
17+
BinaryReader, BinaryReaderError, BlockType, CompositeInnerType, ContType, FrameKind, FuncType,
18+
Operator, RefType, Result, SubType,
19+
};
20+
21+
/// To compute the arity (param and result counts) of "variable-arity"
22+
/// operators, the operator_arity macro needs information about the
23+
/// module's types and the current control stack. The ModuleArity
24+
/// trait exposes this information.
25+
pub trait ModuleArity {
26+
/// Type with given index
27+
fn sub_type_at(&self, type_idx: u32) -> Option<&SubType>;
28+
29+
/// Arity (param and result counts) of tag with given index
30+
fn tag_type_arity(&self, at: u32) -> Option<(u32, u32)>;
31+
32+
/// Type index of function with given index
33+
fn type_index_of_function(&self, function_idx: u32) -> Option<u32>;
34+
35+
/// Function type for a given continuation type
36+
fn func_type_of_cont_type(&self, c: &ContType) -> Option<&FuncType>;
37+
38+
/// Sub type for a given reference type
39+
fn sub_type_of_ref_type(&self, rt: &RefType) -> Option<&SubType>;
40+
41+
/// Current height of control stack
42+
fn control_stack_height(&self) -> u32;
43+
44+
/// BlockType and FrameKind of label with given index
45+
fn label_block(&self, depth: u32) -> Option<(BlockType, FrameKind)>;
46+
47+
/// Computes arity of given SubType
48+
fn sub_type_arity(&self, t: &SubType) -> Option<(u32, u32)> {
49+
match &t.composite_type.inner {
50+
CompositeInnerType::Func(f) => {
51+
Some((f.params().len() as u32, f.results().len() as u32))
52+
}
53+
CompositeInnerType::Struct(s) => Some((s.fields.len() as u32, s.fields.len() as u32)),
54+
CompositeInnerType::Array(_) => None,
55+
CompositeInnerType::Cont(c) => {
56+
let f = self.func_type_of_cont_type(c)?;
57+
Some((f.params().len() as u32, f.results().len() as u32))
58+
}
59+
}
60+
}
61+
62+
/// Computes arity of given BlockType
63+
fn block_type_arity(&self, ty: BlockType) -> Option<(u32, u32)> {
64+
match ty {
65+
BlockType::Empty => Some((0, 0)),
66+
BlockType::Type(_) => Some((0, 1)),
67+
BlockType::FuncType(t) => self.sub_type_arity(self.sub_type_at(t)?),
68+
}
69+
}
70+
}
71+
72+
impl BinaryReader<'_> {
73+
/// Read the next operator and compute its arity (param and result counts)
74+
pub fn operator_arity(&self, module: &impl ModuleArity) -> Result<(u32, u32)> {
75+
self.clone()
76+
.read_operator()?
77+
.operator_arity(module)
78+
.ok_or_else(|| {
79+
BinaryReaderError::new("operator arity is unknown", self.original_position())
80+
})
81+
}
82+
}
83+
84+
/// The operator_arity macro interprets the annotations in the for_each_operator macro
85+
/// to compute the arity of each operator. It needs access to a ModuleArity implementation.
86+
macro_rules! operator_arity {
87+
(arity $self:ident $({ $($arg:ident: $argty:ty),* })? arity $($ann:tt)*) => {
88+
{
89+
let params = (|| -> Option<(i32, i32)> { operator_arity!(params $self { $($($arg: $argty),*)? } $($ann)*) })();
90+
let results = (|| -> Option<(i32, i32)> { operator_arity!(results $self { $($($arg: $argty),*)? } $($ann)*) })();
91+
match (params, results) {
92+
(Some((a,_)), Some((_,d))) if a >= 0 && d >= 0 => (Some((a as u32, d as u32))),
93+
_ => None,
94+
}
95+
}
96+
};
97+
98+
(arity $self:ident $({ $($arg:ident: $argty:ty),* })? $cat:ident $($ann:tt)*) => {
99+
Some(operator_arity!(fixed $cat $($ann)*))
100+
};
101+
102+
(params $self:ident { $($arg:ident: $argty:ty),* } ~ $cat:ident $($tokens:tt)*) => { { let (a, b) = operator_arity!(count $self { $($arg: $argty),* } $cat)?;
103+
let (c, d) = operator_arity!(params $self { $($arg: $argty),* } $($tokens)*)?;
104+
Some((b as i32 + c as i32, a as i32 + d as i32)) } };
105+
(params $self:ident { $($arg:ident: $argty:ty),* } $val:literal $($tokens:tt)*) => { { let rest = operator_arity!(params $self { $($arg: $argty),* } $($tokens)*)?;
106+
Some(($val + rest.0, $val + rest.1)) } };
107+
(params $self:ident { $($arg:ident: $argty:ty),* } $cat:ident $($tokens:tt)*) => { { let (a, b) = operator_arity!(count $self { $($arg: $argty),* } $cat)?;
108+
let (c, d) = operator_arity!(params $self { $($arg: $argty),* } $($tokens)*)?;
109+
Some((a as i32 + c as i32, b as i32 + d as i32)) } };
110+
(params $self:ident { $($arg:ident: $argty:ty),* } -> $($tokens:tt)*) => { Some((0, 0)) };
111+
(params $self:ident { $($arg:ident: $argty:ty),* }) => { Some((0, 0)) };
112+
113+
(results $self:ident { $($arg:ident: $argty:ty),* } ~ $($tokens:tt)*) => { operator_arity!(results $self { $($arg: $argty),* } $($tokens)*) };
114+
(results $self:ident { $($arg:ident: $argty:ty),* } $val:literal $($tokens:tt)*) => { operator_arity!(results $self { $($arg: $argty),* } $($tokens)*) };
115+
(results $self:ident { $($arg:ident: $argty:ty),* } $cat:ident $($tokens:tt)*) => { operator_arity!(results $self { $($arg: $argty),* } $($tokens)*) };
116+
(results $self:ident { $($arg:ident: $argty:ty),* } -> $($tokens:tt)*) => { operator_arity!(params $self { $($arg: $argty),* } $($tokens)*) };
117+
118+
(count $self:ident { $tag_index:ident: $_:ty } tag) => {{
119+
operator_arity!(tag_index $tag_index);
120+
$self.tag_type_arity($tag_index)
121+
}};
122+
123+
(count $self:ident { $_1:ident: $_2:ty, $tag_index:ident: $($_3:tt)* } tag) => { operator_arity!(count $self { $tag_index: _ } tag) };
124+
125+
(count $self:ident { $func_index:ident: $_:ty } func) => {{
126+
operator_arity!(func_index $func_index);
127+
$self.sub_type_arity($self.sub_type_at($self.type_index_of_function($func_index)?)?)
128+
}};
129+
130+
(count $self:ident { $type_index:ident: $($_:tt)* } type) => {{
131+
operator_arity!(type_index $type_index);
132+
$self.sub_type_arity($self.sub_type_at($type_index)?)
133+
}};
134+
135+
(count $self:ident { $type_index:ident: $($_:tt)* } switch) => {{
136+
operator_arity!(type_index $type_index);
137+
let st = &$self.sub_type_at($type_index)?.composite_type.inner;
138+
if let CompositeInnerType::Cont(ct) = &st {
139+
let last_param = $self.func_type_of_cont_type(ct)?.params().last()?;
140+
$self.sub_type_arity($self.sub_type_of_ref_type(&last_param.as_reference_type()?)?)
141+
} else {
142+
None
143+
}
144+
}};
145+
146+
(count $self:ident { $type1_index:ident: $t1:ty, $type2_index:ident: $t2:ty } type_diff) => {{
147+
operator_arity!(type_index $type1_index);
148+
operator_arity!(type_index $type2_index);
149+
let a = $self.sub_type_arity($self.sub_type_at($type1_index)?)?;
150+
let b = $self.sub_type_arity($self.sub_type_at($type2_index)?)?;
151+
Some((a.0.checked_sub(b.0)?, a.1.checked_sub(b.1)?))
152+
}};
153+
154+
(count $self:ident { $arg1:ident: $argty:ty, $size:ident: $sizety:ty } size) => {{
155+
operator_arity!(size_value $size);
156+
Some(($size, $size))
157+
}};
158+
159+
(count $self:ident { $depth:ident: $($_:tt)* } br) => {{
160+
operator_arity!(depth $depth);
161+
let (ty, kind) = $self.label_block($depth)?;
162+
let (params, results) = $self.block_type_arity(ty)?;
163+
let n = match kind {
164+
FrameKind::Loop => params,
165+
_ => results,
166+
};
167+
Some((n, n))
168+
}};
169+
170+
(count $self:ident { $($_:ident: $__:ty),* } ret) => {{
171+
let (ty, _) = $self.control_stack_height().checked_sub(1)
172+
.and_then(|x| $self.label_block(x))?;
173+
$self.block_type_arity(ty)
174+
}};
175+
176+
(count $self:ident { $blockty:ident: $($_:tt)* } block) => {{
177+
operator_arity!(blockty $blockty);
178+
$self.block_type_arity($blockty)
179+
}};
180+
181+
(count $self:ident {} implicit_else) => {{
182+
let (ty, kind) = $self.label_block(0)?;
183+
let (params, results) = $self.block_type_arity(ty)?;
184+
Some(match kind {
185+
FrameKind::If => (results, params),
186+
_ => (0, 0),
187+
})
188+
}};
189+
190+
(count $self:ident { $($_: ident: $__:ty),* } end) => {{
191+
let (ty, _) = $self.label_block(0)?;
192+
$self.block_type_arity(ty)
193+
}};
194+
195+
(count $self:ident { $try_table:ident: $($_:tt)* } try_table) => {{
196+
operator_arity!(try_table $try_table);
197+
$self.block_type_arity($try_table.ty)
198+
}};
199+
200+
(count $self:ident { $br_table:ident: $($_:tt)* } br_table) => {{
201+
operator_arity!(br_table $br_table);
202+
let relative_depth: u32 = $br_table.default();
203+
operator_arity!(count $self { relative_depth: u32 } br)
204+
}};
205+
206+
(tag_index tag_index $($_:tt)*) => {};
207+
(func_index function_index $($_:tt)*) => {};
208+
(type_index type_index $($_:tt)*) => {};
209+
(type_index struct_type_index $($_:tt)*) => {};
210+
(type_index argument_index $($_:tt)*) => {};
211+
(type_index result_index $($_:tt)*) => {};
212+
(type_index cont_type_index $($_:tt)*) => {};
213+
(size_value array_size $($_:tt)*) => {};
214+
(depth relative_depth $($_:tt)*) => {};
215+
(blockty blockty $($_:tt)*) => {};
216+
(try_table try_table $($_:tt)*) => {};
217+
(br_table targets $($_:tt)*) => {};
218+
219+
(fixed load lane $($_:tt)*) => {(2, 1)};
220+
(fixed load $($_:tt)*) => {(1, 1)};
221+
(fixed store $($_:tt)*) => {(2, 0)};
222+
(fixed test $($_:tt)*) => {(1, 1)};
223+
(fixed unary $($_:tt)*) => {(1, 1)};
224+
(fixed binary $($_:tt)*) => {(2, 1)};
225+
(fixed cmp $($_:tt)*) => {(2, 1)};
226+
(fixed shift $($_:tt)*) => {(2, 1)};
227+
(fixed splat $($_:tt)*) => {(1, 1)};
228+
(fixed ternary $($_:tt)*) => {(3, 1)};
229+
(fixed conversion $($_:tt)*) => {(1, 1)};
230+
(fixed push $($_:tt)*) => {(0, 1)};
231+
(fixed extract $($_:tt)*) => {(1, 1)};
232+
(fixed replace $($_:tt)*) => {(2, 1)};
233+
(fixed atomic rmw array $($_:tt)*) => {(3, 1)};
234+
(fixed atomic rmw $($_:tt)*) => {(2, 1)};
235+
(fixed atomic cmpxchg $($_:tt)*) => {(3, 1)};
236+
}
237+
238+
impl Operator<'_> {
239+
/// Compute the arity (param and result counts) of the operator, given
240+
/// an impl ModuleArity, which stores the necessary module state.
241+
pub fn operator_arity(&self, module: &impl ModuleArity) -> Option<(u32, u32)> {
242+
macro_rules! define_arity {
243+
($(@$proposal:ident $op:ident $({ $($arg:ident: $argty:ty),* })? => $visit:ident ($($ann:tt)*) )*) => (
244+
match self.clone() {
245+
$(
246+
Operator::$op $({ $($arg),* })? => {
247+
$(
248+
$(let _ = $arg;)*
249+
)?
250+
operator_arity!(arity module $({ $($arg: $argty),* })? $($ann)*)
251+
}
252+
)*
253+
}
254+
);
255+
}
256+
for_each_operator!(define_arity)
257+
}
258+
}

crates/wasmparser/src/binary_reader.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -862,7 +862,7 @@ impl<'a> BinaryReader<'a> {
862862
/// }
863863
///
864864
/// macro_rules! define_visit_operator {
865-
/// ($(@$proposal:ident $op:ident $({ $($arg:ident: $argty:ty),* })? => $visit:ident)*) => {
865+
/// ($(@$proposal:ident $op:ident $({ $($arg:ident: $argty:ty),* })? => $visit:ident ($($ann:tt)*))*) => {
866866
/// $(
867867
/// fn $visit(&mut self $($(,$arg: $argty)*)?) -> Self::Output {
868868
/// println!("{}: {}", self.offset, stringify!($visit));
@@ -2083,7 +2083,7 @@ impl<'a> OperatorFactory<'a> {
20832083
}
20842084

20852085
macro_rules! define_visit_operator {
2086-
($(@$proposal:ident $op:ident $({ $($arg:ident: $argty:ty),* })? => $visit:ident)*) => {
2086+
($(@$proposal:ident $op:ident $({ $($arg:ident: $argty:ty),* })? => $visit:ident ($($ann:tt)*))*) => {
20872087
$(
20882088
fn $visit(&mut self $($(,$arg: $argty)*)?) -> Operator<'a> {
20892089
Operator::$op $({ $($arg),* })?

0 commit comments

Comments
 (0)