1/* Copyright 2017 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//! A simple event-driven library for parsing WebAssembly binary files
17//! (or streams).
18//!
19//! The parser library reports events as they happen and only stores
20//! parsing information for a brief period of time, making it very fast
21//! and memory-efficient. The event-driven model, however, has some drawbacks.
22//! If you need random access to the entire WebAssembly data-structure,
23//! this is not the right library for you. You could however, build such
24//! a data-structure using this library.
25//!
26//! To get started, create a [`Parser`] using [`Parser::new`] and then follow
27//! the examples documented for [`Parser::parse`] or [`Parser::parse_all`].
28
29#![deny(missing_docs)]
30#![no_std]
31#![cfg_attr(docsrs, feature(doc_auto_cfg))]
32
33extern crate alloc;
34#[cfg(feature = "std")]
35#[macro_use]
36extern crate std;
37
38/// A small "prelude" to use throughout this crate.
39///
40/// This crate is tagged with `#![no_std]` meaning that we get libcore's prelude
41/// by default. This crate also uses `alloc`, however, and common types there
42/// like `String`. This custom prelude helps bring those types into scope to
43/// avoid having to import each of them manually.
44mod prelude {
45 pub use alloc::borrow::ToOwned;
46 pub use alloc::boxed::Box;
47 pub use alloc::format;
48 pub use alloc::string::{String, ToString};
49 pub use alloc::vec;
50 pub use alloc::vec::Vec;
51
52 #[cfg(all(feature = "validate", feature = "component-model"))]
53 pub use crate::collections::IndexSet;
54 #[cfg(feature = "validate")]
55 pub use crate::collections::{IndexMap, Map, Set};
56}
57
58/// A helper macro to conveniently iterate over all opcodes recognized by this
59/// crate. This can be used to work with either the [`Operator`] enumeration or
60/// the [`VisitOperator`] trait if your use case uniformly handles all operators
61/// the same way.
62///
63/// It is also possible to specialize handling of operators depending on the
64/// Wasm proposal from which they are originating.
65///
66/// This is an "iterator macro" where this macro is invoked with the name of
67/// another macro, and then that macro is invoked with the list of all
68/// operators. An example invocation of this looks like:
69///
70/// The list of specializable Wasm proposals is as follows:
71///
72/// - `@mvp`: Denoting a Wasm operator from the initial Wasm MVP version.
73/// - `@exceptions`: [Wasm `exception-handling` proposal]
74/// - `@tail_call`: [Wasm `tail-calls` proposal]
75/// - `@reference_types`: [Wasm `reference-types` proposal]
76/// - `@sign_extension`: [Wasm `sign-extension-ops` proposal]
77/// - `@saturating_float_to_int`: [Wasm `non_trapping_float-to-int-conversions` proposal]
78/// - `@bulk_memory `:[Wasm `bulk-memory` proposal]
79/// - `@threads`: [Wasm `threads` proposal]
80/// - `@simd`: [Wasm `simd` proposal]
81/// - `@relaxed_simd`: [Wasm `relaxed-simd` proposal]
82/// - `@gc`: [Wasm `gc` proposal]
83/// - `@stack_switching`: [Wasm `stack-switching` proposal]
84/// - `@wide_arithmetic`: [Wasm `wide-arithmetic` proposal]
85///
86/// [Wasm `exception-handling` proposal]:
87/// https://github.com/WebAssembly/exception-handling
88///
89/// [Wasm `tail-calls` proposal]:
90/// https://github.com/WebAssembly/tail-call
91///
92/// [Wasm `reference-types` proposal]:
93/// https://github.com/WebAssembly/reference-types
94///
95/// [Wasm `sign-extension-ops` proposal]:
96/// https://github.com/WebAssembly/sign-extension-ops
97///
98/// [Wasm `non_trapping_float-to-int-conversions` proposal]:
99/// https://github.com/WebAssembly/nontrapping-float-to-int-conversions
100///
101/// [Wasm `bulk-memory` proposal]:
102/// https://github.com/WebAssembly/bulk-memory-operations
103///
104/// [Wasm `threads` proposal]:
105/// https://github.com/webassembly/threads
106///
107/// [Wasm `simd` proposal]:
108/// https://github.com/webassembly/simd
109///
110/// [Wasm `relaxed-simd` proposal]:
111/// https://github.com/WebAssembly/relaxed-simd
112///
113/// [Wasm `gc` proposal]:
114/// https://github.com/WebAssembly/gc
115///
116/// [Wasm `stack-switching` proposal]:
117/// https://github.com/WebAssembly/stack-switching
118///
119/// [Wasm `wide-arithmetic` proposal]:
120/// https://github.com/WebAssembly/wide-arithmetic
121///
122/// ```
123/// macro_rules! define_visit_operator {
124/// // The outer layer of repetition represents how all operators are
125/// // provided to the macro at the same time.
126/// //
127/// // The `$proposal` identifier indicates the Wasm proposals from which
128/// // the Wasm operator is originating.
129/// // For example to specialize the macro match arm for Wasm SIMD proposal
130/// // operators you could write `@simd` instead of `@$proposal:ident` to
131/// // only catch those operators.
132/// //
133/// // The `$op` name is bound to the `Operator` variant name. The
134/// // payload of the operator is optionally specified (the `$(...)?`
135/// // clause) since not all instructions have payloads. Within the payload
136/// // each argument is named and has its type specified.
137/// //
138/// // The `$visit` name is bound to the corresponding name in the
139/// // `VisitOperator` trait that this corresponds to.
140/// //
141/// // The `$ann` annotations give information about the operator's type (e.g. binary i32 or arity 2 -> 1).
142/// ($( @$proposal:ident $op:ident $({ $($arg:ident: $argty:ty),* })? => $visit:ident ($($ann:tt)*))*) => {
143/// $(
144/// fn $visit(&mut self $($(,$arg: $argty)*)?) {
145/// // do nothing for this example
146/// }
147/// )*
148/// }
149/// }
150///
151/// pub struct VisitAndDoNothing;
152///
153/// impl<'a> wasmparser::VisitOperator<'a> for VisitAndDoNothing {
154/// type Output = ();
155///
156/// wasmparser::for_each_operator!(define_visit_operator);
157/// }
158/// ```
159///
160/// If you only wanted to visit the initial base set of wasm instructions, for
161/// example, you could do:
162///
163/// ```
164/// macro_rules! visit_only_mvp {
165/// // delegate the macro invocation to sub-invocations of this macro to
166/// // deal with each instruction on a case-by-case basis.
167/// ($( @$proposal:ident $op:ident $({ $($arg:ident: $argty:ty),* })? => $visit:ident ($($ann:tt)*))*) => {
168/// $(
169/// visit_only_mvp!(visit_one @$proposal $op $({ $($arg: $argty),* })? => $visit);
170/// )*
171/// };
172///
173/// // MVP instructions are defined manually, so do nothing.
174/// (visit_one @mvp $($rest:tt)*) => {};
175///
176/// // Non-MVP instructions all return `false` here. The exact type depends
177/// // on `type Output` in the trait implementation below. You could change
178/// // it to `Result<()>` for example and return an error here too.
179/// (visit_one @$proposal:ident $op:ident $({ $($arg:ident: $argty:ty),* })? => $visit:ident) => {
180/// fn $visit(&mut self $($(,$arg: $argty)*)?) -> bool {
181/// false
182/// }
183/// }
184/// }
185/// # // to get this example to compile another macro is used here to define
186/// # // visit methods for all mvp oeprators.
187/// # macro_rules! visit_mvp {
188/// # ($( @$proposal:ident $op:ident $({ $($arg:ident: $argty:ty),* })? => $visit:ident ($($ann:tt)*))*) => {
189/// # $(
190/// # visit_mvp!(visit_one @$proposal $op $({ $($arg: $argty),* })? => $visit);
191/// # )*
192/// # };
193/// # (visit_one @mvp $op:ident $({ $($arg:ident: $argty:ty),* })? => $visit:ident) => {
194/// # fn $visit(&mut self $($(,$arg: $argty)*)?) -> bool {
195/// # true
196/// # }
197/// # };
198/// # (visit_one @$proposal:ident $($rest:tt)*) => {};
199/// # }
200///
201/// pub struct VisitOnlyMvp;
202///
203/// impl<'a> wasmparser::VisitOperator<'a> for VisitOnlyMvp {
204/// type Output = bool;
205///
206/// wasmparser::for_each_operator!(visit_only_mvp);
207/// # wasmparser::for_each_operator!(visit_mvp);
208///
209/// // manually define `visit_*` for all MVP operators here
210/// }
211/// ```
212#[macro_export]
213macro_rules! for_each_operator {
214 ($mac:ident) => {
215 $mac! {
216 @mvp Unreachable => visit_unreachable (arity 0 -> 0)
217 @mvp Nop => visit_nop (arity 0 -> 0)
218 @mvp Block { blockty: $crate::BlockType } => visit_block (arity block -> ~block)
219 @mvp Loop { blockty: $crate::BlockType } => visit_loop (arity block -> ~block)
220 @mvp If { blockty: $crate::BlockType } => visit_if (arity 1 block -> ~block)
221 @mvp Else => visit_else (arity ~end -> ~end)
222 @exceptions TryTable { try_table: $crate::TryTable } => visit_try_table (arity try_table -> ~try_table)
223 @exceptions Throw { tag_index: u32 } => visit_throw (arity tag -> 0)
224 @exceptions ThrowRef => visit_throw_ref (arity 1 -> 0)
225 // Deprecated old instructions from the exceptions proposal
226 @legacy_exceptions Try { blockty: $crate::BlockType } => visit_try (arity block -> ~block)
227 @legacy_exceptions Catch { tag_index: u32 } => visit_catch (arity ~end -> ~tag)
228 @legacy_exceptions Rethrow { relative_depth: u32 } => visit_rethrow (arity 0 -> 0)
229 @legacy_exceptions Delegate { relative_depth: u32 } => visit_delegate (arity ~end -> end)
230 @legacy_exceptions CatchAll => visit_catch_all (arity ~end -> 0)
231 @mvp End => visit_end (arity implicit_else ~end -> implicit_else end)
232 @mvp Br { relative_depth: u32 } => visit_br (arity br -> 0)
233 @mvp BrIf { relative_depth: u32 } => visit_br_if (arity 1 br -> br)
234 @mvp BrTable { targets: $crate::BrTable<'a> } => visit_br_table (arity 1 br_table -> 0)
235 @mvp Return => visit_return (arity ~ret -> 0)
236 @mvp Call { function_index: u32 } => visit_call (arity func -> func)
237 @mvp CallIndirect { type_index: u32, table_index: u32 } => visit_call_indirect (arity 1 type -> type)
238 @tail_call ReturnCall { function_index: u32 } => visit_return_call (arity func -> 0)
239 @tail_call ReturnCallIndirect { type_index: u32, table_index: u32 } => visit_return_call_indirect (arity 1 type -> 0)
240 @mvp Drop => visit_drop (arity 1 -> 0)
241 @mvp Select => visit_select (arity 3 -> 1)
242 @reference_types TypedSelect { ty: $crate::ValType } => visit_typed_select (arity 3 -> 1)
243 @mvp LocalGet { local_index: u32 } => visit_local_get (arity 0 -> 1)
244 @mvp LocalSet { local_index: u32 } => visit_local_set (arity 1 -> 0)
245 @mvp LocalTee { local_index: u32 } => visit_local_tee (arity 1 -> 1)
246 @mvp GlobalGet { global_index: u32 } => visit_global_get (arity 0 -> 1)
247 @mvp GlobalSet { global_index: u32 } => visit_global_set (arity 1 -> 0)
248 @mvp I32Load { memarg: $crate::MemArg } => visit_i32_load (load i32)
249 @mvp I64Load { memarg: $crate::MemArg } => visit_i64_load (load i64)
250 @mvp F32Load { memarg: $crate::MemArg } => visit_f32_load (load f32)
251 @mvp F64Load { memarg: $crate::MemArg } => visit_f64_load (load f64)
252 @mvp I32Load8S { memarg: $crate::MemArg } => visit_i32_load8_s (load i32)
253 @mvp I32Load8U { memarg: $crate::MemArg } => visit_i32_load8_u (load i32)
254 @mvp I32Load16S { memarg: $crate::MemArg } => visit_i32_load16_s (load i32)
255 @mvp I32Load16U { memarg: $crate::MemArg } => visit_i32_load16_u (load i32)
256 @mvp I64Load8S { memarg: $crate::MemArg } => visit_i64_load8_s (load i64)
257 @mvp I64Load8U { memarg: $crate::MemArg } => visit_i64_load8_u (load i64)
258 @mvp I64Load16S { memarg: $crate::MemArg } => visit_i64_load16_s (load i64)
259 @mvp I64Load16U { memarg: $crate::MemArg } => visit_i64_load16_u (load i64)
260 @mvp I64Load32S { memarg: $crate::MemArg } => visit_i64_load32_s (load i64)
261 @mvp I64Load32U { memarg: $crate::MemArg } => visit_i64_load32_u (load i64)
262 @mvp I32Store { memarg: $crate::MemArg } => visit_i32_store (store i32)
263 @mvp I64Store { memarg: $crate::MemArg } => visit_i64_store (store i64)
264 @mvp F32Store { memarg: $crate::MemArg } => visit_f32_store (store f32)
265 @mvp F64Store { memarg: $crate::MemArg } => visit_f64_store (store f64)
266 @mvp I32Store8 { memarg: $crate::MemArg } => visit_i32_store8 (store i32)
267 @mvp I32Store16 { memarg: $crate::MemArg } => visit_i32_store16 (store i32)
268 @mvp I64Store8 { memarg: $crate::MemArg } => visit_i64_store8 (store i64)
269 @mvp I64Store16 { memarg: $crate::MemArg } => visit_i64_store16 (store i64)
270 @mvp I64Store32 { memarg: $crate::MemArg } => visit_i64_store32 (store i64)
271 @mvp MemorySize { mem: u32 } => visit_memory_size (arity 0 -> 1)
272 @mvp MemoryGrow { mem: u32 } => visit_memory_grow (arity 1 -> 1)
273 @mvp I32Const { value: i32 } => visit_i32_const (push i32)
274 @mvp I64Const { value: i64 } => visit_i64_const (push i64)
275 @mvp F32Const { value: $crate::Ieee32 } => visit_f32_const (push f32)
276 @mvp F64Const { value: $crate::Ieee64 } => visit_f64_const (push f64)
277 @reference_types RefNull { hty: $crate::HeapType } => visit_ref_null (arity 0 -> 1)
278 @reference_types RefIsNull => visit_ref_is_null (arity 1 -> 1)
279 @reference_types RefFunc { function_index: u32 } => visit_ref_func (arity 0 -> 1)
280 @gc RefEq => visit_ref_eq (arity 2 -> 1)
281 @mvp I32Eqz => visit_i32_eqz (test i32)
282 @mvp I32Eq => visit_i32_eq (cmp i32)
283 @mvp I32Ne => visit_i32_ne (cmp i32)
284 @mvp I32LtS => visit_i32_lt_s (cmp i32)
285 @mvp I32LtU => visit_i32_lt_u (cmp i32)
286 @mvp I32GtS => visit_i32_gt_s (cmp i32)
287 @mvp I32GtU => visit_i32_gt_u (cmp i32)
288 @mvp I32LeS => visit_i32_le_s (cmp i32)
289 @mvp I32LeU => visit_i32_le_u (cmp i32)
290 @mvp I32GeS => visit_i32_ge_s (cmp i32)
291 @mvp I32GeU => visit_i32_ge_u (cmp i32)
292 @mvp I64Eqz => visit_i64_eqz (test i64)
293 @mvp I64Eq => visit_i64_eq (cmp i64)
294 @mvp I64Ne => visit_i64_ne (cmp i64)
295 @mvp I64LtS => visit_i64_lt_s (cmp i64)
296 @mvp I64LtU => visit_i64_lt_u (cmp i64)
297 @mvp I64GtS => visit_i64_gt_s (cmp i64)
298 @mvp I64GtU => visit_i64_gt_u (cmp i64)
299 @mvp I64LeS => visit_i64_le_s (cmp i64)
300 @mvp I64LeU => visit_i64_le_u (cmp i64)
301 @mvp I64GeS => visit_i64_ge_s (cmp i64)
302 @mvp I64GeU => visit_i64_ge_u (cmp i64)
303 @mvp F32Eq => visit_f32_eq (cmp f32)
304 @mvp F32Ne => visit_f32_ne (cmp f32)
305 @mvp F32Lt => visit_f32_lt (cmp f32)
306 @mvp F32Gt => visit_f32_gt (cmp f32)
307 @mvp F32Le => visit_f32_le (cmp f32)
308 @mvp F32Ge => visit_f32_ge (cmp f32)
309 @mvp F64Eq => visit_f64_eq (cmp f64)
310 @mvp F64Ne => visit_f64_ne (cmp f64)
311 @mvp F64Lt => visit_f64_lt (cmp f64)
312 @mvp F64Gt => visit_f64_gt (cmp f64)
313 @mvp F64Le => visit_f64_le (cmp f64)
314 @mvp F64Ge => visit_f64_ge (cmp f64)
315 @mvp I32Clz => visit_i32_clz (unary i32)
316 @mvp I32Ctz => visit_i32_ctz (unary i32)
317 @mvp I32Popcnt => visit_i32_popcnt (unary i32)
318 @mvp I32Add => visit_i32_add (binary i32)
319 @mvp I32Sub => visit_i32_sub (binary i32)
320 @mvp I32Mul => visit_i32_mul (binary i32)
321 @mvp I32DivS => visit_i32_div_s (binary i32)
322 @mvp I32DivU => visit_i32_div_u (binary i32)
323 @mvp I32RemS => visit_i32_rem_s (binary i32)
324 @mvp I32RemU => visit_i32_rem_u (binary i32)
325 @mvp I32And => visit_i32_and (binary i32)
326 @mvp I32Or => visit_i32_or (binary i32)
327 @mvp I32Xor => visit_i32_xor (binary i32)
328 @mvp I32Shl => visit_i32_shl (binary i32)
329 @mvp I32ShrS => visit_i32_shr_s (binary i32)
330 @mvp I32ShrU => visit_i32_shr_u (binary i32)
331 @mvp I32Rotl => visit_i32_rotl (binary i32)
332 @mvp I32Rotr => visit_i32_rotr (binary i32)
333 @mvp I64Clz => visit_i64_clz (unary i64)
334 @mvp I64Ctz => visit_i64_ctz (unary i64)
335 @mvp I64Popcnt => visit_i64_popcnt (unary i64)
336 @mvp I64Add => visit_i64_add (binary i64)
337 @mvp I64Sub => visit_i64_sub (binary i64)
338 @mvp I64Mul => visit_i64_mul (binary i64)
339 @mvp I64DivS => visit_i64_div_s (binary i64)
340 @mvp I64DivU => visit_i64_div_u (binary i64)
341 @mvp I64RemS => visit_i64_rem_s (binary i64)
342 @mvp I64RemU => visit_i64_rem_u (binary i64)
343 @mvp I64And => visit_i64_and (binary i64)
344 @mvp I64Or => visit_i64_or (binary i64)
345 @mvp I64Xor => visit_i64_xor (binary i64)
346 @mvp I64Shl => visit_i64_shl (binary i64)
347 @mvp I64ShrS => visit_i64_shr_s (binary i64)
348 @mvp I64ShrU => visit_i64_shr_u (binary i64)
349 @mvp I64Rotl => visit_i64_rotl (binary i64)
350 @mvp I64Rotr => visit_i64_rotr (binary i64)
351 @mvp F32Abs => visit_f32_abs (unary f32)
352 @mvp F32Neg => visit_f32_neg (unary f32)
353 @mvp F32Ceil => visit_f32_ceil (unary f32)
354 @mvp F32Floor => visit_f32_floor (unary f32)
355 @mvp F32Trunc => visit_f32_trunc (unary f32)
356 @mvp F32Nearest => visit_f32_nearest (unary f32)
357 @mvp F32Sqrt => visit_f32_sqrt (unary f32)
358 @mvp F32Add => visit_f32_add (binary f32)
359 @mvp F32Sub => visit_f32_sub (binary f32)
360 @mvp F32Mul => visit_f32_mul (binary f32)
361 @mvp F32Div => visit_f32_div (binary f32)
362 @mvp F32Min => visit_f32_min (binary f32)
363 @mvp F32Max => visit_f32_max (binary f32)
364 @mvp F32Copysign => visit_f32_copysign (binary f32)
365 @mvp F64Abs => visit_f64_abs (unary f64)
366 @mvp F64Neg => visit_f64_neg (unary f64)
367 @mvp F64Ceil => visit_f64_ceil (unary f64)
368 @mvp F64Floor => visit_f64_floor (unary f64)
369 @mvp F64Trunc => visit_f64_trunc (unary f64)
370 @mvp F64Nearest => visit_f64_nearest (unary f64)
371 @mvp F64Sqrt => visit_f64_sqrt (unary f64)
372 @mvp F64Add => visit_f64_add (binary f64)
373 @mvp F64Sub => visit_f64_sub (binary f64)
374 @mvp F64Mul => visit_f64_mul (binary f64)
375 @mvp F64Div => visit_f64_div (binary f64)
376 @mvp F64Min => visit_f64_min (binary f64)
377 @mvp F64Max => visit_f64_max (binary f64)
378 @mvp F64Copysign => visit_f64_copysign (binary f64)
379 @mvp I32WrapI64 => visit_i32_wrap_i64 (conversion i32 i64)
380 @mvp I32TruncF32S => visit_i32_trunc_f32_s (conversion i32 f32)
381 @mvp I32TruncF32U => visit_i32_trunc_f32_u (conversion i32 f32)
382 @mvp I32TruncF64S => visit_i32_trunc_f64_s (conversion i32 f64)
383 @mvp I32TruncF64U => visit_i32_trunc_f64_u (conversion i32 f64)
384 @mvp I64ExtendI32S => visit_i64_extend_i32_s (conversion i64 i32)
385 @mvp I64ExtendI32U => visit_i64_extend_i32_u (conversion i64 i32)
386 @mvp I64TruncF32S => visit_i64_trunc_f32_s (conversion i64 f32)
387 @mvp I64TruncF32U => visit_i64_trunc_f32_u (conversion i64 f32)
388 @mvp I64TruncF64S => visit_i64_trunc_f64_s (conversion i64 f64)
389 @mvp I64TruncF64U => visit_i64_trunc_f64_u (conversion i64 f64)
390 @mvp F32ConvertI32S => visit_f32_convert_i32_s (conversion f32 i32)
391 @mvp F32ConvertI32U => visit_f32_convert_i32_u (conversion f32 i32)
392 @mvp F32ConvertI64S => visit_f32_convert_i64_s (conversion f32 i64)
393 @mvp F32ConvertI64U => visit_f32_convert_i64_u (conversion f32 i64)
394 @mvp F32DemoteF64 => visit_f32_demote_f64 (conversion f32 f64)
395 @mvp F64ConvertI32S => visit_f64_convert_i32_s (conversion f64 i32)
396 @mvp F64ConvertI32U => visit_f64_convert_i32_u (conversion f64 i32)
397 @mvp F64ConvertI64S => visit_f64_convert_i64_s (conversion f64 i64)
398 @mvp F64ConvertI64U => visit_f64_convert_i64_u (conversion f64 i64)
399 @mvp F64PromoteF32 => visit_f64_promote_f32 (conversion f64 f32)
400 @mvp I32ReinterpretF32 => visit_i32_reinterpret_f32 (conversion i32 f32)
401 @mvp I64ReinterpretF64 => visit_i64_reinterpret_f64 (conversion i64 f64)
402 @mvp F32ReinterpretI32 => visit_f32_reinterpret_i32 (conversion f32 i32)
403 @mvp F64ReinterpretI64 => visit_f64_reinterpret_i64 (conversion f64 i64)
404 @sign_extension I32Extend8S => visit_i32_extend8_s (unary i32)
405 @sign_extension I32Extend16S => visit_i32_extend16_s (unary i32)
406 @sign_extension I64Extend8S => visit_i64_extend8_s (unary i64)
407 @sign_extension I64Extend16S => visit_i64_extend16_s (unary i64)
408 @sign_extension I64Extend32S => visit_i64_extend32_s (unary i64)
409
410 // 0xFB prefixed operators
411 // Garbage Collection
412 // http://github.com/WebAssembly/gc
413 @gc StructNew { struct_type_index: u32 } => visit_struct_new (arity type -> 1)
414 @gc StructNewDefault { struct_type_index: u32 } => visit_struct_new_default (arity 0 -> 1)
415 @gc StructGet { struct_type_index: u32, field_index: u32 } => visit_struct_get (arity 1 -> 1)
416 @gc StructGetS { struct_type_index: u32, field_index: u32 } => visit_struct_get_s (arity 1 -> 1)
417 @gc StructGetU { struct_type_index: u32, field_index: u32 } => visit_struct_get_u (arity 1 -> 1)
418 @gc StructSet { struct_type_index: u32, field_index: u32 } => visit_struct_set (arity 2 -> 0)
419 @gc ArrayNew { array_type_index: u32 } => visit_array_new (arity 2 -> 1)
420 @gc ArrayNewDefault { array_type_index: u32 } => visit_array_new_default (arity 1 -> 1)
421 @gc ArrayNewFixed { array_type_index: u32, array_size: u32 } => visit_array_new_fixed (arity size -> 1)
422 @gc ArrayNewData { array_type_index: u32, array_data_index: u32 } => visit_array_new_data (arity 2 -> 1)
423 @gc ArrayNewElem { array_type_index: u32, array_elem_index: u32 } => visit_array_new_elem (arity 2 -> 1)
424 @gc ArrayGet { array_type_index: u32 } => visit_array_get (arity 2 -> 1)
425 @gc ArrayGetS { array_type_index: u32 } => visit_array_get_s (arity 2 -> 1)
426 @gc ArrayGetU { array_type_index: u32 } => visit_array_get_u (arity 2 -> 1)
427 @gc ArraySet { array_type_index: u32 } => visit_array_set (arity 3 -> 0)
428 @gc ArrayLen => visit_array_len (arity 1 -> 1)
429 @gc ArrayFill { array_type_index: u32 } => visit_array_fill (arity 4 -> 0)
430 @gc ArrayCopy { array_type_index_dst: u32, array_type_index_src: u32 } => visit_array_copy (arity 5 -> 0)
431 @gc ArrayInitData { array_type_index: u32, array_data_index: u32 } => visit_array_init_data (arity 4 -> 0)
432 @gc ArrayInitElem { array_type_index: u32, array_elem_index: u32 } => visit_array_init_elem (arity 4 -> 0)
433 @gc RefTestNonNull { hty: $crate::HeapType } => visit_ref_test_non_null (arity 1 -> 1)
434 @gc RefTestNullable { hty: $crate::HeapType } => visit_ref_test_nullable (arity 1 -> 1)
435 @gc RefCastNonNull { hty: $crate::HeapType } => visit_ref_cast_non_null (arity 1 -> 1)
436 @gc RefCastNullable { hty: $crate::HeapType } => visit_ref_cast_nullable (arity 1 -> 1)
437 @gc BrOnCast {
438 relative_depth: u32,
439 from_ref_type: $crate::RefType,
440 to_ref_type: $crate::RefType
441 } => visit_br_on_cast (arity br -> br)
442 @gc BrOnCastFail {
443 relative_depth: u32,
444 from_ref_type: $crate::RefType,
445 to_ref_type: $crate::RefType
446 } => visit_br_on_cast_fail (arity br -> br)
447 @gc AnyConvertExtern => visit_any_convert_extern (arity 1 -> 1)
448 @gc ExternConvertAny => visit_extern_convert_any (arity 1 -> 1)
449 @gc RefI31 => visit_ref_i31 (arity 1 -> 1)
450 @gc I31GetS => visit_i31_get_s (arity 1 -> 1)
451 @gc I31GetU => visit_i31_get_u (arity 1 -> 1)
452
453 // 0xFC operators
454 // Non-trapping Float-to-int Conversions
455 // https://github.com/WebAssembly/nontrapping-float-to-int-conversions
456 @saturating_float_to_int I32TruncSatF32S => visit_i32_trunc_sat_f32_s (conversion i32 f32)
457 @saturating_float_to_int I32TruncSatF32U => visit_i32_trunc_sat_f32_u (conversion i32 f32)
458 @saturating_float_to_int I32TruncSatF64S => visit_i32_trunc_sat_f64_s (conversion i32 f64)
459 @saturating_float_to_int I32TruncSatF64U => visit_i32_trunc_sat_f64_u (conversion i32 f64)
460 @saturating_float_to_int I64TruncSatF32S => visit_i64_trunc_sat_f32_s (conversion i64 f32)
461 @saturating_float_to_int I64TruncSatF32U => visit_i64_trunc_sat_f32_u (conversion i64 f32)
462 @saturating_float_to_int I64TruncSatF64S => visit_i64_trunc_sat_f64_s (conversion i64 f64)
463 @saturating_float_to_int I64TruncSatF64U => visit_i64_trunc_sat_f64_u (conversion i64 f64)
464
465 // 0xFC prefixed operators
466 // bulk memory operations
467 // https://github.com/WebAssembly/bulk-memory-operations
468 @bulk_memory MemoryInit { data_index: u32, mem: u32 } => visit_memory_init (arity 3 -> 0)
469 @bulk_memory DataDrop { data_index: u32 } => visit_data_drop (arity 0 -> 0)
470 @bulk_memory MemoryCopy { dst_mem: u32, src_mem: u32 } => visit_memory_copy (arity 3 -> 0)
471 @bulk_memory MemoryFill { mem: u32 } => visit_memory_fill (arity 3 -> 0)
472 @bulk_memory TableInit { elem_index: u32, table: u32 } => visit_table_init (arity 3 -> 0)
473 @bulk_memory ElemDrop { elem_index: u32 } => visit_elem_drop (arity 0 -> 0)
474 @bulk_memory TableCopy { dst_table: u32, src_table: u32 } => visit_table_copy (arity 3 -> 0)
475
476 // 0xFC prefixed operators
477 // reference-types
478 // https://github.com/WebAssembly/reference-types
479 @reference_types TableFill { table: u32 } => visit_table_fill (arity 3 -> 0)
480 @reference_types TableGet { table: u32 } => visit_table_get (arity 1 -> 1)
481 @reference_types TableSet { table: u32 } => visit_table_set (arity 2 -> 0)
482 @reference_types TableGrow { table: u32 } => visit_table_grow (arity 2 -> 1)
483 @reference_types TableSize { table: u32 } => visit_table_size (arity 0 -> 1)
484
485 // OxFC prefixed operators
486 // memory control (experimental)
487 // https://github.com/WebAssembly/design/issues/1439
488 @memory_control MemoryDiscard { mem: u32 } => visit_memory_discard (arity 2 -> 0)
489
490 // 0xFE prefixed operators
491 // threads
492 // https://github.com/WebAssembly/threads
493 @threads MemoryAtomicNotify { memarg: $crate::MemArg } => visit_memory_atomic_notify (atomic rmw i32)
494 @threads MemoryAtomicWait32 { memarg: $crate::MemArg } => visit_memory_atomic_wait32 (arity 3 -> 1)
495 @threads MemoryAtomicWait64 { memarg: $crate::MemArg } => visit_memory_atomic_wait64 (arity 3 -> 1)
496 @threads AtomicFence => visit_atomic_fence (arity 0 -> 0)
497 @threads I32AtomicLoad { memarg: $crate::MemArg } => visit_i32_atomic_load (load atomic i32)
498 @threads I64AtomicLoad { memarg: $crate::MemArg } => visit_i64_atomic_load (load atomic i64)
499 @threads I32AtomicLoad8U { memarg: $crate::MemArg } => visit_i32_atomic_load8_u (load atomic i32)
500 @threads I32AtomicLoad16U { memarg: $crate::MemArg } => visit_i32_atomic_load16_u (load atomic i32)
501 @threads I64AtomicLoad8U { memarg: $crate::MemArg } => visit_i64_atomic_load8_u (load atomic i64)
502 @threads I64AtomicLoad16U { memarg: $crate::MemArg } => visit_i64_atomic_load16_u (load atomic i64)
503 @threads I64AtomicLoad32U { memarg: $crate::MemArg } => visit_i64_atomic_load32_u (load atomic i64)
504 @threads I32AtomicStore { memarg: $crate::MemArg } => visit_i32_atomic_store (store atomic i32)
505 @threads I64AtomicStore { memarg: $crate::MemArg } => visit_i64_atomic_store (store atomic i64)
506 @threads I32AtomicStore8 { memarg: $crate::MemArg } => visit_i32_atomic_store8 (store atomic i32)
507 @threads I32AtomicStore16 { memarg: $crate::MemArg } => visit_i32_atomic_store16 (store atomic i32)
508 @threads I64AtomicStore8 { memarg: $crate::MemArg } => visit_i64_atomic_store8 (store atomic i64)
509 @threads I64AtomicStore16 { memarg: $crate::MemArg } => visit_i64_atomic_store16 (store atomic i64)
510 @threads I64AtomicStore32 { memarg: $crate::MemArg } => visit_i64_atomic_store32 (store atomic i64)
511 @threads I32AtomicRmwAdd { memarg: $crate::MemArg } => visit_i32_atomic_rmw_add (atomic rmw i32)
512 @threads I64AtomicRmwAdd { memarg: $crate::MemArg } => visit_i64_atomic_rmw_add (atomic rmw i64)
513 @threads I32AtomicRmw8AddU { memarg: $crate::MemArg } => visit_i32_atomic_rmw8_add_u (atomic rmw i32)
514 @threads I32AtomicRmw16AddU { memarg: $crate::MemArg } => visit_i32_atomic_rmw16_add_u (atomic rmw i32)
515 @threads I64AtomicRmw8AddU { memarg: $crate::MemArg } => visit_i64_atomic_rmw8_add_u (atomic rmw i64)
516 @threads I64AtomicRmw16AddU { memarg: $crate::MemArg } => visit_i64_atomic_rmw16_add_u (atomic rmw i64)
517 @threads I64AtomicRmw32AddU { memarg: $crate::MemArg } => visit_i64_atomic_rmw32_add_u (atomic rmw i64)
518 @threads I32AtomicRmwSub { memarg: $crate::MemArg } => visit_i32_atomic_rmw_sub (atomic rmw i32)
519 @threads I64AtomicRmwSub { memarg: $crate::MemArg } => visit_i64_atomic_rmw_sub (atomic rmw i64)
520 @threads I32AtomicRmw8SubU { memarg: $crate::MemArg } => visit_i32_atomic_rmw8_sub_u (atomic rmw i32)
521 @threads I32AtomicRmw16SubU { memarg: $crate::MemArg } => visit_i32_atomic_rmw16_sub_u (atomic rmw i32)
522 @threads I64AtomicRmw8SubU { memarg: $crate::MemArg } => visit_i64_atomic_rmw8_sub_u (atomic rmw i64)
523 @threads I64AtomicRmw16SubU { memarg: $crate::MemArg } => visit_i64_atomic_rmw16_sub_u (atomic rmw i64)
524 @threads I64AtomicRmw32SubU { memarg: $crate::MemArg } => visit_i64_atomic_rmw32_sub_u (atomic rmw i64)
525 @threads I32AtomicRmwAnd { memarg: $crate::MemArg } => visit_i32_atomic_rmw_and (atomic rmw i32)
526 @threads I64AtomicRmwAnd { memarg: $crate::MemArg } => visit_i64_atomic_rmw_and (atomic rmw i64)
527 @threads I32AtomicRmw8AndU { memarg: $crate::MemArg } => visit_i32_atomic_rmw8_and_u (atomic rmw i32)
528 @threads I32AtomicRmw16AndU { memarg: $crate::MemArg } => visit_i32_atomic_rmw16_and_u (atomic rmw i32)
529 @threads I64AtomicRmw8AndU { memarg: $crate::MemArg } => visit_i64_atomic_rmw8_and_u (atomic rmw i64)
530 @threads I64AtomicRmw16AndU { memarg: $crate::MemArg } => visit_i64_atomic_rmw16_and_u (atomic rmw i64)
531 @threads I64AtomicRmw32AndU { memarg: $crate::MemArg } => visit_i64_atomic_rmw32_and_u (atomic rmw i64)
532 @threads I32AtomicRmwOr { memarg: $crate::MemArg } => visit_i32_atomic_rmw_or (atomic rmw i32)
533 @threads I64AtomicRmwOr { memarg: $crate::MemArg } => visit_i64_atomic_rmw_or (atomic rmw i64)
534 @threads I32AtomicRmw8OrU { memarg: $crate::MemArg } => visit_i32_atomic_rmw8_or_u (atomic rmw i32)
535 @threads I32AtomicRmw16OrU { memarg: $crate::MemArg } => visit_i32_atomic_rmw16_or_u (atomic rmw i32)
536 @threads I64AtomicRmw8OrU { memarg: $crate::MemArg } => visit_i64_atomic_rmw8_or_u (atomic rmw i64)
537 @threads I64AtomicRmw16OrU { memarg: $crate::MemArg } => visit_i64_atomic_rmw16_or_u (atomic rmw i64)
538 @threads I64AtomicRmw32OrU { memarg: $crate::MemArg } => visit_i64_atomic_rmw32_or_u (atomic rmw i64)
539 @threads I32AtomicRmwXor { memarg: $crate::MemArg } => visit_i32_atomic_rmw_xor (atomic rmw i32)
540 @threads I64AtomicRmwXor { memarg: $crate::MemArg } => visit_i64_atomic_rmw_xor (atomic rmw i64)
541 @threads I32AtomicRmw8XorU { memarg: $crate::MemArg } => visit_i32_atomic_rmw8_xor_u (atomic rmw i32)
542 @threads I32AtomicRmw16XorU { memarg: $crate::MemArg } => visit_i32_atomic_rmw16_xor_u (atomic rmw i32)
543 @threads I64AtomicRmw8XorU { memarg: $crate::MemArg } => visit_i64_atomic_rmw8_xor_u (atomic rmw i64)
544 @threads I64AtomicRmw16XorU { memarg: $crate::MemArg } => visit_i64_atomic_rmw16_xor_u (atomic rmw i64)
545 @threads I64AtomicRmw32XorU { memarg: $crate::MemArg } => visit_i64_atomic_rmw32_xor_u (atomic rmw i64)
546 @threads I32AtomicRmwXchg { memarg: $crate::MemArg } => visit_i32_atomic_rmw_xchg (atomic rmw i32)
547 @threads I64AtomicRmwXchg { memarg: $crate::MemArg } => visit_i64_atomic_rmw_xchg (atomic rmw i64)
548 @threads I32AtomicRmw8XchgU { memarg: $crate::MemArg } => visit_i32_atomic_rmw8_xchg_u (atomic rmw i32)
549 @threads I32AtomicRmw16XchgU { memarg: $crate::MemArg } => visit_i32_atomic_rmw16_xchg_u (atomic rmw i32)
550 @threads I64AtomicRmw8XchgU { memarg: $crate::MemArg } => visit_i64_atomic_rmw8_xchg_u (atomic rmw i64)
551 @threads I64AtomicRmw16XchgU { memarg: $crate::MemArg } => visit_i64_atomic_rmw16_xchg_u (atomic rmw i64)
552 @threads I64AtomicRmw32XchgU { memarg: $crate::MemArg } => visit_i64_atomic_rmw32_xchg_u (atomic rmw i64)
553 @threads I32AtomicRmwCmpxchg { memarg: $crate::MemArg } => visit_i32_atomic_rmw_cmpxchg (atomic cmpxchg i32)
554 @threads I64AtomicRmwCmpxchg { memarg: $crate::MemArg } => visit_i64_atomic_rmw_cmpxchg (atomic cmpxchg i64)
555 @threads I32AtomicRmw8CmpxchgU { memarg: $crate::MemArg } => visit_i32_atomic_rmw8_cmpxchg_u (atomic cmpxchg i32)
556 @threads I32AtomicRmw16CmpxchgU { memarg: $crate::MemArg } => visit_i32_atomic_rmw16_cmpxchg_u (atomic cmpxchg i32)
557 @threads I64AtomicRmw8CmpxchgU { memarg: $crate::MemArg } => visit_i64_atomic_rmw8_cmpxchg_u (atomic cmpxchg i64)
558 @threads I64AtomicRmw16CmpxchgU { memarg: $crate::MemArg } => visit_i64_atomic_rmw16_cmpxchg_u (atomic cmpxchg i64)
559 @threads I64AtomicRmw32CmpxchgU { memarg: $crate::MemArg } => visit_i64_atomic_rmw32_cmpxchg_u (atomic cmpxchg i64)
560
561 // Also 0xFE prefixed operators
562 // shared-everything threads
563 // https://github.com/WebAssembly/shared-everything-threads
564 @shared_everything_threads GlobalAtomicGet { ordering: $crate::Ordering, global_index: u32 } => visit_global_atomic_get (arity 0 -> 1)
565 @shared_everything_threads GlobalAtomicSet { ordering: $crate::Ordering, global_index: u32 } => visit_global_atomic_set (arity 1 -> 0)
566 @shared_everything_threads GlobalAtomicRmwAdd { ordering: $crate::Ordering, global_index: u32 } => visit_global_atomic_rmw_add (unary atomic global)
567 @shared_everything_threads GlobalAtomicRmwSub { ordering: $crate::Ordering, global_index: u32 } => visit_global_atomic_rmw_sub (unary atomic global)
568 @shared_everything_threads GlobalAtomicRmwAnd { ordering: $crate::Ordering, global_index: u32 } => visit_global_atomic_rmw_and (unary atomic global)
569 @shared_everything_threads GlobalAtomicRmwOr { ordering: $crate::Ordering, global_index: u32 } => visit_global_atomic_rmw_or (unary atomic global)
570 @shared_everything_threads GlobalAtomicRmwXor { ordering: $crate::Ordering, global_index: u32 } => visit_global_atomic_rmw_xor (unary atomic global)
571 @shared_everything_threads GlobalAtomicRmwXchg { ordering: $crate::Ordering, global_index: u32 } => visit_global_atomic_rmw_xchg (arity 1 -> 1)
572 @shared_everything_threads GlobalAtomicRmwCmpxchg { ordering: $crate::Ordering, global_index: u32 } => visit_global_atomic_rmw_cmpxchg (arity 2 -> 1)
573 @shared_everything_threads TableAtomicGet { ordering: $crate::Ordering, table_index: u32 } => visit_table_atomic_get (arity 1 -> 1)
574 @shared_everything_threads TableAtomicSet { ordering: $crate::Ordering, table_index: u32 } => visit_table_atomic_set (arity 2 -> 0)
575 @shared_everything_threads TableAtomicRmwXchg { ordering: $crate::Ordering, table_index: u32 } => visit_table_atomic_rmw_xchg (arity 2 -> 1)
576 @shared_everything_threads TableAtomicRmwCmpxchg { ordering: $crate::Ordering, table_index: u32 } => visit_table_atomic_rmw_cmpxchg (arity 3 -> 1)
577 @shared_everything_threads StructAtomicGet { ordering: $crate::Ordering, struct_type_index: u32, field_index: u32 } => visit_struct_atomic_get (arity 1 -> 1)
578 @shared_everything_threads StructAtomicGetS { ordering: $crate::Ordering, struct_type_index: u32, field_index: u32 } => visit_struct_atomic_get_s (arity 1 -> 1)
579 @shared_everything_threads StructAtomicGetU { ordering: $crate::Ordering, struct_type_index: u32, field_index: u32 } => visit_struct_atomic_get_u (arity 1 -> 1)
580 @shared_everything_threads StructAtomicSet { ordering: $crate::Ordering, struct_type_index: u32, field_index: u32 } => visit_struct_atomic_set (arity 2 -> 0)
581 @shared_everything_threads StructAtomicRmwAdd { ordering: $crate::Ordering, struct_type_index: u32, field_index: u32 } => visit_struct_atomic_rmw_add (atomic rmw struct add)
582 @shared_everything_threads StructAtomicRmwSub { ordering: $crate::Ordering, struct_type_index: u32, field_index: u32 } => visit_struct_atomic_rmw_sub (atomic rmw struct sub)
583 @shared_everything_threads StructAtomicRmwAnd { ordering: $crate::Ordering, struct_type_index: u32, field_index: u32 } => visit_struct_atomic_rmw_and (atomic rmw struct and)
584 @shared_everything_threads StructAtomicRmwOr { ordering: $crate::Ordering, struct_type_index: u32, field_index: u32 } => visit_struct_atomic_rmw_or (atomic rmw struct or)
585 @shared_everything_threads StructAtomicRmwXor { ordering: $crate::Ordering, struct_type_index: u32, field_index: u32 } => visit_struct_atomic_rmw_xor (atomic rmw struct xor)
586 @shared_everything_threads StructAtomicRmwXchg { ordering: $crate::Ordering, struct_type_index: u32, field_index: u32 } => visit_struct_atomic_rmw_xchg (arity 2 -> 1)
587 @shared_everything_threads StructAtomicRmwCmpxchg { ordering: $crate::Ordering, struct_type_index: u32, field_index: u32 } => visit_struct_atomic_rmw_cmpxchg (arity 3 -> 1)
588 @shared_everything_threads ArrayAtomicGet { ordering: $crate::Ordering, array_type_index: u32 } => visit_array_atomic_get (arity 2 -> 1)
589 @shared_everything_threads ArrayAtomicGetS { ordering: $crate::Ordering, array_type_index: u32 } => visit_array_atomic_get_s (arity 2 -> 1)
590 @shared_everything_threads ArrayAtomicGetU { ordering: $crate::Ordering, array_type_index: u32 } => visit_array_atomic_get_u (arity 2 -> 1)
591 @shared_everything_threads ArrayAtomicSet { ordering: $crate::Ordering, array_type_index: u32 } => visit_array_atomic_set (arity 3 -> 0)
592 @shared_everything_threads ArrayAtomicRmwAdd { ordering: $crate::Ordering, array_type_index: u32 } => visit_array_atomic_rmw_add (atomic rmw array add)
593 @shared_everything_threads ArrayAtomicRmwSub { ordering: $crate::Ordering, array_type_index: u32 } => visit_array_atomic_rmw_sub (atomic rmw array sub)
594 @shared_everything_threads ArrayAtomicRmwAnd { ordering: $crate::Ordering, array_type_index: u32 } => visit_array_atomic_rmw_and (atomic rmw array and)
595 @shared_everything_threads ArrayAtomicRmwOr { ordering: $crate::Ordering, array_type_index: u32 } => visit_array_atomic_rmw_or (atomic rmw array or)
596 @shared_everything_threads ArrayAtomicRmwXor { ordering: $crate::Ordering, array_type_index: u32 } => visit_array_atomic_rmw_xor (atomic rmw array xor)
597 @shared_everything_threads ArrayAtomicRmwXchg { ordering: $crate::Ordering, array_type_index: u32 } => visit_array_atomic_rmw_xchg (arity 3 -> 1)
598 @shared_everything_threads ArrayAtomicRmwCmpxchg { ordering: $crate::Ordering, array_type_index: u32 } => visit_array_atomic_rmw_cmpxchg (arity 4 -> 1)
599 @shared_everything_threads RefI31Shared => visit_ref_i31_shared (arity 1 -> 1)
600
601 // 0xFD operators
602 // 128-bit SIMD
603 // - https://github.com/webassembly/simd
604 // - https://webassembly.github.io/simd/core/binary/instructions.html
605 @simd V128Load { memarg: $crate::MemArg } => visit_v128_load (load v128)
606 @simd V128Load8x8S { memarg: $crate::MemArg } => visit_v128_load8x8_s (load v128)
607 @simd V128Load8x8U { memarg: $crate::MemArg } => visit_v128_load8x8_u (load v128)
608 @simd V128Load16x4S { memarg: $crate::MemArg } => visit_v128_load16x4_s (load v128)
609 @simd V128Load16x4U { memarg: $crate::MemArg } => visit_v128_load16x4_u (load v128)
610 @simd V128Load32x2S { memarg: $crate::MemArg } => visit_v128_load32x2_s (load v128)
611 @simd V128Load32x2U { memarg: $crate::MemArg } => visit_v128_load32x2_u (load v128)
612 @simd V128Load8Splat { memarg: $crate::MemArg } => visit_v128_load8_splat (load v128)
613 @simd V128Load16Splat { memarg: $crate::MemArg } => visit_v128_load16_splat (load v128)
614 @simd V128Load32Splat { memarg: $crate::MemArg } => visit_v128_load32_splat (load v128)
615 @simd V128Load64Splat { memarg: $crate::MemArg } => visit_v128_load64_splat (load v128)
616 @simd V128Load32Zero { memarg: $crate::MemArg } => visit_v128_load32_zero (load v128)
617 @simd V128Load64Zero { memarg: $crate::MemArg } => visit_v128_load64_zero (load v128)
618 @simd V128Store { memarg: $crate::MemArg } => visit_v128_store (store v128)
619 @simd V128Load8Lane { memarg: $crate::MemArg, lane: u8 } => visit_v128_load8_lane (load lane 16)
620 @simd V128Load16Lane { memarg: $crate::MemArg, lane: u8 } => visit_v128_load16_lane (load lane 8)
621 @simd V128Load32Lane { memarg: $crate::MemArg, lane: u8 } => visit_v128_load32_lane (load lane 4)
622 @simd V128Load64Lane { memarg: $crate::MemArg, lane: u8 } => visit_v128_load64_lane (load lane 2)
623 @simd V128Store8Lane { memarg: $crate::MemArg, lane: u8 } => visit_v128_store8_lane (store lane 16)
624 @simd V128Store16Lane { memarg: $crate::MemArg, lane: u8 } => visit_v128_store16_lane (store lane 8)
625 @simd V128Store32Lane { memarg: $crate::MemArg, lane: u8 } => visit_v128_store32_lane (store lane 4)
626 @simd V128Store64Lane { memarg: $crate::MemArg, lane: u8 } => visit_v128_store64_lane (store lane 2)
627 @simd V128Const { value: $crate::V128 } => visit_v128_const (push v128)
628 @simd I8x16Shuffle { lanes: [u8; 16] } => visit_i8x16_shuffle (arity 2 -> 1)
629 @simd I8x16ExtractLaneS { lane: u8 } => visit_i8x16_extract_lane_s (extract i32 16)
630 @simd I8x16ExtractLaneU { lane: u8 } => visit_i8x16_extract_lane_u (extract i32 16)
631 @simd I8x16ReplaceLane { lane: u8 } => visit_i8x16_replace_lane (replace i32 16)
632 @simd I16x8ExtractLaneS { lane: u8 } => visit_i16x8_extract_lane_s (extract i32 8)
633 @simd I16x8ExtractLaneU { lane: u8 } => visit_i16x8_extract_lane_u (extract i32 8)
634 @simd I16x8ReplaceLane { lane: u8 } => visit_i16x8_replace_lane (replace i32 8)
635 @simd I32x4ExtractLane { lane: u8 } => visit_i32x4_extract_lane (extract i32 4)
636 @simd I32x4ReplaceLane { lane: u8 } => visit_i32x4_replace_lane (replace i32 4)
637 @simd I64x2ExtractLane { lane: u8 } => visit_i64x2_extract_lane (extract i64 2)
638 @simd I64x2ReplaceLane { lane: u8 } => visit_i64x2_replace_lane (replace i64 2)
639 @simd F32x4ExtractLane { lane: u8 } => visit_f32x4_extract_lane (extract f32 4)
640 @simd F32x4ReplaceLane { lane: u8 } => visit_f32x4_replace_lane (replace f32 4)
641 @simd F64x2ExtractLane { lane: u8 } => visit_f64x2_extract_lane (extract f64 2)
642 @simd F64x2ReplaceLane { lane: u8 } => visit_f64x2_replace_lane (replace f64 2)
643 @simd I8x16Swizzle => visit_i8x16_swizzle (binary v128)
644 @simd I8x16Splat => visit_i8x16_splat (splat i32)
645 @simd I16x8Splat => visit_i16x8_splat (splat i32)
646 @simd I32x4Splat => visit_i32x4_splat (splat i32)
647 @simd I64x2Splat => visit_i64x2_splat (splat i64)
648 @simd F32x4Splat => visit_f32x4_splat (splat f32)
649 @simd F64x2Splat => visit_f64x2_splat (splat f64)
650 @simd I8x16Eq => visit_i8x16_eq (binary v128)
651 @simd I8x16Ne => visit_i8x16_ne (binary v128)
652 @simd I8x16LtS => visit_i8x16_lt_s (binary v128)
653 @simd I8x16LtU => visit_i8x16_lt_u (binary v128)
654 @simd I8x16GtS => visit_i8x16_gt_s (binary v128)
655 @simd I8x16GtU => visit_i8x16_gt_u (binary v128)
656 @simd I8x16LeS => visit_i8x16_le_s (binary v128)
657 @simd I8x16LeU => visit_i8x16_le_u (binary v128)
658 @simd I8x16GeS => visit_i8x16_ge_s (binary v128)
659 @simd I8x16GeU => visit_i8x16_ge_u (binary v128)
660 @simd I16x8Eq => visit_i16x8_eq (binary v128)
661 @simd I16x8Ne => visit_i16x8_ne (binary v128)
662 @simd I16x8LtS => visit_i16x8_lt_s (binary v128)
663 @simd I16x8LtU => visit_i16x8_lt_u (binary v128)
664 @simd I16x8GtS => visit_i16x8_gt_s (binary v128)
665 @simd I16x8GtU => visit_i16x8_gt_u (binary v128)
666 @simd I16x8LeS => visit_i16x8_le_s (binary v128)
667 @simd I16x8LeU => visit_i16x8_le_u (binary v128)
668 @simd I16x8GeS => visit_i16x8_ge_s (binary v128)
669 @simd I16x8GeU => visit_i16x8_ge_u (binary v128)
670 @simd I32x4Eq => visit_i32x4_eq (binary v128)
671 @simd I32x4Ne => visit_i32x4_ne (binary v128)
672 @simd I32x4LtS => visit_i32x4_lt_s (binary v128)
673 @simd I32x4LtU => visit_i32x4_lt_u (binary v128)
674 @simd I32x4GtS => visit_i32x4_gt_s (binary v128)
675 @simd I32x4GtU => visit_i32x4_gt_u (binary v128)
676 @simd I32x4LeS => visit_i32x4_le_s (binary v128)
677 @simd I32x4LeU => visit_i32x4_le_u (binary v128)
678 @simd I32x4GeS => visit_i32x4_ge_s (binary v128)
679 @simd I32x4GeU => visit_i32x4_ge_u (binary v128)
680 @simd I64x2Eq => visit_i64x2_eq (binary v128)
681 @simd I64x2Ne => visit_i64x2_ne (binary v128)
682 @simd I64x2LtS => visit_i64x2_lt_s (binary v128)
683 @simd I64x2GtS => visit_i64x2_gt_s (binary v128)
684 @simd I64x2LeS => visit_i64x2_le_s (binary v128)
685 @simd I64x2GeS => visit_i64x2_ge_s (binary v128)
686 @simd F32x4Eq => visit_f32x4_eq (binary v128f)
687 @simd F32x4Ne => visit_f32x4_ne (binary v128f)
688 @simd F32x4Lt => visit_f32x4_lt (binary v128f)
689 @simd F32x4Gt => visit_f32x4_gt (binary v128f)
690 @simd F32x4Le => visit_f32x4_le (binary v128f)
691 @simd F32x4Ge => visit_f32x4_ge (binary v128f)
692 @simd F64x2Eq => visit_f64x2_eq (binary v128f)
693 @simd F64x2Ne => visit_f64x2_ne (binary v128f)
694 @simd F64x2Lt => visit_f64x2_lt (binary v128f)
695 @simd F64x2Gt => visit_f64x2_gt (binary v128f)
696 @simd F64x2Le => visit_f64x2_le (binary v128f)
697 @simd F64x2Ge => visit_f64x2_ge (binary v128f)
698 @simd V128Not => visit_v128_not (unary v128)
699 @simd V128And => visit_v128_and (binary v128)
700 @simd V128AndNot => visit_v128_andnot (binary v128)
701 @simd V128Or => visit_v128_or (binary v128)
702 @simd V128Xor => visit_v128_xor (binary v128)
703 @simd V128Bitselect => visit_v128_bitselect (ternary v128)
704 @simd V128AnyTrue => visit_v128_any_true (test v128)
705 @simd I8x16Abs => visit_i8x16_abs (unary v128)
706 @simd I8x16Neg => visit_i8x16_neg (unary v128)
707 @simd I8x16Popcnt => visit_i8x16_popcnt (unary v128)
708 @simd I8x16AllTrue => visit_i8x16_all_true (test v128)
709 @simd I8x16Bitmask => visit_i8x16_bitmask (test v128)
710 @simd I8x16NarrowI16x8S => visit_i8x16_narrow_i16x8_s (binary v128)
711 @simd I8x16NarrowI16x8U => visit_i8x16_narrow_i16x8_u (binary v128)
712 @simd I8x16Shl => visit_i8x16_shl (shift v128)
713 @simd I8x16ShrS => visit_i8x16_shr_s (shift v128)
714 @simd I8x16ShrU => visit_i8x16_shr_u (shift v128)
715 @simd I8x16Add => visit_i8x16_add (binary v128)
716 @simd I8x16AddSatS => visit_i8x16_add_sat_s (binary v128)
717 @simd I8x16AddSatU => visit_i8x16_add_sat_u (binary v128)
718 @simd I8x16Sub => visit_i8x16_sub (binary v128)
719 @simd I8x16SubSatS => visit_i8x16_sub_sat_s (binary v128)
720 @simd I8x16SubSatU => visit_i8x16_sub_sat_u (binary v128)
721 @simd I8x16MinS => visit_i8x16_min_s (binary v128)
722 @simd I8x16MinU => visit_i8x16_min_u (binary v128)
723 @simd I8x16MaxS => visit_i8x16_max_s (binary v128)
724 @simd I8x16MaxU => visit_i8x16_max_u (binary v128)
725 @simd I8x16AvgrU => visit_i8x16_avgr_u (binary v128)
726 @simd I16x8ExtAddPairwiseI8x16S => visit_i16x8_extadd_pairwise_i8x16_s (unary v128)
727 @simd I16x8ExtAddPairwiseI8x16U => visit_i16x8_extadd_pairwise_i8x16_u (unary v128)
728 @simd I16x8Abs => visit_i16x8_abs (unary v128)
729 @simd I16x8Neg => visit_i16x8_neg (unary v128)
730 @simd I16x8Q15MulrSatS => visit_i16x8_q15mulr_sat_s (binary v128)
731 @simd I16x8AllTrue => visit_i16x8_all_true (test v128)
732 @simd I16x8Bitmask => visit_i16x8_bitmask (test v128)
733 @simd I16x8NarrowI32x4S => visit_i16x8_narrow_i32x4_s (binary v128)
734 @simd I16x8NarrowI32x4U => visit_i16x8_narrow_i32x4_u (binary v128)
735 @simd I16x8ExtendLowI8x16S => visit_i16x8_extend_low_i8x16_s (unary v128)
736 @simd I16x8ExtendHighI8x16S => visit_i16x8_extend_high_i8x16_s (unary v128)
737 @simd I16x8ExtendLowI8x16U => visit_i16x8_extend_low_i8x16_u (unary v128)
738 @simd I16x8ExtendHighI8x16U => visit_i16x8_extend_high_i8x16_u (unary v128)
739 @simd I16x8Shl => visit_i16x8_shl (shift v128)
740 @simd I16x8ShrS => visit_i16x8_shr_s (shift v128)
741 @simd I16x8ShrU => visit_i16x8_shr_u (shift v128)
742 @simd I16x8Add => visit_i16x8_add (binary v128)
743 @simd I16x8AddSatS => visit_i16x8_add_sat_s (binary v128)
744 @simd I16x8AddSatU => visit_i16x8_add_sat_u (binary v128)
745 @simd I16x8Sub => visit_i16x8_sub (binary v128)
746 @simd I16x8SubSatS => visit_i16x8_sub_sat_s (binary v128)
747 @simd I16x8SubSatU => visit_i16x8_sub_sat_u (binary v128)
748 @simd I16x8Mul => visit_i16x8_mul (binary v128)
749 @simd I16x8MinS => visit_i16x8_min_s (binary v128)
750 @simd I16x8MinU => visit_i16x8_min_u (binary v128)
751 @simd I16x8MaxS => visit_i16x8_max_s (binary v128)
752 @simd I16x8MaxU => visit_i16x8_max_u (binary v128)
753 @simd I16x8AvgrU => visit_i16x8_avgr_u (binary v128)
754 @simd I16x8ExtMulLowI8x16S => visit_i16x8_extmul_low_i8x16_s (binary v128)
755 @simd I16x8ExtMulHighI8x16S => visit_i16x8_extmul_high_i8x16_s (binary v128)
756 @simd I16x8ExtMulLowI8x16U => visit_i16x8_extmul_low_i8x16_u (binary v128)
757 @simd I16x8ExtMulHighI8x16U => visit_i16x8_extmul_high_i8x16_u (binary v128)
758 @simd I32x4ExtAddPairwiseI16x8S => visit_i32x4_extadd_pairwise_i16x8_s (unary v128)
759 @simd I32x4ExtAddPairwiseI16x8U => visit_i32x4_extadd_pairwise_i16x8_u (unary v128)
760 @simd I32x4Abs => visit_i32x4_abs (unary v128)
761 @simd I32x4Neg => visit_i32x4_neg (unary v128)
762 @simd I32x4AllTrue => visit_i32x4_all_true (test v128)
763 @simd I32x4Bitmask => visit_i32x4_bitmask (test v128)
764 @simd I32x4ExtendLowI16x8S => visit_i32x4_extend_low_i16x8_s (unary v128)
765 @simd I32x4ExtendHighI16x8S => visit_i32x4_extend_high_i16x8_s (unary v128)
766 @simd I32x4ExtendLowI16x8U => visit_i32x4_extend_low_i16x8_u (unary v128)
767 @simd I32x4ExtendHighI16x8U => visit_i32x4_extend_high_i16x8_u (unary v128)
768 @simd I32x4Shl => visit_i32x4_shl (shift v128)
769 @simd I32x4ShrS => visit_i32x4_shr_s (shift v128)
770 @simd I32x4ShrU => visit_i32x4_shr_u (shift v128)
771 @simd I32x4Add => visit_i32x4_add (binary v128)
772 @simd I32x4Sub => visit_i32x4_sub (binary v128)
773 @simd I32x4Mul => visit_i32x4_mul (binary v128)
774 @simd I32x4MinS => visit_i32x4_min_s (binary v128)
775 @simd I32x4MinU => visit_i32x4_min_u (binary v128)
776 @simd I32x4MaxS => visit_i32x4_max_s (binary v128)
777 @simd I32x4MaxU => visit_i32x4_max_u (binary v128)
778 @simd I32x4DotI16x8S => visit_i32x4_dot_i16x8_s (binary v128)
779 @simd I32x4ExtMulLowI16x8S => visit_i32x4_extmul_low_i16x8_s (binary v128)
780 @simd I32x4ExtMulHighI16x8S => visit_i32x4_extmul_high_i16x8_s (binary v128)
781 @simd I32x4ExtMulLowI16x8U => visit_i32x4_extmul_low_i16x8_u (binary v128)
782 @simd I32x4ExtMulHighI16x8U => visit_i32x4_extmul_high_i16x8_u (binary v128)
783 @simd I64x2Abs => visit_i64x2_abs (unary v128)
784 @simd I64x2Neg => visit_i64x2_neg (unary v128)
785 @simd I64x2AllTrue => visit_i64x2_all_true (test v128)
786 @simd I64x2Bitmask => visit_i64x2_bitmask (test v128)
787 @simd I64x2ExtendLowI32x4S => visit_i64x2_extend_low_i32x4_s (unary v128)
788 @simd I64x2ExtendHighI32x4S => visit_i64x2_extend_high_i32x4_s (unary v128)
789 @simd I64x2ExtendLowI32x4U => visit_i64x2_extend_low_i32x4_u (unary v128)
790 @simd I64x2ExtendHighI32x4U => visit_i64x2_extend_high_i32x4_u (unary v128)
791 @simd I64x2Shl => visit_i64x2_shl (shift v128)
792 @simd I64x2ShrS => visit_i64x2_shr_s (shift v128)
793 @simd I64x2ShrU => visit_i64x2_shr_u (shift v128)
794 @simd I64x2Add => visit_i64x2_add (binary v128)
795 @simd I64x2Sub => visit_i64x2_sub (binary v128)
796 @simd I64x2Mul => visit_i64x2_mul (binary v128)
797 @simd I64x2ExtMulLowI32x4S => visit_i64x2_extmul_low_i32x4_s (binary v128)
798 @simd I64x2ExtMulHighI32x4S => visit_i64x2_extmul_high_i32x4_s (binary v128)
799 @simd I64x2ExtMulLowI32x4U => visit_i64x2_extmul_low_i32x4_u (binary v128)
800 @simd I64x2ExtMulHighI32x4U => visit_i64x2_extmul_high_i32x4_u (binary v128)
801 @simd F32x4Ceil => visit_f32x4_ceil (unary v128f)
802 @simd F32x4Floor => visit_f32x4_floor (unary v128f)
803 @simd F32x4Trunc => visit_f32x4_trunc (unary v128f)
804 @simd F32x4Nearest => visit_f32x4_nearest (unary v128f)
805 @simd F32x4Abs => visit_f32x4_abs (unary v128f)
806 @simd F32x4Neg => visit_f32x4_neg (unary v128f)
807 @simd F32x4Sqrt => visit_f32x4_sqrt (unary v128f)
808 @simd F32x4Add => visit_f32x4_add (binary v128f)
809 @simd F32x4Sub => visit_f32x4_sub (binary v128f)
810 @simd F32x4Mul => visit_f32x4_mul (binary v128f)
811 @simd F32x4Div => visit_f32x4_div (binary v128f)
812 @simd F32x4Min => visit_f32x4_min (binary v128f)
813 @simd F32x4Max => visit_f32x4_max (binary v128f)
814 @simd F32x4PMin => visit_f32x4_pmin (binary v128f)
815 @simd F32x4PMax => visit_f32x4_pmax (binary v128f)
816 @simd F64x2Ceil => visit_f64x2_ceil (unary v128f)
817 @simd F64x2Floor => visit_f64x2_floor (unary v128f)
818 @simd F64x2Trunc => visit_f64x2_trunc (unary v128f)
819 @simd F64x2Nearest => visit_f64x2_nearest (unary v128f)
820 @simd F64x2Abs => visit_f64x2_abs (unary v128f)
821 @simd F64x2Neg => visit_f64x2_neg (unary v128f)
822 @simd F64x2Sqrt => visit_f64x2_sqrt (unary v128f)
823 @simd F64x2Add => visit_f64x2_add (binary v128f)
824 @simd F64x2Sub => visit_f64x2_sub (binary v128f)
825 @simd F64x2Mul => visit_f64x2_mul (binary v128f)
826 @simd F64x2Div => visit_f64x2_div (binary v128f)
827 @simd F64x2Min => visit_f64x2_min (binary v128f)
828 @simd F64x2Max => visit_f64x2_max (binary v128f)
829 @simd F64x2PMin => visit_f64x2_pmin (binary v128f)
830 @simd F64x2PMax => visit_f64x2_pmax (binary v128f)
831 @simd I32x4TruncSatF32x4S => visit_i32x4_trunc_sat_f32x4_s (unary v128f)
832 @simd I32x4TruncSatF32x4U => visit_i32x4_trunc_sat_f32x4_u (unary v128f)
833 @simd F32x4ConvertI32x4S => visit_f32x4_convert_i32x4_s (unary v128f)
834 @simd F32x4ConvertI32x4U => visit_f32x4_convert_i32x4_u (unary v128f)
835 @simd I32x4TruncSatF64x2SZero => visit_i32x4_trunc_sat_f64x2_s_zero (unary v128f)
836 @simd I32x4TruncSatF64x2UZero => visit_i32x4_trunc_sat_f64x2_u_zero (unary v128f)
837 @simd F64x2ConvertLowI32x4S => visit_f64x2_convert_low_i32x4_s (unary v128f)
838 @simd F64x2ConvertLowI32x4U => visit_f64x2_convert_low_i32x4_u (unary v128f)
839 @simd F32x4DemoteF64x2Zero => visit_f32x4_demote_f64x2_zero (unary v128f)
840 @simd F64x2PromoteLowF32x4 => visit_f64x2_promote_low_f32x4 (unary v128f)
841
842 // Relaxed SIMD operators
843 // https://github.com/WebAssembly/relaxed-simd
844 @relaxed_simd I8x16RelaxedSwizzle => visit_i8x16_relaxed_swizzle (binary v128)
845 @relaxed_simd I32x4RelaxedTruncF32x4S => visit_i32x4_relaxed_trunc_f32x4_s (unary v128)
846 @relaxed_simd I32x4RelaxedTruncF32x4U => visit_i32x4_relaxed_trunc_f32x4_u (unary v128)
847 @relaxed_simd I32x4RelaxedTruncF64x2SZero => visit_i32x4_relaxed_trunc_f64x2_s_zero (unary v128)
848 @relaxed_simd I32x4RelaxedTruncF64x2UZero => visit_i32x4_relaxed_trunc_f64x2_u_zero (unary v128)
849 @relaxed_simd F32x4RelaxedMadd => visit_f32x4_relaxed_madd (ternary v128)
850 @relaxed_simd F32x4RelaxedNmadd => visit_f32x4_relaxed_nmadd (ternary v128)
851 @relaxed_simd F64x2RelaxedMadd => visit_f64x2_relaxed_madd (ternary v128)
852 @relaxed_simd F64x2RelaxedNmadd => visit_f64x2_relaxed_nmadd (ternary v128)
853 @relaxed_simd I8x16RelaxedLaneselect => visit_i8x16_relaxed_laneselect (ternary v128)
854 @relaxed_simd I16x8RelaxedLaneselect => visit_i16x8_relaxed_laneselect (ternary v128)
855 @relaxed_simd I32x4RelaxedLaneselect => visit_i32x4_relaxed_laneselect (ternary v128)
856 @relaxed_simd I64x2RelaxedLaneselect => visit_i64x2_relaxed_laneselect (ternary v128)
857 @relaxed_simd F32x4RelaxedMin => visit_f32x4_relaxed_min (binary v128)
858 @relaxed_simd F32x4RelaxedMax => visit_f32x4_relaxed_max (binary v128)
859 @relaxed_simd F64x2RelaxedMin => visit_f64x2_relaxed_min (binary v128)
860 @relaxed_simd F64x2RelaxedMax => visit_f64x2_relaxed_max (binary v128)
861 @relaxed_simd I16x8RelaxedQ15mulrS => visit_i16x8_relaxed_q15mulr_s (binary v128)
862 @relaxed_simd I16x8RelaxedDotI8x16I7x16S => visit_i16x8_relaxed_dot_i8x16_i7x16_s (binary v128)
863 @relaxed_simd I32x4RelaxedDotI8x16I7x16AddS => visit_i32x4_relaxed_dot_i8x16_i7x16_add_s (ternary v128)
864
865 // Typed Function references
866 @function_references CallRef { type_index: u32 } => visit_call_ref (arity 1 type -> type)
867 @function_references ReturnCallRef { type_index: u32 } => visit_return_call_ref (arity 1 type -> 0)
868 @function_references RefAsNonNull => visit_ref_as_non_null (arity 1 -> 1)
869 @function_references BrOnNull { relative_depth: u32 } => visit_br_on_null (arity 1 br -> 1 br)
870 @function_references BrOnNonNull { relative_depth: u32 } => visit_br_on_non_null (arity br -> br -1)
871
872 // Stack switching
873 @stack_switching ContNew { cont_type_index: u32 } => visit_cont_new (arity 1 -> 1)
874 @stack_switching ContBind { argument_index: u32, result_index: u32 } => visit_cont_bind (arity type_diff 1 -> 1)
875 @stack_switching Suspend { tag_index: u32 } => visit_suspend (arity tag -> tag)
876 @stack_switching Resume { cont_type_index: u32, resume_table: $crate::ResumeTable } => visit_resume (arity 1 type -> type)
877 @stack_switching ResumeThrow { cont_type_index: u32, tag_index: u32, resume_table: $crate::ResumeTable } => visit_resume_throw (arity 1 tag -> type)
878 @stack_switching Switch { cont_type_index: u32, tag_index: u32 } => visit_switch (arity type -> ~switch)
879
880 @wide_arithmetic I64Add128 => visit_i64_add128 (arity 4 -> 2)
881 @wide_arithmetic I64Sub128 => visit_i64_sub128 (arity 4 -> 2)
882 @wide_arithmetic I64MulWideS => visit_i64_mul_wide_s (arity 2 -> 2)
883 @wide_arithmetic I64MulWideU => visit_i64_mul_wide_u (arity 2 -> 2)
884 }
885 };
886}
887
888macro_rules! format_err {
889 ($offset:expr, $($arg:tt)*) => {
890 crate::BinaryReaderError::fmt(format_args!($($arg)*), $offset)
891 }
892}
893
894macro_rules! bail {
895 ($($arg:tt)*) => {return Err(format_err!($($arg)*))}
896}
897
898pub use crate::arity::*;
899pub use crate::binary_reader::{BinaryReader, BinaryReaderError, Result};
900pub use crate::features::*;
901pub use crate::parser::*;
902pub use crate::readers::*;
903
904mod arity;
905mod binary_reader;
906mod features;
907mod limits;
908mod parser;
909mod readers;
910
911#[cfg(feature = "validate")]
912mod resources;
913#[cfg(feature = "validate")]
914mod validator;
915#[cfg(feature = "validate")]
916pub use crate::resources::*;
917#[cfg(feature = "validate")]
918pub use crate::validator::*;
919
920#[cfg(feature = "validate")]
921pub mod collections;
922