wasm/validation/
code.rs

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