wasm/validation/
code.rs

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