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