wasm/execution/
interpreter_loop.rs

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