wasm/execution/
interpreter_loop.rs

1//! This module solely contains the actual interpretation loop that matches instructions, interpreting the WASM bytecode
2//!
3//!
4//! # Note to Developer:
5//!
6//! 1. There must be only imports and one `impl` with one function (`run`) in it.
7//! 2. This module must only use [`RuntimeError`] and never [`Error`](crate::core::error::ValidationError).
8
9use core::{
10    num::NonZeroU32,
11    {
12        array,
13        iter::zip,
14        ops::{Add, Div, Mul, Neg, Sub},
15    },
16};
17
18use crate::{
19    addrs::{AddrVec, DataAddr, ElemAddr, MemAddr, ModuleAddr, TableAddr},
20    assert_validated::UnwrapValidatedExt,
21    core::{
22        indices::{DataIdx, FuncIdx, GlobalIdx, LabelIdx, LocalIdx, MemIdx, TableIdx, TypeIdx},
23        reader::{
24            types::{memarg::MemArg, BlockType},
25            WasmReadable, WasmReader,
26        },
27        sidetable::Sidetable,
28    },
29    instances::{DataInst, ElemInst, FuncInst, MemInst, ModuleInst, TableInst},
30    resumable::Resumable,
31    store::HaltExecutionError,
32    unreachable_validated,
33    value::{self, Ref, F32, F64},
34    value_stack::Stack,
35    RefType, RuntimeError, TrapError, ValType, Value,
36};
37
38use crate::execution::config::Config;
39
40use super::{little_endian::LittleEndianBytes, store::Store};
41
42/// Interprets wasm native functions. Wasm parameters and Wasm return values are passed on the stack.
43/// Returns `Ok(None)` in case execution successfully terminates, `Ok(Some(required_fuel))` if execution
44/// terminates due to insufficient fuel, indicating how much fuel is required to resume with `required_fuel`,
45/// and `[Error::RuntimeError]` otherwise.
46pub(super) fn run<T: Config>(
47    resumable: &mut Resumable,
48    store: &mut Store<T>,
49) -> Result<Option<NonZeroU32>, RuntimeError> {
50    let stack = &mut resumable.stack;
51    let mut current_func_addr = resumable.current_func_addr;
52    let pc = resumable.pc;
53    let mut stp = resumable.stp;
54    let func_inst = store.functions.get(current_func_addr);
55    let FuncInst::WasmFunc(wasm_func_inst) = &func_inst else {
56        unreachable!(
57            "the interpreter loop shall only be executed with native wasm functions as root call"
58        );
59    };
60    let mut current_module = wasm_func_inst.module_addr;
61
62    // Start reading the function's instructions
63    let wasm = &mut WasmReader::new(store.modules.get(current_module).wasm_bytecode);
64
65    let mut current_sidetable: &Sidetable = &store.modules.get(current_module).sidetable;
66
67    // local variable for holding where the function code ends (last END instr address + 1) to avoid lookup at every END instr
68    let mut current_function_end_marker =
69        wasm_func_inst.code_expr.from() + wasm_func_inst.code_expr.len();
70
71    wasm.pc = pc;
72
73    use crate::core::reader::types::opcode::*;
74    loop {
75        // call the instruction hook
76        store
77            .user_data
78            .instruction_hook(store.modules.get(current_module).wasm_bytecode, wasm.pc);
79
80        // Fuel mechanism: 1 fuel per instruction
81        if let Some(fuel) = &mut resumable.maybe_fuel {
82            if *fuel >= 1 {
83                *fuel -= 1;
84            } else {
85                resumable.current_func_addr = current_func_addr;
86                resumable.pc = wasm.pc;
87                resumable.stp = stp;
88                return Ok(NonZeroU32::new(1));
89            }
90        }
91
92        let first_instr_byte = wasm.read_u8().unwrap_validated();
93
94        #[cfg(debug_assertions)]
95        trace!(
96            "Executing instruction {}",
97            opcode_byte_to_str(first_instr_byte)
98        );
99
100        match first_instr_byte {
101            NOP => {
102                trace!("Instruction: NOP");
103            }
104            END => {
105                // There might be multiple ENDs in a single function. We want to
106                // exit only when the outermost block (aka function block) ends.
107                if wasm.pc != current_function_end_marker {
108                    continue;
109                }
110
111                let (maybe_return_func_addr, maybe_return_address, maybe_return_stp) =
112                    stack.pop_call_frame();
113
114                // We finished this entire invocation if there is no call frame left. If there are
115                // one or more call frames, we need to continue from where the callee was called
116                // from.
117                if stack.call_frame_count() == 0 {
118                    break;
119                }
120
121                trace!("end of function reached, returning to previous call frame");
122                current_func_addr = maybe_return_func_addr;
123                let FuncInst::WasmFunc(current_wasm_func_inst) =
124                    store.functions.get(current_func_addr)
125                else {
126                    unreachable!("function addresses on the stack always correspond to native wasm functions")
127                };
128                current_module = current_wasm_func_inst.module_addr;
129                wasm.full_wasm_binary = store.modules.get(current_module).wasm_bytecode;
130                wasm.pc = maybe_return_address;
131                stp = maybe_return_stp;
132
133                current_sidetable = &store.modules.get(current_module).sidetable;
134
135                current_function_end_marker = current_wasm_func_inst.code_expr.from()
136                    + current_wasm_func_inst.code_expr.len();
137
138                trace!("Instruction: END");
139            }
140            IF => {
141                wasm.read_var_u32().unwrap_validated();
142
143                let test_val: i32 = stack.pop_value().try_into().unwrap_validated();
144
145                if test_val != 0 {
146                    stp += 1;
147                } else {
148                    do_sidetable_control_transfer(wasm, stack, &mut stp, current_sidetable)?;
149                }
150                trace!("Instruction: IF");
151            }
152            ELSE => {
153                do_sidetable_control_transfer(wasm, stack, &mut stp, current_sidetable)?;
154            }
155            BR_IF => {
156                wasm.read_var_u32().unwrap_validated();
157
158                let test_val: i32 = stack.pop_value().try_into().unwrap_validated();
159
160                if test_val != 0 {
161                    do_sidetable_control_transfer(wasm, stack, &mut stp, current_sidetable)?;
162                } else {
163                    stp += 1;
164                }
165                trace!("Instruction: BR_IF");
166            }
167            BR_TABLE => {
168                let label_vec = wasm
169                    .read_vec(|wasm| wasm.read_var_u32().map(|v| v as LabelIdx))
170                    .unwrap_validated();
171                wasm.read_var_u32().unwrap_validated();
172
173                // TODO is this correct?
174                let case_val_i32: i32 = stack.pop_value().try_into().unwrap_validated();
175                let case_val = case_val_i32 as usize;
176
177                if case_val >= label_vec.len() {
178                    stp += label_vec.len();
179                } else {
180                    stp += case_val;
181                }
182
183                do_sidetable_control_transfer(wasm, stack, &mut stp, current_sidetable)?;
184            }
185            BR => {
186                //skip n of BR n
187                wasm.read_var_u32().unwrap_validated();
188                do_sidetable_control_transfer(wasm, stack, &mut stp, current_sidetable)?;
189            }
190            BLOCK | LOOP => {
191                BlockType::read(wasm).unwrap_validated();
192            }
193            RETURN => {
194                //same as BR, except no need to skip n of BR n
195                do_sidetable_control_transfer(wasm, stack, &mut stp, current_sidetable)?;
196            }
197            CALL => {
198                let local_func_idx = wasm.read_var_u32().unwrap_validated() as FuncIdx;
199                let FuncInst::WasmFunc(current_wasm_func_inst) =
200                    store.functions.get(current_func_addr)
201                else {
202                    unreachable!()
203                };
204
205                let func_to_call_addr = store
206                    .modules
207                    .get(current_wasm_func_inst.module_addr)
208                    .func_addrs[local_func_idx];
209
210                let func_to_call_ty = store.functions.get(func_to_call_addr).ty();
211
212                trace!("Instruction: call [{func_to_call_addr:?}]");
213
214                match store.functions.get(func_to_call_addr) {
215                    FuncInst::HostFunc(host_func_to_call_inst) => {
216                        let params = stack
217                            .pop_tail_iter(func_to_call_ty.params.valtypes.len())
218                            .collect();
219                        let returns =
220                            (host_func_to_call_inst.hostcode)(&mut store.user_data, params);
221
222                        let returns = returns.map_err(|HaltExecutionError| {
223                            RuntimeError::HostFunctionHaltedExecution
224                        })?;
225
226                        // Verify that the return parameters match the host function parameters
227                        // since we have no validation guarantees for host functions
228                        if returns.len() != func_to_call_ty.returns.valtypes.len() {
229                            return Err(RuntimeError::HostFunctionSignatureMismatch);
230                        }
231                        for (value, ty) in zip(returns, func_to_call_ty.returns.valtypes) {
232                            if value.to_ty() != ty {
233                                return Err(RuntimeError::HostFunctionSignatureMismatch);
234                            }
235                            stack.push_value::<T>(value)?;
236                        }
237                    }
238                    FuncInst::WasmFunc(wasm_func_to_call_inst) => {
239                        let remaining_locals = &wasm_func_to_call_inst.locals;
240
241                        stack.push_call_frame::<T>(
242                            current_func_addr,
243                            &func_to_call_ty,
244                            remaining_locals,
245                            wasm.pc,
246                            stp,
247                        )?;
248
249                        current_func_addr = func_to_call_addr;
250                        current_module = wasm_func_to_call_inst.module_addr;
251                        wasm.full_wasm_binary = store.modules.get(current_module).wasm_bytecode;
252                        wasm.move_start_to(wasm_func_to_call_inst.code_expr)
253                            .expect("code expression spans to always be valid");
254
255                        stp = wasm_func_to_call_inst.stp;
256                        current_sidetable = &store.modules.get(current_module).sidetable;
257                        current_function_end_marker = wasm_func_to_call_inst.code_expr.from()
258                            + wasm_func_to_call_inst.code_expr.len();
259                    }
260                }
261                trace!("Instruction: CALL");
262            }
263
264            // TODO: fix push_call_frame, because the func idx that you get from the table is global func idx
265            CALL_INDIRECT => {
266                let given_type_idx = wasm.read_var_u32().unwrap_validated() as TypeIdx;
267                let table_idx = wasm.read_var_u32().unwrap_validated() as TableIdx;
268
269                let table_addr = *store
270                    .modules
271                    .get(current_module)
272                    .table_addrs
273                    .get(table_idx)
274                    .unwrap_validated();
275                let tab = store.tables.get(table_addr);
276                let func_ty = store
277                    .modules
278                    .get(current_module)
279                    .types
280                    .get(given_type_idx)
281                    .unwrap_validated();
282
283                let i: u32 = stack.pop_value().try_into().unwrap_validated();
284
285                let r = tab
286                    .elem
287                    .get(i as usize)
288                    .ok_or(TrapError::TableAccessOutOfBounds)
289                    .and_then(|r| {
290                        if matches!(r, Ref::Null(_)) {
291                            trace!("table_idx ({table_idx}) --- element index in table ({i})");
292                            Err(TrapError::UninitializedElement)
293                        } else {
294                            Ok(r)
295                        }
296                    })?;
297
298                let func_to_call_addr = match *r {
299                    Ref::Func(func_addr) => func_addr,
300                    Ref::Null(_) => return Err(TrapError::IndirectCallNullFuncRef.into()),
301                    Ref::Extern(_) => unreachable_validated!(),
302                };
303
304                let func_to_call_ty = store.functions.get(func_to_call_addr).ty();
305                if *func_ty != func_to_call_ty {
306                    return Err(TrapError::SignatureMismatch.into());
307                }
308
309                trace!("Instruction: call [{func_to_call_addr:?}]");
310
311                match store.functions.get(func_to_call_addr) {
312                    FuncInst::HostFunc(host_func_to_call_inst) => {
313                        let params = stack
314                            .pop_tail_iter(func_to_call_ty.params.valtypes.len())
315                            .collect();
316                        let returns =
317                            (host_func_to_call_inst.hostcode)(&mut store.user_data, params);
318
319                        let returns = returns.map_err(|HaltExecutionError| {
320                            RuntimeError::HostFunctionHaltedExecution
321                        })?;
322
323                        // Verify that the return parameters match the host function parameters
324                        // since we have no validation guarantees for host functions
325                        if returns.len() != func_to_call_ty.returns.valtypes.len() {
326                            return Err(RuntimeError::HostFunctionSignatureMismatch);
327                        }
328                        for (value, ty) in zip(returns, func_to_call_ty.returns.valtypes) {
329                            if value.to_ty() != ty {
330                                return Err(RuntimeError::HostFunctionSignatureMismatch);
331                            }
332                            stack.push_value::<T>(value)?;
333                        }
334                    }
335                    FuncInst::WasmFunc(wasm_func_to_call_inst) => {
336                        let remaining_locals = &wasm_func_to_call_inst.locals;
337
338                        stack.push_call_frame::<T>(
339                            current_func_addr,
340                            &func_to_call_ty,
341                            remaining_locals,
342                            wasm.pc,
343                            stp,
344                        )?;
345
346                        current_func_addr = func_to_call_addr;
347                        current_module = wasm_func_to_call_inst.module_addr;
348                        wasm.full_wasm_binary = store.modules.get(current_module).wasm_bytecode;
349                        wasm.move_start_to(wasm_func_to_call_inst.code_expr)
350                            .expect("code expression spans to always be valid");
351
352                        stp = wasm_func_to_call_inst.stp;
353                        current_sidetable = &store.modules.get(current_module).sidetable;
354                        current_function_end_marker = wasm_func_to_call_inst.code_expr.from()
355                            + wasm_func_to_call_inst.code_expr.len();
356                    }
357                }
358                trace!("Instruction: CALL_INDIRECT");
359            }
360            DROP => {
361                stack.pop_value();
362                trace!("Instruction: DROP");
363            }
364            SELECT => {
365                let test_val: i32 = stack.pop_value().try_into().unwrap_validated();
366                let val2 = stack.pop_value();
367                let val1 = stack.pop_value();
368                if test_val != 0 {
369                    stack.push_value::<T>(val1)?;
370                } else {
371                    stack.push_value::<T>(val2)?;
372                }
373                trace!("Instruction: SELECT");
374            }
375            SELECT_T => {
376                let _type_vec = wasm.read_vec(ValType::read).unwrap_validated();
377                let test_val: i32 = stack.pop_value().try_into().unwrap_validated();
378                let val2 = stack.pop_value();
379                let val1 = stack.pop_value();
380                if test_val != 0 {
381                    stack.push_value::<T>(val1)?;
382                } else {
383                    stack.push_value::<T>(val2)?;
384                }
385                trace!("Instruction: SELECT_T");
386            }
387            LOCAL_GET => {
388                let local_idx = wasm.read_var_u32().unwrap_validated() as LocalIdx;
389                let value = *stack.get_local(local_idx);
390                stack.push_value::<T>(value)?;
391                trace!("Instruction: local.get {} [] -> [t]", local_idx);
392            }
393            LOCAL_SET => {
394                let local_idx = wasm.read_var_u32().unwrap_validated() as LocalIdx;
395                let value = stack.pop_value();
396                *stack.get_local_mut(local_idx) = value;
397                trace!("Instruction: local.set {} [t] -> []", local_idx);
398            }
399            LOCAL_TEE => {
400                let local_idx = wasm.read_var_u32().unwrap_validated() as LocalIdx;
401                let value = stack.peek_value().unwrap_validated();
402                *stack.get_local_mut(local_idx) = value;
403                trace!("Instruction: local.tee {} [t] -> [t]", local_idx);
404            }
405            GLOBAL_GET => {
406                let global_idx = wasm.read_var_u32().unwrap_validated() as GlobalIdx;
407                let global_addr = *store
408                    .modules
409                    .get(current_module)
410                    .global_addrs
411                    .get(global_idx)
412                    .unwrap_validated();
413                let global = store.globals.get(global_addr);
414
415                stack.push_value::<T>(global.value)?;
416
417                trace!(
418                    "Instruction: global.get '{}' [<GLOBAL>] -> [{:?}]",
419                    global_idx,
420                    global.value
421                );
422            }
423            GLOBAL_SET => {
424                let global_idx = wasm.read_var_u32().unwrap_validated() as GlobalIdx;
425                let global_addr = *store
426                    .modules
427                    .get(current_module)
428                    .global_addrs
429                    .get(global_idx)
430                    .unwrap_validated();
431                let global = store.globals.get_mut(global_addr);
432                global.value = stack.pop_value();
433                trace!("Instruction: GLOBAL_SET");
434            }
435            TABLE_GET => {
436                let table_idx = wasm.read_var_u32().unwrap_validated() as TableIdx;
437                let table_addr = *store
438                    .modules
439                    .get(current_module)
440                    .table_addrs
441                    .get(table_idx)
442                    .unwrap_validated();
443                let tab = store.tables.get(table_addr);
444
445                let i: i32 = stack.pop_value().try_into().unwrap_validated();
446
447                let val = tab
448                    .elem
449                    .get(i as usize)
450                    .ok_or(TrapError::TableOrElementAccessOutOfBounds)?;
451
452                stack.push_value::<T>((*val).into())?;
453                trace!(
454                    "Instruction: table.get '{}' [{}] -> [{}]",
455                    table_idx,
456                    i,
457                    val
458                );
459            }
460            TABLE_SET => {
461                let table_idx = wasm.read_var_u32().unwrap_validated() as TableIdx;
462                let table_addr = *store
463                    .modules
464                    .get(current_module)
465                    .table_addrs
466                    .get(table_idx)
467                    .unwrap_validated();
468                let tab = store.tables.get_mut(table_addr);
469
470                let val: Ref = stack.pop_value().try_into().unwrap_validated();
471                let i: i32 = stack.pop_value().try_into().unwrap_validated();
472
473                tab.elem
474                    .get_mut(i as usize)
475                    .ok_or(TrapError::TableOrElementAccessOutOfBounds)
476                    .map(|r| *r = val)?;
477                trace!(
478                    "Instruction: table.set '{}' [{} {}] -> []",
479                    table_idx,
480                    i,
481                    val
482                )
483            }
484            UNREACHABLE => {
485                return Err(TrapError::ReachedUnreachable.into());
486            }
487            I32_LOAD => {
488                let memarg = MemArg::read(wasm).unwrap_validated();
489                let relative_address: u32 = stack.pop_value().try_into().unwrap_validated();
490
491                let mem_addr = *store
492                    .modules
493                    .get(current_module)
494                    .mem_addrs
495                    .first()
496                    .unwrap_validated();
497                let mem_inst = store.memories.get(mem_addr);
498
499                let idx = calculate_mem_address(&memarg, relative_address)?;
500                let data = mem_inst.mem.load(idx)?;
501
502                stack.push_value::<T>(Value::I32(data))?;
503                trace!("Instruction: i32.load [{relative_address}] -> [{data}]");
504            }
505            I64_LOAD => {
506                let memarg = MemArg::read(wasm).unwrap_validated();
507                let relative_address: u32 = stack.pop_value().try_into().unwrap_validated();
508
509                let mem_addr = *store
510                    .modules
511                    .get(current_module)
512                    .mem_addrs
513                    .first()
514                    .unwrap_validated();
515                let mem = store.memories.get(mem_addr);
516
517                let idx = calculate_mem_address(&memarg, relative_address)?;
518                let data = mem.mem.load(idx)?;
519
520                stack.push_value::<T>(Value::I64(data))?;
521                trace!("Instruction: i64.load [{relative_address}] -> [{data}]");
522            }
523            F32_LOAD => {
524                let memarg = MemArg::read(wasm).unwrap_validated();
525                let relative_address: u32 = stack.pop_value().try_into().unwrap_validated();
526
527                let mem_addr = *store
528                    .modules
529                    .get(current_module)
530                    .mem_addrs
531                    .first()
532                    .unwrap_validated();
533                let mem = store.memories.get(mem_addr);
534
535                let idx = calculate_mem_address(&memarg, relative_address)?;
536                let data = mem.mem.load(idx)?;
537
538                stack.push_value::<T>(Value::F32(data))?;
539                trace!("Instruction: f32.load [{relative_address}] -> [{data}]");
540            }
541            F64_LOAD => {
542                let memarg = MemArg::read(wasm).unwrap_validated();
543                let relative_address: u32 = stack.pop_value().try_into().unwrap_validated();
544
545                let mem_addr = *store
546                    .modules
547                    .get(current_module)
548                    .mem_addrs
549                    .first()
550                    .unwrap_validated();
551                let mem = store.memories.get(mem_addr);
552
553                let idx = calculate_mem_address(&memarg, relative_address)?;
554                let data = mem.mem.load(idx)?;
555
556                stack.push_value::<T>(Value::F64(data))?;
557                trace!("Instruction: f64.load [{relative_address}] -> [{data}]");
558            }
559            I32_LOAD8_S => {
560                let memarg = MemArg::read(wasm).unwrap_validated();
561                let relative_address: u32 = stack.pop_value().try_into().unwrap_validated();
562
563                let mem_addr = *store
564                    .modules
565                    .get(current_module)
566                    .mem_addrs
567                    .first()
568                    .unwrap_validated();
569                let mem = store.memories.get(mem_addr);
570
571                let idx = calculate_mem_address(&memarg, relative_address)?;
572                let data: i8 = mem.mem.load(idx)?;
573
574                stack.push_value::<T>(Value::I32(data as u32))?;
575                trace!("Instruction: i32.load8_s [{relative_address}] -> [{data}]");
576            }
577            I32_LOAD8_U => {
578                let memarg = MemArg::read(wasm).unwrap_validated();
579                let relative_address: u32 = stack.pop_value().try_into().unwrap_validated();
580
581                let mem_addr = *store
582                    .modules
583                    .get(current_module)
584                    .mem_addrs
585                    .first()
586                    .unwrap_validated();
587                let mem = store.memories.get(mem_addr);
588
589                let idx = calculate_mem_address(&memarg, relative_address)?;
590                let data: u8 = mem.mem.load(idx)?;
591
592                stack.push_value::<T>(Value::I32(data as u32))?;
593                trace!("Instruction: i32.load8_u [{relative_address}] -> [{data}]");
594            }
595            I32_LOAD16_S => {
596                let memarg = MemArg::read(wasm).unwrap_validated();
597                let relative_address: u32 = stack.pop_value().try_into().unwrap_validated();
598
599                let mem_addr = *store
600                    .modules
601                    .get(current_module)
602                    .mem_addrs
603                    .first()
604                    .unwrap_validated();
605                let mem = store.memories.get(mem_addr);
606
607                let idx = calculate_mem_address(&memarg, relative_address)?;
608                let data: i16 = mem.mem.load(idx)?;
609
610                stack.push_value::<T>(Value::I32(data as u32))?;
611                trace!("Instruction: i32.load16_s [{relative_address}] -> [{data}]");
612            }
613            I32_LOAD16_U => {
614                let memarg = MemArg::read(wasm).unwrap_validated();
615                let relative_address: u32 = stack.pop_value().try_into().unwrap_validated();
616
617                let mem_addr = *store
618                    .modules
619                    .get(current_module)
620                    .mem_addrs
621                    .first()
622                    .unwrap_validated();
623                let mem = store.memories.get(mem_addr);
624
625                let idx = calculate_mem_address(&memarg, relative_address)?;
626                let data: u16 = mem.mem.load(idx)?;
627
628                stack.push_value::<T>(Value::I32(data as u32))?;
629                trace!("Instruction: i32.load16_u [{relative_address}] -> [{data}]");
630            }
631            I64_LOAD8_S => {
632                let memarg = MemArg::read(wasm).unwrap_validated();
633                let relative_address: u32 = stack.pop_value().try_into().unwrap_validated();
634
635                let mem_addr = *store
636                    .modules
637                    .get(current_module)
638                    .mem_addrs
639                    .first()
640                    .unwrap_validated();
641                let mem = store.memories.get(mem_addr);
642
643                let idx = calculate_mem_address(&memarg, relative_address)?;
644                let data: i8 = mem.mem.load(idx)?;
645
646                stack.push_value::<T>(Value::I64(data as u64))?;
647                trace!("Instruction: i64.load8_s [{relative_address}] -> [{data}]");
648            }
649            I64_LOAD8_U => {
650                let memarg = MemArg::read(wasm).unwrap_validated();
651                let relative_address: u32 = stack.pop_value().try_into().unwrap_validated();
652
653                let mem_addr = *store
654                    .modules
655                    .get(current_module)
656                    .mem_addrs
657                    .first()
658                    .unwrap_validated();
659                let mem = store.memories.get(mem_addr);
660
661                let idx = calculate_mem_address(&memarg, relative_address)?;
662                let data: u8 = mem.mem.load(idx)?;
663
664                stack.push_value::<T>(Value::I64(data as u64))?;
665                trace!("Instruction: i64.load8_u [{relative_address}] -> [{data}]");
666            }
667            I64_LOAD16_S => {
668                let memarg = MemArg::read(wasm).unwrap_validated();
669                let relative_address: u32 = stack.pop_value().try_into().unwrap_validated();
670
671                let mem_addr = *store
672                    .modules
673                    .get(current_module)
674                    .mem_addrs
675                    .first()
676                    .unwrap_validated();
677                let mem = store.memories.get(mem_addr);
678
679                let idx = calculate_mem_address(&memarg, relative_address)?;
680                let data: i16 = mem.mem.load(idx)?;
681
682                stack.push_value::<T>(Value::I64(data as u64))?;
683                trace!("Instruction: i64.load16_s [{relative_address}] -> [{data}]");
684            }
685            I64_LOAD16_U => {
686                let memarg = MemArg::read(wasm).unwrap_validated();
687                let relative_address: u32 = stack.pop_value().try_into().unwrap_validated();
688
689                let mem_addr = *store
690                    .modules
691                    .get(current_module)
692                    .mem_addrs
693                    .first()
694                    .unwrap_validated();
695                let mem = store.memories.get(mem_addr);
696
697                let idx = calculate_mem_address(&memarg, relative_address)?;
698                let data: u16 = mem.mem.load(idx)?;
699
700                stack.push_value::<T>(Value::I64(data as u64))?;
701                trace!("Instruction: i64.load16_u [{relative_address}] -> [{data}]");
702            }
703            I64_LOAD32_S => {
704                let memarg = MemArg::read(wasm).unwrap_validated();
705                let relative_address: u32 = stack.pop_value().try_into().unwrap_validated();
706
707                let mem_addr = *store
708                    .modules
709                    .get(current_module)
710                    .mem_addrs
711                    .first()
712                    .unwrap_validated();
713                let mem = store.memories.get(mem_addr);
714
715                let idx = calculate_mem_address(&memarg, relative_address)?;
716                let data: i32 = mem.mem.load(idx)?;
717
718                stack.push_value::<T>(Value::I64(data as u64))?;
719                trace!("Instruction: i64.load32_s [{relative_address}] -> [{data}]");
720            }
721            I64_LOAD32_U => {
722                let memarg = MemArg::read(wasm).unwrap_validated();
723                let relative_address: u32 = stack.pop_value().try_into().unwrap_validated();
724
725                let mem_addr = *store
726                    .modules
727                    .get(current_module)
728                    .mem_addrs
729                    .first()
730                    .unwrap_validated();
731                let mem = store.memories.get(mem_addr);
732
733                let idx = calculate_mem_address(&memarg, relative_address)?;
734                let data: u32 = mem.mem.load(idx)?;
735
736                stack.push_value::<T>(Value::I64(data as u64))?;
737                trace!("Instruction: i64.load32_u [{relative_address}] -> [{data}]");
738            }
739            I32_STORE => {
740                let memarg = MemArg::read(wasm).unwrap_validated();
741
742                let data_to_store: u32 = stack.pop_value().try_into().unwrap_validated();
743                let relative_address: u32 = stack.pop_value().try_into().unwrap_validated();
744
745                let mem_addr = *store
746                    .modules
747                    .get(current_module)
748                    .mem_addrs
749                    .first()
750                    .unwrap_validated();
751                let mem = store.memories.get(mem_addr);
752
753                let idx = calculate_mem_address(&memarg, relative_address)?;
754                mem.mem.store(idx, data_to_store)?;
755
756                trace!("Instruction: i32.store [{relative_address} {data_to_store}] -> []");
757            }
758            I64_STORE => {
759                let memarg = MemArg::read(wasm).unwrap_validated();
760
761                let data_to_store: u64 = stack.pop_value().try_into().unwrap_validated();
762                let relative_address: u32 = stack.pop_value().try_into().unwrap_validated();
763
764                let mem_addr = *store
765                    .modules
766                    .get(current_module)
767                    .mem_addrs
768                    .first()
769                    .unwrap_validated();
770                let mem = store.memories.get(mem_addr);
771
772                let idx = calculate_mem_address(&memarg, relative_address)?;
773                mem.mem.store(idx, data_to_store)?;
774
775                trace!("Instruction: i64.store [{relative_address} {data_to_store}] -> []");
776            }
777            F32_STORE => {
778                let memarg = MemArg::read(wasm).unwrap_validated();
779
780                let data_to_store: F32 = stack.pop_value().try_into().unwrap_validated();
781                let relative_address: u32 = stack.pop_value().try_into().unwrap_validated();
782
783                let mem_addr = *store
784                    .modules
785                    .get(current_module)
786                    .mem_addrs
787                    .first()
788                    .unwrap_validated();
789                let mem = store.memories.get(mem_addr);
790
791                let idx = calculate_mem_address(&memarg, relative_address)?;
792                mem.mem.store(idx, data_to_store)?;
793
794                trace!("Instruction: f32.store [{relative_address} {data_to_store}] -> []");
795            }
796            F64_STORE => {
797                let memarg = MemArg::read(wasm).unwrap_validated();
798
799                let data_to_store: F64 = stack.pop_value().try_into().unwrap_validated();
800                let relative_address: u32 = stack.pop_value().try_into().unwrap_validated();
801
802                let mem_addr = *store
803                    .modules
804                    .get(current_module)
805                    .mem_addrs
806                    .first()
807                    .unwrap_validated();
808                let mem = store.memories.get(mem_addr);
809
810                let idx = calculate_mem_address(&memarg, relative_address)?;
811                mem.mem.store(idx, data_to_store)?;
812
813                trace!("Instruction: f64.store [{relative_address} {data_to_store}] -> []");
814            }
815            I32_STORE8 => {
816                let memarg = MemArg::read(wasm).unwrap_validated();
817
818                let data_to_store: i32 = stack.pop_value().try_into().unwrap_validated();
819                let relative_address: u32 = stack.pop_value().try_into().unwrap_validated();
820
821                let wrapped_data = data_to_store as i8;
822
823                let mem_addr = *store
824                    .modules
825                    .get(current_module)
826                    .mem_addrs
827                    .first()
828                    .unwrap_validated();
829                let mem = store.memories.get(mem_addr);
830
831                let idx = calculate_mem_address(&memarg, relative_address)?;
832                mem.mem.store(idx, wrapped_data)?;
833
834                trace!("Instruction: i32.store8 [{relative_address} {wrapped_data}] -> []");
835            }
836            I32_STORE16 => {
837                let memarg = MemArg::read(wasm).unwrap_validated();
838
839                let data_to_store: i32 = stack.pop_value().try_into().unwrap_validated();
840                let relative_address: u32 = stack.pop_value().try_into().unwrap_validated();
841
842                let wrapped_data = data_to_store as i16;
843
844                let mem_addr = *store
845                    .modules
846                    .get(current_module)
847                    .mem_addrs
848                    .first()
849                    .unwrap_validated();
850                let mem = store.memories.get(mem_addr);
851
852                let idx = calculate_mem_address(&memarg, relative_address)?;
853                mem.mem.store(idx, wrapped_data)?;
854
855                trace!("Instruction: i32.store16 [{relative_address} {data_to_store}] -> []");
856            }
857            I64_STORE8 => {
858                let memarg = MemArg::read(wasm).unwrap_validated();
859
860                let data_to_store: i64 = stack.pop_value().try_into().unwrap_validated();
861                let relative_address: u32 = stack.pop_value().try_into().unwrap_validated();
862
863                let wrapped_data = data_to_store as i8;
864
865                let mem_addr = *store
866                    .modules
867                    .get(current_module)
868                    .mem_addrs
869                    .first()
870                    .unwrap_validated();
871                let mem = store.memories.get(mem_addr);
872
873                let idx = calculate_mem_address(&memarg, relative_address)?;
874                mem.mem.store(idx, wrapped_data)?;
875
876                trace!("Instruction: i64.store8 [{relative_address} {data_to_store}] -> []");
877            }
878            I64_STORE16 => {
879                let memarg = MemArg::read(wasm).unwrap_validated();
880
881                let data_to_store: i64 = stack.pop_value().try_into().unwrap_validated();
882                let relative_address: u32 = stack.pop_value().try_into().unwrap_validated();
883
884                let wrapped_data = data_to_store as i16;
885
886                let mem_addr = *store
887                    .modules
888                    .get(current_module)
889                    .mem_addrs
890                    .first()
891                    .unwrap_validated();
892                let mem = store.memories.get(mem_addr);
893
894                let idx = calculate_mem_address(&memarg, relative_address)?;
895                mem.mem.store(idx, wrapped_data)?;
896
897                trace!("Instruction: i64.store16 [{relative_address} {data_to_store}] -> []");
898            }
899            I64_STORE32 => {
900                let memarg = MemArg::read(wasm).unwrap_validated();
901
902                let data_to_store: i64 = stack.pop_value().try_into().unwrap_validated();
903                let relative_address: u32 = stack.pop_value().try_into().unwrap_validated();
904
905                let wrapped_data = data_to_store as i32;
906
907                let mem_addr = *store
908                    .modules
909                    .get(current_module)
910                    .mem_addrs
911                    .first()
912                    .unwrap_validated();
913                let mem = store.memories.get(mem_addr);
914
915                let idx = calculate_mem_address(&memarg, relative_address)?;
916                mem.mem.store(idx, wrapped_data)?;
917
918                trace!("Instruction: i64.store32 [{relative_address} {data_to_store}] -> []");
919            }
920            MEMORY_SIZE => {
921                let mem_idx = wasm.read_u8().unwrap_validated() as usize;
922                let mem_addr = *store
923                    .modules
924                    .get(current_module)
925                    .mem_addrs
926                    .get(mem_idx)
927                    .unwrap_validated();
928                let mem = store.memories.get(mem_addr);
929                let size = mem.size() as u32;
930                stack.push_value::<T>(Value::I32(size))?;
931                trace!("Instruction: memory.size [] -> [{}]", size);
932            }
933            MEMORY_GROW => {
934                let mem_idx = wasm.read_u8().unwrap_validated() as usize;
935                let mem_addr = *store
936                    .modules
937                    .get(current_module)
938                    .mem_addrs
939                    .get(mem_idx)
940                    .unwrap_validated();
941                let mem = store.memories.get_mut(mem_addr);
942                let sz: u32 = mem.size() as u32;
943
944                let n: u32 = stack.pop_value().try_into().unwrap_validated();
945
946                // TODO this instruction is non-deterministic w.r.t. spec, and can fail if the embedder wills it.
947                // for now we execute it always according to the following match expr.
948                // if the grow operation fails, err := Value::I32(2^32-1) is pushed to the stack per spec
949                let pushed_value = match mem.grow(n) {
950                    Ok(_) => sz,
951                    Err(_) => u32::MAX,
952                };
953                stack.push_value::<T>(Value::I32(pushed_value))?;
954                trace!("Instruction: memory.grow [{}] -> [{}]", n, pushed_value);
955            }
956            I32_CONST => {
957                let constant = wasm.read_var_i32().unwrap_validated();
958                trace!("Instruction: i32.const [] -> [{constant}]");
959                stack.push_value::<T>(constant.into())?;
960            }
961            F32_CONST => {
962                let constant = F32::from_bits(wasm.read_f32().unwrap_validated());
963                trace!("Instruction: f32.const [] -> [{constant:.7}]");
964                stack.push_value::<T>(constant.into())?;
965            }
966            I32_EQZ => {
967                let v1: i32 = stack.pop_value().try_into().unwrap_validated();
968
969                let res = if v1 == 0 { 1 } else { 0 };
970
971                trace!("Instruction: i32.eqz [{v1}] -> [{res}]");
972                stack.push_value::<T>(res.into())?;
973            }
974            I32_EQ => {
975                let v2: i32 = stack.pop_value().try_into().unwrap_validated();
976                let v1: i32 = stack.pop_value().try_into().unwrap_validated();
977
978                let res = if v1 == v2 { 1 } else { 0 };
979
980                trace!("Instruction: i32.eq [{v1} {v2}] -> [{res}]");
981                stack.push_value::<T>(res.into())?;
982            }
983            I32_NE => {
984                let v2: i32 = stack.pop_value().try_into().unwrap_validated();
985                let v1: i32 = stack.pop_value().try_into().unwrap_validated();
986
987                let res = if v1 != v2 { 1 } else { 0 };
988
989                trace!("Instruction: i32.ne [{v1} {v2}] -> [{res}]");
990                stack.push_value::<T>(res.into())?;
991            }
992            I32_LT_S => {
993                let v2: i32 = stack.pop_value().try_into().unwrap_validated();
994                let v1: i32 = stack.pop_value().try_into().unwrap_validated();
995
996                let res = if v1 < v2 { 1 } else { 0 };
997
998                trace!("Instruction: i32.lt_s [{v1} {v2}] -> [{res}]");
999                stack.push_value::<T>(res.into())?;
1000            }
1001
1002            I32_LT_U => {
1003                let v2: i32 = stack.pop_value().try_into().unwrap_validated();
1004                let v1: i32 = stack.pop_value().try_into().unwrap_validated();
1005
1006                let res = if (v1 as u32) < (v2 as u32) { 1 } else { 0 };
1007
1008                trace!("Instruction: i32.lt_u [{v1} {v2}] -> [{res}]");
1009                stack.push_value::<T>(res.into())?;
1010            }
1011            I32_GT_S => {
1012                let v2: i32 = stack.pop_value().try_into().unwrap_validated();
1013                let v1: i32 = stack.pop_value().try_into().unwrap_validated();
1014
1015                let res = if v1 > v2 { 1 } else { 0 };
1016
1017                trace!("Instruction: i32.gt_s [{v1} {v2}] -> [{res}]");
1018                stack.push_value::<T>(res.into())?;
1019            }
1020            I32_GT_U => {
1021                let v2: i32 = stack.pop_value().try_into().unwrap_validated();
1022                let v1: i32 = stack.pop_value().try_into().unwrap_validated();
1023
1024                let res = if (v1 as u32) > (v2 as u32) { 1 } else { 0 };
1025
1026                trace!("Instruction: i32.gt_u [{v1} {v2}] -> [{res}]");
1027                stack.push_value::<T>(res.into())?;
1028            }
1029            I32_LE_S => {
1030                let v2: i32 = stack.pop_value().try_into().unwrap_validated();
1031                let v1: i32 = stack.pop_value().try_into().unwrap_validated();
1032
1033                let res = if v1 <= v2 { 1 } else { 0 };
1034
1035                trace!("Instruction: i32.le_s [{v1} {v2}] -> [{res}]");
1036                stack.push_value::<T>(res.into())?;
1037            }
1038            I32_LE_U => {
1039                let v2: i32 = stack.pop_value().try_into().unwrap_validated();
1040                let v1: i32 = stack.pop_value().try_into().unwrap_validated();
1041
1042                let res = if (v1 as u32) <= (v2 as u32) { 1 } else { 0 };
1043
1044                trace!("Instruction: i32.le_u [{v1} {v2}] -> [{res}]");
1045                stack.push_value::<T>(res.into())?;
1046            }
1047            I32_GE_S => {
1048                let v2: i32 = stack.pop_value().try_into().unwrap_validated();
1049                let v1: i32 = stack.pop_value().try_into().unwrap_validated();
1050
1051                let res = if v1 >= v2 { 1 } else { 0 };
1052
1053                trace!("Instruction: i32.ge_s [{v1} {v2}] -> [{res}]");
1054                stack.push_value::<T>(res.into())?;
1055            }
1056            I32_GE_U => {
1057                let v2: i32 = stack.pop_value().try_into().unwrap_validated();
1058                let v1: i32 = stack.pop_value().try_into().unwrap_validated();
1059
1060                let res = if (v1 as u32) >= (v2 as u32) { 1 } else { 0 };
1061
1062                trace!("Instruction: i32.ge_u [{v1} {v2}] -> [{res}]");
1063                stack.push_value::<T>(res.into())?;
1064            }
1065            I64_EQZ => {
1066                let v1: i64 = stack.pop_value().try_into().unwrap_validated();
1067
1068                let res = if v1 == 0 { 1 } else { 0 };
1069
1070                trace!("Instruction: i64.eqz [{v1}] -> [{res}]");
1071                stack.push_value::<T>(res.into())?;
1072            }
1073            I64_EQ => {
1074                let v2: i64 = stack.pop_value().try_into().unwrap_validated();
1075                let v1: i64 = stack.pop_value().try_into().unwrap_validated();
1076
1077                let res = if v1 == v2 { 1 } else { 0 };
1078
1079                trace!("Instruction: i64.eq [{v1} {v2}] -> [{res}]");
1080                stack.push_value::<T>(res.into())?;
1081            }
1082            I64_NE => {
1083                let v2: i64 = stack.pop_value().try_into().unwrap_validated();
1084                let v1: i64 = stack.pop_value().try_into().unwrap_validated();
1085
1086                let res = if v1 != v2 { 1 } else { 0 };
1087
1088                trace!("Instruction: i64.ne [{v1} {v2}] -> [{res}]");
1089                stack.push_value::<T>(res.into())?;
1090            }
1091            I64_LT_S => {
1092                let v2: i64 = stack.pop_value().try_into().unwrap_validated();
1093                let v1: i64 = stack.pop_value().try_into().unwrap_validated();
1094
1095                let res = if v1 < v2 { 1 } else { 0 };
1096
1097                trace!("Instruction: i64.lt_s [{v1} {v2}] -> [{res}]");
1098                stack.push_value::<T>(res.into())?;
1099            }
1100
1101            I64_LT_U => {
1102                let v2: i64 = stack.pop_value().try_into().unwrap_validated();
1103                let v1: i64 = stack.pop_value().try_into().unwrap_validated();
1104
1105                let res = if (v1 as u64) < (v2 as u64) { 1 } else { 0 };
1106
1107                trace!("Instruction: i64.lt_u [{v1} {v2}] -> [{res}]");
1108                stack.push_value::<T>(res.into())?;
1109            }
1110            I64_GT_S => {
1111                let v2: i64 = stack.pop_value().try_into().unwrap_validated();
1112                let v1: i64 = stack.pop_value().try_into().unwrap_validated();
1113
1114                let res = if v1 > v2 { 1 } else { 0 };
1115
1116                trace!("Instruction: i64.gt_s [{v1} {v2}] -> [{res}]");
1117                stack.push_value::<T>(res.into())?;
1118            }
1119            I64_GT_U => {
1120                let v2: i64 = stack.pop_value().try_into().unwrap_validated();
1121                let v1: i64 = stack.pop_value().try_into().unwrap_validated();
1122
1123                let res = if (v1 as u64) > (v2 as u64) { 1 } else { 0 };
1124
1125                trace!("Instruction: i64.gt_u [{v1} {v2}] -> [{res}]");
1126                stack.push_value::<T>(res.into())?;
1127            }
1128            I64_LE_S => {
1129                let v2: i64 = stack.pop_value().try_into().unwrap_validated();
1130                let v1: i64 = stack.pop_value().try_into().unwrap_validated();
1131
1132                let res = if v1 <= v2 { 1 } else { 0 };
1133
1134                trace!("Instruction: i64.le_s [{v1} {v2}] -> [{res}]");
1135                stack.push_value::<T>(res.into())?;
1136            }
1137            I64_LE_U => {
1138                let v2: i64 = stack.pop_value().try_into().unwrap_validated();
1139                let v1: i64 = stack.pop_value().try_into().unwrap_validated();
1140
1141                let res = if (v1 as u64) <= (v2 as u64) { 1 } else { 0 };
1142
1143                trace!("Instruction: i64.le_u [{v1} {v2}] -> [{res}]");
1144                stack.push_value::<T>(res.into())?;
1145            }
1146            I64_GE_S => {
1147                let v2: i64 = stack.pop_value().try_into().unwrap_validated();
1148                let v1: i64 = stack.pop_value().try_into().unwrap_validated();
1149
1150                let res = if v1 >= v2 { 1 } else { 0 };
1151
1152                trace!("Instruction: i64.ge_s [{v1} {v2}] -> [{res}]");
1153                stack.push_value::<T>(res.into())?;
1154            }
1155            I64_GE_U => {
1156                let v2: i64 = stack.pop_value().try_into().unwrap_validated();
1157                let v1: i64 = stack.pop_value().try_into().unwrap_validated();
1158
1159                let res = if (v1 as u64) >= (v2 as u64) { 1 } else { 0 };
1160
1161                trace!("Instruction: i64.ge_u [{v1} {v2}] -> [{res}]");
1162                stack.push_value::<T>(res.into())?;
1163            }
1164            F32_EQ => {
1165                let v2: value::F32 = stack.pop_value().try_into().unwrap_validated();
1166                let v1: value::F32 = stack.pop_value().try_into().unwrap_validated();
1167
1168                let res = if v1 == v2 { 1 } else { 0 };
1169
1170                trace!("Instruction: f32.eq [{v1} {v2}] -> [{res}]");
1171                stack.push_value::<T>(res.into())?;
1172            }
1173            F32_NE => {
1174                let v2: value::F32 = stack.pop_value().try_into().unwrap_validated();
1175                let v1: value::F32 = stack.pop_value().try_into().unwrap_validated();
1176
1177                let res = if v1 != v2 { 1 } else { 0 };
1178
1179                trace!("Instruction: f32.ne [{v1} {v2}] -> [{res}]");
1180                stack.push_value::<T>(res.into())?;
1181            }
1182            F32_LT => {
1183                let v2: value::F32 = stack.pop_value().try_into().unwrap_validated();
1184                let v1: value::F32 = stack.pop_value().try_into().unwrap_validated();
1185
1186                let res = if v1 < v2 { 1 } else { 0 };
1187
1188                trace!("Instruction: f32.lt [{v1} {v2}] -> [{res}]");
1189                stack.push_value::<T>(res.into())?;
1190            }
1191            F32_GT => {
1192                let v2: value::F32 = stack.pop_value().try_into().unwrap_validated();
1193                let v1: value::F32 = stack.pop_value().try_into().unwrap_validated();
1194
1195                let res = if v1 > v2 { 1 } else { 0 };
1196
1197                trace!("Instruction: f32.gt [{v1} {v2}] -> [{res}]");
1198                stack.push_value::<T>(res.into())?;
1199            }
1200            F32_LE => {
1201                let v2: value::F32 = stack.pop_value().try_into().unwrap_validated();
1202                let v1: value::F32 = stack.pop_value().try_into().unwrap_validated();
1203
1204                let res = if v1 <= v2 { 1 } else { 0 };
1205
1206                trace!("Instruction: f32.le [{v1} {v2}] -> [{res}]");
1207                stack.push_value::<T>(res.into())?;
1208            }
1209            F32_GE => {
1210                let v2: value::F32 = stack.pop_value().try_into().unwrap_validated();
1211                let v1: value::F32 = stack.pop_value().try_into().unwrap_validated();
1212
1213                let res = if v1 >= v2 { 1 } else { 0 };
1214
1215                trace!("Instruction: f32.ge [{v1} {v2}] -> [{res}]");
1216                stack.push_value::<T>(res.into())?;
1217            }
1218
1219            F64_EQ => {
1220                let v2: value::F64 = stack.pop_value().try_into().unwrap_validated();
1221                let v1: value::F64 = stack.pop_value().try_into().unwrap_validated();
1222
1223                let res = if v1 == v2 { 1 } else { 0 };
1224
1225                trace!("Instruction: f64.eq [{v1} {v2}] -> [{res}]");
1226                stack.push_value::<T>(res.into())?;
1227            }
1228            F64_NE => {
1229                let v2: value::F64 = stack.pop_value().try_into().unwrap_validated();
1230                let v1: value::F64 = stack.pop_value().try_into().unwrap_validated();
1231
1232                let res = if v1 != v2 { 1 } else { 0 };
1233
1234                trace!("Instruction: f64.ne [{v1} {v2}] -> [{res}]");
1235                stack.push_value::<T>(res.into())?;
1236            }
1237            F64_LT => {
1238                let v2: value::F64 = stack.pop_value().try_into().unwrap_validated();
1239                let v1: value::F64 = stack.pop_value().try_into().unwrap_validated();
1240
1241                let res = if v1 < v2 { 1 } else { 0 };
1242
1243                trace!("Instruction: f64.lt [{v1} {v2}] -> [{res}]");
1244                stack.push_value::<T>(res.into())?;
1245            }
1246            F64_GT => {
1247                let v2: value::F64 = stack.pop_value().try_into().unwrap_validated();
1248                let v1: value::F64 = stack.pop_value().try_into().unwrap_validated();
1249
1250                let res = if v1 > v2 { 1 } else { 0 };
1251
1252                trace!("Instruction: f64.gt [{v1} {v2}] -> [{res}]");
1253                stack.push_value::<T>(res.into())?;
1254            }
1255            F64_LE => {
1256                let v2: value::F64 = stack.pop_value().try_into().unwrap_validated();
1257                let v1: value::F64 = stack.pop_value().try_into().unwrap_validated();
1258
1259                let res = if v1 <= v2 { 1 } else { 0 };
1260
1261                trace!("Instruction: f64.le [{v1} {v2}] -> [{res}]");
1262                stack.push_value::<T>(res.into())?;
1263            }
1264            F64_GE => {
1265                let v2: value::F64 = stack.pop_value().try_into().unwrap_validated();
1266                let v1: value::F64 = stack.pop_value().try_into().unwrap_validated();
1267
1268                let res = if v1 >= v2 { 1 } else { 0 };
1269
1270                trace!("Instruction: f64.ge [{v1} {v2}] -> [{res}]");
1271                stack.push_value::<T>(res.into())?;
1272            }
1273
1274            I32_CLZ => {
1275                let v1: i32 = stack.pop_value().try_into().unwrap_validated();
1276                let res = v1.leading_zeros() as i32;
1277
1278                trace!("Instruction: i32.clz [{v1}] -> [{res}]");
1279                stack.push_value::<T>(res.into())?;
1280            }
1281            I32_CTZ => {
1282                let v1: i32 = stack.pop_value().try_into().unwrap_validated();
1283                let res = v1.trailing_zeros() as i32;
1284
1285                trace!("Instruction: i32.ctz [{v1}] -> [{res}]");
1286                stack.push_value::<T>(res.into())?;
1287            }
1288            I32_POPCNT => {
1289                let v1: i32 = stack.pop_value().try_into().unwrap_validated();
1290                let res = v1.count_ones() as i32;
1291
1292                trace!("Instruction: i32.popcnt [{v1}] -> [{res}]");
1293                stack.push_value::<T>(res.into())?;
1294            }
1295            I64_CONST => {
1296                let constant = wasm.read_var_i64().unwrap_validated();
1297                trace!("Instruction: i64.const [] -> [{constant}]");
1298                stack.push_value::<T>(constant.into())?;
1299            }
1300            F64_CONST => {
1301                let constant = F64::from_bits(wasm.read_f64().unwrap_validated());
1302                trace!("Instruction: f64.const [] -> [{constant}]");
1303                stack.push_value::<T>(constant.into())?;
1304            }
1305            I32_ADD => {
1306                let v1: i32 = stack.pop_value().try_into().unwrap_validated();
1307                let v2: i32 = stack.pop_value().try_into().unwrap_validated();
1308                let res = v1.wrapping_add(v2);
1309
1310                trace!("Instruction: i32.add [{v1} {v2}] -> [{res}]");
1311                stack.push_value::<T>(res.into())?;
1312            }
1313            I32_SUB => {
1314                let v2: i32 = stack.pop_value().try_into().unwrap_validated();
1315                let v1: i32 = stack.pop_value().try_into().unwrap_validated();
1316                let res = v1.wrapping_sub(v2);
1317
1318                trace!("Instruction: i32.sub [{v1} {v2}] -> [{res}]");
1319                stack.push_value::<T>(res.into())?;
1320            }
1321            I32_MUL => {
1322                let v1: i32 = stack.pop_value().try_into().unwrap_validated();
1323                let v2: i32 = stack.pop_value().try_into().unwrap_validated();
1324                let res = v1.wrapping_mul(v2);
1325
1326                trace!("Instruction: i32.mul [{v1} {v2}] -> [{res}]");
1327                stack.push_value::<T>(res.into())?;
1328            }
1329            I32_DIV_S => {
1330                let dividend: i32 = stack.pop_value().try_into().unwrap_validated();
1331                let divisor: i32 = stack.pop_value().try_into().unwrap_validated();
1332
1333                if dividend == 0 {
1334                    return Err(TrapError::DivideBy0.into());
1335                }
1336                if divisor == i32::MIN && dividend == -1 {
1337                    return Err(TrapError::UnrepresentableResult.into());
1338                }
1339
1340                let res = divisor / dividend;
1341
1342                trace!("Instruction: i32.div_s [{divisor} {dividend}] -> [{res}]");
1343                stack.push_value::<T>(res.into())?;
1344            }
1345            I32_DIV_U => {
1346                let dividend: i32 = stack.pop_value().try_into().unwrap_validated();
1347                let divisor: i32 = stack.pop_value().try_into().unwrap_validated();
1348
1349                let dividend = dividend as u32;
1350                let divisor = divisor as u32;
1351
1352                if dividend == 0 {
1353                    return Err(TrapError::DivideBy0.into());
1354                }
1355
1356                let res = (divisor / dividend) as i32;
1357
1358                trace!("Instruction: i32.div_u [{divisor} {dividend}] -> [{res}]");
1359                stack.push_value::<T>(res.into())?;
1360            }
1361            I32_REM_S => {
1362                let dividend: i32 = stack.pop_value().try_into().unwrap_validated();
1363                let divisor: i32 = stack.pop_value().try_into().unwrap_validated();
1364
1365                if dividend == 0 {
1366                    return Err(TrapError::DivideBy0.into());
1367                }
1368
1369                let res = divisor.checked_rem(dividend);
1370                let res = res.unwrap_or_default();
1371
1372                trace!("Instruction: i32.rem_s [{divisor} {dividend}] -> [{res}]");
1373                stack.push_value::<T>(res.into())?;
1374            }
1375            I64_CLZ => {
1376                let v1: i64 = stack.pop_value().try_into().unwrap_validated();
1377                let res = v1.leading_zeros() as i64;
1378
1379                trace!("Instruction: i64.clz [{v1}] -> [{res}]");
1380                stack.push_value::<T>(res.into())?;
1381            }
1382            I64_CTZ => {
1383                let v1: i64 = stack.pop_value().try_into().unwrap_validated();
1384                let res = v1.trailing_zeros() as i64;
1385
1386                trace!("Instruction: i64.ctz [{v1}] -> [{res}]");
1387                stack.push_value::<T>(res.into())?;
1388            }
1389            I64_POPCNT => {
1390                let v1: i64 = stack.pop_value().try_into().unwrap_validated();
1391                let res = v1.count_ones() as i64;
1392
1393                trace!("Instruction: i64.popcnt [{v1}] -> [{res}]");
1394                stack.push_value::<T>(res.into())?;
1395            }
1396            I64_ADD => {
1397                let v1: i64 = stack.pop_value().try_into().unwrap_validated();
1398                let v2: i64 = stack.pop_value().try_into().unwrap_validated();
1399                let res = v1.wrapping_add(v2);
1400
1401                trace!("Instruction: i64.add [{v1} {v2}] -> [{res}]");
1402                stack.push_value::<T>(res.into())?;
1403            }
1404            I64_SUB => {
1405                let v2: i64 = stack.pop_value().try_into().unwrap_validated();
1406                let v1: i64 = stack.pop_value().try_into().unwrap_validated();
1407                let res = v1.wrapping_sub(v2);
1408
1409                trace!("Instruction: i64.sub [{v1} {v2}] -> [{res}]");
1410                stack.push_value::<T>(res.into())?;
1411            }
1412            I64_MUL => {
1413                let v1: i64 = stack.pop_value().try_into().unwrap_validated();
1414                let v2: i64 = stack.pop_value().try_into().unwrap_validated();
1415                let res = v1.wrapping_mul(v2);
1416
1417                trace!("Instruction: i64.mul [{v1} {v2}] -> [{res}]");
1418                stack.push_value::<T>(res.into())?;
1419            }
1420            I64_DIV_S => {
1421                let dividend: i64 = stack.pop_value().try_into().unwrap_validated();
1422                let divisor: i64 = stack.pop_value().try_into().unwrap_validated();
1423
1424                if dividend == 0 {
1425                    return Err(TrapError::DivideBy0.into());
1426                }
1427                if divisor == i64::MIN && dividend == -1 {
1428                    return Err(TrapError::UnrepresentableResult.into());
1429                }
1430
1431                let res = divisor / dividend;
1432
1433                trace!("Instruction: i64.div_s [{divisor} {dividend}] -> [{res}]");
1434                stack.push_value::<T>(res.into())?;
1435            }
1436            I64_DIV_U => {
1437                let dividend: i64 = stack.pop_value().try_into().unwrap_validated();
1438                let divisor: i64 = stack.pop_value().try_into().unwrap_validated();
1439
1440                let dividend = dividend as u64;
1441                let divisor = divisor as u64;
1442
1443                if dividend == 0 {
1444                    return Err(TrapError::DivideBy0.into());
1445                }
1446
1447                let res = (divisor / dividend) as i64;
1448
1449                trace!("Instruction: i64.div_u [{divisor} {dividend}] -> [{res}]");
1450                stack.push_value::<T>(res.into())?;
1451            }
1452            I64_REM_S => {
1453                let dividend: i64 = stack.pop_value().try_into().unwrap_validated();
1454                let divisor: i64 = stack.pop_value().try_into().unwrap_validated();
1455
1456                if dividend == 0 {
1457                    return Err(TrapError::DivideBy0.into());
1458                }
1459
1460                let res = divisor.checked_rem(dividend);
1461                let res = res.unwrap_or_default();
1462
1463                trace!("Instruction: i64.rem_s [{divisor} {dividend}] -> [{res}]");
1464                stack.push_value::<T>(res.into())?;
1465            }
1466            I64_REM_U => {
1467                let dividend: i64 = stack.pop_value().try_into().unwrap_validated();
1468                let divisor: i64 = stack.pop_value().try_into().unwrap_validated();
1469
1470                let dividend = dividend as u64;
1471                let divisor = divisor as u64;
1472
1473                if dividend == 0 {
1474                    return Err(TrapError::DivideBy0.into());
1475                }
1476
1477                let res = (divisor % dividend) as i64;
1478
1479                trace!("Instruction: i64.rem_u [{divisor} {dividend}] -> [{res}]");
1480                stack.push_value::<T>(res.into())?;
1481            }
1482            I64_AND => {
1483                let v2: i64 = stack.pop_value().try_into().unwrap_validated();
1484                let v1: i64 = stack.pop_value().try_into().unwrap_validated();
1485
1486                let res = v1 & v2;
1487
1488                trace!("Instruction: i64.and [{v1} {v2}] -> [{res}]");
1489                stack.push_value::<T>(res.into())?;
1490            }
1491            I64_OR => {
1492                let v2: i64 = stack.pop_value().try_into().unwrap_validated();
1493                let v1: i64 = stack.pop_value().try_into().unwrap_validated();
1494
1495                let res = v1 | v2;
1496
1497                trace!("Instruction: i64.or [{v1} {v2}] -> [{res}]");
1498                stack.push_value::<T>(res.into())?;
1499            }
1500            I64_XOR => {
1501                let v2: i64 = stack.pop_value().try_into().unwrap_validated();
1502                let v1: i64 = stack.pop_value().try_into().unwrap_validated();
1503
1504                let res = v1 ^ v2;
1505
1506                trace!("Instruction: i64.xor [{v1} {v2}] -> [{res}]");
1507                stack.push_value::<T>(res.into())?;
1508            }
1509            I64_SHL => {
1510                let v2: i64 = stack.pop_value().try_into().unwrap_validated();
1511                let v1: i64 = stack.pop_value().try_into().unwrap_validated();
1512
1513                let res = v1.wrapping_shl((v2 & 63) as u32);
1514
1515                trace!("Instruction: i64.shl [{v1} {v2}] -> [{res}]");
1516                stack.push_value::<T>(res.into())?;
1517            }
1518            I64_SHR_S => {
1519                let v2: i64 = stack.pop_value().try_into().unwrap_validated();
1520                let v1: i64 = stack.pop_value().try_into().unwrap_validated();
1521
1522                let res = v1.wrapping_shr((v2 & 63) as u32);
1523
1524                trace!("Instruction: i64.shr_s [{v1} {v2}] -> [{res}]");
1525                stack.push_value::<T>(res.into())?;
1526            }
1527            I64_SHR_U => {
1528                let v2: i64 = stack.pop_value().try_into().unwrap_validated();
1529                let v1: i64 = stack.pop_value().try_into().unwrap_validated();
1530
1531                let res = (v1 as u64).wrapping_shr((v2 & 63) as u32);
1532
1533                trace!("Instruction: i64.shr_u [{v1} {v2}] -> [{res}]");
1534                stack.push_value::<T>(res.into())?;
1535            }
1536            I64_ROTL => {
1537                let v2: i64 = stack.pop_value().try_into().unwrap_validated();
1538                let v1: i64 = stack.pop_value().try_into().unwrap_validated();
1539
1540                let res = v1.rotate_left((v2 & 63) as u32);
1541
1542                trace!("Instruction: i64.rotl [{v1} {v2}] -> [{res}]");
1543                stack.push_value::<T>(res.into())?;
1544            }
1545            I64_ROTR => {
1546                let v2: i64 = stack.pop_value().try_into().unwrap_validated();
1547                let v1: i64 = stack.pop_value().try_into().unwrap_validated();
1548
1549                let res = v1.rotate_right((v2 & 63) as u32);
1550
1551                trace!("Instruction: i64.rotr [{v1} {v2}] -> [{res}]");
1552                stack.push_value::<T>(res.into())?;
1553            }
1554            I32_REM_U => {
1555                let dividend: i32 = stack.pop_value().try_into().unwrap_validated();
1556                let divisor: i32 = stack.pop_value().try_into().unwrap_validated();
1557
1558                let dividend = dividend as u32;
1559                let divisor = divisor as u32;
1560
1561                if dividend == 0 {
1562                    return Err(TrapError::DivideBy0.into());
1563                }
1564
1565                let res = divisor.checked_rem(dividend);
1566                let res = res.unwrap_or_default() as i32;
1567
1568                trace!("Instruction: i32.rem_u [{divisor} {dividend}] -> [{res}]");
1569                stack.push_value::<T>(res.into())?;
1570            }
1571            I32_AND => {
1572                let v1: i32 = stack.pop_value().try_into().unwrap_validated();
1573                let v2: i32 = stack.pop_value().try_into().unwrap_validated();
1574                let res = v1 & v2;
1575
1576                trace!("Instruction: i32.and [{v1} {v2}] -> [{res}]");
1577                stack.push_value::<T>(res.into())?;
1578            }
1579            I32_OR => {
1580                let v1: i32 = stack.pop_value().try_into().unwrap_validated();
1581                let v2: i32 = stack.pop_value().try_into().unwrap_validated();
1582                let res = v1 | v2;
1583
1584                trace!("Instruction: i32.or [{v1} {v2}] -> [{res}]");
1585                stack.push_value::<T>(res.into())?;
1586            }
1587            I32_XOR => {
1588                let v1: i32 = stack.pop_value().try_into().unwrap_validated();
1589                let v2: i32 = stack.pop_value().try_into().unwrap_validated();
1590                let res = v1 ^ v2;
1591
1592                trace!("Instruction: i32.xor [{v1} {v2}] -> [{res}]");
1593                stack.push_value::<T>(res.into())?;
1594            }
1595            I32_SHL => {
1596                let v1: i32 = stack.pop_value().try_into().unwrap_validated();
1597                let v2: i32 = stack.pop_value().try_into().unwrap_validated();
1598                let res = v2.wrapping_shl(v1 as u32);
1599
1600                trace!("Instruction: i32.shl [{v2} {v1}] -> [{res}]");
1601                stack.push_value::<T>(res.into())?;
1602            }
1603            I32_SHR_S => {
1604                let v1: i32 = stack.pop_value().try_into().unwrap_validated();
1605                let v2: i32 = stack.pop_value().try_into().unwrap_validated();
1606
1607                let res = v2.wrapping_shr(v1 as u32);
1608
1609                trace!("Instruction: i32.shr_s [{v2} {v1}] -> [{res}]");
1610                stack.push_value::<T>(res.into())?;
1611            }
1612            I32_SHR_U => {
1613                let v1: i32 = stack.pop_value().try_into().unwrap_validated();
1614                let v2: i32 = stack.pop_value().try_into().unwrap_validated();
1615
1616                let res = (v2 as u32).wrapping_shr(v1 as u32) as i32;
1617
1618                trace!("Instruction: i32.shr_u [{v2} {v1}] -> [{res}]");
1619                stack.push_value::<T>(res.into())?;
1620            }
1621            I32_ROTL => {
1622                let v1: i32 = stack.pop_value().try_into().unwrap_validated();
1623                let v2: i32 = stack.pop_value().try_into().unwrap_validated();
1624
1625                let res = v2.rotate_left(v1 as u32);
1626
1627                trace!("Instruction: i32.rotl [{v2} {v1}] -> [{res}]");
1628                stack.push_value::<T>(res.into())?;
1629            }
1630            I32_ROTR => {
1631                let v1: i32 = stack.pop_value().try_into().unwrap_validated();
1632                let v2: i32 = stack.pop_value().try_into().unwrap_validated();
1633
1634                let res = v2.rotate_right(v1 as u32);
1635
1636                trace!("Instruction: i32.rotr [{v2} {v1}] -> [{res}]");
1637                stack.push_value::<T>(res.into())?;
1638            }
1639
1640            F32_ABS => {
1641                let v1: value::F32 = stack.pop_value().try_into().unwrap_validated();
1642                let res: value::F32 = v1.abs();
1643
1644                trace!("Instruction: f32.abs [{v1}] -> [{res}]");
1645                stack.push_value::<T>(res.into())?;
1646            }
1647            F32_NEG => {
1648                let v1: value::F32 = stack.pop_value().try_into().unwrap_validated();
1649                let res: value::F32 = v1.neg();
1650
1651                trace!("Instruction: f32.neg [{v1}] -> [{res}]");
1652                stack.push_value::<T>(res.into())?;
1653            }
1654            F32_CEIL => {
1655                let v1: value::F32 = stack.pop_value().try_into().unwrap_validated();
1656                let res: value::F32 = v1.ceil();
1657
1658                trace!("Instruction: f32.ceil [{v1}] -> [{res}]");
1659                stack.push_value::<T>(res.into())?;
1660            }
1661            F32_FLOOR => {
1662                let v1: value::F32 = stack.pop_value().try_into().unwrap_validated();
1663                let res: value::F32 = v1.floor();
1664
1665                trace!("Instruction: f32.floor [{v1}] -> [{res}]");
1666                stack.push_value::<T>(res.into())?;
1667            }
1668            F32_TRUNC => {
1669                let v1: value::F32 = stack.pop_value().try_into().unwrap_validated();
1670                let res: value::F32 = v1.trunc();
1671
1672                trace!("Instruction: f32.trunc [{v1}] -> [{res}]");
1673                stack.push_value::<T>(res.into())?;
1674            }
1675            F32_NEAREST => {
1676                let v1: value::F32 = stack.pop_value().try_into().unwrap_validated();
1677                let res: value::F32 = v1.nearest();
1678
1679                trace!("Instruction: f32.nearest [{v1}] -> [{res}]");
1680                stack.push_value::<T>(res.into())?;
1681            }
1682            F32_SQRT => {
1683                let v1: value::F32 = stack.pop_value().try_into().unwrap_validated();
1684                let res: value::F32 = v1.sqrt();
1685
1686                trace!("Instruction: f32.sqrt [{v1}] -> [{res}]");
1687                stack.push_value::<T>(res.into())?;
1688            }
1689            F32_ADD => {
1690                let v2: value::F32 = stack.pop_value().try_into().unwrap_validated();
1691                let v1: value::F32 = stack.pop_value().try_into().unwrap_validated();
1692                let res: value::F32 = v1 + v2;
1693
1694                trace!("Instruction: f32.add [{v1} {v2}] -> [{res}]");
1695                stack.push_value::<T>(res.into())?;
1696            }
1697            F32_SUB => {
1698                let v2: value::F32 = stack.pop_value().try_into().unwrap_validated();
1699                let v1: value::F32 = stack.pop_value().try_into().unwrap_validated();
1700                let res: value::F32 = v1 - v2;
1701
1702                trace!("Instruction: f32.sub [{v1} {v2}] -> [{res}]");
1703                stack.push_value::<T>(res.into())?;
1704            }
1705            F32_MUL => {
1706                let v2: value::F32 = stack.pop_value().try_into().unwrap_validated();
1707                let v1: value::F32 = stack.pop_value().try_into().unwrap_validated();
1708                let res: value::F32 = v1 * v2;
1709
1710                trace!("Instruction: f32.mul [{v1} {v2}] -> [{res}]");
1711                stack.push_value::<T>(res.into())?;
1712            }
1713            F32_DIV => {
1714                let v2: value::F32 = stack.pop_value().try_into().unwrap_validated();
1715                let v1: value::F32 = stack.pop_value().try_into().unwrap_validated();
1716                let res: value::F32 = v1 / v2;
1717
1718                trace!("Instruction: f32.div [{v1} {v2}] -> [{res}]");
1719                stack.push_value::<T>(res.into())?;
1720            }
1721            F32_MIN => {
1722                let v2: value::F32 = stack.pop_value().try_into().unwrap_validated();
1723                let v1: value::F32 = stack.pop_value().try_into().unwrap_validated();
1724                let res: value::F32 = v1.min(v2);
1725
1726                trace!("Instruction: f32.min [{v1} {v2}] -> [{res}]");
1727                stack.push_value::<T>(res.into())?;
1728            }
1729            F32_MAX => {
1730                let v2: value::F32 = stack.pop_value().try_into().unwrap_validated();
1731                let v1: value::F32 = stack.pop_value().try_into().unwrap_validated();
1732                let res: value::F32 = v1.max(v2);
1733
1734                trace!("Instruction: f32.max [{v1} {v2}] -> [{res}]");
1735                stack.push_value::<T>(res.into())?;
1736            }
1737            F32_COPYSIGN => {
1738                let v2: value::F32 = stack.pop_value().try_into().unwrap_validated();
1739                let v1: value::F32 = stack.pop_value().try_into().unwrap_validated();
1740                let res: value::F32 = v1.copysign(v2);
1741
1742                trace!("Instruction: f32.copysign [{v1} {v2}] -> [{res}]");
1743                stack.push_value::<T>(res.into())?;
1744            }
1745
1746            F64_ABS => {
1747                let v1: value::F64 = stack.pop_value().try_into().unwrap_validated();
1748                let res: value::F64 = v1.abs();
1749
1750                trace!("Instruction: f64.abs [{v1}] -> [{res}]");
1751                stack.push_value::<T>(res.into())?;
1752            }
1753            F64_NEG => {
1754                let v1: value::F64 = stack.pop_value().try_into().unwrap_validated();
1755                let res: value::F64 = v1.neg();
1756
1757                trace!("Instruction: f64.neg [{v1}] -> [{res}]");
1758                stack.push_value::<T>(res.into())?;
1759            }
1760            F64_CEIL => {
1761                let v1: value::F64 = stack.pop_value().try_into().unwrap_validated();
1762                let res: value::F64 = v1.ceil();
1763
1764                trace!("Instruction: f64.ceil [{v1}] -> [{res}]");
1765                stack.push_value::<T>(res.into())?;
1766            }
1767            F64_FLOOR => {
1768                let v1: value::F64 = stack.pop_value().try_into().unwrap_validated();
1769                let res: value::F64 = v1.floor();
1770
1771                trace!("Instruction: f64.floor [{v1}] -> [{res}]");
1772                stack.push_value::<T>(res.into())?;
1773            }
1774            F64_TRUNC => {
1775                let v1: value::F64 = stack.pop_value().try_into().unwrap_validated();
1776                let res: value::F64 = v1.trunc();
1777
1778                trace!("Instruction: f64.trunc [{v1}] -> [{res}]");
1779                stack.push_value::<T>(res.into())?;
1780            }
1781            F64_NEAREST => {
1782                let v1: value::F64 = stack.pop_value().try_into().unwrap_validated();
1783                let res: value::F64 = v1.nearest();
1784
1785                trace!("Instruction: f64.nearest [{v1}] -> [{res}]");
1786                stack.push_value::<T>(res.into())?;
1787            }
1788            F64_SQRT => {
1789                let v1: value::F64 = stack.pop_value().try_into().unwrap_validated();
1790                let res: value::F64 = v1.sqrt();
1791
1792                trace!("Instruction: f64.sqrt [{v1}] -> [{res}]");
1793                stack.push_value::<T>(res.into())?;
1794            }
1795            F64_ADD => {
1796                let v2: value::F64 = stack.pop_value().try_into().unwrap_validated();
1797                let v1: value::F64 = stack.pop_value().try_into().unwrap_validated();
1798                let res: value::F64 = v1 + v2;
1799
1800                trace!("Instruction: f64.add [{v1} {v2}] -> [{res}]");
1801                stack.push_value::<T>(res.into())?;
1802            }
1803            F64_SUB => {
1804                let v2: value::F64 = stack.pop_value().try_into().unwrap_validated();
1805                let v1: value::F64 = stack.pop_value().try_into().unwrap_validated();
1806                let res: value::F64 = v1 - v2;
1807
1808                trace!("Instruction: f64.sub [{v1} {v2}] -> [{res}]");
1809                stack.push_value::<T>(res.into())?;
1810            }
1811            F64_MUL => {
1812                let v2: value::F64 = stack.pop_value().try_into().unwrap_validated();
1813                let v1: value::F64 = stack.pop_value().try_into().unwrap_validated();
1814                let res: value::F64 = v1 * v2;
1815
1816                trace!("Instruction: f64.mul [{v1} {v2}] -> [{res}]");
1817                stack.push_value::<T>(res.into())?;
1818            }
1819            F64_DIV => {
1820                let v2: value::F64 = stack.pop_value().try_into().unwrap_validated();
1821                let v1: value::F64 = stack.pop_value().try_into().unwrap_validated();
1822                let res: value::F64 = v1 / v2;
1823
1824                trace!("Instruction: f64.div [{v1} {v2}] -> [{res}]");
1825                stack.push_value::<T>(res.into())?;
1826            }
1827            F64_MIN => {
1828                let v2: value::F64 = stack.pop_value().try_into().unwrap_validated();
1829                let v1: value::F64 = stack.pop_value().try_into().unwrap_validated();
1830                let res: value::F64 = v1.min(v2);
1831
1832                trace!("Instruction: f64.min [{v1} {v2}] -> [{res}]");
1833                stack.push_value::<T>(res.into())?;
1834            }
1835            F64_MAX => {
1836                let v2: value::F64 = stack.pop_value().try_into().unwrap_validated();
1837                let v1: value::F64 = stack.pop_value().try_into().unwrap_validated();
1838                let res: value::F64 = v1.max(v2);
1839
1840                trace!("Instruction: f64.max [{v1} {v2}] -> [{res}]");
1841                stack.push_value::<T>(res.into())?;
1842            }
1843            F64_COPYSIGN => {
1844                let v2: value::F64 = stack.pop_value().try_into().unwrap_validated();
1845                let v1: value::F64 = stack.pop_value().try_into().unwrap_validated();
1846                let res: value::F64 = v1.copysign(v2);
1847
1848                trace!("Instruction: f64.copysign [{v1} {v2}] -> [{res}]");
1849                stack.push_value::<T>(res.into())?;
1850            }
1851            I32_WRAP_I64 => {
1852                let v: i64 = stack.pop_value().try_into().unwrap_validated();
1853                let res: i32 = v as i32;
1854
1855                trace!("Instruction: i32.wrap_i64 [{v}] -> [{res}]");
1856                stack.push_value::<T>(res.into())?;
1857            }
1858            I32_TRUNC_F32_S => {
1859                let v: value::F32 = stack.pop_value().try_into().unwrap_validated();
1860                if v.is_infinity() {
1861                    return Err(TrapError::UnrepresentableResult.into());
1862                }
1863                if v.is_nan() {
1864                    return Err(TrapError::BadConversionToInteger.into());
1865                }
1866                if v >= value::F32(2147483648.0) || v <= value::F32(-2147483904.0) {
1867                    return Err(TrapError::UnrepresentableResult.into());
1868                }
1869
1870                let res: i32 = v.as_i32();
1871
1872                trace!("Instruction: i32.trunc_f32_s [{v:.7}] -> [{res}]");
1873                stack.push_value::<T>(res.into())?;
1874            }
1875            I32_TRUNC_F32_U => {
1876                let v: value::F32 = stack.pop_value().try_into().unwrap_validated();
1877                if v.is_infinity() {
1878                    return Err(TrapError::UnrepresentableResult.into());
1879                }
1880                if v.is_nan() {
1881                    return Err(TrapError::BadConversionToInteger.into());
1882                }
1883                if v >= value::F32(4294967296.0) || v <= value::F32(-1.0) {
1884                    return Err(TrapError::UnrepresentableResult.into());
1885                }
1886
1887                let res: i32 = v.as_u32() as i32;
1888
1889                trace!("Instruction: i32.trunc_f32_u [{v:.7}] -> [{res}]");
1890                stack.push_value::<T>(res.into())?;
1891            }
1892
1893            I32_TRUNC_F64_S => {
1894                let v: value::F64 = stack.pop_value().try_into().unwrap_validated();
1895                if v.is_infinity() {
1896                    return Err(TrapError::UnrepresentableResult.into());
1897                }
1898                if v.is_nan() {
1899                    return Err(TrapError::BadConversionToInteger.into());
1900                }
1901                if v >= value::F64(2147483648.0) || v <= value::F64(-2147483649.0) {
1902                    return Err(TrapError::UnrepresentableResult.into());
1903                }
1904
1905                let res: i32 = v.as_i32();
1906
1907                trace!("Instruction: i32.trunc_f64_s [{v:.7}] -> [{res}]");
1908                stack.push_value::<T>(res.into())?;
1909            }
1910            I32_TRUNC_F64_U => {
1911                let v: value::F64 = stack.pop_value().try_into().unwrap_validated();
1912                if v.is_infinity() {
1913                    return Err(TrapError::UnrepresentableResult.into());
1914                }
1915                if v.is_nan() {
1916                    return Err(TrapError::BadConversionToInteger.into());
1917                }
1918                if v >= value::F64(4294967296.0) || v <= value::F64(-1.0) {
1919                    return Err(TrapError::UnrepresentableResult.into());
1920                }
1921
1922                let res: i32 = v.as_u32() as i32;
1923
1924                trace!("Instruction: i32.trunc_f32_u [{v:.7}] -> [{res}]");
1925                stack.push_value::<T>(res.into())?;
1926            }
1927
1928            I64_EXTEND_I32_S => {
1929                let v: i32 = stack.pop_value().try_into().unwrap_validated();
1930
1931                let res: i64 = v as i64;
1932
1933                trace!("Instruction: i64.extend_i32_s [{v}] -> [{res}]");
1934                stack.push_value::<T>(res.into())?;
1935            }
1936
1937            I64_EXTEND_I32_U => {
1938                let v: i32 = stack.pop_value().try_into().unwrap_validated();
1939
1940                let res: i64 = v as u32 as i64;
1941
1942                trace!("Instruction: i64.extend_i32_u [{v}] -> [{res}]");
1943                stack.push_value::<T>(res.into())?;
1944            }
1945
1946            I64_TRUNC_F32_S => {
1947                let v: value::F32 = stack.pop_value().try_into().unwrap_validated();
1948                if v.is_infinity() {
1949                    return Err(TrapError::UnrepresentableResult.into());
1950                }
1951                if v.is_nan() {
1952                    return Err(TrapError::BadConversionToInteger.into());
1953                }
1954                if v >= value::F32(9223372036854775808.0) || v <= value::F32(-9223373136366403584.0)
1955                {
1956                    return Err(TrapError::UnrepresentableResult.into());
1957                }
1958
1959                let res: i64 = v.as_i64();
1960
1961                trace!("Instruction: i64.trunc_f32_s [{v:.7}] -> [{res}]");
1962                stack.push_value::<T>(res.into())?;
1963            }
1964            I64_TRUNC_F32_U => {
1965                let v: value::F32 = stack.pop_value().try_into().unwrap_validated();
1966                if v.is_infinity() {
1967                    return Err(TrapError::UnrepresentableResult.into());
1968                }
1969                if v.is_nan() {
1970                    return Err(TrapError::BadConversionToInteger.into());
1971                }
1972                if v >= value::F32(18446744073709551616.0) || v <= value::F32(-1.0) {
1973                    return Err(TrapError::UnrepresentableResult.into());
1974                }
1975
1976                let res: i64 = v.as_u64() as i64;
1977
1978                trace!("Instruction: i64.trunc_f32_u [{v:.7}] -> [{res}]");
1979                stack.push_value::<T>(res.into())?;
1980            }
1981
1982            I64_TRUNC_F64_S => {
1983                let v: value::F64 = stack.pop_value().try_into().unwrap_validated();
1984                if v.is_infinity() {
1985                    return Err(TrapError::UnrepresentableResult.into());
1986                }
1987                if v.is_nan() {
1988                    return Err(TrapError::BadConversionToInteger.into());
1989                }
1990                if v >= value::F64(9223372036854775808.0) || v <= value::F64(-9223372036854777856.0)
1991                {
1992                    return Err(TrapError::UnrepresentableResult.into());
1993                }
1994
1995                let res: i64 = v.as_i64();
1996
1997                trace!("Instruction: i64.trunc_f64_s [{v:.17}] -> [{res}]");
1998                stack.push_value::<T>(res.into())?;
1999            }
2000            I64_TRUNC_F64_U => {
2001                let v: value::F64 = stack.pop_value().try_into().unwrap_validated();
2002                if v.is_infinity() {
2003                    return Err(TrapError::UnrepresentableResult.into());
2004                }
2005                if v.is_nan() {
2006                    return Err(TrapError::BadConversionToInteger.into());
2007                }
2008                if v >= value::F64(18446744073709551616.0) || v <= value::F64(-1.0) {
2009                    return Err(TrapError::UnrepresentableResult.into());
2010                }
2011
2012                let res: i64 = v.as_u64() as i64;
2013
2014                trace!("Instruction: i64.trunc_f64_u [{v:.17}] -> [{res}]");
2015                stack.push_value::<T>(res.into())?;
2016            }
2017            F32_CONVERT_I32_S => {
2018                let v: i32 = stack.pop_value().try_into().unwrap_validated();
2019                let res: value::F32 = value::F32(v as f32);
2020
2021                trace!("Instruction: f32.convert_i32_s [{v}] -> [{res}]");
2022                stack.push_value::<T>(res.into())?;
2023            }
2024            F32_CONVERT_I32_U => {
2025                let v: i32 = stack.pop_value().try_into().unwrap_validated();
2026                let res: value::F32 = value::F32(v as u32 as f32);
2027
2028                trace!("Instruction: f32.convert_i32_u [{v}] -> [{res}]");
2029                stack.push_value::<T>(res.into())?;
2030            }
2031            F32_CONVERT_I64_S => {
2032                let v: i64 = stack.pop_value().try_into().unwrap_validated();
2033                let res: value::F32 = value::F32(v as f32);
2034
2035                trace!("Instruction: f32.convert_i64_s [{v}] -> [{res}]");
2036                stack.push_value::<T>(res.into())?;
2037            }
2038            F32_CONVERT_I64_U => {
2039                let v: i64 = stack.pop_value().try_into().unwrap_validated();
2040                let res: value::F32 = value::F32(v as u64 as f32);
2041
2042                trace!("Instruction: f32.convert_i64_u [{v}] -> [{res}]");
2043                stack.push_value::<T>(res.into())?;
2044            }
2045            F32_DEMOTE_F64 => {
2046                let v: value::F64 = stack.pop_value().try_into().unwrap_validated();
2047                let res: value::F32 = v.as_f32();
2048
2049                trace!("Instruction: f32.demote_f64 [{v:.17}] -> [{res:.7}]");
2050                stack.push_value::<T>(res.into())?;
2051            }
2052            F64_CONVERT_I32_S => {
2053                let v: i32 = stack.pop_value().try_into().unwrap_validated();
2054                let res: value::F64 = value::F64(v as f64);
2055
2056                trace!("Instruction: f64.convert_i32_s [{v}] -> [{res:.17}]");
2057                stack.push_value::<T>(res.into())?;
2058            }
2059            F64_CONVERT_I32_U => {
2060                let v: i32 = stack.pop_value().try_into().unwrap_validated();
2061                let res: value::F64 = value::F64(v as u32 as f64);
2062
2063                trace!("Instruction: f64.convert_i32_u [{v}] -> [{res:.17}]");
2064                stack.push_value::<T>(res.into())?;
2065            }
2066            F64_CONVERT_I64_S => {
2067                let v: i64 = stack.pop_value().try_into().unwrap_validated();
2068                let res: value::F64 = value::F64(v as f64);
2069
2070                trace!("Instruction: f64.convert_i64_s [{v}] -> [{res:.17}]");
2071                stack.push_value::<T>(res.into())?;
2072            }
2073            F64_CONVERT_I64_U => {
2074                let v: i64 = stack.pop_value().try_into().unwrap_validated();
2075                let res: value::F64 = value::F64(v as u64 as f64);
2076
2077                trace!("Instruction: f64.convert_i64_u [{v}] -> [{res:.17}]");
2078                stack.push_value::<T>(res.into())?;
2079            }
2080            F64_PROMOTE_F32 => {
2081                let v: value::F32 = stack.pop_value().try_into().unwrap_validated();
2082                let res: value::F64 = v.as_f64();
2083
2084                trace!("Instruction: f64.promote_f32 [{v:.7}] -> [{res:.17}]");
2085                stack.push_value::<T>(res.into())?;
2086            }
2087            I32_REINTERPRET_F32 => {
2088                let v: value::F32 = stack.pop_value().try_into().unwrap_validated();
2089                let res: i32 = v.reinterpret_as_i32();
2090
2091                trace!("Instruction: i32.reinterpret_f32 [{v:.7}] -> [{res}]");
2092                stack.push_value::<T>(res.into())?;
2093            }
2094            I64_REINTERPRET_F64 => {
2095                let v: value::F64 = stack.pop_value().try_into().unwrap_validated();
2096                let res: i64 = v.reinterpret_as_i64();
2097
2098                trace!("Instruction: i64.reinterpret_f64 [{v:.17}] -> [{res}]");
2099                stack.push_value::<T>(res.into())?;
2100            }
2101            F32_REINTERPRET_I32 => {
2102                let v1: i32 = stack.pop_value().try_into().unwrap_validated();
2103                let res: value::F32 = value::F32::from_bits(v1 as u32);
2104
2105                trace!("Instruction: f32.reinterpret_i32 [{v1}] -> [{res:.7}]");
2106                stack.push_value::<T>(res.into())?;
2107            }
2108            F64_REINTERPRET_I64 => {
2109                let v1: i64 = stack.pop_value().try_into().unwrap_validated();
2110                let res: value::F64 = value::F64::from_bits(v1 as u64);
2111
2112                trace!("Instruction: f64.reinterpret_i64 [{v1}] -> [{res:.17}]");
2113                stack.push_value::<T>(res.into())?;
2114            }
2115            REF_NULL => {
2116                let reftype = RefType::read(wasm).unwrap_validated();
2117
2118                stack.push_value::<T>(Value::Ref(Ref::Null(reftype)))?;
2119                trace!("Instruction: ref.null '{:?}' -> [{:?}]", reftype, reftype);
2120            }
2121            REF_IS_NULL => {
2122                let rref: Ref = stack.pop_value().try_into().unwrap_validated();
2123                let is_null = matches!(rref, Ref::Null(_));
2124
2125                let res = if is_null { 1 } else { 0 };
2126                trace!("Instruction: ref.is_null [{}] -> [{}]", rref, res);
2127                stack.push_value::<T>(Value::I32(res))?;
2128            }
2129            // https://webassembly.github.io/spec/core/exec/instructions.html#xref-syntax-instructions-syntax-instr-ref-mathsf-ref-func-x
2130            REF_FUNC => {
2131                let func_idx = wasm.read_var_u32().unwrap_validated() as FuncIdx;
2132                let func_addr = *store
2133                    .modules
2134                    .get(current_module)
2135                    .func_addrs
2136                    .get(func_idx)
2137                    .unwrap_validated();
2138                stack.push_value::<T>(Value::Ref(Ref::Func(func_addr)))?;
2139            }
2140            FC_EXTENSIONS => {
2141                // Should we call instruction hook here as well? Multibyte instruction
2142                let second_instr = wasm.read_var_u32().unwrap_validated();
2143
2144                use crate::core::reader::types::opcode::fc_extensions::*;
2145                match second_instr {
2146                    I32_TRUNC_SAT_F32_S => {
2147                        let v1: value::F32 = stack.pop_value().try_into().unwrap_validated();
2148                        let res = {
2149                            if v1.is_nan() {
2150                                0
2151                            } else if v1.is_negative_infinity() {
2152                                i32::MIN
2153                            } else if v1.is_infinity() {
2154                                i32::MAX
2155                            } else {
2156                                v1.as_i32()
2157                            }
2158                        };
2159
2160                        trace!("Instruction: i32.trunc_sat_f32_s [{v1}] -> [{res}]");
2161                        stack.push_value::<T>(res.into())?;
2162                    }
2163                    I32_TRUNC_SAT_F32_U => {
2164                        let v1: value::F32 = stack.pop_value().try_into().unwrap_validated();
2165                        let res = {
2166                            if v1.is_nan() || v1.is_negative_infinity() {
2167                                0
2168                            } else if v1.is_infinity() {
2169                                u32::MAX as i32
2170                            } else {
2171                                v1.as_u32() as i32
2172                            }
2173                        };
2174
2175                        trace!("Instruction: i32.trunc_sat_f32_u [{v1}] -> [{res}]");
2176                        stack.push_value::<T>(res.into())?;
2177                    }
2178                    I32_TRUNC_SAT_F64_S => {
2179                        let v1: value::F64 = stack.pop_value().try_into().unwrap_validated();
2180                        let res = {
2181                            if v1.is_nan() {
2182                                0
2183                            } else if v1.is_negative_infinity() {
2184                                i32::MIN
2185                            } else if v1.is_infinity() {
2186                                i32::MAX
2187                            } else {
2188                                v1.as_i32()
2189                            }
2190                        };
2191
2192                        trace!("Instruction: i32.trunc_sat_f64_s [{v1}] -> [{res}]");
2193                        stack.push_value::<T>(res.into())?;
2194                    }
2195                    I32_TRUNC_SAT_F64_U => {
2196                        let v1: value::F64 = stack.pop_value().try_into().unwrap_validated();
2197                        let res = {
2198                            if v1.is_nan() || v1.is_negative_infinity() {
2199                                0
2200                            } else if v1.is_infinity() {
2201                                u32::MAX as i32
2202                            } else {
2203                                v1.as_u32() as i32
2204                            }
2205                        };
2206
2207                        trace!("Instruction: i32.trunc_sat_f64_u [{v1}] -> [{res}]");
2208                        stack.push_value::<T>(res.into())?;
2209                    }
2210                    I64_TRUNC_SAT_F32_S => {
2211                        let v1: value::F32 = stack.pop_value().try_into().unwrap_validated();
2212                        let res = {
2213                            if v1.is_nan() {
2214                                0
2215                            } else if v1.is_negative_infinity() {
2216                                i64::MIN
2217                            } else if v1.is_infinity() {
2218                                i64::MAX
2219                            } else {
2220                                v1.as_i64()
2221                            }
2222                        };
2223
2224                        trace!("Instruction: i64.trunc_sat_f32_s [{v1}] -> [{res}]");
2225                        stack.push_value::<T>(res.into())?;
2226                    }
2227                    I64_TRUNC_SAT_F32_U => {
2228                        let v1: value::F32 = stack.pop_value().try_into().unwrap_validated();
2229                        let res = {
2230                            if v1.is_nan() || v1.is_negative_infinity() {
2231                                0
2232                            } else if v1.is_infinity() {
2233                                u64::MAX as i64
2234                            } else {
2235                                v1.as_u64() as i64
2236                            }
2237                        };
2238
2239                        trace!("Instruction: i64.trunc_sat_f32_u [{v1}] -> [{res}]");
2240                        stack.push_value::<T>(res.into())?;
2241                    }
2242                    I64_TRUNC_SAT_F64_S => {
2243                        let v1: value::F64 = stack.pop_value().try_into().unwrap_validated();
2244                        let res = {
2245                            if v1.is_nan() {
2246                                0
2247                            } else if v1.is_negative_infinity() {
2248                                i64::MIN
2249                            } else if v1.is_infinity() {
2250                                i64::MAX
2251                            } else {
2252                                v1.as_i64()
2253                            }
2254                        };
2255
2256                        trace!("Instruction: i64.trunc_sat_f64_s [{v1}] -> [{res}]");
2257                        stack.push_value::<T>(res.into())?;
2258                    }
2259                    I64_TRUNC_SAT_F64_U => {
2260                        let v1: value::F64 = stack.pop_value().try_into().unwrap_validated();
2261                        let res = {
2262                            if v1.is_nan() || v1.is_negative_infinity() {
2263                                0
2264                            } else if v1.is_infinity() {
2265                                u64::MAX as i64
2266                            } else {
2267                                v1.as_u64() as i64
2268                            }
2269                        };
2270
2271                        trace!("Instruction: i64.trunc_sat_f64_u [{v1}] -> [{res}]");
2272                        stack.push_value::<T>(res.into())?;
2273                    }
2274                    // See https://webassembly.github.io/bulk-memory-operations/core/exec/instructions.html#xref-syntax-instructions-syntax-instr-memory-mathsf-memory-init-x
2275                    // Copy a region from a data segment into memory
2276                    MEMORY_INIT => {
2277                        //  mappings:
2278                        //      n => number of bytes to copy
2279                        //      s => starting pointer in the data segment
2280                        //      d => destination address to copy to
2281                        let data_idx = wasm.read_var_u32().unwrap_validated() as DataIdx;
2282                        let mem_idx = wasm.read_u8().unwrap_validated() as usize;
2283
2284                        let n: i32 = stack.pop_value().try_into().unwrap_validated();
2285                        let s: i32 = stack.pop_value().try_into().unwrap_validated();
2286                        let d: i32 = stack.pop_value().try_into().unwrap_validated();
2287
2288                        memory_init(
2289                            &store.modules,
2290                            &mut store.memories,
2291                            &store.data,
2292                            current_module,
2293                            data_idx,
2294                            mem_idx,
2295                            n,
2296                            s,
2297                            d,
2298                        )?;
2299                    }
2300                    DATA_DROP => {
2301                        let data_idx = wasm.read_var_u32().unwrap_validated() as DataIdx;
2302                        data_drop(&store.modules, &mut store.data, current_module, data_idx)?;
2303                    }
2304                    // See https://webassembly.github.io/bulk-memory-operations/core/exec/instructions.html#xref-syntax-instructions-syntax-instr-memory-mathsf-memory-copy
2305                    MEMORY_COPY => {
2306                        //  mappings:
2307                        //      n => number of bytes to copy
2308                        //      s => source address to copy from
2309                        //      d => destination address to copy to
2310                        let (dst_idx, src_idx) = (
2311                            wasm.read_u8().unwrap_validated() as usize,
2312                            wasm.read_u8().unwrap_validated() as usize,
2313                        );
2314                        let n: i32 = stack.pop_value().try_into().unwrap_validated();
2315                        let s: i32 = stack.pop_value().try_into().unwrap_validated();
2316                        let d: i32 = stack.pop_value().try_into().unwrap_validated();
2317
2318                        let src_addr = *store
2319                            .modules
2320                            .get(current_module)
2321                            .mem_addrs
2322                            .get(src_idx)
2323                            .unwrap_validated();
2324                        let dst_addr = *store
2325                            .modules
2326                            .get(current_module)
2327                            .mem_addrs
2328                            .get(dst_idx)
2329                            .unwrap_validated();
2330
2331                        let src_mem = store.memories.get(src_addr);
2332                        let dest_mem = store.memories.get(dst_addr);
2333
2334                        dest_mem
2335                            .mem
2336                            .copy(d as MemIdx, &src_mem.mem, s as MemIdx, n as MemIdx)?;
2337                        trace!("Instruction: memory.copy");
2338                    }
2339                    // See https://webassembly.github.io/bulk-memory-operations/core/exec/instructions.html#xref-syntax-instructions-syntax-instr-memory-mathsf-memory-fill
2340                    MEMORY_FILL => {
2341                        //  mappings:
2342                        //      n => number of bytes to update
2343                        //      val => the value to set each byte to (must be < 256)
2344                        //      d => the pointer to the region to update
2345                        let mem_idx = wasm.read_u8().unwrap_validated() as usize;
2346                        let mem_addr = *store
2347                            .modules
2348                            .get(current_module)
2349                            .mem_addrs
2350                            .get(mem_idx)
2351                            .unwrap_validated();
2352                        let mem = store.memories.get(mem_addr);
2353                        let n: i32 = stack.pop_value().try_into().unwrap_validated();
2354                        let val: i32 = stack.pop_value().try_into().unwrap_validated();
2355
2356                        if !(0..=255).contains(&val) {
2357                            warn!("Value for memory.fill does not fit in a byte ({val})");
2358                        }
2359
2360                        let d: i32 = stack.pop_value().try_into().unwrap_validated();
2361
2362                        mem.mem.fill(d as usize, val as u8, n as usize)?;
2363
2364                        trace!("Instruction: memory.fill");
2365                    }
2366                    // https://webassembly.github.io/spec/core/exec/instructions.html#xref-syntax-instructions-syntax-instr-table-mathsf-table-init-x-y
2367                    // https://webassembly.github.io/spec/core/binary/instructions.html#table-instructions
2368                    // in binary format it seems that elemidx is first ???????
2369                    // this is ONLY for passive elements
2370                    TABLE_INIT => {
2371                        let elem_idx = wasm.read_var_u32().unwrap_validated() as usize;
2372                        let table_idx = wasm.read_var_u32().unwrap_validated() as usize;
2373
2374                        let n: i32 = stack.pop_value().try_into().unwrap_validated(); // size
2375                        let s: i32 = stack.pop_value().try_into().unwrap_validated(); // offset
2376                        let d: i32 = stack.pop_value().try_into().unwrap_validated(); // dst
2377
2378                        table_init(
2379                            &store.modules,
2380                            &mut store.tables,
2381                            &store.elements,
2382                            current_module,
2383                            elem_idx,
2384                            table_idx,
2385                            n,
2386                            s,
2387                            d,
2388                        )?;
2389                    }
2390                    ELEM_DROP => {
2391                        let elem_idx = wasm.read_var_u32().unwrap_validated() as usize;
2392
2393                        elem_drop(
2394                            &store.modules,
2395                            &mut store.elements,
2396                            current_module,
2397                            elem_idx,
2398                        )?;
2399                    }
2400                    // https://webassembly.github.io/spec/core/exec/instructions.html#xref-syntax-instructions-syntax-instr-table-mathsf-table-copy-x-y
2401                    TABLE_COPY => {
2402                        let table_x_idx = wasm.read_var_u32().unwrap_validated() as usize;
2403                        let table_y_idx = wasm.read_var_u32().unwrap_validated() as usize;
2404
2405                        let tab_x_elem_len = store
2406                            .tables
2407                            .get(store.modules.get(current_module).table_addrs[table_x_idx])
2408                            .elem
2409                            .len();
2410                        let tab_y_elem_len = store
2411                            .tables
2412                            .get(store.modules.get(current_module).table_addrs[table_y_idx])
2413                            .elem
2414                            .len();
2415
2416                        let n: u32 = stack.pop_value().try_into().unwrap_validated(); // size
2417                        let s: u32 = stack.pop_value().try_into().unwrap_validated(); // source
2418                        let d: u32 = stack.pop_value().try_into().unwrap_validated(); // destination
2419
2420                        let src_res = match s.checked_add(n) {
2421                            Some(res) => {
2422                                if res > tab_y_elem_len as u32 {
2423                                    return Err(TrapError::TableOrElementAccessOutOfBounds.into());
2424                                } else {
2425                                    res as usize
2426                                }
2427                            }
2428                            _ => return Err(TrapError::TableOrElementAccessOutOfBounds.into()),
2429                        };
2430
2431                        let dst_res = match d.checked_add(n) {
2432                            Some(res) => {
2433                                if res > tab_x_elem_len as u32 {
2434                                    return Err(TrapError::TableOrElementAccessOutOfBounds.into());
2435                                } else {
2436                                    res as usize
2437                                }
2438                            }
2439                            _ => return Err(TrapError::TableOrElementAccessOutOfBounds.into()),
2440                        };
2441
2442                        let dst = table_x_idx;
2443                        let src = table_y_idx;
2444
2445                        if table_x_idx == table_y_idx {
2446                            let table_addr = *store
2447                                .modules
2448                                .get(current_module)
2449                                .table_addrs
2450                                .get(table_x_idx)
2451                                .unwrap_validated();
2452                            let table = store.tables.get_mut(table_addr);
2453                            table.elem.copy_within(s as usize..src_res, d as usize);
2454                        } else {
2455                            let src_addr = *store
2456                                .modules
2457                                .get(current_module)
2458                                .table_addrs
2459                                .get(src)
2460                                .unwrap_validated();
2461                            let dst_addr = *store
2462                                .modules
2463                                .get(current_module)
2464                                .table_addrs
2465                                .get(dst)
2466                                .unwrap_validated();
2467
2468                            let (src_table, dst_table) = store
2469                                .tables
2470                                .get_two_mut(src_addr, dst_addr)
2471                                .expect("both addrs to never be equal");
2472
2473                            dst_table.elem[d as usize..dst_res]
2474                                .copy_from_slice(&src_table.elem[s as usize..src_res]);
2475                        }
2476
2477                        trace!(
2478                            "Instruction: table.copy '{}' '{}' [{} {} {}] -> []",
2479                            table_x_idx,
2480                            table_y_idx,
2481                            d,
2482                            s,
2483                            n
2484                        );
2485                    }
2486                    TABLE_GROW => {
2487                        let table_idx = wasm.read_var_u32().unwrap_validated() as usize;
2488                        let table_addr = *store
2489                            .modules
2490                            .get(current_module)
2491                            .table_addrs
2492                            .get(table_idx)
2493                            .unwrap_validated();
2494                        let tab = &mut store.tables.get_mut(table_addr);
2495
2496                        let sz = tab.elem.len() as u32;
2497
2498                        let n: u32 = stack.pop_value().try_into().unwrap_validated();
2499                        let val: Ref = stack.pop_value().try_into().unwrap_validated();
2500
2501                        // TODO this instruction is non-deterministic w.r.t. spec, and can fail if the embedder wills it.
2502                        // for now we execute it always according to the following match expr.
2503                        // if the grow operation fails, err := Value::I32(2^32-1) is pushed to the stack per spec
2504                        match tab.grow(n, val) {
2505                            Ok(_) => {
2506                                stack.push_value::<T>(Value::I32(sz))?;
2507                            }
2508                            Err(_) => {
2509                                stack.push_value::<T>(Value::I32(u32::MAX))?;
2510                            }
2511                        }
2512                    }
2513                    TABLE_SIZE => {
2514                        let table_idx = wasm.read_var_u32().unwrap_validated() as usize;
2515                        let table_addr = *store
2516                            .modules
2517                            .get(current_module)
2518                            .table_addrs
2519                            .get(table_idx)
2520                            .unwrap_validated();
2521                        let tab = store.tables.get(table_addr);
2522
2523                        let sz = tab.elem.len() as u32;
2524
2525                        stack.push_value::<T>(Value::I32(sz))?;
2526
2527                        trace!("Instruction: table.size '{}' [] -> [{}]", table_idx, sz);
2528                    }
2529                    TABLE_FILL => {
2530                        let table_idx = wasm.read_var_u32().unwrap_validated() as usize;
2531                        let table_addr = *store
2532                            .modules
2533                            .get(current_module)
2534                            .table_addrs
2535                            .get(table_idx)
2536                            .unwrap_validated();
2537                        let tab = store.tables.get_mut(table_addr);
2538
2539                        let len: u32 = stack.pop_value().try_into().unwrap_validated();
2540                        let val: Ref = stack.pop_value().try_into().unwrap_validated();
2541                        let dst: u32 = stack.pop_value().try_into().unwrap_validated();
2542
2543                        let end = (dst as usize)
2544                            .checked_add(len as usize)
2545                            .ok_or(TrapError::TableOrElementAccessOutOfBounds)?;
2546
2547                        tab.elem
2548                            .get_mut(dst as usize..end)
2549                            .ok_or(TrapError::TableOrElementAccessOutOfBounds)?
2550                            .fill(val);
2551
2552                        trace!(
2553                            "Instruction table.fill '{}' [{} {} {}] -> []",
2554                            table_idx,
2555                            dst,
2556                            val,
2557                            len
2558                        )
2559                    }
2560                    _ => unreachable!(),
2561                }
2562            }
2563
2564            I32_EXTEND8_S => {
2565                let mut v: u32 = stack.pop_value().try_into().unwrap_validated();
2566
2567                if v | 0xFF != 0xFF {
2568                    trace!("Number v ({}) not contained in 8 bits, truncating", v);
2569                    v &= 0xFF;
2570                }
2571
2572                let res = if v | 0x7F != 0x7F { v | 0xFFFFFF00 } else { v };
2573
2574                stack.push_value::<T>(res.into())?;
2575
2576                trace!("Instruction i32.extend8_s [{}] -> [{}]", v, res);
2577            }
2578            I32_EXTEND16_S => {
2579                let mut v: u32 = stack.pop_value().try_into().unwrap_validated();
2580
2581                if v | 0xFFFF != 0xFFFF {
2582                    trace!("Number v ({}) not contained in 16 bits, truncating", v);
2583                    v &= 0xFFFF;
2584                }
2585
2586                let res = if v | 0x7FFF != 0x7FFF {
2587                    v | 0xFFFF0000
2588                } else {
2589                    v
2590                };
2591
2592                stack.push_value::<T>(res.into())?;
2593
2594                trace!("Instruction i32.extend16_s [{}] -> [{}]", v, res);
2595            }
2596            I64_EXTEND8_S => {
2597                let mut v: u64 = stack.pop_value().try_into().unwrap_validated();
2598
2599                if v | 0xFF != 0xFF {
2600                    trace!("Number v ({}) not contained in 8 bits, truncating", v);
2601                    v &= 0xFF;
2602                }
2603
2604                let res = if v | 0x7F != 0x7F {
2605                    v | 0xFFFFFFFF_FFFFFF00
2606                } else {
2607                    v
2608                };
2609
2610                stack.push_value::<T>(res.into())?;
2611
2612                trace!("Instruction i64.extend8_s [{}] -> [{}]", v, res);
2613            }
2614            I64_EXTEND16_S => {
2615                let mut v: u64 = stack.pop_value().try_into().unwrap_validated();
2616
2617                if v | 0xFFFF != 0xFFFF {
2618                    trace!("Number v ({}) not contained in 16 bits, truncating", v);
2619                    v &= 0xFFFF;
2620                }
2621
2622                let res = if v | 0x7FFF != 0x7FFF {
2623                    v | 0xFFFFFFFF_FFFF0000
2624                } else {
2625                    v
2626                };
2627
2628                stack.push_value::<T>(res.into())?;
2629
2630                trace!("Instruction i64.extend16_s [{}] -> [{}]", v, res);
2631            }
2632            I64_EXTEND32_S => {
2633                let mut v: u64 = stack.pop_value().try_into().unwrap_validated();
2634
2635                if v | 0xFFFF_FFFF != 0xFFFF_FFFF {
2636                    trace!("Number v ({}) not contained in 32 bits, truncating", v);
2637                    v &= 0xFFFF_FFFF;
2638                }
2639
2640                let res = if v | 0x7FFF_FFFF != 0x7FFF_FFFF {
2641                    v | 0xFFFFFFFF_00000000
2642                } else {
2643                    v
2644                };
2645
2646                stack.push_value::<T>(res.into())?;
2647
2648                trace!("Instruction i64.extend32_s [{}] -> [{}]", v, res);
2649            }
2650            FD_EXTENSIONS => {
2651                // Should we call instruction hook here as well? Multibyte instruction
2652                let second_instr = wasm.read_var_u32().unwrap_validated();
2653
2654                use crate::core::reader::types::opcode::fd_extensions::*;
2655                match second_instr {
2656                    V128_LOAD => {
2657                        let memarg = MemArg::read(wasm).unwrap_validated();
2658                        let mem_addr = *store
2659                            .modules
2660                            .get(current_module)
2661                            .mem_addrs
2662                            .first()
2663                            .unwrap_validated();
2664                        let memory = store.memories.get(mem_addr);
2665
2666                        let relative_address: u32 = stack.pop_value().try_into().unwrap_validated();
2667                        let idx = calculate_mem_address(&memarg, relative_address)?;
2668
2669                        let data: u128 = memory.mem.load(idx)?;
2670                        stack.push_value::<T>(data.to_le_bytes().into())?;
2671                    }
2672                    V128_STORE => {
2673                        let memarg = MemArg::read(wasm).unwrap_validated();
2674                        let mem_addr = *store
2675                            .modules
2676                            .get(current_module)
2677                            .mem_addrs
2678                            .first()
2679                            .unwrap_validated();
2680                        let memory = store.memories.get(mem_addr);
2681
2682                        let data: [u8; 16] = stack.pop_value().try_into().unwrap_validated();
2683                        let relative_address: u32 = stack.pop_value().try_into().unwrap_validated();
2684                        let idx = calculate_mem_address(&memarg, relative_address)?;
2685
2686                        memory.mem.store(idx, u128::from_le_bytes(data))?;
2687                    }
2688
2689                    // v128.loadNxM_sx
2690                    V128_LOAD8X8_S => {
2691                        let memarg = MemArg::read(wasm).unwrap_validated();
2692                        let mem_addr = *store
2693                            .modules
2694                            .get(current_module)
2695                            .mem_addrs
2696                            .first()
2697                            .unwrap_validated();
2698                        let memory = store.memories.get(mem_addr);
2699
2700                        let relative_address: u32 = stack.pop_value().try_into().unwrap_validated();
2701                        let idx = calculate_mem_address(&memarg, relative_address)?;
2702
2703                        let half_data: [u8; 8] = memory.mem.load_bytes::<8>(idx)?; // v128 load always loads half of a v128
2704
2705                        // Special case where we have only half of a v128. To convert it to lanes via `to_lanes`, pad the data with zeros
2706                        let data: [u8; 16] = array::from_fn(|i| *half_data.get(i).unwrap_or(&0));
2707                        let half_lanes: [i8; 8] =
2708                            to_lanes::<1, 16, i8>(data)[..8].try_into().unwrap();
2709
2710                        let extended_lanes = half_lanes.map(|lane| lane as i16);
2711
2712                        stack.push_value::<T>(Value::V128(from_lanes(extended_lanes)))?;
2713                    }
2714                    V128_LOAD8X8_U => {
2715                        let memarg = MemArg::read(wasm).unwrap_validated();
2716                        let mem_addr = *store
2717                            .modules
2718                            .get(current_module)
2719                            .mem_addrs
2720                            .first()
2721                            .unwrap_validated();
2722                        let memory = store.memories.get(mem_addr);
2723
2724                        let relative_address: u32 = stack.pop_value().try_into().unwrap_validated();
2725                        let idx = calculate_mem_address(&memarg, relative_address)?;
2726
2727                        let half_data: [u8; 8] = memory.mem.load_bytes::<8>(idx)?; // v128 load always loads half of a v128
2728
2729                        // Special case where we have only half of a v128. To convert it to lanes via `to_lanes`, pad the data with zeros
2730                        let data: [u8; 16] = array::from_fn(|i| *half_data.get(i).unwrap_or(&0));
2731                        let half_lanes: [u8; 8] =
2732                            to_lanes::<1, 16, u8>(data)[..8].try_into().unwrap();
2733
2734                        let extended_lanes = half_lanes.map(|lane| lane as u16);
2735
2736                        stack.push_value::<T>(Value::V128(from_lanes(extended_lanes)))?;
2737                    }
2738                    V128_LOAD16X4_S => {
2739                        let memarg = MemArg::read(wasm).unwrap_validated();
2740                        let mem_addr = *store
2741                            .modules
2742                            .get(current_module)
2743                            .mem_addrs
2744                            .first()
2745                            .unwrap_validated();
2746                        let memory = store.memories.get(mem_addr);
2747
2748                        let relative_address: u32 = stack.pop_value().try_into().unwrap_validated();
2749                        let idx = calculate_mem_address(&memarg, relative_address)?;
2750
2751                        let half_data: [u8; 8] = memory.mem.load_bytes::<8>(idx)?; // v128 load always loads half of a v128
2752
2753                        // Special case where we have only half of a v128. To convert it to lanes via `to_lanes`, pad the data with zeros
2754                        let data: [u8; 16] = array::from_fn(|i| *half_data.get(i).unwrap_or(&0));
2755                        let half_lanes: [i16; 4] =
2756                            to_lanes::<2, 8, i16>(data)[..4].try_into().unwrap();
2757
2758                        let extended_lanes = half_lanes.map(|lane| lane as i32);
2759
2760                        stack.push_value::<T>(Value::V128(from_lanes(extended_lanes)))?;
2761                    }
2762                    V128_LOAD16X4_U => {
2763                        let memarg = MemArg::read(wasm).unwrap_validated();
2764                        let mem_addr = *store
2765                            .modules
2766                            .get(current_module)
2767                            .mem_addrs
2768                            .first()
2769                            .unwrap_validated();
2770                        let memory = store.memories.get(mem_addr);
2771
2772                        let relative_address: u32 = stack.pop_value().try_into().unwrap_validated();
2773                        let idx = calculate_mem_address(&memarg, relative_address)?;
2774
2775                        let half_data: [u8; 8] = memory.mem.load_bytes::<8>(idx)?; // v128 load always loads half of a v128
2776
2777                        // Special case where we have only half of a v128. To convert it to lanes via `to_lanes`, pad the data with zeros
2778                        let data: [u8; 16] = array::from_fn(|i| *half_data.get(i).unwrap_or(&0));
2779                        let half_lanes: [u16; 4] =
2780                            to_lanes::<2, 8, u16>(data)[..4].try_into().unwrap();
2781
2782                        let extended_lanes = half_lanes.map(|lane| lane as u32);
2783
2784                        stack.push_value::<T>(Value::V128(from_lanes(extended_lanes)))?;
2785                    }
2786                    V128_LOAD32X2_S => {
2787                        let memarg = MemArg::read(wasm).unwrap_validated();
2788                        let mem_addr = *store
2789                            .modules
2790                            .get(current_module)
2791                            .mem_addrs
2792                            .first()
2793                            .unwrap_validated();
2794                        let memory = store.memories.get(mem_addr);
2795
2796                        let relative_address: u32 = stack.pop_value().try_into().unwrap_validated();
2797                        let idx = calculate_mem_address(&memarg, relative_address)?;
2798
2799                        let half_data: [u8; 8] = memory.mem.load_bytes::<8>(idx)?; // v128 load always loads half of a v128
2800
2801                        // Special case where we have only half of a v128. To convert it to lanes via `to_lanes`, pad the data with zeros
2802                        let data: [u8; 16] = array::from_fn(|i| *half_data.get(i).unwrap_or(&0));
2803                        let half_lanes: [i32; 2] =
2804                            to_lanes::<4, 4, i32>(data)[..2].try_into().unwrap();
2805
2806                        let extended_lanes = half_lanes.map(|lane| lane as i64);
2807
2808                        stack.push_value::<T>(Value::V128(from_lanes(extended_lanes)))?;
2809                    }
2810                    V128_LOAD32X2_U => {
2811                        let memarg = MemArg::read(wasm).unwrap_validated();
2812                        let mem_addr = *store
2813                            .modules
2814                            .get(current_module)
2815                            .mem_addrs
2816                            .first()
2817                            .unwrap_validated();
2818                        let memory = store.memories.get(mem_addr);
2819
2820                        let relative_address: u32 = stack.pop_value().try_into().unwrap_validated();
2821                        let idx = calculate_mem_address(&memarg, relative_address)?;
2822
2823                        let half_data: [u8; 8] = memory.mem.load_bytes::<8>(idx)?; // v128 load always loads half of a v128
2824
2825                        // Special case where we have only half of a v128. To convert it to lanes via `to_lanes`, pad the data with zeros
2826                        let data: [u8; 16] = array::from_fn(|i| *half_data.get(i).unwrap_or(&0));
2827                        let half_lanes: [u32; 2] =
2828                            to_lanes::<4, 4, u32>(data)[..2].try_into().unwrap();
2829
2830                        let extended_lanes = half_lanes.map(|lane| lane as u64);
2831
2832                        stack.push_value::<T>(Value::V128(from_lanes(extended_lanes)))?;
2833                    }
2834
2835                    // v128.loadN_splat
2836                    V128_LOAD8_SPLAT => {
2837                        let memarg = MemArg::read(wasm).unwrap_validated();
2838                        let mem_addr = *store
2839                            .modules
2840                            .get(current_module)
2841                            .mem_addrs
2842                            .first()
2843                            .unwrap_validated();
2844                        let memory = store.memories.get(mem_addr);
2845                        let relative_address: u32 = stack.pop_value().try_into().unwrap_validated();
2846                        let idx = calculate_mem_address(&memarg, relative_address)?;
2847
2848                        let lane = memory.mem.load::<1, u8>(idx)?;
2849                        stack.push_value::<T>(Value::V128(from_lanes([lane; 16])))?;
2850                    }
2851                    V128_LOAD16_SPLAT => {
2852                        let memarg = MemArg::read(wasm).unwrap_validated();
2853                        let mem_addr = *store
2854                            .modules
2855                            .get(current_module)
2856                            .mem_addrs
2857                            .first()
2858                            .unwrap_validated();
2859                        let memory = store.memories.get(mem_addr);
2860                        let relative_address: u32 = stack.pop_value().try_into().unwrap_validated();
2861                        let idx = calculate_mem_address(&memarg, relative_address)?;
2862
2863                        let lane = memory.mem.load::<2, u16>(idx)?;
2864                        stack.push_value::<T>(Value::V128(from_lanes([lane; 8])))?;
2865                    }
2866                    V128_LOAD32_SPLAT => {
2867                        let memarg = MemArg::read(wasm).unwrap_validated();
2868                        let mem_addr = *store
2869                            .modules
2870                            .get(current_module)
2871                            .mem_addrs
2872                            .first()
2873                            .unwrap_validated();
2874                        let memory = store.memories.get(mem_addr);
2875                        let relative_address: u32 = stack.pop_value().try_into().unwrap_validated();
2876                        let idx = calculate_mem_address(&memarg, relative_address)?;
2877
2878                        let lane = memory.mem.load::<4, u32>(idx)?;
2879                        stack.push_value::<T>(Value::V128(from_lanes([lane; 4])))?;
2880                    }
2881                    V128_LOAD64_SPLAT => {
2882                        let memarg = MemArg::read(wasm).unwrap_validated();
2883                        let mem_addr = *store
2884                            .modules
2885                            .get(current_module)
2886                            .mem_addrs
2887                            .first()
2888                            .unwrap_validated();
2889                        let memory = store.memories.get(mem_addr);
2890                        let relative_address: u32 = stack.pop_value().try_into().unwrap_validated();
2891                        let idx = calculate_mem_address(&memarg, relative_address)?;
2892
2893                        let lane = memory.mem.load::<8, u64>(idx)?;
2894                        stack.push_value::<T>(Value::V128(from_lanes([lane; 2])))?;
2895                    }
2896
2897                    // v128.loadN_zero
2898                    V128_LOAD32_ZERO => {
2899                        let memarg = MemArg::read(wasm).unwrap_validated();
2900                        let mem_addr = *store
2901                            .modules
2902                            .get(current_module)
2903                            .mem_addrs
2904                            .first()
2905                            .unwrap_validated();
2906                        let memory = store.memories.get(mem_addr);
2907
2908                        let relative_address: u32 = stack.pop_value().try_into().unwrap_validated();
2909                        let idx = calculate_mem_address(&memarg, relative_address)?;
2910
2911                        let data = memory.mem.load::<4, u32>(idx)? as u128;
2912                        stack.push_value::<T>(Value::V128(data.to_le_bytes()))?;
2913                    }
2914                    V128_LOAD64_ZERO => {
2915                        let memarg = MemArg::read(wasm).unwrap_validated();
2916                        let mem_addr = *store
2917                            .modules
2918                            .get(current_module)
2919                            .mem_addrs
2920                            .first()
2921                            .unwrap_validated();
2922                        let memory = store.memories.get(mem_addr);
2923
2924                        let relative_address: u32 = stack.pop_value().try_into().unwrap_validated();
2925                        let idx = calculate_mem_address(&memarg, relative_address)?;
2926
2927                        let data = memory.mem.load::<8, u64>(idx)? as u128;
2928                        stack.push_value::<T>(Value::V128(data.to_le_bytes()))?;
2929                    }
2930
2931                    // v128.loadN_lane
2932                    V128_LOAD8_LANE => {
2933                        let data: [u8; 16] = stack.pop_value().try_into().unwrap_validated();
2934                        let relative_address: u32 = stack.pop_value().try_into().unwrap_validated();
2935                        let memarg = MemArg::read(wasm).unwrap_validated();
2936                        let mem_addr = *store
2937                            .modules
2938                            .get(current_module)
2939                            .mem_addrs
2940                            .first()
2941                            .unwrap_validated();
2942                        let memory = store.memories.get(mem_addr);
2943                        let idx = calculate_mem_address(&memarg, relative_address)?;
2944                        let lane_idx = wasm.read_u8().unwrap_validated() as usize;
2945                        let mut lanes: [u8; 16] = to_lanes(data);
2946                        *lanes.get_mut(lane_idx).unwrap_validated() =
2947                            memory.mem.load::<1, u8>(idx)?;
2948                        stack.push_value::<T>(Value::V128(from_lanes(lanes)))?;
2949                    }
2950
2951                    V128_LOAD16_LANE => {
2952                        let data: [u8; 16] = stack.pop_value().try_into().unwrap_validated();
2953                        let relative_address: u32 = stack.pop_value().try_into().unwrap_validated();
2954                        let memarg = MemArg::read(wasm).unwrap_validated();
2955                        let mem_addr = *store
2956                            .modules
2957                            .get(current_module)
2958                            .mem_addrs
2959                            .first()
2960                            .unwrap_validated();
2961                        let memory = store.memories.get(mem_addr);
2962                        let idx = calculate_mem_address(&memarg, relative_address)?;
2963                        let lane_idx = wasm.read_u8().unwrap_validated() as usize;
2964                        let mut lanes: [u16; 8] = to_lanes(data);
2965                        *lanes.get_mut(lane_idx).unwrap_validated() =
2966                            memory.mem.load::<2, u16>(idx)?;
2967                        stack.push_value::<T>(Value::V128(from_lanes(lanes)))?;
2968                    }
2969                    V128_LOAD32_LANE => {
2970                        let data: [u8; 16] = stack.pop_value().try_into().unwrap_validated();
2971                        let relative_address: u32 = stack.pop_value().try_into().unwrap_validated();
2972                        let memarg = MemArg::read(wasm).unwrap_validated();
2973                        let mem_addr = *store
2974                            .modules
2975                            .get(current_module)
2976                            .mem_addrs
2977                            .first()
2978                            .unwrap_validated();
2979                        let memory = store.memories.get(mem_addr);
2980                        let idx = calculate_mem_address(&memarg, relative_address)?;
2981                        let lane_idx = wasm.read_u8().unwrap_validated() as usize;
2982                        let mut lanes: [u32; 4] = to_lanes(data);
2983                        *lanes.get_mut(lane_idx).unwrap_validated() =
2984                            memory.mem.load::<4, u32>(idx)?;
2985                        stack.push_value::<T>(Value::V128(from_lanes(lanes)))?;
2986                    }
2987                    V128_LOAD64_LANE => {
2988                        let data: [u8; 16] = stack.pop_value().try_into().unwrap_validated();
2989                        let relative_address: u32 = stack.pop_value().try_into().unwrap_validated();
2990                        let memarg = MemArg::read(wasm).unwrap_validated();
2991                        let mem_addr = *store
2992                            .modules
2993                            .get(current_module)
2994                            .mem_addrs
2995                            .first()
2996                            .unwrap_validated();
2997                        let memory = store.memories.get(mem_addr);
2998                        let idx = calculate_mem_address(&memarg, relative_address)?;
2999                        let lane_idx = wasm.read_u8().unwrap_validated() as usize;
3000                        let mut lanes: [u64; 2] = to_lanes(data);
3001                        *lanes.get_mut(lane_idx).unwrap_validated() =
3002                            memory.mem.load::<8, u64>(idx)?;
3003                        stack.push_value::<T>(Value::V128(from_lanes(lanes)))?;
3004                    }
3005
3006                    // v128.storeN_lane
3007                    V128_STORE8_LANE => {
3008                        let data: [u8; 16] = stack.pop_value().try_into().unwrap_validated();
3009                        let relative_address: u32 = stack.pop_value().try_into().unwrap_validated();
3010                        let memarg = MemArg::read(wasm).unwrap_validated();
3011                        let mem_addr = *store
3012                            .modules
3013                            .get(current_module)
3014                            .mem_addrs
3015                            .first()
3016                            .unwrap_validated();
3017                        let memory = store.memories.get(mem_addr);
3018                        let idx = calculate_mem_address(&memarg, relative_address)?;
3019                        let lane_idx = wasm.read_u8().unwrap_validated() as usize;
3020
3021                        let lane = *to_lanes::<1, 16, u8>(data).get(lane_idx).unwrap_validated();
3022
3023                        memory.mem.store::<1, u8>(idx, lane)?;
3024                    }
3025                    V128_STORE16_LANE => {
3026                        let data: [u8; 16] = stack.pop_value().try_into().unwrap_validated();
3027                        let relative_address: u32 = stack.pop_value().try_into().unwrap_validated();
3028                        let memarg = MemArg::read(wasm).unwrap_validated();
3029                        let mem_addr = *store
3030                            .modules
3031                            .get(current_module)
3032                            .mem_addrs
3033                            .first()
3034                            .unwrap_validated();
3035                        let memory = store.memories.get(mem_addr);
3036                        let idx = calculate_mem_address(&memarg, relative_address)?;
3037                        let lane_idx = wasm.read_u8().unwrap_validated() as usize;
3038
3039                        let lane = *to_lanes::<2, 8, u16>(data).get(lane_idx).unwrap_validated();
3040
3041                        memory.mem.store::<2, u16>(idx, lane)?;
3042                    }
3043                    V128_STORE32_LANE => {
3044                        let data: [u8; 16] = stack.pop_value().try_into().unwrap_validated();
3045                        let relative_address: u32 = stack.pop_value().try_into().unwrap_validated();
3046                        let memarg = MemArg::read(wasm).unwrap_validated();
3047                        let mem_addr = *store
3048                            .modules
3049                            .get(current_module)
3050                            .mem_addrs
3051                            .first()
3052                            .unwrap_validated();
3053                        let memory = store.memories.get(mem_addr);
3054                        let idx = calculate_mem_address(&memarg, relative_address)?;
3055                        let lane_idx = wasm.read_u8().unwrap_validated() as usize;
3056
3057                        let lane = *to_lanes::<4, 4, u32>(data).get(lane_idx).unwrap_validated();
3058
3059                        memory.mem.store::<4, u32>(idx, lane)?;
3060                    }
3061                    V128_STORE64_LANE => {
3062                        let data: [u8; 16] = stack.pop_value().try_into().unwrap_validated();
3063                        let relative_address: u32 = stack.pop_value().try_into().unwrap_validated();
3064                        let memarg = MemArg::read(wasm).unwrap_validated();
3065                        let mem_addr = *store
3066                            .modules
3067                            .get(current_module)
3068                            .mem_addrs
3069                            .first()
3070                            .unwrap_validated();
3071                        let memory = store.memories.get(mem_addr);
3072                        let idx = calculate_mem_address(&memarg, relative_address)?;
3073                        let lane_idx = wasm.read_u8().unwrap_validated() as usize;
3074
3075                        let lane = *to_lanes::<8, 2, u64>(data).get(lane_idx).unwrap_validated();
3076
3077                        memory.mem.store::<8, u64>(idx, lane)?;
3078                    }
3079
3080                    V128_CONST => {
3081                        let mut data = [0; 16];
3082                        for byte_ref in &mut data {
3083                            *byte_ref = wasm.read_u8().unwrap_validated();
3084                        }
3085
3086                        stack.push_value::<T>(Value::V128(data))?;
3087                    }
3088
3089                    // vvunop <https://webassembly.github.io/spec/core/syntax/instructions.html#syntax-vvunop>
3090                    V128_NOT => {
3091                        let data: [u8; 16] = stack.pop_value().try_into().unwrap_validated();
3092                        stack.push_value::<T>(Value::V128(data.map(|byte| !byte)))?;
3093                    }
3094
3095                    // vvbinop <https://webassembly.github.io/spec/core/syntax/instructions.html#syntax-vvbinop>
3096                    V128_AND => {
3097                        let data2: [u8; 16] = stack.pop_value().try_into().unwrap_validated();
3098                        let data1: [u8; 16] = stack.pop_value().try_into().unwrap_validated();
3099                        let result = array::from_fn(|i| data1[i] & data2[i]);
3100                        stack.push_value::<T>(Value::V128(result))?;
3101                    }
3102                    V128_ANDNOT => {
3103                        let data2: [u8; 16] = stack.pop_value().try_into().unwrap_validated();
3104                        let data1: [u8; 16] = stack.pop_value().try_into().unwrap_validated();
3105                        let result = array::from_fn(|i| data1[i] & !data2[i]);
3106                        stack.push_value::<T>(Value::V128(result))?;
3107                    }
3108                    V128_OR => {
3109                        let data2: [u8; 16] = stack.pop_value().try_into().unwrap_validated();
3110                        let data1: [u8; 16] = stack.pop_value().try_into().unwrap_validated();
3111                        let result = array::from_fn(|i| data1[i] | data2[i]);
3112                        stack.push_value::<T>(Value::V128(result))?;
3113                    }
3114                    V128_XOR => {
3115                        let data2: [u8; 16] = stack.pop_value().try_into().unwrap_validated();
3116                        let data1: [u8; 16] = stack.pop_value().try_into().unwrap_validated();
3117                        let result = array::from_fn(|i| data1[i] ^ data2[i]);
3118                        stack.push_value::<T>(Value::V128(result))?;
3119                    }
3120
3121                    // vvternop <https://webassembly.github.io/spec/core/syntax/instructions.html#syntax-vvternop>
3122                    V128_BITSELECT => {
3123                        let data3: [u8; 16] = stack.pop_value().try_into().unwrap_validated();
3124                        let data2: [u8; 16] = stack.pop_value().try_into().unwrap_validated();
3125                        let data1: [u8; 16] = stack.pop_value().try_into().unwrap_validated();
3126                        let result =
3127                            array::from_fn(|i| (data1[i] & data3[i]) | (data2[i] & !data3[i]));
3128                        stack.push_value::<T>(Value::V128(result))?;
3129                    }
3130
3131                    // vvtestop <https://webassembly.github.io/spec/core/syntax/instructions.html#syntax-vvtestop>
3132                    V128_ANY_TRUE => {
3133                        let data: [u8; 16] = stack.pop_value().try_into().unwrap_validated();
3134                        let any_true = data.into_iter().any(|byte| byte > 0);
3135                        stack.push_value::<T>(Value::I32(any_true as u32))?;
3136                    }
3137
3138                    I8X16_SWIZZLE => {
3139                        let data2: [u8; 16] = stack.pop_value().try_into().unwrap_validated();
3140                        let data1: [u8; 16] = stack.pop_value().try_into().unwrap_validated();
3141                        let result =
3142                            array::from_fn(|i| *data1.get(data2[i] as usize).unwrap_or(&0));
3143                        stack.push_value::<T>(Value::V128(result))?;
3144                    }
3145
3146                    I8X16_SHUFFLE => {
3147                        let data2: [u8; 16] = stack.pop_value().try_into().unwrap_validated();
3148                        let data1: [u8; 16] = stack.pop_value().try_into().unwrap_validated();
3149
3150                        let lane_selector_indices: [u8; 16] =
3151                            array::from_fn(|_| wasm.read_u8().unwrap_validated());
3152
3153                        let result = lane_selector_indices.map(|i| {
3154                            *data1
3155                                .get(i as usize)
3156                                .or_else(|| data2.get(i as usize - 16))
3157                                .unwrap_validated()
3158                        });
3159
3160                        stack.push_value::<T>(Value::V128(result))?;
3161                    }
3162
3163                    // shape.splat
3164                    I8X16_SPLAT => {
3165                        let value: u32 = stack.pop_value().try_into().unwrap_validated();
3166                        let lane = value as u8;
3167                        let data = from_lanes([lane; 16]);
3168                        stack.push_value::<T>(Value::V128(data))?;
3169                    }
3170                    I16X8_SPLAT => {
3171                        let value: u32 = stack.pop_value().try_into().unwrap_validated();
3172                        let lane = value as u16;
3173                        let data = from_lanes([lane; 8]);
3174                        stack.push_value::<T>(Value::V128(data))?;
3175                    }
3176                    I32X4_SPLAT => {
3177                        let lane: u32 = stack.pop_value().try_into().unwrap_validated();
3178                        let data = from_lanes([lane; 4]);
3179                        stack.push_value::<T>(Value::V128(data))?;
3180                    }
3181                    I64X2_SPLAT => {
3182                        let lane: u64 = stack.pop_value().try_into().unwrap_validated();
3183                        let data = from_lanes([lane; 2]);
3184                        stack.push_value::<T>(Value::V128(data))?;
3185                    }
3186                    F32X4_SPLAT => {
3187                        let lane: F32 = stack.pop_value().try_into().unwrap_validated();
3188                        let data = from_lanes([lane; 4]);
3189                        stack.push_value::<T>(Value::V128(data))?;
3190                    }
3191                    F64X2_SPLAT => {
3192                        let lane: F64 = stack.pop_value().try_into().unwrap_validated();
3193                        let data = from_lanes([lane; 2]);
3194                        stack.push_value::<T>(Value::V128(data))?;
3195                    }
3196
3197                    // shape.extract_lane
3198                    I8X16_EXTRACT_LANE_S => {
3199                        let lane_idx = wasm.read_u8().unwrap_validated() as usize;
3200                        let data: [u8; 16] = stack.pop_value().try_into().unwrap_validated();
3201                        let lanes: [i8; 16] = to_lanes(data);
3202                        let lane = *lanes.get(lane_idx).unwrap_validated();
3203                        stack.push_value::<T>(Value::I32(lane as u32))?;
3204                    }
3205                    I8X16_EXTRACT_LANE_U => {
3206                        let lane_idx = wasm.read_u8().unwrap_validated() as usize;
3207                        let data: [u8; 16] = stack.pop_value().try_into().unwrap_validated();
3208                        let lanes: [u8; 16] = to_lanes(data);
3209                        let lane = *lanes.get(lane_idx).unwrap_validated();
3210                        stack.push_value::<T>(Value::I32(lane as u32))?;
3211                    }
3212                    I16X8_EXTRACT_LANE_S => {
3213                        let lane_idx = wasm.read_u8().unwrap_validated() as usize;
3214                        let data: [u8; 16] = stack.pop_value().try_into().unwrap_validated();
3215                        let lanes: [i16; 8] = to_lanes(data);
3216                        let lane = *lanes.get(lane_idx).unwrap_validated();
3217                        stack.push_value::<T>(Value::I32(lane as u32))?;
3218                    }
3219                    I16X8_EXTRACT_LANE_U => {
3220                        let lane_idx = wasm.read_u8().unwrap_validated() as usize;
3221                        let data: [u8; 16] = stack.pop_value().try_into().unwrap_validated();
3222                        let lanes: [u16; 8] = to_lanes(data);
3223                        let lane = *lanes.get(lane_idx).unwrap_validated();
3224                        stack.push_value::<T>(Value::I32(lane as u32))?;
3225                    }
3226                    I32X4_EXTRACT_LANE => {
3227                        let lane_idx = wasm.read_u8().unwrap_validated() as usize;
3228                        let data: [u8; 16] = stack.pop_value().try_into().unwrap_validated();
3229                        let lanes: [u32; 4] = to_lanes(data);
3230                        let lane = *lanes.get(lane_idx).unwrap_validated();
3231                        stack.push_value::<T>(Value::I32(lane))?;
3232                    }
3233                    I64X2_EXTRACT_LANE => {
3234                        let lane_idx = wasm.read_u8().unwrap_validated() as usize;
3235                        let data: [u8; 16] = stack.pop_value().try_into().unwrap_validated();
3236                        let lanes: [u64; 2] = to_lanes(data);
3237                        let lane = *lanes.get(lane_idx).unwrap_validated();
3238                        stack.push_value::<T>(Value::I64(lane))?;
3239                    }
3240                    F32X4_EXTRACT_LANE => {
3241                        let lane_idx = wasm.read_u8().unwrap_validated() as usize;
3242                        let data: [u8; 16] = stack.pop_value().try_into().unwrap_validated();
3243                        let lanes: [F32; 4] = to_lanes(data);
3244                        let lane = *lanes.get(lane_idx).unwrap_validated();
3245                        stack.push_value::<T>(Value::F32(lane))?;
3246                    }
3247                    F64X2_EXTRACT_LANE => {
3248                        let lane_idx = wasm.read_u8().unwrap_validated() as usize;
3249                        let data: [u8; 16] = stack.pop_value().try_into().unwrap_validated();
3250                        let lanes: [F64; 2] = to_lanes(data);
3251                        let lane = *lanes.get(lane_idx).unwrap_validated();
3252                        stack.push_value::<T>(Value::F64(lane))?;
3253                    }
3254
3255                    // shape.replace_lane
3256                    I8X16_REPLACE_LANE => {
3257                        let lane_idx = wasm.read_u8().unwrap_validated() as usize;
3258                        let value: u32 = stack.pop_value().try_into().unwrap_validated();
3259                        let new_lane = value as u8;
3260                        let data: [u8; 16] = stack.pop_value().try_into().unwrap_validated();
3261                        let mut lanes: [u8; 16] = to_lanes(data);
3262                        *lanes.get_mut(lane_idx).unwrap_validated() = new_lane;
3263                        stack.push_value::<T>(Value::V128(from_lanes(lanes)))?;
3264                    }
3265                    I16X8_REPLACE_LANE => {
3266                        let lane_idx = wasm.read_u8().unwrap_validated() as usize;
3267                        let value: u32 = stack.pop_value().try_into().unwrap_validated();
3268                        let new_lane = value as u16;
3269                        let data: [u8; 16] = stack.pop_value().try_into().unwrap_validated();
3270                        let mut lanes: [u16; 8] = to_lanes(data);
3271                        *lanes.get_mut(lane_idx).unwrap_validated() = new_lane;
3272                        stack.push_value::<T>(Value::V128(from_lanes(lanes)))?;
3273                    }
3274                    I32X4_REPLACE_LANE => {
3275                        let lane_idx = wasm.read_u8().unwrap_validated() as usize;
3276                        let new_lane: u32 = stack.pop_value().try_into().unwrap_validated();
3277                        let data: [u8; 16] = stack.pop_value().try_into().unwrap_validated();
3278                        let mut lanes: [u32; 4] = to_lanes(data);
3279                        *lanes.get_mut(lane_idx).unwrap_validated() = new_lane;
3280                        stack.push_value::<T>(Value::V128(from_lanes(lanes)))?;
3281                    }
3282                    I64X2_REPLACE_LANE => {
3283                        let lane_idx = wasm.read_u8().unwrap_validated() as usize;
3284                        let new_lane: u64 = stack.pop_value().try_into().unwrap_validated();
3285                        let data: [u8; 16] = stack.pop_value().try_into().unwrap_validated();
3286                        let mut lanes: [u64; 2] = to_lanes(data);
3287                        *lanes.get_mut(lane_idx).unwrap_validated() = new_lane;
3288                        stack.push_value::<T>(Value::V128(from_lanes(lanes)))?;
3289                    }
3290                    F32X4_REPLACE_LANE => {
3291                        let lane_idx = wasm.read_u8().unwrap_validated() as usize;
3292                        let new_lane: F32 = stack.pop_value().try_into().unwrap_validated();
3293                        let data: [u8; 16] = stack.pop_value().try_into().unwrap_validated();
3294                        let mut lanes: [F32; 4] = to_lanes(data);
3295                        *lanes.get_mut(lane_idx).unwrap_validated() = new_lane;
3296                        stack.push_value::<T>(Value::V128(from_lanes(lanes)))?;
3297                    }
3298                    F64X2_REPLACE_LANE => {
3299                        let lane_idx = wasm.read_u8().unwrap_validated() as usize;
3300                        let new_lane: F64 = stack.pop_value().try_into().unwrap_validated();
3301                        let data: [u8; 16] = stack.pop_value().try_into().unwrap_validated();
3302                        let mut lanes: [F64; 2] = to_lanes(data);
3303                        *lanes.get_mut(lane_idx).unwrap_validated() = new_lane;
3304                        stack.push_value::<T>(Value::V128(from_lanes(lanes)))?;
3305                    }
3306
3307                    // Group vunop <https://webassembly.github.io/spec/core/syntax/instructions.html#syntax-vunop>
3308                    // viunop
3309                    I8X16_ABS => {
3310                        let data: [u8; 16] = stack.pop_value().try_into().unwrap_validated();
3311                        let lanes: [i8; 16] = to_lanes(data);
3312                        let result: [i8; 16] = lanes.map(i8::wrapping_abs);
3313                        stack.push_value::<T>(Value::V128(from_lanes(result)))?;
3314                    }
3315                    I16X8_ABS => {
3316                        let data: [u8; 16] = stack.pop_value().try_into().unwrap_validated();
3317                        let lanes: [i16; 8] = to_lanes(data);
3318                        let result: [i16; 8] = lanes.map(i16::wrapping_abs);
3319                        stack.push_value::<T>(Value::V128(from_lanes(result)))?;
3320                    }
3321                    I32X4_ABS => {
3322                        let data: [u8; 16] = stack.pop_value().try_into().unwrap_validated();
3323                        let lanes: [i32; 4] = to_lanes(data);
3324                        let result: [i32; 4] = lanes.map(i32::wrapping_abs);
3325                        stack.push_value::<T>(Value::V128(from_lanes(result)))?;
3326                    }
3327                    I64X2_ABS => {
3328                        let data: [u8; 16] = stack.pop_value().try_into().unwrap_validated();
3329                        let lanes: [i64; 2] = to_lanes(data);
3330                        let result: [i64; 2] = lanes.map(i64::wrapping_abs);
3331                        stack.push_value::<T>(Value::V128(from_lanes(result)))?;
3332                    }
3333                    I8X16_NEG => {
3334                        let data: [u8; 16] = stack.pop_value().try_into().unwrap_validated();
3335                        let lanes: [i8; 16] = to_lanes(data);
3336                        let result: [i8; 16] = lanes.map(i8::wrapping_neg);
3337                        stack.push_value::<T>(Value::V128(from_lanes(result)))?;
3338                    }
3339                    I16X8_NEG => {
3340                        let data: [u8; 16] = stack.pop_value().try_into().unwrap_validated();
3341                        let lanes: [i16; 8] = to_lanes(data);
3342                        let result: [i16; 8] = lanes.map(i16::wrapping_neg);
3343                        stack.push_value::<T>(Value::V128(from_lanes(result)))?;
3344                    }
3345                    I32X4_NEG => {
3346                        let data: [u8; 16] = stack.pop_value().try_into().unwrap_validated();
3347                        let lanes: [i32; 4] = to_lanes(data);
3348                        let result: [i32; 4] = lanes.map(i32::wrapping_neg);
3349                        stack.push_value::<T>(Value::V128(from_lanes(result)))?;
3350                    }
3351                    I64X2_NEG => {
3352                        let data: [u8; 16] = stack.pop_value().try_into().unwrap_validated();
3353                        let lanes: [i64; 2] = to_lanes(data);
3354                        let result: [i64; 2] = lanes.map(i64::wrapping_neg);
3355                        stack.push_value::<T>(Value::V128(from_lanes(result)))?;
3356                    }
3357                    // vfunop
3358                    F32X4_ABS => {
3359                        let data: [u8; 16] = stack.pop_value().try_into().unwrap_validated();
3360                        let lanes: [F32; 4] = to_lanes(data);
3361                        let result: [F32; 4] = lanes.map(|lane| lane.abs());
3362                        stack.push_value::<T>(Value::V128(from_lanes(result)))?;
3363                    }
3364                    F64X2_ABS => {
3365                        let data: [u8; 16] = stack.pop_value().try_into().unwrap_validated();
3366                        let lanes: [F64; 2] = to_lanes(data);
3367                        let result: [F64; 2] = lanes.map(|lane| lane.abs());
3368                        stack.push_value::<T>(Value::V128(from_lanes(result)))?;
3369                    }
3370                    F32X4_NEG => {
3371                        let data: [u8; 16] = stack.pop_value().try_into().unwrap_validated();
3372                        let lanes: [F32; 4] = to_lanes(data);
3373                        let result: [F32; 4] = lanes.map(|lane| lane.neg());
3374                        stack.push_value::<T>(Value::V128(from_lanes(result)))?;
3375                    }
3376                    F64X2_NEG => {
3377                        let data: [u8; 16] = stack.pop_value().try_into().unwrap_validated();
3378                        let lanes: [F64; 2] = to_lanes(data);
3379                        let result: [F64; 2] = lanes.map(|lane| lane.neg());
3380                        stack.push_value::<T>(Value::V128(from_lanes(result)))?;
3381                    }
3382                    F32X4_SQRT => {
3383                        let data: [u8; 16] = stack.pop_value().try_into().unwrap_validated();
3384                        let lanes: [F32; 4] = to_lanes(data);
3385                        let result: [F32; 4] = lanes.map(|lane| lane.sqrt());
3386                        stack.push_value::<T>(Value::V128(from_lanes(result)))?;
3387                    }
3388                    F64X2_SQRT => {
3389                        let data: [u8; 16] = stack.pop_value().try_into().unwrap_validated();
3390                        let lanes: [F64; 2] = to_lanes(data);
3391                        let result: [F64; 2] = lanes.map(|lane| lane.sqrt());
3392                        stack.push_value::<T>(Value::V128(from_lanes(result)))?;
3393                    }
3394                    F32X4_CEIL => {
3395                        let data: [u8; 16] = stack.pop_value().try_into().unwrap_validated();
3396                        let lanes: [F32; 4] = to_lanes(data);
3397                        let result: [F32; 4] = lanes.map(|lane| lane.ceil());
3398                        stack.push_value::<T>(Value::V128(from_lanes(result)))?;
3399                    }
3400                    F64X2_CEIL => {
3401                        let data: [u8; 16] = stack.pop_value().try_into().unwrap_validated();
3402                        let lanes: [F64; 2] = to_lanes(data);
3403                        let result: [F64; 2] = lanes.map(|lane| lane.ceil());
3404                        stack.push_value::<T>(Value::V128(from_lanes(result)))?;
3405                    }
3406                    F32X4_FLOOR => {
3407                        let data: [u8; 16] = stack.pop_value().try_into().unwrap_validated();
3408                        let lanes: [F32; 4] = to_lanes(data);
3409                        let result: [F32; 4] = lanes.map(|lane| lane.floor());
3410                        stack.push_value::<T>(Value::V128(from_lanes(result)))?;
3411                    }
3412                    F64X2_FLOOR => {
3413                        let data: [u8; 16] = stack.pop_value().try_into().unwrap_validated();
3414                        let lanes: [F64; 2] = to_lanes(data);
3415                        let result: [F64; 2] = lanes.map(|lane| lane.floor());
3416                        stack.push_value::<T>(Value::V128(from_lanes(result)))?;
3417                    }
3418                    F32X4_TRUNC => {
3419                        let data: [u8; 16] = stack.pop_value().try_into().unwrap_validated();
3420                        let lanes: [F32; 4] = to_lanes(data);
3421                        let result: [F32; 4] = lanes.map(|lane| lane.trunc());
3422                        stack.push_value::<T>(Value::V128(from_lanes(result)))?;
3423                    }
3424                    F64X2_TRUNC => {
3425                        let data: [u8; 16] = stack.pop_value().try_into().unwrap_validated();
3426                        let lanes: [F64; 2] = to_lanes(data);
3427                        let result: [F64; 2] = lanes.map(|lane| lane.trunc());
3428                        stack.push_value::<T>(Value::V128(from_lanes(result)))?;
3429                    }
3430                    F32X4_NEAREST => {
3431                        let data: [u8; 16] = stack.pop_value().try_into().unwrap_validated();
3432                        let lanes: [F32; 4] = to_lanes(data);
3433                        let result: [F32; 4] = lanes.map(|lane| lane.nearest());
3434                        stack.push_value::<T>(Value::V128(from_lanes(result)))?;
3435                    }
3436                    F64X2_NEAREST => {
3437                        let data: [u8; 16] = stack.pop_value().try_into().unwrap_validated();
3438                        let lanes: [F64; 2] = to_lanes(data);
3439                        let result: [F64; 2] = lanes.map(|lane| lane.nearest());
3440                        stack.push_value::<T>(Value::V128(from_lanes(result)))?;
3441                    }
3442                    // others
3443                    I8X16_POPCNT => {
3444                        let data: [u8; 16] = stack.pop_value().try_into().unwrap_validated();
3445                        let lanes: [u8; 16] = to_lanes(data);
3446                        let result: [u8; 16] = lanes.map(|lane| lane.count_ones() as u8);
3447                        stack.push_value::<T>(Value::V128(from_lanes(result)))?;
3448                    }
3449
3450                    // Group vbinop <https://webassembly.github.io/spec/core/syntax/instructions.html#syntax-vbinop>
3451                    // vibinop
3452                    I8X16_ADD => {
3453                        let data2: [u8; 16] = stack.pop_value().try_into().unwrap_validated();
3454                        let data1: [u8; 16] = stack.pop_value().try_into().unwrap_validated();
3455                        let lanes2: [u8; 16] = to_lanes(data2);
3456                        let lanes1: [u8; 16] = to_lanes(data1);
3457                        let result: [u8; 16] =
3458                            array::from_fn(|i| lanes1[i].wrapping_add(lanes2[i]));
3459                        stack.push_value::<T>(Value::V128(from_lanes(result)))?;
3460                    }
3461                    I16X8_ADD => {
3462                        let data2: [u8; 16] = stack.pop_value().try_into().unwrap_validated();
3463                        let data1: [u8; 16] = stack.pop_value().try_into().unwrap_validated();
3464                        let lanes2: [u16; 8] = to_lanes(data2);
3465                        let lanes1: [u16; 8] = to_lanes(data1);
3466                        let result: [u16; 8] =
3467                            array::from_fn(|i| lanes1[i].wrapping_add(lanes2[i]));
3468                        stack.push_value::<T>(Value::V128(from_lanes(result)))?;
3469                    }
3470                    I32X4_ADD => {
3471                        let data2: [u8; 16] = stack.pop_value().try_into().unwrap_validated();
3472                        let data1: [u8; 16] = stack.pop_value().try_into().unwrap_validated();
3473                        let lanes2: [u32; 4] = to_lanes(data2);
3474                        let lanes1: [u32; 4] = to_lanes(data1);
3475                        let result: [u32; 4] =
3476                            array::from_fn(|i| lanes1[i].wrapping_add(lanes2[i]));
3477                        stack.push_value::<T>(Value::V128(from_lanes(result)))?;
3478                    }
3479                    I64X2_ADD => {
3480                        let data2: [u8; 16] = stack.pop_value().try_into().unwrap_validated();
3481                        let data1: [u8; 16] = stack.pop_value().try_into().unwrap_validated();
3482                        let lanes2: [u64; 2] = to_lanes(data2);
3483                        let lanes1: [u64; 2] = to_lanes(data1);
3484                        let result: [u64; 2] =
3485                            array::from_fn(|i| lanes1[i].wrapping_add(lanes2[i]));
3486                        stack.push_value::<T>(Value::V128(from_lanes(result)))?;
3487                    }
3488                    I8X16_SUB => {
3489                        let data2: [u8; 16] = stack.pop_value().try_into().unwrap_validated();
3490                        let data1: [u8; 16] = stack.pop_value().try_into().unwrap_validated();
3491                        let lanes2: [u8; 16] = to_lanes(data2);
3492                        let lanes1: [u8; 16] = to_lanes(data1);
3493                        let result: [u8; 16] =
3494                            array::from_fn(|i| lanes1[i].wrapping_sub(lanes2[i]));
3495                        stack.push_value::<T>(Value::V128(from_lanes(result)))?;
3496                    }
3497                    I16X8_SUB => {
3498                        let data2: [u8; 16] = stack.pop_value().try_into().unwrap_validated();
3499                        let data1: [u8; 16] = stack.pop_value().try_into().unwrap_validated();
3500                        let lanes2: [u16; 8] = to_lanes(data2);
3501                        let lanes1: [u16; 8] = to_lanes(data1);
3502                        let result: [u16; 8] =
3503                            array::from_fn(|i| lanes1[i].wrapping_sub(lanes2[i]));
3504                        stack.push_value::<T>(Value::V128(from_lanes(result)))?;
3505                    }
3506                    I32X4_SUB => {
3507                        let data2: [u8; 16] = stack.pop_value().try_into().unwrap_validated();
3508                        let data1: [u8; 16] = stack.pop_value().try_into().unwrap_validated();
3509                        let lanes2: [u32; 4] = to_lanes(data2);
3510                        let lanes1: [u32; 4] = to_lanes(data1);
3511                        let result: [u32; 4] =
3512                            array::from_fn(|i| lanes1[i].wrapping_sub(lanes2[i]));
3513                        stack.push_value::<T>(Value::V128(from_lanes(result)))?;
3514                    }
3515                    I64X2_SUB => {
3516                        let data2: [u8; 16] = stack.pop_value().try_into().unwrap_validated();
3517                        let data1: [u8; 16] = stack.pop_value().try_into().unwrap_validated();
3518                        let lanes2: [u64; 2] = to_lanes(data2);
3519                        let lanes1: [u64; 2] = to_lanes(data1);
3520                        let result: [u64; 2] =
3521                            array::from_fn(|i| lanes1[i].wrapping_sub(lanes2[i]));
3522                        stack.push_value::<T>(Value::V128(from_lanes(result)))?;
3523                    }
3524                    // vfbinop
3525                    F32X4_ADD => {
3526                        let data2: [u8; 16] = stack.pop_value().try_into().unwrap_validated();
3527                        let data1: [u8; 16] = stack.pop_value().try_into().unwrap_validated();
3528                        let lanes2: [F32; 4] = to_lanes(data2);
3529                        let lanes1: [F32; 4] = to_lanes(data1);
3530                        let result: [F32; 4] = array::from_fn(|i| lanes1[i].add(lanes2[i]));
3531                        stack.push_value::<T>(Value::V128(from_lanes(result)))?;
3532                    }
3533                    F64X2_ADD => {
3534                        let data2: [u8; 16] = stack.pop_value().try_into().unwrap_validated();
3535                        let data1: [u8; 16] = stack.pop_value().try_into().unwrap_validated();
3536                        let lanes2: [F64; 2] = to_lanes(data2);
3537                        let lanes1: [F64; 2] = to_lanes(data1);
3538                        let result: [F64; 2] = array::from_fn(|i| lanes1[i].add(lanes2[i]));
3539                        stack.push_value::<T>(Value::V128(from_lanes(result)))?;
3540                    }
3541                    F32X4_SUB => {
3542                        let data2: [u8; 16] = stack.pop_value().try_into().unwrap_validated();
3543                        let data1: [u8; 16] = stack.pop_value().try_into().unwrap_validated();
3544                        let lanes2: [F32; 4] = to_lanes(data2);
3545                        let lanes1: [F32; 4] = to_lanes(data1);
3546                        let result: [F32; 4] = array::from_fn(|i| lanes1[i].sub(lanes2[i]));
3547                        stack.push_value::<T>(Value::V128(from_lanes(result)))?;
3548                    }
3549                    F64X2_SUB => {
3550                        let data2: [u8; 16] = stack.pop_value().try_into().unwrap_validated();
3551                        let data1: [u8; 16] = stack.pop_value().try_into().unwrap_validated();
3552                        let lanes2: [F64; 2] = to_lanes(data2);
3553                        let lanes1: [F64; 2] = to_lanes(data1);
3554                        let result: [F64; 2] = array::from_fn(|i| lanes1[i].sub(lanes2[i]));
3555                        stack.push_value::<T>(Value::V128(from_lanes(result)))?;
3556                    }
3557                    F32X4_MUL => {
3558                        let data2: [u8; 16] = stack.pop_value().try_into().unwrap_validated();
3559                        let data1: [u8; 16] = stack.pop_value().try_into().unwrap_validated();
3560                        let lanes2: [F32; 4] = to_lanes(data2);
3561                        let lanes1: [F32; 4] = to_lanes(data1);
3562                        let result: [F32; 4] = array::from_fn(|i| lanes1[i].mul(lanes2[i]));
3563                        stack.push_value::<T>(Value::V128(from_lanes(result)))?;
3564                    }
3565                    F64X2_MUL => {
3566                        let data2: [u8; 16] = stack.pop_value().try_into().unwrap_validated();
3567                        let data1: [u8; 16] = stack.pop_value().try_into().unwrap_validated();
3568                        let lanes2: [F64; 2] = to_lanes(data2);
3569                        let lanes1: [F64; 2] = to_lanes(data1);
3570                        let result: [F64; 2] = array::from_fn(|i| lanes1[i].mul(lanes2[i]));
3571                        stack.push_value::<T>(Value::V128(from_lanes(result)))?;
3572                    }
3573                    F32X4_DIV => {
3574                        let data2: [u8; 16] = stack.pop_value().try_into().unwrap_validated();
3575                        let data1: [u8; 16] = stack.pop_value().try_into().unwrap_validated();
3576                        let lanes2: [F32; 4] = to_lanes(data2);
3577                        let lanes1: [F32; 4] = to_lanes(data1);
3578                        let result: [F32; 4] = array::from_fn(|i| lanes1[i].div(lanes2[i]));
3579                        stack.push_value::<T>(Value::V128(from_lanes(result)))?;
3580                    }
3581                    F64X2_DIV => {
3582                        let data2: [u8; 16] = stack.pop_value().try_into().unwrap_validated();
3583                        let data1: [u8; 16] = stack.pop_value().try_into().unwrap_validated();
3584                        let lanes2: [F64; 2] = to_lanes(data2);
3585                        let lanes1: [F64; 2] = to_lanes(data1);
3586                        let result: [F64; 2] = array::from_fn(|i| lanes1[i].div(lanes2[i]));
3587                        stack.push_value::<T>(Value::V128(from_lanes(result)))?;
3588                    }
3589                    F32X4_MIN => {
3590                        let data2: [u8; 16] = stack.pop_value().try_into().unwrap_validated();
3591                        let data1: [u8; 16] = stack.pop_value().try_into().unwrap_validated();
3592                        let lanes2: [F32; 4] = to_lanes(data2);
3593                        let lanes1: [F32; 4] = to_lanes(data1);
3594                        let result: [F32; 4] = array::from_fn(|i| lanes1[i].min(lanes2[i]));
3595                        stack.push_value::<T>(Value::V128(from_lanes(result)))?;
3596                    }
3597                    F64X2_MIN => {
3598                        let data2: [u8; 16] = stack.pop_value().try_into().unwrap_validated();
3599                        let data1: [u8; 16] = stack.pop_value().try_into().unwrap_validated();
3600                        let lanes2: [F64; 2] = to_lanes(data2);
3601                        let lanes1: [F64; 2] = to_lanes(data1);
3602                        let result: [F64; 2] = array::from_fn(|i| lanes1[i].min(lanes2[i]));
3603                        stack.push_value::<T>(Value::V128(from_lanes(result)))?;
3604                    }
3605                    F32X4_MAX => {
3606                        let data2: [u8; 16] = stack.pop_value().try_into().unwrap_validated();
3607                        let data1: [u8; 16] = stack.pop_value().try_into().unwrap_validated();
3608                        let lanes2: [F32; 4] = to_lanes(data2);
3609                        let lanes1: [F32; 4] = to_lanes(data1);
3610                        let result: [F32; 4] = array::from_fn(|i| lanes1[i].max(lanes2[i]));
3611                        stack.push_value::<T>(Value::V128(from_lanes(result)))?;
3612                    }
3613                    F64X2_MAX => {
3614                        let data2: [u8; 16] = stack.pop_value().try_into().unwrap_validated();
3615                        let data1: [u8; 16] = stack.pop_value().try_into().unwrap_validated();
3616                        let lanes2: [F64; 2] = to_lanes(data2);
3617                        let lanes1: [F64; 2] = to_lanes(data1);
3618                        let result: [F64; 2] = array::from_fn(|i| lanes1[i].max(lanes2[i]));
3619                        stack.push_value::<T>(Value::V128(from_lanes(result)))?;
3620                    }
3621                    F32X4_PMIN => {
3622                        let data2: [u8; 16] = stack.pop_value().try_into().unwrap_validated();
3623                        let data1: [u8; 16] = stack.pop_value().try_into().unwrap_validated();
3624                        let lanes2: [F32; 4] = to_lanes(data2);
3625                        let lanes1: [F32; 4] = to_lanes(data1);
3626                        let result: [F32; 4] = array::from_fn(|i| {
3627                            let v1 = lanes1[i];
3628                            let v2 = lanes2[i];
3629                            if v2 < v1 {
3630                                v2
3631                            } else {
3632                                v1
3633                            }
3634                        });
3635                        stack.push_value::<T>(Value::V128(from_lanes(result)))?;
3636                    }
3637                    F64X2_PMIN => {
3638                        let data2: [u8; 16] = stack.pop_value().try_into().unwrap_validated();
3639                        let data1: [u8; 16] = stack.pop_value().try_into().unwrap_validated();
3640                        let lanes2: [F64; 2] = to_lanes(data2);
3641                        let lanes1: [F64; 2] = to_lanes(data1);
3642                        let result: [F64; 2] = array::from_fn(|i| {
3643                            let v1 = lanes1[i];
3644                            let v2 = lanes2[i];
3645                            if v2 < v1 {
3646                                v2
3647                            } else {
3648                                v1
3649                            }
3650                        });
3651                        stack.push_value::<T>(Value::V128(from_lanes(result)))?;
3652                    }
3653                    F32X4_PMAX => {
3654                        let data2: [u8; 16] = stack.pop_value().try_into().unwrap_validated();
3655                        let data1: [u8; 16] = stack.pop_value().try_into().unwrap_validated();
3656                        let lanes2: [F32; 4] = to_lanes(data2);
3657                        let lanes1: [F32; 4] = to_lanes(data1);
3658                        let result: [F32; 4] = array::from_fn(|i| {
3659                            let v1 = lanes1[i];
3660                            let v2 = lanes2[i];
3661                            if v1 < v2 {
3662                                v2
3663                            } else {
3664                                v1
3665                            }
3666                        });
3667                        stack.push_value::<T>(Value::V128(from_lanes(result)))?;
3668                    }
3669                    F64X2_PMAX => {
3670                        let data2: [u8; 16] = stack.pop_value().try_into().unwrap_validated();
3671                        let data1: [u8; 16] = stack.pop_value().try_into().unwrap_validated();
3672                        let lanes2: [F64; 2] = to_lanes(data2);
3673                        let lanes1: [F64; 2] = to_lanes(data1);
3674                        let result: [F64; 2] = array::from_fn(|i| {
3675                            let v1 = lanes1[i];
3676                            let v2 = lanes2[i];
3677                            if v1 < v2 {
3678                                v2
3679                            } else {
3680                                v1
3681                            }
3682                        });
3683                        stack.push_value::<T>(Value::V128(from_lanes(result)))?;
3684                    }
3685                    // viminmaxop
3686                    I8X16_MIN_S => {
3687                        let data2: [u8; 16] = stack.pop_value().try_into().unwrap_validated();
3688                        let data1: [u8; 16] = stack.pop_value().try_into().unwrap_validated();
3689                        let lanes2: [i8; 16] = to_lanes(data2);
3690                        let lanes1: [i8; 16] = to_lanes(data1);
3691                        let result: [i8; 16] = array::from_fn(|i| lanes1[i].min(lanes2[i]));
3692                        stack.push_value::<T>(Value::V128(from_lanes(result)))?;
3693                    }
3694                    I16X8_MIN_S => {
3695                        let data2: [u8; 16] = stack.pop_value().try_into().unwrap_validated();
3696                        let data1: [u8; 16] = stack.pop_value().try_into().unwrap_validated();
3697                        let lanes2: [i16; 8] = to_lanes(data2);
3698                        let lanes1: [i16; 8] = to_lanes(data1);
3699                        let result: [i16; 8] = array::from_fn(|i| lanes1[i].min(lanes2[i]));
3700                        stack.push_value::<T>(Value::V128(from_lanes(result)))?;
3701                    }
3702                    I32X4_MIN_S => {
3703                        let data2: [u8; 16] = stack.pop_value().try_into().unwrap_validated();
3704                        let data1: [u8; 16] = stack.pop_value().try_into().unwrap_validated();
3705                        let lanes2: [i32; 4] = to_lanes(data2);
3706                        let lanes1: [i32; 4] = to_lanes(data1);
3707                        let result: [i32; 4] = array::from_fn(|i| lanes1[i].min(lanes2[i]));
3708                        stack.push_value::<T>(Value::V128(from_lanes(result)))?;
3709                    }
3710                    I8X16_MIN_U => {
3711                        let data2: [u8; 16] = stack.pop_value().try_into().unwrap_validated();
3712                        let data1: [u8; 16] = stack.pop_value().try_into().unwrap_validated();
3713                        let lanes2: [u8; 16] = to_lanes(data2);
3714                        let lanes1: [u8; 16] = to_lanes(data1);
3715                        let result: [u8; 16] = array::from_fn(|i| lanes1[i].min(lanes2[i]));
3716                        stack.push_value::<T>(Value::V128(from_lanes(result)))?;
3717                    }
3718                    I16X8_MIN_U => {
3719                        let data2: [u8; 16] = stack.pop_value().try_into().unwrap_validated();
3720                        let data1: [u8; 16] = stack.pop_value().try_into().unwrap_validated();
3721                        let lanes2: [u16; 8] = to_lanes(data2);
3722                        let lanes1: [u16; 8] = to_lanes(data1);
3723                        let result: [u16; 8] = array::from_fn(|i| lanes1[i].min(lanes2[i]));
3724                        stack.push_value::<T>(Value::V128(from_lanes(result)))?;
3725                    }
3726                    I32X4_MIN_U => {
3727                        let data2: [u8; 16] = stack.pop_value().try_into().unwrap_validated();
3728                        let data1: [u8; 16] = stack.pop_value().try_into().unwrap_validated();
3729                        let lanes2: [u32; 4] = to_lanes(data2);
3730                        let lanes1: [u32; 4] = to_lanes(data1);
3731                        let result: [u32; 4] = array::from_fn(|i| lanes1[i].min(lanes2[i]));
3732                        stack.push_value::<T>(Value::V128(from_lanes(result)))?;
3733                    }
3734                    I8X16_MAX_S => {
3735                        let data2: [u8; 16] = stack.pop_value().try_into().unwrap_validated();
3736                        let data1: [u8; 16] = stack.pop_value().try_into().unwrap_validated();
3737                        let lanes2: [i8; 16] = to_lanes(data2);
3738                        let lanes1: [i8; 16] = to_lanes(data1);
3739                        let result: [i8; 16] = array::from_fn(|i| lanes1[i].max(lanes2[i]));
3740                        stack.push_value::<T>(Value::V128(from_lanes(result)))?;
3741                    }
3742                    I16X8_MAX_S => {
3743                        let data2: [u8; 16] = stack.pop_value().try_into().unwrap_validated();
3744                        let data1: [u8; 16] = stack.pop_value().try_into().unwrap_validated();
3745                        let lanes2: [i16; 8] = to_lanes(data2);
3746                        let lanes1: [i16; 8] = to_lanes(data1);
3747                        let result: [i16; 8] = array::from_fn(|i| lanes1[i].max(lanes2[i]));
3748                        stack.push_value::<T>(Value::V128(from_lanes(result)))?;
3749                    }
3750                    I32X4_MAX_S => {
3751                        let data2: [u8; 16] = stack.pop_value().try_into().unwrap_validated();
3752                        let data1: [u8; 16] = stack.pop_value().try_into().unwrap_validated();
3753                        let lanes2: [i32; 4] = to_lanes(data2);
3754                        let lanes1: [i32; 4] = to_lanes(data1);
3755                        let result: [i32; 4] = array::from_fn(|i| lanes1[i].max(lanes2[i]));
3756                        stack.push_value::<T>(Value::V128(from_lanes(result)))?;
3757                    }
3758                    I8X16_MAX_U => {
3759                        let data2: [u8; 16] = stack.pop_value().try_into().unwrap_validated();
3760                        let data1: [u8; 16] = stack.pop_value().try_into().unwrap_validated();
3761                        let lanes2: [u8; 16] = to_lanes(data2);
3762                        let lanes1: [u8; 16] = to_lanes(data1);
3763                        let result: [u8; 16] = array::from_fn(|i| lanes1[i].max(lanes2[i]));
3764                        stack.push_value::<T>(Value::V128(from_lanes(result)))?;
3765                    }
3766                    I16X8_MAX_U => {
3767                        let data2: [u8; 16] = stack.pop_value().try_into().unwrap_validated();
3768                        let data1: [u8; 16] = stack.pop_value().try_into().unwrap_validated();
3769                        let lanes2: [u16; 8] = to_lanes(data2);
3770                        let lanes1: [u16; 8] = to_lanes(data1);
3771                        let result: [u16; 8] = array::from_fn(|i| lanes1[i].max(lanes2[i]));
3772                        stack.push_value::<T>(Value::V128(from_lanes(result)))?;
3773                    }
3774                    I32X4_MAX_U => {
3775                        let data2: [u8; 16] = stack.pop_value().try_into().unwrap_validated();
3776                        let data1: [u8; 16] = stack.pop_value().try_into().unwrap_validated();
3777                        let lanes2: [u32; 4] = to_lanes(data2);
3778                        let lanes1: [u32; 4] = to_lanes(data1);
3779                        let result: [u32; 4] = array::from_fn(|i| lanes1[i].max(lanes2[i]));
3780                        stack.push_value::<T>(Value::V128(from_lanes(result)))?;
3781                    }
3782
3783                    // visatbinop
3784                    I8X16_ADD_SAT_S => {
3785                        let data2: [u8; 16] = stack.pop_value().try_into().unwrap_validated();
3786                        let data1: [u8; 16] = stack.pop_value().try_into().unwrap_validated();
3787                        let lanes2: [i8; 16] = to_lanes(data2);
3788                        let lanes1: [i8; 16] = to_lanes(data1);
3789                        let result: [i8; 16] =
3790                            array::from_fn(|i| lanes1[i].saturating_add(lanes2[i]));
3791                        stack.push_value::<T>(Value::V128(from_lanes(result)))?;
3792                    }
3793                    I16X8_ADD_SAT_S => {
3794                        let data2: [u8; 16] = stack.pop_value().try_into().unwrap_validated();
3795                        let data1: [u8; 16] = stack.pop_value().try_into().unwrap_validated();
3796                        let lanes2: [i16; 8] = to_lanes(data2);
3797                        let lanes1: [i16; 8] = to_lanes(data1);
3798                        let result: [i16; 8] =
3799                            array::from_fn(|i| lanes1[i].saturating_add(lanes2[i]));
3800                        stack.push_value::<T>(Value::V128(from_lanes(result)))?;
3801                    }
3802                    I8X16_ADD_SAT_U => {
3803                        let data2: [u8; 16] = stack.pop_value().try_into().unwrap_validated();
3804                        let data1: [u8; 16] = stack.pop_value().try_into().unwrap_validated();
3805                        let lanes2: [u8; 16] = to_lanes(data2);
3806                        let lanes1: [u8; 16] = to_lanes(data1);
3807                        let result: [u8; 16] =
3808                            array::from_fn(|i| lanes1[i].saturating_add(lanes2[i]));
3809                        stack.push_value::<T>(Value::V128(from_lanes(result)))?;
3810                    }
3811                    I16X8_ADD_SAT_U => {
3812                        let data2: [u8; 16] = stack.pop_value().try_into().unwrap_validated();
3813                        let data1: [u8; 16] = stack.pop_value().try_into().unwrap_validated();
3814                        let lanes2: [u16; 8] = to_lanes(data2);
3815                        let lanes1: [u16; 8] = to_lanes(data1);
3816                        let result: [u16; 8] =
3817                            array::from_fn(|i| lanes1[i].saturating_add(lanes2[i]));
3818                        stack.push_value::<T>(Value::V128(from_lanes(result)))?;
3819                    }
3820                    I8X16_SUB_SAT_S => {
3821                        let data2: [u8; 16] = stack.pop_value().try_into().unwrap_validated();
3822                        let data1: [u8; 16] = stack.pop_value().try_into().unwrap_validated();
3823                        let lanes2: [i8; 16] = to_lanes(data2);
3824                        let lanes1: [i8; 16] = to_lanes(data1);
3825                        let result: [i8; 16] =
3826                            array::from_fn(|i| lanes1[i].saturating_sub(lanes2[i]));
3827                        stack.push_value::<T>(Value::V128(from_lanes(result)))?;
3828                    }
3829                    I16X8_SUB_SAT_S => {
3830                        let data2: [u8; 16] = stack.pop_value().try_into().unwrap_validated();
3831                        let data1: [u8; 16] = stack.pop_value().try_into().unwrap_validated();
3832                        let lanes2: [i16; 8] = to_lanes(data2);
3833                        let lanes1: [i16; 8] = to_lanes(data1);
3834                        let result: [i16; 8] =
3835                            array::from_fn(|i| lanes1[i].saturating_sub(lanes2[i]));
3836                        stack.push_value::<T>(Value::V128(from_lanes(result)))?;
3837                    }
3838                    I8X16_SUB_SAT_U => {
3839                        let data2: [u8; 16] = stack.pop_value().try_into().unwrap_validated();
3840                        let data1: [u8; 16] = stack.pop_value().try_into().unwrap_validated();
3841                        let lanes2: [u8; 16] = to_lanes(data2);
3842                        let lanes1: [u8; 16] = to_lanes(data1);
3843                        let result: [u8; 16] =
3844                            array::from_fn(|i| lanes1[i].saturating_sub(lanes2[i]));
3845                        stack.push_value::<T>(Value::V128(from_lanes(result)))?;
3846                    }
3847                    I16X8_SUB_SAT_U => {
3848                        let data2: [u8; 16] = stack.pop_value().try_into().unwrap_validated();
3849                        let data1: [u8; 16] = stack.pop_value().try_into().unwrap_validated();
3850                        let lanes2: [u16; 8] = to_lanes(data2);
3851                        let lanes1: [u16; 8] = to_lanes(data1);
3852                        let result: [u16; 8] =
3853                            array::from_fn(|i| lanes1[i].saturating_sub(lanes2[i]));
3854                        stack.push_value::<T>(Value::V128(from_lanes(result)))?;
3855                    }
3856                    // others
3857                    I16X8_MUL => {
3858                        let data2: [u8; 16] = stack.pop_value().try_into().unwrap_validated();
3859                        let data1: [u8; 16] = stack.pop_value().try_into().unwrap_validated();
3860                        let lanes2: [u16; 8] = to_lanes(data2);
3861                        let lanes1: [u16; 8] = to_lanes(data1);
3862                        let result: [u16; 8] =
3863                            array::from_fn(|i| lanes1[i].wrapping_mul(lanes2[i]));
3864                        stack.push_value::<T>(Value::V128(from_lanes(result)))?;
3865                    }
3866                    I32X4_MUL => {
3867                        let data2: [u8; 16] = stack.pop_value().try_into().unwrap_validated();
3868                        let data1: [u8; 16] = stack.pop_value().try_into().unwrap_validated();
3869                        let lanes2: [u32; 4] = to_lanes(data2);
3870                        let lanes1: [u32; 4] = to_lanes(data1);
3871                        let result: [u32; 4] =
3872                            array::from_fn(|i| lanes1[i].wrapping_mul(lanes2[i]));
3873                        stack.push_value::<T>(Value::V128(from_lanes(result)))?;
3874                    }
3875                    I64X2_MUL => {
3876                        let data2: [u8; 16] = stack.pop_value().try_into().unwrap_validated();
3877                        let data1: [u8; 16] = stack.pop_value().try_into().unwrap_validated();
3878                        let lanes2: [u64; 2] = to_lanes(data2);
3879                        let lanes1: [u64; 2] = to_lanes(data1);
3880                        let result: [u64; 2] =
3881                            array::from_fn(|i| lanes1[i].wrapping_mul(lanes2[i]));
3882                        stack.push_value::<T>(Value::V128(from_lanes(result)))?;
3883                    }
3884                    I8X16_AVGR_U => {
3885                        let data2: [u8; 16] = stack.pop_value().try_into().unwrap_validated();
3886                        let data1: [u8; 16] = stack.pop_value().try_into().unwrap_validated();
3887                        let lanes2: [u8; 16] = to_lanes(data2);
3888                        let lanes1: [u8; 16] = to_lanes(data1);
3889                        let result: [u8; 16] = array::from_fn(|i| {
3890                            (lanes1[i] as u16 + lanes2[i] as u16).div_ceil(2) as u8
3891                        });
3892                        stack.push_value::<T>(Value::V128(from_lanes(result)))?;
3893                    }
3894                    I16X8_AVGR_U => {
3895                        let data2: [u8; 16] = stack.pop_value().try_into().unwrap_validated();
3896                        let data1: [u8; 16] = stack.pop_value().try_into().unwrap_validated();
3897                        let lanes2: [u16; 8] = to_lanes(data2);
3898                        let lanes1: [u16; 8] = to_lanes(data1);
3899                        let result: [u16; 8] = array::from_fn(|i| {
3900                            (lanes1[i] as u32 + lanes2[i] as u32).div_ceil(2) as u16
3901                        });
3902                        stack.push_value::<T>(Value::V128(from_lanes(result)))?;
3903                    }
3904                    I16X8_Q15MULRSAT_S => {
3905                        let data2: [u8; 16] = stack.pop_value().try_into().unwrap_validated();
3906                        let data1: [u8; 16] = stack.pop_value().try_into().unwrap_validated();
3907                        let lanes2: [i16; 8] = to_lanes(data2);
3908                        let lanes1: [i16; 8] = to_lanes(data1);
3909                        let result: [i16; 8] = array::from_fn(|i| {
3910                            (((lanes1[i] as i64).mul(lanes2[i] as i64) + 2i64.pow(14)) >> 15i64)
3911                                .clamp(i16::MIN as i64, i16::MAX as i64)
3912                                as i16
3913                        });
3914                        stack.push_value::<T>(Value::V128(from_lanes(result)))?;
3915                    }
3916
3917                    // Group vrelop <https://webassembly.github.io/spec/core/syntax/instructions.html#syntax-vrelop>
3918                    // virelop
3919                    I8X16_EQ => {
3920                        let data2: [u8; 16] = stack.pop_value().try_into().unwrap_validated();
3921                        let data1: [u8; 16] = stack.pop_value().try_into().unwrap_validated();
3922                        let lanes2: [u8; 16] = to_lanes(data2);
3923                        let lanes1: [u8; 16] = to_lanes(data1);
3924                        let result: [i8; 16] =
3925                            array::from_fn(|i| ((lanes1[i] == lanes2[i]) as i8).neg());
3926                        stack.push_value::<T>(Value::V128(from_lanes(result)))?;
3927                    }
3928                    I16X8_EQ => {
3929                        let data2: [u8; 16] = stack.pop_value().try_into().unwrap_validated();
3930                        let data1: [u8; 16] = stack.pop_value().try_into().unwrap_validated();
3931                        let lanes2: [u16; 8] = to_lanes(data2);
3932                        let lanes1: [u16; 8] = to_lanes(data1);
3933                        let result: [i16; 8] =
3934                            array::from_fn(|i| ((lanes1[i] == lanes2[i]) as i16).neg());
3935                        stack.push_value::<T>(Value::V128(from_lanes(result)))?;
3936                    }
3937                    I32X4_EQ => {
3938                        let data2: [u8; 16] = stack.pop_value().try_into().unwrap_validated();
3939                        let data1: [u8; 16] = stack.pop_value().try_into().unwrap_validated();
3940                        let lanes2: [u32; 4] = to_lanes(data2);
3941                        let lanes1: [u32; 4] = to_lanes(data1);
3942                        let result: [i32; 4] =
3943                            array::from_fn(|i| ((lanes1[i] == lanes2[i]) as i32).neg());
3944                        stack.push_value::<T>(Value::V128(from_lanes(result)))?;
3945                    }
3946                    I64X2_EQ => {
3947                        let data2: [u8; 16] = stack.pop_value().try_into().unwrap_validated();
3948                        let data1: [u8; 16] = stack.pop_value().try_into().unwrap_validated();
3949                        let lanes2: [u64; 2] = to_lanes(data2);
3950                        let lanes1: [u64; 2] = to_lanes(data1);
3951                        let result: [i64; 2] =
3952                            array::from_fn(|i| ((lanes1[i] == lanes2[i]) as i64).neg());
3953                        stack.push_value::<T>(Value::V128(from_lanes(result)))?;
3954                    }
3955                    I8X16_NE => {
3956                        let data2: [u8; 16] = stack.pop_value().try_into().unwrap_validated();
3957                        let data1: [u8; 16] = stack.pop_value().try_into().unwrap_validated();
3958                        let lanes2: [u8; 16] = to_lanes(data2);
3959                        let lanes1: [u8; 16] = to_lanes(data1);
3960                        let result: [i8; 16] =
3961                            array::from_fn(|i| ((lanes1[i] != lanes2[i]) as i8).neg());
3962                        stack.push_value::<T>(Value::V128(from_lanes(result)))?;
3963                    }
3964                    I16X8_NE => {
3965                        let data2: [u8; 16] = stack.pop_value().try_into().unwrap_validated();
3966                        let data1: [u8; 16] = stack.pop_value().try_into().unwrap_validated();
3967                        let lanes2: [u16; 8] = to_lanes(data2);
3968                        let lanes1: [u16; 8] = to_lanes(data1);
3969                        let result: [i16; 8] =
3970                            array::from_fn(|i| ((lanes1[i] != lanes2[i]) as i16).neg());
3971                        stack.push_value::<T>(Value::V128(from_lanes(result)))?;
3972                    }
3973                    I32X4_NE => {
3974                        let data2: [u8; 16] = stack.pop_value().try_into().unwrap_validated();
3975                        let data1: [u8; 16] = stack.pop_value().try_into().unwrap_validated();
3976                        let lanes2: [u32; 4] = to_lanes(data2);
3977                        let lanes1: [u32; 4] = to_lanes(data1);
3978                        let result: [i32; 4] =
3979                            array::from_fn(|i| ((lanes1[i] != lanes2[i]) as i32).neg());
3980                        stack.push_value::<T>(Value::V128(from_lanes(result)))?;
3981                    }
3982                    I64X2_NE => {
3983                        let data2: [u8; 16] = stack.pop_value().try_into().unwrap_validated();
3984                        let data1: [u8; 16] = stack.pop_value().try_into().unwrap_validated();
3985                        let lanes2: [u64; 2] = to_lanes(data2);
3986                        let lanes1: [u64; 2] = to_lanes(data1);
3987                        let result: [i64; 2] =
3988                            array::from_fn(|i| ((lanes1[i] != lanes2[i]) as i64).neg());
3989                        stack.push_value::<T>(Value::V128(from_lanes(result)))?;
3990                    }
3991                    I8X16_LT_S => {
3992                        let data2: [u8; 16] = stack.pop_value().try_into().unwrap_validated();
3993                        let data1: [u8; 16] = stack.pop_value().try_into().unwrap_validated();
3994                        let lanes2: [i8; 16] = to_lanes(data2);
3995                        let lanes1: [i8; 16] = to_lanes(data1);
3996                        let result: [i8; 16] =
3997                            array::from_fn(|i| ((lanes1[i] < lanes2[i]) as i8).neg());
3998                        stack.push_value::<T>(Value::V128(from_lanes(result)))?;
3999                    }
4000                    I16X8_LT_S => {
4001                        let data2: [u8; 16] = stack.pop_value().try_into().unwrap_validated();
4002                        let data1: [u8; 16] = stack.pop_value().try_into().unwrap_validated();
4003                        let lanes2: [i16; 8] = to_lanes(data2);
4004                        let lanes1: [i16; 8] = to_lanes(data1);
4005                        let result: [i16; 8] =
4006                            array::from_fn(|i| ((lanes1[i] < lanes2[i]) as i16).neg());
4007                        stack.push_value::<T>(Value::V128(from_lanes(result)))?;
4008                    }
4009                    I32X4_LT_S => {
4010                        let data2: [u8; 16] = stack.pop_value().try_into().unwrap_validated();
4011                        let data1: [u8; 16] = stack.pop_value().try_into().unwrap_validated();
4012                        let lanes2: [i32; 4] = to_lanes(data2);
4013                        let lanes1: [i32; 4] = to_lanes(data1);
4014                        let result: [i32; 4] =
4015                            array::from_fn(|i| ((lanes1[i] < lanes2[i]) as i32).neg());
4016                        stack.push_value::<T>(Value::V128(from_lanes(result)))?;
4017                    }
4018                    I64X2_LT_S => {
4019                        let data2: [u8; 16] = stack.pop_value().try_into().unwrap_validated();
4020                        let data1: [u8; 16] = stack.pop_value().try_into().unwrap_validated();
4021                        let lanes2: [i64; 2] = to_lanes(data2);
4022                        let lanes1: [i64; 2] = to_lanes(data1);
4023                        let result: [i64; 2] =
4024                            array::from_fn(|i| ((lanes1[i] < lanes2[i]) as i64).neg());
4025                        stack.push_value::<T>(Value::V128(from_lanes(result)))?;
4026                    }
4027                    I8X16_LT_U => {
4028                        let data2: [u8; 16] = stack.pop_value().try_into().unwrap_validated();
4029                        let data1: [u8; 16] = stack.pop_value().try_into().unwrap_validated();
4030                        let lanes2: [u8; 16] = to_lanes(data2);
4031                        let lanes1: [u8; 16] = to_lanes(data1);
4032                        let result: [i8; 16] =
4033                            array::from_fn(|i| ((lanes1[i] < lanes2[i]) as i8).neg());
4034                        stack.push_value::<T>(Value::V128(from_lanes(result)))?;
4035                    }
4036                    I16X8_LT_U => {
4037                        let data2: [u8; 16] = stack.pop_value().try_into().unwrap_validated();
4038                        let data1: [u8; 16] = stack.pop_value().try_into().unwrap_validated();
4039                        let lanes2: [u16; 8] = to_lanes(data2);
4040                        let lanes1: [u16; 8] = to_lanes(data1);
4041                        let result: [i16; 8] =
4042                            array::from_fn(|i| ((lanes1[i] < lanes2[i]) as i16).neg());
4043                        stack.push_value::<T>(Value::V128(from_lanes(result)))?;
4044                    }
4045                    I32X4_LT_U => {
4046                        let data2: [u8; 16] = stack.pop_value().try_into().unwrap_validated();
4047                        let data1: [u8; 16] = stack.pop_value().try_into().unwrap_validated();
4048                        let lanes2: [u32; 4] = to_lanes(data2);
4049                        let lanes1: [u32; 4] = to_lanes(data1);
4050                        let result: [i32; 4] =
4051                            array::from_fn(|i| ((lanes1[i] < lanes2[i]) as i32).neg());
4052                        stack.push_value::<T>(Value::V128(from_lanes(result)))?;
4053                    }
4054                    I8X16_GT_S => {
4055                        let data2: [u8; 16] = stack.pop_value().try_into().unwrap_validated();
4056                        let data1: [u8; 16] = stack.pop_value().try_into().unwrap_validated();
4057                        let lanes2: [i8; 16] = to_lanes(data2);
4058                        let lanes1: [i8; 16] = to_lanes(data1);
4059                        let result: [i8; 16] =
4060                            array::from_fn(|i| ((lanes1[i] > lanes2[i]) as i8).neg());
4061                        stack.push_value::<T>(Value::V128(from_lanes(result)))?;
4062                    }
4063                    I16X8_GT_S => {
4064                        let data2: [u8; 16] = stack.pop_value().try_into().unwrap_validated();
4065                        let data1: [u8; 16] = stack.pop_value().try_into().unwrap_validated();
4066                        let lanes2: [i16; 8] = to_lanes(data2);
4067                        let lanes1: [i16; 8] = to_lanes(data1);
4068                        let result: [i16; 8] =
4069                            array::from_fn(|i| ((lanes1[i] > lanes2[i]) as i16).neg());
4070                        stack.push_value::<T>(Value::V128(from_lanes(result)))?;
4071                    }
4072                    I32X4_GT_S => {
4073                        let data2: [u8; 16] = stack.pop_value().try_into().unwrap_validated();
4074                        let data1: [u8; 16] = stack.pop_value().try_into().unwrap_validated();
4075                        let lanes2: [i32; 4] = to_lanes(data2);
4076                        let lanes1: [i32; 4] = to_lanes(data1);
4077                        let result: [i32; 4] =
4078                            array::from_fn(|i| ((lanes1[i] > lanes2[i]) as i32).neg());
4079                        stack.push_value::<T>(Value::V128(from_lanes(result)))?;
4080                    }
4081                    I64X2_GT_S => {
4082                        let data2: [u8; 16] = stack.pop_value().try_into().unwrap_validated();
4083                        let data1: [u8; 16] = stack.pop_value().try_into().unwrap_validated();
4084                        let lanes2: [i64; 2] = to_lanes(data2);
4085                        let lanes1: [i64; 2] = to_lanes(data1);
4086                        let result: [i64; 2] =
4087                            array::from_fn(|i| ((lanes1[i] > lanes2[i]) as i64).neg());
4088                        stack.push_value::<T>(Value::V128(from_lanes(result)))?;
4089                    }
4090                    I8X16_GT_U => {
4091                        let data2: [u8; 16] = stack.pop_value().try_into().unwrap_validated();
4092                        let data1: [u8; 16] = stack.pop_value().try_into().unwrap_validated();
4093                        let lanes2: [u8; 16] = to_lanes(data2);
4094                        let lanes1: [u8; 16] = to_lanes(data1);
4095                        let result: [i8; 16] =
4096                            array::from_fn(|i| ((lanes1[i] > lanes2[i]) as i8).neg());
4097                        stack.push_value::<T>(Value::V128(from_lanes(result)))?;
4098                    }
4099                    I16X8_GT_U => {
4100                        let data2: [u8; 16] = stack.pop_value().try_into().unwrap_validated();
4101                        let data1: [u8; 16] = stack.pop_value().try_into().unwrap_validated();
4102                        let lanes2: [u16; 8] = to_lanes(data2);
4103                        let lanes1: [u16; 8] = to_lanes(data1);
4104                        let result: [i16; 8] =
4105                            array::from_fn(|i| ((lanes1[i] > lanes2[i]) as i16).neg());
4106                        stack.push_value::<T>(Value::V128(from_lanes(result)))?;
4107                    }
4108                    I32X4_GT_U => {
4109                        let data2: [u8; 16] = stack.pop_value().try_into().unwrap_validated();
4110                        let data1: [u8; 16] = stack.pop_value().try_into().unwrap_validated();
4111                        let lanes2: [u32; 4] = to_lanes(data2);
4112                        let lanes1: [u32; 4] = to_lanes(data1);
4113                        let result: [i32; 4] =
4114                            array::from_fn(|i| ((lanes1[i] > lanes2[i]) as i32).neg());
4115                        stack.push_value::<T>(Value::V128(from_lanes(result)))?;
4116                    }
4117                    I8X16_LE_S => {
4118                        let data2: [u8; 16] = stack.pop_value().try_into().unwrap_validated();
4119                        let data1: [u8; 16] = stack.pop_value().try_into().unwrap_validated();
4120                        let lanes2: [i8; 16] = to_lanes(data2);
4121                        let lanes1: [i8; 16] = to_lanes(data1);
4122                        let result: [i8; 16] =
4123                            array::from_fn(|i| ((lanes1[i] <= lanes2[i]) as i8).neg());
4124                        stack.push_value::<T>(Value::V128(from_lanes(result)))?;
4125                    }
4126                    I16X8_LE_S => {
4127                        let data2: [u8; 16] = stack.pop_value().try_into().unwrap_validated();
4128                        let data1: [u8; 16] = stack.pop_value().try_into().unwrap_validated();
4129                        let lanes2: [i16; 8] = to_lanes(data2);
4130                        let lanes1: [i16; 8] = to_lanes(data1);
4131                        let result: [i16; 8] =
4132                            array::from_fn(|i| ((lanes1[i] <= lanes2[i]) as i16).neg());
4133                        stack.push_value::<T>(Value::V128(from_lanes(result)))?;
4134                    }
4135                    I32X4_LE_S => {
4136                        let data2: [u8; 16] = stack.pop_value().try_into().unwrap_validated();
4137                        let data1: [u8; 16] = stack.pop_value().try_into().unwrap_validated();
4138                        let lanes2: [i32; 4] = to_lanes(data2);
4139                        let lanes1: [i32; 4] = to_lanes(data1);
4140                        let result: [i32; 4] =
4141                            array::from_fn(|i| ((lanes1[i] <= lanes2[i]) as i32).neg());
4142                        stack.push_value::<T>(Value::V128(from_lanes(result)))?;
4143                    }
4144                    I64X2_LE_S => {
4145                        let data2: [u8; 16] = stack.pop_value().try_into().unwrap_validated();
4146                        let data1: [u8; 16] = stack.pop_value().try_into().unwrap_validated();
4147                        let lanes2: [i64; 2] = to_lanes(data2);
4148                        let lanes1: [i64; 2] = to_lanes(data1);
4149                        let result: [i64; 2] =
4150                            array::from_fn(|i| ((lanes1[i] <= lanes2[i]) as i64).neg());
4151                        stack.push_value::<T>(Value::V128(from_lanes(result)))?;
4152                    }
4153                    I8X16_LE_U => {
4154                        let data2: [u8; 16] = stack.pop_value().try_into().unwrap_validated();
4155                        let data1: [u8; 16] = stack.pop_value().try_into().unwrap_validated();
4156                        let lanes2: [u8; 16] = to_lanes(data2);
4157                        let lanes1: [u8; 16] = to_lanes(data1);
4158                        let result: [i8; 16] =
4159                            array::from_fn(|i| ((lanes1[i] <= lanes2[i]) as i8).neg());
4160                        stack.push_value::<T>(Value::V128(from_lanes(result)))?;
4161                    }
4162                    I16X8_LE_U => {
4163                        let data2: [u8; 16] = stack.pop_value().try_into().unwrap_validated();
4164                        let data1: [u8; 16] = stack.pop_value().try_into().unwrap_validated();
4165                        let lanes2: [u16; 8] = to_lanes(data2);
4166                        let lanes1: [u16; 8] = to_lanes(data1);
4167                        let result: [i16; 8] =
4168                            array::from_fn(|i| ((lanes1[i] <= lanes2[i]) as i16).neg());
4169                        stack.push_value::<T>(Value::V128(from_lanes(result)))?;
4170                    }
4171                    I32X4_LE_U => {
4172                        let data2: [u8; 16] = stack.pop_value().try_into().unwrap_validated();
4173                        let data1: [u8; 16] = stack.pop_value().try_into().unwrap_validated();
4174                        let lanes2: [u32; 4] = to_lanes(data2);
4175                        let lanes1: [u32; 4] = to_lanes(data1);
4176                        let result: [i32; 4] =
4177                            array::from_fn(|i| ((lanes1[i] <= lanes2[i]) as i32).neg());
4178                        stack.push_value::<T>(Value::V128(from_lanes(result)))?;
4179                    }
4180
4181                    I8X16_GE_S => {
4182                        let data2: [u8; 16] = stack.pop_value().try_into().unwrap_validated();
4183                        let data1: [u8; 16] = stack.pop_value().try_into().unwrap_validated();
4184                        let lanes2: [i8; 16] = to_lanes(data2);
4185                        let lanes1: [i8; 16] = to_lanes(data1);
4186                        let result: [i8; 16] =
4187                            array::from_fn(|i| ((lanes1[i] >= lanes2[i]) as i8).neg());
4188                        stack.push_value::<T>(Value::V128(from_lanes(result)))?;
4189                    }
4190                    I16X8_GE_S => {
4191                        let data2: [u8; 16] = stack.pop_value().try_into().unwrap_validated();
4192                        let data1: [u8; 16] = stack.pop_value().try_into().unwrap_validated();
4193                        let lanes2: [i16; 8] = to_lanes(data2);
4194                        let lanes1: [i16; 8] = to_lanes(data1);
4195                        let result: [i16; 8] =
4196                            array::from_fn(|i| ((lanes1[i] >= lanes2[i]) as i16).neg());
4197                        stack.push_value::<T>(Value::V128(from_lanes(result)))?;
4198                    }
4199                    I32X4_GE_S => {
4200                        let data2: [u8; 16] = stack.pop_value().try_into().unwrap_validated();
4201                        let data1: [u8; 16] = stack.pop_value().try_into().unwrap_validated();
4202                        let lanes2: [i32; 4] = to_lanes(data2);
4203                        let lanes1: [i32; 4] = to_lanes(data1);
4204                        let result: [i32; 4] =
4205                            array::from_fn(|i| ((lanes1[i] >= lanes2[i]) as i32).neg());
4206                        stack.push_value::<T>(Value::V128(from_lanes(result)))?;
4207                    }
4208                    I64X2_GE_S => {
4209                        let data2: [u8; 16] = stack.pop_value().try_into().unwrap_validated();
4210                        let data1: [u8; 16] = stack.pop_value().try_into().unwrap_validated();
4211                        let lanes2: [i64; 2] = to_lanes(data2);
4212                        let lanes1: [i64; 2] = to_lanes(data1);
4213                        let result: [i64; 2] =
4214                            array::from_fn(|i| ((lanes1[i] >= lanes2[i]) as i64).neg());
4215                        stack.push_value::<T>(Value::V128(from_lanes(result)))?;
4216                    }
4217                    I8X16_GE_U => {
4218                        let data2: [u8; 16] = stack.pop_value().try_into().unwrap_validated();
4219                        let data1: [u8; 16] = stack.pop_value().try_into().unwrap_validated();
4220                        let lanes2: [u8; 16] = to_lanes(data2);
4221                        let lanes1: [u8; 16] = to_lanes(data1);
4222                        let result: [i8; 16] =
4223                            array::from_fn(|i| ((lanes1[i] >= lanes2[i]) as i8).neg());
4224                        stack.push_value::<T>(Value::V128(from_lanes(result)))?;
4225                    }
4226                    I16X8_GE_U => {
4227                        let data2: [u8; 16] = stack.pop_value().try_into().unwrap_validated();
4228                        let data1: [u8; 16] = stack.pop_value().try_into().unwrap_validated();
4229                        let lanes2: [u16; 8] = to_lanes(data2);
4230                        let lanes1: [u16; 8] = to_lanes(data1);
4231                        let result: [i16; 8] =
4232                            array::from_fn(|i| ((lanes1[i] >= lanes2[i]) as i16).neg());
4233                        stack.push_value::<T>(Value::V128(from_lanes(result)))?;
4234                    }
4235                    I32X4_GE_U => {
4236                        let data2: [u8; 16] = stack.pop_value().try_into().unwrap_validated();
4237                        let data1: [u8; 16] = stack.pop_value().try_into().unwrap_validated();
4238                        let lanes2: [u32; 4] = to_lanes(data2);
4239                        let lanes1: [u32; 4] = to_lanes(data1);
4240                        let result: [i32; 4] =
4241                            array::from_fn(|i| ((lanes1[i] >= lanes2[i]) as i32).neg());
4242                        stack.push_value::<T>(Value::V128(from_lanes(result)))?;
4243                    }
4244                    // vfrelop
4245                    F32X4_EQ => {
4246                        let data2: [u8; 16] = stack.pop_value().try_into().unwrap_validated();
4247                        let data1: [u8; 16] = stack.pop_value().try_into().unwrap_validated();
4248                        let lanes2: [F32; 4] = to_lanes(data2);
4249                        let lanes1: [F32; 4] = to_lanes(data1);
4250                        let result: [i32; 4] =
4251                            array::from_fn(|i| ((lanes1[i] == lanes2[i]) as i32).neg());
4252                        stack.push_value::<T>(Value::V128(from_lanes(result)))?;
4253                    }
4254                    F64X2_EQ => {
4255                        let data2: [u8; 16] = stack.pop_value().try_into().unwrap_validated();
4256                        let data1: [u8; 16] = stack.pop_value().try_into().unwrap_validated();
4257                        let lanes2: [F64; 2] = to_lanes(data2);
4258                        let lanes1: [F64; 2] = to_lanes(data1);
4259                        let result: [i64; 2] =
4260                            array::from_fn(|i| ((lanes1[i] == lanes2[i]) as i64).neg());
4261                        stack.push_value::<T>(Value::V128(from_lanes(result)))?;
4262                    }
4263                    F32X4_NE => {
4264                        let data2: [u8; 16] = stack.pop_value().try_into().unwrap_validated();
4265                        let data1: [u8; 16] = stack.pop_value().try_into().unwrap_validated();
4266                        let lanes2: [F32; 4] = to_lanes(data2);
4267                        let lanes1: [F32; 4] = to_lanes(data1);
4268                        let result: [i32; 4] =
4269                            array::from_fn(|i| ((lanes1[i] != lanes2[i]) as i32).neg());
4270                        stack.push_value::<T>(Value::V128(from_lanes(result)))?;
4271                    }
4272                    F64X2_NE => {
4273                        let data2: [u8; 16] = stack.pop_value().try_into().unwrap_validated();
4274                        let data1: [u8; 16] = stack.pop_value().try_into().unwrap_validated();
4275                        let lanes2: [F64; 2] = to_lanes(data2);
4276                        let lanes1: [F64; 2] = to_lanes(data1);
4277                        let result: [i64; 2] =
4278                            array::from_fn(|i| ((lanes1[i] != lanes2[i]) as i64).neg());
4279                        stack.push_value::<T>(Value::V128(from_lanes(result)))?;
4280                    }
4281                    F32X4_LT => {
4282                        let data2: [u8; 16] = stack.pop_value().try_into().unwrap_validated();
4283                        let data1: [u8; 16] = stack.pop_value().try_into().unwrap_validated();
4284                        let lanes2: [F32; 4] = to_lanes(data2);
4285                        let lanes1: [F32; 4] = to_lanes(data1);
4286                        let result: [i32; 4] =
4287                            array::from_fn(|i| ((lanes1[i] < lanes2[i]) as i32).neg());
4288                        stack.push_value::<T>(Value::V128(from_lanes(result)))?;
4289                    }
4290                    F64X2_LT => {
4291                        let data2: [u8; 16] = stack.pop_value().try_into().unwrap_validated();
4292                        let data1: [u8; 16] = stack.pop_value().try_into().unwrap_validated();
4293                        let lanes2: [F64; 2] = to_lanes(data2);
4294                        let lanes1: [F64; 2] = to_lanes(data1);
4295                        let result: [i64; 2] =
4296                            array::from_fn(|i| ((lanes1[i] < lanes2[i]) as i64).neg());
4297                        stack.push_value::<T>(Value::V128(from_lanes(result)))?;
4298                    }
4299                    F32X4_GT => {
4300                        let data2: [u8; 16] = stack.pop_value().try_into().unwrap_validated();
4301                        let data1: [u8; 16] = stack.pop_value().try_into().unwrap_validated();
4302                        let lanes2: [F32; 4] = to_lanes(data2);
4303                        let lanes1: [F32; 4] = to_lanes(data1);
4304                        let result: [i32; 4] =
4305                            array::from_fn(|i| ((lanes1[i] > lanes2[i]) as i32).neg());
4306                        stack.push_value::<T>(Value::V128(from_lanes(result)))?;
4307                    }
4308                    F64X2_GT => {
4309                        let data2: [u8; 16] = stack.pop_value().try_into().unwrap_validated();
4310                        let data1: [u8; 16] = stack.pop_value().try_into().unwrap_validated();
4311                        let lanes2: [F64; 2] = to_lanes(data2);
4312                        let lanes1: [F64; 2] = to_lanes(data1);
4313                        let result: [i64; 2] =
4314                            array::from_fn(|i| ((lanes1[i] > lanes2[i]) as i64).neg());
4315                        stack.push_value::<T>(Value::V128(from_lanes(result)))?;
4316                    }
4317                    F32X4_LE => {
4318                        let data2: [u8; 16] = stack.pop_value().try_into().unwrap_validated();
4319                        let data1: [u8; 16] = stack.pop_value().try_into().unwrap_validated();
4320                        let lanes2: [F32; 4] = to_lanes(data2);
4321                        let lanes1: [F32; 4] = to_lanes(data1);
4322                        let result: [i32; 4] =
4323                            array::from_fn(|i| ((lanes1[i] <= lanes2[i]) as i32).neg());
4324                        stack.push_value::<T>(Value::V128(from_lanes(result)))?;
4325                    }
4326                    F64X2_LE => {
4327                        let data2: [u8; 16] = stack.pop_value().try_into().unwrap_validated();
4328                        let data1: [u8; 16] = stack.pop_value().try_into().unwrap_validated();
4329                        let lanes2: [F64; 2] = to_lanes(data2);
4330                        let lanes1: [F64; 2] = to_lanes(data1);
4331                        let result: [i64; 2] =
4332                            array::from_fn(|i| ((lanes1[i] <= lanes2[i]) as i64).neg());
4333                        stack.push_value::<T>(Value::V128(from_lanes(result)))?;
4334                    }
4335                    F32X4_GE => {
4336                        let data2: [u8; 16] = stack.pop_value().try_into().unwrap_validated();
4337                        let data1: [u8; 16] = stack.pop_value().try_into().unwrap_validated();
4338                        let lanes2: [F32; 4] = to_lanes(data2);
4339                        let lanes1: [F32; 4] = to_lanes(data1);
4340                        let result: [i32; 4] =
4341                            array::from_fn(|i| ((lanes1[i] >= lanes2[i]) as i32).neg());
4342                        stack.push_value::<T>(Value::V128(from_lanes(result)))?;
4343                    }
4344                    F64X2_GE => {
4345                        let data2: [u8; 16] = stack.pop_value().try_into().unwrap_validated();
4346                        let data1: [u8; 16] = stack.pop_value().try_into().unwrap_validated();
4347                        let lanes2: [F64; 2] = to_lanes(data2);
4348                        let lanes1: [F64; 2] = to_lanes(data1);
4349                        let result: [i64; 2] =
4350                            array::from_fn(|i| ((lanes1[i] >= lanes2[i]) as i64).neg());
4351                        stack.push_value::<T>(Value::V128(from_lanes(result)))?;
4352                    }
4353
4354                    // Group vishiftop
4355                    I8X16_SHL => {
4356                        let shift: u32 = stack.pop_value().try_into().unwrap_validated();
4357                        let data: [u8; 16] = stack.pop_value().try_into().unwrap_validated();
4358                        let lanes: [u8; 16] = to_lanes(data);
4359                        let result: [u8; 16] = lanes.map(|lane| lane.wrapping_shl(shift));
4360                        stack.push_value::<T>(Value::V128(from_lanes(result)))?;
4361                    }
4362                    I16X8_SHL => {
4363                        let shift: u32 = stack.pop_value().try_into().unwrap_validated();
4364                        let data: [u8; 16] = stack.pop_value().try_into().unwrap_validated();
4365                        let lanes: [u16; 8] = to_lanes(data);
4366                        let result: [u16; 8] = lanes.map(|lane| lane.wrapping_shl(shift));
4367                        stack.push_value::<T>(Value::V128(from_lanes(result)))?;
4368                    }
4369                    I32X4_SHL => {
4370                        let shift: u32 = stack.pop_value().try_into().unwrap_validated();
4371                        let data: [u8; 16] = stack.pop_value().try_into().unwrap_validated();
4372                        let lanes: [u32; 4] = to_lanes(data);
4373                        let result: [u32; 4] = lanes.map(|lane| lane.wrapping_shl(shift));
4374                        stack.push_value::<T>(Value::V128(from_lanes(result)))?;
4375                    }
4376                    I64X2_SHL => {
4377                        let shift: u32 = stack.pop_value().try_into().unwrap_validated();
4378                        let data: [u8; 16] = stack.pop_value().try_into().unwrap_validated();
4379                        let lanes: [u64; 2] = to_lanes(data);
4380                        let result: [u64; 2] = lanes.map(|lane| lane.wrapping_shl(shift));
4381                        stack.push_value::<T>(Value::V128(from_lanes(result)))?;
4382                    }
4383                    I8X16_SHR_S => {
4384                        let shift: u32 = stack.pop_value().try_into().unwrap_validated();
4385                        let data: [u8; 16] = stack.pop_value().try_into().unwrap_validated();
4386                        let lanes: [i8; 16] = to_lanes(data);
4387                        let result: [i8; 16] = lanes.map(|lane| lane.wrapping_shr(shift));
4388                        stack.push_value::<T>(Value::V128(from_lanes(result)))?;
4389                    }
4390                    I8X16_SHR_U => {
4391                        let shift: u32 = stack.pop_value().try_into().unwrap_validated();
4392                        let data: [u8; 16] = stack.pop_value().try_into().unwrap_validated();
4393                        let lanes: [u8; 16] = to_lanes(data);
4394                        let result: [u8; 16] = lanes.map(|lane| lane.wrapping_shr(shift));
4395                        stack.push_value::<T>(Value::V128(from_lanes(result)))?;
4396                    }
4397                    I16X8_SHR_S => {
4398                        let shift: u32 = stack.pop_value().try_into().unwrap_validated();
4399                        let data: [u8; 16] = stack.pop_value().try_into().unwrap_validated();
4400                        let lanes: [i16; 8] = to_lanes(data);
4401                        let result: [i16; 8] = lanes.map(|lane| lane.wrapping_shr(shift));
4402                        stack.push_value::<T>(Value::V128(from_lanes(result)))?;
4403                    }
4404                    I16X8_SHR_U => {
4405                        let shift: u32 = stack.pop_value().try_into().unwrap_validated();
4406                        let data: [u8; 16] = stack.pop_value().try_into().unwrap_validated();
4407                        let lanes: [u16; 8] = to_lanes(data);
4408                        let result: [u16; 8] = lanes.map(|lane| lane.wrapping_shr(shift));
4409                        stack.push_value::<T>(Value::V128(from_lanes(result)))?;
4410                    }
4411                    I32X4_SHR_S => {
4412                        let shift: u32 = stack.pop_value().try_into().unwrap_validated();
4413                        let data: [u8; 16] = stack.pop_value().try_into().unwrap_validated();
4414                        let lanes: [i32; 4] = to_lanes(data);
4415                        let result: [i32; 4] = lanes.map(|lane| lane.wrapping_shr(shift));
4416                        stack.push_value::<T>(Value::V128(from_lanes(result)))?;
4417                    }
4418                    I32X4_SHR_U => {
4419                        let shift: u32 = stack.pop_value().try_into().unwrap_validated();
4420                        let data: [u8; 16] = stack.pop_value().try_into().unwrap_validated();
4421                        let lanes: [u32; 4] = to_lanes(data);
4422                        let result: [u32; 4] = lanes.map(|lane| lane.wrapping_shr(shift));
4423                        stack.push_value::<T>(Value::V128(from_lanes(result)))?;
4424                    }
4425                    I64X2_SHR_S => {
4426                        let shift: u32 = stack.pop_value().try_into().unwrap_validated();
4427                        let data: [u8; 16] = stack.pop_value().try_into().unwrap_validated();
4428                        let lanes: [i64; 2] = to_lanes(data);
4429                        let result: [i64; 2] = lanes.map(|lane| lane.wrapping_shr(shift));
4430                        stack.push_value::<T>(Value::V128(from_lanes(result)))?;
4431                    }
4432                    I64X2_SHR_U => {
4433                        let shift: u32 = stack.pop_value().try_into().unwrap_validated();
4434                        let data: [u8; 16] = stack.pop_value().try_into().unwrap_validated();
4435                        let lanes: [u64; 2] = to_lanes(data);
4436                        let result: [u64; 2] = lanes.map(|lane| lane.wrapping_shr(shift));
4437                        stack.push_value::<T>(Value::V128(from_lanes(result)))?;
4438                    }
4439
4440                    // Group vtestop <https://webassembly.github.io/spec/core/syntax/instructions.html#syntax-vtestop>
4441                    // vitestop
4442                    I8X16_ALL_TRUE => {
4443                        let data: [u8; 16] = stack.pop_value().try_into().unwrap_validated();
4444                        let lanes: [u8; 16] = to_lanes(data);
4445                        let all_true = lanes.into_iter().all(|lane| lane != 0);
4446                        stack.push_value::<T>(Value::I32(all_true as u32))?;
4447                    }
4448                    I16X8_ALL_TRUE => {
4449                        let data: [u8; 16] = stack.pop_value().try_into().unwrap_validated();
4450                        let lanes: [u16; 8] = to_lanes(data);
4451                        let all_true = lanes.into_iter().all(|lane| lane != 0);
4452                        stack.push_value::<T>(Value::I32(all_true as u32))?;
4453                    }
4454                    I32X4_ALL_TRUE => {
4455                        let data: [u8; 16] = stack.pop_value().try_into().unwrap_validated();
4456                        let lanes: [u32; 4] = to_lanes(data);
4457                        let all_true = lanes.into_iter().all(|lane| lane != 0);
4458                        stack.push_value::<T>(Value::I32(all_true as u32))?;
4459                    }
4460                    I64X2_ALL_TRUE => {
4461                        let data: [u8; 16] = stack.pop_value().try_into().unwrap_validated();
4462                        let lanes: [u64; 2] = to_lanes(data);
4463                        let all_true = lanes.into_iter().all(|lane| lane != 0);
4464                        stack.push_value::<T>(Value::I32(all_true as u32))?;
4465                    }
4466
4467                    // Group vcvtop <https://webassembly.github.io/spec/core/syntax/instructions.html#syntax-vcvtop>
4468                    I16X8_EXTEND_HIGH_I8X16_S => {
4469                        let data: [u8; 16] = stack.pop_value().try_into().unwrap_validated();
4470                        let lanes: [i8; 16] = to_lanes(data);
4471                        let high_lanes: [i8; 8] = lanes[8..].try_into().unwrap();
4472                        let result = high_lanes.map(|lane| lane as i16);
4473                        stack.push_value::<T>(Value::V128(from_lanes(result)))?;
4474                    }
4475                    I16X8_EXTEND_HIGH_I8X16_U => {
4476                        let data: [u8; 16] = stack.pop_value().try_into().unwrap_validated();
4477                        let lanes: [u8; 16] = to_lanes(data);
4478                        let high_lanes: [u8; 8] = lanes[8..].try_into().unwrap();
4479                        let result = high_lanes.map(|lane| lane as u16);
4480                        stack.push_value::<T>(Value::V128(from_lanes(result)))?;
4481                    }
4482                    I16X8_EXTEND_LOW_I8X16_S => {
4483                        let data: [u8; 16] = stack.pop_value().try_into().unwrap_validated();
4484                        let lanes: [i8; 16] = to_lanes(data);
4485                        let low_lanes: [i8; 8] = lanes[..8].try_into().unwrap();
4486                        let result = low_lanes.map(|lane| lane as i16);
4487                        stack.push_value::<T>(Value::V128(from_lanes(result)))?;
4488                    }
4489                    I16X8_EXTEND_LOW_I8X16_U => {
4490                        let data: [u8; 16] = stack.pop_value().try_into().unwrap_validated();
4491                        let lanes: [u8; 16] = to_lanes(data);
4492                        let low_lanes: [u8; 8] = lanes[..8].try_into().unwrap();
4493                        let result = low_lanes.map(|lane| lane as u16);
4494                        stack.push_value::<T>(Value::V128(from_lanes(result)))?;
4495                    }
4496                    I32X4_EXTEND_HIGH_I16X8_S => {
4497                        let data: [u8; 16] = stack.pop_value().try_into().unwrap_validated();
4498                        let lanes: [i16; 8] = to_lanes(data);
4499                        let high_lanes: [i16; 4] = lanes[4..].try_into().unwrap();
4500                        let result = high_lanes.map(|lane| lane as i32);
4501                        stack.push_value::<T>(Value::V128(from_lanes(result)))?;
4502                    }
4503                    I32X4_EXTEND_HIGH_I16X8_U => {
4504                        let data: [u8; 16] = stack.pop_value().try_into().unwrap_validated();
4505                        let lanes: [u16; 8] = to_lanes(data);
4506                        let high_lanes: [u16; 4] = lanes[4..].try_into().unwrap();
4507                        let result = high_lanes.map(|lane| lane as u32);
4508                        stack.push_value::<T>(Value::V128(from_lanes(result)))?;
4509                    }
4510                    I32X4_EXTEND_LOW_I16X8_S => {
4511                        let data: [u8; 16] = stack.pop_value().try_into().unwrap_validated();
4512                        let lanes: [i16; 8] = to_lanes(data);
4513                        let low_lanes: [i16; 4] = lanes[..4].try_into().unwrap();
4514                        let result = low_lanes.map(|lane| lane as i32);
4515                        stack.push_value::<T>(Value::V128(from_lanes(result)))?;
4516                    }
4517                    I32X4_EXTEND_LOW_I16X8_U => {
4518                        let data: [u8; 16] = stack.pop_value().try_into().unwrap_validated();
4519                        let lanes: [u16; 8] = to_lanes(data);
4520                        let low_lanes: [u16; 4] = lanes[..4].try_into().unwrap();
4521                        let result = low_lanes.map(|lane| lane as u32);
4522                        stack.push_value::<T>(Value::V128(from_lanes(result)))?;
4523                    }
4524                    I64X2_EXTEND_HIGH_I32X4_S => {
4525                        let data: [u8; 16] = stack.pop_value().try_into().unwrap_validated();
4526                        let lanes: [i32; 4] = to_lanes(data);
4527                        let high_lanes: [i32; 2] = lanes[2..].try_into().unwrap();
4528                        let result = high_lanes.map(|lane| lane as i64);
4529                        stack.push_value::<T>(Value::V128(from_lanes(result)))?;
4530                    }
4531                    I64X2_EXTEND_HIGH_I32X4_U => {
4532                        let data: [u8; 16] = stack.pop_value().try_into().unwrap_validated();
4533                        let lanes: [u32; 4] = to_lanes(data);
4534                        let high_lanes: [u32; 2] = lanes[2..].try_into().unwrap();
4535                        let result = high_lanes.map(|lane| lane as u64);
4536                        stack.push_value::<T>(Value::V128(from_lanes(result)))?;
4537                    }
4538                    I64X2_EXTEND_LOW_I32X4_S => {
4539                        let data: [u8; 16] = stack.pop_value().try_into().unwrap_validated();
4540                        let lanes: [i32; 4] = to_lanes(data);
4541                        let low_lanes: [i32; 2] = lanes[..2].try_into().unwrap();
4542                        let result = low_lanes.map(|lane| lane as i64);
4543                        stack.push_value::<T>(Value::V128(from_lanes(result)))?;
4544                    }
4545                    I64X2_EXTEND_LOW_I32X4_U => {
4546                        let data: [u8; 16] = stack.pop_value().try_into().unwrap_validated();
4547                        let lanes: [u32; 4] = to_lanes(data);
4548                        let low_lanes: [u32; 2] = lanes[..2].try_into().unwrap();
4549                        let result = low_lanes.map(|lane| lane as u64);
4550                        stack.push_value::<T>(Value::V128(from_lanes(result)))?;
4551                    }
4552                    I32X4_TRUNC_SAT_F32X4_S => {
4553                        let data: [u8; 16] = stack.pop_value().try_into().unwrap_validated();
4554                        let lanes: [F32; 4] = to_lanes(data);
4555                        let result = lanes.map(|lane| {
4556                            if lane.is_nan() {
4557                                0
4558                            } else if lane.is_negative_infinity() {
4559                                i32::MIN
4560                            } else if lane.is_infinity() {
4561                                i32::MAX
4562                            } else {
4563                                lane.as_i32()
4564                            }
4565                        });
4566                        stack.push_value::<T>(Value::V128(from_lanes(result)))?;
4567                    }
4568                    I32X4_TRUNC_SAT_F32X4_U => {
4569                        let data: [u8; 16] = stack.pop_value().try_into().unwrap_validated();
4570                        let lanes: [F32; 4] = to_lanes(data);
4571                        let result = lanes.map(|lane| {
4572                            if lane.is_nan() {
4573                                0
4574                            } else if lane.is_negative_infinity() {
4575                                u32::MIN
4576                            } else if lane.is_infinity() {
4577                                u32::MAX
4578                            } else {
4579                                lane.as_u32()
4580                            }
4581                        });
4582                        stack.push_value::<T>(Value::V128(from_lanes(result)))?;
4583                    }
4584                    I32X4_TRUNC_SAT_F64X2_S_ZERO => {
4585                        let data: [u8; 16] = stack.pop_value().try_into().unwrap_validated();
4586                        let lanes: [F64; 2] = to_lanes(data);
4587                        let result = lanes.map(|lane| {
4588                            if lane.is_nan() {
4589                                0
4590                            } else if lane.is_negative_infinity() {
4591                                i32::MIN
4592                            } else if lane.is_infinity() {
4593                                i32::MAX
4594                            } else {
4595                                lane.as_i32()
4596                            }
4597                        });
4598                        stack.push_value::<T>(Value::V128(from_lanes([
4599                            result[0], result[1], 0, 0,
4600                        ])))?;
4601                    }
4602                    I32X4_TRUNC_SAT_F64X2_U_ZERO => {
4603                        let data: [u8; 16] = stack.pop_value().try_into().unwrap_validated();
4604                        let lanes: [F64; 2] = to_lanes(data);
4605                        let result = lanes.map(|lane| {
4606                            if lane.is_nan() {
4607                                0
4608                            } else if lane.is_negative_infinity() {
4609                                u32::MIN
4610                            } else if lane.is_infinity() {
4611                                u32::MAX
4612                            } else {
4613                                lane.as_u32()
4614                            }
4615                        });
4616                        stack.push_value::<T>(Value::V128(from_lanes([
4617                            result[0], result[1], 0, 0,
4618                        ])))?;
4619                    }
4620                    F32X4_CONVERT_I32X4_S => {
4621                        let data: [u8; 16] = stack.pop_value().try_into().unwrap_validated();
4622                        let lanes: [i32; 4] = to_lanes(data);
4623                        let result: [F32; 4] = lanes.map(|lane| F32(lane as f32));
4624                        stack.push_value::<T>(Value::V128(from_lanes(result)))?;
4625                    }
4626                    F32X4_CONVERT_I32X4_U => {
4627                        let data: [u8; 16] = stack.pop_value().try_into().unwrap_validated();
4628                        let lanes: [u32; 4] = to_lanes(data);
4629                        let result: [F32; 4] = lanes.map(|lane| F32(lane as f32));
4630                        stack.push_value::<T>(Value::V128(from_lanes(result)))?;
4631                    }
4632                    F64X2_CONVERT_LOW_I32X4_S => {
4633                        let data: [u8; 16] = stack.pop_value().try_into().unwrap_validated();
4634                        let lanes: [i32; 4] = to_lanes(data);
4635                        let low_lanes: [i32; 2] = lanes[..2].try_into().unwrap();
4636                        let result = low_lanes.map(|lane| F64(lane as f64));
4637                        stack.push_value::<T>(Value::V128(from_lanes(result)))?;
4638                    }
4639                    F64X2_CONVERT_LOW_I32X4_U => {
4640                        let data: [u8; 16] = stack.pop_value().try_into().unwrap_validated();
4641                        let lanes: [u32; 4] = to_lanes(data);
4642                        let low_lanes: [u32; 2] = lanes[..2].try_into().unwrap();
4643                        let result = low_lanes.map(|lane| F64(lane as f64));
4644                        stack.push_value::<T>(Value::V128(from_lanes(result)))?;
4645                    }
4646                    F32X4_DEMOTE_F64X2_ZERO => {
4647                        let data: [u8; 16] = stack.pop_value().try_into().unwrap_validated();
4648                        let lanes = to_lanes::<8, 2, F64>(data);
4649                        let half_lanes = lanes.map(|lane| lane.as_f32());
4650                        let result = [half_lanes[0], half_lanes[1], F32(0.0), F32(0.0)];
4651                        stack.push_value::<T>(Value::V128(from_lanes(result)))?;
4652                    }
4653                    F64X2_PROMOTE_LOW_F32X4 => {
4654                        let data: [u8; 16] = stack.pop_value().try_into().unwrap_validated();
4655                        let lanes: [F32; 4] = to_lanes(data);
4656                        let half_lanes: [F32; 2] = lanes[..2].try_into().unwrap();
4657                        let result = half_lanes.map(|lane| lane.as_f64());
4658                        stack.push_value::<T>(Value::V128(from_lanes(result)))?;
4659                    }
4660
4661                    // ishape.narrow_ishape_sx
4662                    I8X16_NARROW_I16X8_S => {
4663                        let data2: [u8; 16] = stack.pop_value().try_into().unwrap_validated();
4664                        let data1: [u8; 16] = stack.pop_value().try_into().unwrap_validated();
4665                        let lanes2: [i16; 8] = to_lanes(data2);
4666                        let lanes1: [i16; 8] = to_lanes(data1);
4667                        let mut concatenated_narrowed_lanes = lanes1
4668                            .into_iter()
4669                            .chain(lanes2)
4670                            .map(|lane| lane.clamp(i8::MIN as i16, i8::MAX as i16) as i8);
4671                        let result: [i8; 16] =
4672                            array::from_fn(|_| concatenated_narrowed_lanes.next().unwrap());
4673                        stack.push_value::<T>(Value::V128(from_lanes(result)))?;
4674                    }
4675                    I8X16_NARROW_I16X8_U => {
4676                        let data2: [u8; 16] = stack.pop_value().try_into().unwrap_validated();
4677                        let data1: [u8; 16] = stack.pop_value().try_into().unwrap_validated();
4678                        let lanes2: [i16; 8] = to_lanes(data2);
4679                        let lanes1: [i16; 8] = to_lanes(data1);
4680                        let mut concatenated_narrowed_lanes = lanes1
4681                            .into_iter()
4682                            .chain(lanes2)
4683                            .map(|lane| lane.clamp(u8::MIN as i16, u8::MAX as i16) as u8);
4684                        let result: [u8; 16] =
4685                            array::from_fn(|_| concatenated_narrowed_lanes.next().unwrap());
4686                        stack.push_value::<T>(Value::V128(from_lanes(result)))?;
4687                    }
4688                    I16X8_NARROW_I32X4_S => {
4689                        let data2: [u8; 16] = stack.pop_value().try_into().unwrap_validated();
4690                        let data1: [u8; 16] = stack.pop_value().try_into().unwrap_validated();
4691                        let lanes2: [i32; 4] = to_lanes(data2);
4692                        let lanes1: [i32; 4] = to_lanes(data1);
4693                        let mut concatenated_narrowed_lanes = lanes1
4694                            .into_iter()
4695                            .chain(lanes2)
4696                            .map(|lane| lane.clamp(i16::MIN as i32, i16::MAX as i32) as i16);
4697                        let result: [i16; 8] =
4698                            array::from_fn(|_| concatenated_narrowed_lanes.next().unwrap());
4699                        stack.push_value::<T>(Value::V128(from_lanes(result)))?;
4700                    }
4701                    I16X8_NARROW_I32X4_U => {
4702                        let data2: [u8; 16] = stack.pop_value().try_into().unwrap_validated();
4703                        let data1: [u8; 16] = stack.pop_value().try_into().unwrap_validated();
4704                        let lanes2: [i32; 4] = to_lanes(data2);
4705                        let lanes1: [i32; 4] = to_lanes(data1);
4706                        let mut concatenated_narrowed_lanes = lanes1
4707                            .into_iter()
4708                            .chain(lanes2)
4709                            .map(|lane| lane.clamp(u16::MIN as i32, u16::MAX as i32) as u16);
4710                        let result: [u16; 8] =
4711                            array::from_fn(|_| concatenated_narrowed_lanes.next().unwrap());
4712                        stack.push_value::<T>(Value::V128(from_lanes(result)))?;
4713                    }
4714
4715                    // ishape.bitmask
4716                    I8X16_BITMASK => {
4717                        let data: [u8; 16] = stack.pop_value().try_into().unwrap_validated();
4718                        let lanes: [i8; 16] = to_lanes(data);
4719                        let bits = lanes.map(|lane| lane < 0);
4720                        let bitmask = bits
4721                            .into_iter()
4722                            .enumerate()
4723                            .fold(0u32, |acc, (i, bit)| acc | ((bit as u32) << i));
4724                        stack.push_value::<T>(Value::I32(bitmask))?;
4725                    }
4726                    I16X8_BITMASK => {
4727                        let data: [u8; 16] = stack.pop_value().try_into().unwrap_validated();
4728                        let lanes: [i16; 8] = to_lanes(data);
4729                        let bits = lanes.map(|lane| lane < 0);
4730                        let bitmask = bits
4731                            .into_iter()
4732                            .enumerate()
4733                            .fold(0u32, |acc, (i, bit)| acc | ((bit as u32) << i));
4734                        stack.push_value::<T>(Value::I32(bitmask))?;
4735                    }
4736                    I32X4_BITMASK => {
4737                        let data: [u8; 16] = stack.pop_value().try_into().unwrap_validated();
4738                        let lanes: [i32; 4] = to_lanes(data);
4739                        let bits = lanes.map(|lane| lane < 0);
4740                        let bitmask = bits
4741                            .into_iter()
4742                            .enumerate()
4743                            .fold(0u32, |acc, (i, bit)| acc | ((bit as u32) << i));
4744                        stack.push_value::<T>(Value::I32(bitmask))?;
4745                    }
4746                    I64X2_BITMASK => {
4747                        let data: [u8; 16] = stack.pop_value().try_into().unwrap_validated();
4748                        let lanes: [i64; 2] = to_lanes(data);
4749                        let bits = lanes.map(|lane| lane < 0);
4750                        let bitmask = bits
4751                            .into_iter()
4752                            .enumerate()
4753                            .fold(0u32, |acc, (i, bit)| acc | ((bit as u32) << i));
4754                        stack.push_value::<T>(Value::I32(bitmask))?;
4755                    }
4756
4757                    // ishape.dot_ishape_s
4758                    I32X4_DOT_I16X8_S => {
4759                        let data1: [u8; 16] = stack.pop_value().try_into().unwrap_validated();
4760                        let data2: [u8; 16] = stack.pop_value().try_into().unwrap_validated();
4761                        let lanes1: [i16; 8] = to_lanes(data1);
4762                        let lanes2: [i16; 8] = to_lanes(data2);
4763                        let multiplied: [i32; 8] = array::from_fn(|i| {
4764                            let v1 = lanes1[i] as i32;
4765                            let v2 = lanes2[i] as i32;
4766                            v1.wrapping_mul(v2)
4767                        });
4768                        let added: [i32; 4] = array::from_fn(|i| {
4769                            let v1 = multiplied[2 * i];
4770                            let v2 = multiplied[2 * i + 1];
4771                            v1.wrapping_add(v2)
4772                        });
4773                        stack.push_value::<T>(Value::V128(from_lanes(added)))?;
4774                    }
4775
4776                    // ishape.extmul_half_ishape_sx
4777                    I16X8_EXTMUL_HIGH_I8X16_S => {
4778                        let data1: [u8; 16] = stack.pop_value().try_into().unwrap_validated();
4779                        let data2: [u8; 16] = stack.pop_value().try_into().unwrap_validated();
4780                        let lanes1: [i8; 16] = to_lanes(data1);
4781                        let lanes2: [i8; 16] = to_lanes(data2);
4782                        let high_lanes1: [i8; 8] = lanes1[8..].try_into().unwrap();
4783                        let high_lanes2: [i8; 8] = lanes2[8..].try_into().unwrap();
4784                        let multiplied: [i16; 8] = array::from_fn(|i| {
4785                            let v1 = high_lanes1[i] as i16;
4786                            let v2 = high_lanes2[i] as i16;
4787                            v1.wrapping_mul(v2)
4788                        });
4789                        stack.push_value::<T>(Value::V128(from_lanes(multiplied)))?;
4790                    }
4791                    I16X8_EXTMUL_HIGH_I8X16_U => {
4792                        let data1: [u8; 16] = stack.pop_value().try_into().unwrap_validated();
4793                        let data2: [u8; 16] = stack.pop_value().try_into().unwrap_validated();
4794                        let lanes1: [u8; 16] = to_lanes(data1);
4795                        let lanes2: [u8; 16] = to_lanes(data2);
4796                        let high_lanes1: [u8; 8] = lanes1[8..].try_into().unwrap();
4797                        let high_lanes2: [u8; 8] = lanes2[8..].try_into().unwrap();
4798                        let multiplied: [u16; 8] = array::from_fn(|i| {
4799                            let v1 = high_lanes1[i] as u16;
4800                            let v2 = high_lanes2[i] as u16;
4801                            v1.wrapping_mul(v2)
4802                        });
4803                        stack.push_value::<T>(Value::V128(from_lanes(multiplied)))?;
4804                    }
4805                    I16X8_EXTMUL_LOW_I8X16_S => {
4806                        let data1: [u8; 16] = stack.pop_value().try_into().unwrap_validated();
4807                        let data2: [u8; 16] = stack.pop_value().try_into().unwrap_validated();
4808                        let lanes1: [i8; 16] = to_lanes(data1);
4809                        let lanes2: [i8; 16] = to_lanes(data2);
4810                        let high_lanes1: [i8; 8] = lanes1[..8].try_into().unwrap();
4811                        let high_lanes2: [i8; 8] = lanes2[..8].try_into().unwrap();
4812                        let multiplied: [i16; 8] = array::from_fn(|i| {
4813                            let v1 = high_lanes1[i] as i16;
4814                            let v2 = high_lanes2[i] as i16;
4815                            v1.wrapping_mul(v2)
4816                        });
4817                        stack.push_value::<T>(Value::V128(from_lanes(multiplied)))?;
4818                    }
4819                    I16X8_EXTMUL_LOW_I8X16_U => {
4820                        let data1: [u8; 16] = stack.pop_value().try_into().unwrap_validated();
4821                        let data2: [u8; 16] = stack.pop_value().try_into().unwrap_validated();
4822                        let lanes1: [u8; 16] = to_lanes(data1);
4823                        let lanes2: [u8; 16] = to_lanes(data2);
4824                        let high_lanes1: [u8; 8] = lanes1[..8].try_into().unwrap();
4825                        let high_lanes2: [u8; 8] = lanes2[..8].try_into().unwrap();
4826                        let multiplied: [u16; 8] = array::from_fn(|i| {
4827                            let v1 = high_lanes1[i] as u16;
4828                            let v2 = high_lanes2[i] as u16;
4829                            v1.wrapping_mul(v2)
4830                        });
4831                        stack.push_value::<T>(Value::V128(from_lanes(multiplied)))?;
4832                    }
4833                    I32X4_EXTMUL_HIGH_I16X8_S => {
4834                        let data1: [u8; 16] = stack.pop_value().try_into().unwrap_validated();
4835                        let data2: [u8; 16] = stack.pop_value().try_into().unwrap_validated();
4836                        let lanes1: [i16; 8] = to_lanes(data1);
4837                        let lanes2: [i16; 8] = to_lanes(data2);
4838                        let high_lanes1: [i16; 4] = lanes1[4..].try_into().unwrap();
4839                        let high_lanes2: [i16; 4] = lanes2[4..].try_into().unwrap();
4840                        let multiplied: [i32; 4] = array::from_fn(|i| {
4841                            let v1 = high_lanes1[i] as i32;
4842                            let v2 = high_lanes2[i] as i32;
4843                            v1.wrapping_mul(v2)
4844                        });
4845                        stack.push_value::<T>(Value::V128(from_lanes(multiplied)))?;
4846                    }
4847                    I32X4_EXTMUL_HIGH_I16X8_U => {
4848                        let data1: [u8; 16] = stack.pop_value().try_into().unwrap_validated();
4849                        let data2: [u8; 16] = stack.pop_value().try_into().unwrap_validated();
4850                        let lanes1: [u16; 8] = to_lanes(data1);
4851                        let lanes2: [u16; 8] = to_lanes(data2);
4852                        let high_lanes1: [u16; 4] = lanes1[4..].try_into().unwrap();
4853                        let high_lanes2: [u16; 4] = lanes2[4..].try_into().unwrap();
4854                        let multiplied: [u32; 4] = array::from_fn(|i| {
4855                            let v1 = high_lanes1[i] as u32;
4856                            let v2 = high_lanes2[i] as u32;
4857                            v1.wrapping_mul(v2)
4858                        });
4859                        stack.push_value::<T>(Value::V128(from_lanes(multiplied)))?;
4860                    }
4861                    I32X4_EXTMUL_LOW_I16X8_S => {
4862                        let data1: [u8; 16] = stack.pop_value().try_into().unwrap_validated();
4863                        let data2: [u8; 16] = stack.pop_value().try_into().unwrap_validated();
4864                        let lanes1: [i16; 8] = to_lanes(data1);
4865                        let lanes2: [i16; 8] = to_lanes(data2);
4866                        let high_lanes1: [i16; 4] = lanes1[..4].try_into().unwrap();
4867                        let high_lanes2: [i16; 4] = lanes2[..4].try_into().unwrap();
4868                        let multiplied: [i32; 4] = array::from_fn(|i| {
4869                            let v1 = high_lanes1[i] as i32;
4870                            let v2 = high_lanes2[i] as i32;
4871                            v1.wrapping_mul(v2)
4872                        });
4873                        stack.push_value::<T>(Value::V128(from_lanes(multiplied)))?;
4874                    }
4875                    I32X4_EXTMUL_LOW_I16X8_U => {
4876                        let data1: [u8; 16] = stack.pop_value().try_into().unwrap_validated();
4877                        let data2: [u8; 16] = stack.pop_value().try_into().unwrap_validated();
4878                        let lanes1: [u16; 8] = to_lanes(data1);
4879                        let lanes2: [u16; 8] = to_lanes(data2);
4880                        let high_lanes1: [u16; 4] = lanes1[..4].try_into().unwrap();
4881                        let high_lanes2: [u16; 4] = lanes2[..4].try_into().unwrap();
4882                        let multiplied: [u32; 4] = array::from_fn(|i| {
4883                            let v1 = high_lanes1[i] as u32;
4884                            let v2 = high_lanes2[i] as u32;
4885                            v1.wrapping_mul(v2)
4886                        });
4887                        stack.push_value::<T>(Value::V128(from_lanes(multiplied)))?;
4888                    }
4889                    I64X2_EXTMUL_HIGH_I32X4_S => {
4890                        let data1: [u8; 16] = stack.pop_value().try_into().unwrap_validated();
4891                        let data2: [u8; 16] = stack.pop_value().try_into().unwrap_validated();
4892                        let lanes1: [i32; 4] = to_lanes(data1);
4893                        let lanes2: [i32; 4] = to_lanes(data2);
4894                        let high_lanes1: [i32; 2] = lanes1[2..].try_into().unwrap();
4895                        let high_lanes2: [i32; 2] = lanes2[2..].try_into().unwrap();
4896                        let multiplied: [i64; 2] = array::from_fn(|i| {
4897                            let v1 = high_lanes1[i] as i64;
4898                            let v2 = high_lanes2[i] as i64;
4899                            v1.wrapping_mul(v2)
4900                        });
4901                        stack.push_value::<T>(Value::V128(from_lanes(multiplied)))?;
4902                    }
4903                    I64X2_EXTMUL_HIGH_I32X4_U => {
4904                        let data1: [u8; 16] = stack.pop_value().try_into().unwrap_validated();
4905                        let data2: [u8; 16] = stack.pop_value().try_into().unwrap_validated();
4906                        let lanes1: [u32; 4] = to_lanes(data1);
4907                        let lanes2: [u32; 4] = to_lanes(data2);
4908                        let high_lanes1: [u32; 2] = lanes1[2..].try_into().unwrap();
4909                        let high_lanes2: [u32; 2] = lanes2[2..].try_into().unwrap();
4910                        let multiplied: [u64; 2] = array::from_fn(|i| {
4911                            let v1 = high_lanes1[i] as u64;
4912                            let v2 = high_lanes2[i] as u64;
4913                            v1.wrapping_mul(v2)
4914                        });
4915                        stack.push_value::<T>(Value::V128(from_lanes(multiplied)))?;
4916                    }
4917                    I64X2_EXTMUL_LOW_I32X4_S => {
4918                        let data1: [u8; 16] = stack.pop_value().try_into().unwrap_validated();
4919                        let data2: [u8; 16] = stack.pop_value().try_into().unwrap_validated();
4920                        let lanes1: [i32; 4] = to_lanes(data1);
4921                        let lanes2: [i32; 4] = to_lanes(data2);
4922                        let high_lanes1: [i32; 2] = lanes1[..2].try_into().unwrap();
4923                        let high_lanes2: [i32; 2] = lanes2[..2].try_into().unwrap();
4924                        let multiplied: [i64; 2] = array::from_fn(|i| {
4925                            let v1 = high_lanes1[i] as i64;
4926                            let v2 = high_lanes2[i] as i64;
4927                            v1.wrapping_mul(v2)
4928                        });
4929                        stack.push_value::<T>(Value::V128(from_lanes(multiplied)))?;
4930                    }
4931                    I64X2_EXTMUL_LOW_I32X4_U => {
4932                        let data1: [u8; 16] = stack.pop_value().try_into().unwrap_validated();
4933                        let data2: [u8; 16] = stack.pop_value().try_into().unwrap_validated();
4934                        let lanes1: [u32; 4] = to_lanes(data1);
4935                        let lanes2: [u32; 4] = to_lanes(data2);
4936                        let high_lanes1: [u32; 2] = lanes1[..2].try_into().unwrap();
4937                        let high_lanes2: [u32; 2] = lanes2[..2].try_into().unwrap();
4938                        let multiplied: [u64; 2] = array::from_fn(|i| {
4939                            let v1 = high_lanes1[i] as u64;
4940                            let v2 = high_lanes2[i] as u64;
4941                            v1.wrapping_mul(v2)
4942                        });
4943                        stack.push_value::<T>(Value::V128(from_lanes(multiplied)))?;
4944                    }
4945
4946                    // ishape.extadd_pairwise_ishape_sx
4947                    I16X8_EXTADD_PAIRWISE_I8X16_S => {
4948                        let data: [u8; 16] = stack.pop_value().try_into().unwrap_validated();
4949                        let lanes: [i8; 16] = to_lanes(data);
4950                        let added_pairwise: [i16; 8] = array::from_fn(|i| {
4951                            let v1 = lanes[2 * i] as i16;
4952                            let v2 = lanes[2 * i + 1] as i16;
4953                            v1.wrapping_add(v2)
4954                        });
4955                        stack.push_value::<T>(Value::V128(from_lanes(added_pairwise)))?;
4956                    }
4957                    I16X8_EXTADD_PAIRWISE_I8X16_U => {
4958                        let data: [u8; 16] = stack.pop_value().try_into().unwrap_validated();
4959                        let lanes: [u8; 16] = to_lanes(data);
4960                        let added_pairwise: [u16; 8] = array::from_fn(|i| {
4961                            let v1 = lanes[2 * i] as u16;
4962                            let v2 = lanes[2 * i + 1] as u16;
4963                            v1.wrapping_add(v2)
4964                        });
4965                        stack.push_value::<T>(Value::V128(from_lanes(added_pairwise)))?;
4966                    }
4967                    I32X4_EXTADD_PAIRWISE_I16X8_S => {
4968                        let data: [u8; 16] = stack.pop_value().try_into().unwrap_validated();
4969                        let lanes: [i16; 8] = to_lanes(data);
4970                        let added_pairwise: [i32; 4] = array::from_fn(|i| {
4971                            let v1 = lanes[2 * i] as i32;
4972                            let v2 = lanes[2 * i + 1] as i32;
4973                            v1.wrapping_add(v2)
4974                        });
4975                        stack.push_value::<T>(Value::V128(from_lanes(added_pairwise)))?;
4976                    }
4977                    I32X4_EXTADD_PAIRWISE_I16X8_U => {
4978                        let data: [u8; 16] = stack.pop_value().try_into().unwrap_validated();
4979                        let lanes: [u16; 8] = to_lanes(data);
4980                        let added_pairwise: [u32; 4] = array::from_fn(|i| {
4981                            let v1 = lanes[2 * i] as u32;
4982                            let v2 = lanes[2 * i + 1] as u32;
4983                            v1.wrapping_add(v2)
4984                        });
4985                        stack.push_value::<T>(Value::V128(from_lanes(added_pairwise)))?;
4986                    }
4987
4988                    // Unimplemented or invalid instructions
4989                    F32X4_RELAXED_MADD
4990                    | F32X4_RELAXED_MAX
4991                    | F32X4_RELAXED_MIN
4992                    | F32X4_RELAXED_NMADD
4993                    | F64X2_RELAXED_MADD
4994                    | F64X2_RELAXED_MAX
4995                    | F64X2_RELAXED_MIN
4996                    | F64X2_RELAXED_NMADD
4997                    | I16X8_RELAXED_LANESELECT
4998                    | I32X4_RELAXED_LANESELECT
4999                    | I32X4_RELAXED_TRUNC_F32X4_S
5000                    | I32X4_RELAXED_TRUNC_F32X4_U
5001                    | I32X4_RELAXED_TRUNC_F64X2_S_ZERO
5002                    | I32X4_RELAXED_TRUNC_F64X2_U_ZERO
5003                    | I64X2_RELAXED_LANESELECT
5004                    | I8X16_RELAXED_LANESELECT
5005                    | I8X16_RELAXED_SWIZZLE
5006                    | 154
5007                    | 187
5008                    | 194
5009                    | 256.. => unreachable_validated!(),
5010                }
5011            }
5012
5013            // Unimplemented or invalid instructions
5014            0x06..=0x0A
5015            | 0x12..=0x19
5016            | 0x1C..=0x1F
5017            | 0x25..=0x27
5018            | 0xC0..=0xFA
5019            | 0xFB
5020            | 0xFE
5021            | 0xFF => {
5022                unreachable_validated!();
5023            }
5024        }
5025    }
5026    Ok(None)
5027}
5028
5029//helper function for avoiding code duplication at intraprocedural jumps
5030fn do_sidetable_control_transfer(
5031    wasm: &mut WasmReader,
5032    stack: &mut Stack,
5033    current_stp: &mut usize,
5034    current_sidetable: &Sidetable,
5035) -> Result<(), RuntimeError> {
5036    let sidetable_entry = &current_sidetable[*current_stp];
5037
5038    stack.remove_in_between(sidetable_entry.popcnt, sidetable_entry.valcnt);
5039
5040    *current_stp = (*current_stp as isize + sidetable_entry.delta_stp) as usize;
5041    wasm.pc = (wasm.pc as isize + sidetable_entry.delta_pc) as usize;
5042
5043    Ok(())
5044}
5045
5046#[inline(always)]
5047fn calculate_mem_address(memarg: &MemArg, relative_address: u32) -> Result<usize, RuntimeError> {
5048    memarg
5049        .offset
5050        // The spec states that this should be a 33 bit integer, e.g. it is not legal to wrap if the
5051        // sum of offset and relative_address exceeds u32::MAX. To emulate this behavior, we use a
5052        // checked addition.
5053        // See: https://webassembly.github.io/spec/core/syntax/instructions.html#memory-instructions
5054        .checked_add(relative_address)
5055        .ok_or(TrapError::MemoryOrDataAccessOutOfBounds)?
5056        .try_into()
5057        .map_err(|_| TrapError::MemoryOrDataAccessOutOfBounds.into())
5058}
5059
5060//helpers for avoiding code duplication during module instantiation
5061#[inline(always)]
5062#[allow(clippy::too_many_arguments)]
5063pub(super) fn table_init(
5064    store_modules: &AddrVec<ModuleAddr, ModuleInst>,
5065    store_tables: &mut AddrVec<TableAddr, TableInst>,
5066    store_elements: &AddrVec<ElemAddr, ElemInst>,
5067    current_module: ModuleAddr,
5068    elem_idx: usize,
5069    table_idx: usize,
5070    n: i32,
5071    s: i32,
5072    d: i32,
5073) -> Result<(), RuntimeError> {
5074    let tab_addr = *store_modules
5075        .get(current_module)
5076        .table_addrs
5077        .get(table_idx)
5078        .unwrap_validated();
5079    let elem_addr = *store_modules
5080        .get(current_module)
5081        .elem_addrs
5082        .get(elem_idx)
5083        .unwrap_validated();
5084
5085    let tab = store_tables.get_mut(tab_addr);
5086
5087    let elem = store_elements.get(elem_addr);
5088
5089    trace!(
5090        "Instruction: table.init '{}' '{}' [{} {} {}] -> []",
5091        elem_idx,
5092        table_idx,
5093        d,
5094        s,
5095        n
5096    );
5097
5098    let final_src_offset = (s as usize)
5099        .checked_add(n as usize)
5100        .filter(|&res| res <= elem.len())
5101        .ok_or(TrapError::TableOrElementAccessOutOfBounds)?;
5102
5103    if (d as usize)
5104        .checked_add(n as usize)
5105        .filter(|&res| res <= tab.len())
5106        .is_none()
5107    {
5108        return Err(TrapError::TableOrElementAccessOutOfBounds.into());
5109    }
5110
5111    let dest = &mut tab.elem[d as usize..];
5112    let src = &elem.references[s as usize..final_src_offset];
5113    dest[..src.len()].copy_from_slice(src);
5114    Ok(())
5115}
5116
5117#[inline(always)]
5118pub(super) fn elem_drop(
5119    store_modules: &AddrVec<ModuleAddr, ModuleInst>,
5120    store_elements: &mut AddrVec<ElemAddr, ElemInst>,
5121    current_module: ModuleAddr,
5122    elem_idx: usize,
5123) -> Result<(), RuntimeError> {
5124    // WARN: i'm not sure if this is okay or not
5125    let elem_addr = *store_modules
5126        .get(current_module)
5127        .elem_addrs
5128        .get(elem_idx)
5129        .unwrap_validated();
5130    store_elements.get_mut(elem_addr).references.clear();
5131    Ok(())
5132}
5133
5134#[inline(always)]
5135#[allow(clippy::too_many_arguments)]
5136pub(super) fn memory_init(
5137    store_modules: &AddrVec<ModuleAddr, ModuleInst>,
5138    store_memories: &mut AddrVec<MemAddr, MemInst>,
5139    store_data: &AddrVec<DataAddr, DataInst>,
5140    current_module: ModuleAddr,
5141    data_idx: usize,
5142    mem_idx: usize,
5143    n: i32,
5144    s: i32,
5145    d: i32,
5146) -> Result<(), RuntimeError> {
5147    let mem_addr = *store_modules
5148        .get(current_module)
5149        .mem_addrs
5150        .get(mem_idx)
5151        .unwrap_validated();
5152    let mem = store_memories.get(mem_addr);
5153
5154    mem.mem.init(
5155        d as MemIdx,
5156        &store_data
5157            .get(store_modules.get(current_module).data_addrs[data_idx])
5158            .data,
5159        s as MemIdx,
5160        n as MemIdx,
5161    )?;
5162
5163    trace!("Instruction: memory.init");
5164    Ok(())
5165}
5166
5167#[inline(always)]
5168pub(super) fn data_drop(
5169    store_modules: &AddrVec<ModuleAddr, ModuleInst>,
5170    store_data: &mut AddrVec<DataAddr, DataInst>,
5171    current_module: ModuleAddr,
5172    data_idx: usize,
5173) -> Result<(), RuntimeError> {
5174    // Here is debatable
5175    // If we were to be on par with the spec we'd have to use a DataInst struct
5176    // But since memory.init is specifically made for Passive data segments
5177    // I thought that using DataMode would be better because we can see if the
5178    // data segment is passive or active
5179
5180    // Also, we should set data to null here (empty), which we do by clearing it
5181    let data_addr = *store_modules
5182        .get(current_module)
5183        .data_addrs
5184        .get(data_idx)
5185        .unwrap_validated();
5186    store_data.get_mut(data_addr).data.clear();
5187    Ok(())
5188}
5189
5190#[inline(always)]
5191fn to_lanes<const M: usize, const N: usize, T: LittleEndianBytes<M>>(data: [u8; 16]) -> [T; N] {
5192    assert_eq!(M * N, 16);
5193
5194    let mut lanes = data
5195        .chunks(M)
5196        .map(|chunk| T::from_le_bytes(chunk.try_into().unwrap()));
5197    array::from_fn(|_| lanes.next().unwrap())
5198}
5199
5200#[inline(always)]
5201fn from_lanes<const M: usize, const N: usize, T: LittleEndianBytes<M>>(lanes: [T; N]) -> [u8; 16] {
5202    assert_eq!(M * N, 16);
5203
5204    let mut bytes = lanes.into_iter().flat_map(T::to_le_bytes);
5205    array::from_fn(|_| bytes.next().unwrap())
5206}