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