wasm/validation/
code.rs

1use core::iter;
2
3use alloc::collections::btree_set::BTreeSet;
4use alloc::vec::Vec;
5
6use crate::core::error::DecodingError;
7use crate::core::indices::{
8    read_label_idx, DataIdx, ElemIdx, ExtendedIdxVec, FuncIdx, GlobalIdx, IdxVec, LocalIdx, MemIdx,
9    TableIdx, TypeIdx,
10};
11use crate::core::reader::section_header::{SectionHeader, SectionTy};
12use crate::core::reader::span::Span;
13use crate::core::reader::types::element::ElemType;
14use crate::core::reader::types::global::Global;
15use crate::core::reader::types::memarg::MemArg;
16use crate::core::reader::types::{BlockType, FuncType, MemType, NumType, TableType, ValType};
17use crate::core::reader::WasmReader;
18use crate::core::sidetable::{Sidetable, SidetableEntry};
19use crate::core::utils::ToUsizeExt;
20use crate::validation_stack::{LabelInfo, ValidationStack};
21use crate::{RefType, ValidationError};
22
23/// # Safety
24///
25/// The caller must ensure that all index values passed into this function are
26/// valid in the relevant `IdxVec`. The following table lists all index types
27/// and their respective `IdxVec` types:
28///
29/// | Index | `IdxVec` |
30/// | ----- | -------- |
31/// | [`TypeIdx`] | [`IdxVec<TypeIdx, FuncType>`] |
32/// | [`FuncIdx`] | [`IdxVec<FuncIdx, TypeIdx>`] contained in [`ExtendedIdxVec<FuncIdx, TypeIdx>`] |
33/// | [`TableIdx`] | [`IdxVec<TableIdx, TableType>`] |
34#[allow(clippy::too_many_arguments)]
35pub unsafe fn validate_code_section(
36    wasm: &mut WasmReader,
37    section_header: SectionHeader,
38    fn_types: &IdxVec<TypeIdx, FuncType>,
39    c_funcs: &ExtendedIdxVec<FuncIdx, TypeIdx>,
40    c_globals: &IdxVec<GlobalIdx, Global>,
41    c_mems: &IdxVec<MemIdx, MemType>,
42    data_count: Option<u32>,
43    c_tables: &IdxVec<TableIdx, TableType>,
44    c_elems: &IdxVec<ElemIdx, ElemType>,
45    validation_context_refs: &BTreeSet<FuncIdx>,
46    sidetable: &mut Sidetable,
47) -> Result<Vec<(Span, usize)>, ValidationError> {
48    assert_eq!(section_header.ty, SectionTy::Code);
49    let code_block_spans_stps = wasm.read_vec_enumerated(|wasm, idx| {
50        // We need to offset the index by the number of functions that were
51        // imported. Imported functions always live at the start of the index
52        // space.
53        let ty_idx = c_funcs
54            .iter_local_definitions()
55            .nth(idx.into_usize())
56            .ok_or(ValidationError::FunctionAndCodeSectionsHaveDifferentLengths)?;
57
58        // SAFETY: The caller ensures that all passed `TypeIdx` values,
59        // including this one, are valid in this `IdxVec<TypeIdx, FuncType>`.
60        let func_ty: FuncType = unsafe { fn_types.get(*ty_idx).clone() };
61
62        let func_size = wasm.read_var_u32()?;
63        let func_block = wasm.make_span(func_size.into_usize())?;
64        let previous_pc = wasm.pc;
65
66        let locals = {
67            let params = func_ty.params.valtypes.iter().cloned();
68            let declared_locals = read_declared_locals(wasm)?;
69            params.chain(declared_locals).collect::<Vec<ValType>>()
70        };
71
72        let mut stack = ValidationStack::new_for_func(func_ty);
73        let stp = sidetable.len();
74
75        // SAFETY: The caller ensures the same safety requirements for the same
76        // unmodified index values.
77        unsafe {
78            read_instructions(
79                wasm,
80                &mut stack,
81                sidetable,
82                &locals,
83                c_globals,
84                fn_types,
85                c_funcs.inner(),
86                c_mems,
87                data_count,
88                c_tables,
89                c_elems,
90                validation_context_refs,
91            )
92        }?;
93
94        // Check if there were unread trailing instructions after the last END
95        if previous_pc + func_size.into_usize() != wasm.pc {
96            return Err(ValidationError::CodeExprHasTrailingInstructions);
97        }
98
99        Ok((func_block, stp))
100    })?;
101
102    trace!(
103        "Read code section. Found {} code blocks",
104        code_block_spans_stps.len()
105    );
106
107    Ok(code_block_spans_stps)
108}
109
110pub fn read_declared_locals(wasm: &mut WasmReader) -> Result<Vec<ValType>, DecodingError> {
111    let locals = wasm.read_vec(|wasm| {
112        let n = wasm.read_var_u32()?.into_usize();
113        let valtype = ValType::read(wasm)?;
114
115        Ok((n, valtype))
116    })?;
117
118    // these checks are related to the official test suite binary.wast file, the first 2 assert_malformed's starting at line 350
119    // we check to not have more than 2^32-1 locals, and if that number is okay, we then get to instantiate them all
120    // this is because the flat_map and collect take an insane amount of time
121    // in total, these 2 tests take more than 240s
122    let mut total_no_of_locals: u64 = 0;
123    for local in &locals {
124        let temp = local.0 as u64;
125        if temp > u32::MAX.into() {
126            return Err(DecodingError::TooManyLocals(total_no_of_locals));
127        };
128        total_no_of_locals = match total_no_of_locals.checked_add(temp) {
129            None => return Err(DecodingError::TooManyLocals(total_no_of_locals)),
130            Some(n) => n,
131        }
132    }
133
134    if total_no_of_locals > u32::MAX.into() {
135        return Err(DecodingError::TooManyLocals(total_no_of_locals));
136    }
137
138    // Flatten local types for easier representation where n > 1
139    let locals = locals
140        .into_iter()
141        .flat_map(|entry| iter::repeat_n(entry.1, entry.0))
142        .collect::<Vec<ValType>>();
143
144    Ok(locals)
145}
146
147/// Validates a specific branch to some label by its index `label_idx`.
148/// Branches are generated by branching instructions and some can even generate multiple branches.
149fn validate_branch_and_generate_sidetable_entry(
150    _wasm: &WasmReader,
151    label_idx: u32,
152    stack: &mut ValidationStack,
153    sidetable: &mut Sidetable,
154    unify_to_expected_types: bool,
155) -> Result<(), ValidationError> {
156    stack.assert_val_types_of_label_jump_types_on_top(label_idx, unify_to_expected_types)?;
157
158    // Get stack length before we mutably borrow the label's `CtrlStackEntry`.
159    let stack_len = stack.len();
160
161    let index_of_label_in_ctrl_stack = stack
162        .ctrl_stack
163        .len()
164        .checked_sub(label_idx.into_usize())
165        .and_then(|i| i.checked_sub(1));
166
167    let targeted_ctrl_block_entry = index_of_label_in_ctrl_stack
168        .and_then(|idx| stack.ctrl_stack.get_mut(idx))
169        .ok_or(ValidationError::InvalidLabelIdx(label_idx))?;
170
171    let valcnt = targeted_ctrl_block_entry.label_types().len();
172    let popcnt = stack_len - targeted_ctrl_block_entry.height - valcnt;
173
174    // Now we generate the actual sidetable entry.
175    //
176    // This entry needs to be backpatched later, except for when it targets a label generated
177    // by a `loop` instruction. This is because loops are the only instruction able to perform
178    // backwards jumps, so we already know the exact instruction and sidetable pointers for that label.
179    // For all other types of labels (blocks, ifs, functions) we generate a partial sidetable entry.
180    //
181    // This partial sidetable entry temporarily stores dummy values in the `pc` and `stp` fields until we reach
182    // the `end` of this label's scope,
183    let stp_here = sidetable.len();
184    sidetable.push(SidetableEntry {
185        pc: usize::MAX,
186        stp: usize::MAX,
187        popcnt,
188        valcnt,
189    });
190
191    match &mut targeted_ctrl_block_entry.label_info {
192        LabelInfo::Block { stps_to_backpatch } => stps_to_backpatch.push(stp_here),
193        LabelInfo::Loop { ip, stp } => {
194            //we already know where to jump to for loops
195            sidetable[stp_here].pc = *ip;
196            sidetable[stp_here].stp = *stp;
197        }
198        LabelInfo::If {
199            stps_to_backpatch, ..
200        } => stps_to_backpatch.push(stp_here),
201        LabelInfo::Func { stps_to_backpatch } => stps_to_backpatch.push(stp_here),
202        LabelInfo::Untyped => {
203            unreachable!("this label is for untyped wasm sequences")
204        }
205    }
206    Ok(())
207}
208
209/// # Safety
210///
211/// The caller must ensure that all index values passed into this function are
212/// valid in the relevant `IdxVec`. The following table lists all index types
213/// and their respective `IdxVec` types:
214///
215/// | Index | `IdxVec` |
216/// |-------|----------|
217/// | [`TypeIdx`] | [`IdxVec<TypeIdx, FuncType>`] |
218/// | [`FuncIdx`] | [`IdxVec<FuncIdx, TypeIdx>`] |
219/// | [`TableIdx`] | [`IdxVec<TableIdx, TableType>`] |
220#[allow(clippy::too_many_arguments)]
221unsafe fn read_instructions(
222    wasm: &mut WasmReader,
223    stack: &mut ValidationStack,
224    sidetable: &mut Sidetable,
225    locals: &[ValType],
226    c_globals: &IdxVec<GlobalIdx, Global>,
227    fn_types: &IdxVec<TypeIdx, FuncType>,
228    c_funcs: &IdxVec<FuncIdx, TypeIdx>,
229    c_mems: &IdxVec<MemIdx, MemType>,
230    data_count: Option<u32>,
231    c_tables: &IdxVec<TableIdx, TableType>,
232    c_elems: &IdxVec<ElemIdx, ElemType>,
233    validation_context_refs: &BTreeSet<FuncIdx>,
234) -> Result<(), ValidationError> {
235    loop {
236        let Ok(first_instr_byte) = wasm.read_u8() else {
237            // TODO only do this if EOF
238            return Err(ValidationError::ExprMissingEnd);
239        };
240
241        #[cfg(feature = "log")]
242        crate::core::utils::print_beautiful_instruction_name_1_byte(first_instr_byte, wasm.pc);
243
244        use crate::core::reader::types::opcode::*;
245        match first_instr_byte {
246            // nop: [] -> []
247            NOP => {}
248            // block: [] -> [t*2]
249            BLOCK => {
250                let block_ty = {
251                    let block_ty = BlockType::read_and_validate(wasm, fn_types)?;
252                    // SAFETY: The block type was just validated using the same
253                    // `IdxVec<TypeIdx, FuncType>`.
254                    unsafe { block_ty.as_func_type(fn_types) }?
255                };
256                let label_info = LabelInfo::Block {
257                    stps_to_backpatch: Vec::new(),
258                };
259                // The types are explicitly popped and pushed in
260                // https://webassembly.github.io/spec/core/appendix/algorithm.html
261                // therefore types on the stack might change.
262                stack.assert_push_ctrl(label_info, block_ty, true)?;
263            }
264            LOOP => {
265                let block_ty = {
266                    let block_ty = BlockType::read_and_validate(wasm, fn_types)?;
267                    // SAFETY: The block type was just validated using the same
268                    // `IdxVec<TypeIdx, FuncType>`.
269                    unsafe { block_ty.as_func_type(fn_types) }?
270                };
271                let label_info = LabelInfo::Loop {
272                    ip: wasm.pc,
273                    stp: sidetable.len(),
274                };
275                // The types are explicitly popped and pushed in
276                // https://webassembly.github.io/spec/core/appendix/algorithm.html
277                // therefore types on the stack might change.
278                stack.assert_push_ctrl(label_info, block_ty, true)?;
279            }
280            IF => {
281                let block_ty = {
282                    let block_ty = BlockType::read_and_validate(wasm, fn_types)?;
283                    // SAFETY: The block type was just validated using the same
284                    // `IdxVec<TypeIdx, FuncType>`.
285                    unsafe { block_ty.as_func_type(fn_types) }?
286                };
287
288                stack.assert_pop_val_type(ValType::NumType(NumType::I32))?;
289
290                let stp_here = sidetable.len();
291                sidetable.push(SidetableEntry {
292                    pc: usize::MAX,
293                    stp: usize::MAX,
294                    popcnt: 0,
295                    valcnt: block_ty.params.valtypes.len(),
296                });
297
298                let label_info = LabelInfo::If {
299                    stp: stp_here,
300                    stps_to_backpatch: Vec::new(),
301                };
302                // The types are explicitly popped and pushed in
303                // https://webassembly.github.io/spec/core/appendix/algorithm.html
304                // therefore types on the stack might change.
305                stack.assert_push_ctrl(label_info, block_ty, true)?;
306            }
307            ELSE => {
308                let (mut label_info, block_ty) = stack.assert_pop_ctrl(true)?;
309                if let LabelInfo::If {
310                    stp,
311                    stps_to_backpatch,
312                } = &mut label_info
313                {
314                    if *stp == usize::MAX {
315                        //this If was previously matched with an else already, it is already backpatched!
316                        return Err(ValidationError::ElseWithoutMatchingIf);
317                    }
318                    let stp_here = sidetable.len();
319                    sidetable.push(SidetableEntry {
320                        pc: usize::MAX,
321                        stp: usize::MAX,
322                        popcnt: 0,
323                        valcnt: block_ty.returns.valtypes.len(),
324                    });
325                    stps_to_backpatch.push(stp_here);
326
327                    sidetable[*stp].pc = wasm.pc;
328                    sidetable[*stp].stp = sidetable.len();
329
330                    *stp = usize::MAX; // mark this If as backpatched
331
332                    for valtype in block_ty.returns.valtypes.iter().rev() {
333                        stack.assert_pop_val_type(*valtype)?;
334                    }
335
336                    for valtype in block_ty.params.valtypes.iter() {
337                        stack.push_valtype(*valtype);
338                    }
339                    // The types are explicitly popped and pushed in
340                    // https://webassembly.github.io/spec/core/appendix/algorithm.html
341                    // therefore types on the stack might change.
342                    stack.assert_push_ctrl(label_info, block_ty, true)?;
343                } else {
344                    return Err(ValidationError::ElseWithoutMatchingIf);
345                }
346            }
347            BR => {
348                let label_idx = read_label_idx(wasm)?;
349                validate_branch_and_generate_sidetable_entry(
350                    wasm, label_idx, stack, sidetable, false,
351                )?;
352                stack.make_unspecified()?;
353            }
354            BR_IF => {
355                let label_idx = read_label_idx(wasm)?;
356                stack.assert_pop_val_type(ValType::NumType(NumType::I32))?;
357                // The types are explicitly popped and pushed in
358                // https://webassembly.github.io/spec/core/appendix/algorithm.html
359                // therefore types on the stack might change.
360                validate_branch_and_generate_sidetable_entry(
361                    wasm, label_idx, stack, sidetable, true,
362                )?;
363            }
364            BR_TABLE => {
365                let label_vec = wasm.read_vec(read_label_idx)?;
366                let max_label_idx = read_label_idx(wasm)?;
367                stack.assert_pop_val_type(ValType::NumType(NumType::I32))?;
368                for label_idx in &label_vec {
369                    validate_branch_and_generate_sidetable_entry(
370                        wasm, *label_idx, stack, sidetable, false,
371                    )?;
372                }
373
374                validate_branch_and_generate_sidetable_entry(
375                    wasm,
376                    max_label_idx,
377                    stack,
378                    sidetable,
379                    false,
380                )?;
381
382                // The label arity of the branches must be explicitly checked against each other further
383                // if their arities are the same, then they must unify, as they unify against the stack variables already
384                // If the following check is not made, the algorithm incorrectly unifies label types with different arities
385                // in which the smaller arity type is a suffix in the label type list of the larger arity function
386
387                // stack includes all labels, that check is made in the above fn already
388                let max_label_idx = max_label_idx.into_usize();
389
390                let max_label_arity = stack
391                    .ctrl_stack
392                    .get(stack.ctrl_stack.len() - max_label_idx - 1)
393                    .unwrap()
394                    .label_types()
395                    .len();
396                for label_idx in &label_vec {
397                    let label_idx_as_usize = label_idx.into_usize();
398                    let label_arity = stack
399                        .ctrl_stack
400                        .get(stack.ctrl_stack.len() - label_idx_as_usize - 1)
401                        .unwrap()
402                        .label_types()
403                        .len();
404                    if max_label_arity != label_arity {
405                        return Err(ValidationError::InvalidLabelIdx(*label_idx));
406                    }
407                }
408
409                stack.make_unspecified()?;
410            }
411            END => {
412                // The types are explicitly popped and pushed in
413                // https://webassembly.github.io/spec/core/appendix/algorithm.html
414                // therefore types on the stack might change.
415                let (label_info, block_ty) = stack.assert_pop_ctrl(true)?;
416                let stp_here = sidetable.len();
417
418                match label_info {
419                    LabelInfo::Block { stps_to_backpatch } => {
420                        stps_to_backpatch.iter().for_each(|i| {
421                            sidetable[*i].pc = wasm.pc;
422                            sidetable[*i].stp = stp_here;
423                        });
424                    }
425                    LabelInfo::If {
426                        stp,
427                        stps_to_backpatch,
428                    } => {
429                        if stp != usize::MAX {
430                            //This If is still not backpatched, meaning it does not have a corresponding
431                            //ELSE. This is only allowed when the corresponding If block has the same input
432                            //types as its output types (an untyped ELSE block with no instruction is valid
433                            //if and only if it is of this type)
434                            if !(block_ty.params == block_ty.returns) {
435                                return Err(ValidationError::IfWithoutMatchingElse);
436                            }
437
438                            //This If is still not backpatched, meaning it does not have a corresponding
439                            //ELSE. Therefore if its condition fails, it jumps after END.
440                            sidetable[stp].pc = wasm.pc;
441                            sidetable[stp].stp = stp_here;
442                        }
443                        stps_to_backpatch.iter().for_each(|i| {
444                            sidetable[*i].pc = wasm.pc;
445                            sidetable[*i].stp = stp_here;
446                        });
447                    }
448                    LabelInfo::Loop { .. } => (),
449                    LabelInfo::Func { stps_to_backpatch } => {
450                        // same as blocks, except jump just before the end instr, not after it
451                        // the last end instruction will handle the return to callee during execution
452                        stps_to_backpatch.iter().for_each(|i| {
453                            sidetable[*i].pc = wasm.pc - 1; // minus 1 is important!
454                                                            // during execution we check at every END instruction whether the function body is finished
455                                                            // Therefore only for function scope we jump before the END instruction
456                            sidetable[*i].stp = stp_here;
457                        });
458                    }
459                    LabelInfo::Untyped => unreachable!("this label is for untyped wasm sequences"),
460                }
461
462                if stack.ctrl_stack.is_empty() {
463                    return Ok(());
464                }
465            }
466            RETURN => {
467                // Generally `return` behaves the same as `br <most_outer>`,
468                // except when there are more than [`u32::MAX`] labels. In that
469                // case `return` would still be valid, while `br (u32::MAX + n)`
470                // is invalid.
471                //
472                // TODO Find a way to get rid of this limitation
473                let label_idx = u32::try_from(stack.ctrl_stack.len() - 1)
474                    .expect("that there are never so many nested control blocks that the index to the outermost label exceeds u32::MAX");
475                validate_branch_and_generate_sidetable_entry(
476                    wasm, label_idx, stack, sidetable, false,
477                )?;
478                stack.make_unspecified()?;
479            }
480            // call [t1*] -> [t2*]
481            CALL => {
482                let func_idx = FuncIdx::read_and_validate(wasm, c_funcs)?;
483                // SAFETY: We just validated this function index with the same
484                // `IdxVec`.
485                let type_idx = *unsafe { c_funcs.get(func_idx) };
486                // SAFETY: The caller ensures that all passed `TypeIdx` values,
487                // including this one, are valid in this `IdxVec<TypeIdx,
488                // FuncType>`.
489                let func_ty = unsafe { fn_types.get(type_idx) };
490
491                for typ in func_ty.params.valtypes.iter().rev() {
492                    stack.assert_pop_val_type(*typ)?;
493                }
494
495                for typ in func_ty.returns.valtypes.iter() {
496                    stack.push_valtype(*typ);
497                }
498            }
499            CALL_INDIRECT => {
500                let type_idx = TypeIdx::read_and_validate(wasm, fn_types)?;
501
502                let table_idx = TableIdx::read_and_validate(wasm, c_tables)?;
503
504                // SAFETY: We just validated that this is a valid `TableIdx` in
505                // this `IdxVec<TableIdx, TableType>`.
506                let tab = unsafe { c_tables.get(table_idx) };
507
508                if tab.et != RefType::FuncRef {
509                    return Err(ValidationError::IndirectCallToNonFuncRefTable(tab.et));
510                }
511
512                // SAFETY: We just validated that this is a valid `TypeIdx` in
513                // this `IdxVec<TypeIdx, FuncType>`,
514                let func_ty = unsafe { fn_types.get(type_idx) };
515
516                stack.assert_pop_val_type(ValType::NumType(NumType::I32))?;
517
518                for typ in func_ty.params.valtypes.iter().rev() {
519                    stack.assert_pop_val_type(*typ)?;
520                }
521
522                for typ in func_ty.returns.valtypes.iter() {
523                    stack.push_valtype(*typ);
524                }
525            }
526            // unreachable: [t1*] -> [t2*]
527            UNREACHABLE => {
528                stack.make_unspecified()?;
529            }
530            DROP => {
531                stack.drop_val()?;
532            }
533            SELECT => {
534                stack.validate_polymorphic_select()?;
535            }
536            SELECT_T => {
537                let type_vec = wasm.read_vec(ValType::read)?;
538                if type_vec.len() != 1 {
539                    return Err(ValidationError::InvalidSelectTypeVectorLength(
540                        type_vec.len(),
541                    ));
542                }
543                stack.assert_pop_val_type(ValType::NumType(NumType::I32))?;
544                stack.assert_pop_val_type(type_vec[0])?;
545                stack.assert_pop_val_type(type_vec[0])?;
546                stack.push_valtype(type_vec[0]);
547            }
548            // local.get: [] -> [t]
549            LOCAL_GET => {
550                let local_idx = LocalIdx::read_and_validate(wasm, locals)?;
551                let local_ty = locals
552                    .get(local_idx.into_inner().into_usize())
553                    .expect("the local index to be valid as this was just checked");
554                stack.push_valtype(*local_ty);
555            }
556            // local.set [t] -> []
557            LOCAL_SET => {
558                let local_idx = LocalIdx::read_and_validate(wasm, locals)?;
559                let local_ty = locals
560                    .get(local_idx.into_inner().into_usize())
561                    .expect("the local index to be valid as this was just checked");
562                stack.assert_pop_val_type(*local_ty)?;
563            }
564            // local.set [t] -> [t]
565            LOCAL_TEE => {
566                let local_idx = LocalIdx::read_and_validate(wasm, locals)?;
567                let local_ty = locals
568                    .get(local_idx.into_inner().into_usize())
569                    .expect("the local index to be valid as this was just checked");
570                stack.assert_val_types_on_top(&[*local_ty], true)?;
571            }
572            // global.get [] -> [t]
573            GLOBAL_GET => {
574                let global_idx = GlobalIdx::read_and_validate(wasm, c_globals)?;
575                // SAFETY: We just validated that this is a valid `TypeIdx` in
576                // this vector.
577                let global = unsafe { c_globals.get(global_idx) };
578
579                stack.push_valtype(global.ty.ty);
580                trace!(
581                    "Instruction: global.get '{}' [] -> [{:?}]",
582                    global_idx,
583                    // global,
584                    global.ty.ty
585                );
586            }
587            // global.set [t] -> []
588            GLOBAL_SET => {
589                let global_idx = GlobalIdx::read_and_validate(wasm, c_globals)?;
590                // SAFETY: We just validated that this is a valid `TypeIdx` in
591                // this vector.
592                let global = unsafe { c_globals.get(global_idx) };
593
594                if !global.ty.is_mut {
595                    return Err(ValidationError::MutationOfConstGlobal);
596                }
597
598                stack.assert_pop_val_type(global.ty.ty)?;
599            }
600            TABLE_GET => {
601                let table_idx = TableIdx::read_and_validate(wasm, c_tables)?;
602
603                // SAFETY: We just validated that this is a valid `TableIdx` in
604                // this `IdxVec<TableIdx, TableType>`.
605                let table = unsafe { c_tables.get(table_idx) };
606                let t = table.et;
607
608                stack.assert_pop_val_type(ValType::NumType(NumType::I32))?;
609                stack.push_valtype(ValType::RefType(t));
610            }
611            TABLE_SET => {
612                let table_idx = TableIdx::read_and_validate(wasm, c_tables)?;
613
614                // SAFETY: We just validated that this is a valid `TableIdx` in
615                // this `IdxVec<TableIdx, TableType>`.
616                let table = unsafe { c_tables.get(table_idx) };
617                let t = table.et;
618
619                stack.assert_pop_ref_type(Some(t))?;
620                stack.assert_pop_val_type(ValType::NumType(NumType::I32))?;
621            }
622            I32_LOAD => {
623                let _mem_idx = MemIdx::validate(0, c_mems)?;
624                let memarg = MemArg::read(wasm)?;
625                if memarg.align > 2 {
626                    return Err(ValidationError::ErroneousAlignment {
627                        alignment: memarg.align,
628                        minimum_required_alignment: 2,
629                    });
630                }
631                stack.assert_pop_val_type(ValType::NumType(NumType::I32))?;
632                stack.push_valtype(ValType::NumType(NumType::I32));
633            }
634            I64_LOAD => {
635                let _mem_idx = MemIdx::validate(0, c_mems)?;
636                let memarg = MemArg::read(wasm)?;
637                if memarg.align > 3 {
638                    return Err(ValidationError::ErroneousAlignment {
639                        alignment: memarg.align,
640                        minimum_required_alignment: 3,
641                    });
642                }
643                stack.assert_pop_val_type(ValType::NumType(NumType::I32))?;
644                stack.push_valtype(ValType::NumType(NumType::I64));
645            }
646            F32_LOAD => {
647                let _mem_idx = MemIdx::validate(0, c_mems)?;
648                let memarg = MemArg::read(wasm)?;
649                if memarg.align > 2 {
650                    return Err(ValidationError::ErroneousAlignment {
651                        alignment: memarg.align,
652                        minimum_required_alignment: 2,
653                    });
654                }
655                stack.assert_pop_val_type(ValType::NumType(NumType::I32))?;
656                stack.push_valtype(ValType::NumType(NumType::F32));
657            }
658            F64_LOAD => {
659                let _mem_idx = MemIdx::validate(0, c_mems)?;
660                let memarg = MemArg::read(wasm)?;
661                if memarg.align > 3 {
662                    return Err(ValidationError::ErroneousAlignment {
663                        alignment: memarg.align,
664                        minimum_required_alignment: 3,
665                    });
666                }
667                stack.assert_pop_val_type(ValType::NumType(NumType::I32))?;
668                stack.push_valtype(ValType::NumType(NumType::F64));
669            }
670            I32_LOAD8_S => {
671                let _mem_idx = MemIdx::validate(0, c_mems)?;
672                let memarg = MemArg::read(wasm)?;
673                if memarg.align > 0 {
674                    return Err(ValidationError::ErroneousAlignment {
675                        alignment: memarg.align,
676                        minimum_required_alignment: 0,
677                    });
678                }
679                stack.assert_pop_val_type(ValType::NumType(NumType::I32))?;
680                stack.push_valtype(ValType::NumType(NumType::I32));
681            }
682            I32_LOAD8_U => {
683                let _mem_idx = MemIdx::validate(0, c_mems)?;
684                let memarg = MemArg::read(wasm)?;
685                if memarg.align > 0 {
686                    return Err(ValidationError::ErroneousAlignment {
687                        alignment: memarg.align,
688                        minimum_required_alignment: 0,
689                    });
690                }
691                stack.assert_pop_val_type(ValType::NumType(NumType::I32))?;
692                stack.push_valtype(ValType::NumType(NumType::I32));
693            }
694            I32_LOAD16_S => {
695                let _mem_idx = MemIdx::validate(0, c_mems)?;
696                let memarg = MemArg::read(wasm)?;
697                if memarg.align > 1 {
698                    return Err(ValidationError::ErroneousAlignment {
699                        alignment: memarg.align,
700                        minimum_required_alignment: 1,
701                    });
702                }
703                stack.assert_pop_val_type(ValType::NumType(NumType::I32))?;
704                stack.push_valtype(ValType::NumType(NumType::I32));
705            }
706            I32_LOAD16_U => {
707                let _mem_idx = MemIdx::validate(0, c_mems)?;
708                let memarg = MemArg::read(wasm)?;
709                if memarg.align > 1 {
710                    return Err(ValidationError::ErroneousAlignment {
711                        alignment: memarg.align,
712                        minimum_required_alignment: 1,
713                    });
714                }
715                stack.assert_pop_val_type(ValType::NumType(NumType::I32))?;
716                stack.push_valtype(ValType::NumType(NumType::I32));
717            }
718            I64_LOAD8_S => {
719                let _mem_idx = MemIdx::validate(0, c_mems)?;
720                let memarg = MemArg::read(wasm)?;
721                if memarg.align > 0 {
722                    return Err(ValidationError::ErroneousAlignment {
723                        alignment: memarg.align,
724                        minimum_required_alignment: 0,
725                    });
726                }
727                stack.assert_pop_val_type(ValType::NumType(NumType::I32))?;
728                stack.push_valtype(ValType::NumType(NumType::I64));
729            }
730            I64_LOAD8_U => {
731                let _mem_idx = MemIdx::validate(0, c_mems)?;
732                let memarg = MemArg::read(wasm)?;
733                if memarg.align > 0 {
734                    return Err(ValidationError::ErroneousAlignment {
735                        alignment: memarg.align,
736                        minimum_required_alignment: 0,
737                    });
738                }
739                stack.assert_pop_val_type(ValType::NumType(NumType::I32))?;
740                stack.push_valtype(ValType::NumType(NumType::I64));
741            }
742            I64_LOAD16_S => {
743                let _mem_idx = MemIdx::validate(0, c_mems)?;
744                let memarg = MemArg::read(wasm)?;
745                if memarg.align > 1 {
746                    return Err(ValidationError::ErroneousAlignment {
747                        alignment: memarg.align,
748                        minimum_required_alignment: 1,
749                    });
750                }
751                stack.assert_pop_val_type(ValType::NumType(NumType::I32))?;
752                stack.push_valtype(ValType::NumType(NumType::I64));
753            }
754            I64_LOAD16_U => {
755                let _mem_idx = MemIdx::validate(0, c_mems)?;
756                let memarg = MemArg::read(wasm)?;
757                if memarg.align > 1 {
758                    return Err(ValidationError::ErroneousAlignment {
759                        alignment: memarg.align,
760                        minimum_required_alignment: 1,
761                    });
762                }
763                stack.assert_pop_val_type(ValType::NumType(NumType::I32))?;
764                stack.push_valtype(ValType::NumType(NumType::I64));
765            }
766            I64_LOAD32_S => {
767                let _mem_idx = MemIdx::validate(0, c_mems)?;
768                let memarg = MemArg::read(wasm)?;
769                if memarg.align > 2 {
770                    return Err(ValidationError::ErroneousAlignment {
771                        alignment: memarg.align,
772                        minimum_required_alignment: 2,
773                    });
774                }
775                stack.assert_pop_val_type(ValType::NumType(NumType::I32))?;
776                stack.push_valtype(ValType::NumType(NumType::I64));
777            }
778            I64_LOAD32_U => {
779                let _mem_idx = MemIdx::validate(0, c_mems)?;
780                let memarg = MemArg::read(wasm)?;
781                if memarg.align > 2 {
782                    return Err(ValidationError::ErroneousAlignment {
783                        alignment: memarg.align,
784                        minimum_required_alignment: 2,
785                    });
786                }
787                stack.assert_pop_val_type(ValType::NumType(NumType::I32))?;
788                stack.push_valtype(ValType::NumType(NumType::I64));
789            }
790            I32_STORE => {
791                let _mem_idx = MemIdx::validate(0, c_mems)?;
792                let memarg = MemArg::read(wasm)?;
793                if memarg.align > 2 {
794                    return Err(ValidationError::ErroneousAlignment {
795                        alignment: memarg.align,
796                        minimum_required_alignment: 2,
797                    });
798                }
799                stack.assert_pop_val_type(ValType::NumType(NumType::I32))?;
800                stack.assert_pop_val_type(ValType::NumType(NumType::I32))?;
801            }
802            I64_STORE => {
803                let _mem_idx = MemIdx::validate(0, c_mems)?;
804                let memarg = MemArg::read(wasm)?;
805                if memarg.align > 3 {
806                    return Err(ValidationError::ErroneousAlignment {
807                        alignment: memarg.align,
808                        minimum_required_alignment: 3,
809                    });
810                }
811                stack.assert_pop_val_type(ValType::NumType(NumType::I64))?;
812                stack.assert_pop_val_type(ValType::NumType(NumType::I32))?;
813            }
814            F32_STORE => {
815                let _mem_idx = MemIdx::validate(0, c_mems)?;
816                let memarg = MemArg::read(wasm)?;
817                if memarg.align > 2 {
818                    return Err(ValidationError::ErroneousAlignment {
819                        alignment: memarg.align,
820                        minimum_required_alignment: 2,
821                    });
822                }
823                stack.assert_pop_val_type(ValType::NumType(NumType::F32))?;
824                stack.assert_pop_val_type(ValType::NumType(NumType::I32))?;
825            }
826            F64_STORE => {
827                let _mem_idx = MemIdx::validate(0, c_mems)?;
828                let memarg = MemArg::read(wasm)?;
829                if memarg.align > 3 {
830                    return Err(ValidationError::ErroneousAlignment {
831                        alignment: memarg.align,
832                        minimum_required_alignment: 3,
833                    });
834                }
835                stack.assert_pop_val_type(ValType::NumType(NumType::F64))?;
836                stack.assert_pop_val_type(ValType::NumType(NumType::I32))?;
837            }
838            I32_STORE8 => {
839                let _mem_idx = MemIdx::validate(0, c_mems)?;
840                let memarg = MemArg::read(wasm)?;
841                if memarg.align > 0 {
842                    return Err(ValidationError::ErroneousAlignment {
843                        alignment: memarg.align,
844                        minimum_required_alignment: 0,
845                    });
846                }
847                stack.assert_pop_val_type(ValType::NumType(NumType::I32))?;
848                stack.assert_pop_val_type(ValType::NumType(NumType::I32))?;
849            }
850            I32_STORE16 => {
851                let _mem_idx = MemIdx::validate(0, c_mems)?;
852                let memarg = MemArg::read(wasm)?;
853                if memarg.align > 1 {
854                    return Err(ValidationError::ErroneousAlignment {
855                        alignment: memarg.align,
856                        minimum_required_alignment: 1,
857                    });
858                }
859                stack.assert_pop_val_type(ValType::NumType(NumType::I32))?;
860                stack.assert_pop_val_type(ValType::NumType(NumType::I32))?;
861            }
862            I64_STORE8 => {
863                let _mem_idx = MemIdx::validate(0, c_mems)?;
864                let memarg = MemArg::read(wasm)?;
865                if memarg.align > 0 {
866                    return Err(ValidationError::ErroneousAlignment {
867                        alignment: memarg.align,
868                        minimum_required_alignment: 0,
869                    });
870                }
871                stack.assert_pop_val_type(ValType::NumType(NumType::I64))?;
872                stack.assert_pop_val_type(ValType::NumType(NumType::I32))?;
873            }
874            I64_STORE16 => {
875                let _mem_idx = MemIdx::validate(0, c_mems)?;
876                let memarg = MemArg::read(wasm)?;
877                if memarg.align > 1 {
878                    return Err(ValidationError::ErroneousAlignment {
879                        alignment: memarg.align,
880                        minimum_required_alignment: 1,
881                    });
882                }
883                stack.assert_pop_val_type(ValType::NumType(NumType::I64))?;
884                stack.assert_pop_val_type(ValType::NumType(NumType::I32))?;
885            }
886            I64_STORE32 => {
887                let _mem_idx = MemIdx::validate(0, c_mems)?;
888                let memarg = MemArg::read(wasm)?;
889                if memarg.align > 2 {
890                    return Err(ValidationError::ErroneousAlignment {
891                        alignment: memarg.align,
892                        minimum_required_alignment: 2,
893                    });
894                }
895                stack.assert_pop_val_type(ValType::NumType(NumType::I64))?;
896                stack.assert_pop_val_type(ValType::NumType(NumType::I32))?;
897            }
898            MEMORY_SIZE => {
899                // Note: This zero byte is reserved for the multiple
900                // memories proposal.
901                let zero = wasm.read_u8()?;
902                if zero != 0 {
903                    return Err(ValidationError::UnsupportedMultipleMemoriesProposal);
904                }
905                let _mem_idx = MemIdx::validate(0, c_mems)?;
906
907                stack.push_valtype(ValType::NumType(NumType::I32));
908            }
909            MEMORY_GROW => {
910                // Note: This zero byte is reserved for the multiple
911                // memories proposal.
912                let zero = wasm.read_u8()?;
913                if zero != 0 {
914                    return Err(ValidationError::UnsupportedMultipleMemoriesProposal);
915                }
916                let _mem_idx = MemIdx::validate(0, c_mems)?;
917
918                stack.assert_pop_val_type(ValType::NumType(NumType::I32))?;
919                stack.push_valtype(ValType::NumType(NumType::I32));
920            }
921            // i32.const: [] -> [i32]
922            I32_CONST => {
923                let _num = wasm.read_var_i32()?;
924                stack.push_valtype(ValType::NumType(NumType::I32));
925            }
926            I64_CONST => {
927                let _num = wasm.read_var_i64()?;
928                stack.push_valtype(ValType::NumType(NumType::I64));
929            }
930            F32_CONST => {
931                let _num = wasm.read_f32()?;
932                stack.push_valtype(ValType::NumType(NumType::F32));
933            }
934            F64_CONST => {
935                let _num = wasm.read_f64()?;
936                stack.push_valtype(ValType::NumType(NumType::F64));
937            }
938            I32_EQZ => {
939                stack.assert_pop_val_type(ValType::NumType(NumType::I32))?;
940
941                stack.push_valtype(ValType::NumType(NumType::I32));
942            }
943            I32_EQ | I32_NE | I32_LT_S | I32_LT_U | I32_GT_S | I32_GT_U | I32_LE_S | I32_LE_U
944            | I32_GE_S | I32_GE_U => {
945                stack.assert_pop_val_type(ValType::NumType(NumType::I32))?;
946                stack.assert_pop_val_type(ValType::NumType(NumType::I32))?;
947
948                stack.push_valtype(ValType::NumType(NumType::I32));
949            }
950            I64_EQZ => {
951                stack.assert_pop_val_type(ValType::NumType(NumType::I64))?;
952
953                stack.push_valtype(ValType::NumType(NumType::I32));
954            }
955            I64_EQ | I64_NE | I64_LT_S | I64_LT_U | I64_GT_S | I64_GT_U | I64_LE_S | I64_LE_U
956            | I64_GE_S | I64_GE_U => {
957                stack.assert_pop_val_type(ValType::NumType(NumType::I64))?;
958                stack.assert_pop_val_type(ValType::NumType(NumType::I64))?;
959
960                stack.push_valtype(ValType::NumType(NumType::I32));
961            }
962            F32_EQ | F32_NE | F32_LT | F32_GT | F32_LE | F32_GE => {
963                stack.assert_pop_val_type(ValType::NumType(NumType::F32))?;
964                stack.assert_pop_val_type(ValType::NumType(NumType::F32))?;
965
966                stack.push_valtype(ValType::NumType(NumType::I32));
967            }
968            F64_EQ | F64_NE | F64_LT | F64_GT | F64_LE | F64_GE => {
969                stack.assert_pop_val_type(ValType::NumType(NumType::F64))?;
970                stack.assert_pop_val_type(ValType::NumType(NumType::F64))?;
971
972                stack.push_valtype(ValType::NumType(NumType::I32));
973            }
974            F32_ABS | F32_NEG | F32_CEIL | F32_FLOOR | F32_TRUNC | F32_NEAREST | F32_SQRT => {
975                stack.assert_pop_val_type(ValType::NumType(NumType::F32))?;
976
977                stack.push_valtype(ValType::NumType(NumType::F32));
978            }
979            F32_ADD | F32_SUB | F32_MUL | F32_DIV | F32_MIN | F32_MAX | F32_COPYSIGN => {
980                stack.assert_pop_val_type(ValType::NumType(NumType::F32))?;
981                stack.assert_pop_val_type(ValType::NumType(NumType::F32))?;
982
983                stack.push_valtype(ValType::NumType(NumType::F32));
984            }
985            F64_ABS | F64_NEG | F64_CEIL | F64_FLOOR | F64_TRUNC | F64_NEAREST | F64_SQRT => {
986                stack.assert_pop_val_type(ValType::NumType(NumType::F64))?;
987
988                stack.push_valtype(ValType::NumType(NumType::F64));
989            }
990            F64_ADD | F64_SUB | F64_MUL | F64_DIV | F64_MIN | F64_MAX | F64_COPYSIGN => {
991                stack.assert_pop_val_type(ValType::NumType(NumType::F64))?;
992                stack.assert_pop_val_type(ValType::NumType(NumType::F64))?;
993
994                stack.push_valtype(ValType::NumType(NumType::F64));
995            }
996            I32_ADD | I32_SUB | I32_MUL | I32_DIV_S | I32_DIV_U | I32_REM_S => {
997                stack.assert_pop_val_type(ValType::NumType(NumType::I32))?;
998                stack.assert_pop_val_type(ValType::NumType(NumType::I32))?;
999
1000                stack.push_valtype(ValType::NumType(NumType::I32));
1001            }
1002            // i32.clz: [i32] -> [i32]
1003            I32_CLZ | I32_CTZ | I32_POPCNT => {
1004                stack.assert_pop_val_type(ValType::NumType(NumType::I32))?;
1005
1006                stack.push_valtype(ValType::NumType(NumType::I32));
1007            }
1008            I32_REM_U | I32_AND | I32_OR | I32_XOR | I32_SHL | I32_SHR_S | I32_SHR_U | I32_ROTL
1009            | I32_ROTR => {
1010                stack.assert_pop_val_type(ValType::NumType(NumType::I32))?;
1011                stack.assert_pop_val_type(ValType::NumType(NumType::I32))?;
1012
1013                stack.push_valtype(ValType::NumType(NumType::I32));
1014            }
1015            I64_CLZ | I64_CTZ | I64_POPCNT => {
1016                stack.assert_pop_val_type(ValType::NumType(NumType::I64))?;
1017
1018                stack.push_valtype(ValType::NumType(NumType::I64));
1019            }
1020
1021            I64_ADD | I64_SUB | I64_MUL | I64_DIV_S | I64_DIV_U | I64_REM_S | I64_REM_U
1022            | I64_AND | I64_OR | I64_XOR | I64_SHL | I64_SHR_S | I64_SHR_U | I64_ROTL
1023            | I64_ROTR => {
1024                stack.assert_pop_val_type(ValType::NumType(NumType::I64))?;
1025                stack.assert_pop_val_type(ValType::NumType(NumType::I64))?;
1026
1027                stack.push_valtype(ValType::NumType(NumType::I64));
1028            }
1029
1030            I32_WRAP_I64 => {
1031                stack.assert_pop_val_type(ValType::NumType(NumType::I64))?;
1032
1033                stack.push_valtype(ValType::NumType(NumType::I32));
1034            }
1035
1036            I32_TRUNC_F32_S | I32_TRUNC_F32_U | I32_REINTERPRET_F32 => {
1037                stack.assert_pop_val_type(ValType::NumType(NumType::F32))?;
1038
1039                stack.push_valtype(ValType::NumType(NumType::I32));
1040            }
1041
1042            I32_TRUNC_F64_S | I32_TRUNC_F64_U => {
1043                stack.assert_pop_val_type(ValType::NumType(NumType::F64))?;
1044
1045                stack.push_valtype(ValType::NumType(NumType::I32));
1046            }
1047
1048            I64_EXTEND_I32_S | I64_EXTEND_I32_U => {
1049                stack.assert_pop_val_type(ValType::NumType(NumType::I32))?;
1050
1051                stack.push_valtype(ValType::NumType(NumType::I64));
1052            }
1053
1054            I64_TRUNC_F32_S | I64_TRUNC_F32_U => {
1055                stack.assert_pop_val_type(ValType::NumType(NumType::F32))?;
1056
1057                stack.push_valtype(ValType::NumType(NumType::I64));
1058            }
1059
1060            I64_TRUNC_F64_S | I64_TRUNC_F64_U | I64_REINTERPRET_F64 => {
1061                stack.assert_pop_val_type(ValType::NumType(NumType::F64))?;
1062
1063                stack.push_valtype(ValType::NumType(NumType::I64));
1064            }
1065
1066            F32_CONVERT_I32_S | F32_CONVERT_I32_U | F32_REINTERPRET_I32 => {
1067                stack.assert_pop_val_type(ValType::NumType(NumType::I32))?;
1068
1069                stack.push_valtype(ValType::NumType(NumType::F32));
1070            }
1071
1072            F32_CONVERT_I64_S | F32_CONVERT_I64_U => {
1073                stack.assert_pop_val_type(ValType::NumType(NumType::I64))?;
1074
1075                stack.push_valtype(ValType::NumType(NumType::F32));
1076            }
1077
1078            F32_DEMOTE_F64 => {
1079                stack.assert_pop_val_type(ValType::NumType(NumType::F64))?;
1080
1081                stack.push_valtype(ValType::NumType(NumType::F32));
1082            }
1083
1084            F64_CONVERT_I32_S | F64_CONVERT_I32_U => {
1085                stack.assert_pop_val_type(ValType::NumType(NumType::I32))?;
1086
1087                stack.push_valtype(ValType::NumType(NumType::F64));
1088            }
1089
1090            F64_CONVERT_I64_S | F64_CONVERT_I64_U | F64_REINTERPRET_I64 => {
1091                stack.assert_pop_val_type(ValType::NumType(NumType::I64))?;
1092
1093                stack.push_valtype(ValType::NumType(NumType::F64));
1094            }
1095
1096            F64_PROMOTE_F32 => {
1097                stack.assert_pop_val_type(ValType::NumType(NumType::F32))?;
1098
1099                stack.push_valtype(ValType::NumType(NumType::F64));
1100            }
1101
1102            REF_NULL => {
1103                let reftype = RefType::read(wasm)?;
1104                // at validation-time we don't really care if it's null or not
1105                stack.push_valtype(ValType::RefType(reftype));
1106            }
1107
1108            REF_IS_NULL => {
1109                stack.assert_pop_ref_type(None)?;
1110                stack.push_valtype(ValType::NumType(NumType::I32));
1111            }
1112
1113            REF_FUNC => {
1114                let func_idx = FuncIdx::read_and_validate(wasm, c_funcs)?;
1115
1116                // check whether func_idx is in C.refs
1117                // https://webassembly.github.io/spec/core/valid/conventions.html#context
1118                if !validation_context_refs.contains(&func_idx) {
1119                    return Err(ValidationError::ReferencingAnUnreferencedFunction(func_idx));
1120                }
1121
1122                stack.push_valtype(ValType::RefType(RefType::FuncRef));
1123            }
1124
1125            FC_EXTENSIONS => {
1126                let Ok(second_instr) = wasm.read_var_u32() else {
1127                    // TODO only do this if EOF
1128                    return Err(ValidationError::ExprMissingEnd);
1129                };
1130
1131                #[cfg(feature = "log")]
1132                crate::core::utils::print_beautiful_fc_extension(second_instr, wasm.pc);
1133
1134                #[cfg(feature = "log")]
1135                trace!(
1136                    "Read instruction byte {second_instr} at wasm_binary[{}]",
1137                    wasm.pc
1138                );
1139
1140                use crate::core::reader::types::opcode::fc_extensions::*;
1141                match second_instr {
1142                    I32_TRUNC_SAT_F32_S => {
1143                        stack.assert_pop_val_type(ValType::NumType(NumType::F32))?;
1144                        stack.push_valtype(ValType::NumType(NumType::I32));
1145                    }
1146                    I32_TRUNC_SAT_F32_U => {
1147                        stack.assert_pop_val_type(ValType::NumType(NumType::F32))?;
1148                        stack.push_valtype(ValType::NumType(NumType::I32));
1149                    }
1150                    I32_TRUNC_SAT_F64_S => {
1151                        stack.assert_pop_val_type(ValType::NumType(NumType::F64))?;
1152                        stack.push_valtype(ValType::NumType(NumType::I32));
1153                    }
1154                    I32_TRUNC_SAT_F64_U => {
1155                        stack.assert_pop_val_type(ValType::NumType(NumType::F64))?;
1156                        stack.push_valtype(ValType::NumType(NumType::I32));
1157                    }
1158                    I64_TRUNC_SAT_F32_S => {
1159                        stack.assert_pop_val_type(ValType::NumType(NumType::F32))?;
1160                        stack.push_valtype(ValType::NumType(NumType::I64));
1161                    }
1162                    I64_TRUNC_SAT_F32_U => {
1163                        stack.assert_pop_val_type(ValType::NumType(NumType::F32))?;
1164                        stack.push_valtype(ValType::NumType(NumType::I64));
1165                    }
1166                    I64_TRUNC_SAT_F64_S => {
1167                        stack.assert_pop_val_type(ValType::NumType(NumType::F64))?;
1168                        stack.push_valtype(ValType::NumType(NumType::I64));
1169                    }
1170                    I64_TRUNC_SAT_F64_U => {
1171                        stack.assert_pop_val_type(ValType::NumType(NumType::F64))?;
1172                        stack.push_valtype(ValType::NumType(NumType::I64));
1173                    }
1174                    MEMORY_INIT => {
1175                        let data_idx = DataIdx::read_and_validate(
1176                            wasm,
1177                            data_count.ok_or(ValidationError::MissingDataCountSection)?,
1178                        );
1179                        // Note: This zero byte is reserved for the multiple
1180                        // memories proposal.
1181                        let zero = wasm.read_u8()?;
1182                        if zero != 0 {
1183                            return Err(ValidationError::UnsupportedMultipleMemoriesProposal);
1184                        }
1185                        if c_mems.len() == 0 {
1186                            return Err(ValidationError::InvalidMemIdx(0));
1187                        }
1188                        // Validate data index after memory index
1189                        let _data_idx = data_idx?;
1190
1191                        stack.assert_pop_val_type(ValType::NumType(NumType::I32))?;
1192                        stack.assert_pop_val_type(ValType::NumType(NumType::I32))?;
1193                        stack.assert_pop_val_type(ValType::NumType(NumType::I32))?;
1194                    }
1195                    DATA_DROP => {
1196                        let _data_idx = DataIdx::read_and_validate(
1197                            wasm,
1198                            data_count.ok_or(ValidationError::MissingDataCountSection)?,
1199                        )?;
1200                    }
1201                    MEMORY_COPY => {
1202                        // Note: These zero bytes are reserved for the multiple
1203                        // memories proposal.
1204                        let zeros = (wasm.read_u8()?, wasm.read_u8()?);
1205                        if zeros != (0, 0) {
1206                            return Err(ValidationError::UnsupportedMultipleMemoriesProposal);
1207                        }
1208                        let _mem_idx = MemIdx::validate(0, c_mems)?;
1209
1210                        stack.assert_pop_val_type(ValType::NumType(NumType::I32))?;
1211                        stack.assert_pop_val_type(ValType::NumType(NumType::I32))?;
1212                        stack.assert_pop_val_type(ValType::NumType(NumType::I32))?;
1213                    }
1214                    MEMORY_FILL => {
1215                        // Note: This zero byte is reserved for the multiple
1216                        // memories proposal.
1217                        let zero = wasm.read_u8()?;
1218                        if zero != 0 {
1219                            return Err(ValidationError::UnsupportedMultipleMemoriesProposal);
1220                        }
1221                        let _mem_idx = MemIdx::validate(0, c_mems)?;
1222
1223                        stack.assert_pop_val_type(ValType::NumType(NumType::I32))?;
1224                        stack.assert_pop_val_type(ValType::NumType(NumType::I32))?;
1225                        stack.assert_pop_val_type(ValType::NumType(NumType::I32))?;
1226                    }
1227                    TABLE_INIT => {
1228                        // Validation requires us to validate the table index
1229                        // before the element index -- even though these are
1230                        // encoded the other way around.
1231                        let elem_idx = ElemIdx::read_and_validate(wasm, c_elems);
1232                        let table_idx = TableIdx::read_and_validate(wasm, c_tables);
1233                        if let Err(invalid_table_idx @ ValidationError::InvalidTableIdx(_)) =
1234                            table_idx
1235                        {
1236                            return Err(invalid_table_idx);
1237                        }
1238                        let elem_idx = elem_idx?;
1239                        let table_idx = table_idx?;
1240
1241                        // SAFETY: We just validated that this is a valid
1242                        // `TableIdx` in this `IdxVec<TableIdx, TableType>`.
1243                        let table1 = unsafe { c_tables.get(table_idx) };
1244                        let table_type = table1.et;
1245
1246                        // SAFETY: We just validated that this is a valid
1247                        // `ElemIdx` in this `IdxVec`.
1248                        let element = unsafe { c_elems.get(elem_idx) };
1249                        let element_type = element.to_ref_type();
1250
1251                        if table_type != element_type {
1252                            return Err(ValidationError::MismatchedRefTypesDuringTableInit {
1253                                table_ty: table_type,
1254                                elem_ty: element_type,
1255                            });
1256                        }
1257                        stack.assert_pop_val_type(ValType::NumType(NumType::I32))?;
1258                        stack.assert_pop_val_type(ValType::NumType(NumType::I32))?;
1259                        // INFO: wasmtime checks for this value to be an index in the tables array, interesting
1260                        stack.assert_pop_val_type(ValType::NumType(NumType::I32))?;
1261                    }
1262                    ELEM_DROP => {
1263                        let _elem_idx = ElemIdx::read_and_validate(wasm, c_elems)?;
1264                    }
1265                    TABLE_COPY => {
1266                        let table_x_idx = TableIdx::read_and_validate(wasm, c_tables)?;
1267                        let table_y_idx = TableIdx::read_and_validate(wasm, c_tables)?;
1268
1269                        // SAFETY: We just validated that this is a valid
1270                        // `TableIdx` in this `IdxVec<TableIdx, TableType>`.
1271                        let table1 = unsafe { c_tables.get(table_x_idx) };
1272                        // SAFETY: We just validated that this is a valid
1273                        // `TableIdx` in this `IdxVec<TableIdx, TableType>`.
1274                        let table2 = unsafe { c_tables.get(table_y_idx) };
1275
1276                        let t1 = table1.et;
1277                        let t2 = table2.et;
1278
1279                        if t1 != t2 {
1280                            return Err(ValidationError::MismatchedRefTypesDuringTableCopy {
1281                                source_table_ty: t2,
1282                                destination_table_ty: t1,
1283                            });
1284                        }
1285
1286                        stack.assert_pop_val_type(ValType::NumType(NumType::I32))?;
1287                        stack.assert_pop_val_type(ValType::NumType(NumType::I32))?;
1288                        stack.assert_pop_val_type(ValType::NumType(NumType::I32))?;
1289                    }
1290                    TABLE_GROW => {
1291                        let table_idx = TableIdx::read_and_validate(wasm, c_tables)?;
1292
1293                        // SAFETY: We just validated that this is a valid
1294                        // `TableIdx` in this `IdxVec<TableIdx, TableType>`.
1295                        let table = unsafe { c_tables.get(table_idx) };
1296                        let t = table.et;
1297
1298                        stack.assert_pop_val_type(ValType::NumType(NumType::I32))?;
1299                        stack.assert_pop_ref_type(Some(t))?;
1300
1301                        stack.push_valtype(ValType::NumType(NumType::I32));
1302                    }
1303                    TABLE_SIZE => {
1304                        let _table_idx = TableIdx::read_and_validate(wasm, c_tables)?;
1305
1306                        stack.push_valtype(ValType::NumType(NumType::I32));
1307                    }
1308                    TABLE_FILL => {
1309                        let table_idx = TableIdx::read_and_validate(wasm, c_tables)?;
1310
1311                        // SAFETY: We just validated that this is a valid
1312                        // `TableIdx` in this `IdxVec<TableIdx, TableType>`.
1313                        let table = unsafe { c_tables.get(table_idx) };
1314                        let t = table.et;
1315
1316                        stack.assert_pop_val_type(ValType::NumType(NumType::I32))?;
1317                        stack.assert_pop_ref_type(Some(t))?;
1318                        stack.assert_pop_val_type(ValType::NumType(NumType::I32))?;
1319                    }
1320                    _ => {
1321                        return Err(ValidationError::InvalidMultiByteInstr(
1322                            first_instr_byte,
1323                            second_instr,
1324                        ))
1325                    }
1326                }
1327            }
1328
1329            I32_EXTEND8_S => {
1330                stack.assert_pop_val_type(ValType::NumType(NumType::I32))?;
1331
1332                stack.push_valtype(ValType::NumType(NumType::I32));
1333            }
1334            I32_EXTEND16_S => {
1335                stack.assert_pop_val_type(ValType::NumType(NumType::I32))?;
1336
1337                stack.push_valtype(ValType::NumType(NumType::I32));
1338            }
1339            I64_EXTEND8_S => {
1340                stack.assert_pop_val_type(ValType::NumType(NumType::I64))?;
1341
1342                stack.push_valtype(ValType::NumType(NumType::I64));
1343            }
1344            I64_EXTEND16_S => {
1345                stack.assert_pop_val_type(ValType::NumType(NumType::I64))?;
1346
1347                stack.push_valtype(ValType::NumType(NumType::I64));
1348            }
1349            I64_EXTEND32_S => {
1350                stack.assert_pop_val_type(ValType::NumType(NumType::I64))?;
1351
1352                stack.push_valtype(ValType::NumType(NumType::I64));
1353            }
1354
1355            FD_EXTENSIONS => {
1356                let Ok(second_instr) = wasm.read_var_u32() else {
1357                    // TODO only do this if EOF
1358                    return Err(ValidationError::ExprMissingEnd);
1359                };
1360
1361                #[cfg(feature = "log")]
1362                crate::core::utils::print_beautiful_fd_extension(second_instr, wasm.pc);
1363
1364                use crate::core::reader::types::opcode::fd_extensions::*;
1365
1366                match second_instr {
1367                    V128_LOAD => {
1368                        let _mem_idx = MemIdx::validate(0, c_mems)?;
1369                        let memarg = MemArg::read(wasm)?;
1370                        if memarg.align > 4 {
1371                            return Err(ValidationError::ErroneousAlignment {
1372                                alignment: memarg.align,
1373                                minimum_required_alignment: 4,
1374                            });
1375                        }
1376                        stack.assert_pop_val_type(ValType::NumType(NumType::I32))?;
1377                        stack.push_valtype(ValType::VecType);
1378                    }
1379                    V128_STORE => {
1380                        let _mem_idx = MemIdx::validate(0, c_mems)?;
1381                        let memarg = MemArg::read(wasm)?;
1382                        if memarg.align > 4 {
1383                            return Err(ValidationError::ErroneousAlignment { alignment: memarg.align, minimum_required_alignment: 4 });
1384                        }
1385                        stack.assert_pop_val_type(ValType::VecType)?;
1386                        stack.assert_pop_val_type(ValType::NumType(NumType::I32))?;
1387                    }
1388
1389                    // v128.loadNxM_sx
1390                    V128_LOAD8X8_S | V128_LOAD8X8_U
1391                    | V128_LOAD16X4_S | V128_LOAD16X4_U
1392                    | V128_LOAD32X2_S | V128_LOAD32X2_U
1393                    => {
1394                        let _mem_idx = MemIdx::validate(0, c_mems)?;
1395                        let memarg = MemArg::read(wasm)?;
1396                        if memarg.align > 3 {
1397                            return Err(ValidationError::ErroneousAlignment { alignment: memarg.align, minimum_required_alignment: 3 });
1398                        }
1399                        stack.assert_pop_val_type(ValType::NumType(NumType::I32))?;
1400                        stack.push_valtype(ValType::VecType);
1401                    },
1402
1403                    // v128.loadN_splat + v128.loadN_zero
1404                    V128_LOAD8_SPLAT => {
1405                        let _mem_idx = MemIdx::validate(0, c_mems)?;
1406                        let memarg = MemArg::read(wasm)?;
1407                        if memarg.align > 0 {
1408                            return Err(ValidationError::ErroneousAlignment { alignment: memarg.align, minimum_required_alignment: 0 });
1409                        }
1410                        stack.assert_pop_val_type(ValType::NumType(NumType::I32))?;
1411                        stack.push_valtype(ValType::VecType);
1412                    }
1413                    V128_LOAD16_SPLAT => {
1414                        let _mem_idx = MemIdx::validate(0, c_mems)?;
1415                        let memarg = MemArg::read(wasm)?;
1416                        if memarg.align > 1 {
1417                            return Err(ValidationError::ErroneousAlignment { alignment: memarg.align, minimum_required_alignment: 1 });
1418                        }
1419                        stack.assert_pop_val_type(ValType::NumType(NumType::I32))?;
1420                        stack.push_valtype(ValType::VecType);
1421                    }
1422                    V128_LOAD32_SPLAT | V128_LOAD32_ZERO => {
1423                        let _mem_idx = MemIdx::validate(0, c_mems)?;
1424                        let memarg = MemArg::read(wasm)?;
1425                        if memarg.align > 2 {
1426                            return Err(ValidationError::ErroneousAlignment { alignment: memarg.align, minimum_required_alignment: 2 });
1427                        }
1428                        stack.assert_pop_val_type(ValType::NumType(NumType::I32))?;
1429                        stack.push_valtype(ValType::VecType);
1430                    }
1431                    V128_LOAD64_SPLAT | V128_LOAD64_ZERO => {
1432                    let _mem_idx = MemIdx::validate(0, c_mems)?;
1433                        let memarg = MemArg::read(wasm)?;
1434                        if memarg.align > 3 {
1435                            return Err(ValidationError::ErroneousAlignment { alignment: memarg.align, minimum_required_alignment: 3 });
1436                        }
1437                        stack.assert_pop_val_type(ValType::NumType(NumType::I32))?;
1438                        stack.push_valtype(ValType::VecType);
1439                    }
1440
1441                    // v128.loadN_lane
1442                    V128_LOAD8_LANE => {
1443                        let memarg = MemArg::read(wasm)?;
1444                        let lane_idx = wasm.read_u8()?;
1445                        if lane_idx >= 16 {
1446                            return Err(ValidationError::InvalidLaneIdx(lane_idx));
1447                        }
1448                        let _mem_idx = MemIdx::validate(0, c_mems)?;
1449                        if memarg.align > 0 {
1450                            return Err(ValidationError::ErroneousAlignment { alignment: memarg.align, minimum_required_alignment: 0 });
1451                        }
1452                        stack.assert_pop_val_type(ValType::VecType)?;
1453                        stack.assert_pop_val_type(ValType::NumType(NumType::I32))?;
1454                        stack.push_valtype(ValType::VecType);
1455                    }
1456                    V128_LOAD16_LANE => {
1457                        let memarg = MemArg::read(wasm)?;
1458                        let lane_idx = wasm.read_u8()?;
1459                        if lane_idx >= 8 {
1460                            return Err(ValidationError::InvalidLaneIdx(lane_idx));
1461                        }
1462                        let _mem_idx = MemIdx::validate(0, c_mems)?;
1463                        if memarg.align > 1 {
1464                            return Err(ValidationError::ErroneousAlignment { alignment: memarg.align, minimum_required_alignment: 1 });
1465                        }
1466                        stack.assert_pop_val_type(ValType::VecType)?;
1467                        stack.assert_pop_val_type(ValType::NumType(NumType::I32))?;
1468                        stack.push_valtype(ValType::VecType);
1469                    }
1470                    V128_LOAD32_LANE => {
1471                        let memarg = MemArg::read(wasm)?;
1472                        let lane_idx = wasm.read_u8()?;
1473                        if lane_idx >= 4 {
1474                            return Err(ValidationError::InvalidLaneIdx(lane_idx));
1475                        }
1476                        let _mem_idx = MemIdx::validate(0, c_mems)?;
1477                        if memarg.align > 2 {
1478                            return Err(ValidationError::ErroneousAlignment { alignment: memarg.align, minimum_required_alignment: 2 });
1479                        }
1480                        stack.assert_pop_val_type(ValType::VecType)?;
1481                        stack.assert_pop_val_type(ValType::NumType(NumType::I32))?;
1482                        stack.push_valtype(ValType::VecType);
1483                    }
1484                    V128_LOAD64_LANE => {
1485                        let memarg = MemArg::read(wasm)?;
1486                        let lane_idx = wasm.read_u8()?;
1487                        if lane_idx >= 2 {
1488                            return Err(ValidationError::InvalidLaneIdx(lane_idx));
1489                        }
1490                        let _mem_idx = MemIdx::validate(0, c_mems)?;
1491                        if memarg.align > 3 {
1492                            return Err(ValidationError::ErroneousAlignment { alignment: memarg.align, minimum_required_alignment: 3 });
1493                        }
1494                        stack.assert_pop_val_type(ValType::VecType)?;
1495                        stack.assert_pop_val_type(ValType::NumType(NumType::I32))?;
1496                        stack.push_valtype(ValType::VecType);
1497                    }
1498
1499                    // v128.storeN_lane
1500                    V128_STORE8_LANE => {
1501                        let memarg = MemArg::read(wasm)?;
1502                        let lane_idx = wasm.read_u8()?;
1503                        if lane_idx >= 16 {
1504                            return Err(ValidationError::InvalidLaneIdx(lane_idx));
1505                        }
1506                        let _mem_idx = MemIdx::validate(0, c_mems)?;
1507                        if memarg.align > 0 {
1508                            return Err(ValidationError::ErroneousAlignment { alignment: memarg.align, minimum_required_alignment: 0 });
1509                        }
1510                        stack.assert_pop_val_type(ValType::VecType)?;
1511                        stack.assert_pop_val_type(ValType::NumType(NumType::I32))?;
1512                    }
1513                    V128_STORE16_LANE => {
1514                        let memarg = MemArg::read(wasm)?;
1515                        let lane_idx = wasm.read_u8()?;
1516                        if lane_idx >= 8 {
1517                            return Err(ValidationError::InvalidLaneIdx(lane_idx));
1518                        }
1519                        let _mem_idx = MemIdx::validate(0, c_mems)?;
1520                        if memarg.align > 1 {
1521                            return Err(ValidationError::ErroneousAlignment { alignment: memarg.align, minimum_required_alignment: 1 });
1522                        }
1523                        stack.assert_pop_val_type(ValType::VecType)?;
1524                        stack.assert_pop_val_type(ValType::NumType(NumType::I32))?;
1525                    }
1526                    V128_STORE32_LANE => {
1527                        let memarg = MemArg::read(wasm)?;
1528                        let lane_idx = wasm.read_u8()?;
1529                        if lane_idx >= 4 {
1530                            return Err(ValidationError::InvalidLaneIdx(lane_idx));
1531                        }
1532                        let _mem_idx = MemIdx::validate(0, c_mems)?;
1533                        if memarg.align > 2 {
1534                            return Err(ValidationError::ErroneousAlignment { alignment: memarg.align, minimum_required_alignment: 2 });
1535                        }
1536                        stack.assert_pop_val_type(ValType::VecType)?;
1537                        stack.assert_pop_val_type(ValType::NumType(NumType::I32))?;
1538                    }
1539                    V128_STORE64_LANE => {
1540                        let memarg = MemArg::read(wasm)?;
1541                        let lane_idx = wasm.read_u8()?;
1542                        if lane_idx >= 2 {
1543                            return Err(ValidationError::InvalidLaneIdx(lane_idx));
1544                        }
1545                        let _mem_idx = MemIdx::validate(0, c_mems)?;
1546                        if memarg.align > 3 {
1547                            return Err(ValidationError::ErroneousAlignment { alignment: memarg.align, minimum_required_alignment: 3 });
1548                        }
1549                        stack.assert_pop_val_type(ValType::VecType)?;
1550                        stack.assert_pop_val_type(ValType::NumType(NumType::I32))?;
1551                    }
1552
1553                    V128_CONST => {
1554                        for _ in 0..16 {
1555                            let _data = wasm.read_u8()?;
1556                        }
1557                        stack.push_valtype(ValType::VecType);
1558                    }
1559
1560                    // vvunop <https://webassembly.github.io/spec/core/syntax/instructions.html#syntax-vvunop>
1561                    V128_NOT => {
1562                        stack.assert_pop_val_type(ValType::VecType)?;
1563                        stack.push_valtype(ValType::VecType);
1564                    }
1565
1566                    // vvbinop <https://webassembly.github.io/spec/core/syntax/instructions.html#syntax-vvbinop>
1567                    V128_AND | V128_ANDNOT | V128_OR | V128_XOR => {
1568                        stack.assert_pop_val_type(ValType::VecType)?;
1569                        stack.assert_pop_val_type(ValType::VecType)?;
1570                        stack.push_valtype(ValType::VecType);
1571                    }
1572
1573                    // vvternop <https://webassembly.github.io/spec/core/syntax/instructions.html#syntax-vvternop>
1574                    V128_BITSELECT => {
1575                        stack.assert_pop_val_type(ValType::VecType)?;
1576                        stack.assert_pop_val_type(ValType::VecType)?;
1577                        stack.assert_pop_val_type(ValType::VecType)?;
1578                        stack.push_valtype(ValType::VecType);
1579                    }
1580
1581                    // vvtestop <https://webassembly.github.io/spec/core/syntax/instructions.html#syntax-vvtestop>
1582                    V128_ANY_TRUE => {
1583                        stack.assert_pop_val_type(ValType::VecType)?;
1584                        stack.push_valtype(ValType::NumType(NumType::I32));
1585                    }
1586                    I8X16_SWIZZLE => {
1587                        stack.assert_pop_val_type(ValType::VecType)?;
1588                        stack.assert_pop_val_type(ValType::VecType)?;
1589                        stack.push_valtype(ValType::VecType);
1590                    }
1591                    I8X16_SHUFFLE => {
1592                        for _ in 0..16 {
1593                            let lane_idx = wasm.read_u8()?;
1594                            if lane_idx >= 32 {
1595                                return Err(ValidationError::InvalidLaneIdx(lane_idx));
1596                            }
1597                        }
1598                        stack.assert_pop_val_type(ValType::VecType)?;
1599                        stack.assert_pop_val_type(ValType::VecType)?;
1600                        stack.push_valtype(ValType::VecType);
1601                    }
1602
1603                    // shape.splat
1604                    I8X16_SPLAT | I16X8_SPLAT | I32X4_SPLAT => {
1605                        stack.assert_pop_val_type(ValType::NumType(NumType::I32))?;
1606                        stack.push_valtype(ValType::VecType);
1607                    }
1608                    I64X2_SPLAT => {
1609                        stack.assert_pop_val_type(ValType::NumType(NumType::I64))?;
1610                        stack.push_valtype(ValType::VecType);
1611                    }
1612                    F32X4_SPLAT => {
1613                        stack.assert_pop_val_type(ValType::NumType(NumType::F32))?;
1614                        stack.push_valtype(ValType::VecType);
1615                    }
1616                    F64X2_SPLAT => {
1617                        stack.assert_pop_val_type(ValType::NumType(NumType::F64))?;
1618                        stack.push_valtype(ValType::VecType);
1619                    }
1620
1621                    // shape.extract_lane
1622                    I8X16_EXTRACT_LANE_S | I8X16_EXTRACT_LANE_U => {
1623                        let lane_idx = wasm.read_u8()?;
1624                        if lane_idx >= 16 {
1625                            return Err(ValidationError::InvalidLaneIdx(lane_idx));
1626                        }
1627                        stack.assert_pop_val_type(ValType::VecType)?;
1628                        stack.push_valtype(ValType::NumType(NumType::I32));
1629                    }
1630                    I16X8_EXTRACT_LANE_S | I16X8_EXTRACT_LANE_U => {
1631                        let lane_idx = wasm.read_u8()?;
1632                        if lane_idx >= 8 {
1633                            return Err(ValidationError::InvalidLaneIdx(lane_idx));
1634                        }
1635                        stack.assert_pop_val_type(ValType::VecType)?;
1636                        stack.push_valtype(ValType::NumType(NumType::I32));
1637                    }
1638                    I32X4_EXTRACT_LANE => {
1639                        let lane_idx = wasm.read_u8()?;
1640                        if lane_idx >= 4 {
1641                            return Err(ValidationError::InvalidLaneIdx(lane_idx));
1642                        }
1643                        stack.assert_pop_val_type(ValType::VecType)?;
1644                        stack.push_valtype(ValType::NumType(NumType::I32));
1645                    }
1646                    I64X2_EXTRACT_LANE => {
1647                        let lane_idx = wasm.read_u8()?;
1648                        if lane_idx >= 2 {
1649                            return Err(ValidationError::InvalidLaneIdx(lane_idx));
1650                        }
1651                        stack.assert_pop_val_type(ValType::VecType)?;
1652                        stack.push_valtype(ValType::NumType(NumType::I64));
1653                    }
1654                    F32X4_EXTRACT_LANE => {
1655                        let lane_idx = wasm.read_u8()?;
1656                        if lane_idx >= 4 {
1657                            return Err(ValidationError::InvalidLaneIdx(lane_idx));
1658                        }
1659                        stack.assert_pop_val_type(ValType::VecType)?;
1660                        stack.push_valtype(ValType::NumType(NumType::F32));
1661                    }
1662                    F64X2_EXTRACT_LANE => {
1663                        let lane_idx = wasm.read_u8()?;
1664                        if lane_idx >= 2 {
1665                            return Err(ValidationError::InvalidLaneIdx(lane_idx));
1666                        }
1667                        stack.assert_pop_val_type(ValType::VecType)?;
1668                        stack.push_valtype(ValType::NumType(NumType::F64));
1669                    }
1670
1671                    // shape.replace_lane
1672                    I8X16_REPLACE_LANE => {
1673                        let lane_idx = wasm.read_u8()?;
1674                        if lane_idx >= 16 {
1675                            return Err(ValidationError::InvalidLaneIdx(lane_idx));
1676                        }
1677                        stack.assert_pop_val_type(ValType::NumType(NumType::I32))?;
1678                        stack.assert_pop_val_type(ValType::VecType)?;
1679                        stack.push_valtype(ValType::VecType);
1680                    }
1681                    I16X8_REPLACE_LANE => {
1682                        let lane_idx = wasm.read_u8()?;
1683                        if lane_idx >= 8 {
1684                            return Err(ValidationError::InvalidLaneIdx(lane_idx));
1685                        }
1686                        stack.assert_pop_val_type(ValType::NumType(NumType::I32))?;
1687                        stack.assert_pop_val_type(ValType::VecType)?;
1688                        stack.push_valtype(ValType::VecType);
1689                    }
1690                    I32X4_REPLACE_LANE => {
1691                        let lane_idx = wasm.read_u8()?;
1692                        if lane_idx >= 4 {
1693                            return Err(ValidationError::InvalidLaneIdx(lane_idx));
1694                        }
1695                        stack.assert_pop_val_type(ValType::NumType(NumType::I32))?;
1696                        stack.assert_pop_val_type(ValType::VecType)?;
1697                        stack.push_valtype(ValType::VecType);
1698                    }
1699                    I64X2_REPLACE_LANE => {
1700                        let lane_idx = wasm.read_u8()?;
1701                        if lane_idx >= 2 {
1702                            return Err(ValidationError::InvalidLaneIdx(lane_idx));
1703                        }
1704                        stack.assert_pop_val_type(ValType::NumType(NumType::I64))?;
1705                        stack.assert_pop_val_type(ValType::VecType)?;
1706                        stack.push_valtype(ValType::VecType);
1707                    }
1708                    F32X4_REPLACE_LANE => {
1709                        let lane_idx = wasm.read_u8()?;
1710                        if lane_idx >= 4 {
1711                            return Err(ValidationError::InvalidLaneIdx(lane_idx));
1712                        }
1713                        stack.assert_pop_val_type(ValType::NumType(NumType::F32))?;
1714                        stack.assert_pop_val_type(ValType::VecType)?;
1715                        stack.push_valtype(ValType::VecType);
1716                    }
1717                    F64X2_REPLACE_LANE => {
1718                        let lane_idx = wasm.read_u8()?;
1719                        if lane_idx >= 2 {
1720                            return Err(ValidationError::InvalidLaneIdx(lane_idx));
1721                        }
1722                        stack.assert_pop_val_type(ValType::NumType(NumType::F64))?;
1723                        stack.assert_pop_val_type(ValType::VecType)?;
1724                        stack.push_valtype(ValType::VecType);
1725                    }
1726
1727                    // Group vunop <https://webassembly.github.io/spec/core/syntax/instructions.html#syntax-vunop>
1728                    // viunop
1729                    I8X16_ABS | I16X8_ABS | I32X4_ABS | I64X2_ABS
1730                    | I8X16_NEG | I16X8_NEG | I32X4_NEG | I64X2_NEG
1731                    // vfunop
1732                    | F32X4_ABS | F64X2_ABS
1733                    | F32X4_NEG | F64X2_NEG
1734                    | F32X4_SQRT | F64X2_SQRT
1735                    | F32X4_CEIL | F64X2_CEIL
1736                    | F32X4_FLOOR | F64X2_FLOOR
1737                    | F32X4_TRUNC | F64X2_TRUNC
1738                    | F32X4_NEAREST | F64X2_NEAREST
1739                    // others
1740                    | I8X16_POPCNT
1741                    => {
1742                        stack.assert_pop_val_type(ValType::VecType)?;
1743                        stack.push_valtype(ValType::VecType);
1744                    }
1745
1746                    // Group vbinop <https://webassembly.github.io/spec/core/syntax/instructions.html#syntax-vbinop>
1747                    // vibinop
1748                    I8X16_ADD | I16X8_ADD | I32X4_ADD | I64X2_ADD
1749                    | I8X16_SUB | I16X8_SUB | I32X4_SUB | I64X2_SUB
1750                    // vfbinop
1751                    | F32X4_ADD | F64X2_ADD
1752                    | F32X4_SUB | F64X2_SUB
1753                    | F32X4_MUL | F64X2_MUL
1754                    | F32X4_DIV | F64X2_DIV
1755                    | F32X4_MIN | F64X2_MIN
1756                    | F32X4_MAX | F64X2_MAX
1757                    | F32X4_PMIN | F64X2_PMIN
1758                    | F32X4_PMAX | F64X2_PMAX
1759                    // viminmaxop
1760                    | I8X16_MIN_S | I16X8_MIN_S | I32X4_MIN_S
1761                    | I8X16_MIN_U | I16X8_MIN_U | I32X4_MIN_U
1762                    | I8X16_MAX_S | I16X8_MAX_S | I32X4_MAX_S
1763                    | I8X16_MAX_U | I16X8_MAX_U | I32X4_MAX_U
1764                    // visatbinop
1765                    | I8X16_ADD_SAT_S | I16X8_ADD_SAT_S
1766                    | I8X16_ADD_SAT_U | I16X8_ADD_SAT_U
1767                    | I8X16_SUB_SAT_S | I16X8_SUB_SAT_S
1768                    | I8X16_SUB_SAT_U | I16X8_SUB_SAT_U
1769                    // others
1770                    | I16X8_MUL | I32X4_MUL | I64X2_MUL
1771                    | I8X16_AVGR_U | I16X8_AVGR_U
1772                    | I16X8_Q15MULRSAT_S
1773                    => {
1774                        stack.assert_pop_val_type(ValType::VecType)?;
1775                        stack.assert_pop_val_type(ValType::VecType)?;
1776                        stack.push_valtype(ValType::VecType);
1777                    }
1778
1779                    // Group vrelop <https://webassembly.github.io/spec/core/syntax/instructions.html#syntax-vrelop>
1780                    // virelop
1781                    I8X16_EQ | I16X8_EQ | I32X4_EQ | I64X2_EQ
1782                    | I8X16_NE | I16X8_NE | I32X4_NE | I64X2_NE
1783                    | I8X16_LT_S | I16X8_LT_S | I32X4_LT_S | I64X2_LT_S
1784                    | I8X16_LT_U | I16X8_LT_U | I32X4_LT_U | I8X16_GT_S
1785                    | I16X8_GT_S | I32X4_GT_S | I64X2_GT_S
1786                    | I8X16_GT_U | I16X8_GT_U | I32X4_GT_U
1787                    | I8X16_LE_S | I16X8_LE_S | I32X4_LE_S | I64X2_LE_S
1788                    | I8X16_LE_U | I16X8_LE_U | I32X4_LE_U
1789                    | I8X16_GE_S | I16X8_GE_S | I32X4_GE_S | I64X2_GE_S
1790                    | I8X16_GE_U | I16X8_GE_U | I32X4_GE_U
1791                    // vfrelop
1792                    | F32X4_EQ | F64X2_EQ
1793                    | F32X4_NE | F64X2_NE
1794                    | F32X4_LT | F64X2_LT
1795                    | F32X4_GT | F64X2_GT
1796                    | F32X4_LE | F64X2_LE
1797                    | F32X4_GE | F64X2_GE
1798                    => {
1799                        stack.assert_pop_val_type(ValType::VecType)?;
1800                        stack.assert_pop_val_type(ValType::VecType)?;
1801                        stack.push_valtype(ValType::VecType);
1802                    }
1803
1804                    // Group vishiftop
1805                    I8X16_SHL | I16X8_SHL | I32X4_SHL | I64X2_SHL
1806                    | I8X16_SHR_S | I8X16_SHR_U | I16X8_SHR_S | I16X8_SHR_U | I32X4_SHR_S | I32X4_SHR_U | I64X2_SHR_S | I64X2_SHR_U
1807                     => {
1808                        stack.assert_pop_val_type(ValType::NumType(NumType::I32))?;
1809                        stack.assert_pop_val_type(ValType::VecType)?;
1810                        stack.push_valtype(ValType::VecType);
1811                    }
1812
1813                    // Group vtestop <https://webassembly.github.io/spec/core/syntax/instructions.html#syntax-vtestop>
1814                    // vitestop
1815                    I8X16_ALL_TRUE | I16X8_ALL_TRUE | I32X4_ALL_TRUE | I64X2_ALL_TRUE
1816                    => {
1817                        stack.assert_pop_val_type(ValType::VecType)?;
1818                        stack.push_valtype(ValType::NumType(NumType::I32));
1819                    }
1820
1821                    // Group vcvtop <https://webassembly.github.io/spec/core/syntax/instructions.html#syntax-vcvtop>
1822                    I16X8_EXTEND_HIGH_I8X16_S | I16X8_EXTEND_HIGH_I8X16_U | I16X8_EXTEND_LOW_I8X16_S | I16X8_EXTEND_LOW_I8X16_U
1823                    | I32X4_EXTEND_HIGH_I16X8_S | I32X4_EXTEND_HIGH_I16X8_U | I32X4_EXTEND_LOW_I16X8_S | I32X4_EXTEND_LOW_I16X8_U
1824                    | I64X2_EXTEND_HIGH_I32X4_S | I64X2_EXTEND_HIGH_I32X4_U | I64X2_EXTEND_LOW_I32X4_S | I64X2_EXTEND_LOW_I32X4_U
1825                    | I32X4_TRUNC_SAT_F32X4_S | I32X4_TRUNC_SAT_F32X4_U | I32X4_TRUNC_SAT_F64X2_S_ZERO | I32X4_TRUNC_SAT_F64X2_U_ZERO
1826                    | F32X4_CONVERT_I32X4_S | F32X4_CONVERT_I32X4_U | F64X2_CONVERT_LOW_I32X4_S | F64X2_CONVERT_LOW_I32X4_U
1827                    | F32X4_DEMOTE_F64X2_ZERO
1828                    | F64X2_PROMOTE_LOW_F32X4
1829                    => {
1830                        stack.assert_pop_val_type(ValType::VecType)?;
1831                        stack.push_valtype(ValType::VecType);
1832                    }
1833
1834                    // ishape.narrow_ishape_sx
1835                    | I8X16_NARROW_I16X8_S | I8X16_NARROW_I16X8_U
1836                    | I16X8_NARROW_I32X4_S | I16X8_NARROW_I32X4_U
1837                    => {
1838                        stack.assert_pop_val_type(ValType::VecType)?;
1839                        stack.assert_pop_val_type(ValType::VecType)?;
1840                        stack.push_valtype(ValType::VecType);
1841                    }
1842
1843                    // ishape.bitmask
1844                    I8X16_BITMASK | I16X8_BITMASK | I32X4_BITMASK | I64X2_BITMASK
1845                    => {
1846                        stack.assert_pop_val_type(ValType::VecType)?;
1847                        stack.push_valtype(ValType::NumType(NumType::I32));
1848                    }
1849
1850                    // ishape.dot_ishape_s
1851                    I32X4_DOT_I16X8_S => {
1852                        stack.assert_pop_val_type(ValType::VecType)?;
1853                        stack.assert_pop_val_type(ValType::VecType)?;
1854                        stack.push_valtype(ValType::VecType);
1855                    }
1856
1857                    // ishape.extmul_half_ishape_sx
1858                    I16X8_EXTMUL_HIGH_I8X16_S | I16X8_EXTMUL_HIGH_I8X16_U | I16X8_EXTMUL_LOW_I8X16_S | I16X8_EXTMUL_LOW_I8X16_U
1859                    | I32X4_EXTMUL_HIGH_I16X8_S | I32X4_EXTMUL_HIGH_I16X8_U | I32X4_EXTMUL_LOW_I16X8_S | I32X4_EXTMUL_LOW_I16X8_U
1860                    | I64X2_EXTMUL_HIGH_I32X4_S | I64X2_EXTMUL_HIGH_I32X4_U | I64X2_EXTMUL_LOW_I32X4_S | I64X2_EXTMUL_LOW_I32X4_U
1861                    => {
1862                        stack.assert_pop_val_type(ValType::VecType)?;
1863                        stack.assert_pop_val_type(ValType::VecType)?;
1864                        stack.push_valtype(ValType::VecType);
1865                    }
1866
1867                    // ishape.extadd_pairwise_ishape_sx
1868                    I16X8_EXTADD_PAIRWISE_I8X16_S | I16X8_EXTADD_PAIRWISE_I8X16_U
1869                    | I32X4_EXTADD_PAIRWISE_I16X8_S | I32X4_EXTADD_PAIRWISE_I16X8_U
1870                    => {
1871                        stack.assert_pop_val_type(ValType::VecType)?;
1872                        stack.push_valtype(ValType::VecType);
1873                    }
1874
1875                    // Unimplemented or invalid instructions
1876                    F32X4_RELAXED_MADD | F32X4_RELAXED_MAX | F32X4_RELAXED_MIN | F32X4_RELAXED_NMADD
1877                    | F64X2_RELAXED_MADD | F64X2_RELAXED_MAX | F64X2_RELAXED_MIN | F64X2_RELAXED_NMADD
1878                    | I8X16_RELAXED_LANESELECT | I16X8_RELAXED_LANESELECT | I32X4_RELAXED_LANESELECT | I64X2_RELAXED_LANESELECT
1879                    | I32X4_RELAXED_TRUNC_F32X4_S | I32X4_RELAXED_TRUNC_F32X4_U
1880                    | I32X4_RELAXED_TRUNC_F64X2_S_ZERO | I32X4_RELAXED_TRUNC_F64X2_U_ZERO
1881                    | I8X16_RELAXED_SWIZZLE
1882                    | 154 | 187 | 194 | 256.. => return Err(ValidationError::InvalidMultiByteInstr(first_instr_byte, second_instr)),
1883                }
1884            }
1885
1886            // Unimplemented or invalid instructions
1887            0x06..=0x0A
1888            | 0x12..=0x19
1889            | 0x1C..=0x1F
1890            | 0x25..=0x27
1891            | 0xC0..=0xFA
1892            | 0xFB
1893            | 0xFE
1894            | 0xFF => {
1895                return Err(ValidationError::InvalidInstr(first_instr_byte));
1896            }
1897        }
1898    }
1899}