1use crate::{Function, Result};
8use paste::paste;
9use tracing::trace;
10use wasmparser::{for_each_operator, BlockType, BrTable, Ieee32, Ieee64, MemArg, VisitOperator};
11
12mod call;
13mod control;
14mod local;
15mod log;
16
17macro_rules! impl_visit_operator {
24 ( @mvp $op:ident $({ $($arg:ident: $argty:ty),* })? => $visit:ident $($rest:tt)* ) => {
25 impl_visit_operator!($($rest)*);
26 };
27 ( @$proposal:ident $op:ident $({ $($arg:ident: $argty:ty),* })? => $visit:ident $($rest:tt)* ) => {
28 fn $visit(&mut self $($(, $arg: $argty)*)?) -> Self::Output {
29 trace!("{}", stringify!($op));
30 Ok(())
31 }
32
33 impl_visit_operator!($($rest)*);
34 };
35 () => {};
36}
37
38macro_rules! map_wasm_operators {
40 (@basic $ty:tt, $wasm:tt, $evm:tt $($arg:ident: $argty:ty),*) => {
41 paste! {
42 fn [< visit_ $ty _ $wasm >](&mut self $(,$arg: $argty),*) -> Self::Output {
43 trace!("{}.{}", stringify!($ty), stringify!($evm));
44
45 let before = self.masm.buffer().len();
46 self.masm.[< _ $evm >]()?;
47
48 let instr = self.masm.buffer()[before..].to_vec();
49 self.backtrace.push(instr);
50
51 Ok(())
52 }
53 }
54 };
55 (@integer32 $wasm:tt, $evm:tt $($arg:ident: $argty:ty),*) => {
56 map_wasm_operators!(@basic i32, $wasm, $evm $($arg: $argty),*);
57 };
58 (@integer64 $wasm:tt, $evm:tt $($arg:ident: $argty:ty),*) => {
59 map_wasm_operators!(@basic i64, $wasm, $evm $($arg: $argty),*);
60 };
61 (@integer $wasm:tt, $evm:tt $($arg:ident: $argty:ty),*) => {
62 map_wasm_operators!(@integer32 $wasm, $evm $($arg: $argty),*);
63 map_wasm_operators!(@integer64 $wasm, $evm $($arg: $argty),*);
64 };
65 (@xdr $wasm:tt, $evm:tt $($arg:ident: $argty:ty),*) => {
66 paste!{
67 map_wasm_operators!(@integer [< $wasm _s >], $evm $($arg: $argty),*);
68 map_wasm_operators!(@integer [< $wasm _u >], $evm $($arg: $argty),*);
69 }
70 };
71 (@float32 $wasm:tt, $evm:tt $($arg:ident: $argty:ty),*) => {
72 map_wasm_operators!(@basic f32, $wasm, $evm $($arg: $argty),*);
73 };
74 (@float64 $wasm:tt, $evm:tt $($arg:ident: $argty:ty),*) => {
75 map_wasm_operators!(@basic f64, $wasm, $evm $($arg: $argty),*);
76 };
77 (@float $wasm:tt, $evm:tt $($arg:ident: $argty:ty),*) => {
78 map_wasm_operators!(@float32 $wasm, $evm $($arg: $argty),*);
79 map_wasm_operators!(@float64 $wasm, $evm $($arg: $argty),*);
80 };
81 (@integer_and_float $op:tt $($arg:ident: $argty:ty),*) => {
82 map_wasm_operators!(@integer $op, $op);
83 map_wasm_operators!(@float $op, $op);
84 };
85 (@field ($($field:ident).*) ($op:tt -> $evm:tt) $($arg:tt: $argty:ty),* ) => {
86 paste! {
87 fn [< visit_ $op >](&mut self, $($arg: $argty),*) -> Self::Output {
88 let mut log = stringify!($op).to_string();
89 log = log.replace('_', ".");
90
91 $(
92 let fmt = &format!(" {:?}", $arg);
93 if fmt != " Empty" {
94 log.push_str(&fmt);
95 }
96 )*
97
98 trace!("{}", log);
99
100 let before = self.masm.buffer().len();
101 self.$($field.)*[< _ $evm >]($($arg),*)?;
102
103 let instr = self.masm.buffer()[before..].to_vec();
104 self.backtrace.push(instr);
105 Ok(())
106 }
107 }
108 };
109 (
110 all: [$($all:tt),+],
111 xdr: [$($xdr:tt),+],
112 integer: [$($integer:tt),+],
113 integer_and_float: [$($op:tt),+],
114 float: [$($float:tt),+],
115 map: {
116 integer: [$($map_int_wasm:tt => $map_int_evm:tt),+],
117 },
118 mem: {
119 all: [$($mem:tt),+],
120 integer: [$($mem_integer:tt),+],
121 integer64: [$($mem_integer64:tt),+],
122 signed: [$($mem_signed:tt),+],
123 signed64: [$($mem_signed64:tt),+],
124 signed_and_float: [$($mem_signed_and_float:tt),+],
125 },
126 masm: {
127 $( $masm:tt $(: { $($marg:ident: $margty:ty),+ })? ),+
128 },
129 global: {
130 $( $global:tt $(: { $($garg:ident: $gargty:ty),+ })? ),+
131 }
132 ) => {
133 paste! {
134 $(map_wasm_operators!(@integer_and_float $op);)+
135
136 $(
137 map_wasm_operators!(@integer [< $all _s >], [< s $all >]);
138 map_wasm_operators!(@integer [< $all _u >], $all);
139 map_wasm_operators!(@float $all, $all);
140 )+
141
142 $(map_wasm_operators!(@integer $integer, $integer);)+
143 $(map_wasm_operators!(@xdr $xdr, $xdr);)+
144 $(map_wasm_operators!(@float $float, $float);)+
145
146 $(
147 map_wasm_operators!(@integer [< $map_int_wasm _s >], [< s $map_int_evm >]);
148 map_wasm_operators!(@integer [< $map_int_wasm _u >], $map_int_evm);
149 )+
150
151 $(
152 map_wasm_operators!(@integer $mem, $mem _arg: MemArg);
153 map_wasm_operators!(@float $mem, $mem _arg: MemArg);
154 )+
155
156
157 $(
158 map_wasm_operators!(@xdr $mem_integer, $mem_integer _arg: MemArg);
159 )+
160
161 $(
162 map_wasm_operators!(@integer64 [< $mem_integer64 _s >], $mem_integer64 _arg: MemArg );
163 map_wasm_operators!(@integer64 [< $mem_integer64 _u >], $mem_integer64 _arg: MemArg );
164 )+
165
166
167 $(
168 map_wasm_operators!(@integer $mem_signed, $mem_signed _arg: MemArg);
169 )+
170
171 $(
172 map_wasm_operators!(@integer $mem_signed_and_float, $mem_signed_and_float _arg: MemArg);
173 map_wasm_operators!(@float $mem_signed_and_float, $mem_signed_and_float _arg: MemArg);
174 )+
175
176 $(
177 map_wasm_operators!(@integer64 $mem_signed64, $mem_signed64 _arg: MemArg);
178 )+
179
180 $(
181 map_wasm_operators!(@field (masm) ($masm -> $masm) $( $($marg: $margty),+ )?);
182 )+
183
184 $(
185 map_wasm_operators!(@field () ($global -> $global) $( $($garg: $gargty),+ )?);
186 )+
187 }
188 };
189}
190
191impl VisitOperator<'_> for Function {
192 type Output = Result<()>;
193
194 for_each_operator!(impl_visit_operator);
195
196 map_wasm_operators! {
197 all: [div, lt, gt, ge, le],
198 xdr: [shr, trunc_f32, trunc_f64],
199 integer: [and, clz, ctz, eqz, or, popcnt, rotl, rotr, shl, xor],
200 integer_and_float: [add, sub, mul, eq, ne],
201 float: [
202 abs, ceil, copysign, floor, max, min, nearest, neg, sqrt,
203 convert_i32_s, convert_i32_u, convert_i64_s, convert_i64_u,
204 trunc
205 ],
206 map: {
207 integer: [rem => mod],
208 },
209 mem: {
210 all: [load],
211 integer: [load8, load16],
212 integer64: [load32],
213 signed: [store8, store16],
214 signed64: [store32],
215 signed_and_float: [store],
216 },
217 masm: {
218 drop,
219 memory_grow: {
220 mem: u32,
221 mem_byte: u8
222 },
223 memory_size: {
224 mem: u32,
225 mem_byte: u8
226 },
227 i32_const: {
228 value: i32
229 },
230 i64_const: {
231 value: i64
232 },
233 f32_const: {
234 value: Ieee32
235 },
236 f64_const: {
237 value: Ieee64
238 },
239 i32_wrap_i64,
240 i64_extend_i32_s,
241 i64_extend_i32_u,
242 f32_demote_f64,
243 f64_promote_f32,
244 i32_reinterpret_f32,
245 i64_reinterpret_f64,
246 f32_reinterpret_i32,
247 f64_reinterpret_i64
248 },
249 global: {
250 else, select, end, nop, unreachable,
251 if: {
252 blockty: BlockType
253 },
254 block: {
255 blockty: BlockType
256 },
257 loop: {
258 blockty: BlockType
259 },
260 br: {
261 relative_depth: u32
262 },
263 br_if: {
264 relative_depth: u32
265 },
266 br_table: {
267 table: BrTable<'_>
268 },
269 local_get: {
270 local_index: u32
271 },
272 local_set: {
273 local_index: u32
274 },
275 local_tee: {
276 local_index: u32
277 },
278 global_get: {
279 global_index: u32
280 },
281 global_set: {
282 global_index: u32
283 },
284 call: {
285 func_index: u32
286 },
287 call_indirect: {
288 type_index: u32,
289 table_index: u32,
290 table_byte: u8
291 }
292 }
293 }
294
295 fn visit_return(&mut self) -> Self::Output {
297 trace!("return");
298
299 let before = self.masm.buffer().len();
300
301 if self.is_main || self.abi.is_some() {
303 tracing::trace!("early return from main function");
304 self.masm.emit_return_value(&[1])?;
305 } else {
306 tracing::trace!("early return from call");
307 self.masm.call_return(self.ty.results())?;
308 }
309
310 let instr = self.masm.buffer()[before..].to_vec();
311 self.backtrace.push(instr);
312
313 Ok(())
314 }
315}